diff --git a/erpnext/accounts/doctype/account/account.json b/erpnext/accounts/doctype/account/account.json
index 668164ca64..de28a59f8c 100644
--- a/erpnext/accounts/doctype/account/account.json
+++ b/erpnext/accounts/doctype/account/account.json
@@ -412,7 +412,7 @@
"no_copy": 0,
"oldfieldname": "account_type",
"oldfieldtype": "Select",
- "options": "\nAccumulated Depreciation\nBank\nCash\nChargeable\nCost of Goods Sold\nDepreciation\nEquity\nExpense Account\nExpenses Included In Valuation\nFixed Asset\nIncome Account\nPayable\nReceivable\nRound Off\nStock\nStock Adjustment\nStock Received But Not Billed\nTax\nTemporary",
+ "options": "\nAccumulated Depreciation\nAsset Received But Not Billed\nBank\nCash\nChargeable\nCapital Work in Progress\nCost of Goods Sold\nDepreciation\nEquity\nExpense Account\nExpenses Included In Asset Valuation\nExpenses Included In Valuation\nFixed Asset\nIncome Account\nPayable\nReceivable\nRound Off\nStock\nStock Adjustment\nStock Received But Not Billed\nTax\nTemporary",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
@@ -625,7 +625,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2018-05-02 11:00:34.108490",
+ "modified": "2018-05-07 15:37:25.962506",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Account",
diff --git a/erpnext/accounts/doctype/account/chart_of_accounts/verified/in_standard_chart_of_accounts.json b/erpnext/accounts/doctype/account/chart_of_accounts/verified/in_standard_chart_of_accounts.json
index bc7f965956..2ec0b7f70c 100644
--- a/erpnext/accounts/doctype/account/chart_of_accounts/verified/in_standard_chart_of_accounts.json
+++ b/erpnext/accounts/doctype/account/chart_of_accounts/verified/in_standard_chart_of_accounts.json
@@ -147,8 +147,9 @@
}
},
"Duties and Taxes": {
- "account_type": "Tax",
- "is_group": 1
+ "TDS": {
+ "account_type": "Tax"
+ }
},
"Loans (Liabilities)": {
"Secured Loans": {},
diff --git a/erpnext/accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts.py b/erpnext/accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts.py
index 5452040fb6..6e1637165a 100644
--- a/erpnext/accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts.py
+++ b/erpnext/accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts.py
@@ -63,7 +63,10 @@ def get():
},
_("Accumulated Depreciation"): {
"account_type": "Accumulated Depreciation"
- }
+ },
+ _("CWIP Account"): {
+ "account_type": "Capital Work in Progress",
+ }
},
_("Investments"): {
"is_group": 1
@@ -81,6 +84,9 @@ def get():
_("Cost of Goods Sold"): {
"account_type": "Cost of Goods Sold"
},
+ _("Expenses Included In Asset Valuation"): {
+ "account_type": "Expenses Included In Asset Valuation"
+ },
_("Expenses Included In Valuation"): {
"account_type": "Expenses Included In Valuation"
},
@@ -146,6 +152,9 @@ def get():
_("Stock Received But Not Billed"): {
"account_type": "Stock Received But Not Billed"
},
+ _("Asset Received But Not Billed"): {
+ "account_type": "Asset Received But Not Billed"
+ }
},
_("Duties and Taxes"): {
"account_type": "Tax",
diff --git a/erpnext/accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts_with_account_number.py b/erpnext/accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts_with_account_number.py
index bad84533a5..5ed3e45086 100644
--- a/erpnext/accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts_with_account_number.py
+++ b/erpnext/accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts_with_account_number.py
@@ -85,6 +85,10 @@ def get():
"account_type": "Accumulated Depreciation",
"account_number": "1780"
},
+ _("CWIP Account"): {
+ "account_type": "Capital Work in Progress",
+ "account_number": "1790"
+ },
"account_number": "1700"
},
_("Investments"): {
@@ -108,6 +112,10 @@ def get():
"account_type": "Cost of Goods Sold",
"account_number": "5111"
},
+ _("Expenses Included In Asset Valuation"): {
+ "account_type": "Expenses Included In Asset Valuation",
+ "account_number": "5112"
+ },
_("Expenses Included In Valuation"): {
"account_type": "Expenses Included In Valuation",
"account_number": "5118"
@@ -228,6 +236,10 @@ def get():
"account_type": "Stock Received But Not Billed",
"account_number": "2210"
},
+ _("Asset Received But Not Billed"): {
+ "account_type": "Asset Received But Not Billed",
+ "account_number": "2211"
+ },
"account_number": "2200"
},
_("Duties and Taxes"): {
diff --git a/erpnext/accounts/doctype/accounting_period/accounting_period.js b/erpnext/accounts/doctype/accounting_period/accounting_period.js
index 1fb57eabcf..e3d805a168 100644
--- a/erpnext/accounts/doctype/accounting_period/accounting_period.js
+++ b/erpnext/accounts/doctype/accounting_period/accounting_period.js
@@ -2,7 +2,23 @@
// For license information, please see license.txt
frappe.ui.form.on('Accounting Period', {
- refresh: function(frm) {
-
+ onload: function(frm) {
+ if(frm.doc.closed_documents.length === 0 || (frm.doc.closed_documents.length === 1 && frm.doc.closed_documents[0].document_type == undefined)) {
+ frappe.call({
+ method: "get_doctypes_for_closing",
+ doc:frm.doc,
+ callback: function(r) {
+ if(r.message) {
+ cur_frm.clear_table("closed_documents");
+ r.message.forEach(function(element) {
+ var c = frm.add_child("closed_documents");
+ c.document_type = element.document_type;
+ c.closed = element.closed;
+ });
+ refresh_field("closed_documents");
+ }
+ }
+ });
+ }
}
});
diff --git a/erpnext/accounts/doctype/accounting_period/accounting_period.py b/erpnext/accounts/doctype/accounting_period/accounting_period.py
index 31f18490a3..32441db2c1 100644
--- a/erpnext/accounts/doctype/accounting_period/accounting_period.py
+++ b/erpnext/accounts/doctype/accounting_period/accounting_period.py
@@ -7,4 +7,48 @@ import frappe
from frappe.model.document import Document
class AccountingPeriod(Document):
- pass
+ def validate(self):
+ self.validate_overlap()
+
+ def before_insert(self):
+ self.bootstrap_doctypes_for_closing()
+
+ def autoname(self):
+ company_abbr = frappe.db.get_value("Company", self.company, "abbr")
+ self.name = " - ".join([self.period_name, company_abbr])
+
+ def validate_overlap(self):
+ existing_accounting_period = frappe.db.sql("""select name from `tabAccounting Period`
+ where (
+ (%(start_date)s between start_date and end_date)
+ or (%(end_date)s between start_date and end_date)
+ or (start_date between %(start_date)s and %(end_date)s)
+ or (end_date between %(start_date)s and %(end_date)s)
+ ) and name!=%(name)s and company=%(company)s""",
+ {
+ "start_date": self.start_date,
+ "end_date": self.end_date,
+ "name": self.name,
+ "company": self.company
+ }, as_dict=True)
+
+ if len(existing_accounting_period) > 0:
+ frappe.throw("Accounting Period overlaps with {0}".format(existing_accounting_period[0].get("name")))
+
+ def get_doctypes_for_closing(self):
+ docs_for_closing = []
+ #if not self.closed_documents or len(self.closed_documents) == 0:
+ doctypes = ["Sales Invoice", "Purchase Invoice", "Journal Entry", "Payroll Entry", "Bank Reconciliation", "Asset", "Purchase Order", "Sales Order", "Leave Application", "Leave Allocation", "Stock Entry"]
+ closed_doctypes = [{"document_type": doctype, "closed": 1} for doctype in doctypes]
+ for closed_doctype in closed_doctypes:
+ docs_for_closing.append(closed_doctype)
+
+ return docs_for_closing
+
+ def bootstrap_doctypes_for_closing(self):
+ if len(self.closed_documents) == 0:
+ for doctype_for_closing in self.get_doctypes_for_closing():
+ self.append('closed_documents', {
+ "document_type": doctype_for_closing.document_type,
+ "closed": doctype_for_closing.closed
+ })
diff --git a/erpnext/accounts/doctype/accounting_period/test_accounting_period.py b/erpnext/accounts/doctype/accounting_period/test_accounting_period.py
index 99694d2136..cc2e6a9fc6 100644
--- a/erpnext/accounts/doctype/accounting_period/test_accounting_period.py
+++ b/erpnext/accounts/doctype/accounting_period/test_accounting_period.py
@@ -7,4 +7,21 @@ import frappe
import unittest
class TestAccountingPeriod(unittest.TestCase):
- pass
+ def test_overlap(self):
+ ap1 = create_accounting_period({"start_date":"2018-04-01", "end_date":"2018-06-30", "company":"Wind Power LLC"})
+ ap1.save()
+ ap2 = create_accounting_period({"start_date":"2018-06-30", "end_date":"2018-07-10", "company":"Wind Power LLC"})
+ self.assertRaises(frappe.OverlapError, accounting_period_2.save())
+
+ def tearDown(self):
+ pass
+
+
+def create_accounting_period(**args):
+ accounting_period = frappe.new_doc("Accounting Period")
+ accounting_period.start_date = args.start_date or frappe.utils.datetime.date(2018, 4, 1)
+ accounting_period.end_date = args.end_date or frappe.utils.datetime.date(2018, 6, 30)
+ accounting_period.company = args.company
+ accounting_period.period_name = "_Test_Period_Name_1"
+
+ return accounting_period
diff --git a/erpnext/accounts/doctype/cost_center/cost_center.js b/erpnext/accounts/doctype/cost_center/cost_center.js
index cbc37fff8d..a5bcaf47c1 100644
--- a/erpnext/accounts/doctype/cost_center/cost_center.js
+++ b/erpnext/accounts/doctype/cost_center/cost_center.js
@@ -15,8 +15,57 @@ frappe.ui.form.on('Cost Center', {
}
}
})
+ },
+ refresh: function(frm) {
+ if (!frm.is_new()) {
+ frm.add_custom_button(__('Update Cost Center Number'), function () {
+ frm.trigger("update_cost_center_number");
+ });
+ }
+ },
+ update_cost_center_number: function(frm) {
+ var d = new frappe.ui.Dialog({
+ title: __('Update Cost Center Number'),
+ fields: [
+ {
+ "label": 'Cost Center Number',
+ "fieldname": "cost_center_number",
+ "fieldtype": "Data",
+ "reqd": 1
+ }
+ ],
+ primary_action: function() {
+ var data = d.get_values();
+ if(data.cost_center_number === frm.doc.cost_center_number) {
+ d.hide();
+ return;
+ }
+ frappe.call({
+ method: "erpnext.accounts.doctype.cost_center.cost_center.update_number_field",
+ args: {
+ doctype_name: frm.doc.doctype,
+ name: frm.doc.name,
+ field_name: d.fields[0].fieldname,
+ field_value: data.cost_center_number,
+ company: frm.doc.company
+ },
+ callback: function(r) {
+ if(!r.exc) {
+ if(r.message) {
+ frappe.set_route("Form", "Cost Center", r.message);
+ } else {
+ me.set_value("cost_center_number", data.cost_center_number);
+ }
+ d.hide();
+ }
+ }
+ });
+ },
+ primary_action_label: __('Update')
+ });
+ d.show();
}
-})
+});
cur_frm.cscript.refresh = function(doc, cdt, cdn) {
var intro_txt = '';
diff --git a/erpnext/accounts/doctype/cost_center/cost_center.json b/erpnext/accounts/doctype/cost_center/cost_center.json
index 9eddeec04f..4da21f11fe 100644
--- a/erpnext/accounts/doctype/cost_center/cost_center.json
+++ b/erpnext/accounts/doctype/cost_center/cost_center.json
@@ -1,5 +1,6 @@
{
"allow_copy": 1,
+ "allow_guest_to_view": 0,
"allow_import": 1,
"allow_rename": 1,
"autoname": "field:cost_center_name",
@@ -13,6 +14,7 @@
"editable_grid": 0,
"fields": [
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -38,9 +40,11 @@
"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,
@@ -68,9 +72,42 @@
"reqd": 1,
"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": "cost_center_number",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "Cost Center Number",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "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,
@@ -99,9 +136,11 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -130,9 +169,11 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -157,10 +198,12 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0,
"width": "50%"
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -188,9 +231,11 @@
"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,
@@ -218,9 +263,11 @@
"reqd": 0,
"search_index": 1,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -248,9 +295,11 @@
"reqd": 0,
"search_index": 1,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -279,22 +328,23 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
}
],
+ "has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"icon": "fa fa-money",
"idx": 1,
"image_view": 0,
"in_create": 0,
- "in_dialog": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"menu_index": 0,
- "modified": "2017-02-17 16:22:27.129572",
+ "modified": "2018-04-26 15:26:25.325778",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Cost Center",
@@ -302,7 +352,6 @@
"permissions": [
{
"amend": 0,
- "apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
@@ -322,7 +371,6 @@
},
{
"amend": 0,
- "apply_user_permissions": 0,
"cancel": 0,
"create": 0,
"delete": 0,
@@ -342,7 +390,6 @@
},
{
"amend": 0,
- "apply_user_permissions": 0,
"cancel": 0,
"create": 0,
"delete": 0,
@@ -362,7 +409,6 @@
},
{
"amend": 0,
- "apply_user_permissions": 0,
"cancel": 0,
"create": 0,
"delete": 0,
@@ -382,7 +428,6 @@
},
{
"amend": 0,
- "apply_user_permissions": 0,
"cancel": 0,
"create": 0,
"delete": 0,
diff --git a/erpnext/accounts/doctype/cost_center/cost_center.py b/erpnext/accounts/doctype/cost_center/cost_center.py
index fe1e9076de..24af0ce376 100644
--- a/erpnext/accounts/doctype/cost_center/cost_center.py
+++ b/erpnext/accounts/doctype/cost_center/cost_center.py
@@ -4,6 +4,7 @@
from __future__ import unicode_literals
import frappe
from frappe import _
+from frappe.utils import cint, cstr
from frappe.utils.nestedset import NestedSet
class CostCenter(NestedSet):
@@ -62,8 +63,68 @@ class CostCenter(NestedSet):
super(CostCenter, self).after_rename(olddn, newdn, merge)
if not merge:
- frappe.db.set_value("Cost Center", newdn, "cost_center_name",
- " - ".join(newdn.split(" - ")[:-1]))
+ new_cost_center = frappe.db.get_value("Cost Center", newdn, ["cost_center_name", "cost_center_number"], as_dict=1)
+
+ # exclude company abbr
+ new_parts = newdn.split(" - ")[:-1]
+ # update cost center number and remove from parts
+ if new_parts[0][0].isdigit():
+ if len(new_parts) == 1:
+ new_parts = newdn.split(" ")
+ if new_cost_center.cost_center_number != new_parts[0]:
+ validate_field_number("Cost Center", self.name, new_parts[0], self.company, "cost_center_number")
+ self.cost_center_number = new_parts[0]
+ self.db_set("cost_center_number", new_parts[0])
+ new_parts = new_parts[1:]
+
+ # update cost center name
+ cost_center_name = " - ".join(new_parts)
+ if new_cost_center.cost_center_name != cost_center_name:
+ self.cost_center_name = cost_center_name
+ self.db_set("cost_center_name", cost_center_name)
def on_doctype_update():
- frappe.db.add_index("Cost Center", ["lft", "rgt"])
\ No newline at end of file
+ frappe.db.add_index("Cost Center", ["lft", "rgt"])
+
+def get_doc_name_autoname(field_value, doc_title, name, company):
+ if company:
+ name_split=name.split("-")
+ parts = [doc_title.strip(), name_split[len(name_split)-1].strip()]
+ else:
+ parts = [doc_title.strip()]
+ if cstr(field_value).strip():
+ parts.insert(0, cstr(field_value).strip())
+ return ' - '.join(parts)
+
+def validate_field_number(doctype_name, name, field_value, company, field_name):
+ if field_value:
+ if company:
+ doctype_with_same_number = frappe.db.get_value(doctype_name,
+ {field_name: field_value, "company": company, "name": ["!=", name]})
+ else:
+ doctype_with_same_number = frappe.db.get_value(doctype_name,
+ {field_name: field_value, "name": ["!=", name]})
+ if doctype_with_same_number:
+ frappe.throw(_("{0} Number {1} already used in account {2}")
+ .format(doctype_name, field_value, doctype_with_same_number))
+
+@frappe.whitelist()
+def update_number_field(doctype_name, name, field_name, field_value, company):
+
+ doc_title = frappe.db.get_value(doctype_name, name, frappe.scrub(doctype_name)+"_name")
+
+ validate_field_number(doctype_name, name, field_value, company, field_name)
+
+ frappe.db.set_value(doctype_name, name, field_name, field_value)
+
+ if doc_title[0].isdigit():
+ separator = " - " if " - " in doc_title else " "
+ doc_title = doc_title.split(separator, 1)[1]
+
+ frappe.db.set_value(doctype_name, name, frappe.scrub(doctype_name)+"_name", doc_title)
+
+ new_name = get_doc_name_autoname(field_value, doc_title, name, company)
+
+ if name != new_name:
+ frappe.rename_doc(doctype_name, name, new_name)
+ return new_name
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/finance_book/__init__.py b/erpnext/accounts/doctype/finance_book/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/accounts/doctype/finance_book/finance_book.js b/erpnext/accounts/doctype/finance_book/finance_book.js
new file mode 100644
index 0000000000..71191bb0cf
--- /dev/null
+++ b/erpnext/accounts/doctype/finance_book/finance_book.js
@@ -0,0 +1,8 @@
+// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Finance Book', {
+ refresh: function(frm) {
+
+ }
+});
diff --git a/erpnext/accounts/doctype/finance_book/finance_book.json b/erpnext/accounts/doctype/finance_book/finance_book.json
new file mode 100644
index 0000000000..c9fb843cc3
--- /dev/null
+++ b/erpnext/accounts/doctype/finance_book/finance_book.json
@@ -0,0 +1,133 @@
+{
+ "allow_copy": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 1,
+ "allow_rename": 0,
+ "autoname": "field:finance_book_name",
+ "beta": 0,
+ "creation": "2018-04-13 17:42:43.252224",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "Document",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "fields": [
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "finance_book_name",
+ "fieldtype": "Data",
+ "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": "Name",
+ "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
+ }
+ ],
+ "has_web_view": 0,
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "icon": "fa fa-book",
+ "idx": 0,
+ "image_view": 0,
+ "in_create": 0,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 0,
+ "max_attachments": 0,
+ "modified": "2018-05-09 14:55:01.394387",
+ "modified_by": "Administrator",
+ "module": "Accounts",
+ "name": "Finance Book",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "amend": 0,
+ "cancel": 0,
+ "create": 0,
+ "delete": 0,
+ "email": 1,
+ "export": 1,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Accounts User",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 0
+ },
+ {
+ "amend": 0,
+ "cancel": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Accounts Manager",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 1
+ },
+ {
+ "amend": 0,
+ "cancel": 0,
+ "create": 0,
+ "delete": 0,
+ "email": 1,
+ "export": 1,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Auditor",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 0
+ }
+ ],
+ "quick_entry": 1,
+ "read_only": 0,
+ "read_only_onload": 0,
+ "search_fields": "finance_book_name",
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1,
+ "track_seen": 1
+}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/finance_book/finance_book.py b/erpnext/accounts/doctype/finance_book/finance_book.py
new file mode 100644
index 0000000000..bc9fce2ce8
--- /dev/null
+++ b/erpnext/accounts/doctype/finance_book/finance_book.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe.model.document import Document
+
+class FinanceBook(Document):
+ pass
diff --git a/erpnext/setup/doctype/supplier_type/test_supplier_type.js b/erpnext/accounts/doctype/finance_book/test_finance_book.js
similarity index 72%
rename from erpnext/setup/doctype/supplier_type/test_supplier_type.js
rename to erpnext/accounts/doctype/finance_book/test_finance_book.js
index 085dddd0b6..9fb7d4fcc8 100644
--- a/erpnext/setup/doctype/supplier_type/test_supplier_type.js
+++ b/erpnext/accounts/doctype/finance_book/test_finance_book.js
@@ -2,15 +2,15 @@
// rename this file from _test_[name] to test_[name] to activate
// and remove above this line
-QUnit.test("test: Supplier Type", function (assert) {
+QUnit.test("test: Finance Book", function (assert) {
let done = assert.async();
// number of asserts
assert.expect(1);
frappe.run_serially([
- // insert a new Supplier Type
- () => frappe.tests.make('Supplier Type', [
+ // insert a new Finance Book
+ () => frappe.tests.make('Finance Book', [
// values to be set
{key: 'value'}
]),
diff --git a/erpnext/accounts/doctype/finance_book/test_finance_book.py b/erpnext/accounts/doctype/finance_book/test_finance_book.py
new file mode 100644
index 0000000000..771e8130c5
--- /dev/null
+++ b/erpnext/accounts/doctype/finance_book/test_finance_book.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import frappe
+import unittest
+
+class TestFinanceBook(unittest.TestCase):
+ pass
diff --git a/erpnext/accounts/doctype/gl_entry/gl_entry.json b/erpnext/accounts/doctype/gl_entry/gl_entry.json
index 441266199a..4b3396828b 100644
--- a/erpnext/accounts/doctype/gl_entry/gl_entry.json
+++ b/erpnext/accounts/doctype/gl_entry/gl_entry.json
@@ -41,6 +41,7 @@
"reqd": 0,
"search_index": 1,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -72,6 +73,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -104,6 +106,7 @@
"reqd": 0,
"search_index": 1,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -134,6 +137,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -164,6 +168,7 @@
"reqd": 0,
"search_index": 1,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -196,6 +201,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -229,6 +235,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -262,6 +269,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -293,6 +301,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -324,6 +333,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -355,6 +365,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -386,6 +397,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -418,6 +430,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -450,6 +463,7 @@
"reqd": 0,
"search_index": 1,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -482,6 +496,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -514,6 +529,7 @@
"reqd": 0,
"search_index": 1,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -545,6 +561,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -576,6 +593,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -608,6 +626,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -640,6 +659,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -672,6 +692,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -704,6 +725,39 @@
"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": "finance_book",
+ "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": "Finance Book",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Finance Book",
+ "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
}
],
@@ -718,7 +772,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2017-12-20 12:40:09.611951",
+ "modified": "2018-04-23 02:15:22.297509",
"modified_by": "Administrator",
"module": "Accounts",
"name": "GL Entry",
@@ -726,7 +780,6 @@
"permissions": [
{
"amend": 0,
- "apply_user_permissions": 0,
"cancel": 0,
"create": 0,
"delete": 0,
@@ -746,7 +799,6 @@
},
{
"amend": 0,
- "apply_user_permissions": 0,
"cancel": 0,
"create": 0,
"delete": 0,
@@ -766,7 +818,6 @@
},
{
"amend": 0,
- "apply_user_permissions": 0,
"cancel": 0,
"create": 0,
"delete": 0,
@@ -794,4 +845,4 @@
"sort_order": "DESC",
"track_changes": 0,
"track_seen": 0
-}
+}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.json b/erpnext/accounts/doctype/journal_entry/journal_entry.json
index 916c71f20f..a975aa0756 100644
--- a/erpnext/accounts/doctype/journal_entry/journal_entry.json
+++ b/erpnext/accounts/doctype/journal_entry/journal_entry.json
@@ -238,6 +238,38 @@
"translatable": 0,
"unique": 0
},
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "finance_book",
+ "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": "Finance Book",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Finance Book",
+ "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,
@@ -1553,7 +1585,7 @@
"istable": 0,
"max_attachments": 0,
"menu_index": 0,
- "modified": "2018-05-05 13:11:33.696498",
+ "modified": "2018-05-09 14:56:08.687994",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Journal Entry",
diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py
index f9ffbcdbd7..9bbd137159 100644
--- a/erpnext/accounts/doctype/journal_entry/journal_entry.py
+++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py
@@ -3,7 +3,7 @@
from __future__ import unicode_literals
import frappe, erpnext, json
-from frappe.utils import cstr, flt, fmt_money, formatdate, getdate, nowdate
+from frappe.utils import cstr, flt, fmt_money, formatdate, getdate, nowdate, cint
from frappe import msgprint, _, scrub
from erpnext.controllers.accounts_controller import AccountsController
from erpnext.accounts.utils import get_balance_on, get_account_currency
@@ -92,6 +92,7 @@ class JournalEntry(AccountsController):
self.unlink_advance_entry_reference()
self.unlink_asset_reference()
self.unlink_inter_company_jv()
+ self.unlink_asset_adjustment_entry()
def unlink_advance_entry_reference(self):
for d in self.get("accounts"):
@@ -109,9 +110,12 @@ class JournalEntry(AccountsController):
for s in asset.get("schedules"):
if s.journal_entry == self.name:
s.db_set("journal_entry", None)
- asset.value_after_depreciation += s.depreciation_amount
- asset.db_set("value_after_depreciation", asset.value_after_depreciation)
+ idx = cint(s.finance_book_id) or 1
+ finance_books = asset.get('finance_books')[idx - 1]
+ finance_books.value_after_depreciation += s.depreciation_amount
+ finance_books.db_update()
+
asset.set_status()
def unlink_inter_company_jv(self):
@@ -121,6 +125,10 @@ class JournalEntry(AccountsController):
frappe.db.set_value("Journal Entry", self.name,\
"inter_company_journal_entry_reference", "")
+ def unlink_asset_adjustment_entry(self):
+ frappe.db.sql(""" update `tabAsset Adjustment`
+ set journal_entry = null where journal_entry = %s""", self.name)
+
def validate_party(self):
for d in self.get("accounts"):
account_type = frappe.db.get_value("Account", d.account, "account_type")
@@ -460,7 +468,8 @@ class JournalEntry(AccountsController):
"against_voucher": d.reference_name,
"remarks": self.remark,
"cost_center": d.cost_center,
- "project": d.project
+ "project": d.project,
+ "finance_book": self.finance_book
})
)
diff --git a/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py b/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py
index 753540eb42..5712bf83ab 100644
--- a/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py
+++ b/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py
@@ -120,12 +120,12 @@ class OpeningInvoiceCreationTool(Document):
if party_type == "Customer":
party_doc.customer_name = party
else:
- supplier_type = frappe.db.get_single_value("Buying Settings", "supplier_type")
- if not supplier_type:
- frappe.throw(_("Please Set Supplier Type in Buying Settings."))
+ supplier_group = frappe.db.get_single_value("Buying Settings", "supplier_group")
+ if not supplier_group:
+ frappe.throw(_("Please Set Supplier Group in Buying Settings."))
party_doc.supplier_name = party
- party_doc.supplier_type = supplier_type
+ party_doc.supplier_group = supplier_group
party_doc.flags.ignore_mandatory = True
party_doc.save(ignore_permissions=True)
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py
index f983868a0f..0a22ae0a47 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.py
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py
@@ -7,7 +7,7 @@ import frappe, erpnext, json
from frappe import _, scrub, ValidationError
from frappe.utils import flt, comma_or, nowdate
from erpnext.accounts.utils import get_outstanding_invoices, get_account_currency, get_balance_on
-from erpnext.accounts.party import get_party_account
+from erpnext.accounts.party import get_party_account, get_patry_tax_withholding_details
from erpnext.accounts.doctype.journal_entry.journal_entry import get_default_bank_cash_account
from erpnext.setup.utils import get_exchange_rate
from erpnext.accounts.general_ledger import make_gl_entries
@@ -43,6 +43,7 @@ class PaymentEntry(AccountsController):
def validate(self):
self.setup_party_account_field()
+ self.set_tax_withholding()
self.set_missing_values()
self.validate_payment_type()
self.validate_party_details()
@@ -510,6 +511,27 @@ class PaymentEntry(AccountsController):
def on_recurring(self, reference_doc, subscription_doc):
self.reference_no = reference_doc.name
self.reference_date = nowdate()
+
+ def set_tax_withholding(self):
+ if self.party_type != 'Supplier':
+ return
+
+ self.supplier = self.party
+ tax_withholding_details = get_patry_tax_withholding_details(self)
+
+ for tax_details in tax_withholding_details:
+ if self.deductions:
+ if tax_details['tax']['account_head'] not in [deduction.account for deduction in self.deductions]:
+ self.append('deductions', self.calculate_deductions(tax_details))
+ else:
+ self.append('deductions', self.calculate_deductions(tax_details))
+
+ def calculate_deductions(self, tax_details):
+ return {
+ "account": tax_details['tax']['account_head'],
+ "cost_center": frappe.db.get_value("Company", self.company, "cost_center"),
+ "amount": self.total_allocated_amount * (tax_details['tax']['rate'] / 100)
+ }
@frappe.whitelist()
def get_outstanding_reference_documents(args):
diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.js b/erpnext/accounts/doctype/pricing_rule/pricing_rule.js
index dcbf354c16..4be09deb4b 100644
--- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.js
+++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.js
@@ -33,7 +33,7 @@ frappe.ui.form.on("Pricing Rule", "refresh", function(frm) {
${__("Pricing Rule is first selected based on 'Apply On' field, which can be Item, Item Group or Brand.")}
- ${__("Then Pricing Rules are filtered out based on Customer, Customer Group, Territory, Supplier, Supplier Type, Campaign, Sales Partner etc.")}
+ ${__("Then Pricing Rules are filtered out based on Customer, Customer Group, Territory, Supplier, Supplier Group, Campaign, Sales Partner etc.")}
${__('Pricing Rules are further filtered based on quantity.')}
@@ -51,7 +51,7 @@ frappe.ui.form.on("Pricing Rule", "refresh", function(frm) {
${__('Customer > Customer Group > Territory')}
- ${__('Supplier > Supplier Type')}
+ ${__('Supplier > Supplier Group')}
@@ -75,7 +75,7 @@ cur_frm.cscript.set_options_for_applicable_for = function() {
options = $.merge(options, ["Customer", "Customer Group", "Territory", "Sales Partner", "Campaign"]);
}
if(cur_frm.doc.buying) {
- $.merge(options, ["Supplier", "Supplier Type"]);
+ $.merge(options, ["Supplier", "Supplier Group"]);
}
set_field_options("applicable_for", options.join("\n"));
diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.json b/erpnext/accounts/doctype/pricing_rule/pricing_rule.json
index 1c30fa4357..ac5990427e 100644
--- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.json
+++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.json
@@ -39,6 +39,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -69,6 +70,7 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -100,6 +102,7 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -131,6 +134,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -162,6 +166,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -193,6 +198,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -222,6 +228,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -253,6 +260,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -282,6 +290,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -311,6 +320,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -340,6 +350,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -369,6 +380,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -398,6 +410,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -419,7 +432,7 @@
"label": "Applicable For",
"length": 0,
"no_copy": 0,
- "options": "\nCustomer\nCustomer Group\nTerritory\nSales Partner\nCampaign\nSupplier\nSupplier Type",
+ "options": "\nCustomer\nCustomer Group\nTerritory\nSales Partner\nCampaign\nSupplier\nSupplier Group",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
@@ -429,6 +442,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -460,6 +474,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -491,6 +506,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -522,6 +538,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -553,6 +570,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -584,6 +602,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -615,6 +634,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -623,8 +643,8 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
- "depends_on": "eval:doc.applicable_for==\"Supplier Type\"",
- "fieldname": "supplier_type",
+ "depends_on": "eval:doc.applicable_for==\"Supplier Group\"",
+ "fieldname": "supplier_group",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
@@ -633,10 +653,10 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
- "label": "Supplier Type",
+ "label": "Supplier Group",
"length": 0,
"no_copy": 0,
- "options": "Supplier Type",
+ "options": "Supplier Group",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
@@ -646,6 +666,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -675,6 +696,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -704,6 +726,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -733,6 +756,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -762,6 +786,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -791,6 +816,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -821,6 +847,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -850,6 +877,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -878,6 +906,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -908,6 +937,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -940,6 +970,7 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -971,6 +1002,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -1003,6 +1035,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -1032,6 +1065,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -1064,6 +1098,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -1093,6 +1128,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -1124,6 +1160,7 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -1152,6 +1189,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -1182,6 +1220,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -1212,6 +1251,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -1243,6 +1283,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -1273,6 +1314,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -1302,6 +1344,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
}
],
@@ -1316,7 +1359,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2018-02-12 17:21:22.559996",
+ "modified": "2018-04-19 07:52:41.024618",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Pricing Rule",
@@ -1324,7 +1367,6 @@
"permissions": [
{
"amend": 0,
- "apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
@@ -1344,7 +1386,6 @@
},
{
"amend": 0,
- "apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
@@ -1364,7 +1405,6 @@
},
{
"amend": 0,
- "apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
@@ -1384,7 +1424,6 @@
},
{
"amend": 0,
- "apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
@@ -1404,7 +1443,6 @@
},
{
"amend": 0,
- "apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py
index e047b6d67e..9b73fcd968 100644
--- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py
+++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py
@@ -41,7 +41,7 @@ class PricingRule(Document):
throw(_("Selling must be checked, if Applicable For is selected as {0}"
.format(self.applicable_for)))
- if not self.buying and self.applicable_for in ["Supplier", "Supplier Type"]:
+ if not self.buying and self.applicable_for in ["Supplier", "Supplier Group"]:
throw(_("Buying must be checked, if Applicable For is selected as {0}"
.format(self.applicable_for)))
@@ -85,7 +85,7 @@ def apply_pricing_rule(args):
"customer_group": "something",
"territory": "something",
"supplier": "something",
- "supplier_type": "something",
+ "supplier_group": "something",
"currency": "something",
"conversion_rate": "something",
"price_list": "something",
@@ -165,10 +165,10 @@ def get_pricing_rule_for_item(args):
if customer:
args.customer_group, args.territory = customer
- args.supplier = args.supplier_type = None
+ args.supplier = args.supplier_group = None
- elif args.supplier and not args.supplier_type:
- args.supplier_type = frappe.db.get_value("Supplier", args.supplier, "supplier_type")
+ elif args.supplier and not args.supplier_group:
+ args.supplier_group = frappe.db.get_value("Supplier", args.supplier, "supplier_group")
args.customer = args.customer_group = args.territory = None
pricing_rules = get_pricing_rules(args)
@@ -258,7 +258,7 @@ def get_pricing_rules(args):
conditions = item_variant_condition = ""
values = {"item_code": args.get("item_code"), "brand": args.get("brand")}
- for field in ["company", "customer", "supplier", "supplier_type", "campaign", "sales_partner"]:
+ for field in ["company", "customer", "supplier", "supplier_group", "campaign", "sales_partner"]:
if args.get(field):
conditions += " and ifnull("+field+", '') in (%("+field+")s, '')"
values[field] = args.get(field)
@@ -324,11 +324,11 @@ def filter_pricing_rules(args, pricing_rules):
# apply internal priority
all_fields = ["item_code", "item_group", "brand", "customer", "customer_group", "territory",
- "supplier", "supplier_type", "campaign", "sales_partner", "variant_of"]
+ "supplier", "supplier_group", "campaign", "sales_partner", "variant_of"]
if len(pricing_rules) > 1:
for field_set in [["item_code", "variant_of", "item_group", "brand"],
- ["customer", "customer_group", "territory"], ["supplier", "supplier_type"]]:
+ ["customer", "customer_group", "territory"], ["supplier", "supplier_group"]]:
remaining_fields = list(set(all_fields) - set(field_set))
if if_all_rules_same(pricing_rules, remaining_fields):
pricing_rules = apply_internal_priority(pricing_rules, field_set, args)
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
index e7fdd64a6d..d2c41938fe 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
@@ -205,9 +205,10 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
var row = locals[cdt][cdn];
if(row.asset) {
frappe.call({
- method: "erpnext.accounts.doctype.purchase_invoice.purchase_invoice.get_fixed_asset_account",
+ method: "erpnext.assets.doctype.asset_category.asset_category.get_asset_category_account",
args: {
"asset": row.asset,
+ "fieldname": "fixed_asset_account",
"account": row.expense_account
},
callback: function(r, rt) {
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
index 67b41a3248..c9cf47d114 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
@@ -8,7 +8,7 @@ from frappe import _, throw
import frappe.defaults
from erpnext.controllers.buying_controller import BuyingController
-from erpnext.accounts.party import get_party_account, get_due_date
+from erpnext.accounts.party import get_party_account, get_due_date, get_patry_tax_withholding_details
from erpnext.accounts.utils import get_account_currency, get_fiscal_year
from erpnext.stock.doctype.purchase_receipt.purchase_receipt import update_billed_amount_based_on_po
from erpnext.stock import get_warehouse_account_map
@@ -19,6 +19,7 @@ from erpnext.accounts.general_ledger import get_round_off_account_and_cost_cente
from frappe.model.mapper import get_mapped_doc
from erpnext.accounts.doctype.sales_invoice.sales_invoice import validate_inter_company_party, update_linked_invoice,\
unlink_inter_company_invoice
+from erpnext.assets.doctype.asset_category.asset_category import get_asset_category_account
form_grid_templates = {
"items": "templates/form_grid/item_grid.html"
@@ -45,6 +46,7 @@ class PurchaseInvoice(BuyingController):
self.is_opening = 'No'
self.validate_posting_time()
+ self.set_tax_withholding()
super(PurchaseInvoice, self).validate()
if not self.is_return:
@@ -52,7 +54,6 @@ class PurchaseInvoice(BuyingController):
self.pr_required()
self.validate_supplier_invoice()
-
# validate cash purchase
if (self.is_paid == 1):
self.validate_cash()
@@ -167,7 +168,6 @@ class PurchaseInvoice(BuyingController):
super(PurchaseInvoice, self).validate_warehouse()
-
def validate_item_code(self):
for d in self.get('items'):
if not d.item_code:
@@ -305,24 +305,8 @@ class PurchaseInvoice(BuyingController):
self.make_gl_entries()
self.update_project()
- self.update_fixed_asset()
update_linked_invoice(self.doctype, self.name, self.inter_company_invoice_reference)
- def update_fixed_asset(self):
- for d in self.get("items"):
- if d.is_fixed_asset:
- asset = frappe.get_doc("Asset", d.asset)
- if self.docstatus==1:
- asset.purchase_invoice = self.name
- asset.purchase_date = self.posting_date
- asset.supplier = self.supplier
- else:
- asset.purchase_invoice = None
- asset.supplier = None
-
- asset.flags.ignore_validate_update_after_submit = True
- asset.save()
-
def make_gl_entries(self, gl_entries=None, repost_future_gle=True, from_repost=False):
if not self.grand_total:
return
@@ -438,6 +422,50 @@ class PurchaseInvoice(BuyingController):
"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
"credit": flt(item.rm_supp_cost)
}, warehouse_account[self.supplier_warehouse]["account_currency"]))
+
+ elif item.is_fixed_asset:
+ asset_accounts = self.get_company_default(["asset_received_but_not_billed",
+ "expenses_included_in_asset_valuation", "capital_work_in_progress_account"])
+
+ asset_amount = flt(item.net_amount) + flt(item.item_tax_amount/self.conversion_rate)
+ base_asset_amount = flt(item.base_net_amount + item.item_tax_amount)
+
+ if not self.update_stock:
+ asset_rbnb_currency = get_account_currency(asset_accounts[0])
+ gl_entries.append(self.get_gl_dict({
+ "account": asset_accounts[0],
+ "against": self.supplier,
+ "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)
+ }))
+ else:
+ cwip_account = get_asset_category_account(item.asset,
+ 'capital_work_in_progress_account') or asset_accounts[2]
+
+ cwip_account_currency = get_account_currency(cwip_account)
+ gl_entries.append(self.get_gl_dict({
+ "account": cwip_account,
+ "against": self.supplier,
+ "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 item.item_tax_amount:
+ asset_eiiav_currency = get_account_currency(asset_accounts[0])
+ gl_entries.append(self.get_gl_dict({
+ "account": asset_accounts[1],
+ "against": self.supplier,
+ "remarks": self.get("remarks") or _("Accounting Entry for Asset"),
+ "cost_center": item.cost_center,
+ "credit": item.item_tax_amount,
+ "credit_in_account_currency": (item.item_tax_amount
+ if asset_eiiav_currency == self.company_currency else
+ item.item_tax_amount / self.conversion_rate)
+ }))
else:
gl_entries.append(
self.get_gl_dict({
@@ -636,7 +664,6 @@ class PurchaseInvoice(BuyingController):
self.make_gl_entries_on_cancel()
self.update_project()
- self.update_fixed_asset()
frappe.db.set(self, 'status', 'Cancelled')
unlink_inter_company_invoice(self.doctype, self.name, self.inter_company_invoice_reference)
@@ -703,25 +730,25 @@ class PurchaseInvoice(BuyingController):
def on_recurring(self, reference_doc, subscription_doc):
self.due_date = None
+ def set_tax_withholding(self):
+ """
+ 1. Get TDS Configurations against Supplier
+ """
+
+ tax_withholding_details = get_patry_tax_withholding_details(self)
+ for tax_details in tax_withholding_details:
+ if flt(self.get("rounded_total") or self.grand_total) >= flt(tax_details['threshold']):
+ if self.taxes:
+ if tax_details['tax']['description'] not in [tax.description for tax in self.taxes]:
+ self.append('taxes', tax_details['tax'])
+ else:
+ self.append('taxes', tax_details['tax'])
+
@frappe.whitelist()
def make_debit_note(source_name, target_doc=None):
from erpnext.controllers.sales_and_purchase_return import make_return_doc
return make_return_doc("Purchase Invoice", source_name, target_doc)
-@frappe.whitelist()
-def get_fixed_asset_account(asset, account=None):
- if account:
- if frappe.db.get_value("Account", account, "account_type") != "Fixed Asset":
- account=None
-
- if not account:
- asset_category, company = frappe.db.get_value("Asset", asset, ["asset_category", "company"])
-
- account = frappe.db.get_value("Asset Category Account",
- filters={"parent": asset_category, "company_name": company}, fieldname="fixed_asset_account")
-
- return account
-
@frappe.whitelist()
def make_stock_entry(source_name, target_doc=None):
doc = get_mapped_doc("Purchase Invoice", source_name, {
diff --git a/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json b/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json
index d1f99ab3eb..ef9b2f69b6 100755
--- a/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json
+++ b/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json
@@ -2258,7 +2258,7 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
- "modified": "2018-02-22 15:15:25.297672",
+ "modified": "2018-04-23 14:07:33.576495",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Invoice Item",
diff --git a/erpnext/accounts/doctype/tax_rule/tax_rule.js b/erpnext/accounts/doctype/tax_rule/tax_rule.js
index 84c42a3da3..370890e4d8 100644
--- a/erpnext/accounts/doctype/tax_rule/tax_rule.js
+++ b/erpnext/accounts/doctype/tax_rule/tax_rule.js
@@ -2,7 +2,7 @@
// License: GNU General Public License v3. See license.txt
cur_frm.add_fetch("customer", "customer_group", "customer_group" );
-cur_frm.add_fetch("supplier", "supplier_type", "supplier_type" );
+cur_frm.add_fetch("supplier", "supplier_group_name", "supplier_group" );
frappe.ui.form.on("Tax Rule", "tax_type", function(frm) {
frm.toggle_reqd("sales_tax_template", frm.doc.tax_type=="Sales");
diff --git a/erpnext/accounts/doctype/tax_rule/tax_rule.json b/erpnext/accounts/doctype/tax_rule/tax_rule.json
index a746dafa04..56ca055770 100644
--- a/erpnext/accounts/doctype/tax_rule/tax_rule.json
+++ b/erpnext/accounts/doctype/tax_rule/tax_rule.json
@@ -1,5 +1,6 @@
{
"allow_copy": 0,
+ "allow_guest_to_view": 0,
"allow_import": 1,
"allow_rename": 0,
"autoname": "TR.####",
@@ -12,6 +13,7 @@
"editable_grid": 0,
"fields": [
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -40,9 +42,11 @@
"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,
@@ -69,9 +73,11 @@
"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,
@@ -97,9 +103,11 @@
"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,
@@ -128,9 +136,11 @@
"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,
@@ -159,9 +169,11 @@
"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,
@@ -188,9 +200,11 @@
"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,
@@ -219,9 +233,11 @@
"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,
@@ -250,9 +266,11 @@
"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,
@@ -279,9 +297,11 @@
"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,
@@ -308,9 +328,11 @@
"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,
@@ -337,9 +359,11 @@
"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,
@@ -367,9 +391,11 @@
"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,
@@ -395,9 +421,11 @@
"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,
@@ -426,15 +454,17 @@
"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,
"depends_on": "eval:doc.tax_type==\"Purchase\"",
- "fieldname": "supplier_type",
+ "fieldname": "supplier_group",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
@@ -443,10 +473,10 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
- "label": "Supplier Type",
+ "label": "Supplier Group",
"length": 0,
"no_copy": 0,
- "options": "Supplier Type",
+ "options": "Supplier Group",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@@ -457,9 +487,11 @@
"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,
@@ -486,9 +518,11 @@
"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,
@@ -515,9 +549,11 @@
"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,
@@ -544,9 +580,11 @@
"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,
@@ -574,9 +612,11 @@
"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,
@@ -603,9 +643,11 @@
"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,
@@ -632,9 +674,11 @@
"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,
@@ -660,9 +704,11 @@
"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,
@@ -689,9 +735,11 @@
"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,
@@ -717,9 +765,11 @@
"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,
@@ -747,9 +797,11 @@
"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,
@@ -775,9 +827,11 @@
"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,
@@ -805,20 +859,21 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
}
],
+ "has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
- "in_dialog": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2017-02-17 16:22:42.501765",
+ "modified": "2018-04-19 07:53:43.020808",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Tax Rule",
@@ -827,7 +882,6 @@
"permissions": [
{
"amend": 0,
- "apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
diff --git a/erpnext/accounts/doctype/tax_rule/tax_rule.py b/erpnext/accounts/doctype/tax_rule/tax_rule.py
index ddef65799b..56bd2870ba 100644
--- a/erpnext/accounts/doctype/tax_rule/tax_rule.py
+++ b/erpnext/accounts/doctype/tax_rule/tax_rule.py
@@ -30,7 +30,7 @@ class TaxRule(Document):
def validate_tax_template(self):
if self.tax_type== "Sales":
- self.purchase_tax_template = self.supplier = self.supplier_type = None
+ self.purchase_tax_template = self.supplier = self.supplier_group = None
if self.customer:
self.customer_group = None
@@ -38,7 +38,7 @@ class TaxRule(Document):
self.sales_tax_template = self.customer = self.customer_group = None
if self.supplier:
- self.supplier_type = None
+ self.supplier_group = None
if not (self.sales_tax_template or self.purchase_tax_template):
frappe.throw(_("Tax Template is mandatory."))
@@ -53,7 +53,7 @@ class TaxRule(Document):
"customer": self.customer,
"customer_group": self.customer_group,
"supplier": self.supplier,
- "supplier_type": self.supplier_type,
+ "supplier_group": self.supplier_group,
"billing_city": self.billing_city,
"billing_county": self.billing_county,
"billing_state": self.billing_state,
diff --git a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.json b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.json
index f02a52043e..a590776e68 100644
--- a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.json
+++ b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.json
@@ -13,6 +13,68 @@
"editable_grid": 1,
"engine": "InnoDB",
"fields": [
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "is_default",
+ "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": "Is Default",
+ "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": "enabled",
+ "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": "Enabled",
+ "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,
@@ -271,7 +333,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2018-04-13 19:17:12.494050",
+ "modified": "2018-05-11 14:25:07.474461",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Tax Withholding Category",
diff --git a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
index 4940c4f3fe..61f4b60c8b 100644
--- a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
+++ b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
@@ -7,4 +7,7 @@ import frappe
from frappe.model.document import Document
class TaxWithholdingCategory(Document):
- pass
+ def validate(self):
+ if not frappe.db.get_value("Tax Withholding Category",
+ {"is_default": 1, "name": ("!=", self.name)}, "name"):
+ self.is_default = 1
\ No newline at end of file
diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py
index 6f272cf833..75089b2ff4 100644
--- a/erpnext/accounts/party.py
+++ b/erpnext/accounts/party.py
@@ -47,7 +47,7 @@ def _get_party_details(party=None, account=None, party_type="Customer", company=
set_contact_details(out, party, party_type)
set_other_values(out, party, party_type)
set_price_list(out, party, party_type, price_list)
- out["taxes_and_charges"] = set_taxes(party.name, party_type, posting_date, company, out.customer_group, out.supplier_type)
+ out["taxes_and_charges"] = set_taxes(party.name, party_type, posting_date, company, out.customer_group, out.supplier_group)
out["payment_terms_template"] = get_pyt_term_template(party.name, party_type, company)
if not out.get("currency"):
@@ -105,7 +105,7 @@ def set_other_values(out, party, party_type):
if party_type=="Customer":
to_copy = ["customer_name", "customer_group", "territory", "language"]
else:
- to_copy = ["supplier_name", "supplier_type", "language"]
+ to_copy = ["supplier_name", "supplier_group", "language"]
for f in to_copy:
out[f] = party.get(f)
@@ -169,7 +169,7 @@ def set_account_and_due_date(party, account, party_type, company, posting_date,
def get_party_account(party_type, party, company):
"""Returns the account for the given `party`.
Will first search in party (Customer / Supplier) record, if not found,
- will search in group (Customer Group / Supplier Type),
+ will search in group (Customer Group / Supplier Group),
finally will return default."""
if not company:
frappe.throw(_("Please select a Company"))
@@ -181,7 +181,7 @@ def get_party_account(party_type, party, company):
{"parenttype": party_type, "parent": party, "company": company}, "account")
if not account and party_type in ['Customer', 'Supplier']:
- party_group_doctype = "Customer Group" if party_type=="Customer" else "Supplier Type"
+ party_group_doctype = "Customer Group" if party_type=="Customer" else "Supplier Group"
group = frappe.db.get_value(party_type, party, scrub(party_group_doctype))
account = frappe.db.get_value("Party Account",
{"parenttype": party_group_doctype, "parent": group, "company": company}, "account")
@@ -274,8 +274,8 @@ def get_due_date(posting_date, party_type, party, company=None, bill_date=None):
due_date = get_due_date_from_template(template_name, posting_date, bill_date).strftime("%Y-%m-%d")
else:
if party_type == "Supplier":
- supplier_type = frappe.db.get_value(party_type, party, fieldname="supplier_type")
- template_name = frappe.db.get_value("Supplier Type", supplier_type, fieldname="payment_terms")
+ supplier_group = frappe.db.get_value(party_type, party, fieldname="supplier_group")
+ template_name = frappe.db.get_value("Supplier Group", supplier_group, fieldname="payment_terms")
if template_name:
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
@@ -321,7 +321,7 @@ def validate_due_date(posting_date, due_date, party_type, party, company=None, b
.format(formatdate(default_due_date)))
@frappe.whitelist()
-def set_taxes(party, party_type, posting_date, company, customer_group=None, supplier_type=None,
+def set_taxes(party, party_type, posting_date, company, customer_group=None, supplier_group=None,
billing_address=None, shipping_address=None, use_for_shopping_cart=None):
from erpnext.accounts.doctype.tax_rule.tax_rule import get_tax_template, get_party_details
args = {
@@ -332,8 +332,8 @@ def set_taxes(party, party_type, posting_date, company, customer_group=None, sup
if customer_group:
args['customer_group'] = customer_group
- if supplier_type:
- args['supplier_type'] = supplier_type
+ if supplier_group:
+ args['supplier_group'] = supplier_group
if billing_address or shipping_address:
args.update(get_party_details(party, party_type, {"billing_address": billing_address, \
@@ -371,10 +371,10 @@ def get_pyt_term_template(party_name, party_type, company=None):
customer.customer_group, fieldname='payment_terms')
else:
supplier = frappe.db.get_value("Supplier", party_name,
- fieldname=['payment_terms', "supplier_type"], as_dict=1)
+ fieldname=['payment_terms', "supplier_group"], as_dict=1)
template = supplier.payment_terms
- if not template and supplier.supplier_type:
- template = frappe.db.get_value("Supplier Type", supplier.supplier_type, fieldname='payment_terms')
+ if not template and supplier.supplier_group:
+ template = frappe.db.get_value("Supplier Group", supplier.supplier_group, fieldname='payment_terms')
if not template and company:
template = frappe.db.get_value("Company", company, fieldname='payment_terms')
@@ -448,7 +448,6 @@ def get_dashboard_info(party_type, party):
return info
-
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.
@@ -476,3 +475,60 @@ def get_party_shipping_address(doctype, name):
return out[0][0]
else:
return ''
+
+def get_patry_tax_withholding_details(ref_doc):
+ supplier = frappe.get_doc("Supplier", ref_doc.supplier)
+ tax_withholding_details = []
+ print(supplier)
+ for tax in supplier.tax_withholding_config:
+ tax_mapper = get_tax_mapper()
+
+ set_tax_withholding_details(tax_mapper, ref_doc, tax_withholding_category=tax.tax_withholding_category)
+
+ if tax.valid_till and date_diff(tax.valid_till, ref_doc.posting_date) > 0:
+ tax_mapper.update({
+ "rate": tax.applicable_percentage
+ })
+
+ prepare_tax_withholding_details(tax_mapper, tax_withholding_details)
+
+ return tax_withholding_details
+
+def prepare_tax_withholding_details(tax_mapper, tax_withholding_details):
+ if tax_mapper.get('account_head'):
+
+ tax_withholding_details.append({
+ "threshold": tax_mapper['threshold'],
+ "tax": tax_mapper
+ })
+
+ del tax_mapper['threshold']
+
+def set_tax_withholding_details(tax_mapper, ref_doc, tax_withholding_category=None, use_default=0):
+ if tax_withholding_category:
+ tax_withholding = frappe.get_doc("Tax Withholding Category", tax_withholding_category)
+ else:
+ tax_withholding = frappe.get_doc("Tax Withholding Category", {'is_default': 1, 'enabled': 1})
+
+ if tax_withholding.book_on_invoice and ref_doc.doctype=='Purchase Invoice' \
+ or tax_withholding.book_on_advance and ref_doc.doctype in ('Payment Entry', 'Journal Entry'):
+
+ for account_detail in tax_withholding.accounts:
+ if ref_doc.company == account_detail.company:
+ tax_mapper.update({
+ "account_head": account_detail.account,
+ "rate": tax_withholding.percent_of_tax_withheld,
+ "threshold": tax_withholding.threshold,
+ "description": tax_withholding.name
+ })
+
+def get_tax_mapper():
+ return {
+ "category": "Total",
+ "add_deduct_tax": "Deduct",
+ "charge_type": "On Net Total",
+ "rate": 0,
+ "description": '',
+ "account_head": '',
+ "threshold": 0.0
+ }
diff --git a/erpnext/accounts/report/accounts_payable/accounts_payable.js b/erpnext/accounts/report/accounts_payable/accounts_payable.js
index 63ef83263c..f39df3da3d 100644
--- a/erpnext/accounts/report/accounts_payable/accounts_payable.js
+++ b/erpnext/accounts/report/accounts_payable/accounts_payable.js
@@ -10,6 +10,12 @@ frappe.query_reports["Accounts Payable"] = {
"options": "Company",
"default": frappe.defaults.get_user_default("Company")
},
+ {
+ "fieldname":"finance_book",
+ "label": __("Finance Book"),
+ "fieldtype": "Link",
+ "options": "Finance Book"
+ },
{
"fieldname":"supplier",
"label": __("Supplier"),
diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.js b/erpnext/accounts/report/accounts_receivable/accounts_receivable.js
index ec1e9f9d61..2caf3590fb 100644
--- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.js
+++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.js
@@ -10,6 +10,12 @@ frappe.query_reports["Accounts Receivable"] = {
"options": "Company",
"default": frappe.defaults.get_user_default("Company")
},
+ {
+ "fieldname":"finance_book",
+ "label": __("Finance Book"),
+ "fieldtype": "Link",
+ "options": "Finance Book"
+ },
{
"fieldname":"customer",
"label": __("Customer"),
diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
index 61096837f5..ca806bfc4a 100644
--- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
+++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
@@ -112,7 +112,7 @@ class ReceivablePayableReport(object):
_("Customer Group") + ":Link/Customer Group:120"
]
if args.get("party_type") == "Supplier":
- columns += [_("Supplier Type") + ":Link/Supplier Type:80"]
+ columns += [_("Supplier Group") + ":Link/Supplier Group:80"]
columns.append(_("Remarks") + "::200")
@@ -194,11 +194,11 @@ class ReceivablePayableReport(object):
# Delivery Note
row += [voucher_details.get(gle.voucher_no, {}).get("delivery_note")]
- # customer territory / supplier type
+ # customer territory / supplier group
if args.get("party_type") == "Customer":
row += [self.get_territory(gle.party), self.get_customer_group(gle.party)]
if args.get("party_type") == "Supplier":
- row += [self.get_supplier_type(gle.party)]
+ row += [self.get_supplier_group(gle.party)]
row.append(gle.remarks)
data.append(row)
@@ -260,15 +260,15 @@ class ReceivablePayableReport(object):
def get_customer_group(self, party_name):
return self.get_party_map("Customer").get(party_name, {}).get("customer_group") or ""
- def get_supplier_type(self, party_name):
- return self.get_party_map("Supplier").get(party_name, {}).get("supplier_type") or ""
+ def get_supplier_group(self, party_name):
+ return self.get_party_map("Supplier").get(party_name, {}).get("supplier_group") or ""
def get_party_map(self, party_type):
if not hasattr(self, "party_map"):
if party_type == "Customer":
select_fields = "name, customer_name, territory, customer_group"
elif party_type == "Supplier":
- select_fields = "name, supplier_name, supplier_type"
+ select_fields = "name, supplier_name, supplier_group"
self.party_map = dict(((r.name, r) for r in frappe.db.sql("select {0} from `tab{1}`"
.format(select_fields, party_type), as_dict=True)))
@@ -321,6 +321,13 @@ class ReceivablePayableReport(object):
conditions.append("company=%s")
values.append(self.filters.company)
+ if self.filters.finance_book:
+ conditions.append("finance_book in (%s, '')")
+ values.append(self.filters.finance_book)
+ else:
+ conditions.append("ifnull(finance_book,'')=%s")
+ values.append('')
+
if self.filters.get(party_type_field):
conditions.append("party=%s")
values.append(self.filters.get(party_type_field))
diff --git a/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py b/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py
index 08b24fb147..9b50960f4b 100644
--- a/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py
+++ b/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py
@@ -35,7 +35,7 @@ class AccountsReceivableSummary(ReceivablePayableReport):
_("Customer Group") + ":Link/Customer Group:120"
]
if args.get("party_type") == "Supplier":
- columns += [_("Supplier Type") + ":Link/Supplier Type:80"]
+ columns += [_("Supplier Group") + ":Link/Supplier Group:80"]
columns.append({
"fieldname": "currency",
@@ -66,7 +66,7 @@ class AccountsReceivableSummary(ReceivablePayableReport):
if args.get("party_type") == "Customer":
row += [self.get_territory(party), self.get_customer_group(party)]
if args.get("party_type") == "Supplier":
- row += [self.get_supplier_type(party)]
+ row += [self.get_supplier_group(party)]
row.append(party_dict.currency)
data.append(row)
@@ -113,7 +113,7 @@ class AccountsReceivableSummary(ReceivablePayableReport):
"outstanding_amt", "age", "range1", "range2", "range3", "range4", "currency"]
if args.get("party_type") == "Supplier":
- cols += ["supplier_type", "remarks"]
+ cols += ["supplier_group", "remarks"]
if args.get("party_type") == "Customer":
cols += ["territory", "customer_group", "remarks"]
diff --git a/erpnext/accounts/report/financial_statements.py b/erpnext/accounts/report/financial_statements.py
index dd47ca0b37..ea22bacf21 100644
--- a/erpnext/accounts/report/financial_statements.py
+++ b/erpnext/accounts/report/financial_statements.py
@@ -375,6 +375,12 @@ def get_additional_conditions(from_date, ignore_closing_entries, filters):
additional_conditions.append("project = '%s'" % (frappe.db.escape(filters.get("project"))))
if filters.get("cost_center"):
additional_conditions.append(get_cost_center_cond(filters.get("cost_center")))
+ if filters.get("finance_book"):
+ additional_conditions.append("finance_book in ('%s', '')" %
+ frappe.db.escape(filters.get("finance_book")))
+ else:
+ additional_conditions.append("ifnull(finance_book, '') = ''")
+
return " and {}".format(" and ".join(additional_conditions)) if additional_conditions else ""
diff --git a/erpnext/accounts/report/general_ledger/general_ledger.js b/erpnext/accounts/report/general_ledger/general_ledger.js
index 5e8f9cfc28..9a774ce6b9 100644
--- a/erpnext/accounts/report/general_ledger/general_ledger.js
+++ b/erpnext/accounts/report/general_ledger/general_ledger.js
@@ -11,6 +11,12 @@ frappe.query_reports["General Ledger"] = {
"default": frappe.defaults.get_user_default("Company"),
"reqd": 1
},
+ {
+ "fieldname":"finance_book",
+ "label": __("Finance Book"),
+ "fieldtype": "Link",
+ "options": "Finance Book"
+ },
{
"fieldname":"from_date",
"label": __("From Date"),
diff --git a/erpnext/accounts/report/general_ledger/general_ledger.py b/erpnext/accounts/report/general_ledger/general_ledger.py
index 7fd653e39b..2d0bd52fd0 100644
--- a/erpnext/accounts/report/general_ledger/general_ledger.py
+++ b/erpnext/accounts/report/general_ledger/general_ledger.py
@@ -164,6 +164,11 @@ def get_conditions(filters):
if filters.get("project"):
conditions.append("project=%(project)s")
+ if filters.get("finance_book"):
+ conditions.append("finance_book in (%(finance_book)s, '')")
+ else:
+ conditions.append("ifnull(finance_book, '')=''")
+
from frappe.desk.reportview import build_match_conditions
match_conditions = build_match_conditions("GL Entry")
diff --git a/erpnext/accounts/report/purchase_register/purchase_register.py b/erpnext/accounts/report/purchase_register/purchase_register.py
index cf599a0ccc..7a298b322f 100644
--- a/erpnext/accounts/report/purchase_register/purchase_register.py
+++ b/erpnext/accounts/report/purchase_register/purchase_register.py
@@ -42,7 +42,7 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum
row.append(inv.get(col))
row += [
- supplier_details.get(inv.supplier), # supplier_type
+ supplier_details.get(inv.supplier), # supplier_group
inv.tax_id, inv.credit_to, inv.mode_of_payment, ", ".join(project),
inv.bill_no, inv.bill_date, inv.remarks,
", ".join(purchase_order), ", ".join(purchase_receipt), company_currency
@@ -83,7 +83,7 @@ def get_columns(invoice_list, additional_table_columns):
columns += additional_table_columns
columns += [
- _("Supplier Type") + ":Link/Supplier Type:120", _("Tax Id") + "::80", _("Payable Account") + ":Link/Account:120",
+ _("Supplier Group") + ":Link/Supplier Group:120", _("Tax Id") + "::80", _("Payable Account") + ":Link/Account:120",
_("Mode of Payment") + ":Link/Mode of Payment:80", _("Project") + ":Link/Project:80",
_("Bill No") + "::120", _("Bill Date") + ":Date:80", _("Remarks") + "::150",
_("Purchase Order") + ":Link/Purchase Order:100",
@@ -229,8 +229,8 @@ def get_account_details(invoice_list):
def get_supplier_details(suppliers):
supplier_details = {}
- for supp in frappe.db.sql("""select name, supplier_type from `tabSupplier`
+ for supp in frappe.db.sql("""select name, supplier_group from `tabSupplier`
where name in (%s)""" % ", ".join(["%s"]*len(suppliers)), tuple(suppliers), as_dict=1):
- supplier_details.setdefault(supp.name, supp.supplier_type)
+ supplier_details.setdefault(supp.name, supp.supplier_group)
return supplier_details
diff --git a/erpnext/assets/doctype/asset/asset.js b/erpnext/assets/doctype/asset/asset.js
index 236c4f9f9b..c05667a767 100644
--- a/erpnext/assets/doctype/asset/asset.js
+++ b/erpnext/assets/doctype/asset/asset.js
@@ -23,6 +23,14 @@ frappe.ui.form.on('Asset', {
}
};
});
+
+ frm.set_query("department", function() {
+ return {
+ "filters": {
+ "company": frm.doc.company,
+ }
+ };
+ });
},
refresh: function(frm) {
@@ -49,6 +57,19 @@ frappe.ui.form.on('Asset', {
erpnext.asset.restore_asset(frm);
});
}
+
+ if (frm.doc.purchase_receipt) {
+ frm.add_custom_button("General Ledger", function() {
+ frappe.route_options = {
+ "voucher_no": frm.doc.name,
+ "from_date": frm.doc.available_for_use_date,
+ "to_date": frm.doc.available_for_use_date,
+ "company": frm.doc.company
+ };
+ frappe.set_route("query-report", "General Ledger");
+ });
+ }
+
if (frm.doc.status=='Submitted' && !frm.doc.is_existing_asset && !frm.doc.purchase_invoice) {
frm.add_custom_button(__("Purchase Invoice"), function() {
frm.trigger("make_purchase_invoice");
@@ -59,6 +80,12 @@ frappe.ui.form.on('Asset', {
frm.trigger("create_asset_maintenance");
}, __("Make"));
}
+ if (frm.doc.status != 'Fully Depreciated') {
+ frm.add_custom_button(__("Asset Adjustment"), function() {
+ frm.trigger("create_asset_maintenance");
+ }, __("Make"));
+ }
+
frm.page.set_inner_btn_group_as_primary(__("Make"));
frm.trigger("setup_chart");
}
@@ -123,9 +150,7 @@ frappe.ui.form.on('Asset', {
},
callback: function(r, rt) {
if(r.message) {
- $.each(r.message, function(field, value) {
- frm.set_value(field, value);
- })
+ frm.set_value('finance_books', r.message);
}
}
})
@@ -133,7 +158,7 @@ frappe.ui.form.on('Asset', {
},
is_existing_asset: function(frm) {
- frm.toggle_reqd("next_depreciation_date", (!frm.doc.is_existing_asset && frm.doc.calculate_depreciation));
+ // frm.toggle_reqd("next_depreciation_date", (!frm.doc.is_existing_asset && frm.doc.calculate_depreciation));
},
opening_accumulated_depreciation: function(frm) {
@@ -173,7 +198,8 @@ frappe.ui.form.on('Asset', {
args: {
"asset": frm.doc.name,
"item_code": frm.doc.item_code,
- "company": frm.doc.company
+ "company": frm.doc.company,
+ "serial_no": frm.doc.serial_no
},
method: "erpnext.assets.doctype.asset.asset.make_sales_invoice",
callback: function(r) {
@@ -282,15 +308,14 @@ erpnext.asset.transfer_asset = function(frm) {
title: __("Transfer Asset"),
fields: [
{
- "label": __("Target Warehouse"),
- "fieldname": "target_warehouse",
+ "label": __("Target Location"),
+ "fieldname": "target_location",
"fieldtype": "Link",
- "options": "Warehouse",
+ "options": "Location",
"get_query": function () {
return {
filters: [
- ["Warehouse", "company", "in", ["", cstr(frm.doc.company)]],
- ["Warehouse", "is_group", "=", 0]
+ ["Location", "is_group", "=", 0]
]
}
},
@@ -317,8 +342,8 @@ erpnext.asset.transfer_asset = function(frm) {
args: {
"asset": frm.doc.name,
"transaction_date": args.transfer_date,
- "source_warehouse": frm.doc.warehouse,
- "target_warehouse": args.target_warehouse,
+ "source_warehouse": frm.doc.location,
+ "target_warehouse": args.target_location,
"company": frm.doc.company
}
},
diff --git a/erpnext/assets/doctype/asset/asset.json b/erpnext/assets/doctype/asset/asset.json
index 49b574d3b0..49a010d7d5 100644
--- a/erpnext/assets/doctype/asset/asset.json
+++ b/erpnext/assets/doctype/asset/asset.json
@@ -3,7 +3,7 @@
"allow_guest_to_view": 0,
"allow_import": 1,
"allow_rename": 1,
- "autoname": "field:asset_name",
+ "autoname": "naming_series:",
"beta": 0,
"creation": "2016-03-01 17:01:27.920130",
"custom": 0,
@@ -12,6 +12,38 @@
"document_type": "Document",
"editable_grid": 0,
"fields": [
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "default": "AST",
+ "fieldname": "naming_series",
+ "fieldtype": "Select",
+ "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": "Naming Series",
+ "length": 0,
+ "no_copy": 0,
+ "options": "AST\nAT",
+ "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,
+ "unique": 0
+ },
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@@ -135,38 +167,6 @@
"set_only_once": 0,
"unique": 0
},
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "Draft",
- "fieldname": "status",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 1,
- "label": "Status",
- "length": 0,
- "no_copy": 1,
- "options": "Draft\nSubmitted\nPartially Depreciated\nFully Depreciated\nSold\nScrapped\nIn Maintenance\nOut of Order",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@@ -390,7 +390,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
- "fieldname": "warehouse",
+ "fieldname": "location",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
@@ -398,11 +398,11 @@
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
- "in_standard_filter": 1,
- "label": "Warehouse",
+ "in_standard_filter": 0,
+ "label": "Location",
"length": 0,
"no_copy": 0,
- "options": "Warehouse",
+ "options": "Location",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@@ -415,6 +415,37 @@
"set_only_once": 0,
"unique": 0
},
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "custodian",
+ "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": "Custodian",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Employee",
+ "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,
+ "unique": 0
+ },
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@@ -476,97 +507,6 @@
"set_only_once": 0,
"unique": 0
},
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "purchase_invoice",
- "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": "Purchase Invoice",
- "length": 0,
- "no_copy": 1,
- "options": "Purchase Invoice",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "available_for_use_date",
- "fieldtype": "Date",
- "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": "Available-for-use Date",
- "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,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "is_existing_asset",
- "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": "Is Existing Asset",
- "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,
- "unique": 0
- },
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@@ -688,6 +628,36 @@
"set_only_once": 0,
"unique": 0
},
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "available_for_use_date",
+ "fieldtype": "Date",
+ "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": "Available-for-use Date",
+ "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,
+ "unique": 0
+ },
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@@ -717,99 +687,6 @@
"set_only_once": 0,
"unique": 0
},
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "",
- "fieldname": "expected_value_after_useful_life",
- "fieldtype": "Currency",
- "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": "Expected Value After Useful Life",
- "length": 0,
- "no_copy": 0,
- "options": "Company:company:default_currency",
- "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,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "is_existing_asset",
- "fieldname": "opening_accumulated_depreciation",
- "fieldtype": "Currency",
- "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": "Opening Accumulated Depreciation",
- "length": 0,
- "no_copy": 1,
- "options": "Company:company:default_currency",
- "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,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "section_break_20",
- "fieldtype": "Section Break",
- "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,
- "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,
- "unique": 0
- },
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@@ -844,7 +721,100 @@
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
- "collapsible": 1,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "is_existing_asset",
+ "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": "Is Existing Asset",
+ "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,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "depends_on": "is_existing_asset",
+ "fieldname": "opening_accumulated_depreciation",
+ "fieldtype": "Currency",
+ "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": "Opening Accumulated Depreciation",
+ "length": 0,
+ "no_copy": 1,
+ "options": "Company:company:default_currency",
+ "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,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "depends_on": "eval:(doc.is_existing_asset && doc.opening_accumulated_depreciation)",
+ "fieldname": "number_of_depreciations_booked",
+ "fieldtype": "Int",
+ "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": "Number of Depreciations Booked",
+ "length": 0,
+ "no_copy": 1,
+ "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,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
"columns": 0,
"depends_on": "calculate_depreciation",
"fieldname": "section_break_23",
@@ -871,6 +841,66 @@
"set_only_once": 0,
"unique": 0
},
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "finance_books",
+ "fieldtype": "Table",
+ "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": "Finance Books",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Asset Finance Book",
+ "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,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "section_break_33",
+ "fieldtype": "Section Break",
+ "hidden": 1,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "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,
+ "unique": 0
+ },
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@@ -994,37 +1024,6 @@
"set_only_once": 0,
"unique": 0
},
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:(doc.is_existing_asset && doc.opening_accumulated_depreciation)",
- "fieldname": "number_of_depreciations_booked",
- "fieldtype": "Int",
- "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": "Number of Depreciations Booked",
- "length": 0,
- "no_copy": 1,
- "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,
- "unique": 0
- },
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@@ -1148,6 +1147,245 @@
"set_only_once": 0,
"unique": 0
},
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 1,
+ "columns": 0,
+ "fieldname": "insurance_details",
+ "fieldtype": "Section Break",
+ "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": "Insurance details",
+ "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,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "policy_number",
+ "fieldtype": "Data",
+ "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": "Policy number",
+ "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,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "insurer",
+ "fieldtype": "Data",
+ "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": "Insurer",
+ "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,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "insured_value",
+ "fieldtype": "Data",
+ "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": "Insured value",
+ "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,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "column_break_48",
+ "fieldtype": "Column Break",
+ "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,
+ "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,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "insurance_start_date",
+ "fieldtype": "Date",
+ "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": "Insurance Start Date",
+ "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,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "insurance_end_date",
+ "fieldtype": "Date",
+ "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": "Insurance End Date",
+ "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,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "comprehensive_insurance",
+ "fieldtype": "Data",
+ "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": "Comprehensive Insurance",
+ "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,
+ "unique": 0
+ },
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@@ -1209,6 +1447,220 @@
"set_only_once": 0,
"unique": 0
},
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 1,
+ "columns": 0,
+ "fieldname": "other_details",
+ "fieldtype": "Section Break",
+ "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": "Other Details",
+ "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,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 1,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "default": "Draft",
+ "fieldname": "status",
+ "fieldtype": "Select",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "Status",
+ "length": 0,
+ "no_copy": 1,
+ "options": "Draft\nSubmitted\nPartially Depreciated\nFully Depreciated\nSold\nScrapped\nIn Maintenance\nOut of Order\nIssue\nReceipt",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "default": "0",
+ "fieldname": "booked_fixed_asset",
+ "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": "Booked Fixed Asset",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "column_break_51",
+ "fieldtype": "Column Break",
+ "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,
+ "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,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "purchase_receipt",
+ "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": "Purchase Receipt",
+ "length": 0,
+ "no_copy": 1,
+ "options": "Purchase Receipt",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 1,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "purchase_receipt_amount",
+ "fieldtype": "Currency",
+ "hidden": 1,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Purchase Receipt Amount",
+ "length": 0,
+ "no_copy": 1,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 1,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "purchase_invoice",
+ "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": "Purchase Invoice",
+ "length": 0,
+ "no_copy": 1,
+ "options": "Purchase Invoice",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@@ -1251,7 +1703,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2018-01-05 09:53:05.945328",
+ "modified": "2018-05-11 10:41:45.972686",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset",
@@ -1307,4 +1759,4 @@
"sort_order": "DESC",
"track_changes": 0,
"track_seen": 0
-}
+}
\ No newline at end of file
diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py
index baffdd757d..55a29bc0df 100644
--- a/erpnext/assets/doctype/asset/asset.py
+++ b/erpnext/assets/doctype/asset/asset.py
@@ -7,11 +7,14 @@ import frappe
from frappe import _
from frappe.utils import flt, add_months, cint, nowdate, getdate, today, date_diff
from frappe.model.document import Document
-from erpnext.accounts.doctype.purchase_invoice.purchase_invoice import get_fixed_asset_account
+from erpnext.assets.doctype.asset_category.asset_category import get_asset_category_account
from erpnext.assets.doctype.asset.depreciation \
import get_disposal_account_and_cost_center, get_depreciation_accounts
+from erpnext.accounts.general_ledger import make_gl_entries
+from erpnext.accounts.utils import get_account_currency
+from erpnext.controllers.accounts_controller import AccountsController
-class Asset(Document):
+class Asset(AccountsController):
def validate(self):
self.status = self.get_status()
self.validate_item()
@@ -26,6 +29,7 @@ class Asset(Document):
def on_submit(self):
self.set_status()
+ self.update_stock_movement()
def on_cancel(self):
self.validate_cancellation()
@@ -45,11 +49,12 @@ class Asset(Document):
frappe.throw(_("Item {0} must be a non-stock item").format(self.item_code))
def set_missing_values(self):
- if self.item_code:
- item_details = get_item_details(self.item_code)
- for field, value in item_details.items():
- if not self.get(field):
- self.set(field, value)
+ if not self.asset_category:
+ self.asset_category = frappe.db.get_value("Item", self.item_code, "asset_category")
+
+ if self.item_code and not self.get('finance_books'):
+ finance_books = get_item_details(self.item_code, self.asset_category)
+ self.set('finance_books', finance_books)
def validate_asset_values(self):
if not flt(self.gross_purchase_amount):
@@ -58,16 +63,105 @@ class Asset(Document):
if not self.calculate_depreciation:
return
- if flt(self.expected_value_after_useful_life) >= flt(self.gross_purchase_amount):
- frappe.throw(_("Expected Value After Useful Life must be less than Gross Purchase Amount"))
+ if self.available_for_use_date and getdate(self.available_for_use_date) < getdate(nowdate()):
+ frappe.throw(_("Available-for-use Date is entered as past date"))
+
+ def make_depreciation_schedule(self):
+ if self.depreciation_method != 'Manual':
+ self.schedules = []
+
+ if not self.get("schedules") and self.available_for_use_date:
+ total_depreciations = sum([d.total_number_of_depreciations for d in self.get('finance_books')])
+
+ for d in self.get('finance_books'):
+ self.validate_asset_finance_books(d)
+
+ value_after_depreciation = (flt(self.gross_purchase_amount) -
+ flt(self.opening_accumulated_depreciation))
+
+ d.value_after_depreciation = value_after_depreciation
+
+ no_of_depreciations = cint(d.total_number_of_depreciations - 1) - cint(self.number_of_depreciations_booked)
+ end_date = add_months(d.depreciation_start_date,
+ no_of_depreciations * cint(d.frequency_of_depreciation))
+
+ total_days = date_diff(end_date, self.available_for_use_date)
+ rate_per_day = value_after_depreciation / total_days
+
+ number_of_pending_depreciations = cint(d.total_number_of_depreciations) - \
+ cint(self.number_of_depreciations_booked)
+
+ from_date = self.available_for_use_date
+ if number_of_pending_depreciations:
+ next_depr_date = getdate(add_months(self.available_for_use_date,
+ number_of_pending_depreciations * 12))
+ if (cint(frappe.db.get_value("Asset Settings", None, "schedule_based_on_fiscal_year")) == 1
+ and getdate(d.depreciation_start_date) < next_depr_date):
+
+ number_of_pending_depreciations += 1
+ for n in range(number_of_pending_depreciations):
+ if n == range(number_of_pending_depreciations)[-1]:
+ schedule_date = add_months(self.available_for_use_date, n * 12)
+ previous_scheduled_date = add_months(d.depreciation_start_date, (n-1) * 12)
+ depreciation_amount = \
+ self.get_depreciation_amount_prorata_temporis(value_after_depreciation,
+ d, previous_scheduled_date, schedule_date)
+
+ elif n == range(number_of_pending_depreciations)[0]:
+ schedule_date = d.depreciation_start_date
+ depreciation_amount = \
+ self.get_depreciation_amount_prorata_temporis(value_after_depreciation,
+ d, self.available_for_use_date, schedule_date)
+
+ else:
+ schedule_date = add_months(d.depreciation_start_date, n * 12)
+ depreciation_amount = \
+ self.get_depreciation_amount_prorata_temporis(value_after_depreciation, d)
+
+ if value_after_depreciation != 0:
+ value_after_depreciation -= flt(depreciation_amount)
+
+ self.append("schedules", {
+ "schedule_date": schedule_date,
+ "depreciation_amount": depreciation_amount,
+ "depreciation_method": d.depreciation_method,
+ "finance_book": d.finance_book,
+ "finance_book_id": d.idx
+ })
+ else:
+ for n in range(number_of_pending_depreciations):
+ schedule_date = add_months(d.depreciation_start_date,
+ n * cint(d.frequency_of_depreciation))
+
+ if d.depreciation_method in ("Straight Line", "Manual"):
+ days = date_diff(schedule_date, from_date)
+ depreciation_amount = days * rate_per_day
+ from_date = schedule_date
+ else:
+ depreciation_amount = self.get_depreciation_amount(value_after_depreciation,
+ d.total_number_of_depreciations, d)
+
+ if depreciation_amount:
+ value_after_depreciation -= flt(depreciation_amount)
+
+ self.append("schedules", {
+ "schedule_date": schedule_date,
+ "depreciation_amount": depreciation_amount,
+ "depreciation_method": d.depreciation_method,
+ "finance_book": d.finance_book,
+ "finance_book_id": d.idx
+ })
+
+ def validate_asset_finance_books(self, row):
+ if flt(row.expected_value_after_useful_life) >= flt(self.gross_purchase_amount):
+ frappe.throw(_("Row {0}: Expected Value After Useful Life must be less than Gross Purchase Amount")
+ .format(row.idx))
if not self.is_existing_asset:
self.opening_accumulated_depreciation = 0
self.number_of_depreciations_booked = 0
- if not self.next_depreciation_date:
- frappe.throw(_("Next Depreciation Date is mandatory for new asset"))
else:
- depreciable_amount = flt(self.gross_purchase_amount) - flt(self.expected_value_after_useful_life)
+ depreciable_amount = flt(self.gross_purchase_amount) - flt(row.expected_value_after_useful_life)
if flt(self.opening_accumulated_depreciation) > depreciable_amount:
frappe.throw(_("Opening Accumulated Depreciation must be less than equal to {0}")
.format(depreciable_amount))
@@ -78,139 +172,89 @@ class Asset(Document):
else:
self.number_of_depreciations_booked = 0
- if cint(self.number_of_depreciations_booked) > cint(self.total_number_of_depreciations):
+ if cint(self.number_of_depreciations_booked) > cint(row.total_number_of_depreciations):
frappe.throw(_("Number of Depreciations Booked cannot be greater than Total Number of Depreciations"))
- self.value_after_depreciation = (flt(self.gross_purchase_amount) -
- flt(self.opening_accumulated_depreciation))
+ if row.depreciation_start_date and getdate(row.depreciation_start_date) < getdate(nowdate()):
+ frappe.msgprint(_("Depreciation Row {0}: Depreciation Start Date is entered as past date")
+ .format(row.idx), title=_('Warning'), indicator='red')
- if self.next_depreciation_date and getdate(self.next_depreciation_date) < getdate(nowdate()):
- frappe.msgprint(_("Next Depreciation Date is entered as past date"), title=_('Warning'), indicator='red')
+ if row.depreciation_start_date and getdate(row.depreciation_start_date) < getdate(self.purchase_date):
+ frappe.throw(_("Depreciation Row {0}: Next Depreciation Date cannot be before Purchase Date")
+ .format(row.idx))
- if self.next_depreciation_date and getdate(self.next_depreciation_date) < getdate(self.purchase_date):
- frappe.throw(_("Next Depreciation Date cannot be before Purchase Date"))
+ if row.depreciation_start_date and getdate(row.depreciation_start_date) < getdate(self.available_for_use_date):
+ frappe.throw(_("Depreciation Row {0}: Next Depreciation Date cannot be before Available-for-use Date")
+ .format(row.idx))
- if self.next_depreciation_date and getdate(self.next_depreciation_date) < getdate(self.available_for_use_date):
- frappe.throw(_("Next Depreciation Date cannot be before Available-for-use Date"))
+ def set_accumulated_depreciation(self, ignore_booked_entry = False):
+ straight_line_idx = [d.idx for d in self.get("schedules") if d.depreciation_method == 'Straight Line']
+ finance_books = []
- if (flt(self.value_after_depreciation) > flt(self.expected_value_after_useful_life)
- and not self.next_depreciation_date and self.calculate_depreciation):
- frappe.throw(_("Please set Next Depreciation Date"))
-
- def make_depreciation_schedule(self):
-
- if self.depreciation_method != 'Manual':
- self.schedules = []
-
- if not self.get("schedules") and self.next_depreciation_date:
- value_after_depreciation = flt(self.value_after_depreciation)
-
- number_of_pending_depreciations = cint(self.total_number_of_depreciations) - \
- cint(self.number_of_depreciations_booked)
- if number_of_pending_depreciations:
- next_depr_date = getdate(add_months(self.available_for_use_date,
- number_of_pending_depreciations * 12))
- if (cint(frappe.db.get_value("Asset Settings", None, "schedule_based_on_fiscal_year")) == 1
- and getdate(self.next_depreciation_date) < next_depr_date):
-
- number_of_pending_depreciations += 1
- for n in range(number_of_pending_depreciations):
- if n == range(number_of_pending_depreciations)[-1]:
- schedule_date = add_months(self.available_for_use_date, n * 12)
- previous_scheduled_date = add_months(self.next_depreciation_date, (n-1) * 12)
- depreciation_amount = \
- self.get_depreciation_amount_prorata_temporis(value_after_depreciation,
- previous_scheduled_date, schedule_date)
-
- elif n == range(number_of_pending_depreciations)[0]:
- schedule_date = self.next_depreciation_date
- depreciation_amount = \
- self.get_depreciation_amount_prorata_temporis(value_after_depreciation,
- self.available_for_use_date, schedule_date)
-
- else:
- schedule_date = add_months(self.next_depreciation_date, n * 12)
- depreciation_amount = \
- self.get_depreciation_amount_prorata_temporis(value_after_depreciation)
-
- if value_after_depreciation != 0:
- value_after_depreciation -= flt(depreciation_amount)
-
- self.append("schedules", {
- "schedule_date": schedule_date,
- "depreciation_amount": depreciation_amount
- })
- else:
- for n in range(number_of_pending_depreciations):
- schedule_date = add_months(self.next_depreciation_date,
- n * cint(self.frequency_of_depreciation))
-
- depreciation_amount = self.get_depreciation_amount(value_after_depreciation)
- if depreciation_amount:
- value_after_depreciation -= flt(depreciation_amount)
-
- self.append("schedules", {
- "schedule_date": schedule_date,
- "depreciation_amount": depreciation_amount
- })
-
- def set_accumulated_depreciation(self):
- accumulated_depreciation = flt(self.opening_accumulated_depreciation)
- value_after_depreciation = flt(self.value_after_depreciation)
for i, d in enumerate(self.get("schedules")):
+ if ignore_booked_entry and d.journal_entry:
+ continue
+
+ if d.finance_book_id not in finance_books:
+ accumulated_depreciation = flt(self.opening_accumulated_depreciation)
+ value_after_depreciation = flt(self.get_value_after_depreciation(d.finance_book_id))
+ finance_books.append(d.finance_book_id)
+
depreciation_amount = flt(d.depreciation_amount, d.precision("depreciation_amount"))
value_after_depreciation -= flt(depreciation_amount)
- if i==len(self.get("schedules"))-1 and self.depreciation_method == "Straight Line":
+ if straight_line_idx and i == max(straight_line_idx) - 1:
+ book = self.get('finance_books')[cint(d.finance_book_id) - 1]
depreciation_amount += flt(value_after_depreciation -
- flt(self.expected_value_after_useful_life), d.precision("depreciation_amount"))
+ flt(book.expected_value_after_useful_life), d.precision("depreciation_amount"))
d.depreciation_amount = depreciation_amount
accumulated_depreciation += d.depreciation_amount
d.accumulated_depreciation_amount = flt(accumulated_depreciation,
d.precision("accumulated_depreciation_amount"))
- def get_depreciation_amount(self, depreciable_value):
- if self.depreciation_method in ("Straight Line", "Manual"):
- depreciation_amount = (flt(self.value_after_depreciation) -
- flt(self.expected_value_after_useful_life)) / (cint(self.total_number_of_depreciations) -
- cint(self.number_of_depreciations_booked))
- else:
- factor = 200.0 / self.total_number_of_depreciations
- depreciation_amount = flt(depreciable_value * factor / 100, 0)
+ def get_value_after_depreciation(self, idx):
+ return flt(self.get('finance_books')[cint(idx)-1].value_after_depreciation)
- value_after_depreciation = flt(depreciable_value) - depreciation_amount
- if value_after_depreciation < flt(self.expected_value_after_useful_life):
- depreciation_amount = flt(depreciable_value) - flt(self.expected_value_after_useful_life)
+ def get_depreciation_amount(self, depreciable_value, total_number_of_depreciations, row):
+ percentage_value = 100.0 if row.depreciation_method == 'Written Down Value' else 200.0
+
+ factor = percentage_value / total_number_of_depreciations
+ depreciation_amount = flt(depreciable_value * factor / 100, 0)
+
+ value_after_depreciation = flt(depreciable_value) - depreciation_amount
+ if value_after_depreciation < flt(row.expected_value_after_useful_life):
+ depreciation_amount = flt(depreciable_value) - flt(row.expected_value_after_useful_life)
return depreciation_amount
- def get_depreciation_amount_prorata_temporis(self, depreciable_value, start_date=None, end_date=None):
+ def get_depreciation_amount_prorata_temporis(self, depreciable_value, row, start_date=None, end_date=None):
if start_date and end_date:
prorata_temporis = min(abs(flt(date_diff(str(end_date), str(start_date)))) / flt(frappe.db.get_value("Asset Settings", None, "number_of_days_in_fiscal_year")), 1)
else:
prorata_temporis = 1
- if self.depreciation_method in ("Straight Line", "Manual"):
- depreciation_amount = (flt(self.value_after_depreciation) -
- flt(self.expected_value_after_useful_life)) / (cint(self.total_number_of_depreciations) -
+ if row.depreciation_method in ("Straight Line", "Manual"):
+ depreciation_amount = (flt(row.value_after_depreciation) -
+ flt(row.expected_value_after_useful_life)) / (cint(row.total_number_of_depreciations) -
cint(self.number_of_depreciations_booked)) * prorata_temporis
-
- return depreciation_amount
else:
- self.get_depreciation_amount(depreciable_value)
+ depreciation_amount = self.get_depreciation_amount(depreciable_value, row)
+
+ return depreciation_amount
def validate_expected_value_after_useful_life(self):
- accumulated_depreciation_after_full_schedule = \
- max([d.accumulated_depreciation_amount for d in self.get("schedules")])
+ for row in self.get('finance_books'):
+ accumulated_depreciation_after_full_schedule = \
+ max([d.accumulated_depreciation_amount for d in self.get("schedules") if d.finance_book_id == row.idx])
- asset_value_after_full_schedule = flt(flt(self.gross_purchase_amount) -
- flt(accumulated_depreciation_after_full_schedule),
- self.precision('expected_value_after_useful_life'))
+ asset_value_after_full_schedule = flt(flt(self.gross_purchase_amount) -
+ flt(accumulated_depreciation_after_full_schedule),
+ self.precision('gross_purchase_amount'))
- if self.expected_value_after_useful_life < asset_value_after_full_schedule:
- frappe.throw(_("Expected value after useful life must be greater than or equal to {0}")
- .format(asset_value_after_full_schedule))
+ if row.expected_value_after_useful_life < asset_value_after_full_schedule:
+ frappe.throw(_("Depreciation Row {0}: Expected value after useful life must be greater than or equal to {1}")
+ .format(row.idx, asset_value_after_full_schedule))
def validate_cancellation(self):
if self.status not in ("Submitted", "Partially Depreciated", "Fully Depreciated"):
@@ -219,6 +263,9 @@ class Asset(Document):
if self.purchase_invoice:
frappe.throw(_("Please cancel Purchase Invoice {0} first").format(self.purchase_invoice))
+ if self.purchase_receipt:
+ frappe.throw(_("Please cancel Purchase Receipt {0} first").format(self.purchase_receipt))
+
def delete_depreciation_entries(self):
for d in self.get("schedules"):
if d.journal_entry:
@@ -240,9 +287,15 @@ class Asset(Document):
status = "Draft"
elif self.docstatus == 1:
status = "Submitted"
+ expected_value_after_useful_life = flt(sum([d.expected_value_after_useful_life
+ for d in self.get('finance_books')]))
+
+ value_after_depreciation = flt(sum([d.value_after_depreciation
+ for d in self.get('finance_books')]))
+
if self.journal_entry_for_scrap:
status = "Scrapped"
- elif flt(self.value_after_depreciation) <= flt(self.expected_value_after_useful_life):
+ elif flt(value_after_depreciation) <= expected_value_after_useful_life:
status = "Fully Depreciated"
elif flt(self.value_after_depreciation) < flt(self.gross_purchase_amount):
status = 'Partially Depreciated'
@@ -250,6 +303,45 @@ class Asset(Document):
status = "Cancelled"
return status
+ def update_stock_movement(self):
+ asset_movement = frappe.db.get_value('Asset Movement',
+ {'asset': self.name, 'reference_name': self.purchase_receipt, 'docstatus': 0}, 'name')
+
+ if asset_movement:
+ doc = frappe.get_doc('Asset Movement', asset_movement)
+ doc.submit()
+
+ def make_gl_entries(self):
+ if self.purchase_receipt and self.purchase_receipt_amount:
+ from erpnext.accounts.general_ledger import make_gl_entries
+
+ gl_entries = []
+
+ cwip_account = get_cwip_account(self.name, self.asset_category, self.company)
+ fixed_aseet_account = get_asset_category_account(self.name, 'fixed_asset_account',
+ asset_category = self.asset_category, company = self.company)
+
+ gl_entries.append(self.get_gl_dict({
+ "account": cwip_account,
+ "against": fixed_aseet_account,
+ "remarks": self.get("remarks") or _("Accounting Entry for Asset"),
+ "posting_date": self.available_for_use_date,
+ "credit": self.purchase_receipt_amount,
+ "credit_in_account_currency": self.purchase_receipt_amount
+ }))
+
+ gl_entries.append(self.get_gl_dict({
+ "account": fixed_aseet_account,
+ "against": cwip_account,
+ "remarks": self.get("remarks") or _("Accounting Entry for Asset"),
+ "posting_date": self.available_for_use_date,
+ "debit": self.purchase_receipt_amount,
+ "debit_in_account_currency": self.purchase_receipt_amount
+ }))
+
+ make_gl_entries(gl_entries)
+ self.db_set('booked_fixed_asset', 1)
+
def update_maintenance_status():
assets = frappe.get_all('Asset', filters = {'docstatus': 1, 'maintenance_required': 1})
@@ -260,6 +352,18 @@ def update_maintenance_status():
if frappe.db.exists('Asset Repair', {'asset_name': asset.name, 'repair_status': 'Pending'}):
asset.set_status('Out of Order')
+def make_post_gl_entry():
+ assets = frappe.db.sql_list(""" select name from `tabAsset`
+ where ifnull(booked_fixed_asset, 0) = 0 and available_for_use_date = %s""", nowdate())
+
+ for asset in assets:
+ doc = frappe.get_doc('Asset', asset)
+ doc.make_gl_entries()
+
+def get_asset_naming_series():
+ meta = frappe.get_meta('Asset')
+ return meta.get_field("naming_series").options
+
@frappe.whitelist()
def make_purchase_invoice(asset, item_code, gross_purchase_amount, company, posting_date):
pi = frappe.new_doc("Purchase Invoice")
@@ -271,7 +375,7 @@ def make_purchase_invoice(asset, item_code, gross_purchase_amount, company, post
"item_code": item_code,
"is_fixed_asset": 1,
"asset": asset,
- "expense_account": get_fixed_asset_account(asset),
+ "expense_account": get_asset_category_account(asset, 'fixed_asset_account'),
"qty": 1,
"price_list_rate": gross_purchase_amount,
"rate": gross_purchase_amount
@@ -280,7 +384,7 @@ def make_purchase_invoice(asset, item_code, gross_purchase_amount, company, post
return pi
@frappe.whitelist()
-def make_sales_invoice(asset, item_code, company):
+def make_sales_invoice(asset, item_code, company, serial_no=None):
si = frappe.new_doc("Sales Invoice")
si.company = company
si.currency = frappe.db.get_value("Company", company, "default_currency")
@@ -290,6 +394,7 @@ def make_sales_invoice(asset, item_code, company):
"is_fixed_asset": 1,
"asset": asset,
"income_account": disposal_account,
+ "serial_no": serial_no,
"cost_center": depreciation_cost_center,
"qty": 1
})
@@ -322,17 +427,32 @@ def transfer_asset(args):
frappe.msgprint(_("Asset Movement record {0} created").format("{0}".format(movement_entry.name)))
@frappe.whitelist()
-def get_item_details(item_code):
- asset_category = frappe.db.get_value("Item", item_code, "asset_category")
-
+def get_item_details(item_code, asset_category=None):
if not asset_category:
frappe.throw(_("Please enter Asset Category in Item {0}").format(item_code))
- ret = frappe.db.get_value("Asset Category", asset_category,
- ["depreciation_method", "total_number_of_depreciations", "frequency_of_depreciation"], as_dict=1)
+ asset_category_doc = frappe.get_doc('Asset Category', asset_category)
+ books = []
+ for d in asset_category_doc.finance_books:
+ books.append({
+ 'finance_book': d.finance_book,
+ 'depreciation_method': d.depreciation_method,
+ 'total_number_of_depreciations': d.total_number_of_depreciations,
+ 'frequency_of_depreciation': d.frequency_of_depreciation,
+ 'start_date': nowdate()
+ })
- ret.update({
- "asset_category": asset_category
- })
+ return books
- return ret
+def get_cwip_account(asset, asset_category=None, company=None):
+ cwip_account = get_asset_category_account(asset, 'capital_work_in_progress_account',
+ asset_category = asset_category, company = company)
+
+ if not cwip_account:
+ cwip_account = frappe.db.get_value('Company', company, 'capital_work_in_progress_account')
+
+ if not cwip_account:
+ frappe.throw(_("Set Capital Work In Progress Account in asset category {0} or company {1}")
+ .format(asset_category, company))
+
+ return cwip_account
diff --git a/erpnext/assets/doctype/asset/asset_dashboard.py b/erpnext/assets/doctype/asset/asset_dashboard.py
index 94dad1b311..89699f3edb 100644
--- a/erpnext/assets/doctype/asset/asset_dashboard.py
+++ b/erpnext/assets/doctype/asset/asset_dashboard.py
@@ -1,6 +1,9 @@
def get_data():
return {
'fieldname': 'asset_name',
+ 'non_standard_fieldnames': {
+ 'Asset Movement': 'asset'
+ },
'transactions': [
{
'label': ['Maintenance'],
@@ -9,6 +12,10 @@ def get_data():
{
'label': ['Repair'],
'items': ['Asset Repair']
+ },
+ {
+ 'label': ['Movement'],
+ 'items': ['Asset Movement']
}
]
}
\ No newline at end of file
diff --git a/erpnext/assets/doctype/asset/depreciation.py b/erpnext/assets/doctype/asset/depreciation.py
index 92a251e4fa..aacaef5414 100644
--- a/erpnext/assets/doctype/asset/depreciation.py
+++ b/erpnext/assets/doctype/asset/depreciation.py
@@ -5,7 +5,7 @@
from __future__ import unicode_literals
import frappe
from frappe import _
-from frappe.utils import flt, today, getdate
+from frappe.utils import flt, today, getdate, cint
def post_depreciation_entries(date=None):
# Return if automatic booking of asset depreciation is disabled
@@ -47,6 +47,7 @@ def make_depreciation_entry(asset_name, date=None):
je.naming_series = depreciation_series
je.posting_date = d.schedule_date
je.company = asset.company
+ je.finance_book = d.finance_book
je.remark = "Depreciation Entry against {0} worth {1}".format(asset_name, d.depreciation_amount)
je.append("accounts", {
@@ -68,9 +69,12 @@ def make_depreciation_entry(asset_name, date=None):
je.submit()
d.db_set("journal_entry", je.name)
- asset.value_after_depreciation -= d.depreciation_amount
+
+ idx = cint(d.finance_book_id)
+ finance_books = asset.get('finance_books')[idx - 1]
+ finance_books.value_after_depreciation -= d.depreciation_amount
+ finance_books.db_update()
- asset.db_set("value_after_depreciation", asset.value_after_depreciation)
asset.set_status()
return asset
diff --git a/erpnext/assets/doctype/asset_adjustment/__init__.py b/erpnext/assets/doctype/asset_adjustment/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/assets/doctype/asset_adjustment/asset_adjustment.js b/erpnext/assets/doctype/asset_adjustment/asset_adjustment.js
new file mode 100644
index 0000000000..11c02e105f
--- /dev/null
+++ b/erpnext/assets/doctype/asset_adjustment/asset_adjustment.js
@@ -0,0 +1,30 @@
+// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Asset Adjustment', {
+ asset: function(frm) {
+ frm.trigger("set_current_asset_value");
+ },
+
+ finance_book: function(frm) {
+ frm.trigger("set_current_asset_value");
+ },
+
+ set_current_asset_value: function(frm) {
+ debugger
+ if (frm.doc.finance_book && frm.doc.asset) {
+ frm.call({
+ method: "erpnext.assets.doctype.asset_adjustment.asset_adjustment.get_current_asset_value",
+ args: {
+ asset: frm.doc.asset,
+ finance_book: frm.doc.finance_book
+ },
+ callback: function(r) {
+ if (r.message) {
+ frm.set_value('current_asset_value', r.message);
+ }
+ }
+ });
+ }
+ }
+});
diff --git a/erpnext/assets/doctype/asset_adjustment/asset_adjustment.json b/erpnext/assets/doctype/asset_adjustment/asset_adjustment.json
new file mode 100644
index 0000000000..faa36efe07
--- /dev/null
+++ b/erpnext/assets/doctype/asset_adjustment/asset_adjustment.json
@@ -0,0 +1,437 @@
+{
+ "allow_copy": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "beta": 0,
+ "creation": "2018-05-11 00:22:43.695151",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "fields": [
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "company",
+ "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": "Company",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Company",
+ "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,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "asset",
+ "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": "Asset",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Asset",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "asset_category",
+ "fieldtype": "Read Only",
+ "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": "Asset Category",
+ "length": 0,
+ "no_copy": 0,
+ "options": "asset.asset_category",
+ "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,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "finance_book",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Finance Book",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Finance Book",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "journal_entry",
+ "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": "Journal Entry",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Journal Entry",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "column_break_4",
+ "fieldtype": "Column Break",
+ "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,
+ "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,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "date",
+ "fieldtype": "Datetime",
+ "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": "Date",
+ "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,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "current_asset_value",
+ "fieldtype": "Currency",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Current Asset Value",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "new_asset_value",
+ "fieldtype": "Currency",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "New Asset Value",
+ "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": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "difference_amount",
+ "fieldtype": "Currency",
+ "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": "Difference Amount",
+ "length": 0,
+ "no_copy": 1,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "amended_from",
+ "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": "Amended From",
+ "length": 0,
+ "no_copy": 1,
+ "options": "Asset Adjustment",
+ "permlevel": 0,
+ "print_hide": 1,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ }
+ ],
+ "has_web_view": 0,
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "idx": 0,
+ "image_view": 0,
+ "in_create": 0,
+ "is_submittable": 1,
+ "issingle": 0,
+ "istable": 0,
+ "max_attachments": 0,
+ "modified": "2018-05-11 21:45:03.459696",
+ "modified_by": "Administrator",
+ "module": "Assets",
+ "name": "Asset Adjustment",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "amend": 1,
+ "apply_user_permissions": 0,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 1,
+ "write": 1
+ },
+ {
+ "amend": 1,
+ "apply_user_permissions": 0,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Accounts User",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 1,
+ "write": 1
+ },
+ {
+ "amend": 1,
+ "apply_user_permissions": 0,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Accounts Manager",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 1,
+ "write": 1
+ }
+ ],
+ "quick_entry": 1,
+ "read_only": 0,
+ "read_only_onload": 0,
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "title_field": "asset",
+ "track_changes": 1,
+ "track_seen": 0
+}
\ No newline at end of file
diff --git a/erpnext/assets/doctype/asset_adjustment/asset_adjustment.py b/erpnext/assets/doctype/asset_adjustment/asset_adjustment.py
new file mode 100644
index 0000000000..6b4b752e7f
--- /dev/null
+++ b/erpnext/assets/doctype/asset_adjustment/asset_adjustment.py
@@ -0,0 +1,103 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe import _
+from frappe.utils import flt, getdate, cint, date_diff
+from erpnext.assets.doctype.asset.depreciation import get_depreciation_accounts
+from frappe.model.document import Document
+
+class AssetAdjustment(Document):
+ def validate(self):
+ self.set_difference_amount()
+ self.set_current_asset_value()
+
+ def on_submit(self):
+ self.make_depreciation_entry()
+ self.reschedule_depreciations()
+
+ def on_cancel(self):
+ if self.journal_entry:
+ frappe.throw(_("Cancel the journal entry {0} first").format(self.journal_entry))
+
+ def set_difference_amount(self):
+ self.difference_amount = flt(self.current_asset_value - self.new_asset_value)
+
+ def set_current_asset_value(self):
+ if not self.current_asset_value and self.asset and self.finance_book:
+ self.current_asset_value = get_current_asset_value(self.asset, self.finance_book)
+
+ def make_depreciation_entry(self):
+ asset = frappe.get_doc("Asset", self.asset)
+ fixed_asset_account, accumulated_depreciation_account, depreciation_expense_account = \
+ get_depreciation_accounts(asset)
+
+ depreciation_cost_center, depreciation_series = frappe.db.get_value("Company", asset.company,
+ ["depreciation_cost_center", "series_for_depreciation_entry"])
+
+ je = frappe.new_doc("Journal Entry")
+ je.voucher_type = "Depreciation Entry"
+ je.naming_series = depreciation_series
+ je.posting_date = self.date
+ je.company = self.company
+ je.remark = "Depreciation Entry against {0} worth {1}".format(self.asset, self.difference_amount)
+
+ je.append("accounts", {
+ "account": accumulated_depreciation_account,
+ "credit_in_account_currency": self.difference_amount,
+ })
+
+ je.append("accounts", {
+ "account": depreciation_expense_account,
+ "debit_in_account_currency": self.difference_amount,
+ "cost_center": depreciation_cost_center
+ })
+
+ je.flags.ignore_permissions = True
+ je.submit()
+
+ self.db_set("journal_entry", je.name)
+
+ def reschedule_depreciations(self):
+ asset = frappe.get_doc('Asset', self.asset)
+
+ for d in asset.finance_books:
+ d.value_after_depreciation = self.new_asset_value
+
+ if d.depreciation_method in ("Straight Line", "Manual"):
+ end_date = max([s.schedule_date for s in asset.schedules if cint(s.finance_book_id) == d.idx])
+ total_days = date_diff(end_date, self.date)
+ rate_per_day = flt(d.value_after_depreciation) / flt(total_days)
+ from_date = self.date
+ else:
+ no_of_depreciations = len([e.name for e in asset.schedules
+ if (cint(s.finance_book_id) == d.idx and not e.journal_entry)])
+
+ value_after_depreciation = d.value_after_depreciation
+ for data in asset.schedules:
+ if cint(data.finance_book_id) == d.idx and not data.journal_entry:
+ if d.depreciation_method in ("Straight Line", "Manual"):
+ days = date_diff(data.schedule_date, from_date)
+ depreciation_amount = days * rate_per_day
+ from_date = data.schedule_date
+ else:
+ depreciation_amount = asset.get_depreciation_amount(value_after_depreciation,
+ no_of_depreciations, d)
+
+ if depreciation_amount:
+ value_after_depreciation -= flt(depreciation_amount)
+ data.depreciation_amount = depreciation_amount
+
+ d.db_update()
+
+ asset.set_accumulated_depreciation(ignore_booked_entry=True)
+ for asset_data in asset.schedules:
+ if not asset_data.journal_entry:
+ asset_data.db_update()
+
+@frappe.whitelist()
+def get_current_asset_value(asset, finance_book):
+ return frappe.db.get_value('Asset Finance Book',
+ {'parent': asset, 'parenttype': 'Asset', 'finance_book': finance_book}, 'value_after_depreciation', debug=1)
diff --git a/erpnext/assets/doctype/asset_adjustment/test_asset_adjustment.js b/erpnext/assets/doctype/asset_adjustment/test_asset_adjustment.js
new file mode 100644
index 0000000000..29d070af52
--- /dev/null
+++ b/erpnext/assets/doctype/asset_adjustment/test_asset_adjustment.js
@@ -0,0 +1,23 @@
+/* eslint-disable */
+// rename this file from _test_[name] to test_[name] to activate
+// and remove above this line
+
+QUnit.test("test: Asset Adjustment", function (assert) {
+ let done = assert.async();
+
+ // number of asserts
+ assert.expect(1);
+
+ frappe.run_serially([
+ // insert a new Asset Adjustment
+ () => frappe.tests.make('Asset Adjustment', [
+ // values to be set
+ {key: 'value'}
+ ]),
+ () => {
+ assert.equal(cur_frm.doc.key, 'value');
+ },
+ () => done()
+ ]);
+
+});
diff --git a/erpnext/assets/doctype/asset_adjustment/test_asset_adjustment.py b/erpnext/assets/doctype/asset_adjustment/test_asset_adjustment.py
new file mode 100644
index 0000000000..209692e04c
--- /dev/null
+++ b/erpnext/assets/doctype/asset_adjustment/test_asset_adjustment.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import frappe
+import unittest
+
+class TestAssetAdjustment(unittest.TestCase):
+ pass
diff --git a/erpnext/assets/doctype/asset_category/asset_category.js b/erpnext/assets/doctype/asset_category/asset_category.js
index aafe8a69a0..6f0c428c4d 100644
--- a/erpnext/assets/doctype/asset_category/asset_category.js
+++ b/erpnext/assets/doctype/asset_category/asset_category.js
@@ -40,5 +40,16 @@ frappe.ui.form.on('Asset Category', {
};
});
+ frm.set_query('capital_work_in_progress_account', 'accounts', function(doc, cdt, cdn) {
+ var d = locals[cdt][cdn];
+ return {
+ "filters": {
+ "account_type": "Capital Work in Progress",
+ "is_group": 0,
+ "company": d.company_name
+ }
+ };
+ });
+
}
});
\ No newline at end of file
diff --git a/erpnext/assets/doctype/asset_category/asset_category.json b/erpnext/assets/doctype/asset_category/asset_category.json
index 3331d05e85..882cbe2eaa 100644
--- a/erpnext/assets/doctype/asset_category/asset_category.json
+++ b/erpnext/assets/doctype/asset_category/asset_category.json
@@ -43,38 +43,6 @@
"set_only_once": 0,
"unique": 0
},
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "Straight Line",
- "fieldname": "depreciation_method",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 1,
- "label": "Depreciation Method",
- "length": 0,
- "no_copy": 0,
- "options": "\nStraight Line\nDouble Declining Balance\nManual",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@@ -110,16 +78,16 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
- "fieldname": "total_number_of_depreciations",
- "fieldtype": "Int",
+ "fieldname": "finance_book_detail",
+ "fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
- "in_list_view": 1,
+ "in_list_view": 0,
"in_standard_filter": 0,
- "label": "Total Number of Depreciations",
+ "label": "Finance Book Detail",
"length": 0,
"no_copy": 0,
"permlevel": 0,
@@ -129,7 +97,7 @@
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
- "reqd": 1,
+ "reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
@@ -140,18 +108,19 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
- "fieldname": "frequency_of_depreciation",
- "fieldtype": "Int",
+ "fieldname": "finance_books",
+ "fieldtype": "Table",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
- "in_list_view": 1,
+ "in_list_view": 0,
"in_standard_filter": 0,
- "label": "Frequency of Depreciation (Months)",
+ "label": "Finance Books",
"length": 0,
"no_copy": 0,
+ "options": "Asset Finance Book",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@@ -159,7 +128,7 @@
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
- "reqd": 1,
+ "reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
@@ -236,7 +205,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2017-12-01 15:14:25.645077",
+ "modified": "2018-05-12 14:56:04.116425",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Category",
@@ -312,4 +281,4 @@
"sort_order": "DESC",
"track_changes": 0,
"track_seen": 0
-}
+}
\ No newline at end of file
diff --git a/erpnext/assets/doctype/asset_category/asset_category.py b/erpnext/assets/doctype/asset_category/asset_category.py
index 542bd12861..bbdc6ec2cf 100644
--- a/erpnext/assets/doctype/asset_category/asset_category.py
+++ b/erpnext/assets/doctype/asset_category/asset_category.py
@@ -10,6 +10,22 @@ from frappe.model.document import Document
class AssetCategory(Document):
def validate(self):
- for field in ("total_number_of_depreciations", "frequency_of_depreciation"):
- if cint(self.get(field))<1:
- frappe.throw(_("{0} must be greater than 0").format(self.meta.get_label(field)), frappe.MandatoryError)
+ for d in self.finance_books:
+ for field in ("Total Number of Depreciations", "Frequency of Depreciation"):
+ if cint(d.get(frappe.scrub(field)))<1:
+ frappe.throw(_("Row {0}: {1} must be greater than 0").format(d.idx, field), frappe.MandatoryError)
+
+@frappe.whitelist()
+def get_asset_category_account(asset, fieldname, account=None, asset_category = None, company = None):
+ if not asset_category and company:
+ if account:
+ if frappe.db.get_value("Account", account, "account_type") != "Fixed Asset":
+ account=None
+
+ if not account:
+ asset_category, company = frappe.db.get_value("Asset", asset, ["asset_category", "company"])
+
+ account = frappe.db.get_value("Asset Category Account",
+ filters={"parent": asset_category, "company_name": company}, fieldname=fieldname)
+
+ return account
\ No newline at end of file
diff --git a/erpnext/assets/doctype/asset_category_account/asset_category_account.json b/erpnext/assets/doctype/asset_category_account/asset_category_account.json
index 679cc5271d..b7df557552 100644
--- a/erpnext/assets/doctype/asset_category_account/asset_category_account.json
+++ b/erpnext/assets/doctype/asset_category_account/asset_category_account.json
@@ -17,7 +17,7 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
- "columns": 3,
+ "columns": 2,
"fieldname": "company_name",
"fieldtype": "Link",
"hidden": 0,
@@ -48,7 +48,7 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
- "columns": 3,
+ "columns": 2,
"fieldname": "fixed_asset_account",
"fieldtype": "Link",
"hidden": 0,
@@ -135,6 +135,37 @@
"search_index": 0,
"set_only_once": 0,
"unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 2,
+ "fieldname": "capital_work_in_progress_account",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Capital Work In Progress Account",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Account",
+ "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,
+ "unique": 0
}
],
"has_web_view": 0,
@@ -147,7 +178,7 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
- "modified": "2017-11-28 16:54:12.252271",
+ "modified": "2018-05-10 17:06:48.839347",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Category Account",
diff --git a/erpnext/assets/doctype/asset_finance_book/__init__.py b/erpnext/assets/doctype/asset_finance_book/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/assets/doctype/asset_finance_book/asset_finance_book.json b/erpnext/assets/doctype/asset_finance_book/asset_finance_book.json
new file mode 100644
index 0000000000..f75c8510dc
--- /dev/null
+++ b/erpnext/assets/doctype/asset_finance_book/asset_finance_book.json
@@ -0,0 +1,289 @@
+{
+ "allow_copy": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "beta": 0,
+ "creation": "2018-05-08 14:44:37.095570",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "fields": [
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "depends_on": "",
+ "fieldname": "finance_book",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Finance Book",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Finance Book",
+ "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,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "depreciation_method",
+ "fieldtype": "Select",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Depreciation Method",
+ "length": 0,
+ "no_copy": 0,
+ "options": "\nStraight Line\nDouble Declining Balance\nWritten Down Value\nManual",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "total_number_of_depreciations",
+ "fieldtype": "Int",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Total Number of Depreciations",
+ "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": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "column_break_5",
+ "fieldtype": "Column Break",
+ "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": "",
+ "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,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "frequency_of_depreciation",
+ "fieldtype": "Int",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Frequency of Depreciation (Months)",
+ "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": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "depends_on": "eval:parent.doctype == 'Asset'",
+ "fieldname": "depreciation_start_date",
+ "fieldtype": "Date",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Depreciation Start Date",
+ "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,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "default": "0",
+ "depends_on": "eval:parent.doctype == 'Asset'",
+ "fieldname": "expected_value_after_useful_life",
+ "fieldtype": "Currency",
+ "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": "Expected Value After Useful Life",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Company:company:default_currency",
+ "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,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "value_after_depreciation",
+ "fieldtype": "Currency",
+ "hidden": 1,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Value After Depreciation",
+ "length": 0,
+ "no_copy": 1,
+ "options": "Company:company:default_currency",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 1,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ }
+ ],
+ "has_web_view": 0,
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "idx": 0,
+ "image_view": 0,
+ "in_create": 0,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 1,
+ "max_attachments": 0,
+ "modified": "2018-05-12 14:56:44.800046",
+ "modified_by": "Administrator",
+ "module": "Assets",
+ "name": "Asset Finance Book",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "read_only": 0,
+ "read_only_onload": 0,
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1,
+ "track_seen": 0
+}
\ No newline at end of file
diff --git a/erpnext/assets/doctype/asset_finance_book/asset_finance_book.py b/erpnext/assets/doctype/asset_finance_book/asset_finance_book.py
new file mode 100644
index 0000000000..bdc2acfb79
--- /dev/null
+++ b/erpnext/assets/doctype/asset_finance_book/asset_finance_book.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe.model.document import Document
+
+class AssetFinanceBook(Document):
+ pass
diff --git a/erpnext/assets/doctype/asset_maintenance/asset_maintenance.json b/erpnext/assets/doctype/asset_maintenance/asset_maintenance.json
index 72d96b0db0..f36fe4e078 100644
--- a/erpnext/assets/doctype/asset_maintenance/asset_maintenance.json
+++ b/erpnext/assets/doctype/asset_maintenance/asset_maintenance.json
@@ -42,6 +42,7 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -73,6 +74,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -104,6 +106,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -135,6 +138,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -164,6 +168,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -195,6 +200,39 @@
"reqd": 1,
"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": "serial_no",
+ "fieldtype": "Small Text",
+ "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": "Serial No",
+ "length": 0,
+ "no_copy": 0,
+ "options": "asset_name.serial_no",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -224,6 +262,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -255,6 +294,7 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -284,6 +324,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -315,6 +356,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -346,6 +388,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -376,6 +419,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -407,6 +451,7 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
}
],
@@ -420,7 +465,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2017-12-01 15:13:29.816396",
+ "modified": "2018-04-20 08:39:27.072622",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Maintenance",
@@ -429,7 +474,6 @@
"permissions": [
{
"amend": 0,
- "apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
@@ -449,7 +493,6 @@
},
{
"amend": 0,
- "apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
diff --git a/erpnext/assets/doctype/asset_maintenance/asset_maintenance.py b/erpnext/assets/doctype/asset_maintenance/asset_maintenance.py
index 7551eae229..b30685f108 100644
--- a/erpnext/assets/doctype/asset_maintenance/asset_maintenance.py
+++ b/erpnext/assets/doctype/asset_maintenance/asset_maintenance.py
@@ -11,6 +11,9 @@ from frappe.utils import add_days, add_months, add_years, getdate, nowdate
class AssetMaintenance(Document):
def validate(self):
+ if not self.serial_no:
+ self.serial_no = frappe.db.get_value("Asset", self.asset_name, 'serial_no')
+
for task in self.get('asset_maintenance_tasks'):
if task.end_date and (getdate(task.start_date) >= getdate(task.end_date)):
throw(_("Start date should be less than end date for task {0}").format(task.maintenance_task))
diff --git a/erpnext/assets/doctype/asset_movement/asset_movement.json b/erpnext/assets/doctype/asset_movement/asset_movement.json
index 0c05552962..8adbf57b67 100644
--- a/erpnext/assets/doctype/asset_movement/asset_movement.json
+++ b/erpnext/assets/doctype/asset_movement/asset_movement.json
@@ -12,6 +12,69 @@
"document_type": "",
"editable_grid": 0,
"fields": [
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "Company",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Company",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 1,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "default": "Transfer",
+ "fieldname": "purpose",
+ "fieldtype": "Select",
+ "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": "Purpose",
+ "length": 0,
+ "no_copy": 0,
+ "options": "\nIssue\nReceipt\nTransfer",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@@ -73,37 +136,6 @@
"set_only_once": 0,
"unique": 0
},
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "company",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 1,
- "label": "Company",
- "length": 0,
- "no_copy": 0,
- "options": "Company",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 1,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@@ -139,7 +171,96 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
- "fieldname": "source_warehouse",
+ "fieldname": "quantity",
+ "fieldtype": "Float",
+ "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": "Quantity",
+ "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,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "serial_no",
+ "fieldtype": "Small Text",
+ "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": "Serial No",
+ "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,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "section_break_7",
+ "fieldtype": "Section Break",
+ "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,
+ "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,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "source_location",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
@@ -147,11 +268,194 @@
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
- "in_standard_filter": 1,
- "label": "Source Warehouse",
+ "in_standard_filter": 0,
+ "label": "Source Location",
"length": 0,
"no_copy": 0,
- "options": "Warehouse",
+ "options": "Location",
+ "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,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "target_location",
+ "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": "Target Location",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Location",
+ "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,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "column_break_10",
+ "fieldtype": "Column Break",
+ "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,
+ "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,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "from_employee",
+ "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": "From Employee",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Employee",
+ "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,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "to_employee",
+ "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": "To Employee",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Employee",
+ "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,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "reference",
+ "fieldtype": "Section Break",
+ "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": "Reference",
+ "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,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "reference_doctype",
+ "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": "Reference DocType",
+ "length": 0,
+ "no_copy": 1,
+ "options": "DocType",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@@ -170,27 +474,27 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
- "fieldname": "target_warehouse",
- "fieldtype": "Link",
+ "fieldname": "reference_name",
+ "fieldtype": "Dynamic Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 1,
- "label": "Target Warehouse",
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Reference Name",
"length": 0,
- "no_copy": 0,
- "options": "Warehouse",
+ "no_copy": 1,
+ "options": "reference_doctype",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
- "read_only": 0,
+ "read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
- "reqd": 1,
+ "reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
@@ -236,7 +540,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2017-10-19 16:08:17.389257",
+ "modified": "2018-05-10 23:16:20.791672",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Movement",
diff --git a/erpnext/assets/doctype/asset_movement/asset_movement.py b/erpnext/assets/doctype/asset_movement/asset_movement.py
index 574c49992b..32fc663837 100644
--- a/erpnext/assets/doctype/asset_movement/asset_movement.py
+++ b/erpnext/assets/doctype/asset_movement/asset_movement.py
@@ -5,44 +5,60 @@
from __future__ import unicode_literals
import frappe
from frappe import _
+from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
from frappe.model.document import Document
class AssetMovement(Document):
def validate(self):
self.validate_asset()
self.validate_warehouses()
-
+
def validate_asset(self):
- status, company = frappe.db.get_value("Asset", self.asset, ["status", "company"])
- if status in ("Draft", "Scrapped", "Sold"):
+ status, company, serial_no = frappe.db.get_value("Asset", self.asset, ["status", "company", "serial_no"])
+ if self.purpose == 'Transfer' and status in ("Draft", "Scrapped", "Sold"):
frappe.throw(_("{0} asset cannot be transferred").format(status))
-
+
if company != self.company:
frappe.throw(_("Asset {0} does not belong to company {1}").format(self.asset, self.company))
-
+
+ if serial_no and not self.serial_no:
+ self.serial_no = serial_no
+
+ if self.serial_no and len(get_serial_nos(self.serial_no)) != self.quantity:
+ frappe.throw(_("Number of serial nos and quantity must be the same"))
+
+ if not(self.source_location or self.target_location or self.from_employee or self.to_employee):
+ frappe.throw(_("Either location or employee must be required"))
+
def validate_warehouses(self):
- if not self.source_warehouse:
- self.source_warehouse = frappe.db.get_value("Asset", self.asset, "warehouse")
-
- if self.source_warehouse == self.target_warehouse:
- frappe.throw(_("Source and Target Warehouse cannot be same"))
+ if self.purpose in ['Transfer', 'Issue']:
+ self.source_location = frappe.db.get_value("Asset", self.asset, "location")
+
+ if self.source_location == self.target_location:
+ frappe.throw(_("Source and Target Location cannot be same"))
def on_submit(self):
- self.set_latest_warehouse_in_asset()
+ self.set_latest_location_in_asset()
def on_cancel(self):
- self.set_latest_warehouse_in_asset()
-
- def set_latest_warehouse_in_asset(self):
- latest_movement_entry = frappe.db.sql("""select target_warehouse from `tabAsset Movement`
+ self.set_latest_location_in_asset()
+
+ def set_latest_location_in_asset(self):
+ latest_movement_entry = frappe.db.sql("""select target_location from `tabAsset Movement`
where asset=%s and docstatus=1 and company=%s
order by transaction_date desc limit 1""", (self.asset, self.company))
if latest_movement_entry:
- warehouse = latest_movement_entry[0][0]
+ location = latest_movement_entry[0][0]
else:
- warehouse = frappe.db.sql("""select source_warehouse from `tabAsset Movement`
+ location = frappe.db.sql("""select source_location from `tabAsset Movement`
where asset=%s and docstatus=2 and company=%s
order by transaction_date asc limit 1""", (self.asset, self.company))[0][0]
-
- frappe.db.set_value("Asset", self.asset, "warehouse", warehouse)
\ No newline at end of file
+
+ frappe.db.set_value("Asset", self.asset, "location", location)
+
+ if self.serial_no:
+ serial_nos = get_serial_nos(self.serial_no)
+
+ frappe.db.sql(""" update `tabSerial No` set location = %s where name in (%s)"""
+ %('%s', ','.join(['%s'] * len(serial_nos))), (location, tuple(serial_nos)))
diff --git a/erpnext/assets/doctype/depreciation_schedule/depreciation_schedule.json b/erpnext/assets/doctype/depreciation_schedule/depreciation_schedule.json
index 330347240d..35a2c9dd7f 100644
--- a/erpnext/assets/doctype/depreciation_schedule/depreciation_schedule.json
+++ b/erpnext/assets/doctype/depreciation_schedule/depreciation_schedule.json
@@ -13,6 +13,37 @@
"editable_grid": 1,
"engine": "InnoDB",
"fields": [
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "finance_book",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Finance Book",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Finance Book",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@@ -196,6 +227,67 @@
"search_index": 0,
"set_only_once": 0,
"unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "finance_book_id",
+ "fieldtype": "Data",
+ "hidden": 1,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Finance Book Id",
+ "length": 0,
+ "no_copy": 1,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 1,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "depreciation_method",
+ "fieldtype": "Select",
+ "hidden": 1,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Depreciation Method",
+ "length": 0,
+ "no_copy": 1,
+ "options": "\nStraight Line\nDouble Declining Balance\nWritten Down Value\nManual",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 1,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
}
],
"has_web_view": 0,
@@ -208,7 +300,7 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
- "modified": "2017-10-19 16:30:13.738170",
+ "modified": "2018-05-10 15:12:41.679436",
"modified_by": "Administrator",
"module": "Assets",
"name": "Depreciation Schedule",
diff --git a/erpnext/assets/doctype/location/__init__.py b/erpnext/assets/doctype/location/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/assets/doctype/location/location.js b/erpnext/assets/doctype/location/location.js
new file mode 100644
index 0000000000..c3783dfae7
--- /dev/null
+++ b/erpnext/assets/doctype/location/location.js
@@ -0,0 +1,8 @@
+// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Location', {
+ refresh: function(frm) {
+
+ }
+});
diff --git a/erpnext/assets/doctype/location/location.json b/erpnext/assets/doctype/location/location.json
new file mode 100644
index 0000000000..d83fdf3667
--- /dev/null
+++ b/erpnext/assets/doctype/location/location.json
@@ -0,0 +1,306 @@
+{
+ "allow_copy": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "autoname": "field:location_name",
+ "beta": 0,
+ "creation": "2018-05-07 12:49:22.595974",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "fields": [
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "location_name",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Location Name",
+ "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": 1,
+ "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": "is_group",
+ "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": "Is Group",
+ "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": "parent_location",
+ "fieldtype": "Link",
+ "hidden": 1,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Parent Location",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Location",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 1,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "lft",
+ "fieldtype": "Int",
+ "hidden": 1,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "lft",
+ "length": 0,
+ "no_copy": 1,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 1,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "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": "rgt",
+ "fieldtype": "Int",
+ "hidden": 1,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "rgt",
+ "length": 0,
+ "no_copy": 1,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 1,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "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": "old_parent",
+ "fieldtype": "Data",
+ "hidden": 1,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Old Parent",
+ "length": 0,
+ "no_copy": 1,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 1,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ }
+ ],
+ "has_web_view": 0,
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "idx": 0,
+ "image_view": 0,
+ "in_create": 0,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 0,
+ "max_attachments": 0,
+ "modified": "2018-05-07 19:21:06.051414",
+ "modified_by": "Administrator",
+ "module": "Assets",
+ "name": "Location",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "amend": 0,
+ "cancel": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 1
+ },
+ {
+ "amend": 0,
+ "cancel": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Stock User",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 1
+ },
+ {
+ "amend": 0,
+ "cancel": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Accounts User",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 1
+ },
+ {
+ "amend": 0,
+ "cancel": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Stock Manager",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 1
+ }
+ ],
+ "quick_entry": 1,
+ "read_only": 0,
+ "read_only_onload": 0,
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1,
+ "track_seen": 0
+}
\ No newline at end of file
diff --git a/erpnext/assets/doctype/location/location.py b/erpnext/assets/doctype/location/location.py
new file mode 100644
index 0000000000..9d05720a0d
--- /dev/null
+++ b/erpnext/assets/doctype/location/location.py
@@ -0,0 +1,47 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe.model.document import Document
+from frappe.utils.nestedset import NestedSet
+
+class Location(NestedSet):
+ def on_update(self):
+ self.update_nsm_model()
+
+ def on_trash(self):
+ self.update_nsm_model()
+
+ def update_nsm_model(self):
+ frappe.utils.nestedset.update_nsm(self)
+
+@frappe.whitelist()
+def get_children(doctype, parent=None, location=None, is_root=False):
+ if parent == None or parent == "All Locations":
+ parent = ""
+
+ return frappe.db.sql("""
+ select
+ name as value,
+ is_group as expandable
+ from
+ `tab{doctype}` comp
+ where
+ ifnull(parent_location, "")="{parent}"
+ """.format(
+ doctype = frappe.db.escape(doctype),
+ parent=frappe.db.escape(parent)
+ ), as_dict=1)
+
+@frappe.whitelist()
+def add_node():
+ from frappe.desk.treeview import make_tree_args
+ args = frappe.form_dict
+ args = make_tree_args(**args)
+
+ if args.parent_location == 'All Locations':
+ args.parent_location = None
+
+ frappe.get_doc(args).insert()
\ No newline at end of file
diff --git a/erpnext/assets/doctype/location/location_tree.js b/erpnext/assets/doctype/location/location_tree.js
new file mode 100644
index 0000000000..523dd63ced
--- /dev/null
+++ b/erpnext/assets/doctype/location/location_tree.js
@@ -0,0 +1,28 @@
+frappe.treeview_settings["Location"] = {
+ ignore_fields:["parent_location"],
+ get_tree_nodes: 'erpnext.assets.doctype.location.location.get_children',
+ add_tree_node: 'erpnext.assets.doctype.location.location.add_node',
+ filters: [
+ {
+ fieldname: "location",
+ fieldtype:"Link",
+ options: "Location",
+ label: __("Location")
+ },
+ ],
+ breadcrumb: "Assets",
+ root_label: "All Locations",
+ get_tree_root: false,
+ menu_items: [
+ {
+ label: __("New Location"),
+ action: function() {
+ frappe.new_doc("Location", true);
+ },
+ condition: 'frappe.boot.user.can_create.indexOf("Location") !== -1'
+ }
+ ],
+ onload: function(treeview) {
+ treeview.make_tree();
+ }
+};
\ No newline at end of file
diff --git a/erpnext/assets/doctype/location/test_location.js b/erpnext/assets/doctype/location/test_location.js
new file mode 100644
index 0000000000..236b5c65b0
--- /dev/null
+++ b/erpnext/assets/doctype/location/test_location.js
@@ -0,0 +1,23 @@
+/* eslint-disable */
+// rename this file from _test_[name] to test_[name] to activate
+// and remove above this line
+
+QUnit.test("test: Location", function (assert) {
+ let done = assert.async();
+
+ // number of asserts
+ assert.expect(1);
+
+ frappe.run_serially([
+ // insert a new Location
+ () => frappe.tests.make('Location', [
+ // values to be set
+ {key: 'value'}
+ ]),
+ () => {
+ assert.equal(cur_frm.doc.key, 'value');
+ },
+ () => done()
+ ]);
+
+});
diff --git a/erpnext/assets/doctype/location/test_location.py b/erpnext/assets/doctype/location/test_location.py
new file mode 100644
index 0000000000..9a46fd93ef
--- /dev/null
+++ b/erpnext/assets/doctype/location/test_location.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import frappe
+import unittest
+
+class TestLocation(unittest.TestCase):
+ pass
diff --git a/erpnext/buying/doctype/buying_settings/buying_settings.json b/erpnext/buying/doctype/buying_settings/buying_settings.json
index bb2b47def7..c0684f939a 100644
--- a/erpnext/buying/doctype/buying_settings/buying_settings.json
+++ b/erpnext/buying/doctype/buying_settings/buying_settings.json
@@ -1,188 +1,263 @@
{
"allow_copy": 0,
+ "allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
+ "beta": 0,
"creation": "2013-06-25 11:04:03",
"custom": 0,
"description": "Settings for Buying Module",
"docstatus": 0,
"doctype": "DocType",
"document_type": "Other",
+ "editable_grid": 0,
"fields": [
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
+ "columns": 0,
"default": "Supplier Name",
"fieldname": "supp_master_name",
"fieldtype": "Select",
"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": "Supplier Naming By",
+ "length": 0,
"no_copy": 0,
"options": "Supplier Name\nNaming Series",
"permlevel": 0,
"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,
- "fieldname": "supplier_type",
+ "columns": 0,
+ "fieldname": "supplier_group",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
"in_filter": 0,
+ "in_global_search": 0,
"in_list_view": 0,
- "label": "Default Supplier Type",
+ "in_standard_filter": 0,
+ "label": "Default Supplier Group",
+ "length": 0,
"no_copy": 0,
- "options": "Supplier Type",
+ "options": "Supplier Group",
"permlevel": 0,
"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": "buying_price_list",
"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": "Default Buying Price List",
+ "length": 0,
"no_copy": 0,
"options": "Price List",
"permlevel": 0,
"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": "column_break_3",
"fieldtype": "Column Break",
"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,
+ "length": 0,
"no_copy": 0,
"permlevel": 0,
"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": "po_required",
"fieldtype": "Select",
"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": "Purchase Order Required",
+ "length": 0,
"no_copy": 0,
"options": "No\nYes",
"permlevel": 0,
"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": "pr_required",
"fieldtype": "Select",
"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": "Purchase Receipt Required",
+ "length": 0,
"no_copy": 0,
"options": "No\nYes",
"permlevel": 0,
"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": "maintain_same_rate",
"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": "Maintain same rate throughout purchase cycle",
+ "length": 0,
"no_copy": 0,
"permlevel": 0,
"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": "allow_multiple_items",
"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 Item to be added multiple times in a transaction",
+ "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,
@@ -213,19 +288,22 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
}
],
+ "has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"icon": "fa fa-cog",
"idx": 1,
+ "image_view": 0,
"in_create": 0,
- "in_dialog": 0,
"is_submittable": 0,
"issingle": 1,
"istable": 0,
- "modified": "2017-12-27 15:20:06.052342",
+ "max_attachments": 0,
+ "modified": "2018-04-19 07:56:42.888821",
"modified_by": "Administrator",
"module": "Buying",
"name": "Buying Settings",
@@ -233,7 +311,6 @@
"permissions": [
{
"amend": 0,
- "apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 0,
@@ -252,6 +329,10 @@
"write": 1
}
],
+ "quick_entry": 0,
"read_only": 0,
- "read_only_onload": 0
+ "read_only_onload": 0,
+ "show_name_in_global_search": 0,
+ "track_changes": 0,
+ "track_seen": 0
}
\ No newline at end of file
diff --git a/erpnext/buying/doctype/buying_settings/buying_settings.py b/erpnext/buying/doctype/buying_settings/buying_settings.py
index 1f0184b82c..a634a0908b 100644
--- a/erpnext/buying/doctype/buying_settings/buying_settings.py
+++ b/erpnext/buying/doctype/buying_settings/buying_settings.py
@@ -10,7 +10,7 @@ from frappe.model.document import Document
class BuyingSettings(Document):
def validate(self):
- for key in ["supplier_type", "supp_master_name", "maintain_same_rate", "buying_price_list"]:
+ for key in ["supplier_group", "supp_master_name", "maintain_same_rate", "buying_price_list"]:
frappe.db.set_default(key, self.get(key, ""))
from erpnext.setup.doctype.naming_series.naming_series import set_by_naming_series
diff --git a/erpnext/buying/doctype/party_tax_withholding_config/__init__.py b/erpnext/buying/doctype/party_tax_withholding_config/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/buying/doctype/party_tax_withholding_config/party_tax_withholding_config.json b/erpnext/buying/doctype/party_tax_withholding_config/party_tax_withholding_config.json
new file mode 100644
index 0000000000..320485b318
--- /dev/null
+++ b/erpnext/buying/doctype/party_tax_withholding_config/party_tax_withholding_config.json
@@ -0,0 +1,166 @@
+{
+ "allow_copy": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "beta": 0,
+ "creation": "2018-05-11 13:32:33.825307",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "fields": [
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "tax_withholding_category",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Tax Withholding Category",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Tax Withholding Category",
+ "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": "valid_till",
+ "fieldtype": "Date",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Valid Till",
+ "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": "applicable_percent",
+ "fieldtype": "Float",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Applicable Percent",
+ "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": "certificate_received",
+ "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": "Certificate Received",
+ "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
+ }
+ ],
+ "has_web_view": 0,
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "idx": 0,
+ "image_view": 0,
+ "in_create": 0,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 1,
+ "max_attachments": 0,
+ "modified": "2018-05-11 13:35:44.424855",
+ "modified_by": "Administrator",
+ "module": "Buying",
+ "name": "Party Tax Withholding Config",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "read_only": 0,
+ "read_only_onload": 0,
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1,
+ "track_seen": 0
+}
\ No newline at end of file
diff --git a/erpnext/buying/doctype/party_tax_withholding_config/party_tax_withholding_config.py b/erpnext/buying/doctype/party_tax_withholding_config/party_tax_withholding_config.py
new file mode 100644
index 0000000000..bec7e83f23
--- /dev/null
+++ b/erpnext/buying/doctype/party_tax_withholding_config/party_tax_withholding_config.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe.model.document import Document
+
+class PartyTaxWithholdingConfig(Document):
+ pass
diff --git a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.js b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.js
index de87e04443..2ff80755df 100644
--- a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.js
+++ b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.js
@@ -61,11 +61,11 @@ frappe.ui.form.on("Request for Quotation",{
fields: [
{ "fieldtype": "Select", "label": __("Get Suppliers By"),
"fieldname": "search_type",
- "options": "Tag\nSupplier Type", "reqd": 1 },
- { "fieldtype": "Link", "label": __("Supplier Type"),
- "fieldname": "supplier_type",
- "options": "Supplier Type", "reqd": 0,
- "depends_on": "eval:doc.search_type == 'Supplier Type'"},
+ "options": "Tag\nSupplier Group", "reqd": 1 },
+ { "fieldtype": "Link", "label": __("Supplier Group"),
+ "fieldname": "supplier_group",
+ "options": "Supplier Group", "reqd": 0,
+ "depends_on": "eval:doc.search_type == 'Supplier Group'"},
{ "fieldtype": "Data", "label": __("Tag"),
"fieldname": "tag", "reqd": 0,
"depends_on": "eval:doc.search_type == 'Tag'" },
@@ -121,14 +121,14 @@ frappe.ui.form.on("Request for Quotation",{
},
callback: load_suppliers
});
- } else if (args.supplier_type) {
+ } else if (args.supplier_group) {
return frappe.call({
method: "frappe.client.get_list",
args: {
doctype: "Supplier",
order_by: "name",
fields: ["name"],
- filters: [["Supplier", "supplier_type", "=", args.supplier_type]]
+ filters: [["Supplier", "supplier_group_name", "=", args.supplier_group]]
},
callback: load_suppliers
diff --git a/erpnext/buying/doctype/request_for_quotation/test_request_for_quotation.py b/erpnext/buying/doctype/request_for_quotation/test_request_for_quotation.py
index 7eb741f06a..dbd9f02278 100644
--- a/erpnext/buying/doctype/request_for_quotation/test_request_for_quotation.py
+++ b/erpnext/buying/doctype/request_for_quotation/test_request_for_quotation.py
@@ -56,7 +56,7 @@ class TestRequestforQuotation(unittest.TestCase):
frappe.delete_doc_if_exists("Supplier", "_Test Supplier '1", force=1)
supplier = frappe.new_doc("Supplier")
supplier.supplier_name = "_Test Supplier '1"
- supplier.supplier_type = "_Test Supplier Type"
+ supplier.supplier_group = "_Test Supplier Group"
supplier.insert()
rfq = make_request_for_quotation(supplier_wt_appos)
diff --git a/erpnext/buying/doctype/supplier/supplier.json b/erpnext/buying/doctype/supplier/supplier.json
index afb8899dcb..eedbac1dff 100644
--- a/erpnext/buying/doctype/supplier/supplier.json
+++ b/erpnext/buying/doctype/supplier/supplier.json
@@ -43,7 +43,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -76,7 +76,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 1,
- "translatable": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -108,7 +108,7 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -140,7 +140,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -171,7 +171,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -233,7 +233,7 @@
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
- "reqd": 1,
+ "reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
@@ -267,7 +267,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -296,7 +296,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
+ "translatable": 0,
"unique": 0,
"width": "50%"
},
@@ -306,7 +306,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
- "fieldname": "supplier_type",
+ "fieldname": "supplier_group",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
@@ -315,12 +315,12 @@
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 1,
- "label": "Supplier Type",
+ "label": "Supplier Group",
"length": 0,
"no_copy": 0,
"oldfieldname": "supplier_type",
"oldfieldtype": "Link",
- "options": "Supplier Type",
+ "options": "Supplier Group",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
@@ -330,7 +330,7 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -362,7 +362,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -394,7 +394,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -425,7 +425,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -456,7 +456,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -487,7 +487,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -518,7 +518,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -614,7 +614,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -645,7 +645,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -675,7 +675,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -706,7 +706,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -737,7 +737,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -770,7 +770,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -803,7 +803,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -833,7 +833,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -862,7 +862,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
+ "translatable": 0,
"unique": 0,
"width": "50%"
},
@@ -893,7 +893,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -924,7 +924,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -957,6 +957,69 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 1,
+ "columns": 0,
+ "fieldname": "default_tax_withholding_config",
+ "fieldtype": "Section Break",
+ "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": "Default Tax Withholding Config",
+ "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": "tax_withholding_config",
+ "fieldtype": "Table",
+ "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": "Tax Withholding Account",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Party Tax Withholding Config",
+ "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
},
@@ -988,7 +1051,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
+ "translatable": 0,
"unique": 0,
"width": "50%"
},
@@ -1021,7 +1084,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -1117,38 +1180,6 @@
"set_only_once": 0,
"translatable": 0,
"unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "tax_withholding_category",
- "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": "Tax Withholding Category",
- "length": 0,
- "no_copy": 0,
- "options": "Tax Withholding Category",
- "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
}
],
"has_web_view": 0,
@@ -1163,7 +1194,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2018-04-19 12:19:52.519026",
+ "modified": "2018-05-11 15:15:19.912308",
"modified_by": "Administrator",
"module": "Buying",
"name": "Supplier",
@@ -1307,7 +1338,7 @@
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
- "search_fields": "supplier_name, supplier_type",
+ "search_fields": "supplier_name, supplier_group",
"show_name_in_global_search": 1,
"sort_order": "ASC",
"title_field": "supplier_name",
diff --git a/erpnext/buying/doctype/supplier/supplier_list.js b/erpnext/buying/doctype/supplier/supplier_list.js
index ab25d2c8fc..d99e3f8f0f 100644
--- a/erpnext/buying/doctype/supplier/supplier_list.js
+++ b/erpnext/buying/doctype/supplier/supplier_list.js
@@ -1,3 +1,3 @@
frappe.listview_settings['Supplier'] = {
- add_fields: ["supplier_name", "supplier_type", "image"],
+ add_fields: ["supplier_name", "supplier_group", "image"],
};
diff --git a/erpnext/buying/doctype/supplier/test_records.json b/erpnext/buying/doctype/supplier/test_records.json
index 2536721326..9c019898cb 100644
--- a/erpnext/buying/doctype/supplier/test_records.json
+++ b/erpnext/buying/doctype/supplier/test_records.json
@@ -2,39 +2,39 @@
{
"doctype": "Supplier",
"supplier_name": "_Test Supplier With Template 1",
- "supplier_type": "_Test Supplier Type",
+ "supplier_group": "_Test Supplier Group",
"payment_terms": "_Test Payment Term Template 3"
},
{
"doctype": "Supplier",
"supplier_name": "_Test Supplier P",
- "supplier_type": "_Test Supplier Type"
+ "supplier_group": "_Test Supplier Group"
},
{
"doctype": "Supplier",
"supplier_name": "_Test Supplier with Country",
- "supplier_type": "_Test Supplier Type",
+ "supplier_group": "_Test Supplier Group",
"country": "Greece"
},
{
"doctype": "Supplier",
"supplier_name": "_Test Supplier",
- "supplier_type": "_Test Supplier Type"
+ "supplier_group": "_Test Supplier Group"
},
{
"doctype": "Supplier",
"supplier_name": "_Test Supplier 1",
- "supplier_type": "_Test Supplier Type"
+ "supplier_group": "_Test Supplier Group"
},
{
"doctype": "Supplier",
"supplier_name": "_Test Supplier 2",
- "supplier_type": "_Test Supplier Type"
+ "supplier_group": "_Test Supplier Group"
},
{
"doctype": "Supplier",
"supplier_name": "_Test Supplier USD",
- "supplier_type": "_Test Supplier Type",
+ "supplier_group": "_Test Supplier Group",
"accounts": [{
"company": "_Test Company",
"account": "_Test Payable USD - _TC"
diff --git a/erpnext/buying/doctype/supplier/test_supplier.js b/erpnext/buying/doctype/supplier/test_supplier.js
index 51e3c09788..bf7c192c91 100644
--- a/erpnext/buying/doctype/supplier/test_supplier.js
+++ b/erpnext/buying/doctype/supplier/test_supplier.js
@@ -7,7 +7,7 @@ QUnit.test("test: supplier", function(assert) {
() => {
return frappe.tests.make('Supplier', [
{supplier_name: 'Test Supplier'},
- {supplier_type: 'Hardware'},
+ {supplier_group: 'Hardware'},
{country: 'India'},
{default_currency: 'INR'},
{accounts: [
@@ -66,7 +66,7 @@ QUnit.test("test: supplier", function(assert) {
() => {
assert.ok(cur_frm.doc.supplier_name == 'Test Supplier', "Name correct");
- assert.ok(cur_frm.doc.supplier_type == 'Hardware', "Type correct");
+ assert.ok(cur_frm.doc.supplier_group == 'Hardware', "Type correct");
assert.ok(cur_frm.doc.default_currency == 'INR', "Currency correct");
assert.ok(cur_frm.doc.accounts[0].account == 'Creditors - '+frappe.get_abbr('For Testing'), " Account Head abbr correct");
assert.ok($('.address-box:nth-child(3) p').text().includes('Shipping City 3'), "Address correct");
diff --git a/erpnext/buying/doctype/supplier/test_supplier.py b/erpnext/buying/doctype/supplier/test_supplier.py
index 16dda5c5ff..2211db7e0d 100644
--- a/erpnext/buying/doctype/supplier/test_supplier.py
+++ b/erpnext/buying/doctype/supplier/test_supplier.py
@@ -36,14 +36,14 @@ class TestSupplier(unittest.TestCase):
frappe.db.set_value("Supplier", "_Test Supplier With Template 1", "payment_terms", "")
- # Set credit limit for the supplier type instead of supplier and evaluate the due date
- frappe.db.set_value("Supplier Type", "_Test Supplier Type", "payment_terms", "_Test Payment Term Template 3")
+ # Set credit limit for the supplier group instead of supplier and evaluate the due date
+ frappe.db.set_value("Supplier Group", "_Test Supplier Group", "payment_terms", "_Test Payment Term Template 3")
due_date = get_due_date("2016-01-22", "Supplier", "_Test Supplier With Template 1")
self.assertEqual(due_date, "2016-02-21")
- # Payment terms for Supplier Type instead of supplier and evaluate the due date
- frappe.db.set_value("Supplier Type", "_Test Supplier Type", "payment_terms", "_Test Payment Term Template 1")
+ # Payment terms for Supplier Group instead of supplier and evaluate the due date
+ frappe.db.set_value("Supplier Group", "_Test Supplier Group", "payment_terms", "_Test Payment Term Template 1")
# Leap year
due_date = get_due_date("2016-01-22", "Supplier", "_Test Supplier With Template 1")
@@ -53,7 +53,7 @@ class TestSupplier(unittest.TestCase):
self.assertEqual(due_date, "2017-02-28")
# Supplier with no default Payment Terms Template
- frappe.db.set_value("Supplier Type", "_Test Supplier Type", "payment_terms", "")
+ frappe.db.set_value("Supplier Group", "_Test Supplier Group", "payment_terms", "")
frappe.db.set_value("Supplier", "_Test Supplier", "payment_terms", "")
due_date = get_due_date("2016-01-22", "Supplier", "_Test Supplier")
diff --git a/erpnext/buying/page/purchase_analytics/purchase_analytics.js b/erpnext/buying/page/purchase_analytics/purchase_analytics.js
index 442a8bbd3e..06764a3c60 100644
--- a/erpnext/buying/page/purchase_analytics/purchase_analytics.js
+++ b/erpnext/buying/page/purchase_analytics/purchase_analytics.js
@@ -19,7 +19,7 @@ erpnext.PurchaseAnalytics = frappe.views.TreeGridReport.extend({
title: __("Purchase Analytics"),
parent: $(wrapper).find('.layout-main'),
page: wrapper.page,
- doctypes: ["Item", "Item Group", "Supplier", "Supplier Type", "Company", "Fiscal Year",
+ doctypes: ["Item", "Item Group", "Supplier", "Supplier Group", "Company", "Fiscal Year",
"Purchase Invoice", "Purchase Invoice Item",
"Purchase Order", "Purchase Order Item[Purchase Analytics]",
"Purchase Receipt", "Purchase Receipt Item[Purchase Analytics]"],
@@ -27,11 +27,11 @@ erpnext.PurchaseAnalytics = frappe.views.TreeGridReport.extend({
});
this.tree_grids = {
- "Supplier Type": {
- label: __("Supplier Type / Supplier"),
+ "Supplier Group": {
+ label: __("Supplier Group / Supplier"),
show: true,
item_key: "supplier",
- parent_field: "parent_supplier_type",
+ parent_field: "parent_supplier_group",
formatter: function(item) {
return item.supplier_name ? item.supplier_name + " (" + item.name + ")" : item.name;
}
@@ -77,7 +77,7 @@ erpnext.PurchaseAnalytics = frappe.views.TreeGridReport.extend({
},
filters: [
{fieldtype:"Select", label: __("Tree Type"), fieldname: "tree_type",
- options:["Supplier Type", "Supplier", "Item Group", "Item"],
+ options:["Supplier Group", "Supplier", "Item Group", "Item"],
filter: function(val, item, opts, me) {
return me.apply_zero_filter(val, item, opts, me);
}},
@@ -110,22 +110,10 @@ erpnext.PurchaseAnalytics = frappe.views.TreeGridReport.extend({
var me = this;
if (!this.tl) {
// add 'Not Set' Supplier & Item
- // Add 'All Supplier Types' Supplier Type
// (Supplier / Item are not mandatory!!)
- // Set parent supplier type for tree view
-
- $.each(frappe.report_dump.data["Supplier Type"], function(i, v) {
- v['parent_supplier_type'] = __("All Supplier Types")
- })
-
- frappe.report_dump.data["Supplier Type"] = [{
- name: __("All Supplier Types"),
- id: "All Supplier Types",
- }].concat(frappe.report_dump.data["Supplier Type"]);
-
frappe.report_dump.data["Supplier"].push({
name: __("Not Set"),
- parent_supplier_type: __("All Supplier Types"),
+ parent_supplier_group: __("All Supplier Groups"),
id: "Not Set",
});
@@ -142,14 +130,15 @@ erpnext.PurchaseAnalytics = frappe.views.TreeGridReport.extend({
if(!this.data || me.item_type != me.tree_type) {
+ var items;
if(me.tree_type=='Supplier') {
- var items = frappe.report_dump.data["Supplier"];
- } if(me.tree_type=='Supplier Type') {
- var items = this.prepare_tree("Supplier", "Supplier Type");
+ items = frappe.report_dump.data["Supplier"];
+ } else if(me.tree_type=='Supplier Group') {
+ items = this.prepare_tree("Supplier", "Supplier Group");
} else if(me.tree_type=="Item Group") {
- var items = this.prepare_tree("Item", "Item Group");
+ items = this.prepare_tree("Item", "Item Group");
} else if(me.tree_type=="Item") {
- var items = frappe.report_dump.data["Item"];
+ items = frappe.report_dump.data["Item"];
}
me.item_type = me.tree_type
diff --git a/erpnext/config/assets.py b/erpnext/config/assets.py
index 73c1aee87a..d52f1420cd 100644
--- a/erpnext/config/assets.py
+++ b/erpnext/config/assets.py
@@ -10,6 +10,10 @@ def get_data():
"type": "doctype",
"name": "Asset",
},
+ {
+ "type": "doctype",
+ "name": "Location",
+ },
{
"type": "doctype",
"name": "Asset Category",
@@ -39,6 +43,10 @@ def get_data():
"type": "doctype",
"name": "Asset Maintenance Log",
},
+ {
+ "type": "doctype",
+ "name": "Asset Adjustment",
+ },
{
"type": "doctype",
"name": "Asset Repair",
diff --git a/erpnext/config/buying.py b/erpnext/config/buying.py
index ba29125ca0..e20d514a23 100644
--- a/erpnext/config/buying.py
+++ b/erpnext/config/buying.py
@@ -39,8 +39,8 @@ def get_data():
},
{
"type": "doctype",
- "name": "Supplier Type",
- "description": _("Supplier Type master.")
+ "name": "Supplier Group",
+ "description": _("Supplier Group master.")
},
{
"type": "doctype",
diff --git a/erpnext/config/hr.py b/erpnext/config/hr.py
index 4e9e91ef3b..5da0fbc20c 100644
--- a/erpnext/config/hr.py
+++ b/erpnext/config/hr.py
@@ -23,10 +23,6 @@ def get_data():
"type": "doctype",
"name": "Attendance Request",
},
- {
- "type": "doctype",
- "name": "Attendance Request",
- },
{
"type": "doctype",
"name": "Upload Attendance",
@@ -123,6 +119,10 @@ def get_data():
"type": "doctype",
"name": "Salary Component",
},
+ {
+ "type": "doctype",
+ "name": "Additional Salary Component",
+ },
{
"type": "doctype",
"name": "Salary Structure",
@@ -131,6 +131,10 @@ def get_data():
"type": "doctype",
"name": "Employee Tax Exemption Category",
},
+ {
+ "type": "doctype",
+ "name": "Employee Tax Exemption Sub Category"
+ }
]
},
{
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index c70cfcd811..186aad3a5a 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -273,15 +273,16 @@ class AccountsController(TransactionBase):
def get_gl_dict(self, args, account_currency=None):
"""this method populates the common properties of a gl entry record"""
- fiscal_years = get_fiscal_years(self.posting_date, company=self.company)
+ posting_date = args.get('posting_date') or self.get('posting_date')
+ fiscal_years = get_fiscal_years(posting_date, company=self.company)
if len(fiscal_years) > 1:
- frappe.throw(_("Multiple fiscal years exist for the date {0}. Please set company in Fiscal Year").format(formatdate(self.posting_date)))
+ frappe.throw(_("Multiple fiscal years exist for the date {0}. Please set company in Fiscal Year").format(formatdate(posting_date)))
else:
fiscal_year = fiscal_years[0][0]
gl_dict = frappe._dict({
'company': self.company,
- 'posting_date': self.posting_date,
+ 'posting_date': posting_date,
'fiscal_year': fiscal_year,
'voucher_type': self.doctype,
'voucher_no': self.name,
@@ -600,40 +601,36 @@ class AccountsController(TransactionBase):
if d.qty > 1:
frappe.throw(_("Row #{0}: Qty must be 1, as item is a fixed asset. Please use separate row for multiple qty.").format(d.idx))
- if d.meta.get_field("asset"):
- if not d.asset:
- frappe.throw(_("Row #{0}: Asset is mandatory for fixed asset purchase/sale")
- .format(d.idx))
- else:
- asset = frappe.get_doc("Asset", d.asset)
+ if d.meta.get_field("asset") and d.asset:
+ asset = frappe.get_doc("Asset", d.asset)
- if asset.company != self.company:
- frappe.throw(_("Row #{0}: Asset {1} does not belong to company {2}")
- .format(d.idx, d.asset, self.company))
+ if asset.company != self.company:
+ frappe.throw(_("Row #{0}: Asset {1} does not belong to company {2}")
+ .format(d.idx, d.asset, self.company))
- elif asset.item_code != d.item_code:
- frappe.throw(_("Row #{0}: Asset {1} does not linked to Item {2}")
- .format(d.idx, d.asset, d.item_code))
+ elif asset.item_code != d.item_code:
+ frappe.throw(_("Row #{0}: Asset {1} does not linked to Item {2}")
+ .format(d.idx, d.asset, d.item_code))
- elif asset.docstatus != 1:
- frappe.throw(_("Row #{0}: Asset {1} must be submitted").format(d.idx, d.asset))
+ elif asset.docstatus != 1:
+ frappe.throw(_("Row #{0}: Asset {1} must be submitted").format(d.idx, d.asset))
- elif self.doctype == "Purchase Invoice":
- if asset.status != "Submitted":
- frappe.throw(_("Row #{0}: Asset {1} is already {2}")
- .format(d.idx, d.asset, asset.status))
- elif getdate(asset.purchase_date) != getdate(self.posting_date):
- frappe.throw(_("Row #{0}: Posting Date must be same as purchase date {1} of asset {2}").format(d.idx, asset.purchase_date, d.asset))
- elif asset.is_existing_asset:
- frappe.throw(_("Row #{0}: Purchase Invoice cannot be made against an existing asset {1}").format(d.idx, d.asset))
+ elif self.doctype == "Purchase Invoice":
+ if asset.status != "Submitted":
+ frappe.throw(_("Row #{0}: Asset {1} is already {2}")
+ .format(d.idx, d.asset, asset.status))
+ elif getdate(asset.purchase_date) != getdate(self.posting_date):
+ frappe.throw(_("Row #{0}: Posting Date must be same as purchase date {1} of asset {2}").format(d.idx, asset.purchase_date, d.asset))
+ elif asset.is_existing_asset:
+ frappe.throw(_("Row #{0}: Purchase Invoice cannot be made against an existing asset {1}").format(d.idx, d.asset))
- elif self.docstatus=="Sales Invoice" and self.docstatus == 1:
- if self.update_stock:
- frappe.throw(_("'Update Stock' cannot be checked for fixed asset sale"))
+ elif self.docstatus=="Sales Invoice" and self.docstatus == 1:
+ if self.update_stock:
+ frappe.throw(_("'Update Stock' cannot be checked for fixed asset sale"))
- elif asset.status in ("Scrapped", "Cancelled", "Sold"):
- frappe.throw(_("Row #{0}: Asset {1} cannot be submitted, it is already {2}")
- .format(d.idx, d.asset, asset.status))
+ elif asset.status in ("Scrapped", "Cancelled", "Sold"):
+ frappe.throw(_("Row #{0}: Asset {1} cannot be submitted, it is already {2}")
+ .format(d.idx, d.asset, asset.status))
def delink_advance_entries(self, linked_doc_name):
total_allocated_amount = 0
diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py
index de6ed79351..85fb3f0a66 100644
--- a/erpnext/controllers/buying_controller.py
+++ b/erpnext/controllers/buying_controller.py
@@ -11,6 +11,7 @@ from erpnext.stock.get_item_details import get_conversion_factor
from erpnext.buying.utils import validate_for_items, update_last_purchase_rate
from erpnext.stock.stock_ledger import get_valuation_rate
from erpnext.stock.doctype.stock_entry.stock_entry import get_used_alternative_items
+from erpnext.stock.doctype.serial_no.serial_no import get_auto_serial_nos, auto_make_serial_nos, get_serial_nos
from erpnext.controllers.stock_controller import StockController
@@ -78,7 +79,7 @@ class BuyingController(StockController):
break
def validate_stock_or_nonstock_items(self):
- if self.meta.get_field("taxes") and not self.get_stock_items():
+ if self.meta.get_field("taxes") and not self.get_stock_items() and not self.get_asset_items():
tax_for_valuation = [d for d in self.get("taxes")
if d.category in ["Valuation", "Valuation and Total"]]
@@ -87,6 +88,12 @@ class BuyingController(StockController):
d.category = 'Total'
msgprint(_('Tax Category has been changed to "Total" because all the Items are non-stock items'))
+ def get_asset_items(self):
+ if self.doctype not in ['Purchase Invoice', 'Purchase Receipt']:
+ return []
+
+ return [d.item_code for d in self.items if d.is_fixed_asset]
+
def set_landed_cost_voucher_amount(self):
for d in self.get("items"):
lc_voucher_data = frappe.db.sql("""select sum(applicable_charges), cost_center
@@ -111,7 +118,7 @@ class BuyingController(StockController):
TODO: rename item_tax_amount to valuation_tax_amount
"""
- stock_items = self.get_stock_items()
+ stock_items = self.get_stock_items() + self.get_asset_items()
stock_items_qty, stock_items_amount = 0, 0
last_stock_item_idx = 1
@@ -439,6 +446,12 @@ class BuyingController(StockController):
if self.get('is_return'):
return
+ if self.doctype in ['Purchase Receipt', 'Purchase Invoice']:
+ field = 'purchase_invoice' if self.doctype == 'Purchase Invoice' else 'purchase_receipt'
+
+ self.process_fixed_asset()
+ self.update_fixed_asset(field)
+
update_last_purchase_rate(self, is_submit = 1)
def on_cancel(self):
@@ -446,6 +459,133 @@ class BuyingController(StockController):
return
update_last_purchase_rate(self, is_submit = 0)
+ if self.doctype in ['Purchase Receipt', 'Purchase Invoice']:
+ field = 'purchase_invoice' if self.doctype == 'Purchase Invoice' else 'purchase_receipt'
+
+ self.delete_linked_asset()
+ self.update_fixed_asset(field, delete_asset=True)
+
+ def process_fixed_asset(self):
+ if self.doctype == 'Purchase Invoice' and not self.update_stock:
+ return
+
+ asset_items = self.get_asset_items()
+ if asset_items:
+ self.make_serial_nos_for_asset(asset_items)
+
+ def make_serial_nos_for_asset(self, asset_items):
+ items_data = get_asset_item_details(asset_items)
+
+ for d in self.items:
+ if d.is_fixed_asset:
+ item_data = items_data.get(d.item_code)
+ if not d.asset:
+ asset = self.make_asset(d)
+ d.db_set('asset', asset)
+
+ if item_data.get('has_serial_no'):
+ # If item has serial no
+ if item_data.get('serial_no_series') and not d.serial_no:
+ serial_nos = get_auto_serial_nos(item_data.get('serial_no_series'), d.qty)
+ elif d.serial_no:
+ serial_nos = d.serial_no
+ elif not d.serial_no:
+ frappe.throw(_("Serial no is mandatory for the item {0}").format(d.item_code))
+
+ auto_make_serial_nos({
+ 'serial_no': serial_nos,
+ 'item_code': d.item_code,
+ 'via_stock_ledger': False,
+ 'company': self.company,
+ 'actual_qty': d.qty,
+ 'purchase_document_type': self.doctype,
+ 'purchase_document_no': self.name,
+ 'asset': d.asset
+ })
+ d.db_set('serial_no', serial_nos)
+
+ if d.asset:
+ self.make_asset_movement(d)
+
+ def make_asset(self, row):
+ if not row.asset_location:
+ frappe.throw(_("Row {0}: Enter location for the asset item {1}").format(row.idx, row.item_code))
+
+ item_data = frappe.db.get_value('Item',
+ row.item_code, ['asset_naming_series', 'asset_category'], as_dict=1)
+
+ purchase_amount = flt(row.base_net_amount + row.item_tax_amount)
+ asset = frappe.get_doc({
+ 'doctype': 'Asset',
+ 'item_code': row.item_code,
+ 'asset_name': row.item_name,
+ 'status': 'Receipt',
+ 'naming_series': item_data.get('asset_naming_series') or 'AST',
+ 'asset_category': item_data.get('asset_category'),
+ 'location': row.asset_location,
+ 'company': self.company,
+ 'purchase_date': self.posting_date,
+ 'calculate_depreciation': 1,
+ 'purchase_receipt_amount': purchase_amount,
+ 'gross_purchase_amount': purchase_amount,
+ 'purchase_receipt': self.name if self.doctype == 'Purchase Receipt' else None,
+ 'purchase_invoice': self.name if self.doctype == 'Purchase Invoice' else None
+ })
+
+ asset.flags.ignore_validate = True
+ asset.flags.ignore_mandatory = True
+ asset.set_missing_values()
+ asset.insert()
+
+ frappe.msgprint(_("Asset {0} created").format(asset.name))
+ return asset.name
+
+ def make_asset_movement(self, row):
+ asset_movement = frappe.get_doc({
+ 'doctype': 'Asset Movement',
+ 'asset': row.asset,
+ 'target_location': row.asset_location,
+ 'purpose': 'Receipt',
+ 'serial_no': row.serial_no,
+ 'quantity': len(get_serial_nos(row.serial_no)),
+ 'company': self.company,
+ 'transaction_date': self.posting_date,
+ 'reference_doctype': self.doctype,
+ 'reference_name': self.name
+ }).insert()
+
+ return asset_movement.name
+
+ def update_fixed_asset(self, field, delete_asset = False):
+ for d in self.get("items"):
+ if d.is_fixed_asset and d.asset:
+ asset = frappe.get_doc("Asset", d.asset)
+
+ if delete_asset and asset.docstatus == 0:
+ frappe.delete_doc("Asset", asset.name)
+ d.db_set('asset', None)
+ continue
+
+ if self.docstatus in [0, 1] and not asset.get(field):
+ asset.set(field, self.name)
+ asset.purchase_date = self.posting_date
+ asset.supplier = self.supplier
+ elif self.docstatus == 2:
+ asset.set(field, None)
+ asset.supplier = None
+
+ asset.flags.ignore_validate_update_after_submit = True
+ if asset.docstatus == 0:
+ asset.flags.ignore_validate = True
+
+ asset.save()
+
+ def delete_linked_asset(self):
+ if self.doctype == 'Purchase Invoice' and not self.get('update_stock'):
+ return
+
+ frappe.db.sql("delete from `tabAsset Movement` where reference_name=%s and docstatus = 0", self.name)
+ frappe.db.sql("delete from `tabSerial No` where purchase_document_no=%s", self.name)
def validate_schedule_date(self):
if not self.schedule_date:
@@ -480,3 +620,11 @@ def get_items_from_bom(item_code, bom, exploded_item=1):
msgprint(_("Specified BOM {0} does not exist for Item {1}").format(bom, item_code), raise_exception=1)
return bom_items
+
+def get_asset_item_details(asset_items):
+ asset_items_data = {}
+ for d in frappe.get_all('Item', fields = ["name", "has_serial_no", "serial_no_series"],
+ filters = {'name': ('in', asset_items)}):
+ asset_items_data.setdefault(d.name, d)
+
+ return asset_items_data
diff --git a/erpnext/controllers/queries.py b/erpnext/controllers/queries.py
index fd13c1353e..3bf720fd5d 100644
--- a/erpnext/controllers/queries.py
+++ b/erpnext/controllers/queries.py
@@ -102,9 +102,9 @@ def customer_query(doctype, txt, searchfield, start, page_len, filters):
def supplier_query(doctype, txt, searchfield, start, page_len, filters):
supp_master_name = frappe.defaults.get_user_default("supp_master_name")
if supp_master_name == "Supplier Name":
- fields = ["name", "supplier_type"]
+ fields = ["name", "supplier_group"]
else:
- fields = ["name", "supplier_name", "supplier_type"]
+ fields = ["name", "supplier_name", "supplier_group"]
fields = ", ".join(fields)
return frappe.db.sql("""select {field} from `tabSupplier`
diff --git a/erpnext/controllers/trends.py b/erpnext/controllers/trends.py
index ef698c2a16..28a8fddfac 100644
--- a/erpnext/controllers/trends.py
+++ b/erpnext/controllers/trends.py
@@ -235,16 +235,16 @@ def based_wise_columns_query(based_on, trans):
based_on_details["addl_tables"] = ''
elif based_on == 'Supplier':
- based_on_details["based_on_cols"] = ["Supplier:Link/Supplier:120", "Supplier Type:Link/Supplier Type:140"]
- based_on_details["based_on_select"] = "t1.supplier, t3.supplier_type,"
+ based_on_details["based_on_cols"] = ["Supplier:Link/Supplier:120", "Supplier Group:Link/Supplier Group:140"]
+ based_on_details["based_on_select"] = "t1.supplier, t3.supplier_group,"
based_on_details["based_on_group_by"] = 't1.supplier'
based_on_details["addl_tables"] = ',`tabSupplier` t3'
based_on_details["addl_tables_relational_cond"] = " and t1.supplier = t3.name"
- elif based_on == 'Supplier Type':
- based_on_details["based_on_cols"] = ["Supplier Type:Link/Supplier Type:140"]
- based_on_details["based_on_select"] = "t3.supplier_type,"
- based_on_details["based_on_group_by"] = 't3.supplier_type'
+ elif based_on == 'Supplier Group':
+ based_on_details["based_on_cols"] = ["Supplier Group:Link/Supplier Group:140"]
+ based_on_details["based_on_select"] = "t3.supplier_group,"
+ based_on_details["based_on_group_by"] = 't3.supplier_group'
based_on_details["addl_tables"] = ',`tabSupplier` t3'
based_on_details["addl_tables_relational_cond"] = " and t1.supplier = t3.name"
diff --git a/erpnext/demo/setup/setup_data.py b/erpnext/demo/setup/setup_data.py
index 4ed4df9176..42d079db34 100644
--- a/erpnext/demo/setup/setup_data.py
+++ b/erpnext/demo/setup/setup_data.py
@@ -275,7 +275,7 @@ def setup_supplier():
frappe.get_doc({
"doctype": "Supplier",
"supplier_name": s,
- "supplier_type": random.choice(["Services", "Raw Material"]),
+ "supplier_group": random.choice(["Services", "Raw Material"]),
}).insert()
def setup_warehouse():
diff --git a/erpnext/docs/assets/img/human-resources/shift-assignment-calendar.png b/erpnext/docs/assets/img/human-resources/shift-assignment-calendar.png
new file mode 100644
index 0000000000..7c8ec779c0
Binary files /dev/null and b/erpnext/docs/assets/img/human-resources/shift-assignment-calendar.png differ
diff --git a/erpnext/docs/assets/img/human-resources/shift-assignment.png b/erpnext/docs/assets/img/human-resources/shift-assignment.png
new file mode 100644
index 0000000000..39c2857efc
Binary files /dev/null and b/erpnext/docs/assets/img/human-resources/shift-assignment.png differ
diff --git a/erpnext/docs/assets/img/human-resources/shift-request.png b/erpnext/docs/assets/img/human-resources/shift-request.png
new file mode 100644
index 0000000000..77a7ad59a7
Binary files /dev/null and b/erpnext/docs/assets/img/human-resources/shift-request.png differ
diff --git a/erpnext/docs/assets/img/human-resources/shift-type.png b/erpnext/docs/assets/img/human-resources/shift-type.png
new file mode 100644
index 0000000000..e03e45c64b
Binary files /dev/null and b/erpnext/docs/assets/img/human-resources/shift-type.png differ
diff --git a/erpnext/docs/user/manual/en/human-resources/shift-management.md b/erpnext/docs/user/manual/en/human-resources/shift-management.md
new file mode 100644
index 0000000000..2279538cc2
--- /dev/null
+++ b/erpnext/docs/user/manual/en/human-resources/shift-management.md
@@ -0,0 +1,44 @@
+# Shift Management
+
+Shift Management section of Human Resources helps your Organization manage shifts of your employees.
+
+To use Shift Management in ERPNext,
+
+ 1. Set Up a Shift Type.
+ 2. Enter Shift Request.
+ 3. View and Manage Shift Assignments.
+
+### Shift Type
+
+The Shift Type Set Up allows you to define the different types of Shifts in your Organization.
+
+To create a new Shift Type go to:
+
+Human Resources > Shift Management > Shift Type
+
+* Enter Shift Type, Start Time and End Time for quick entry.
+
+
+
+### Shift Request
+
+Shift Request is used by an employee to request for a particular Shift Type.
+
+To create a new Shift Request Log go to:
+
+Human Resources > Shift Management > Shift Request
+
+* Enter Shift Type, Employee, Company, From Date and To Date.
+
+
+
+### Shift Assignment
+
+* Once the Shift Request is submitted it automatically creates the Shift Assignments for an Employee.
+
+
+
+* You can also view Calendar view of Shift Assignments.
+
+
\ No newline at end of file
diff --git a/erpnext/education/doctype/instructor/instructor.js b/erpnext/education/doctype/instructor/instructor.js
index 62d73b32ee..f9c7a2a13d 100644
--- a/erpnext/education/doctype/instructor/instructor.js
+++ b/erpnext/education/doctype/instructor/instructor.js
@@ -1,31 +1,53 @@
cur_frm.add_fetch("employee", "department", "department");
cur_frm.add_fetch("employee", "image", "image");
-frappe.ui.form.on("Instructor", "refresh", function(frm) {
- if(!frm.doc.__islocal) {
- frm.add_custom_button(__("Student Group"), function() {
- frappe.route_options = {
- instructor: frm.doc.name
- }
- frappe.set_route("List", "Student Group");
+frappe.ui.form.on("Instructor", {
+ employee: function(frm) {
+ if(!frm.doc.employee) return;
+ frappe.db.get_value('Employee', {name: frm.doc.employee}, 'company', (company) => {
+ frm.set_query("department", function() {
+ return {
+ "filters": {
+ "company": company,
+ }
+ };
+ });
+
+ frm.set_query("department", "instructor_log", function() {
+ return {
+ "filters": {
+ "company": company,
+ }
+ };
+ });
});
- frm.add_custom_button(__("Course Schedule"), function() {
- frappe.route_options = {
- instructor: frm.doc.name
- }
- frappe.set_route("List", "Course Schedule");
- });
- frm.add_custom_button(__("As Examiner"), function() {
- frappe.route_options = {
- examiner: frm.doc.name
- }
- frappe.set_route("List", "Assessment Plan");
- }, __("Assessment Plan"));
- frm.add_custom_button(__("As Supervisor"), function() {
- frappe.route_options = {
- supervisor: frm.doc.name
- }
- frappe.set_route("List", "Assessment Plan");
- }, __("Assessment Plan"));
+ },
+ refresh: function(frm) {
+ if(!frm.doc.__islocal) {
+ frm.add_custom_button(__("Student Group"), function() {
+ frappe.route_options = {
+ instructor: frm.doc.name
+ }
+ frappe.set_route("List", "Student Group");
+ });
+ frm.add_custom_button(__("Course Schedule"), function() {
+ frappe.route_options = {
+ instructor: frm.doc.name
+ }
+ frappe.set_route("List", "Course Schedule");
+ });
+ frm.add_custom_button(__("As Examiner"), function() {
+ frappe.route_options = {
+ examiner: frm.doc.name
+ }
+ frappe.set_route("List", "Assessment Plan");
+ }, __("Assessment Plan"));
+ frm.add_custom_button(__("As Supervisor"), function() {
+ frappe.route_options = {
+ supervisor: frm.doc.name
+ }
+ frappe.set_route("List", "Assessment Plan");
+ }, __("Assessment Plan"));
+ }
}
});
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index 57e83e63be..627455b021 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -234,7 +234,8 @@ scheduler_events = {
"erpnext.buying.doctype.supplier_scorecard.supplier_scorecard.refresh_scorecards",
"erpnext.setup.doctype.company.company.cache_companies_monthly_sales_history",
"erpnext.manufacturing.doctype.bom_update_tool.bom_update_tool.update_latest_price_in_all_boms",
- "erpnext.assets.doctype.asset.asset.update_maintenance_status"
+ "erpnext.assets.doctype.asset.asset.update_maintenance_status",
+ "erpnext.assets.doctype.asset.asset.make_post_gl_entry"
]
}
diff --git a/erpnext/hr/doctype/additional_salary_component/__init__.py b/erpnext/hr/doctype/additional_salary_component/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/hr/doctype/additional_salary_component/additional_salary_component.js b/erpnext/hr/doctype/additional_salary_component/additional_salary_component.js
new file mode 100644
index 0000000000..13ed239b36
--- /dev/null
+++ b/erpnext/hr/doctype/additional_salary_component/additional_salary_component.js
@@ -0,0 +1,21 @@
+// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Additional Salary Component', {
+ setup: function(frm) {
+ frm.set_query("salary_component", function() {
+ return {
+ filters: {
+ type: "earning"
+ }
+ };
+ });
+ frm.set_query("employee", function() {
+ return {
+ filters: {
+ company: frm.doc.company
+ }
+ };
+ });
+ }
+});
diff --git a/erpnext/hr/doctype/additional_salary_component/additional_salary_component.json b/erpnext/hr/doctype/additional_salary_component/additional_salary_component.json
new file mode 100644
index 0000000000..47b090469e
--- /dev/null
+++ b/erpnext/hr/doctype/additional_salary_component/additional_salary_component.json
@@ -0,0 +1,364 @@
+{
+ "allow_copy": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "autoname": "field:salary_component",
+ "beta": 0,
+ "creation": "2018-05-10 12:04:08.396461",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "fields": [
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Company",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Company",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "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": "employee",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Employee",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Employee",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "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": "employee_name",
+ "fieldtype": "Data",
+ "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": "Employee Name",
+ "length": 0,
+ "no_copy": 0,
+ "options": "employee.employee_name",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "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": "salary_component",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Salary Component",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Salary Component",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "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": "column_break_5",
+ "fieldtype": "Column Break",
+ "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,
+ "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": "from_date",
+ "fieldtype": "Date",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "From Date",
+ "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": 1,
+ "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": "to_date",
+ "fieldtype": "Date",
+ "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": "To Date",
+ "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": 1,
+ "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": "amount",
+ "fieldtype": "Currency",
+ "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": "Amount",
+ "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": 1,
+ "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": "amended_from",
+ "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": "Amended From",
+ "length": 0,
+ "no_copy": 1,
+ "options": "Additional Salary Component",
+ "permlevel": 0,
+ "print_hide": 1,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ }
+ ],
+ "has_web_view": 0,
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "idx": 0,
+ "image_view": 0,
+ "in_create": 0,
+ "is_submittable": 1,
+ "issingle": 0,
+ "istable": 0,
+ "max_attachments": 0,
+ "modified": "2018-05-10 12:54:06.155708",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Additional Salary Component",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "amend": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 1,
+ "write": 1
+ },
+ {
+ "amend": 0,
+ "cancel": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "HR User",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 1,
+ "write": 1
+ }
+ ],
+ "quick_entry": 0,
+ "read_only": 0,
+ "read_only_onload": 0,
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "title_field": "employee",
+ "track_changes": 1,
+ "track_seen": 0
+}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/additional_salary_component/additional_salary_component.py b/erpnext/hr/doctype/additional_salary_component/additional_salary_component.py
new file mode 100644
index 0000000000..216dea0403
--- /dev/null
+++ b/erpnext/hr/doctype/additional_salary_component/additional_salary_component.py
@@ -0,0 +1,76 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe.model.document import Document
+from frappe import _
+from frappe.utils import getdate, date_diff
+
+class AdditionalSalaryComponent(Document):
+ def validate(self):
+ self.validate_dates()
+ if self.amount <= 0:
+ frappe.throw(_("Amount should be greater than zero."))
+
+ def validate_dates(self):
+ date_of_joining, relieving_date = frappe.db.get_value("Employee", self.employee,
+ ["date_of_joining", "relieving_date"])
+ if getdate(self.from_date) > getdate(self.to_date):
+ frappe.throw(_("To date can not be less than from date"))
+ elif date_of_joining and getdate(self.from_date) < getdate(date_of_joining):
+ frappe.throw(_("From date can not be less than employee's joining date"))
+ elif relieving_date and getdate(self.to_date) > getdate(relieving_date):
+ frappe.throw(_("To date can not greater than employee's relieving date"))
+
+ def get_amount(self, sal_start_date, sal_end_date):
+ start_date = getdate(sal_start_date)
+ end_date = getdate(sal_end_date)
+ total_days = date_diff(getdate(self.to_date), getdate(self.from_date)) + 1
+ amount_per_day = self.amount / total_days
+ if getdate(sal_start_date) <= getdate(self.from_date):
+ start_date = getdate(self.from_date)
+ if getdate(sal_end_date) > getdate(self.to_date):
+ end_date = getdate(self.end_date)
+ no_of_days = date_diff(getdate(end_date), getdate(start_date))
+ return amount_per_day * no_of_days
+
+
+
+
+@frappe.whitelist()
+def get_additional_salary_component(employee, start_date, end_date):
+ additional_components = frappe.db.sql("""
+ select name from `tabAdditional Salary Component`
+ where employee=%(employee)s
+ and docstatus = 1
+ and (
+ (%(from_date)s between from_date and to_date)
+ or (%(to_date)s between from_date and to_date)
+ or (from_date between %(from_date)s and %(to_date)s)
+ )""", {
+ 'employee': employee,
+ 'from_date': start_date,
+ 'to_date': end_date
+ })
+
+ if additional_components:
+ additional_components_array = []
+ for additional_component in additional_components:
+ struct_row = {}
+ additional_components_dict = {}
+ additional_component_obj = frappe.get_doc("Additional Salary Component", additional_component[0])
+ amount = additional_component_obj.get_amount(start_date, end_date)
+ salary_component = frappe.get_doc("Salary Component", additional_component_obj.salary_component)
+ struct_row['depends_on_lwp'] = salary_component.depends_on_lwp
+ struct_row['salary_component'] = salary_component.name
+ struct_row['abbr'] = salary_component.salary_component_abbr
+ struct_row['do_not_include_in_total'] = salary_component.do_not_include_in_total
+ additional_components_dict['amount'] = amount
+ additional_components_dict['struct_row'] = struct_row
+ additional_components_array.append(additional_components_dict)
+
+ if len(additional_components_array) > 0:
+ return additional_components_array
+ return False
diff --git a/erpnext/hr/doctype/additional_salary_component/test_additional_salary_component.js b/erpnext/hr/doctype/additional_salary_component/test_additional_salary_component.js
new file mode 100644
index 0000000000..118290bcfa
--- /dev/null
+++ b/erpnext/hr/doctype/additional_salary_component/test_additional_salary_component.js
@@ -0,0 +1,23 @@
+/* eslint-disable */
+// rename this file from _test_[name] to test_[name] to activate
+// and remove above this line
+
+QUnit.test("test: Additional Salary Component", function (assert) {
+ let done = assert.async();
+
+ // number of asserts
+ assert.expect(1);
+
+ frappe.run_serially([
+ // insert a new Additional Salary Component
+ () => frappe.tests.make('Additional Salary Component', [
+ // values to be set
+ {key: 'value'}
+ ]),
+ () => {
+ assert.equal(cur_frm.doc.key, 'value');
+ },
+ () => done()
+ ]);
+
+});
diff --git a/erpnext/hr/doctype/additional_salary_component/test_additional_salary_component.py b/erpnext/hr/doctype/additional_salary_component/test_additional_salary_component.py
new file mode 100644
index 0000000000..eda2f79dc9
--- /dev/null
+++ b/erpnext/hr/doctype/additional_salary_component/test_additional_salary_component.py
@@ -0,0 +1,8 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+import unittest
+
+class TestAdditionalSalaryComponent(unittest.TestCase):
+ pass
diff --git a/erpnext/hr/doctype/department/department.json b/erpnext/hr/doctype/department/department.json
index a1c8dc16ff..664679d3f1 100644
--- a/erpnext/hr/doctype/department/department.json
+++ b/erpnext/hr/doctype/department/department.json
@@ -3,7 +3,7 @@
"allow_guest_to_view": 0,
"allow_import": 1,
"allow_rename": 1,
- "autoname": "field:department_name",
+ "autoname": "",
"beta": 0,
"creation": "2013-02-05 11:48:26",
"custom": 0,
@@ -434,7 +434,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2018-04-18 12:02:42.572599",
+ "modified": "2018-05-11 12:18:18.839182",
"modified_by": "Administrator",
"module": "HR",
"name": "Department",
diff --git a/erpnext/hr/doctype/department/department.py b/erpnext/hr/doctype/department/department.py
index fda1b69de2..19994ae5ef 100644
--- a/erpnext/hr/doctype/department/department.py
+++ b/erpnext/hr/doctype/department/department.py
@@ -10,6 +10,10 @@ from frappe.model.document import Document
class Department(NestedSet):
nsm_parent_field = 'parent_department'
+ def autoname(self):
+ abbr = frappe.db.get_value('Company', self.company, 'abbr')
+ self.name = '{0} - {1}'.format(self.department_name, abbr)
+
def update_nsm_model(self):
frappe.utils.nestedset.update_nsm(self)
@@ -21,4 +25,23 @@ class Department(NestedSet):
delete_events(self.doctype, self.name)
def on_doctype_update():
- frappe.db.add_index("Department", ["lft", "rgt"])
\ No newline at end of file
+ frappe.db.add_index("Department", ["lft", "rgt"])
+
+@frappe.whitelist()
+def get_children(doctype, parent=None, company=None, is_root=False):
+ condition = ''
+ if company == parent:
+ condition = 'name="All Departments"'
+ elif company:
+ condition = "parent_department='{0}' and company='{1}'".format(parent, company)
+ else:
+ condition = "parent_department = '{0}'".format(parent)
+
+ return frappe.db.sql("""
+ select
+ name as value,
+ is_group as expandable
+ from `tab{doctype}`
+ where
+ {condition}
+ order by name""".format(doctype=doctype, condition=condition), as_dict=1)
diff --git a/erpnext/hr/doctype/department/department_tree.js b/erpnext/hr/doctype/department/department_tree.js
index 5652ad61a0..1f891fd1e5 100644
--- a/erpnext/hr/doctype/department/department_tree.js
+++ b/erpnext/hr/doctype/department/department_tree.js
@@ -1,3 +1,27 @@
frappe.treeview_settings["Department"] = {
- ignore_fields:["parent_department"]
+ ignore_fields:["parent_department"],
+ get_tree_nodes: 'erpnext.hr.doctype.department.department.get_children',
+ filters: [
+ {
+ fieldname: "company",
+ fieldtype:"Link",
+ options: "Company",
+ label: __("Company"),
+ },
+ ],
+ breadcrumb: "HR",
+ root_label: "All Departments",
+ get_tree_root: true,
+ menu_items: [
+ {
+ label: __("New Department"),
+ action: function() {
+ frappe.new_doc("Department", true);
+ },
+ condition: 'frappe.boot.user.can_create.indexOf("Department") !== -1'
+ }
+ ],
+ onload: function(treeview) {
+ treeview.make_tree();
+ }
};
\ No newline at end of file
diff --git a/erpnext/hr/doctype/employee/employee.js b/erpnext/hr/doctype/employee/employee.js
index 240411dcfa..6f6873ac1d 100755
--- a/erpnext/hr/doctype/employee/employee.js
+++ b/erpnext/hr/doctype/employee/employee.js
@@ -37,6 +37,15 @@ erpnext.hr.EmployeeController = frappe.ui.form.Controller.extend({
});
frappe.ui.form.on('Employee',{
+ onload:function(frm) {
+ frm.set_query("department", function() {
+ return {
+ "filters": {
+ "company": frm.doc.company,
+ }
+ };
+ });
+ },
prefered_contact_email:function(frm){
frm.events.update_contact(frm)
},
diff --git a/erpnext/hr/doctype/employee/employee.json b/erpnext/hr/doctype/employee/employee.json
index ef2c75dc83..cc3fb7ff20 100644
--- a/erpnext/hr/doctype/employee/employee.json
+++ b/erpnext/hr/doctype/employee/employee.json
@@ -393,6 +393,38 @@
"translatable": 0,
"unique": 0
},
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "job_applicant",
+ "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": "Job Applicant",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Job Applicant",
+ "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,
@@ -1262,38 +1294,6 @@
"translatable": 0,
"unique": 0
},
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "leave_policy",
- "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": "Leave Policy",
- "length": 0,
- "no_copy": 0,
- "options": "Leave Policy",
- "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,
@@ -2766,7 +2766,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2018-04-25 09:08:06.852604",
+ "modified": "2018-05-11 12:48:46.435484",
"modified_by": "Administrator",
"module": "HR",
"name": "Employee",
diff --git a/erpnext/hr/doctype/employee/employee.py b/erpnext/hr/doctype/employee/employee.py
index 4cf28a16ec..824ddf5aa7 100755
--- a/erpnext/hr/doctype/employee/employee.py
+++ b/erpnext/hr/doctype/employee/employee.py
@@ -42,6 +42,8 @@ class Employee(NestedSet):
self.validate_status()
self.validate_reports_to()
self.validate_preferred_email()
+ if self.job_applicant:
+ self.validate_onboarding_process()
if self.user_id:
self.validate_for_enabled_user_id()
@@ -164,6 +166,14 @@ class Employee(NestedSet):
if self.prefered_contact_email and not self.get(scrub(self.prefered_contact_email)):
frappe.msgprint(_("Please enter " + self.prefered_contact_email))
+ def validate_onboarding_process(self):
+ employee_onboarding = frappe.get_all("Employee Onboarding",
+ filters={"job_applicant": self.job_applicant, "docstatus": 1, "status": ("!=", "Completed")})
+ if employee_onboarding:
+ doc = frappe.get_doc("Employee Onboarding", employee_onboarding[0].name)
+ doc.validate_employee_creation()
+ doc.db_set("employee", self.name)
+
def get_timeline_data(doctype, name):
'''Return timeline for attendance'''
return dict(frappe.db.sql('''select unix_timestamp(attendance_date), count(*)
diff --git a/erpnext/hr/doctype/employee_boarding_activity/__init__.py b/erpnext/hr/doctype/employee_boarding_activity/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/hr/doctype/employee_boarding_activity/employee_boarding_activity.json b/erpnext/hr/doctype/employee_boarding_activity/employee_boarding_activity.json
new file mode 100644
index 0000000000..95d693994e
--- /dev/null
+++ b/erpnext/hr/doctype/employee_boarding_activity/employee_boarding_activity.json
@@ -0,0 +1,291 @@
+{
+ "allow_copy": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "beta": 0,
+ "creation": "2018-05-09 05:37:18.439763",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "fields": [
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "activity_name",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Activity Name",
+ "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": "user",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "User",
+ "length": 0,
+ "no_copy": 0,
+ "options": "User",
+ "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": "role",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Role",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Role",
+ "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": "column_break_3",
+ "fieldtype": "Column Break",
+ "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,
+ "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": "task",
+ "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": "Task",
+ "length": 0,
+ "no_copy": 1,
+ "options": "Task",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "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,
+ "description": "Applicable in the case of Employee Onboarding",
+ "fieldname": "required_for_employee_creation",
+ "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": "Required for Employee Creation",
+ "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": "section_break_6",
+ "fieldtype": "Section Break",
+ "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,
+ "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": "description",
+ "fieldtype": "Text Editor",
+ "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": "Description",
+ "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
+ }
+ ],
+ "has_web_view": 0,
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "idx": 0,
+ "image_view": 0,
+ "in_create": 0,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 1,
+ "max_attachments": 0,
+ "modified": "2018-05-10 06:54:47.282492",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Employee Boarding Activity",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "read_only": 0,
+ "read_only_onload": 0,
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1,
+ "track_seen": 0
+}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/employee_boarding_activity/employee_boarding_activity.py b/erpnext/hr/doctype/employee_boarding_activity/employee_boarding_activity.py
new file mode 100644
index 0000000000..496f1653ba
--- /dev/null
+++ b/erpnext/hr/doctype/employee_boarding_activity/employee_boarding_activity.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe.model.document import Document
+
+class EmployeeBoardingActivity(Document):
+ pass
diff --git a/erpnext/hr/doctype/employee_onboarding/__init__.py b/erpnext/hr/doctype/employee_onboarding/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/hr/doctype/employee_onboarding/employee_onboarding.js b/erpnext/hr/doctype/employee_onboarding/employee_onboarding.js
new file mode 100644
index 0000000000..e95e260fa9
--- /dev/null
+++ b/erpnext/hr/doctype/employee_onboarding/employee_onboarding.js
@@ -0,0 +1,59 @@
+// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Employee Onboarding', {
+ setup: function(frm) {
+ frm.add_fetch("employee_onboarding_template", "company", "company");
+ frm.add_fetch("employee_onboarding_template", "department", "department");
+ frm.add_fetch("employee_onboarding_template", "designation", "designation");
+ frm.add_fetch("employee_onboarding_template", "employee_grade", "employee_grade");
+ },
+
+ refresh: function(frm) {
+ if (frm.doc.employee) {
+ frm.add_custom_button(__('Employee'), function() {
+ frappe.set_route("Form", "Employee", frm.doc.employee);
+ },__("View"));
+ }
+ if (frm.doc.project) {
+ frm.add_custom_button(__('Project'), function() {
+ frappe.set_route("Form", "Project", frm.doc.project);
+ },__("View"));
+ frm.add_custom_button(__('Task'), function() {
+ frappe.set_route('List', 'Task', {project: frm.doc.project});
+ },__("View"));
+ }
+ if ((!frm.doc.employee) && (frm.doc.docstatus === 1)) {
+ frm.add_custom_button(__('Employee'), function () {
+ frappe.model.open_mapped_doc({
+ method: "erpnext.hr.doctype.employee_onboarding.employee_onboarding.make_employee",
+ frm: frm
+ });
+ }, __("Make"));
+ frm.page.set_inner_btn_group_as_primary(__("Make"));
+ }
+
+ },
+
+ employee_onboarding_template: function(frm) {
+ frm.set_value("activities" ,"");
+ if (frm.doc.employee_onboarding_template) {
+ frappe.call({
+ method: "erpnext.hr.utils.get_onboarding_details",
+ args: {
+ "parent": frm.doc.employee_onboarding_template,
+ "parenttype": "Employee Onboarding Template"
+ },
+ callback: function(r) {
+ if (r.message) {
+ $.each(r.message, function(i, d) {
+ var row = frappe.model.add_child(frm.doc, "Employee Boarding Activity", "activities");
+ $.extend(row, d);
+ });
+ }
+ refresh_field("activities");
+ }
+ });
+ }
+ }
+});
diff --git a/erpnext/hr/doctype/employee_onboarding/employee_onboarding.json b/erpnext/hr/doctype/employee_onboarding/employee_onboarding.json
new file mode 100644
index 0000000000..bd2ec4ce9d
--- /dev/null
+++ b/erpnext/hr/doctype/employee_onboarding/employee_onboarding.json
@@ -0,0 +1,569 @@
+{
+ "allow_copy": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "autoname": "EOB.#####",
+ "beta": 0,
+ "creation": "2018-05-09 04:57:20.016220",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "fields": [
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "employee_name",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Employee Name",
+ "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": "employee",
+ "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": "Employee",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Employee",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "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": "job_offer",
+ "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": "Job Offer",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Job Offer",
+ "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": "job_applicant",
+ "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": "Job Applicant",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Job Applicant",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "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": "date_of_joining",
+ "fieldtype": "Date",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Date of Joining",
+ "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": 1,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "boarding_status",
+ "fieldtype": "Select",
+ "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": "Status",
+ "length": 0,
+ "no_copy": 0,
+ "options": "\nPending\nIn Process\nCompleted",
+ "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": "column_break_7",
+ "fieldtype": "Column Break",
+ "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,
+ "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": "employee_onboarding_template",
+ "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": "Employee Onboarding Template",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Employee Onboarding Template",
+ "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": "company",
+ "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": "Company",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Company",
+ "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": "department",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Department",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Department",
+ "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": "designation",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Designation",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Designation",
+ "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": "employee_grade",
+ "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": "Employee Grade",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Employee Grade",
+ "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": "project",
+ "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": "Project",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Project",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "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": "table_for_activity",
+ "fieldtype": "Section Break",
+ "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": "",
+ "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": 1,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "activities",
+ "fieldtype": "Table",
+ "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": "Activities",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Employee Boarding Activity",
+ "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": "amended_from",
+ "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": "Amended From",
+ "length": 0,
+ "no_copy": 1,
+ "options": "Employee Onboarding",
+ "permlevel": 0,
+ "print_hide": 1,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ }
+ ],
+ "has_web_view": 0,
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "idx": 0,
+ "image_view": 0,
+ "in_create": 0,
+ "is_submittable": 1,
+ "issingle": 0,
+ "istable": 0,
+ "max_attachments": 0,
+ "modified": "2018-05-10 06:34:21.103617",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Employee Onboarding",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "amend": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 1,
+ "write": 1
+ }
+ ],
+ "quick_entry": 1,
+ "read_only": 0,
+ "read_only_onload": 0,
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "title_field": "employee_name",
+ "track_changes": 1,
+ "track_seen": 0
+}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/employee_onboarding/employee_onboarding.py b/erpnext/hr/doctype/employee_onboarding/employee_onboarding.py
new file mode 100644
index 0000000000..3390e8ffe5
--- /dev/null
+++ b/erpnext/hr/doctype/employee_onboarding/employee_onboarding.py
@@ -0,0 +1,50 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe import _
+from erpnext.hr.utils import EmployeeBoardingController
+from frappe.model.mapper import get_mapped_doc
+
+
+class EmployeeOnboarding(EmployeeBoardingController):
+ def validate():
+ super(EmployeeOnboarding, self).validate()
+
+ def validate_employee_creation(self):
+ if self.docstatus != 1:
+ frappe.throw(_("Submit this to create the Employee record"))
+ else:
+ for activity in self.activities:
+ if not activity.required_for_employee_creation:
+ continue
+ else:
+ task_status = frappe.db.get_value("Task", activity.task, "status")
+ if task_status not in ["Closed", "Cancelled"]:
+ frappe.throw(_("All the mandatory Task for employee creation hasn't been done yet."))
+
+ def on_submit(self):
+ super(EmployeeOnboarding, self).on_submit()
+
+ def on_cancel(self):
+ super(EmployeeOnboarding, self).on_cancel()
+
+
+@frappe.whitelist()
+def make_employee(source_name, target_doc=None):
+ doc = frappe.get_doc("Employee Onboarding", source_name)
+ doc.validate_employee_creation()
+ def set_missing_values(source, target):
+ target.personal_email = frappe.db.get_value("Job Applicant", source.job_applicant, "email_id")
+ target.status = "Active"
+ doc = get_mapped_doc("Employee Onboarding", source_name, {
+ "Employee Onboarding": {
+ "doctype": "Employee",
+ "field_map": {
+ "employee_grade": "grade",
+ }}
+ }, target_doc, set_missing_values)
+ return doc
+
diff --git a/erpnext/hr/doctype/employee_onboarding/test_employee_onboarding.js b/erpnext/hr/doctype/employee_onboarding/test_employee_onboarding.js
new file mode 100644
index 0000000000..d15cef77dc
--- /dev/null
+++ b/erpnext/hr/doctype/employee_onboarding/test_employee_onboarding.js
@@ -0,0 +1,23 @@
+/* eslint-disable */
+// rename this file from _test_[name] to test_[name] to activate
+// and remove above this line
+
+QUnit.test("test: Employee Onboarding", function (assert) {
+ let done = assert.async();
+
+ // number of asserts
+ assert.expect(1);
+
+ frappe.run_serially([
+ // insert a new Employee Onboarding
+ () => frappe.tests.make('Employee Onboarding', [
+ // values to be set
+ {key: 'value'}
+ ]),
+ () => {
+ assert.equal(cur_frm.doc.key, 'value');
+ },
+ () => done()
+ ]);
+
+});
diff --git a/erpnext/hr/doctype/employee_onboarding/test_employee_onboarding.py b/erpnext/hr/doctype/employee_onboarding/test_employee_onboarding.py
new file mode 100644
index 0000000000..b37ae883b6
--- /dev/null
+++ b/erpnext/hr/doctype/employee_onboarding/test_employee_onboarding.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import frappe
+import unittest
+
+class TestEmployeeOnboarding(unittest.TestCase):
+ pass
diff --git a/erpnext/hr/doctype/employee_onboarding_activity/__init__.py b/erpnext/hr/doctype/employee_onboarding_activity/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/hr/doctype/employee_onboarding_activity/employee_onboarding_activity.json b/erpnext/hr/doctype/employee_onboarding_activity/employee_onboarding_activity.json
new file mode 100644
index 0000000000..4e91b72384
--- /dev/null
+++ b/erpnext/hr/doctype/employee_onboarding_activity/employee_onboarding_activity.json
@@ -0,0 +1,290 @@
+{
+ "allow_copy": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "beta": 0,
+ "creation": "2018-05-09 05:37:18.439763",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "fields": [
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "activity_name",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Activity Name",
+ "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": "user",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "User",
+ "length": 0,
+ "no_copy": 0,
+ "options": "User",
+ "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": "role",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Role",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Role",
+ "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": "column_break_3",
+ "fieldtype": "Column Break",
+ "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,
+ "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,
+ "depends_on": "eval: doc.parenttype == \"Employee Onboarding\"",
+ "fieldname": "completed",
+ "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": "Completed",
+ "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": "required_for_employee_creation",
+ "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": "Required for Employee Creation",
+ "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": "section_break_6",
+ "fieldtype": "Section Break",
+ "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,
+ "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": "description",
+ "fieldtype": "Text Editor",
+ "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": "Description",
+ "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
+ }
+ ],
+ "has_web_view": 0,
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "idx": 0,
+ "image_view": 0,
+ "in_create": 0,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 1,
+ "max_attachments": 0,
+ "modified": "2018-05-09 06:15:41.768236",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Employee Onboarding Activity",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "read_only": 0,
+ "read_only_onload": 0,
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1,
+ "track_seen": 0
+}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/employee_onboarding_activity/employee_onboarding_activity.py b/erpnext/hr/doctype/employee_onboarding_activity/employee_onboarding_activity.py
new file mode 100644
index 0000000000..d170631819
--- /dev/null
+++ b/erpnext/hr/doctype/employee_onboarding_activity/employee_onboarding_activity.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe.model.document import Document
+
+class EmployeeOnboardingActivity(Document):
+ pass
diff --git a/erpnext/hr/doctype/employee_onboarding_template/__init__.py b/erpnext/hr/doctype/employee_onboarding_template/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/hr/doctype/employee_onboarding_template/employee_onboarding_template.js b/erpnext/hr/doctype/employee_onboarding_template/employee_onboarding_template.js
new file mode 100644
index 0000000000..2a531f31a2
--- /dev/null
+++ b/erpnext/hr/doctype/employee_onboarding_template/employee_onboarding_template.js
@@ -0,0 +1,8 @@
+// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Employee Onboarding Template', {
+ refresh: function(frm) {
+
+ }
+});
diff --git a/erpnext/hr/doctype/employee_onboarding_template/employee_onboarding_template.json b/erpnext/hr/doctype/employee_onboarding_template/employee_onboarding_template.json
new file mode 100644
index 0000000000..d0d3a62ba8
--- /dev/null
+++ b/erpnext/hr/doctype/employee_onboarding_template/employee_onboarding_template.json
@@ -0,0 +1,284 @@
+{
+ "allow_copy": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "autoname": "EOBT.#####",
+ "beta": 0,
+ "creation": "2018-05-09 05:27:02.393377",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "fields": [
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "company",
+ "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": "Company",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Company",
+ "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": "department",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Department",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Department",
+ "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": "column_break_7",
+ "fieldtype": "Column Break",
+ "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,
+ "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": "designation",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Designation",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Designation",
+ "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": "employee_grade",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Employee Grade",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Employee Grade",
+ "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": "section_break_7",
+ "fieldtype": "Section Break",
+ "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": "Activities",
+ "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": "activities",
+ "fieldtype": "Table",
+ "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": "Activities",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Employee Boarding Activity",
+ "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
+ }
+ ],
+ "has_web_view": 0,
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "idx": 0,
+ "image_view": 0,
+ "in_create": 0,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 0,
+ "max_attachments": 0,
+ "modified": "2018-05-09 07:05:21.051519",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Employee Onboarding Template",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "amend": 0,
+ "cancel": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 1
+ }
+ ],
+ "quick_entry": 0,
+ "read_only": 0,
+ "read_only_onload": 0,
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "title_field": "designation",
+ "track_changes": 1,
+ "track_seen": 0
+}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/employee_onboarding_template/employee_onboarding_template.py b/erpnext/hr/doctype/employee_onboarding_template/employee_onboarding_template.py
new file mode 100644
index 0000000000..6f1c316731
--- /dev/null
+++ b/erpnext/hr/doctype/employee_onboarding_template/employee_onboarding_template.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe.model.document import Document
+
+class EmployeeOnboardingTemplate(Document):
+ pass
diff --git a/erpnext/hr/doctype/employee_onboarding_template/test_employee_onboarding_template.js b/erpnext/hr/doctype/employee_onboarding_template/test_employee_onboarding_template.js
new file mode 100644
index 0000000000..10912edb6a
--- /dev/null
+++ b/erpnext/hr/doctype/employee_onboarding_template/test_employee_onboarding_template.js
@@ -0,0 +1,23 @@
+/* eslint-disable */
+// rename this file from _test_[name] to test_[name] to activate
+// and remove above this line
+
+QUnit.test("test: Employee Onboarding Template", function (assert) {
+ let done = assert.async();
+
+ // number of asserts
+ assert.expect(1);
+
+ frappe.run_serially([
+ // insert a new Employee Onboarding Template
+ () => frappe.tests.make('Employee Onboarding Template', [
+ // values to be set
+ {key: 'value'}
+ ]),
+ () => {
+ assert.equal(cur_frm.doc.key, 'value');
+ },
+ () => done()
+ ]);
+
+});
diff --git a/erpnext/hr/doctype/employee_onboarding_template/test_employee_onboarding_template.py b/erpnext/hr/doctype/employee_onboarding_template/test_employee_onboarding_template.py
new file mode 100644
index 0000000000..f4b5b88342
--- /dev/null
+++ b/erpnext/hr/doctype/employee_onboarding_template/test_employee_onboarding_template.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import frappe
+import unittest
+
+class TestEmployeeOnboardingTemplate(unittest.TestCase):
+ pass
diff --git a/erpnext/hr/doctype/employee_separation/__init__.py b/erpnext/hr/doctype/employee_separation/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/hr/doctype/employee_separation/employee_separation.js b/erpnext/hr/doctype/employee_separation/employee_separation.js
new file mode 100644
index 0000000000..33830796b6
--- /dev/null
+++ b/erpnext/hr/doctype/employee_separation/employee_separation.js
@@ -0,0 +1,49 @@
+// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Employee Separation', {
+ setup: function(frm) {
+ frm.add_fetch("employee_separation_template", "company", "company");
+ frm.add_fetch("employee_separation_template", "department", "department");
+ frm.add_fetch("employee_separation_template", "designation", "designation");
+ frm.add_fetch("employee_separation_template", "employee_grade", "employee_grade");
+ },
+
+ refresh: function(frm) {
+ if (frm.doc.employee) {
+ frm.add_custom_button(__('Employee'), function() {
+ frappe.set_route("Form", "Employee", frm.doc.employee);
+ },__("View"));
+ }
+ if (frm.doc.project) {
+ frm.add_custom_button(__('Project'), function() {
+ frappe.set_route("Form", "Project", frm.doc.project);
+ },__("View"));
+ frm.add_custom_button(__('Task'), function() {
+ frappe.set_route('List', 'Task', {project: frm.doc.project});
+ },__("View"));
+ }
+ },
+
+ employee_separation_template: function(frm) {
+ frm.set_value("activities" ,"");
+ if (frm.doc.employee_separation_template) {
+ frappe.call({
+ method: "erpnext.hr.utils.get_onboarding_details",
+ args: {
+ "parent": frm.doc.employee_separation_template,
+ "parenttype": "Employee Separation Template"
+ },
+ callback: function(r) {
+ if (r.message) {
+ $.each(r.message, function(i, d) {
+ var row = frappe.model.add_child(frm.doc, "Employee Boarding Activity", "activities");
+ $.extend(row, d);
+ });
+ }
+ refresh_field("activities");
+ }
+ });
+ }
+ }
+});
diff --git a/erpnext/hr/doctype/employee_separation/employee_separation.json b/erpnext/hr/doctype/employee_separation/employee_separation.json
new file mode 100644
index 0000000000..7d9cfb1c59
--- /dev/null
+++ b/erpnext/hr/doctype/employee_separation/employee_separation.json
@@ -0,0 +1,567 @@
+{
+ "allow_copy": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "autoname": "ES.#####",
+ "beta": 0,
+ "creation": "2018-05-10 02:29:16.740490",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "fields": [
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "employee",
+ "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": "Employee",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Employee",
+ "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": "employee_name",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Employee Name",
+ "length": 0,
+ "no_copy": 0,
+ "options": "employee.employee_name",
+ "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": "resignation_letter_date",
+ "fieldtype": "Date",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Resignation Letter Date",
+ "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": 1,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "boarding_status",
+ "fieldtype": "Select",
+ "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": "Status",
+ "length": 0,
+ "no_copy": 0,
+ "options": "\nPending\nIn Process\nCompleted",
+ "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": "project",
+ "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": "Project",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Project",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "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": "column_break_7",
+ "fieldtype": "Column Break",
+ "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,
+ "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": "employee_separation_template",
+ "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": "Employee Separation Template",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Employee Separation Template",
+ "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": "company",
+ "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": "Company",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Company",
+ "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": "department",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Department",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Department",
+ "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": "designation",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Designation",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Designation",
+ "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": "employee_grade",
+ "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": "Employee Grade",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Employee Grade",
+ "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": "table_for_activity",
+ "fieldtype": "Section Break",
+ "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": "",
+ "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": 1,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "activities",
+ "fieldtype": "Table",
+ "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": "Activities",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Employee Boarding Activity",
+ "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": "section_break_14",
+ "fieldtype": "Section Break",
+ "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,
+ "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": "exit_interview",
+ "fieldtype": "Text Editor",
+ "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": "Exit Interview Summary",
+ "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": "amended_from",
+ "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": "Amended From",
+ "length": 0,
+ "no_copy": 1,
+ "options": "Employee Separation",
+ "permlevel": 0,
+ "print_hide": 1,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ }
+ ],
+ "has_web_view": 0,
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "idx": 0,
+ "image_view": 0,
+ "in_create": 0,
+ "is_submittable": 1,
+ "issingle": 0,
+ "istable": 0,
+ "max_attachments": 0,
+ "modified": "2018-05-10 06:34:53.649332",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Employee Separation",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "amend": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 1,
+ "write": 1
+ }
+ ],
+ "quick_entry": 1,
+ "read_only": 0,
+ "read_only_onload": 0,
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "title_field": "employee_name",
+ "track_changes": 1,
+ "track_seen": 0
+}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/employee_separation/employee_separation.py b/erpnext/hr/doctype/employee_separation/employee_separation.py
new file mode 100644
index 0000000000..b908b632c8
--- /dev/null
+++ b/erpnext/hr/doctype/employee_separation/employee_separation.py
@@ -0,0 +1,16 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+from erpnext.hr.utils import EmployeeBoardingController
+
+class EmployeeSeparation(EmployeeBoardingController):
+ def validate(self):
+ super(EmployeeSeparation, self).validate()
+
+ def on_submit(self):
+ super(EmployeeSeparation, self).on_submit()
+
+ def on_cancel(self):
+ super(EmployeeSeparation, self).on_cancel()
diff --git a/erpnext/hr/doctype/employee_separation/test_employee_separation.js b/erpnext/hr/doctype/employee_separation/test_employee_separation.js
new file mode 100644
index 0000000000..d6c635951f
--- /dev/null
+++ b/erpnext/hr/doctype/employee_separation/test_employee_separation.js
@@ -0,0 +1,23 @@
+/* eslint-disable */
+// rename this file from _test_[name] to test_[name] to activate
+// and remove above this line
+
+QUnit.test("test: Employee Separation", function (assert) {
+ let done = assert.async();
+
+ // number of asserts
+ assert.expect(1);
+
+ frappe.run_serially([
+ // insert a new Employee Separation
+ () => frappe.tests.make('Employee Separation', [
+ // values to be set
+ {key: 'value'}
+ ]),
+ () => {
+ assert.equal(cur_frm.doc.key, 'value');
+ },
+ () => done()
+ ]);
+
+});
diff --git a/erpnext/hr/doctype/employee_separation/test_employee_separation.py b/erpnext/hr/doctype/employee_separation/test_employee_separation.py
new file mode 100644
index 0000000000..0773fb6ae9
--- /dev/null
+++ b/erpnext/hr/doctype/employee_separation/test_employee_separation.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import frappe
+import unittest
+
+class TestEmployeeSeparation(unittest.TestCase):
+ pass
diff --git a/erpnext/hr/doctype/employee_separation_template/__init__.py b/erpnext/hr/doctype/employee_separation_template/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/hr/doctype/employee_separation_template/employee_separation_template.js b/erpnext/hr/doctype/employee_separation_template/employee_separation_template.js
new file mode 100644
index 0000000000..172ff9fc5b
--- /dev/null
+++ b/erpnext/hr/doctype/employee_separation_template/employee_separation_template.js
@@ -0,0 +1,8 @@
+// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Employee Separation Template', {
+ refresh: function(frm) {
+
+ }
+});
diff --git a/erpnext/hr/doctype/employee_separation_template/employee_separation_template.json b/erpnext/hr/doctype/employee_separation_template/employee_separation_template.json
new file mode 100644
index 0000000000..f1f440a020
--- /dev/null
+++ b/erpnext/hr/doctype/employee_separation_template/employee_separation_template.json
@@ -0,0 +1,284 @@
+{
+ "allow_copy": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "autoname": "EST.#####",
+ "beta": 0,
+ "creation": "2018-05-09 06:31:44.498557",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "fields": [
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "company",
+ "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": "Company",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Company",
+ "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": "department",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Department",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Department",
+ "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": "column_break_7",
+ "fieldtype": "Column Break",
+ "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,
+ "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": "designation",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Designation",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Designation",
+ "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": "employee_grade",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Employee Grade",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Employee Grade",
+ "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": "section_break_7",
+ "fieldtype": "Section Break",
+ "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": "Activities",
+ "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": "activities",
+ "fieldtype": "Table",
+ "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": "Activities",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Employee Boarding Activity",
+ "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
+ }
+ ],
+ "has_web_view": 0,
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "idx": 0,
+ "image_view": 0,
+ "in_create": 0,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 0,
+ "max_attachments": 0,
+ "modified": "2018-05-09 07:05:30.792336",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Employee Separation Template",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "amend": 0,
+ "cancel": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 1
+ }
+ ],
+ "quick_entry": 0,
+ "read_only": 0,
+ "read_only_onload": 0,
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "title_field": "designation",
+ "track_changes": 1,
+ "track_seen": 0
+}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/employee_separation_template/employee_separation_template.py b/erpnext/hr/doctype/employee_separation_template/employee_separation_template.py
new file mode 100644
index 0000000000..0508fc462e
--- /dev/null
+++ b/erpnext/hr/doctype/employee_separation_template/employee_separation_template.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe.model.document import Document
+
+class EmployeeSeparationTemplate(Document):
+ pass
diff --git a/erpnext/hr/doctype/employee_separation_template/test_employee_separation_template.js b/erpnext/hr/doctype/employee_separation_template/test_employee_separation_template.js
new file mode 100644
index 0000000000..66fd450804
--- /dev/null
+++ b/erpnext/hr/doctype/employee_separation_template/test_employee_separation_template.js
@@ -0,0 +1,23 @@
+/* eslint-disable */
+// rename this file from _test_[name] to test_[name] to activate
+// and remove above this line
+
+QUnit.test("test: Employee Separation Template", function (assert) {
+ let done = assert.async();
+
+ // number of asserts
+ assert.expect(1);
+
+ frappe.run_serially([
+ // insert a new Employee Separation Template
+ () => frappe.tests.make('Employee Separation Template', [
+ // values to be set
+ {key: 'value'}
+ ]),
+ () => {
+ assert.equal(cur_frm.doc.key, 'value');
+ },
+ () => done()
+ ]);
+
+});
diff --git a/erpnext/hr/doctype/employee_separation_template/test_employee_separation_template.py b/erpnext/hr/doctype/employee_separation_template/test_employee_separation_template.py
new file mode 100644
index 0000000000..3fd3d398bd
--- /dev/null
+++ b/erpnext/hr/doctype/employee_separation_template/test_employee_separation_template.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import frappe
+import unittest
+
+class TestEmployeeSeparationTemplate(unittest.TestCase):
+ pass
diff --git a/erpnext/hr/doctype/employee_tax_exemption_declaration/employee_tax_exemption_declaration.js b/erpnext/hr/doctype/employee_tax_exemption_declaration/employee_tax_exemption_declaration.js
index d204efc5bf..b31bf0ec45 100644
--- a/erpnext/hr/doctype/employee_tax_exemption_declaration/employee_tax_exemption_declaration.js
+++ b/erpnext/hr/doctype/employee_tax_exemption_declaration/employee_tax_exemption_declaration.js
@@ -2,7 +2,38 @@
// For license information, please see license.txt
frappe.ui.form.on('Employee Tax Exemption Declaration', {
- refresh: function(frm) {
-
+ setup: function(frm) {
+ frm.set_query('employee', function() {
+ return {
+ filters: {
+ 'status': "Active"
+ }
+ }
+ });
+ frm.set_query('payroll_period', function() {
+ if(frm.doc.employee && frm.doc.company){
+ return {
+ filters: {
+ 'company': frm.doc.company
+ }
+ }
+ }else {
+ frappe.msgprint(__("Please select Employee"));
+ }
+ });
+ frm.set_query('exemption_sub_category', 'declarations', function() {
+ return {
+ filters: {
+ 'is_active': 1
+ }
+ }
+ });
+ },
+ employee: function(frm){
+ if(frm.doc.employee){
+ frm.add_fetch('employee', 'company', 'company');
+ }else{
+ frm.set_value('company', '');
+ }
}
});
diff --git a/erpnext/hr/doctype/employee_tax_exemption_declaration/employee_tax_exemption_declaration.json b/erpnext/hr/doctype/employee_tax_exemption_declaration/employee_tax_exemption_declaration.json
index ebfce2b9e3..3c361eea60 100644
--- a/erpnext/hr/doctype/employee_tax_exemption_declaration/employee_tax_exemption_declaration.json
+++ b/erpnext/hr/doctype/employee_tax_exemption_declaration/employee_tax_exemption_declaration.json
@@ -42,7 +42,37 @@
"reqd": 1,
"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": "company",
+ "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": "Company",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Company",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
"unique": 0
},
{
@@ -72,7 +102,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
"unique": 0
},
{
@@ -104,7 +133,6 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
"unique": 0
},
{
@@ -135,7 +163,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
"unique": 0
},
{
@@ -165,7 +192,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
"unique": 0
},
{
@@ -197,7 +223,6 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
"unique": 0
}
],
@@ -211,7 +236,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2018-04-13 19:23:54.363578",
+ "modified": "2018-05-10 13:26:25.241545",
"modified_by": "Administrator",
"module": "HR",
"name": "Employee Tax Exemption Declaration",
@@ -220,6 +245,7 @@
"permissions": [
{
"amend": 1,
+ "apply_user_permissions": 0,
"cancel": 1,
"create": 1,
"delete": 1,
@@ -239,6 +265,7 @@
},
{
"amend": 1,
+ "apply_user_permissions": 0,
"cancel": 1,
"create": 1,
"delete": 1,
@@ -258,6 +285,7 @@
},
{
"amend": 1,
+ "apply_user_permissions": 0,
"cancel": 1,
"create": 1,
"delete": 1,
@@ -277,6 +305,7 @@
},
{
"amend": 1,
+ "apply_user_permissions": 0,
"cancel": 1,
"create": 1,
"delete": 1,
diff --git a/erpnext/hr/doctype/employee_tax_exemption_declaration/employee_tax_exemption_declaration.py b/erpnext/hr/doctype/employee_tax_exemption_declaration/employee_tax_exemption_declaration.py
index 1a5f195d02..52746d4cff 100644
--- a/erpnext/hr/doctype/employee_tax_exemption_declaration/employee_tax_exemption_declaration.py
+++ b/erpnext/hr/doctype/employee_tax_exemption_declaration/employee_tax_exemption_declaration.py
@@ -5,6 +5,17 @@
from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
+from frappe import _
+from erpnext.hr.utils import validate_tax_declaration
class EmployeeTaxExemptionDeclaration(Document):
- pass
+ def validate(self):
+ validate_tax_declaration(self.declarations)
+
+ def before_submit(self):
+ if frappe.db.exists({"doctype": "Employee Tax Exemption Declaration",
+ "employee": self.employee,
+ "payroll_period": self.payroll_period,
+ "docstatus": 1}):
+ frappe.throw(_("Tax Declaration of {0} for period {1} already submitted.")\
+ .format(self.employee, self.payroll_period), frappe.DocstatusTransitionError)
diff --git a/erpnext/hr/doctype/employee_tax_exemption_declaration/test_employee_tax_exemption_declaration.py b/erpnext/hr/doctype/employee_tax_exemption_declaration/test_employee_tax_exemption_declaration.py
index 48f561a167..84970d85fd 100644
--- a/erpnext/hr/doctype/employee_tax_exemption_declaration/test_employee_tax_exemption_declaration.py
+++ b/erpnext/hr/doctype/employee_tax_exemption_declaration/test_employee_tax_exemption_declaration.py
@@ -5,6 +5,110 @@ from __future__ import unicode_literals
import frappe
import unittest
+from erpnext.hr.doctype.salary_structure.test_salary_structure import make_employee
class TestEmployeeTaxExemptionDeclaration(unittest.TestCase):
- pass
+ def setup(self):
+ make_employee("employee@taxexepmtion.com")
+ make_employee("employee1@taxexepmtion.com")
+ create_payroll_period()
+ create_exemption_category()
+ frappe.db.sql("""delete from `tabEmployee Tax Exemption Declaration`""")
+
+ def test_exemption_amount_greater_than_category_max(self):
+ declaration = frappe.get_doc({
+ "doctype": "Employee Tax Exemption Declaration",
+ "employee": frappe.get_value("Employee", {"user_id":"employee@taxexepmtion.com"}, "name"),
+ "payroll_period": "Test Payroll Period",
+ "declarations": [dict(exemption_sub_category = "_Test Sub Category",
+ exemption_category = "_Test Category",
+ amount = 150000)]
+ })
+ self.assertRaises(frappe.ValidationError, declaration.save)
+ declaration = frappe.get_doc({
+ "doctype": "Employee Tax Exemption Declaration",
+ "payroll_period": "Test Payroll Period",
+ "employee": frappe.get_value("Employee", {"user_id":"employee@taxexepmtion.com"}, "name"),
+ "declarations": [dict(exemption_sub_category = "_Test Sub Category",
+ exemption_category = "_Test Category",
+ amount = 90000)]
+ })
+ self.assertTrue(declaration.save)
+
+ def test_duplicate_category_in_declaration(self):
+ declaration = frappe.get_doc({
+ "doctype": "Employee Tax Exemption Declaration",
+ "employee": frappe.get_value("Employee", {"user_id":"employee@taxexepmtion.com"}, "name"),
+ "payroll_period": "Test Payroll Period",
+ "declarations": [dict(exemption_sub_category = "_Test Sub Category",
+ exemption_category = "_Test Category",
+ amount = 100000),
+ dict(exemption_sub_category = "_Test Sub Category",
+ exemption_category = "_Test Category",
+ amount = 50000),
+ ]
+ })
+ self.assertRaises(frappe.ValidationError, declaration.save)
+
+ def test_duplicate_submission_for_payroll_period(self):
+ declaration = frappe.get_doc({
+ "doctype": "Employee Tax Exemption Declaration",
+ "employee": frappe.get_value("Employee", {"user_id":"employee@taxexepmtion.com"}, "name"),
+ "payroll_period": "Test Payroll Period",
+ "declarations": [dict(exemption_sub_category = "_Test Sub Category",
+ exemption_category = "_Test Category",
+ amount = 100000),
+ dict(exemption_sub_category = "_Test1 Sub Category",
+ exemption_category = "_Test Category",
+ amount = 50000),
+ ]
+ })
+ self.assertTrue(declaration.submit)
+ duplicate_declaration = frappe.get_doc({
+ "doctype": "Employee Tax Exemption Declaration",
+ "employee": frappe.get_value("Employee", {"user_id":"employee@taxexepmtion.com"}, "name"),
+ "payroll_period": "Test Payroll Period",
+ "declarations": [dict(exemption_sub_category = "_Test Sub Category",
+ exemption_category = "_Test Category",
+ amount = 100000)
+ ]
+ })
+ self.assertRaises(frappe.DocstatusTransitionError, duplicate_declaration.submit)
+ duplicate_declaration.employee = frappe.get_value("Employee", {"user_id":"employee1@taxexepmtion.com"}, "name")
+ self.assertTrue(duplicate_declaration.submit)
+
+def create_payroll_period():
+ if not frappe.db.exists("Payroll Period", "_Test Payroll Period"):
+ from datetime import date
+ payroll_period = frappe.get_doc(dict(
+ doctype = 'Payroll Period',
+ name = "_Test Payroll Period",
+ company = "_Test Company",
+ periods = [
+ dict(start_date = date(date.today().year, 1, 1),
+ end_date = date(date.today().year, 12, 31))
+ ]
+ )).insert()
+
+def create_exemption_category():
+ if not frappe.db.exists("Employee Tax Exemption Category", "_Test Category"):
+ category = frappe.get_doc({
+ "doctype": "Employee Tax Exemption Category",
+ "name": "_Test Category",
+ "deduction_component": "_Test Tax",
+ "max_amount": 100000
+ }).insert()
+ if not frappe.db.exists("Employee Tax Exemption Sub Category", "_Test Category"):
+ frappe.get_doc({
+ "doctype": "Employee Tax Exemption Sub Category",
+ "name": "_Test Sub Category",
+ "exemption_category": "_Test Category",
+ "max_amount": 100000
+ }).insert()
+ if not frappe.db.exists("Employee Tax Exemption Sub Category", "_Test Category"):
+ frappe.get_doc({
+ "doctype": "Employee Tax Exemption Sub Category",
+ "name": "_Test1 Sub Category",
+ "exemption_category": "_Test Category",
+ "max_amount": 50000
+ }).insert()
diff --git a/erpnext/hr/doctype/employee_tax_exemption_declaration_category/employee_tax_exemption_declaration_category.json b/erpnext/hr/doctype/employee_tax_exemption_declaration_category/employee_tax_exemption_declaration_category.json
index 48a5dd09db..bdaf9bf3d0 100644
--- a/erpnext/hr/doctype/employee_tax_exemption_declaration_category/employee_tax_exemption_declaration_category.json
+++ b/erpnext/hr/doctype/employee_tax_exemption_declaration_category/employee_tax_exemption_declaration_category.json
@@ -18,7 +18,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
- "fieldname": "exemption_category",
+ "fieldname": "exemption_sub_category",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
@@ -27,10 +27,41 @@
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
- "label": "Exemption Category",
+ "label": "Exemption Sub Category",
"length": 0,
"no_copy": 0,
- "options": "Employee Tax Exemption Category",
+ "options": "Employee Tax Exemption Sub Category",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "exemption_category",
+ "fieldtype": "Read Only",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Exemption Category",
+ "length": 0,
+ "no_copy": 0,
+ "options": "exemption_sub_category.exemption_category",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@@ -41,7 +72,6 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
"unique": 0
},
{
@@ -72,7 +102,6 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
"unique": 0
}
],
@@ -86,7 +115,7 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
- "modified": "2018-04-13 19:24:18.076613",
+ "modified": "2018-05-09 13:30:44.363393",
"modified_by": "Administrator",
"module": "HR",
"name": "Employee Tax Exemption Declaration Category",
diff --git a/erpnext/hr/doctype/employee_tax_exemption_proof_submission/employee_tax_exemption_proof_submission.js b/erpnext/hr/doctype/employee_tax_exemption_proof_submission/employee_tax_exemption_proof_submission.js
index d8036c48e9..99bec14b18 100644
--- a/erpnext/hr/doctype/employee_tax_exemption_proof_submission/employee_tax_exemption_proof_submission.js
+++ b/erpnext/hr/doctype/employee_tax_exemption_proof_submission/employee_tax_exemption_proof_submission.js
@@ -2,7 +2,38 @@
// For license information, please see license.txt
frappe.ui.form.on('Employee Tax Exemption Proof Submission', {
- refresh: function(frm) {
-
+ setup: function(frm) {
+ frm.set_query('employee', function() {
+ return {
+ filters: {
+ 'status': "Active"
+ }
+ }
+ });
+ frm.set_query('payroll_period', function() {
+ if(frm.doc.employee && frm.doc.company){
+ return {
+ filters: {
+ 'company': frm.doc.company
+ }
+ }
+ }else {
+ frappe.msgprint(__("Please select Employee"));
+ }
+ });
+ frm.set_query('exemption_sub_category', 'tax_exemption_proofs', function() {
+ return {
+ filters: {
+ 'is_active': 1
+ }
+ }
+ });
+ },
+ employee: function(frm){
+ if(frm.doc.employee){
+ frm.add_fetch('employee', 'company', 'company');
+ }else{
+ frm.set_value('company', '');
+ }
}
});
diff --git a/erpnext/hr/doctype/employee_tax_exemption_proof_submission/employee_tax_exemption_proof_submission.json b/erpnext/hr/doctype/employee_tax_exemption_proof_submission/employee_tax_exemption_proof_submission.json
index 41d9681b1b..51f23aa55e 100644
--- a/erpnext/hr/doctype/employee_tax_exemption_proof_submission/employee_tax_exemption_proof_submission.json
+++ b/erpnext/hr/doctype/employee_tax_exemption_proof_submission/employee_tax_exemption_proof_submission.json
@@ -42,7 +42,37 @@
"reqd": 1,
"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": "company",
+ "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": "Company",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Company",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
"unique": 0
},
{
@@ -72,7 +102,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
"unique": 0
},
{
@@ -104,7 +133,6 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
"unique": 0
},
{
@@ -135,7 +163,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
"unique": 0
},
{
@@ -165,7 +192,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
"unique": 0
},
{
@@ -197,7 +223,6 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
"unique": 0
},
{
@@ -228,7 +253,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
"unique": 0
},
{
@@ -259,7 +283,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
"unique": 0
},
{
@@ -290,7 +313,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
"unique": 0
}
],
@@ -304,7 +326,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2018-04-13 19:21:59.969371",
+ "modified": "2018-05-10 13:26:53.030547",
"modified_by": "Administrator",
"module": "HR",
"name": "Employee Tax Exemption Proof Submission",
@@ -313,6 +335,7 @@
"permissions": [
{
"amend": 1,
+ "apply_user_permissions": 0,
"cancel": 1,
"create": 1,
"delete": 1,
@@ -332,6 +355,7 @@
},
{
"amend": 1,
+ "apply_user_permissions": 0,
"cancel": 1,
"create": 1,
"delete": 1,
@@ -351,6 +375,7 @@
},
{
"amend": 1,
+ "apply_user_permissions": 0,
"cancel": 1,
"create": 1,
"delete": 1,
@@ -370,6 +395,7 @@
},
{
"amend": 1,
+ "apply_user_permissions": 0,
"cancel": 1,
"create": 1,
"delete": 1,
diff --git a/erpnext/hr/doctype/employee_tax_exemption_proof_submission/employee_tax_exemption_proof_submission.py b/erpnext/hr/doctype/employee_tax_exemption_proof_submission/employee_tax_exemption_proof_submission.py
index 1c31cc4080..a0c003cdc6 100644
--- a/erpnext/hr/doctype/employee_tax_exemption_proof_submission/employee_tax_exemption_proof_submission.py
+++ b/erpnext/hr/doctype/employee_tax_exemption_proof_submission/employee_tax_exemption_proof_submission.py
@@ -5,6 +5,17 @@
from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
+from frappe import _
+from erpnext.hr.utils import validate_tax_declaration
class EmployeeTaxExemptionProofSubmission(Document):
- pass
+ def validate(self):
+ validate_tax_declaration(self.tax_exemption_proofs)
+ #TODO: allow multiple?
+ # def before_submit(self):
+ # if frappe.db.exists({"doctype": "Employee Tax Exemption Proof Submission",
+ # "employee": self.employee,
+ # "payroll_period": self.payroll_period,
+ # "docstatus": 1}):
+ # frappe.throw(_("Proof Submission of {0} for period {1} already submitted.")\
+ # .format(self.employee, self.payroll_period), frappe.DocstatusTransitionError)
diff --git a/erpnext/hr/doctype/employee_tax_exemption_proof_submission/test_employee_tax_exemption_proof_submission.py b/erpnext/hr/doctype/employee_tax_exemption_proof_submission/test_employee_tax_exemption_proof_submission.py
index 1dc090f0bb..4b5777bcab 100644
--- a/erpnext/hr/doctype/employee_tax_exemption_proof_submission/test_employee_tax_exemption_proof_submission.py
+++ b/erpnext/hr/doctype/employee_tax_exemption_proof_submission/test_employee_tax_exemption_proof_submission.py
@@ -5,6 +5,50 @@ from __future__ import unicode_literals
import frappe
import unittest
+from erpnext.hr.doctype.employee_tax_exemption_declaration.test_employee_tax_exemption_declaration import create_exemption_category, create_payroll_period
class TestEmployeeTaxExemptionProofSubmission(unittest.TestCase):
- pass
+ def setup(self):
+ make_employee("employee@proofsubmission.com")
+ create_payroll_period()
+ create_exemption_category()
+ frappe.db.sql("""delete from `tabEmployee Tax Exemption Proof Submission`""")
+
+ def test_exemption_amount_lesser_than_category_max(self):
+ declaration = frappe.get_doc({
+ "doctype": "Employee Tax Exemption Proof Submission",
+ "employee": frappe.get_value("Employee", {"user_id":"employee@proofsubmission.com"}, "name"),
+ "payroll_period": "Test Payroll Period",
+ "tax_exemption_proofs": [dict(exemption_sub_category = "_Test Sub Category",
+ type_of_proof = "Test Proof",
+ exemption_category = "_Test Category",
+ amount = 150000)]
+ })
+ self.assertRaises(frappe.ValidationError, declaration.save)
+ declaration = frappe.get_doc({
+ "doctype": "Employee Tax Exemption Proof Submission",
+ "payroll_period": "Test Payroll Period",
+ "employee": frappe.get_value("Employee", {"user_id":"employee@proofsubmission.com"}, "name"),
+ "tax_exemption_proofs": [dict(exemption_sub_category = "_Test Sub Category",
+ type_of_proof = "Test Proof",
+ exemption_category = "_Test Category",
+ amount = 100000)]
+ })
+ self.assertTrue(declaration.save)
+ self.assertTrue(declaration.submit)
+
+ def test_duplicate_category_in_proof_submission(self):
+ declaration = frappe.get_doc({
+ "doctype": "Employee Tax Exemption Proof Submission",
+ "employee": frappe.get_value("Employee", {"user_id":"employee@proofsubmission.com"}, "name"),
+ "payroll_period": "Test Payroll Period",
+ "tax_exemption_proofs": [dict(exemption_sub_category = "_Test Sub Category",
+ exemption_category = "_Test Category",
+ type_of_proof = "Test Proof",
+ amount = 100000),
+ dict(exemption_sub_category = "_Test Sub Category",
+ exemption_category = "_Test Category",
+ amount = 50000),
+ ]
+ })
+ self.assertRaises(frappe.ValidationError, declaration.save)
diff --git a/erpnext/hr/doctype/employee_tax_exemption_proof_submission_detail/employee_tax_exemption_proof_submission_detail.json b/erpnext/hr/doctype/employee_tax_exemption_proof_submission_detail/employee_tax_exemption_proof_submission_detail.json
index 509e425270..3725900772 100644
--- a/erpnext/hr/doctype/employee_tax_exemption_proof_submission_detail/employee_tax_exemption_proof_submission_detail.json
+++ b/erpnext/hr/doctype/employee_tax_exemption_proof_submission_detail/employee_tax_exemption_proof_submission_detail.json
@@ -18,7 +18,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
- "fieldname": "exemption_category",
+ "fieldname": "exemption_sub_category",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
@@ -27,10 +27,41 @@
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
- "label": "Exemption Category",
+ "label": "Exemption Sub Category",
"length": 0,
"no_copy": 0,
- "options": "Employee Tax Exemption Category",
+ "options": "Employee Tax Exemption Sub Category",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "exemption_category",
+ "fieldtype": "Read Only",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Exemption Category",
+ "length": 0,
+ "no_copy": 0,
+ "options": "exemption_sub_category.exemption_category",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@@ -41,7 +72,6 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
"unique": 0
},
{
@@ -73,7 +103,6 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
"unique": 0
},
{
@@ -104,7 +133,6 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
"unique": 0
}
],
@@ -118,7 +146,7 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
- "modified": "2018-04-13 17:19:03.006149",
+ "modified": "2018-05-09 13:53:22.563316",
"modified_by": "Administrator",
"module": "HR",
"name": "Employee Tax Exemption Proof Submission Detail",
diff --git a/erpnext/hr/doctype/employee_tax_exemption_sub_category/__init__.py b/erpnext/hr/doctype/employee_tax_exemption_sub_category/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/hr/doctype/employee_tax_exemption_sub_category/employee_tax_exemption_sub_category.js b/erpnext/hr/doctype/employee_tax_exemption_sub_category/employee_tax_exemption_sub_category.js
new file mode 100644
index 0000000000..8a83a2739c
--- /dev/null
+++ b/erpnext/hr/doctype/employee_tax_exemption_sub_category/employee_tax_exemption_sub_category.js
@@ -0,0 +1,8 @@
+// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Employee Tax Exemption Sub Category', {
+ refresh: function(frm) {
+
+ }
+});
diff --git a/erpnext/hr/doctype/employee_tax_exemption_sub_category/employee_tax_exemption_sub_category.json b/erpnext/hr/doctype/employee_tax_exemption_sub_category/employee_tax_exemption_sub_category.json
new file mode 100644
index 0000000000..dc99785067
--- /dev/null
+++ b/erpnext/hr/doctype/employee_tax_exemption_sub_category/employee_tax_exemption_sub_category.json
@@ -0,0 +1,194 @@
+{
+ "allow_copy": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 1,
+ "allow_rename": 1,
+ "autoname": "Prompt",
+ "beta": 0,
+ "creation": "2018-05-09 12:47:26.983095",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "fields": [
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "exemption_category",
+ "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": "Tax Exemption Category",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Employee Tax Exemption Category",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "max_amount",
+ "fieldtype": "Currency",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Max Amount",
+ "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": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "is_active",
+ "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": "Is Active",
+ "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,
+ "unique": 0
+ }
+ ],
+ "has_web_view": 0,
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "idx": 0,
+ "image_view": 0,
+ "in_create": 0,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 0,
+ "max_attachments": 0,
+ "modified": "2018-05-09 13:25:01.595240",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Employee Tax Exemption Sub Category",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "amend": 0,
+ "apply_user_permissions": 0,
+ "cancel": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 1
+ },
+ {
+ "amend": 0,
+ "apply_user_permissions": 0,
+ "cancel": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "HR Manager",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 1
+ },
+ {
+ "amend": 0,
+ "apply_user_permissions": 0,
+ "cancel": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "HR User",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 1
+ }
+ ],
+ "quick_entry": 0,
+ "read_only": 0,
+ "read_only_onload": 0,
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1,
+ "track_seen": 0
+}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/employee_tax_exemption_sub_category/employee_tax_exemption_sub_category.py b/erpnext/hr/doctype/employee_tax_exemption_sub_category/employee_tax_exemption_sub_category.py
new file mode 100644
index 0000000000..cd58136d8d
--- /dev/null
+++ b/erpnext/hr/doctype/employee_tax_exemption_sub_category/employee_tax_exemption_sub_category.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe.model.document import Document
+
+class EmployeeTaxExemptionSubCategory(Document):
+ pass
diff --git a/erpnext/hr/doctype/employee_tax_exemption_sub_category/test_employee_tax_exemption_sub_category.js b/erpnext/hr/doctype/employee_tax_exemption_sub_category/test_employee_tax_exemption_sub_category.js
new file mode 100644
index 0000000000..8a1a6d151d
--- /dev/null
+++ b/erpnext/hr/doctype/employee_tax_exemption_sub_category/test_employee_tax_exemption_sub_category.js
@@ -0,0 +1,23 @@
+/* eslint-disable */
+// rename this file from _test_[name] to test_[name] to activate
+// and remove above this line
+
+QUnit.test("test: Employee Tax Exemption Sub Category", function (assert) {
+ let done = assert.async();
+
+ // number of asserts
+ assert.expect(1);
+
+ frappe.run_serially([
+ // insert a new Employee Tax Exemption Sub Category
+ () => frappe.tests.make('Employee Tax Exemption Sub Category', [
+ // values to be set
+ {key: 'value'}
+ ]),
+ () => {
+ assert.equal(cur_frm.doc.key, 'value');
+ },
+ () => done()
+ ]);
+
+});
diff --git a/erpnext/hr/doctype/employee_tax_exemption_sub_category/test_employee_tax_exemption_sub_category.py b/erpnext/hr/doctype/employee_tax_exemption_sub_category/test_employee_tax_exemption_sub_category.py
new file mode 100644
index 0000000000..5d705567a2
--- /dev/null
+++ b/erpnext/hr/doctype/employee_tax_exemption_sub_category/test_employee_tax_exemption_sub_category.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import frappe
+import unittest
+
+class TestEmployeeTaxExemptionSubCategory(unittest.TestCase):
+ pass
diff --git a/erpnext/hr/doctype/job_opening/job_opening.js b/erpnext/hr/doctype/job_opening/job_opening.js
index e69de29bb2..7b0e447a9e 100644
--- a/erpnext/hr/doctype/job_opening/job_opening.js
+++ b/erpnext/hr/doctype/job_opening/job_opening.js
@@ -0,0 +1,47 @@
+// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Job Opening', {
+ onload: function(frm) {
+ frm.set_query("department", function() {
+ return {
+ "filters": {
+ "company": frm.doc.company,
+ }
+ };
+ });
+ },
+ designation: function(frm) {
+ if(frm.doc.designation && frm.doc.company){
+ frappe.call({
+ "method": "erpnext.hr.doctype.staffing_plan.staffing_plan.get_active_staffing_plan_and_vacancies",
+ args: {
+ company: frm.doc.company,
+ designation: frm.doc.designation,
+ department: frm.doc.department,
+ date: frappe.datetime.now_date() // ToDo - Date in Job Opening?
+ },
+ callback: function (data) {
+ if(data.message){
+ frm.set_value('staffing_plan', data.message[0]);
+ frm.set_value('planned_vacancies', data.message[1]);
+ } else {
+ frm.set_value('staffing_plan', "");
+ frm.set_value('planned_vacancies', 0);
+ frappe.show_alert({
+ indicator: 'orange',
+ message: __('No Staffing Plans found for this Designation')
+ });
+ }
+ }
+ });
+ }
+ else{
+ frm.set_value('staffing_plan', "");
+ frm.set_value('planned_vacancies', 0);
+ }
+ },
+ company: function(frm) {
+ frm.set_value('designation', "");
+ }
+});
diff --git a/erpnext/hr/doctype/job_opening/job_opening.json b/erpnext/hr/doctype/job_opening/job_opening.json
index de15114a43..79064390d1 100644
--- a/erpnext/hr/doctype/job_opening/job_opening.json
+++ b/erpnext/hr/doctype/job_opening/job_opening.json
@@ -41,7 +41,6 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
"unique": 0
},
{
@@ -73,7 +72,6 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
"unique": 0
},
{
@@ -104,7 +102,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
"unique": 0
},
{
@@ -134,7 +131,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
"unique": 0
},
{
@@ -166,7 +162,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
"unique": 0
},
{
@@ -198,7 +193,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
"unique": 0
},
{
@@ -224,13 +218,43 @@
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
- "read_only": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "depends_on": "staffing_plan",
+ "fieldname": "planned_vacancies",
+ "fieldtype": "Int",
+ "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": "Planned number of Positions",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
"unique": 0
},
{
@@ -260,7 +284,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
"unique": 0
},
{
@@ -291,7 +314,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
"unique": 0
},
{
@@ -323,7 +345,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
"unique": 1
},
{
@@ -354,7 +375,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
"unique": 0
}
],
@@ -369,7 +389,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2018-04-13 18:52:56.109392",
+ "modified": "2018-05-07 14:16:50.300247",
"modified_by": "Administrator",
"module": "HR",
"name": "Job Opening",
@@ -377,6 +397,7 @@
"permissions": [
{
"amend": 0,
+ "apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
@@ -396,6 +417,7 @@
},
{
"amend": 0,
+ "apply_user_permissions": 0,
"cancel": 0,
"create": 0,
"delete": 0,
diff --git a/erpnext/hr/doctype/job_opening/job_opening.py b/erpnext/hr/doctype/job_opening/job_opening.py
index 60c911a016..b579d6f24a 100644
--- a/erpnext/hr/doctype/job_opening/job_opening.py
+++ b/erpnext/hr/doctype/job_opening/job_opening.py
@@ -8,6 +8,7 @@ import frappe
from frappe.website.website_generator import WebsiteGenerator
from frappe import _
+from erpnext.hr.doctype.staffing_plan.staffing_plan import get_current_employee_count, get_active_staffing_plan_and_vacancies
class JobOpening(WebsiteGenerator):
website = frappe._dict(
@@ -19,6 +20,33 @@ class JobOpening(WebsiteGenerator):
def validate(self):
if not self.route:
self.route = frappe.scrub(self.job_title).replace('_', '-')
+ self.validate_current_vacancies()
+
+ def validate_current_vacancies(self):
+ if not self.staffing_plan:
+ vacancies = get_active_staffing_plan_and_vacancies(self.company,
+ self.designation, self.department)
+ if vacancies:
+ self.staffing_plan = vacancies[0]
+ self.planned_vacancies = vacancies[1]
+ elif not self.planned_vacancies:
+ planned_vacancies = frappe.db.sql("""
+ select vacancies from `tabStaffing Plan Detail`
+ where parent=%s and designation=%s""", (self.staffing_plan, self.designation))
+ self.planned_vacancies = planned_vacancies[0][0] if planned_vacancies else None
+
+ if self.staffing_plan and self.planned_vacancies:
+ staffing_plan_company = frappe.db.get_value("Staffing Plan", self.staffing_plan, "company")
+ lft, rgt = frappe.db.get_value("Company", staffing_plan_company, ["lft", "rgt"])
+
+ current_count = get_current_employee_count(self.designation, staffing_plan_company)
+ current_count+= frappe.db.sql("""select count(*) from `tabJob Opening` \
+ where designation=%s and status='Open'
+ and company in (select name from tabCompany where lft>=%s and rgt<=%s)
+ """, (self.designation, lft, rgt))[0][0]
+
+ if self.planned_vacancies <= current_count:
+ frappe.throw(_("Job Openings for designation {0} and company {1} already opened or hiring completed as per Staffing Plan {2}".format(self.designation, staffing_plan_company, self.staffing_plan)))
def get_context(self, context):
context.parents = [{'route': 'jobs', 'title': _('All Jobs') }]
diff --git a/erpnext/hr/doctype/leave_application/leave_application.js b/erpnext/hr/doctype/leave_application/leave_application.js
index 242c987e58..76b5ae54fa 100755
--- a/erpnext/hr/doctype/leave_application/leave_application.js
+++ b/erpnext/hr/doctype/leave_application/leave_application.js
@@ -18,7 +18,7 @@ frappe.ui.form.on("Leave Application", {
doctype: frm.doc.doctype
}
};
- });
+ });
frm.set_query("employee", erpnext.queries.employee);
},
@@ -27,6 +27,33 @@ frappe.ui.form.on("Leave Application", {
frm.toggle_reqd("half_day_date", frm.doc.half_day == 1);
},
+ make_dashboard: function(frm) {
+ var leave_details;
+ if (frm.doc.employee) {
+ frappe.call({
+ method: "erpnext.hr.doctype.leave_application.leave_application.get_leave_details",
+ async: false,
+ args: {
+ employee: frm.doc.employee,
+ date: frm.doc.posting_date
+ },
+ callback: function(r) {
+ if (!r.exc && r.message) {
+ leave_details = r.message;
+ }
+ }
+ });
+
+ $("div").remove(".form-dashboard-section");
+ let section = frm.dashboard.add_section(
+ frappe.render_template('leave_application_dashboard', {
+ data: leave_details
+ })
+ );
+ frm.dashboard.show();
+ }
+ },
+
refresh: function(frm) {
if (frm.is_new()) {
frm.trigger("calculate_total_days");
@@ -43,6 +70,7 @@ frappe.ui.form.on("Leave Application", {
},
employee: function(frm) {
+ frm.trigger("make_dashboard");
frm.trigger("get_leave_balance");
},
diff --git a/erpnext/hr/doctype/leave_application/leave_application.py b/erpnext/hr/doctype/leave_application/leave_application.py
index a46d6fe4d0..fad40684f1 100755
--- a/erpnext/hr/doctype/leave_application/leave_application.py
+++ b/erpnext/hr/doctype/leave_application/leave_application.py
@@ -19,6 +19,7 @@ class NotAnOptionalHoliday(frappe.ValidationError): pass
from frappe.model.document import Document
class LeaveApplication(Document):
+
def get_feed(self):
return _("{0}: From {0} of type {1}").format(self.employee_name, self.leave_type)
@@ -322,6 +323,24 @@ def get_number_of_leave_days(employee, leave_type, from_date, to_date, half_day
number_of_days = flt(number_of_days) - flt(get_holidays(employee, from_date, to_date))
return number_of_days
+@frappe.whitelist()
+def get_leave_details(employee, date):
+ allocation_records = get_leave_allocation_records(date, employee).get(employee, frappe._dict())
+ leave_allocation = {}
+ for d in allocation_records:
+ allocation = allocation_records.get(d, frappe._dict())
+ date = allocation.to_date
+ leaves_taken = get_leaves_for_period(employee, d, allocation.from_date, date, status="Approved")
+ leaves_pending = get_leaves_for_period(employee, d, allocation.from_date, date, status="Open")
+ remaining_leaves = allocation.total_leaves_allocated - leaves_taken - leaves_pending
+ leave_allocation[d] = {
+ "total_leaves": allocation.total_leaves_allocated,
+ "leaves_taken": leaves_taken,
+ "pending_leaves": leaves_pending,
+ "remaining_leaves": remaining_leaves}
+
+ return leave_allocation
+
@frappe.whitelist()
def get_leave_balance_on(employee, leave_type, date, allocation_records=None,
consider_all_leaves_in_the_allocation_period=False):
@@ -332,16 +351,16 @@ def get_leave_balance_on(employee, leave_type, date, allocation_records=None,
if consider_all_leaves_in_the_allocation_period:
date = allocation.to_date
- leaves_taken = get_approved_leaves_for_period(employee, leave_type, allocation.from_date, date)
+ leaves_taken = get_leaves_for_period(employee, leave_type, allocation.from_date, date, status=Approved)
return flt(allocation.total_leaves_allocated) - flt(leaves_taken)
-def get_approved_leaves_for_period(employee, leave_type, from_date, to_date):
+def get_leaves_for_period(employee, leave_type, from_date, to_date, status):
leave_applications = frappe.db.sql("""
select employee, leave_type, from_date, to_date, total_leave_days
from `tabLeave Application`
where employee=%(employee)s and leave_type=%(leave_type)s
- and docstatus=1
+ and status = %(status)s and docstatus=1
and (from_date between %(from_date)s and %(to_date)s
or to_date between %(from_date)s and %(to_date)s
or (from_date < %(from_date)s and to_date > %(to_date)s))
@@ -349,6 +368,7 @@ def get_approved_leaves_for_period(employee, leave_type, from_date, to_date):
"from_date": from_date,
"to_date": to_date,
"employee": employee,
+ "status": status,
"leave_type": leave_type
}, as_dict=1)
diff --git a/erpnext/hr/doctype/leave_application/leave_application_dashboard.html b/erpnext/hr/doctype/leave_application/leave_application_dashboard.html
new file mode 100644
index 0000000000..95e74a671a
--- /dev/null
+++ b/erpnext/hr/doctype/leave_application/leave_application_dashboard.html
@@ -0,0 +1,30 @@
+
+{% if data %}
+ {{ __("Allocated Leaves") }}
+
+
+
+ {{ __("Leave Type") }} |
+ {{ __("Total Allocated Leaves") }} |
+ {{ __("Used Leaves") }} |
+ {{ __("Pending Leaves") }} |
+ {{ __("Available Leaves") }} |
+
+
+
+
+
+ {% for(const [key, value] of Object.entries(data)) { %}
+
+ {%= key %} |
+ {%= value["total_leaves"] %} |
+ {%= value["leaves_taken"] %} |
+ {%= value["pending_leaves"] %} |
+ {%= value["remaining_leaves"] %} |
+
+ {% } %}
+
+
+{% } else { %}
+ No Leaves have been allocated.
+{% } %}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/leave_control_panel/leave_control_panel.js b/erpnext/hr/doctype/leave_control_panel/leave_control_panel.js
index 0eb6414406..7aeb8ea65d 100644
--- a/erpnext/hr/doctype/leave_control_panel/leave_control_panel.js
+++ b/erpnext/hr/doctype/leave_control_panel/leave_control_panel.js
@@ -26,6 +26,19 @@ cur_frm.cscript.allocation_type = function (doc, cdt, cdn) {
refresh_field('no_of_days');
}
-frappe.ui.form.on("Leave Control Panel", "refresh", function (frm) {
- frm.disable_save();
+frappe.ui.form.on("Leave Control Panel", {
+ company: function(frm) {
+ if(frm.doc.company) {
+ frm.set_query("department", function() {
+ return {
+ "filters": {
+ "company": frm.doc.company,
+ }
+ };
+ });
+ }
+ },
+ refresh: function(frm) {
+ frm.disable_save();
+ }
});
\ No newline at end of file
diff --git a/erpnext/hr/doctype/leave_period/leave_period.js b/erpnext/hr/doctype/leave_period/leave_period.js
index 9229f0b89c..19633e26f4 100644
--- a/erpnext/hr/doctype/leave_period/leave_period.js
+++ b/erpnext/hr/doctype/leave_period/leave_period.js
@@ -22,6 +22,15 @@ frappe.ui.form.on('Leave Period', {
},
freeze: true,
freeze_message: __("Grant allocations......")
- });
+ })
+ },
+ onload: (frm) => {
+ frm.set_query("department", function() {
+ return {
+ "filters": {
+ "company": frm.doc.company,
+ }
+ }
+ })
}
});
diff --git a/erpnext/hr/doctype/payroll_entry/payroll_entry.js b/erpnext/hr/doctype/payroll_entry/payroll_entry.js
index 1e6dc510b0..d02e1f1dc3 100644
--- a/erpnext/hr/doctype/payroll_entry/payroll_entry.js
+++ b/erpnext/hr/doctype/payroll_entry/payroll_entry.js
@@ -9,6 +9,14 @@ frappe.ui.form.on('Payroll Entry', {
frm.doc.posting_date = frappe.datetime.nowdate();
}
frm.toggle_reqd(['payroll_frequency'], !frm.doc.salary_slip_based_on_timesheet);
+
+ frm.set_query("department", function() {
+ return {
+ "filters": {
+ "company": frm.doc.company,
+ }
+ };
+ });
},
refresh: function(frm) {
diff --git a/erpnext/hr/doctype/payroll_entry/payroll_entry.py b/erpnext/hr/doctype/payroll_entry/payroll_entry.py
index 1025bc7dae..0dd2b4cb07 100644
--- a/erpnext/hr/doctype/payroll_entry/payroll_entry.py
+++ b/erpnext/hr/doctype/payroll_entry/payroll_entry.py
@@ -38,18 +38,19 @@ class PayrollEntry(Document):
ifnull(salary_slip_based_on_timesheet,0) = %(salary_slip_based_on_timesheet)s
{condition}""".format(condition=condition),
{"company": self.company, "salary_slip_based_on_timesheet":self.salary_slip_based_on_timesheet})
-
if sal_struct:
- cond += "and t2.parent IN %(sal_struct)s "
+ cond += "and t2.salary_structure IN %(sal_struct)s "
+ cond += "and ((%(from_date)s between t2.from_date and ifnull(t2.to_date, '2199-12-31')) or (%(to_date)s between t2.from_date and ifnull(t2.to_date, '2199-12-31')) or (t2.from_date between %(from_date)s and %(to_date)s))"
emp_list = frappe.db.sql("""
select
- t1.name as employee, t1.employee_name, t1.department, t1.designation
+ t1.name as employee, t1.employee_name, t1.department, t1.designation, t2.name
from
- `tabEmployee` t1, `tabSalary Structure Employee` t2
+ `tabEmployee` t1, `tabSalary Structure Assignment` t2
where
t1.docstatus!=2
and t1.name = t2.employee
- %s """% cond, {"sal_struct": sal_struct}, as_dict=True)
+ and t2.docstatus = 1
+ %s """% cond, {"sal_struct": sal_struct, "from_date": self.start_date, "to_date": self.end_date}, as_dict=True)
return emp_list
def fill_employee_details(self):
diff --git a/erpnext/hr/doctype/salary_component/salary_component.json b/erpnext/hr/doctype/salary_component/salary_component.json
index 27b4bef036..f08b1d7a0b 100644
--- a/erpnext/hr/doctype/salary_component/salary_component.json
+++ b/erpnext/hr/doctype/salary_component/salary_component.json
@@ -610,6 +610,634 @@
"set_only_once": 0,
"translatable": 0,
"unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 1,
+ "columns": 0,
+ "fieldname": "condition_and_formula",
+ "fieldtype": "Section Break",
+ "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": "Condition and Formula",
+ "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": "condition",
+ "fieldtype": "Code",
+ "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": "Condition",
+ "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,
+ "description": "If selected, the value specified or calculated in this component will not contribute to the earnings or deductions. However, it's value can be referenced by other components that can be added or deducted. ",
+ "fieldname": "statistical_component",
+ "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": "Statistical Component",
+ "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": "depends_on_lwp",
+ "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": "Depends on Leave Without Pay",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 1,
+ "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": "do_not_include_in_total",
+ "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": "Do not include in total",
+ "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,
+ "default": "1",
+ "fieldname": "amount_based_on_formula",
+ "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": "Amount based on formula",
+ "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,
+ "depends_on": "eval:doc.amount_based_on_formula!==0",
+ "fieldname": "formula",
+ "fieldtype": "Code",
+ "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": "Formula",
+ "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,
+ "depends_on": "eval:doc.amount_based_on_formula!==1",
+ "fieldname": "amount",
+ "fieldtype": "Currency",
+ "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": "Amount",
+ "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": "column_break_28",
+ "fieldtype": "Column Break",
+ "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,
+ "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": "help",
+ "fieldtype": "HTML",
+ "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": "Help",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Help
\n\nNotes:
\n\n\n- Use field
base
for using base salary of the Employee \n- Use Salary Component abbreviations in conditions and formulas.
BS = Basic Salary
\n- Use field name for employee details in conditions and formulas.
Employment Type = employment_type
Branch = branch
\n- Use field name from Salary Slip in conditions and formulas.
Payment Days = payment_days
Leave without pay = leave_without_pay
\n- Direct Amount can also be entered based on Condtion. See example 3
\n\nExamples
\n\n- Calculating Basic Salary based on
base
\nCondition: base < 10000
\nFormula: base * .2
\n- Calculating HRA based on Basic Salary
BS
\nCondition: BS > 2000
\nFormula: BS * .1
\n- Calculating TDS based on Employment Type
employment_type
\nCondition: employment_type==\"Intern\"
\nAmount: 1000
\n
",
+ "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": 1,
+ "columns": 0,
+ "fieldname": "condition_and_formula",
+ "fieldtype": "Section Break",
+ "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": "Condition and Formula",
+ "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": "condition",
+ "fieldtype": "Code",
+ "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": "Condition",
+ "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,
+ "description": "If selected, the value specified or calculated in this component will not contribute to the earnings or deductions. However, it's value can be referenced by other components that can be added or deducted. ",
+ "fieldname": "statistical_component",
+ "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": "Statistical Component",
+ "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": "depends_on_lwp",
+ "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": "Depends on Leave Without Pay",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 1,
+ "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": "do_not_include_in_total",
+ "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": "Do not include in total",
+ "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,
+ "default": "1",
+ "fieldname": "amount_based_on_formula",
+ "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": "Amount based on formula",
+ "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,
+ "depends_on": "eval:doc.amount_based_on_formula!==0",
+ "fieldname": "formula",
+ "fieldtype": "Code",
+ "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": "Formula",
+ "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,
+ "depends_on": "eval:doc.amount_based_on_formula!==1",
+ "fieldname": "amount",
+ "fieldtype": "Currency",
+ "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": "Amount",
+ "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": "column_break_28",
+ "fieldtype": "Column Break",
+ "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,
+ "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": "help",
+ "fieldtype": "HTML",
+ "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": "Help",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Help
\n\nNotes:
\n\n\n- Use field
base
for using base salary of the Employee \n- Use Salary Component abbreviations in conditions and formulas.
BS = Basic Salary
\n- Use field name for employee details in conditions and formulas.
Employment Type = employment_type
Branch = branch
\n- Use field name from Salary Slip in conditions and formulas.
Payment Days = payment_days
Leave without pay = leave_without_pay
\n- Direct Amount can also be entered based on Condtion. See example 3
\n\nExamples
\n\n- Calculating Basic Salary based on
base
\nCondition: base < 10000
\nFormula: base * .2
\n- Calculating HRA based on Basic Salary
BS
\nCondition: BS > 2000
\nFormula: BS * .1
\n- Calculating TDS based on Employment Type
employment_type
\nCondition: employment_type==\"Intern\"
\nAmount: 1000
\n
",
+ "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
}
],
"has_web_view": 0,
@@ -623,7 +1251,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2018-04-27 13:23:34.503504",
+ "modified": "2018-05-09 17:35:11.073733",
"modified_by": "Administrator",
"module": "HR",
"name": "Salary Component",
@@ -658,4 +1286,4 @@
"sort_order": "DESC",
"track_changes": 0,
"track_seen": 0
-}
\ No newline at end of file
+}
diff --git a/erpnext/hr/doctype/salary_slip/salary_slip.py b/erpnext/hr/doctype/salary_slip/salary_slip.py
index 75eb73b532..984a78c75f 100644
--- a/erpnext/hr/doctype/salary_slip/salary_slip.py
+++ b/erpnext/hr/doctype/salary_slip/salary_slip.py
@@ -12,6 +12,7 @@ from erpnext.hr.doctype.payroll_entry.payroll_entry import get_start_end_dates
from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee
from erpnext.utilities.transaction_base import TransactionBase
from frappe.utils.background_jobs import enqueue
+from erpnext.hr.doctype.additional_salary_component.additional_salary_component import get_additional_salary_component
class SalarySlip(TransactionBase):
def autoname(self):
@@ -58,6 +59,12 @@ class SalarySlip(TransactionBase):
if amount and struct_row.statistical_component == 0:
self.update_component_row(struct_row, amount, key)
+ additional_components = get_additional_salary_component(self.employee, self.start_date, self.end_date)
+ if additional_components:
+ for additional_component in additional_components:
+ additional_component = frappe._dict(additional_component)
+ self.update_component_row(frappe._dict(additional_component.struct_row), additional_component.amount, "earnings")
+
def update_component_row(self, struct_row, amount, key):
component_row = None
for d in self.get(key):
@@ -104,8 +111,8 @@ class SalarySlip(TransactionBase):
'''Returns data for evaluating formula'''
data = frappe._dict()
- data.update(frappe.get_doc("Salary Structure Employee",
- {"employee": self.employee, "parent": self.salary_structure}).as_dict())
+ data.update(frappe.get_doc("Salary Structure Assignment",
+ {"employee": self.employee, "salary_structure": self.salary_structure}).as_dict())
data.update(frappe.get_doc("Employee", self.employee).as_dict())
data.update(self.as_dict())
@@ -166,10 +173,10 @@ class SalarySlip(TransactionBase):
if self.payroll_frequency:
cond = """and payroll_frequency = '%(payroll_frequency)s'""" % {"payroll_frequency": self.payroll_frequency}
- st_name = frappe.db.sql("""select parent from `tabSalary Structure Employee`
+ st_name = frappe.db.sql("""select salary_structure from `tabSalary Structure Assignment`
where employee=%s and (from_date <= %s or from_date <= %s)
and (to_date is null or to_date >= %s or to_date >= %s)
- and parent in (select name from `tabSalary Structure`
+ and salary_structure in (select name from `tabSalary Structure`
where is_active = 'Yes'%s)
"""% ('%s', '%s', '%s','%s','%s', cond),(self.employee, self.start_date, joining_date, self.end_date, relieving_date))
@@ -327,7 +334,7 @@ class SalarySlip(TransactionBase):
def sum_components(self, component_type, total_field):
joining_date, relieving_date = frappe.db.get_value("Employee", self.employee,
["date_of_joining", "relieving_date"])
-
+
if not relieving_date:
relieving_date = getdate(self.end_date)
@@ -463,4 +470,4 @@ def unlink_ref_doc_from_salary_slip(ref_no):
if linked_ss:
for ss in linked_ss:
ss_doc = frappe.get_doc("Salary Slip", ss)
- frappe.db.set_value("Salary Slip", ss_doc.name, "journal_entry", "")
\ No newline at end of file
+ frappe.db.set_value("Salary Slip", ss_doc.name, "journal_entry", "")
diff --git a/erpnext/hr/doctype/salary_slip/test_salary_slip.py b/erpnext/hr/doctype/salary_slip/test_salary_slip.py
index cced29d7d9..ae58298bff 100644
--- a/erpnext/hr/doctype/salary_slip/test_salary_slip.py
+++ b/erpnext/hr/doctype/salary_slip/test_salary_slip.py
@@ -7,6 +7,7 @@ import frappe
import erpnext
import calendar
from erpnext.accounts.utils import get_fiscal_year
+from frappe.utils.make_random import get_random
from frappe.utils import getdate, nowdate, add_days, add_months, flt
from erpnext.hr.doctype.salary_structure.salary_structure import make_salary_slip
from erpnext.hr.doctype.payroll_entry.test_payroll_entry import get_salary_component_account
@@ -272,33 +273,31 @@ def make_salary_structure(sal_struct, payroll_frequency, employee):
frappe.get_doc({
"doctype": "Salary Structure",
"name": sal_struct,
- "company": erpnext.get_default_company(),
- "employees": get_employee_details(employee),
+ "company": "_Test Company",
"earnings": get_earnings_component(),
"deductions": get_deductions_component(),
"payroll_frequency": payroll_frequency,
- "payment_account": frappe.get_value('Account', {'account_type': 'Cash', 'company': erpnext.get_default_company(),'is_group':0}, "name")
+ "payment_account": get_random("Account")
}).insert()
- elif not frappe.db.get_value("Salary Structure Employee",{'parent':sal_struct, 'employee':employee},'name'):
+ create_salary_structure_assignment(employee, sal_struct)
+
+ elif not frappe.db.get_value("Salary Structure Assignment",{'salary_structure':sal_struct, 'employee':employee},'name'):
sal_struct = frappe.get_doc("Salary Structure", sal_struct)
- sal_struct.append("employees", {"employee": employee,
- "employee_name": employee,
- "base": 32000,
- "variable": 3200,
- "from_date": add_months(nowdate(),-1)
- })
- sal_struct.save()
+ create_salary_structure_assignment(employee, sal_struct)
sal_struct = sal_struct.name
return sal_struct
-def get_employee_details(employee):
- return [{"employee": employee,
- "base": 50000,
- "variable": 5000,
- "from_date": add_months(nowdate(),-1)
- }
- ]
+def create_salary_structure_assignment(employee, salary_structure):
+ salary_structure_assignment = frappe.new_doc("Salary Structure Assignment")
+ salary_structure_assignment.employee = employee
+ salary_structure_assignment.base = 50000
+ salary_structure_assignment.variable = 5000
+ salary_structure_assignment.from_date = add_months(nowdate(), -1)
+ salary_structure_assignment.salary_structure = salary_structure
+ salary_structure_assignment.company = erpnext.get_default_company()
+ salary_structure_assignment.save(ignore_permissions=True)
+ return salary_structure_assignment
def get_earnings_component():
return [
@@ -353,4 +352,4 @@ def get_deductions_component():
"formula": 'base*.1',
"idx": 3
}
- ]
\ No newline at end of file
+ ]
diff --git a/erpnext/hr/doctype/salary_structure/salary_structure.js b/erpnext/hr/doctype/salary_structure/salary_structure.js
index 8e5f8e651f..6f5c923a35 100755
--- a/erpnext/hr/doctype/salary_structure/salary_structure.js
+++ b/erpnext/hr/doctype/salary_structure/salary_structure.js
@@ -47,8 +47,18 @@ frappe.ui.form.on('Salary Structure', {
frm.fields_dict['earnings'].grid.set_column_disp("default_amount", false);
frm.fields_dict['deductions'].grid.set_column_disp("default_amount", false);
- frm.add_custom_button(__("Preview Salary Slip"),
- function() { frm.trigger('preview_salary_slip'); }, "fa fa-sitemap", "btn-default");
+ frm.add_custom_button(__("Preview Salary Slip"), function() {
+ frm.trigger('preview_salary_slip');
+ });
+
+ if(frm.doc.docstatus==1) {
+ frm.add_custom_button(__("Assign Salary Structure"), function() {
+ var doc = frappe.model.get_new_doc('Salary Structure Assignment');
+ doc.salary_structure = frm.doc.name;
+ doc.company = frm.doc.company;
+ frappe.set_route('Form', 'Salary Structure Assignment', doc.name);
+ });
+ }
},
salary_slip_based_on_timesheet: function(frm) {
@@ -155,5 +165,46 @@ frappe.ui.form.on('Salary Detail', {
deductions_remove: function(frm) {
calculate_totals(frm.doc);
+ },
+
+ salary_component: function(frm, cdt, cdn) {
+ var child = locals[cdt][cdn];
+ if(child.salary_component){
+ frappe.call({
+ method: "frappe.client.get",
+ args: {
+ doctype: "Salary Component",
+ name: child.salary_component
+ },
+ callback: function(data) {
+ if(data.message){
+ var result = data.message;
+ frappe.model.set_value(cdt, cdn, 'condition',result.condition);
+ frappe.model.set_value(cdt, cdn, 'amount_based_on_formula',result.amount_based_on_formula);
+ if(result.amount_based_on_formula == 1){
+ frappe.model.set_value(cdt, cdn, 'formula',result.formula);
+ }
+ else{
+ frappe.model.set_value(cdt, cdn, 'amount',result.amount);
+ }
+ frappe.model.set_value(cdt, cdn, 'statistical_component',result.statistical_component);
+ frappe.model.set_value(cdt, cdn, 'depends_on_lwp',result.depends_on_lwp);
+ frappe.model.set_value(cdt, cdn, 'do_not_include_in_total',result.do_not_include_in_total);
+ refresh_field("earnings");
+ refresh_field("deductions");
+ }
+ }
+ });
+ }
+ },
+
+ amount_based_on_formula: function(frm, cdt, cdn) {
+ var child = locals[cdt][cdn];
+ if(child.amount_based_on_formula == 1){
+ frappe.model.set_value(cdt, cdn, 'amount', null);
+ }
+ else{
+ frappe.model.set_value(cdt, cdn, 'formula', null);
+ }
}
})
diff --git a/erpnext/hr/doctype/salary_structure_assignment/salary_structure_assignment.js b/erpnext/hr/doctype/salary_structure_assignment/salary_structure_assignment.js
index e7c6598653..56a05e0495 100644
--- a/erpnext/hr/doctype/salary_structure_assignment/salary_structure_assignment.js
+++ b/erpnext/hr/doctype/salary_structure_assignment/salary_structure_assignment.js
@@ -11,9 +11,36 @@ frappe.ui.form.on('Salary Structure Assignment', {
}
}
});
+ frm.set_query("salary_structure", function() {
+ return {
+ filters: {
+ company: frm.doc.company,
+ docstatus: 1,
+ is_active: "Yes"
+ }
+ }
+ });
},
-
- refresh: function(frm) {
-
+ employee: function(frm) {
+ if(frm.doc.employee){
+ frappe.call({
+ method: "frappe.client.get_value",
+ args:{
+ doctype: "Employee",
+ fieldname: "company",
+ filters:{
+ name: frm.doc.employee
+ }
+ },
+ callback: function(data) {
+ if(data.message){
+ frm.set_value("company", data.message.company);
+ }
+ }
+ });
+ }
+ else{
+ frm.set_value("company", null);
+ }
}
});
diff --git a/erpnext/hr/doctype/salary_structure_assignment/salary_structure_assignment.py b/erpnext/hr/doctype/salary_structure_assignment/salary_structure_assignment.py
index c9269d7c92..ee2920be2c 100644
--- a/erpnext/hr/doctype/salary_structure_assignment/salary_structure_assignment.py
+++ b/erpnext/hr/doctype/salary_structure_assignment/salary_structure_assignment.py
@@ -11,6 +11,7 @@ from frappe.model.document import Document
class SalaryStructureAssignment(Document):
def validate(self):
self.validate_dates()
+ self.validate_duplicate_assignments()
def validate_dates(self):
joining_date, relieving_date = frappe.db.get_value("Employee", self.employee,
@@ -33,10 +34,14 @@ class SalaryStructureAssignment(Document):
.format(self.to_date, relieving_date))
def validate_duplicate_assignments(self):
+ if not self.name:
+ # hack! if name is null, it could cause problems with !=
+ self.name = "New "+self.doctype
assignment = frappe.db.sql("""
select name from `tabSalary Structure Assignment`
where employee=%(employee)s
- and name != %(salary_struct)s
+ and name != %(name)s
+ and docstatus != 2
and (
(%(from_date)s between from_date and ifnull(to_date, '2199-12-31'))
or (%(to_date)s between from_date and ifnull(to_date, '2199-12-31'))
@@ -45,8 +50,8 @@ class SalaryStructureAssignment(Document):
'employee': self.employee,
'from_date': self.from_date,
'to_date': (self.to_date or '2199-12-31'),
- 'salary_struct': self.salary_struct
+ 'name': self.name
})
if assignment:
- frappe.throw(_("Active Salary Structure Assignment {0} found for employee {1} for the given dates").format(assignment[0][0], self.employee))
\ No newline at end of file
+ frappe.throw(_("Active Salary Structure Assignment {0} found for employee {1} for the given dates").format(assignment[0][0], self.employee))
diff --git a/erpnext/hr/doctype/shift_request/test_shift_request.py b/erpnext/hr/doctype/shift_request/test_shift_request.py
index 0b8bcb811c..d32443a952 100644
--- a/erpnext/hr/doctype/shift_request/test_shift_request.py
+++ b/erpnext/hr/doctype/shift_request/test_shift_request.py
@@ -5,6 +5,24 @@ from __future__ import unicode_literals
import frappe
import unittest
+from frappe.utils import nowdate
class TestShiftRequest(unittest.TestCase):
- pass
+ def test_make_shift_request(self):
+ shift_request = frappe.get_doc({
+ "doctype": "Shift Request",
+ "shift_type": "Day Shift",
+ "company": "_Test Company",
+ "employee": "_T-Employee-00001",
+ "employee_name": "_Test Employee",
+ "start_date": nowdate(),
+ "end_date": nowdate()
+ })
+ shift_request.insert()
+ shift_request.submit()
+ shift_assignment = frappe.db.sql("""select employee
+ from `tabShift Assignment`
+ where shift_request = %s""", shift_request.name)
+ if shift_assignment:
+ employee = shift_assignment[0][0]
+ self.assertEqual(shift_request.employee, employee)
\ No newline at end of file
diff --git a/erpnext/hr/doctype/shift_type/test_shift_type.py b/erpnext/hr/doctype/shift_type/test_shift_type.py
index bc4f0eafcd..d5afdf519b 100644
--- a/erpnext/hr/doctype/shift_type/test_shift_type.py
+++ b/erpnext/hr/doctype/shift_type/test_shift_type.py
@@ -7,4 +7,11 @@ import frappe
import unittest
class TestShiftType(unittest.TestCase):
- pass
+ def test_make_shift_type(self):
+ shift_type = frappe.get_doc({
+ "doctype": "Shift Type",
+ "name": "Day Shift",
+ "start_time": "9:00:00",
+ "end_time": "18:00:00"
+ })
+ shift_type.insert()
diff --git a/erpnext/hr/doctype/staffing_plan/staffing_plan.js b/erpnext/hr/doctype/staffing_plan/staffing_plan.js
index 3cadfc56c5..ca57d9f19d 100644
--- a/erpnext/hr/doctype/staffing_plan/staffing_plan.js
+++ b/erpnext/hr/doctype/staffing_plan/staffing_plan.js
@@ -2,7 +2,100 @@
// For license information, please see license.txt
frappe.ui.form.on('Staffing Plan', {
- refresh: function(frm) {
+ setup: function(frm) {
+ frm.set_query("designation", "staffing_details", function() {
+ let designations = [];
+ $.each(frm.doc.staffing_details, function(index, staff_detail) {
+ if(staff_detail.designation){
+ designations.push(staff_detail.designation)
+ }
+ })
+ // Filter out designations already selected in Staffing Plan Detail
+ return {
+ filters: [
+ ['Designation', 'name', 'not in', designations],
+ ]
+ }
+ });
+ frm.set_query("department", function() {
+ return {
+ "filters": {
+ "company": frm.doc.company,
+ }
+ };
+ });
}
});
+
+frappe.ui.form.on('Staffing Plan Detail', {
+ designation: function(frm, cdt, cdn) {
+ let child = locals[cdt][cdn]
+ if(frm.doc.company && child.designation){
+ frappe.call({
+ "method": "erpnext.hr.doctype.staffing_plan.staffing_plan.get_current_employee_count",
+ args: {
+ designation: child.designation,
+ company: frm.doc.company
+ },
+ callback: function (data) {
+ if(data.message){
+ frappe.model.set_value(cdt, cdn, 'current_count', data.message);
+ }
+ else{ // No employees for this designation
+ frappe.model.set_value(cdt, cdn, 'current_count', 0);
+ }
+ }
+ });
+ }
+ },
+
+ number_of_positions: function(frm, cdt, cdn) {
+ set_vacancies(frm, cdt, cdn);
+ },
+
+ current_count: function(frm, cdt, cdn) {
+ set_vacancies(frm, cdt, cdn);
+ },
+
+ estimated_cost_per_position: function(frm, cdt, cdn) {
+ let child = locals[cdt][cdn];
+ set_total_estimated_cost(frm, cdt, cdn);
+ }
+
+});
+
+var set_vacancies = function(frm, cdt, cdn) {
+ let child = locals[cdt][cdn]
+ if(child.number_of_positions) {
+ frappe.model.set_value(cdt, cdn, 'vacancies', child.number_of_positions - child.current_count);
+ }
+ else{
+ frappe.model.set_value(cdt, cdn, 'vacancies', 0);
+ }
+ set_total_estimated_cost(frm, cdt, cdn);
+}
+
+// Note: Estimated Cost is calculated on number of Vacancies
+var set_total_estimated_cost = function(frm, cdt, cdn) {
+ let child = locals[cdt][cdn]
+ if(child.number_of_positions && child.estimated_cost_per_position) {
+ frappe.model.set_value(cdt, cdn, 'total_estimated_cost', child.vacancies * child.estimated_cost_per_position);
+ }
+ else {
+ frappe.model.set_value(cdt, cdn, 'total_estimated_cost', 0);
+ }
+ set_total_estimated_budget(frm);
+};
+
+var set_total_estimated_budget = function(frm) {
+ let estimated_budget = 0.0
+ if(frm.doc.staffing_details) {
+ $.each(frm.doc.staffing_details, function(index, staff_detail) {
+ if(staff_detail.total_estimated_cost){
+ estimated_budget += staff_detail.total_estimated_cost
+ }
+ })
+ frm.set_value('total_estimated_budget', estimated_budget);
+ }
+}
diff --git a/erpnext/hr/doctype/staffing_plan/staffing_plan.json b/erpnext/hr/doctype/staffing_plan/staffing_plan.json
index a5d26e6d4f..229cc05ddd 100644
--- a/erpnext/hr/doctype/staffing_plan/staffing_plan.json
+++ b/erpnext/hr/doctype/staffing_plan/staffing_plan.json
@@ -268,6 +268,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "default": "0.00",
"fieldname": "total_estimated_budget",
"fieldtype": "Currency",
"hidden": 0,
@@ -284,7 +285,7 @@
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
- "read_only": 0,
+ "read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
@@ -335,7 +336,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2018-04-13 18:45:16.729979",
+ "modified": "2018-04-18 19:10:34.394249",
"modified_by": "Administrator",
"module": "HR",
"name": "Staffing Plan",
diff --git a/erpnext/hr/doctype/staffing_plan/staffing_plan.py b/erpnext/hr/doctype/staffing_plan/staffing_plan.py
index 510d2dcc49..37ff5cbc90 100644
--- a/erpnext/hr/doctype/staffing_plan/staffing_plan.py
+++ b/erpnext/hr/doctype/staffing_plan/staffing_plan.py
@@ -5,6 +5,62 @@
from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
+from frappe import _
+from frappe.utils import getdate, nowdate
class StaffingPlan(Document):
- pass
+ def validate(self):
+ # Validate Dates
+ if self.from_date and self.to_date and self.from_date > self.to_date:
+ frappe.throw(_("From Date cannot be greater than To Date"))
+
+ # Validate if any submitted Staffing Plan exist for Designations in this plan
+ # and spd.vacancies>0 ?
+ for detail in self.get("staffing_details"):
+ overlap = (frappe.db.sql("""select spd.parent \
+ from `tabStaffing Plan Detail` spd join `tabStaffing Plan` sp on spd.parent=sp.name \
+ where spd.designation='{0}' and sp.docstatus=1 \
+ and sp.to_date >= '{1}' and sp.from_date <='{2}'"""
+ .format(detail.designation, self.from_date, self.to_date)))
+
+ if overlap and overlap [0][0]:
+ frappe.throw(_("Staffing Plan {0} already exist for designation {1}"
+ .format(overlap[0][0], detail.designation)))
+
+@frappe.whitelist()
+def get_current_employee_count(designation, company):
+ if not designation:
+ return False
+
+ lft, rgt = frappe.db.get_value("Company", company, ["lft", "rgt"])
+ employee_count = frappe.db.sql("""select count(*) from `tabEmployee`
+ where designation = %s and status='Active'
+ and company in (select name from tabCompany where lft>=%s and rgt<=%s)
+ """, (designation, lft, rgt))[0][0]
+ return employee_count
+
+def get_active_staffing_plan_and_vacancies(company, designation, department=None, date=getdate(nowdate())):
+ if not company or not designation:
+ frappe.throw(_("Please select Company and Designation"))
+
+ conditions = ""
+ if(department): #Department is an optional field
+ conditions += " and sp.department='{0}'".format(frappe.db.escape(department))
+
+ if(date): #ToDo: Date should be mandatory?
+ conditions += " and '{0}' between sp.from_date and sp.to_date".format(date)
+
+ staffing_plan = frappe.db.sql("""
+ select sp.name, spd.vacancies
+ from `tabStaffing Plan Detail` spd join `tabStaffing Plan` sp on spd.parent=sp.name
+ where company=%s and spd.designation=%s and sp.docstatus=1 {0}
+ """.format(conditions), (company, designation))
+
+ if not staffing_plan:
+ parent_company = frappe.db.get_value("Company", company, "parent_company")
+ if parent_company:
+ staffing_plan = get_active_staffing_plan_and_vacancies(parent_company,
+ designation, department, date)
+
+ # Only a signle staffing plan can be active for a designation on given date
+ return staffing_plan[0] if staffing_plan else None
diff --git a/erpnext/hr/doctype/staffing_plan_detail/staffing_plan_detail.json b/erpnext/hr/doctype/staffing_plan_detail/staffing_plan_detail.json
index 7c395647be..eb77b43914 100644
--- a/erpnext/hr/doctype/staffing_plan_detail/staffing_plan_detail.json
+++ b/erpnext/hr/doctype/staffing_plan_detail/staffing_plan_detail.json
@@ -75,68 +75,6 @@
"translatable": 0,
"unique": 0
},
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "current_count",
- "fieldtype": "Int",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Current Count",
- "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": "vacancies",
- "fieldtype": "Int",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Vacancies",
- "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,
@@ -190,6 +128,36 @@
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
+ "read_only": 1,
+ "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": "column_break_5",
+ "fieldtype": "Column Break",
+ "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,
+ "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,
@@ -198,6 +166,68 @@
"set_only_once": 0,
"translatable": 0,
"unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "current_count",
+ "fieldtype": "Int",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Current Count",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "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": "vacancies",
+ "fieldtype": "Int",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Vacancies",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
}
],
"has_web_view": 0,
@@ -210,7 +240,7 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
- "modified": "2018-04-13 18:39:52.783341",
+ "modified": "2018-04-15 16:09:12.622186",
"modified_by": "Administrator",
"module": "HR",
"name": "Staffing Plan Detail",
diff --git a/erpnext/hr/utils.py b/erpnext/hr/utils.py
index 826e09b1b9..5c64b2ef2c 100644
--- a/erpnext/hr/utils.py
+++ b/erpnext/hr/utils.py
@@ -5,11 +5,99 @@ from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.utils import formatdate, format_datetime, getdate, get_datetime, nowdate
+from frappe.model.document import Document
+from frappe.desk.form import assign_to
+
+class EmployeeBoardingController(Document):
+ '''
+ Create the project and the task for the boarding process
+ Assign to the concerned person and roles as per the onboarding/separation template
+ '''
+ def validate(self):
+ # remove the task if linked before submitting the form
+ if self.amended_from:
+ for activity in self.activities:
+ activity.task = ''
+
+ def on_submit(self):
+ # create the project for the given employee onboarding
+ project_name = _(self.doctype) + " : " + self.employee_name
+ if self.doctype == "Employee Onboarding":
+ project_name += " (" + self.job_applicant + ")"
+ else:
+ project_name += " (" + self.employee + ")"
+ project = frappe.get_doc({
+ "doctype": "Project",
+ "project_name": project_name,
+ "expected_start_date": self.date_of_joining if self.doctype == "Employee Onboarding" else self.resignation_letter_date,
+ "department": self.department,
+ "company": self.company
+ }).insert(ignore_permissions=True)
+ self.db_set("project", project.name)
+
+ # create the task for the given project and assign to the concerned person
+ for activity in self.activities:
+ task = frappe.get_doc({
+ "doctype": "Task",
+ "project": project.name,
+ "subject": activity.activity_name + " : " + self.employee_name,
+ "description": activity.description,
+ "department": self.department,
+ "company": self.company
+ }).insert(ignore_permissions=True)
+ activity.db_set("task", task.name)
+ users = [activity.user] if activity.user else []
+ if activity.role:
+ user_list = frappe.db.sql_list('''select distinct(parent) from `tabHas Role`
+ where parenttype='User' and role=%s''', activity.role)
+ users = users + user_list
+
+ # assign the task the users
+ if users:
+ self.assign_task_to_users(task, set(users))
+
+ def assign_task_to_users(self, task, users):
+ for user in users:
+ args = {
+ 'assign_to' : user,
+ 'doctype' : task.doctype,
+ 'name' : task.name,
+ 'description' : task.description or task.subject,
+ }
+ assign_to.add(args)
+
+ def on_cancel(self):
+ # delete task project
+ for task in frappe.get_all("Task", filters={"project": self.project}):
+ frappe.delete_doc("Task", task.name)
+ frappe.delete_doc("Project", self.project)
+ self.db_set('project', '')
+ for activity in self.activities:
+ activity.db_set("task", "")
+
+
+@frappe.whitelist()
+def get_onboarding_details(parent, parenttype):
+ return frappe.get_list("Employee Boarding Activity",
+ fields=["activity_name", "role", "user", "required_for_employee_creation", "description"],
+ filters={"parent": parent, "parenttype": parenttype},
+ order_by= "idx")
def set_employee_name(doc):
if doc.employee and not doc.employee_name:
doc.employee_name = frappe.db.get_value("Employee", doc.employee, "employee_name")
+def update_employee(employee, details, cancel=False):
+ for item in details:
+ fieldtype = frappe.get_meta("Employee").get_field(item.fieldname).fieldtype
+ new_data = item.new if not cancel else item.current
+ if fieldtype == "Date" and new_data:
+ new_data = getdate(new_data)
+ elif fieldtype =="Datetime" and new_data:
+ new_data = get_datetime(new_data)
+ setattr(employee, item.fieldname, new_data)
+ return employee
+
@frappe.whitelist()
def get_employee_fields_label():
fields = []
@@ -117,6 +205,19 @@ def get_employee_leave_policy(employee):
if leave_policy:
return frappe.get_doc("Leave Policy", leave_policy)
+def validate_tax_declaration(declarations):
+ subcategories = []
+ for declaration in declarations:
+ if declaration.exemption_sub_category in subcategories:
+ frappe.throw(_("More than one selection for {0} not \
+ allowed").format(declaration.exemption_sub_category), frappe.ValidationError)
+ subcategories.append(declaration.exemption_sub_category)
+ max_amount = frappe.db.get_value("Employee Tax Exemption Sub Category", \
+ declaration.exemption_sub_category, "max_amount")
+ if declaration.amount > max_amount:
+ frappe.throw(_("Max exemption amount for {0} is {1}").format(\
+ declaration.exemption_sub_category, max_amount), frappe.ValidationError)
+
def get_leave_period(from_date, to_date, company):
leave_period = frappe.db.sql("""
select name, from_date, to_date
diff --git a/erpnext/hub_node/__init__.py b/erpnext/hub_node/__init__.py
index 89ee926d55..65b1386466 100644
--- a/erpnext/hub_node/__init__.py
+++ b/erpnext/hub_node/__init__.py
@@ -187,7 +187,7 @@ def make_supplier(supplier):
supplier_doc = frappe.get_doc({
'doctype': 'Supplier',
'supplier_name': supplier.supplier_name,
- 'supplier_type': supplier.supplier_type,
+ 'supplier_group': supplier.supplier_group,
'supplier_email': supplier.supplier_email
}).insert()
else:
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 3fffade9bb..70f4ecd71e 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -527,3 +527,7 @@ erpnext.patches.v11_0.rename_field_max_days_allowed
erpnext.patches.v11_0.create_salary_structure_assignments
erpnext.patches.v11_0.rename_health_insurance
erpnext.patches.v11_0.rebuild_tree_for_company
+erpnext.patches.v11_0.rename_supplier_type_to_supplier_group
+erpnext.patches.v11_0.create_department_records_for_each_company
+erpnext.patches.v11_0.make_location_from_warehouse
+erpnext.patches.v11_0.make_asset_finance_book_against_old_entries
diff --git a/erpnext/patches/v11_0/create_department_records_for_each_company.py b/erpnext/patches/v11_0/create_department_records_for_each_company.py
new file mode 100644
index 0000000000..94071857d7
--- /dev/null
+++ b/erpnext/patches/v11_0/create_department_records_for_each_company.py
@@ -0,0 +1,73 @@
+import frappe
+from frappe.utils.nestedset import rebuild_tree
+
+def execute():
+ frappe.reload_doc("hr", "doctype", "department")
+ companies = frappe.db.get_all("Company", fields=["name", "abbr"])
+ departments = frappe.db.get_all("Department")
+ comp_dict = {}
+
+ # create a blank list for each company
+ for company in companies:
+ comp_dict[company.name] = {}
+
+ for department in departments:
+ # skip root node
+ if department.name == "All Departments":
+ continue
+
+ # for each company, create a copy of the doc
+ department_doc = frappe.get_doc("Department", department)
+ for company in companies:
+ copy_doc = frappe.copy_doc(department_doc)
+ copy_doc.update({"company": company.name})
+ copy_doc.insert()
+
+ # append list of new department for each company
+ comp_dict[company.name][department.name] = copy_doc.name
+
+ rebuild_tree('Department', 'parent_department')
+ doctypes = ["Asset", "Employee", "Leave Period", "Payroll Entry", "Staffing Plan", "Job Opening"]
+
+ for d in doctypes:
+ update_records(d, comp_dict)
+
+ update_instructors(comp_dict)
+
+def update_records(doctype, comp_dict):
+ when_then = []
+ for company in comp_dict:
+ records = comp_dict[company]
+
+ for department in records:
+ when_then.append('''
+ WHEN company = "%s" and department = "%s"
+ THEN "%s"
+ '''%(company, department, records[department]))
+
+ frappe.db.sql("""
+ update
+ `tab%s`
+ set
+ department = CASE %s END
+ """%(doctype, " ".join(when_then)))
+
+def update_instructors(comp_dict):
+ when_then = []
+ emp_details = frappe.get_all("Employee", fields=["name", "company"])
+
+ for employee in emp_details:
+ records = comp_dict[employee.company]
+
+ for department in records:
+ when_then.append('''
+ WHEN employee = "%s" and department = "%s"
+ THEN "%s"
+ '''%(employee.name, department, records[department]))
+
+ frappe.db.sql("""
+ update
+ `tabInstructor`
+ set
+ department = CASE %s END
+ """%(" ".join(when_then)))
diff --git a/erpnext/patches/v11_0/make_asset_finance_book_against_old_entries.py b/erpnext/patches/v11_0/make_asset_finance_book_against_old_entries.py
new file mode 100644
index 0000000000..18622f2301
--- /dev/null
+++ b/erpnext/patches/v11_0/make_asset_finance_book_against_old_entries.py
@@ -0,0 +1,47 @@
+# Copyright (c) 2017, Frappe and Contributors
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe.utils.nestedset import rebuild_tree
+
+def execute():
+ frappe.reload_doc('assets', 'doctype', 'asset_finance_book')
+ frappe.reload_doc('assets', 'doctype', 'depreciation_schedule')
+ frappe.reload_doc('assets', 'doctype', 'asset_category')
+ frappe.reload_doc('assets', 'doctype', 'asset')
+ frappe.reload_doc('assets', 'doctype', 'asset_movement')
+
+ frappe.db.sql(""" update `tabAsset` ast, `tabWarehouse` wh
+ set ast.location = wh.warehouse_name where ast.warehouse = wh.name""")
+
+ frappe.db.sql(""" update `tabAsset Movement` ast_mv
+ set ast_mv.source_location = (select warehouse_name from `tabWarehouse` where name = ast_mv.source_warehouse),
+ ast_mv.target_location = (select warehouse_name from `tabWarehouse` where name = ast_mv.target_warehouse)""")
+
+ for d in frappe.get_all('Asset'):
+ doc = frappe.get_doc('Asset', d.name)
+ if doc.calculate_depreciation:
+ fb = doc.append('finance_books', {
+ 'depreciation_method': doc.depreciation_method,
+ 'total_number_of_depreciations': doc.total_number_of_depreciations,
+ 'frequency_of_depreciation': doc.frequency_of_depreciation,
+ 'depreciation_start_date': doc.next_depreciation_date,
+ 'expected_value_after_useful_life': doc.expected_value_after_useful_life,
+ 'value_after_depreciation': doc.value_after_depreciation
+ })
+
+ fb.db_update()
+
+ frappe.db.sql(""" update `tabDepreciation Schedule` ds, `tabAsset` ast
+ set ds.depreciation_method = ast.depreciation_method, ds.finance_book_id = 1 where ds.parent = ast.name """)
+
+ for catergory in frappe.get_all('Asset Category'):
+ asset_category_doc = frappe.get_doc("Asset Category", catergory)
+ row = asset_category_doc.append('finance_books', {
+ 'depreciation_method': asset_category_doc.depreciation_method,
+ 'total_number_of_depreciations': asset_category_doc.total_number_of_depreciations,
+ 'frequency_of_depreciation': asset_category_doc.frequency_of_depreciation
+ })
+
+ row.db_update()
\ No newline at end of file
diff --git a/erpnext/patches/v11_0/make_location_from_warehouse.py b/erpnext/patches/v11_0/make_location_from_warehouse.py
new file mode 100644
index 0000000000..b838ec98bc
--- /dev/null
+++ b/erpnext/patches/v11_0/make_location_from_warehouse.py
@@ -0,0 +1,30 @@
+# Copyright (c) 2017, Frappe and Contributors
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe.utils.nestedset import rebuild_tree
+
+def execute():
+ frappe.reload_doc('assets', 'doctype', 'location')
+ frappe.reload_doc('stock', 'doctype', 'warehouse')
+
+ for d in frappe.get_all('Warehouse',
+ fields = ['warehouse_name', 'is_group', 'parent_warehouse'], order_by="is_group desc"):
+ try:
+ loc = frappe.new_doc('Location')
+ loc.location_name = d.warehouse_name
+ loc.is_group = d.is_group
+ loc.flags.ignore_mandatory = True
+ if d.parent_warehouse:
+ loc.parent_location = get_parent_warehouse_name(d.parent_warehouse)
+
+ loc.save(ignore_permissions=True)
+ except frappe.DuplicateEntryError:
+ continue
+
+ rebuild_tree("Location", "parent_location")
+
+def get_parent_warehouse_name(warehouse):
+ return frappe.db.get_value('Warehouse', warehouse, 'warehouse_name')
+
\ No newline at end of file
diff --git a/erpnext/patches/v11_0/rename_supplier_type_to_supplier_group.py b/erpnext/patches/v11_0/rename_supplier_type_to_supplier_group.py
new file mode 100644
index 0000000000..f0907af333
--- /dev/null
+++ b/erpnext/patches/v11_0/rename_supplier_type_to_supplier_group.py
@@ -0,0 +1,34 @@
+import frappe
+from frappe.model.rename_doc import rename_doc
+from frappe.model.utils.rename_field import rename_field
+from frappe import _
+from frappe.utils.nestedset import rebuild_tree
+
+def execute():
+ if frappe.db.table_exists("Supplier Type") and not frappe.db.table_exists("Supplier Group"):
+ rename_doc("DocType", "Supplier Type", "Supplier Group", force=True)
+ frappe.reload_doc('setup', 'doctype', 'supplier_group')
+ frappe.reload_doc("accounts", "doctype", "pricing_rule")
+ frappe.reload_doc("accounts", "doctype", "tax_rule")
+ frappe.reload_doc("buying", "doctype", "buying_settings")
+ frappe.reload_doc("buying", "doctype", "supplier")
+ rename_field("Supplier Group", "supplier_type", "supplier_group_name")
+ rename_field("Supplier", "supplier_type", "supplier_group")
+ rename_field("Buying Settings", "supplier_type", "supplier_group")
+ rename_field("Pricing Rule", "supplier_type", "supplier_group")
+ rename_field("Tax Rule", "supplier_type", "supplier_group")
+
+ build_tree()
+
+def build_tree():
+ frappe.db.sql("""update `tabSupplier Group` set parent_supplier_group = '{0}'
+ where is_group = 0""".format(_('All Supplier Groups')))
+
+ if not frappe.db.exists("Supplier Group", _('All Supplier Groups')):
+ frappe.get_doc({
+ 'doctype': 'Supplier Group',
+ 'supplier_group_name': _('All Supplier Groups'),
+ 'is_group': 1
+ }).insert(ignore_permissions=True)
+
+ rebuild_tree("Supplier Group", "parent_supplier_group")
diff --git a/erpnext/projects/doctype/project/project.json b/erpnext/projects/doctype/project/project.json
index 43cee681c6..184656bbd0 100644
--- a/erpnext/projects/doctype/project/project.json
+++ b/erpnext/projects/doctype/project/project.json
@@ -178,6 +178,36 @@
"translatable": 0,
"unique": 0
},
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 1,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "percent_complete",
+ "fieldtype": "Percent",
+ "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": "% Completed",
+ "length": 0,
+ "no_copy": 1,
+ "permlevel": 0,
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "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,
@@ -208,6 +238,38 @@
"translatable": 0,
"unique": 0
},
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "department",
+ "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": "Department",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Department",
+ "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,
@@ -305,36 +367,6 @@
"translatable": 0,
"unique": 0
},
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 1,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "percent_complete",
- "fieldtype": "Percent",
- "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": "% Completed",
- "length": 0,
- "no_copy": 1,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "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,
@@ -1709,7 +1741,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 4,
- "modified": "2018-03-28 10:19:32.743900",
+ "modified": "2018-05-10 04:21:25.764015",
"modified_by": "Administrator",
"module": "Projects",
"name": "Project",
@@ -1717,7 +1749,6 @@
"permissions": [
{
"amend": 0,
- "apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
@@ -1737,7 +1768,6 @@
},
{
"amend": 0,
- "apply_user_permissions": 0,
"cancel": 0,
"create": 0,
"delete": 0,
@@ -1757,7 +1787,6 @@
},
{
"amend": 0,
- "apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
diff --git a/erpnext/projects/doctype/task/task.json b/erpnext/projects/doctype/task/task.json
index 8e72d0339e..c1b7aa1c60 100644
--- a/erpnext/projects/doctype/task/task.json
+++ b/erpnext/projects/doctype/task/task.json
@@ -40,6 +40,7 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -72,6 +73,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -103,6 +105,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -133,6 +136,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0,
"width": "50%"
},
@@ -166,6 +170,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -198,6 +203,7 @@
"reqd": 0,
"search_index": 1,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -229,6 +235,7 @@
"reqd": 0,
"search_index": 1,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -260,6 +267,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -292,6 +300,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -326,6 +335,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -357,6 +367,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -386,6 +397,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -418,6 +430,7 @@
"reqd": 0,
"search_index": 1,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -449,6 +462,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -480,6 +494,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -512,6 +527,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -545,6 +561,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0,
"width": "300px"
},
@@ -578,6 +595,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -610,6 +628,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -641,6 +660,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -675,6 +695,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0,
"width": "50%"
},
@@ -708,6 +729,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -742,6 +764,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -771,6 +794,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -803,6 +827,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -833,6 +858,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -866,6 +892,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -898,6 +925,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -927,6 +955,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -958,6 +987,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -987,6 +1017,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -1019,6 +1050,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -1051,6 +1083,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -1079,6 +1112,39 @@
"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": "department",
+ "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": "Department",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Department",
+ "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
},
{
@@ -1109,6 +1175,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -1139,6 +1206,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -1169,6 +1237,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -1199,6 +1268,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
}
],
@@ -1214,7 +1284,7 @@
"istable": 0,
"max_attachments": 5,
"menu_index": 0,
- "modified": "2017-11-10 18:37:19.660293",
+ "modified": "2018-05-10 03:47:12.256088",
"modified_by": "Administrator",
"module": "Projects",
"name": "Task",
@@ -1222,7 +1292,6 @@
"permissions": [
{
"amend": 0,
- "apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
diff --git a/erpnext/projects/doctype/timesheet/test_timesheet.py b/erpnext/projects/doctype/timesheet/test_timesheet.py
index 2458db0cba..d2017c5712 100644
--- a/erpnext/projects/doctype/timesheet/test_timesheet.py
+++ b/erpnext/projects/doctype/timesheet/test_timesheet.py
@@ -118,30 +118,21 @@ class TestTimesheet(unittest.TestCase):
def make_salary_structure(employee):
- name = frappe.db.get_value('Salary Structure Employee', {'employee': employee}, 'parent')
+ name = frappe.db.get_value('Salary Structure Assignment', {'employee': employee}, 'salary_structure')
if name:
salary_structure = frappe.get_doc('Salary Structure', name)
else:
salary_structure = frappe.new_doc("Salary Structure")
salary_structure.name = "Timesheet Salary Structure Test"
salary_structure.salary_slip_based_on_timesheet = 1
- salary_structure.from_date = add_days(nowdate(), -30)
salary_structure.salary_component = "Basic"
salary_structure.hour_rate = 50.0
salary_structure.company = "_Test Company"
salary_structure.payment_account = get_random("Account")
- salary_structure.set('employees', [])
salary_structure.set('earnings', [])
salary_structure.set('deductions', [])
- es = salary_structure.append('employees', {
- "employee": employee,
- "base": 1200,
- "from_date": add_months(nowdate(),-1)
- })
-
-
es = salary_structure.append('earnings', {
"salary_component": "_Test Allowance",
"amount": 100
@@ -154,6 +145,14 @@ def make_salary_structure(employee):
salary_structure.save(ignore_permissions=True)
+ salary_structure_assignment = frappe.new_doc("Salary Structure Assignment")
+ salary_structure_assignment.employee = employee
+ salary_structure_assignment.base = 1200
+ salary_structure_assignment.from_date = add_months(nowdate(), -1)
+ salary_structure_assignment.salary_structure = salary_structure.name
+ salary_structure_assignment.company = "_Test Company"
+ salary_structure_assignment.save(ignore_permissions=True)
+
return salary_structure
def make_timesheet(employee, simulate=False, billable = 0, activity_type="_Test Activity Type", project=None, task=None, company=None):
diff --git a/erpnext/public/js/conf.js b/erpnext/public/js/conf.js
index d256c08e13..08f8d43e50 100644
--- a/erpnext/public/js/conf.js
+++ b/erpnext/public/js/conf.js
@@ -49,7 +49,7 @@ $.extend(frappe.create_routes, {
$.extend(frappe.breadcrumbs.preferred, {
"Item Group": "Stock",
"Customer Group": "Selling",
- "Supplier Type": "Buying",
+ "Supplier Group": "Buying",
"Territory": "Selling",
"Sales Person": "Selling",
"Sales Partner": "Selling",
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index 1551b1dfc3..eb4a7001f3 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -980,7 +980,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
"customer_group": me.frm.doc.customer_group,
"territory": me.frm.doc.territory,
"supplier": me.frm.doc.supplier,
- "supplier_type": me.frm.doc.supplier_type,
+ "supplier_group": me.frm.doc.supplier_group,
"currency": me.frm.doc.currency,
"conversion_rate": me.frm.doc.conversion_rate,
"price_list": me.frm.doc.selling_price_list || me.frm.doc.buying_price_list,
diff --git a/erpnext/public/js/financial_statements.js b/erpnext/public/js/financial_statements.js
index 29e3999f0a..7e31c573c5 100644
--- a/erpnext/public/js/financial_statements.js
+++ b/erpnext/public/js/financial_statements.js
@@ -70,6 +70,12 @@ function get_filters(){
"default": frappe.defaults.get_user_default("Company"),
"reqd": 1
},
+ {
+ "fieldname":"finance_book",
+ "label": __("Finance Book"),
+ "fieldtype": "Link",
+ "options": "Finance Book"
+ },
{
"fieldname":"from_fiscal_year",
"label": __("Start Year"),
diff --git a/erpnext/public/js/hub/hub_form.js b/erpnext/public/js/hub/hub_form.js
index 62c44fcb33..4a8c4eb3ec 100644
--- a/erpnext/public/js/hub/hub_form.js
+++ b/erpnext/public/js/hub/hub_form.js
@@ -444,8 +444,8 @@ erpnext.hub.ItemPage = class ItemPage extends erpnext.hub.HubDetailsPage {
{ label: __('Supplier Name'), fieldtype: 'Data', fieldname: 'supplier_name', default: item.company_name },
{ label: __('Supplier Email'), fieldtype: 'Data', fieldname: 'supplier_email', default: item.seller },
{ fieldtype: 'Column Break' },
- { label: __('Supplier Type'), fieldname: 'supplier_type',
- fieldtype: 'Link', options: 'Supplier Type' }
+ { label: __('Supplier Group'), fieldname: 'supplier_group',
+ fieldtype: 'Link', options: 'Supplier Group' }
];
fields = fields.map(f => { f.reqd = 1; return f; });
diff --git a/erpnext/public/js/purchase_trends_filters.js b/erpnext/public/js/purchase_trends_filters.js
index 117d4eb08c..595a138f12 100644
--- a/erpnext/public/js/purchase_trends_filters.js
+++ b/erpnext/public/js/purchase_trends_filters.js
@@ -23,7 +23,7 @@ erpnext.get_purchase_trends_filters = function() {
{ "value": "Item", "label": __("Item") },
{ "value": "Item Group", "label": __("Item Group") },
{ "value": "Supplier", "label": __("Supplier") },
- { "value": "Supplier Type", "label": __("Supplier Type") },
+ { "value": "Supplier Group", "label": __("Supplier Group") },
{ "value": "Project", "label": __("Project") }
],
"default": "Item"
diff --git a/erpnext/regional/india/setup.py b/erpnext/regional/india/setup.py
index 0073d3311c..70960d714b 100644
--- a/erpnext/regional/india/setup.py
+++ b/erpnext/regional/india/setup.py
@@ -16,7 +16,7 @@ def setup(company=None, patch=True):
add_print_formats()
if not patch:
update_address_template()
- make_fixtures()
+ make_fixtures(company)
def update_address_template():
with open(os.path.join(os.path.dirname(__file__), 'address_template.html'), 'r') as f:
@@ -189,15 +189,13 @@ def make_custom_fields():
create_custom_fields(custom_fields, ignore_validate = frappe.flags.in_patch)
-def make_fixtures():
- docs = [
- {'doctype': 'Salary Component', 'salary_component': 'Professional Tax', 'description': 'Professional Tax', 'type': 'Deduction'},
- {'doctype': 'Salary Component', 'salary_component': 'Provident Fund', 'description': 'Provident fund', 'type': 'Deduction'},
- {'doctype': 'Salary Component', 'salary_component': 'House Rent Allowance', 'description': 'House Rent Allowance', 'type': 'Earning'},
- {'doctype': 'Salary Component', 'salary_component': 'Basic', 'description': 'Basic', 'type': 'Earning'},
- {'doctype': 'Salary Component', 'salary_component': 'Arrear', 'description': 'Arrear', 'type': 'Earning'},
- {'doctype': 'Salary Component', 'salary_component': 'Leave Encashment', 'description': 'Leave Encashment', 'type': 'Earning'}
- ]
+def make_fixtures(company=None):
+ docs = []
+ company = company.name if company else frappe.db.get_value("Global Defaults", None, "default_company")
+
+ set_salary_components(docs)
+ set_tds_account(docs, company)
+ set_tax_withholding_category(docs, company)
for d in docs:
try:
@@ -206,3 +204,43 @@ def make_fixtures():
doc.insert()
except frappe.NameError:
pass
+
+def set_salary_components(docs):
+ docs.extend([
+ {'doctype': 'Salary Component', 'salary_component': 'Professional Tax', 'description': 'Professional Tax', 'type': 'Deduction'},
+ {'doctype': 'Salary Component', 'salary_component': 'Provident Fund', 'description': 'Provident fund', 'type': 'Deduction'},
+ {'doctype': 'Salary Component', 'salary_component': 'House Rent Allowance', 'description': 'House Rent Allowance', 'type': 'Earning'},
+ {'doctype': 'Salary Component', 'salary_component': 'Basic', 'description': 'Basic', 'type': 'Earning'},
+ {'doctype': 'Salary Component', 'salary_component': 'Arrear', 'description': 'Arrear', 'type': 'Earning'},
+ {'doctype': 'Salary Component', 'salary_component': 'Leave Encashment', 'description': 'Leave Encashment', 'type': 'Earning'}
+ ])
+
+def set_tax_withholding_category(docs, company):
+ accounts = []
+ tds_account = frappe.db.get_value("Account", filter={"account_type": "Payable",
+ "account_name": "TDS", "company": company})
+
+ if company and tds_account:
+ accounts = [
+ {
+ 'company': company,
+ 'account': tds_account
+ }
+ ]
+
+ docs.extend([
+ {
+ 'doctype': 'Tax Withholding Category', '__newname': 'TDS',
+ 'percent_of_tax_withheld': 10,'threshold': 150000, 'book_on_invoice': 1,
+ 'book_on_advance': 0, "withhold_cumulative_tax_amount": 0,
+ 'accounts': accounts
+ }
+ ])
+
+def set_tds_account(docs, company):
+ docs.extend([
+ {
+ 'doctype': 'Account', 'account_name': 'TDS', 'account_type': 'Tax',
+ 'parent_account': 'Duties and Taxes', 'company': company
+ }
+ ])
\ No newline at end of file
diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py
index 40c2cf0358..72723eb115 100755
--- a/erpnext/selling/doctype/sales_order/sales_order.py
+++ b/erpnext/selling/doctype/sales_order/sales_order.py
@@ -755,9 +755,9 @@ def make_purchase_order_for_drop_shipment(source_name, for_supplier, target_doc=
def get_supplier(doctype, txt, searchfield, start, page_len, filters):
supp_master_name = frappe.defaults.get_user_default("supp_master_name")
if supp_master_name == "Supplier Name":
- fields = ["name", "supplier_type"]
+ fields = ["name", "supplier_group"]
else:
- fields = ["name", "supplier_name", "supplier_type"]
+ fields = ["name", "supplier_name", "supplier_group"]
fields = ", ".join(fields)
return frappe.db.sql("""select {field} from `tabSupplier`
diff --git a/erpnext/setup/doctype/company/company.js b/erpnext/setup/doctype/company/company.js
index e164d6949f..5ca2885547 100644
--- a/erpnext/setup/doctype/company/company.js
+++ b/erpnext/setup/doctype/company/company.js
@@ -207,6 +207,9 @@ erpnext.company.setup_queries = function(frm) {
["round_off_cost_center", {}],
["depreciation_cost_center", {}],
["default_employee_advance_account", {"root_type": "Asset"}],
+ ["expenses_included_in_asset_valuation", {"account_type": "Expenses Included In Asset Valuation"}],
+ ["capital_work_in_progress_account", {"account_type": "Capital Work in Progress"}],
+ ["asset_received_but_not_billed", {"account_type": "Asset Received But Not Billed"}]
], function(i, v) {
erpnext.company.set_custom_query(frm, v);
});
diff --git a/erpnext/setup/doctype/company/company.json b/erpnext/setup/doctype/company/company.json
index 66b1433eb1..07051eeba8 100644
--- a/erpnext/setup/doctype/company/company.json
+++ b/erpnext/setup/doctype/company/company.json
@@ -456,7 +456,38 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
- "fieldname": "default_letter_head",
+ "fieldname": "default_currency",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 1,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Default Currency",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Currency",
+ "permlevel": 0,
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "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": "default_letter_head",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
@@ -465,10 +496,10 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
- "label": "Default Letter Head",
+ "label": "Default Letter Head",
"length": 0,
"no_copy": 0,
- "options": "Letter Head",
+ "options": "Letter Head",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@@ -488,7 +519,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
- "fieldname": "default_holiday_list",
+ "fieldname": "default_holiday_list",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
@@ -497,12 +528,12 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
- "label": "Default Holiday List",
+ "label": "Default Holiday List",
"length": 0,
"no_copy": 0,
- "options": "Holiday List",
+ "options": "Holiday List",
"permlevel": 0,
- "precision": "",
+ "precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
@@ -520,57 +551,26 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
- "fieldname": "default_terms",
+ "fieldname": "default_terms",
"fieldtype": "Link",
"hidden": 0,
- "ignore_user_permissions": 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": "Default Terms",
+ "label": "Default Terms",
"length": 0,
"no_copy": 0,
- "options": "Terms and Conditions",
+ "options": "Terms and Conditions",
"permlevel": 0,
"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": "default_currency",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 1,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Default Currency",
- "length": 0,
- "no_copy": 0,
- "options": "Currency",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
+ "reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
@@ -1785,6 +1785,38 @@
"translatable": 0,
"unique": 0
},
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "expenses_included_in_asset_valuation",
+ "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": "Expenses Included In Asset Valuation",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Account",
+ "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,
@@ -1879,6 +1911,70 @@
"translatable": 0,
"unique": 0
},
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "capital_work_in_progress_account",
+ "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": "Capital Work In Progress Account",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Account",
+ "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": "asset_received_but_not_billed",
+ "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": "Asset Received But Not Billed",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Account",
+ "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,
@@ -2400,7 +2496,7 @@
"istable": 0,
"max_attachments": 0,
"menu_index": 0,
- "modified": "2018-05-05 13:08:07.351655",
+ "modified": "2018-05-07 15:35:06.736602",
"modified_by": "Administrator",
"module": "Setup",
"name": "Company",
diff --git a/erpnext/setup/doctype/company/company.py b/erpnext/setup/doctype/company/company.py
index 1b68b8a6b6..9040bb7c8f 100644
--- a/erpnext/setup/doctype/company/company.py
+++ b/erpnext/setup/doctype/company/company.py
@@ -168,6 +168,9 @@ class Company(NestedSet):
self._set_default_account("round_off_account", "Round Off")
self._set_default_account("accumulated_depreciation_account", "Accumulated Depreciation")
self._set_default_account("depreciation_expense_account", "Depreciation")
+ self._set_default_account("capital_work_in_progress_account", "Capital Work in Progress")
+ self._set_default_account("asset_received_but_not_billed", "Asset Received But Not Billed")
+ self._set_default_account("expenses_included_in_asset_valuation", "Expenses Included In Asset Valuation")
if self.enable_perpetual_inventory:
self._set_default_account("stock_received_but_not_billed", "Stock Received But Not Billed")
diff --git a/erpnext/setup/doctype/supplier_type/__init__.py b/erpnext/setup/doctype/supplier_group/__init__.py
similarity index 100%
rename from erpnext/setup/doctype/supplier_type/__init__.py
rename to erpnext/setup/doctype/supplier_group/__init__.py
diff --git a/erpnext/setup/doctype/supplier_group/supplier_group.js b/erpnext/setup/doctype/supplier_group/supplier_group.js
new file mode 100644
index 0000000000..ac5bda6e2c
--- /dev/null
+++ b/erpnext/setup/doctype/supplier_group/supplier_group.js
@@ -0,0 +1,37 @@
+// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+cur_frm.cscript.refresh = function(doc) {
+ cur_frm.set_intro(doc.__islocal ? "" : __("There is nothing to edit."));
+ cur_frm.cscript.set_root_readonly(doc);
+};
+
+cur_frm.cscript.set_root_readonly = function(doc) {
+ // read-only for root customer group
+ if(!doc.parent_supplier_group) {
+ cur_frm.set_read_only();
+ cur_frm.set_intro(__("This is a root supplier group and cannot be edited."));
+ } else {
+ cur_frm.set_intro(null);
+ }
+};
+
+// get query select Customer Group
+cur_frm.fields_dict['parent_supplier_group'].get_query = function() {
+ return {
+ filters: {
+ 'is_group': 1
+ }
+ };
+};
+
+cur_frm.fields_dict['accounts'].grid.get_field('account').get_query = function(doc, cdt, cdn) {
+ var d = locals[cdt][cdn];
+ return {
+ filters: {
+ 'account_type': 'Payable',
+ 'company': d.company,
+ "is_group": 0
+ }
+ };
+};
diff --git a/erpnext/setup/doctype/supplier_type/supplier_type.json b/erpnext/setup/doctype/supplier_group/supplier_group.json
similarity index 62%
rename from erpnext/setup/doctype/supplier_type/supplier_type.json
rename to erpnext/setup/doctype/supplier_group/supplier_group.json
index d7d7084d7f..dc8b2631f1 100644
--- a/erpnext/setup/doctype/supplier_type/supplier_type.json
+++ b/erpnext/setup/doctype/supplier_group/supplier_group.json
@@ -3,7 +3,7 @@
"allow_guest_to_view": 0,
"allow_import": 1,
"allow_rename": 1,
- "autoname": "field:supplier_type",
+ "autoname": "field:supplier_group_name",
"beta": 0,
"creation": "2013-01-10 16:34:24",
"custom": 0,
@@ -18,16 +18,16 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
- "fieldname": "supplier_type",
+ "fieldname": "supplier_group_name",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
- "in_list_view": 1,
+ "in_list_view": 0,
"in_standard_filter": 0,
- "label": "Supplier Type",
+ "label": "Supplier Group Name",
"length": 0,
"no_copy": 0,
"oldfieldname": "supplier_type",
@@ -41,8 +41,72 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 1,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "parent_supplier_group",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 1,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Parent Supplier Group",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Supplier Group",
+ "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": 1,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "is_group",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Is Group",
+ "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,
@@ -71,6 +135,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -102,6 +167,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -131,6 +197,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -163,6 +230,101 @@
"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": "lft",
+ "fieldtype": "Int",
+ "hidden": 1,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "lft",
+ "length": 0,
+ "no_copy": 1,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 1,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 1,
+ "reqd": 0,
+ "search_index": 1,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "rgt",
+ "fieldtype": "Int",
+ "hidden": 1,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "rgt",
+ "length": 0,
+ "no_copy": 1,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 1,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 1,
+ "reqd": 0,
+ "search_index": 1,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "old_parent",
+ "fieldtype": "Link",
+ "hidden": 1,
+ "ignore_user_permissions": 1,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Old Parent",
+ "length": 0,
+ "no_copy": 1,
+ "options": "Supplier Group",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 1,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 1,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
"unique": 0
}
],
@@ -177,15 +339,14 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2017-09-04 18:54:10.093500",
+ "modified": "2018-04-20 00:54:48.724120",
"modified_by": "Administrator",
"module": "Setup",
- "name": "Supplier Type",
+ "name": "Supplier Group",
"owner": "Administrator",
"permissions": [
{
"amend": 0,
- "apply_user_permissions": 0,
"cancel": 0,
"create": 0,
"delete": 0,
@@ -205,7 +366,6 @@
},
{
"amend": 0,
- "apply_user_permissions": 0,
"cancel": 0,
"create": 0,
"delete": 0,
@@ -225,7 +385,6 @@
},
{
"amend": 0,
- "apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
@@ -245,7 +404,6 @@
},
{
"amend": 0,
- "apply_user_permissions": 0,
"cancel": 0,
"create": 0,
"delete": 0,
@@ -265,7 +423,6 @@
},
{
"amend": 0,
- "apply_user_permissions": 0,
"cancel": 0,
"create": 0,
"delete": 0,
@@ -285,7 +442,6 @@
},
{
"amend": 0,
- "apply_user_permissions": 0,
"cancel": 0,
"create": 0,
"delete": 0,
diff --git a/erpnext/setup/doctype/supplier_group/supplier_group.py b/erpnext/setup/doctype/supplier_group/supplier_group.py
new file mode 100644
index 0000000000..747560a533
--- /dev/null
+++ b/erpnext/setup/doctype/supplier_group/supplier_group.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe.utils.nestedset import NestedSet
+
+class SupplierGroup(NestedSet):
+ nsm_parent_field = 'parent_supplier_group';
+
+ def update_nsm_model(self):
+ frappe.utils.nestedset.update_nsm(self)
+
+ def on_update(self):
+ self.update_nsm_model()
+ self.validate_one_root()
+
+ def on_trash(self):
+ self.update_nsm_model()
diff --git a/erpnext/setup/doctype/supplier_group/supplier_group_tree.js b/erpnext/setup/doctype/supplier_group/supplier_group_tree.js
new file mode 100644
index 0000000000..73926992e8
--- /dev/null
+++ b/erpnext/setup/doctype/supplier_group/supplier_group_tree.js
@@ -0,0 +1,3 @@
+frappe.treeview_settings["Supplier Group"] = {
+ ignore_fields:["parent_supplier_group"]
+};
\ No newline at end of file
diff --git a/erpnext/setup/doctype/supplier_group/test_records.json b/erpnext/setup/doctype/supplier_group/test_records.json
new file mode 100644
index 0000000000..1681e2a647
--- /dev/null
+++ b/erpnext/setup/doctype/supplier_group/test_records.json
@@ -0,0 +1,7 @@
+[
+ {
+ "doctype": "Supplier Group",
+ "supplier_group_name": "_Test Supplier Group"
+ }
+]
+
\ No newline at end of file
diff --git a/erpnext/setup/doctype/supplier_group/test_supplier_group.js b/erpnext/setup/doctype/supplier_group/test_supplier_group.js
new file mode 100644
index 0000000000..976dd2cc4f
--- /dev/null
+++ b/erpnext/setup/doctype/supplier_group/test_supplier_group.js
@@ -0,0 +1,23 @@
+/* eslint-disable */
+// rename this file from _test_[name] to test_[name] to activate
+// and remove above this line
+
+QUnit.test("test: Supplier Group", function (assert) {
+ let done = assert.async();
+
+ // number of asserts
+ assert.expect(1);
+
+ frappe.run_serially([
+ // insert a new Supplier Group
+ () => frappe.tests.make('Supplier Group', [
+ // values to be set
+ {key: 'value'}
+ ]),
+ () => {
+ assert.equal(cur_frm.doc.key, 'value');
+ },
+ () => done()
+ ]);
+
+});
diff --git a/erpnext/setup/doctype/supplier_group/test_supplier_group.py b/erpnext/setup/doctype/supplier_group/test_supplier_group.py
new file mode 100644
index 0000000000..0e3d23d6bd
--- /dev/null
+++ b/erpnext/setup/doctype/supplier_group/test_supplier_group.py
@@ -0,0 +1,7 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import frappe
+test_records = frappe.get_test_records('Supplier Group')
diff --git a/erpnext/setup/doctype/supplier_type/README.md b/erpnext/setup/doctype/supplier_type/README.md
deleted file mode 100644
index 0da4c708ac..0000000000
--- a/erpnext/setup/doctype/supplier_type/README.md
+++ /dev/null
@@ -1 +0,0 @@
-Supplier classification.
\ No newline at end of file
diff --git a/erpnext/setup/doctype/supplier_type/supplier_type.js b/erpnext/setup/doctype/supplier_type/supplier_type.js
deleted file mode 100644
index f1c5d70640..0000000000
--- a/erpnext/setup/doctype/supplier_type/supplier_type.js
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
-// License: GNU General Public License v3. See license.txt
-
-cur_frm.cscript.refresh = function(doc) {
- cur_frm.set_intro(doc.__islocal ? "" : __("There is nothing to edit."))
-}
-
-cur_frm.fields_dict['accounts'].grid.get_field('account').get_query = function(doc, cdt, cdn) {
- var d = locals[cdt][cdn];
- return {
- filters: {
- 'account_type': 'Payable',
- 'company': d.company,
- "is_group": 0
- }
- }
-}
diff --git a/erpnext/setup/doctype/supplier_type/supplier_type.py b/erpnext/setup/doctype/supplier_type/supplier_type.py
deleted file mode 100644
index 0d237469e3..0000000000
--- a/erpnext/setup/doctype/supplier_type/supplier_type.py
+++ /dev/null
@@ -1,10 +0,0 @@
-# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
-# License: GNU General Public License v3. See license.txt
-
-from __future__ import unicode_literals
-import frappe
-
-from frappe.model.document import Document
-
-class SupplierType(Document):
- pass
\ No newline at end of file
diff --git a/erpnext/setup/doctype/supplier_type/test_records.json b/erpnext/setup/doctype/supplier_type/test_records.json
deleted file mode 100644
index fd632c5afd..0000000000
--- a/erpnext/setup/doctype/supplier_type/test_records.json
+++ /dev/null
@@ -1,6 +0,0 @@
-[
- {
- "doctype": "Supplier Type",
- "supplier_type": "_Test Supplier Type"
- }
-]
diff --git a/erpnext/setup/doctype/supplier_type/test_supplier_type.py b/erpnext/setup/doctype/supplier_type/test_supplier_type.py
deleted file mode 100644
index 9fa8a44b1d..0000000000
--- a/erpnext/setup/doctype/supplier_type/test_supplier_type.py
+++ /dev/null
@@ -1,7 +0,0 @@
-# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
-# License: GNU General Public License v3. See license.txt
-from __future__ import unicode_literals
-
-
-import frappe
-test_records = frappe.get_test_records('Supplier Type')
\ No newline at end of file
diff --git a/erpnext/setup/setup_wizard/operations/install_fixtures.py b/erpnext/setup/setup_wizard/operations/install_fixtures.py
index 8f761e5946..c686ed3080 100644
--- a/erpnext/setup/setup_wizard/operations/install_fixtures.py
+++ b/erpnext/setup/setup_wizard/operations/install_fixtures.py
@@ -147,14 +147,15 @@ def install(country=None):
{'doctype': 'Customer Group', 'customer_group_name': _('Non Profit'), 'is_group': 0, 'parent_customer_group': _('All Customer Groups')},
{'doctype': 'Customer Group', 'customer_group_name': _('Government'), 'is_group': 0, 'parent_customer_group': _('All Customer Groups')},
- # supplier type
- {'doctype': 'Supplier Type', 'supplier_type': _('Services')},
- {'doctype': 'Supplier Type', 'supplier_type': _('Local')},
- {'doctype': 'Supplier Type', 'supplier_type': _('Raw Material')},
- {'doctype': 'Supplier Type', 'supplier_type': _('Electrical')},
- {'doctype': 'Supplier Type', 'supplier_type': _('Hardware')},
- {'doctype': 'Supplier Type', 'supplier_type': _('Pharmaceutical')},
- {'doctype': 'Supplier Type', 'supplier_type': _('Distributor')},
+ # supplier group
+ {'doctype': 'Supplier Group', 'supplier_group_name': _('All Supplier Groups'), 'is_group': 1, 'name': _('All Supplier Groups'), 'parent_supplier_group': ''},
+ {'doctype': 'Supplier Group', 'supplier_group_name': _('Services'), 'is_group': 0, 'parent_supplier_group': _('All Supplier Groups')},
+ {'doctype': 'Supplier Group', 'supplier_group_name': _('Local'), 'is_group': 0, 'parent_supplier_group': _('All Supplier Groups')},
+ {'doctype': 'Supplier Group', 'supplier_group_name': _('Raw Material'), 'is_group': 0, 'parent_supplier_group': _('All Supplier Groups')},
+ {'doctype': 'Supplier Group', 'supplier_group_name': _('Electrical'), 'is_group': 0, 'parent_supplier_group': _('All Supplier Groups')},
+ {'doctype': 'Supplier Group', 'supplier_group_name': _('Hardware'), 'is_group': 0, 'parent_supplier_group': _('All Supplier Groups')},
+ {'doctype': 'Supplier Group', 'supplier_group_name': _('Pharmaceutical'), 'is_group': 0, 'parent_supplier_group': _('All Supplier Groups')},
+ {'doctype': 'Supplier Group', 'supplier_group_name': _('Distributor'), 'is_group': 0, 'parent_supplier_group': _('All Supplier Groups')},
# Sales Person
{'doctype': 'Sales Person', 'sales_person_name': _('Sales Team'), 'is_group': 1, "parent_sales_person": ""},
diff --git a/erpnext/startup/report_data_map.py b/erpnext/startup/report_data_map.py
index daf6fdd3bd..5de7998c7d 100644
--- a/erpnext/startup/report_data_map.py
+++ b/erpnext/startup/report_data_map.py
@@ -208,15 +208,15 @@ data_map = {
},
"Supplier": {
"columns": ["name", "if(supplier_name=name, '', supplier_name) as supplier_name",
- "supplier_type as parent_supplier_type"],
+ "supplier_group as parent_supplier_group"],
"conditions": ["docstatus < 2"],
"order_by": "name",
"links": {
- "parent_supplier_type": ["Supplier Type", "name"],
+ "parent_supplier_group": ["Supplier Group", "name"],
}
},
- "Supplier Type": {
- "columns": ["name"],
+ "Supplier Group": {
+ "columns": ["name", "parent_supplier_group"],
"conditions": ["docstatus < 2"],
"order_by": "name"
},
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.js b/erpnext/stock/doctype/delivery_note/delivery_note.js
index e6029aa4ea..7ee0c5c2d0 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.js
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.js
@@ -34,7 +34,7 @@ frappe.ui.form.on("Delivery Note", {
frm.set_query('transporter_name', function(doc) {
return {
- filters: { 'supplier_type': "transporter" }
+ filters: { 'supplier_group': "transporter" }
}
});
diff --git a/erpnext/stock/doctype/item/item.js b/erpnext/stock/doctype/item/item.js
index f98cbb6268..fbf0deddc7 100644
--- a/erpnext/stock/doctype/item/item.js
+++ b/erpnext/stock/doctype/item/item.js
@@ -19,7 +19,9 @@ frappe.ui.form.on("Item", {
// should never check Private
frm.fields_dict["website_image"].df.is_private = 0;
-
+ if (frm.doc.is_fixed_asset) {
+ frm.trigger("set_asset_naming_series");
+ }
},
refresh: function(frm) {
@@ -124,7 +126,20 @@ frappe.ui.form.on("Item", {
},
is_fixed_asset: function(frm) {
- frm.set_value("is_stock_item", frm.doc.is_fixed_asset ? 0 : 1);
+ frm.call({
+ method: "set_asset_naming_series",
+ doc: frm.doc,
+ callback: function() {
+ frm.set_value("is_stock_item", frm.doc.is_fixed_asset ? 0 : 1);
+ frm.trigger("set_asset_naming_series");
+ }
+ })
+ },
+
+ set_asset_naming_series: function(frm) {
+ if (frm.doc.__onload && frm.doc.__onload.asset_naming_series) {
+ frm.set_df_property("asset_naming_series", "options", frm.doc.__onload.asset_naming_series);
+ }
},
page_name: frappe.utils.warn_page_name_change,
diff --git a/erpnext/stock/doctype/item/item.json b/erpnext/stock/doctype/item/item.json
index 21900ad440..b8621719c4 100644
--- a/erpnext/stock/doctype/item/item.json
+++ b/erpnext/stock/doctype/item/item.json
@@ -395,7 +395,7 @@
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
- "unique": 0
+ "unique": 0
},
{
"allow_bulk_edit": 0,
@@ -559,6 +559,38 @@
"translatable": 0,
"unique": 0
},
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "depends_on": "is_fixed_asset",
+ "fieldname": "asset_naming_series",
+ "fieldtype": "Select",
+ "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": "Asset Naming Series",
+ "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,
@@ -1285,7 +1317,7 @@
"collapsible": 1,
"collapsible_depends_on": "eval:doc.has_batch_no || doc.has_serial_no",
"columns": 0,
- "depends_on": "is_stock_item",
+ "depends_on": "eval:doc.is_stock_item || doc.is_fixed_asset",
"fieldname": "serial_nos_and_batches",
"fieldtype": "Section Break",
"hidden": 0,
@@ -1513,7 +1545,7 @@
"collapsible": 0,
"columns": 0,
"default": "",
- "depends_on": "eval:doc.is_stock_item",
+ "depends_on": "eval:doc.is_stock_item || doc.is_fixed_asset",
"description": "",
"fieldname": "has_serial_no",
"fieldtype": "Check",
@@ -3717,7 +3749,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 1,
- "modified": "2018-04-30 12:21:48.715529",
+ "modified": "2018-05-07 14:54:24.479267",
"modified_by": "Administrator",
"module": "Stock",
"name": "Item",
@@ -3725,7 +3757,6 @@
"permissions": [
{
"amend": 0,
- "apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
@@ -3745,7 +3776,6 @@
},
{
"amend": 0,
- "apply_user_permissions": 0,
"cancel": 0,
"create": 0,
"delete": 0,
@@ -3765,7 +3795,6 @@
},
{
"amend": 0,
- "apply_user_permissions": 0,
"cancel": 0,
"create": 0,
"delete": 0,
@@ -3785,7 +3814,6 @@
},
{
"amend": 0,
- "apply_user_permissions": 0,
"cancel": 0,
"create": 0,
"delete": 0,
@@ -3805,7 +3833,6 @@
},
{
"amend": 0,
- "apply_user_permissions": 0,
"cancel": 0,
"create": 0,
"delete": 0,
@@ -3825,7 +3852,6 @@
},
{
"amend": 0,
- "apply_user_permissions": 0,
"cancel": 0,
"create": 0,
"delete": 0,
@@ -3845,7 +3871,6 @@
},
{
"amend": 0,
- "apply_user_permissions": 0,
"cancel": 0,
"create": 0,
"delete": 0,
@@ -3865,7 +3890,6 @@
},
{
"amend": 0,
- "apply_user_permissions": 0,
"cancel": 0,
"create": 0,
"delete": 0,
diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py
index 123e73f652..94b907b914 100644
--- a/erpnext/stock/doctype/item/item.py
+++ b/erpnext/stock/doctype/item/item.py
@@ -16,6 +16,7 @@ from frappe.utils import (cint, cstr, flt, formatdate, get_timestamp, getdate,
from frappe.utils.html_utils import clean_html
from frappe.website.doctype.website_slideshow.website_slideshow import \
get_slideshow
+
from frappe.website.render import clear_cache
from frappe.website.website_generator import WebsiteGenerator
@@ -42,10 +43,18 @@ class Item(WebsiteGenerator):
super(Item, self).onload()
self.set_onload('stock_exists', self.stock_ledger_created())
+ self.set_asset_naming_series()
if self.is_fixed_asset:
asset = frappe.db.get_all("Asset", filters={"item_code": self.name, "docstatus": 1}, limit=1)
self.set_onload("asset_exists", True if asset else False)
+ def set_asset_naming_series(self):
+ if not hasattr(self, '_asset_naming_series'):
+ from erpnext.assets.doctype.asset.asset import get_asset_naming_series
+ self._asset_naming_series = get_asset_naming_series()
+
+ self.set_onload('asset_naming_series', self._asset_naming_series)
+
def autoname(self):
if frappe.db.get_default("item_naming_by") == "Naming Series":
if self.variant_of:
@@ -444,7 +453,7 @@ class Item(WebsiteGenerator):
_("Conversion factor for default Unit of Measure must be 1 in row {0}").format(d.idx))
def validate_item_type(self):
- if self.has_serial_no == 1 and self.is_stock_item == 0:
+ if self.has_serial_no == 1 and self.is_stock_item == 0 and not self.is_fixed_asset:
msgprint(_("'Has Serial No' can not be 'Yes' for non-stock item"), raise_exception=1)
if self.has_serial_no == 0 and self.serial_no_series:
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js
index 791b2532f7..69d2f2a3d7 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js
@@ -65,6 +65,20 @@ erpnext.stock.PurchaseReceiptController = erpnext.buying.BuyingController.extend
if (erpnext.is_perpetual_inventory_enabled(this.frm.doc.company)) {
this.show_general_ledger();
}
+
+ this.frm.add_custom_button(__('Asset'), function() {
+ frappe.route_options = {
+ purchase_receipt: me.frm.doc.name,
+ };
+ frappe.set_route("List", "Asset");
+ }, __("View"));
+
+ this.frm.add_custom_button(__('Asset Movement'), function() {
+ frappe.route_options = {
+ reference_name: me.frm.doc.name,
+ };
+ frappe.set_route("List", "Asset Movement");
+ }, __("View"));
}
if(!this.frm.doc.is_return && this.frm.doc.status!="Closed") {
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
index 46eee31e90..573f7ed8f3 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
@@ -13,6 +13,7 @@ from erpnext.controllers.buying_controller import BuyingController
from erpnext.accounts.utils import get_account_currency
from frappe.desk.notifications import clear_doctype_notifications
from erpnext.buying.utils import check_for_closed_status
+from erpnext.assets.doctype.asset_category.asset_category import get_asset_category_account
form_grid_templates = {
"items": "templates/form_grid/item_grid.html"
@@ -253,6 +254,40 @@ class PurchaseReceipt(BuyingController):
d.rejected_warehouse not in warehouse_with_no_account:
warehouse_with_no_account.append(d.warehouse)
+ elif d.is_fixed_asset:
+ asset_accounts = self.get_company_default(["capital_work_in_progress_account",
+ "asset_received_but_not_billed"])
+
+ # CWIP entry
+ cwip_account = get_asset_category_account(d.asset,
+ 'capital_work_in_progress_account') or asset_accounts[0]
+
+ asset_amount = flt(d.net_amount) + flt(d.item_tax_amount/self.conversion_rate)
+ base_asset_amount = flt(d.base_net_amount + d.item_tax_amount)
+
+ cwip_account_currency = get_account_currency(cwip_account)
+ gl_entries.append(self.get_gl_dict({
+ "account": cwip_account,
+ "against": asset_accounts[1],
+ "cost_center": d.cost_center,
+ "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)
+ }))
+
+ # Asset received but not billed
+ asset_rbnb_currency = get_account_currency(asset_accounts[1])
+ gl_entries.append(self.get_gl_dict({
+ "account": asset_accounts[1],
+ "against": asset_accounts[0],
+ "cost_center": d.cost_center,
+ "remarks": self.get("remarks") or _("Accounting Entry for Asset"),
+ "credit": base_asset_amount,
+ "credit_in_account_currency": (base_asset_amount
+ if asset_rbnb_currency == self.company_currency else asset_amount)
+ }))
+
# Cost center-wise amount breakup for other charges included for valuation
valuation_tax = {}
for tax in self.get("taxes"):
@@ -393,6 +428,8 @@ def make_purchase_invoice(source_name, target_doc=None):
"parent": "purchase_receipt",
"purchase_order_item": "po_detail",
"purchase_order": "purchase_order",
+ "is_fixed_asset": "is_fixed_asset",
+ "asset": "asset",
},
"postprocess": update_item,
"filter": lambda d: abs(d.qty) - abs(invoiced_qty_map.get(d.name, 0))<=0
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt_dashboard.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt_dashboard.py
index 9ade1afd8a..bcedd7179a 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt_dashboard.py
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt_dashboard.py
@@ -5,6 +5,7 @@ def get_data():
'fieldname': 'purchase_receipt_no',
'non_standard_fieldnames': {
'Purchase Invoice': 'purchase_receipt',
+ 'Asset': 'purchase_receipt',
'Landed Cost Voucher': 'receipt_document',
'Subscription': 'reference_document'
},
@@ -16,7 +17,7 @@ def get_data():
'transactions': [
{
'label': _('Related'),
- 'items': ['Purchase Invoice', 'Landed Cost Voucher']
+ 'items': ['Purchase Invoice', 'Landed Cost Voucher', 'Asset']
},
{
'label': _('Reference'),
diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
index d9f40cca90..ffcc954df1 100644
--- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
@@ -289,13 +289,53 @@ class TestPurchaseReceipt(unittest.TestCase):
serial_no=serial_no, basic_rate=100, do_not_submit=True)
self.assertRaises(SerialNoDuplicateError, se.submit)
+ def test_serialized_asset_item(self):
+ asset_item = "Test Serialized Asset Item"
+
+ if not frappe.db.exists('Item', asset_item):
+ asset_category = frappe.get_all('Asset Category')
+
+ if asset_category:
+ asset_category = asset_category[0].name
+
+ if not asset_category:
+ doc = frappe.get_doc({
+ 'doctype': 'Asset Category',
+ 'asset_category_name': 'Test Asset Category',
+ 'depreciation_method': 'Straight Line',
+ 'total_number_of_depreciations': 12,
+ 'frequency_of_depreciation': 1,
+ 'accounts': [{
+ 'company_name': '_Test Company',
+ 'fixed_asset_account': '_Test Fixed Asset - _TC',
+ 'accumulated_depreciation_account': 'Depreciation - _TC',
+ 'depreciation_expense_account': 'Depreciation - _TC'
+ }]
+ }).insert()
+
+ asset_category = doc.name
+
+ asset_item = make_item(asset_item, {'is_stock_item':0,
+ 'stock_uom': 'Box', 'is_fixed_asset': 1, 'has_serial_no': 1,
+ 'asset_category': asset_category, 'serial_no_series': 'ABC.###'})
+
+ pr = make_purchase_receipt(item_code=asset_item, qty=3)
+ asset = frappe.db.get_value('Asset', {'purchase_receipt': pr.name}, 'name')
+ asset_movement = frappe.db.get_value('Asset Movement', {'reference_name': pr.name}, 'name')
+ serial_nos = frappe.get_all('Serial No', {'asset': asset}, 'name')
+
+ self.assertEquals(len(serial_nos), 3)
+ pr.cancel()
+ serial_nos = frappe.get_all('Serial No', {'asset': asset}, 'name') or []
+ self.assertEquals(len(serial_nos), 0)
+ frappe.db.sql("delete from `tabAsset Category`")
+ frappe.db.sql("delete from `tabAsset`")
def get_gl_entries(voucher_type, voucher_no):
return frappe.db.sql("""select account, debit, credit
from `tabGL Entry` where voucher_type=%s and voucher_no=%s
order by account desc""", (voucher_type, voucher_no), as_dict=1)
-
def make_purchase_receipt(**args):
frappe.db.set_value("Buying Settings", None, "allow_multiple_items", 1)
pr = frappe.new_doc("Purchase Receipt")
diff --git a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json
index 754bd71879..87c9a757bf 100755
--- a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json
+++ b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json
@@ -1577,6 +1577,103 @@
"translatable": 0,
"unique": 0
},
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "is_fixed_asset",
+ "fieldtype": "Check",
+ "hidden": 1,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Is Fixed Asset",
+ "length": 0,
+ "no_copy": 1,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 1,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "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,
+ "depends_on": "is_fixed_asset",
+ "fieldname": "asset",
+ "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": "Asset",
+ "length": 0,
+ "no_copy": 1,
+ "options": "Asset",
+ "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,
+ "depends_on": "is_fixed_asset",
+ "fieldname": "asset_location",
+ "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": "Asset Location",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Location",
+ "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,
@@ -2395,7 +2492,7 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
- "modified": "2018-02-22 15:15:38.793425",
+ "modified": "2018-05-07 13:42:05.061386",
"modified_by": "Administrator",
"module": "Stock",
"name": "Purchase Receipt Item",
diff --git a/erpnext/stock/doctype/serial_no/serial_no.json b/erpnext/stock/doctype/serial_no/serial_no.json
index b37713be96..f84cbef2c8 100644
--- a/erpnext/stock/doctype/serial_no/serial_no.json
+++ b/erpnext/stock/doctype/serial_no/serial_no.json
@@ -619,6 +619,190 @@
"set_only_once": 0,
"unique": 0
},
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "asset_details",
+ "fieldtype": "Section Break",
+ "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": "Asset Details",
+ "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,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "asset",
+ "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": "Asset",
+ "length": 0,
+ "no_copy": 1,
+ "options": "Asset",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 1,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "depends_on": "asset",
+ "fieldname": "asset_status",
+ "fieldtype": "Select",
+ "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": "Asset Status",
+ "length": 0,
+ "no_copy": 0,
+ "options": "\nIssue\nReceipt\nTransfer",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "column_break_24",
+ "fieldtype": "Column Break",
+ "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,
+ "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,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "location",
+ "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": "Location",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Location",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "employee",
+ "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": "Employee",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Employee",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@@ -1270,7 +1454,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2017-05-15 18:22:23.685286",
+ "modified": "2018-05-10 23:38:20.646770",
"modified_by": "Administrator",
"module": "Stock",
"name": "Serial No",
diff --git a/erpnext/stock/doctype/serial_no/serial_no.py b/erpnext/stock/doctype/serial_no/serial_no.py
index 98f15a831a..333963bd66 100644
--- a/erpnext/stock/doctype/serial_no/serial_no.py
+++ b/erpnext/stock/doctype/serial_no/serial_no.py
@@ -4,6 +4,7 @@
from __future__ import unicode_literals
import frappe
+from frappe.model.naming import make_autoname
from frappe.utils import cint, cstr, flt, add_days, nowdate, getdate
from frappe import _, ValidationError
@@ -276,24 +277,31 @@ def allow_serial_nos_with_different_item(sle_serial_no, sle):
def update_serial_nos(sle, item_det):
if sle.is_cancelled == "No" and not sle.serial_no and sle.actual_qty > 0 \
and item_det.has_serial_no == 1 and item_det.serial_no_series:
- from frappe.model.naming import make_autoname
- serial_nos = []
- for i in range(cint(sle.actual_qty)):
- serial_nos.append(make_autoname(item_det.serial_no_series, "Serial No"))
- frappe.db.set(sle, "serial_no", "\n".join(serial_nos))
+ serial_nos = get_auto_serial_nos(item_det.serial_no_series, sle.actual_qty)
+ frappe.db.set(sle, "serial_no", serial_nos)
validate_serial_no(sle, item_det)
if sle.serial_no:
- serial_nos = get_serial_nos(sle.serial_no)
- for serial_no in serial_nos:
- if frappe.db.exists("Serial No", serial_no):
- sr = frappe.get_doc("Serial No", serial_no)
- sr.via_stock_ledger = True
- sr.item_code = sle.item_code
- sr.warehouse = sle.warehouse if sle.actual_qty > 0 else None
- sr.save(ignore_permissions=True)
- elif sle.actual_qty > 0:
- make_serial_no(serial_no, sle)
+ auto_make_serial_nos(sle)
+
+def get_auto_serial_nos(serial_no_series, qty):
+ serial_nos = []
+ for i in range(cint(qty)):
+ serial_nos.append(make_autoname(serial_no_series, "Serial No"))
+
+ return "\n".join(serial_nos)
+
+def auto_make_serial_nos(args):
+ serial_nos = get_serial_nos(args.get('serial_no'))
+ for serial_no in serial_nos:
+ if frappe.db.exists("Serial No", serial_no):
+ sr = frappe.get_doc("Serial No", serial_no)
+ sr.via_stock_ledger = True
+ sr.item_code = args.get('item_code')
+ sr.warehouse = args.get('warehouse') if args.get('actual_qty', 0) > 0 else None
+ sr.save(ignore_permissions=True)
+ elif args.get('actual_qty', 0) > 0:
+ make_serial_no(serial_no, args)
def get_item_details(item_code):
return frappe.db.sql("""select name, has_batch_no, docstatus,
@@ -304,20 +312,27 @@ def get_serial_nos(serial_no):
return [s.strip() for s in cstr(serial_no).strip().upper().replace(',', '\n').split('\n')
if s.strip()]
-def make_serial_no(serial_no, sle):
+def make_serial_no(serial_no, args):
sr = frappe.new_doc("Serial No")
sr.warehouse = None
sr.dont_update_if_missing.append("warehouse")
sr.flags.ignore_permissions = True
sr.serial_no = serial_no
- sr.item_code = sle.item_code
- sr.company = sle.company
- sr.via_stock_ledger = True
- sr.insert()
+ sr.item_code = args.get('item_code')
+ sr.company = args.get('company')
+ sr.via_stock_ledger = args.get('via_stock_ledger') or True
+ sr.asset = args.get('asset')
+
+ if args.get('purchase_document_type'):
+ sr.purchase_document_type = args.get('purchase_document_type')
+ sr.purchase_document_no = args.get('purchase_document_no')
+
+ sr.insert()
+ if args.get('warehouse'):
+ sr.warehouse = args.get('warehouse')
+ sr.save()
- sr.warehouse = sle.warehouse
- sr.save()
frappe.msgprint(_("Serial No {0} created").format(sr.name))
return sr.name
diff --git a/erpnext/stock/doctype/serial_no/test_serial_no.js b/erpnext/stock/doctype/serial_no/test_serial_no.js
new file mode 100644
index 0000000000..bf8293257c
--- /dev/null
+++ b/erpnext/stock/doctype/serial_no/test_serial_no.js
@@ -0,0 +1,23 @@
+/* eslint-disable */
+// rename this file from _test_[name] to test_[name] to activate
+// and remove above this line
+
+QUnit.test("test: Serial No", function (assert) {
+ let done = assert.async();
+
+ // number of asserts
+ assert.expect(1);
+
+ frappe.run_serially([
+ // insert a new Serial No
+ () => frappe.tests.make('Serial No', [
+ // values to be set
+ {key: 'value'}
+ ]),
+ () => {
+ assert.equal(cur_frm.doc.key, 'value');
+ },
+ () => done()
+ ]);
+
+});
diff --git a/erpnext/utilities/user_progress_utils.py b/erpnext/utilities/user_progress_utils.py
index 5bd855f719..20e533e91a 100644
--- a/erpnext/utilities/user_progress_utils.py
+++ b/erpnext/utilities/user_progress_utils.py
@@ -63,7 +63,7 @@ def create_suppliers(args_data):
doc = frappe.get_doc({
"doctype":"Supplier",
"supplier_name": supplier,
- "supplier_type": _("Local"),
+ "supplier_group": _("Local"),
"company": defaults.get("company")
}).insert()