From b3799989616f28b505f6cf363368dabee1a3230a Mon Sep 17 00:00:00 2001 From: deepak-mnt Date: Thu, 26 Apr 2018 17:00:08 +0530 Subject: [PATCH 01/40] Added Update Cost Center Number button and it's functionality --- .../doctype/cost_center/cost_center.js | 51 +++++++++++++++- .../doctype/cost_center/cost_center.json | 59 ++++++++++++++++--- .../doctype/cost_center/cost_center.py | 46 ++++++++++++++- 3 files changed, 147 insertions(+), 9 deletions(-) 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..3fb1f75c2d 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): @@ -66,4 +67,47 @@ class CostCenter(NestedSet): " - ".join(newdn.split(" - ")[:-1])) 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 From b712d1905d5b5357b8738759cc6262a4fb25c002 Mon Sep 17 00:00:00 2001 From: deepak-mnt Date: Thu, 26 Apr 2018 17:04:06 +0530 Subject: [PATCH 02/40] Override after_rename method to fetch cost center number on changing from title --- .../doctype/cost_center/cost_center.py | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/doctype/cost_center/cost_center.py b/erpnext/accounts/doctype/cost_center/cost_center.py index 3fb1f75c2d..24af0ce376 100644 --- a/erpnext/accounts/doctype/cost_center/cost_center.py +++ b/erpnext/accounts/doctype/cost_center/cost_center.py @@ -63,8 +63,25 @@ 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"]) From 6c92cff22657908498a6ee208965a75593fadf44 Mon Sep 17 00:00:00 2001 From: Gaurav Naik Date: Fri, 11 May 2018 07:52:50 +0530 Subject: [PATCH 03/40] Accounting Period autoname --- .../doctype/accounting_period/accounting_period.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/accounting_period/accounting_period.py b/erpnext/accounts/doctype/accounting_period/accounting_period.py index 31f18490a3..030189d88f 100644 --- a/erpnext/accounts/doctype/accounting_period/accounting_period.py +++ b/erpnext/accounts/doctype/accounting_period/accounting_period.py @@ -7,4 +7,9 @@ import frappe from frappe.model.document import Document class AccountingPeriod(Document): - pass + def validate(self): + self.validate_overlap() + + def autoname(self): + company_abbr = frappe.db.get_value("Company", self.company, "abbr") + self.name = " - ".join([self.period_name, company_abbr]) From 9502476c6753cb8c628d48e2b534d48e4ec2625b Mon Sep 17 00:00:00 2001 From: Gaurav Naik Date: Fri, 11 May 2018 07:53:12 +0530 Subject: [PATCH 04/40] Accounting Period overlap validation --- .../accounting_period/accounting_period.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/erpnext/accounts/doctype/accounting_period/accounting_period.py b/erpnext/accounts/doctype/accounting_period/accounting_period.py index 030189d88f..306bf9177e 100644 --- a/erpnext/accounts/doctype/accounting_period/accounting_period.py +++ b/erpnext/accounts/doctype/accounting_period/accounting_period.py @@ -13,3 +13,22 @@ class AccountingPeriod(Document): 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"))) + From a35dad7610d7ebb6d822956b91dedc40fe8948e6 Mon Sep 17 00:00:00 2001 From: Saurabh Date: Thu, 10 May 2018 19:47:41 +0530 Subject: [PATCH 05/40] add get leave period method --- erpnext/hr/utils.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/erpnext/hr/utils.py b/erpnext/hr/utils.py index 057f406e80..be8c948add 100644 --- a/erpnext/hr/utils.py +++ b/erpnext/hr/utils.py @@ -49,3 +49,9 @@ def update_employee(employee, details, cancel=False): new_data = get_datetime(new_data) setattr(employee, item.fieldname, new_data) return employee + + +def get_leave_period(from_date, to_date, company): + return frappe.db.sql("""select name from `tabLeave Period` + where is_active=1 and company=%s + and to_date >= %s and from_date <= %s""", (company, to_date, from_date)) From c1acbdfb690f4ce7d410c2ae342fff205b07ac3c Mon Sep 17 00:00:00 2001 From: Saurabh Date: Sat, 12 May 2018 17:45:22 +0530 Subject: [PATCH 06/40] [fix] overlapping dates --- erpnext/hr/utils.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/erpnext/hr/utils.py b/erpnext/hr/utils.py index be8c948add..686f79170c 100644 --- a/erpnext/hr/utils.py +++ b/erpnext/hr/utils.py @@ -50,8 +50,19 @@ def update_employee(employee, details, cancel=False): setattr(employee, item.fieldname, new_data) return employee - def get_leave_period(from_date, to_date, company): - return frappe.db.sql("""select name from `tabLeave Period` - where is_active=1 and company=%s - and to_date >= %s and from_date <= %s""", (company, to_date, from_date)) + leave_period = frappe.db.sql(""" + select name, from_date, to_date + from `tabLeave Period` + where company=%(company)s and is_active=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)) + """, { + "from_date": from_date, + "to_date": to_date, + "company": company + }, as_dict=1) + + if leave_period: + return leave_period From 4bd7cdb018201db7835e19e0d736a340dae485d7 Mon Sep 17 00:00:00 2001 From: Jamsheer Date: Wed, 9 May 2018 15:55:33 +0530 Subject: [PATCH 07/40] Salary Structure Assignment - filters applied --- .../salary_structure_assignment.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 af4ca3a3b5..56a05e0495 100644 --- a/erpnext/hr/doctype/salary_structure_assignment/salary_structure_assignment.js +++ b/erpnext/hr/doctype/salary_structure_assignment/salary_structure_assignment.js @@ -15,8 +15,8 @@ frappe.ui.form.on('Salary Structure Assignment', { return { filters: { company: frm.doc.company, - is_active: "Yes", - docstatus: 1 + docstatus: 1, + is_active: "Yes" } } }); From b5c5c471b461ddc8a329a5fd462ae4ecd0f8070b Mon Sep 17 00:00:00 2001 From: Jamsheer Date: Wed, 9 May 2018 17:23:06 +0530 Subject: [PATCH 08/40] Formula on Salary Component Master --- .../salary_component/salary_component.json | 223 +++++++++++++++++- 1 file changed, 222 insertions(+), 1 deletion(-) diff --git a/erpnext/hr/doctype/salary_component/salary_component.json b/erpnext/hr/doctype/salary_component/salary_component.json index 5f875a9948..f1f5946342 100644 --- a/erpnext/hr/doctype/salary_component/salary_component.json +++ b/erpnext/hr/doctype/salary_component/salary_component.json @@ -108,6 +108,131 @@ "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, @@ -138,6 +263,102 @@ "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, @@ -972,4 +1193,4 @@ "sort_order": "DESC", "track_changes": 0, "track_seen": 0 -} \ No newline at end of file +} From a5028c8e54c5bc4fc1fc66fd8538c38d99dc9870 Mon Sep 17 00:00:00 2001 From: Jamsheer Date: Wed, 9 May 2018 17:40:27 +0530 Subject: [PATCH 09/40] Salary Structure - filter updated, Salary Component - fields re-arranged --- .../salary_component/salary_component.json | 535 ++++++++++-------- 1 file changed, 314 insertions(+), 221 deletions(-) diff --git a/erpnext/hr/doctype/salary_component/salary_component.json b/erpnext/hr/doctype/salary_component/salary_component.json index f1f5946342..f08b1d7a0b 100644 --- a/erpnext/hr/doctype/salary_component/salary_component.json +++ b/erpnext/hr/doctype/salary_component/salary_component.json @@ -108,131 +108,6 @@ "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, @@ -263,102 +138,6 @@ "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, @@ -1114,6 +893,320 @@ "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\n

Notes:

\n\n
    \n
  1. Use field base for using base salary of the Employee
  2. \n
  3. Use Salary Component abbreviations in conditions and formulas. BS = Basic Salary
  4. \n
  5. Use field name for employee details in conditions and formulas. Employment Type = employment_typeBranch = branch
  6. \n
  7. Use field name from Salary Slip in conditions and formulas. Payment Days = payment_daysLeave without pay = leave_without_pay
  8. \n
  9. Direct Amount can also be entered based on Condtion. See example 3
\n\n

Examples

\n
    \n
  1. Calculating Basic Salary based on base\n
    Condition: base < 10000
    \n
    Formula: base * .2
  2. \n
  3. Calculating HRA based on Basic SalaryBS \n
    Condition: BS > 2000
    \n
    Formula: BS * .1
  4. \n
  5. Calculating TDS based on Employment Typeemployment_type \n
    Condition: employment_type==\"Intern\"
    \n
    Amount: 1000
  6. \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, From 08b60a1a62fb8cc98248f540c2c03da6117f6b13 Mon Sep 17 00:00:00 2001 From: Jamsheer Date: Thu, 10 May 2018 13:16:24 +0530 Subject: [PATCH 10/40] New Doctype - Additional Salary Component --- erpnext/config/hr.py | 4 + .../additional_salary_component/__init__.py | 0 .../additional_salary_component.js | 21 + .../additional_salary_component.json | 364 ++++++++++++++++++ .../additional_salary_component.py | 26 ++ .../test_additional_salary_component.js | 23 ++ .../test_additional_salary_component.py | 10 + 7 files changed, 448 insertions(+) create mode 100644 erpnext/hr/doctype/additional_salary_component/__init__.py create mode 100644 erpnext/hr/doctype/additional_salary_component/additional_salary_component.js create mode 100644 erpnext/hr/doctype/additional_salary_component/additional_salary_component.json create mode 100644 erpnext/hr/doctype/additional_salary_component/additional_salary_component.py create mode 100644 erpnext/hr/doctype/additional_salary_component/test_additional_salary_component.js create mode 100644 erpnext/hr/doctype/additional_salary_component/test_additional_salary_component.py diff --git a/erpnext/config/hr.py b/erpnext/config/hr.py index 4e9e91ef3b..e1c589fe09 100644 --- a/erpnext/config/hr.py +++ b/erpnext/config/hr.py @@ -123,6 +123,10 @@ def get_data(): "type": "doctype", "name": "Salary Component", }, + { + "type": "doctype", + "name": "Additional Salary Component", + }, { "type": "doctype", "name": "Salary Structure", 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..36bfdf2a08 --- /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..0591082b4a --- /dev/null +++ b/erpnext/hr/doctype/additional_salary_component/additional_salary_component.py @@ -0,0 +1,26 @@ +# -*- 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 import formatdate, format_datetime, getdate, get_datetime, nowdate +from erpnext.hr.utils import validate_dates + +class AdditionalSalaryComponent(Document): + def validate(self): + # self.validate_dates() + validate_dates(self, self.from_date, self.to_date) + + # 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(to_date): + # frappe.throw(_("To date can not be less than from date")) + # elif getdate(self.from_date) > getdate(nowdate()): + # frappe.throw(_("Future dates not allowed")) + # 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(to_date) > getdate(relieving_date): + # frappe.throw(_("To date can not greater than employee's relieving date")) 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..6859da1c0b --- /dev/null +++ b/erpnext/hr/doctype/additional_salary_component/test_additional_salary_component.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 TestAdditionalSalaryComponent(unittest.TestCase): + pass From d0b0c87f4034261d3431e83eb0fdab24b50e2289 Mon Sep 17 00:00:00 2001 From: Jamsheer Date: Fri, 11 May 2018 11:33:07 +0530 Subject: [PATCH 11/40] get additional salary component in salary slip --- .../additional_salary_component.py | 80 +++++++++++++++---- erpnext/hr/doctype/salary_slip/salary_slip.py | 7 ++ 2 files changed, 72 insertions(+), 15 deletions(-) diff --git a/erpnext/hr/doctype/additional_salary_component/additional_salary_component.py b/erpnext/hr/doctype/additional_salary_component/additional_salary_component.py index 0591082b4a..216dea0403 100644 --- a/erpnext/hr/doctype/additional_salary_component/additional_salary_component.py +++ b/erpnext/hr/doctype/additional_salary_component/additional_salary_component.py @@ -5,22 +5,72 @@ from __future__ import unicode_literals import frappe from frappe.model.document import Document -from frappe.utils import formatdate, format_datetime, getdate, get_datetime, nowdate -from erpnext.hr.utils import validate_dates +from frappe import _ +from frappe.utils import getdate, date_diff class AdditionalSalaryComponent(Document): def validate(self): - # self.validate_dates() - validate_dates(self, self.from_date, self.to_date) + 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(to_date): - # frappe.throw(_("To date can not be less than from date")) - # elif getdate(self.from_date) > getdate(nowdate()): - # frappe.throw(_("Future dates not allowed")) - # 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(to_date) > getdate(relieving_date): - # frappe.throw(_("To date can not greater than employee's relieving date")) + 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/salary_slip/salary_slip.py b/erpnext/hr/doctype/salary_slip/salary_slip.py index 99de580a3f..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): From 236be226484abc538b79fca4f03d4aac26dd6f8b Mon Sep 17 00:00:00 2001 From: Jamsheer Date: Mon, 14 May 2018 13:32:50 +0530 Subject: [PATCH 12/40] Payroll entry - get employee fix --- erpnext/hr/doctype/payroll_entry/payroll_entry.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/erpnext/hr/doctype/payroll_entry/payroll_entry.py b/erpnext/hr/doctype/payroll_entry/payroll_entry.py index e1b841f9b9..0dd2b4cb07 100644 --- a/erpnext/hr/doctype/payroll_entry/payroll_entry.py +++ b/erpnext/hr/doctype/payroll_entry/payroll_entry.py @@ -38,19 +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.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 Assignment` t2 where t1.docstatus!=2 and t1.name = t2.employee and t2.docstatus = 1 - %s """% cond, {"sal_struct": sal_struct}, as_dict=True) + %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): From 366ca92ba75b21cb3e986b9bb46f60dd114bb3f6 Mon Sep 17 00:00:00 2001 From: Zlash65 Date: Wed, 18 Apr 2018 16:11:38 +0530 Subject: [PATCH 13/40] move default_currency on top --- erpnext/setup/doctype/company/company.json | 86 +++++++++++----------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/erpnext/setup/doctype/company/company.json b/erpnext/setup/doctype/company/company.json index 66b1433eb1..d236dda873 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, From 39668609ce0df12132a622ca274d36f596d3a8cc Mon Sep 17 00:00:00 2001 From: Zlash65 Date: Wed, 18 Apr 2018 18:13:24 +0530 Subject: [PATCH 14/40] improv department tree --- erpnext/hr/doctype/department/department.py | 21 ++++++++++++++- .../hr/doctype/department/department_tree.js | 26 ++++++++++++++++++- 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/erpnext/hr/doctype/department/department.py b/erpnext/hr/doctype/department/department.py index fda1b69de2..f1e0aeed8e 100644 --- a/erpnext/hr/doctype/department/department.py +++ b/erpnext/hr/doctype/department/department.py @@ -21,4 +21,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 From 9a8f5bd6c73b58b77a2ca8a18a882cc0c60723e5 Mon Sep 17 00:00:00 2001 From: Zlash65 Date: Fri, 11 May 2018 12:36:54 +0530 Subject: [PATCH 15/40] set department name with company abbr --- erpnext/hr/doctype/department/department.json | 4 ++-- erpnext/hr/doctype/department/department.py | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) 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 f1e0aeed8e..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) From 03ad0f2f4a0a73a715de65b7900ec8ffa1f00b90 Mon Sep 17 00:00:00 2001 From: Zlash65 Date: Fri, 11 May 2018 16:57:44 +0530 Subject: [PATCH 16/40] set query for department based on company --- erpnext/assets/doctype/asset/asset.js | 8 +++ .../doctype/instructor/instructor.js | 72 ++++++++++++------- erpnext/hr/doctype/employee/employee.js | 9 +++ erpnext/hr/doctype/job_opening/job_opening.js | 9 +++ .../leave_control_panel.js | 17 ++++- .../hr/doctype/leave_period/leave_period.js | 10 ++- .../hr/doctype/payroll_entry/payroll_entry.js | 8 +++ .../hr/doctype/staffing_plan/staffing_plan.js | 8 +++ 8 files changed, 112 insertions(+), 29 deletions(-) diff --git a/erpnext/assets/doctype/asset/asset.js b/erpnext/assets/doctype/asset/asset.js index 236c4f9f9b..f4a01aefca 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) { 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/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/job_opening/job_opening.js b/erpnext/hr/doctype/job_opening/job_opening.js index 960f5b3c65..7b0e447a9e 100644 --- a/erpnext/hr/doctype/job_opening/job_opening.js +++ b/erpnext/hr/doctype/job_opening/job_opening.js @@ -2,6 +2,15 @@ // 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({ 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 2a6010e44f..a54147d18a 100644 --- a/erpnext/hr/doctype/leave_period/leave_period.js +++ b/erpnext/hr/doctype/leave_period/leave_period.js @@ -2,7 +2,13 @@ // For license information, please see license.txt frappe.ui.form.on('Leave Period', { - refresh: function(frm) { - + onload: function(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/staffing_plan/staffing_plan.js b/erpnext/hr/doctype/staffing_plan/staffing_plan.js index 1c1a720088..ca57d9f19d 100644 --- a/erpnext/hr/doctype/staffing_plan/staffing_plan.js +++ b/erpnext/hr/doctype/staffing_plan/staffing_plan.js @@ -17,6 +17,14 @@ frappe.ui.form.on('Staffing Plan', { ] } }); + + frm.set_query("department", function() { + return { + "filters": { + "company": frm.doc.company, + } + }; + }); } }); From d25a264e5bd5258cb6dea894e18d1393fd814da1 Mon Sep 17 00:00:00 2001 From: Zlash65 Date: Sun, 13 May 2018 14:34:20 +0530 Subject: [PATCH 17/40] create and update department records patch --- erpnext/patches.txt | 1 + ...ate_department_records_for_each_company.py | 51 +++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 erpnext/patches/v11_0/create_department_records_for_each_company.py diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 3fffade9bb..4bbb3e9e70 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -527,3 +527,4 @@ 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.create_department_records_for_each_company 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..514c709071 --- /dev/null +++ b/erpnext/patches/v11_0/create_department_records_for_each_company.py @@ -0,0 +1,51 @@ +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) + +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)), debug=1) From 06fd51bf696a0344c6ebc8df77f2ebe307e93871 Mon Sep 17 00:00:00 2001 From: Zlash65 Date: Mon, 14 May 2018 17:16:27 +0530 Subject: [PATCH 18/40] patch fix for instructor --- ...ate_department_records_for_each_company.py | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) 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 index 514c709071..94071857d7 100644 --- a/erpnext/patches/v11_0/create_department_records_for_each_company.py +++ b/erpnext/patches/v11_0/create_department_records_for_each_company.py @@ -32,6 +32,8 @@ def execute(): 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: @@ -48,4 +50,24 @@ def update_records(doctype, comp_dict): `tab%s` set department = CASE %s END - """%(doctype, " ".join(when_then)), debug=1) + """%(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))) From 32b3aa257c65ac0182b07e79bdc987a258e99564 Mon Sep 17 00:00:00 2001 From: Gaurav Naik Date: Mon, 14 May 2018 18:02:24 +0530 Subject: [PATCH 19/40] [Fix] Indentation for accounting_period overlap --- .../accounting_period/accounting_period.py | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/erpnext/accounts/doctype/accounting_period/accounting_period.py b/erpnext/accounts/doctype/accounting_period/accounting_period.py index 306bf9177e..8760d8f35e 100644 --- a/erpnext/accounts/doctype/accounting_period/accounting_period.py +++ b/erpnext/accounts/doctype/accounting_period/accounting_period.py @@ -15,20 +15,20 @@ class AccountingPeriod(Document): 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) + 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"))) + if len(existing_accounting_period) > 0: + frappe.throw("Accounting Period overlaps with {0}".format(existing_accounting_period[0].get("name"))) From 2fe38c3ff5b89c72e5a15f365e6a005370bc0c8f Mon Sep 17 00:00:00 2001 From: Gaurav Naik Date: Mon, 14 May 2018 18:06:34 +0530 Subject: [PATCH 20/40] Bootstrap documents for closing --- .../accounting_period/accounting_period.py | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/erpnext/accounts/doctype/accounting_period/accounting_period.py b/erpnext/accounts/doctype/accounting_period/accounting_period.py index 8760d8f35e..f2ba578965 100644 --- a/erpnext/accounts/doctype/accounting_period/accounting_period.py +++ b/erpnext/accounts/doctype/accounting_period/accounting_period.py @@ -10,6 +10,9 @@ class AccountingPeriod(Document): 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]) @@ -32,3 +35,20 @@ class AccountingPeriod(Document): 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 self.closed_documents.length == 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 + }) From 52571a80daef6bba3ffeb10712183347bd69ad41 Mon Sep 17 00:00:00 2001 From: Gaurav Naik Date: Mon, 14 May 2018 18:06:50 +0530 Subject: [PATCH 21/40] Bootstrap documents for closing (js) --- .../accounting_period/accounting_period.js | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) 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"); + } + } + }); + } } }); From caaebb9d2ac1c3b6cd421a23619e799f80fe7116 Mon Sep 17 00:00:00 2001 From: Gaurav Naik Date: Mon, 14 May 2018 18:11:09 +0530 Subject: [PATCH 22/40] [WIP] Accounting Period Test cases --- .../test_accounting_period.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) 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 From 21b2df41accea57653f39891ab0bd30b801ed6dc Mon Sep 17 00:00:00 2001 From: Gaurav Naik Date: Mon, 14 May 2018 18:15:47 +0530 Subject: [PATCH 23/40] [Fix] len() instead of .length --- erpnext/accounts/doctype/accounting_period/accounting_period.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/accounting_period/accounting_period.py b/erpnext/accounts/doctype/accounting_period/accounting_period.py index f2ba578965..32441db2c1 100644 --- a/erpnext/accounts/doctype/accounting_period/accounting_period.py +++ b/erpnext/accounts/doctype/accounting_period/accounting_period.py @@ -46,7 +46,7 @@ class AccountingPeriod(Document): return docs_for_closing def bootstrap_doctypes_for_closing(self): - if self.closed_documents.length == 0: + 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, From 47039e801e27a83984c1bcc851bc526c227235e4 Mon Sep 17 00:00:00 2001 From: Jamsheer Date: Mon, 14 May 2018 18:54:10 +0530 Subject: [PATCH 24/40] Remove unused import --- .../test_additional_salary_component.py | 2 -- 1 file changed, 2 deletions(-) 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 index 6859da1c0b..eda2f79dc9 100644 --- a/erpnext/hr/doctype/additional_salary_component/test_additional_salary_component.py +++ b/erpnext/hr/doctype/additional_salary_component/test_additional_salary_component.py @@ -2,8 +2,6 @@ # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt from __future__ import unicode_literals - -import frappe import unittest class TestAdditionalSalaryComponent(unittest.TestCase): From ab842541887cc8c0cda245cef88940e911731b97 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Thu, 26 Apr 2018 19:18:29 +0530 Subject: [PATCH 25/40] Asset linked to purchase receipt and serial no --- .../purchase_invoice/purchase_invoice.py | 17 -- .../purchase_invoice_item.json | 2 +- erpnext/assets/doctype/asset/asset.js | 3 +- erpnext/assets/doctype/asset/asset.json | 109 ++++++++++- erpnext/assets/doctype/asset/asset.py | 25 ++- .../assets/doctype/asset/asset_dashboard.py | 7 + .../asset_maintenance/asset_maintenance.json | 49 ++++- .../asset_maintenance/asset_maintenance.py | 3 + .../asset_movement/asset_movement.json | 171 +++++++++++++++++- .../doctype/asset_movement/asset_movement.py | 17 +- erpnext/controllers/accounts_controller.py | 52 +++--- erpnext/controllers/buying_controller.py | 126 +++++++++++++ erpnext/setup/doctype/company/company.js | 8 + erpnext/stock/doctype/item/item.json | 12 +- erpnext/stock/doctype/item/item.py | 2 +- .../purchase_receipt/purchase_receipt.js | 14 ++ .../purchase_receipt/purchase_receipt.py | 2 + .../purchase_receipt_dashboard.py | 3 +- .../purchase_receipt/test_purchase_receipt.py | 42 ++++- .../purchase_receipt_item.json | 66 ++++++- .../stock/doctype/serial_no/serial_no.json | 78 +++++++- erpnext/stock/doctype/serial_no/serial_no.py | 56 +++--- erpnext/stock/get_item_details.py | 4 + 23 files changed, 763 insertions(+), 105 deletions(-) diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py index 67b41a3248..d2cc4eea9f 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -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 @@ -636,7 +620,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) 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/assets/doctype/asset/asset.js b/erpnext/assets/doctype/asset/asset.js index f4a01aefca..edc1e364f5 100644 --- a/erpnext/assets/doctype/asset/asset.js +++ b/erpnext/assets/doctype/asset/asset.js @@ -181,7 +181,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) { diff --git a/erpnext/assets/doctype/asset/asset.json b/erpnext/assets/doctype/asset/asset.json index 49b574d3b0..63b9167cc6 100644 --- a/erpnext/assets/doctype/asset/asset.json +++ b/erpnext/assets/doctype/asset/asset.json @@ -40,6 +40,7 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -71,6 +72,7 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -102,6 +104,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 }, { @@ -165,6 +169,7 @@ "reqd": 0, "search_index": 0, "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 }, { @@ -228,6 +234,7 @@ "reqd": 0, "search_index": 0, "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 }, { @@ -322,6 +331,38 @@ "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": "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": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -351,6 +392,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -382,6 +424,7 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -413,6 +456,7 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -444,6 +488,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -474,6 +519,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": "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, + "translatable": 0, "unique": 0 }, { @@ -505,6 +583,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -535,6 +614,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -565,6 +645,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -595,6 +676,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -626,6 +708,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -655,6 +738,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -686,6 +770,7 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -715,6 +800,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -747,6 +833,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -779,6 +866,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -808,6 +896,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -838,6 +927,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -869,6 +959,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -902,6 +993,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -933,6 +1025,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -963,6 +1056,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -992,6 +1086,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -1023,6 +1118,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -1053,6 +1149,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -1084,6 +1181,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -1115,6 +1213,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -1146,6 +1245,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -1176,6 +1276,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -1207,6 +1308,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -1237,6 +1339,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 } ], @@ -1251,7 +1354,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2018-01-05 09:53:05.945328", + "modified": "2018-04-19 20:03:13.669957", "modified_by": "Administrator", "module": "Assets", "name": "Asset", @@ -1260,7 +1363,6 @@ "permissions": [ { "amend": 1, - "apply_user_permissions": 0, "cancel": 1, "create": 1, "delete": 1, @@ -1280,7 +1382,6 @@ }, { "amend": 0, - "apply_user_permissions": 0, "cancel": 1, "create": 1, "delete": 1, @@ -1307,4 +1408,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..a9cc924b8f 100644 --- a/erpnext/assets/doctype/asset/asset.py +++ b/erpnext/assets/doctype/asset/asset.py @@ -10,6 +10,7 @@ from frappe.model.document import Document from erpnext.accounts.doctype.purchase_invoice.purchase_invoice import get_fixed_asset_account from erpnext.assets.doctype.asset.depreciation \ import get_disposal_account_and_cost_center, get_depreciation_accounts +from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos class Asset(Document): def validate(self): @@ -26,12 +27,16 @@ class Asset(Document): def on_submit(self): self.set_status() + self.update_stock_movement() def on_cancel(self): self.validate_cancellation() self.delete_depreciation_entries() self.set_status() + def on_update(self): + self.update_serial_nos() + def validate_item(self): item = frappe.db.get_value("Item", self.item_code, ["is_fixed_asset", "is_stock_item", "disabled"], as_dict=1) @@ -219,6 +224,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: @@ -250,6 +258,20 @@ class Asset(Document): status = "Cancelled" return status + def update_serial_nos(self): + if self.serial_no: + serial_nos = get_serial_nos(self.serial_no) + frappe.db.sql(""" update `tabSerial No` set asset = '%s' where + name in(%s)"""%(self.name, ','.join(['%s'] * len(serial_nos))), tuple(serial_nos)) + + 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 update_maintenance_status(): assets = frappe.get_all('Asset', filters = {'docstatus': 1, 'maintenance_required': 1}) @@ -280,7 +302,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): si = frappe.new_doc("Sales Invoice") si.company = company si.currency = frappe.db.get_value("Company", company, "default_currency") @@ -290,6 +312,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 }) 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_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..3c3a1dc9cd 100644 --- a/erpnext/assets/doctype/asset_movement/asset_movement.json +++ b/erpnext/assets/doctype/asset_movement/asset_movement.json @@ -12,6 +12,39 @@ "document_type": "", "editable_grid": 0, "fields": [ + { + "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": "Receipt\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": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_on_submit": 0, @@ -41,6 +74,7 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -71,6 +105,7 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -102,6 +137,38 @@ "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, + "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 }, { @@ -131,6 +198,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -162,6 +230,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -193,6 +262,102 @@ "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": "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, + "translatable": 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, + "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": "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": 0, + "in_standard_filter": 0, + "label": "Reference Name", + "length": 0, + "no_copy": 1, + "options": "reference_doctype", + "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 }, { @@ -223,6 +388,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 } ], @@ -236,7 +402,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2017-10-19 16:08:17.389257", + "modified": "2018-04-20 15:45:54.156501", "modified_by": "Administrator", "module": "Assets", "name": "Asset Movement", @@ -245,7 +411,6 @@ "permissions": [ { "amend": 1, - "apply_user_permissions": 0, "cancel": 1, "create": 1, "delete": 1, @@ -265,7 +430,6 @@ }, { "amend": 1, - "apply_user_permissions": 0, "cancel": 1, "create": 1, "delete": 1, @@ -285,7 +449,6 @@ }, { "amend": 1, - "apply_user_permissions": 0, "cancel": 1, "create": 1, "delete": 1, diff --git a/erpnext/assets/doctype/asset_movement/asset_movement.py b/erpnext/assets/doctype/asset_movement/asset_movement.py index 574c49992b..42ed249959 100644 --- a/erpnext/assets/doctype/asset_movement/asset_movement.py +++ b/erpnext/assets/doctype/asset_movement/asset_movement.py @@ -11,19 +11,22 @@ 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 + def validate_warehouses(self): - if not self.source_warehouse: + if self.purpose == 'Transfer' and 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")) diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index c70cfcd811..40028afb01 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -600,40 +600,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..c340901e3b 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 from erpnext.controllers.stock_controller import StockController @@ -439,6 +440,11 @@ class BuyingController(StockController): if self.get('is_return'): return + if self.doctype in ['Purchase Receipt', 'Purchase Invoice']: + if self.doctype == 'Purchase Receipt': + self.process_fixed_asset() + self.update_fixed_asset() + update_last_purchase_rate(self, is_submit = 1) def on_cancel(self): @@ -446,6 +452,118 @@ class BuyingController(StockController): return update_last_purchase_rate(self, is_submit = 0) + if self.doctype in ['Purchase Receipt', 'Purchase Invoice']: + if self.doctype == 'Purchase Receipt': + self.delete_linked_asset() + self.update_fixed_asset() + + def process_fixed_asset(self): + if not self.doctype in ['Purchase Receipt', 'Purchase Invoice']: + return + + asset_items = [d.item_code for d in self.items if d.is_fixed_asset] + 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 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 + }) + d.db_set('serial_no', serial_nos) + + if not d.asset: + asset = self.make_asset(d) + d.db_set('asset', asset) + + if d.asset: + self.make_asset_movement(d) + + def make_asset(self, row): + asset = frappe.get_doc({ + 'doctype': 'Asset', + 'item_code': row.item_code, + 'asset_name': '{0} - {1}'.format(self.name, row.item_code), + 'warehouse': row.warehouse, + 'serial_no': row.serial_no, + 'company': self.company, + 'purchase_date': self.posting_date, + '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.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, + 'source_warehouse': '', + 'target_warehouse': row.warehouse, + 'purpose': 'Receipt', + 'serial_no': 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 = 'purchase_invoice' if self.doctype == 'Purchase Invoice' else 'purchase_receipt' + + for d in self.get("items"): + if d.is_fixed_asset and d.asset: + asset = frappe.get_doc("Asset", d.asset) + 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 + else: + 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 not self.doctype in ['Purchase Receipt', 'Purchase Invoice']: + return + + if self.doctype == 'Purchase Invoice' and 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 +598,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/setup/doctype/company/company.js b/erpnext/setup/doctype/company/company.js index e164d6949f..d4095772cd 100644 --- a/erpnext/setup/doctype/company/company.js +++ b/erpnext/setup/doctype/company/company.js @@ -5,6 +5,14 @@ frappe.provide("erpnext.company"); frappe.ui.form.on("Company", { setup: function(frm) { + frm.fields_dict.fixed_asset_account.get_query = function() { + return { + filters: { + account_type: "Fixed Asset", + company: frm.doc.name + } + } + } erpnext.company.setup_queries(frm); }, diff --git a/erpnext/stock/doctype/item/item.json b/erpnext/stock/doctype/item/item.json index 21900ad440..251717e127 100644 --- a/erpnext/stock/doctype/item/item.json +++ b/erpnext/stock/doctype/item/item.json @@ -1285,7 +1285,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 +1513,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", @@ -3725,7 +3725,6 @@ "permissions": [ { "amend": 0, - "apply_user_permissions": 0, "cancel": 0, "create": 1, "delete": 1, @@ -3745,7 +3744,6 @@ }, { "amend": 0, - "apply_user_permissions": 0, "cancel": 0, "create": 0, "delete": 0, @@ -3765,7 +3763,6 @@ }, { "amend": 0, - "apply_user_permissions": 0, "cancel": 0, "create": 0, "delete": 0, @@ -3785,7 +3782,6 @@ }, { "amend": 0, - "apply_user_permissions": 0, "cancel": 0, "create": 0, "delete": 0, @@ -3805,7 +3801,6 @@ }, { "amend": 0, - "apply_user_permissions": 0, "cancel": 0, "create": 0, "delete": 0, @@ -3825,7 +3820,6 @@ }, { "amend": 0, - "apply_user_permissions": 0, "cancel": 0, "create": 0, "delete": 0, @@ -3845,7 +3839,6 @@ }, { "amend": 0, - "apply_user_permissions": 0, "cancel": 0, "create": 0, "delete": 0, @@ -3865,7 +3858,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..fafdaab51f 100644 --- a/erpnext/stock/doctype/item/item.py +++ b/erpnext/stock/doctype/item/item.py @@ -444,7 +444,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..c7083be286 100644 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py @@ -393,6 +393,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..a7b0a03c0a 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,70 @@ "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, @@ -2395,7 +2459,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2018-02-22 15:15:38.793425", + "modified": "2018-04-23 14:07:48.438379", "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..fa4fa694c1 100644 --- a/erpnext/stock/doctype/serial_no/serial_no.json +++ b/erpnext/stock/doctype/serial_no/serial_no.json @@ -41,6 +41,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -69,6 +70,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -100,6 +102,7 @@ "reqd": 1, "search_index": 1, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -132,6 +135,7 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -165,6 +169,39 @@ "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": "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, + "translatable": 0, "unique": 0 }, { @@ -193,6 +230,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -222,6 +260,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -253,6 +292,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0, "width": "300px" }, @@ -287,6 +327,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -319,6 +360,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -348,6 +390,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, "width": "50%" }, @@ -407,6 +451,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -437,6 +482,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -468,6 +514,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -497,6 +544,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -529,6 +577,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -557,6 +606,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0, "width": "50%" }, @@ -588,6 +638,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -617,6 +668,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -647,6 +699,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -677,6 +730,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -707,6 +761,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -738,6 +793,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -767,6 +823,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -799,6 +856,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -827,6 +885,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0, "width": "50%" }, @@ -860,6 +919,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -891,6 +951,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -921,6 +982,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -952,6 +1014,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -981,6 +1044,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -1009,6 +1073,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0, "width": "50%" }, @@ -1042,6 +1107,7 @@ "reqd": 0, "search_index": 1, "set_only_once": 0, + "translatable": 0, "unique": 0, "width": "150px" }, @@ -1074,6 +1140,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0, "width": "150px" }, @@ -1103,6 +1170,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0, "width": "50%" }, @@ -1135,6 +1203,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0, "width": "150px" }, @@ -1167,6 +1236,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0, "width": "150px" }, @@ -1197,6 +1267,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -1226,6 +1297,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -1256,6 +1328,7 @@ "reqd": 1, "search_index": 1, "set_only_once": 0, + "translatable": 0, "unique": 0 } ], @@ -1270,7 +1343,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2017-05-15 18:22:23.685286", + "modified": "2018-04-19 20:25:52.066995", "modified_by": "Administrator", "module": "Stock", "name": "Serial No", @@ -1278,7 +1351,6 @@ "permissions": [ { "amend": 0, - "apply_user_permissions": 0, "cancel": 0, "create": 1, "delete": 1, @@ -1298,7 +1370,6 @@ }, { "amend": 0, - "apply_user_permissions": 0, "cancel": 0, "create": 0, "delete": 0, @@ -1318,7 +1389,6 @@ }, { "amend": 0, - "apply_user_permissions": 0, "cancel": 0, "create": 0, "delete": 0, diff --git a/erpnext/stock/doctype/serial_no/serial_no.py b/erpnext/stock/doctype/serial_no/serial_no.py index 98f15a831a..17bf1bb1c3 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,26 @@ 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.item_code = args.get('item_code') + sr.company = args.get('company') + sr.via_stock_ledger = args.get('via_stock_ledger') or True sr.insert() - sr.warehouse = sle.warehouse - sr.save() + if args.get('purchase_document_type'): + sr.purchase_document_type = args.get('purchase_document_type') + sr.purchase_document_no = args.get('purchase_document_no') + + if args.get('warehouse'): + sr.warehouse = args.get('warehouse') + sr.save() + frappe.msgprint(_("Serial No {0} created").format(sr.name)) return sr.name diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py index 7e456dd3d3..0d03b4d2ec 100644 --- a/erpnext/stock/get_item_details.py +++ b/erpnext/stock/get_item_details.py @@ -287,6 +287,10 @@ def get_default_income_account(args, item): or frappe.db.get_value("Item Group", item.item_group, "default_income_account")) def get_default_expense_account(args, item): + if item and item.is_fixed_asset: + return frappe.db.get_value("Company", args.company, "fixed_asset_account") + if account: return account + return (item.expense_account or args.expense_account or frappe.db.get_value("Item Group", item.item_group, "default_expense_account")) From c6deb13fb424817b499b725e429ab0481fe7ac97 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Mon, 7 May 2018 15:58:41 +0530 Subject: [PATCH 26/40] Added account fields in the company, fixes in auto creation of the asset from PR --- erpnext/accounts/doctype/account/account.json | 4 +- erpnext/assets/doctype/asset/asset.json | 37 ++- erpnext/assets/doctype/asset/asset.py | 14 +- erpnext/assets/doctype/location/__init__.py | 0 erpnext/assets/doctype/location/location.js | 8 + erpnext/assets/doctype/location/location.json | 213 ++++++++++++++++++ erpnext/assets/doctype/location/location.py | 10 + .../assets/doctype/location/test_location.js | 23 ++ .../assets/doctype/location/test_location.py | 10 + erpnext/config/assets.py | 5 + erpnext/controllers/buying_controller.py | 42 ++-- erpnext/setup/doctype/company/company.js | 11 +- erpnext/setup/doctype/company/company.json | 98 +++++++- erpnext/stock/doctype/item/item.js | 19 +- erpnext/stock/doctype/item/item.json | 36 ++- erpnext/stock/doctype/item/item.py | 9 + .../purchase_receipt_item.json | 35 ++- erpnext/stock/doctype/serial_no/serial_no.py | 1 + erpnext/stock/get_item_details.py | 4 - 19 files changed, 525 insertions(+), 54 deletions(-) create mode 100644 erpnext/assets/doctype/location/__init__.py create mode 100644 erpnext/assets/doctype/location/location.js create mode 100644 erpnext/assets/doctype/location/location.json create mode 100644 erpnext/assets/doctype/location/location.py create mode 100644 erpnext/assets/doctype/location/test_location.js create mode 100644 erpnext/assets/doctype/location/test_location.py 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/assets/doctype/asset/asset.json b/erpnext/assets/doctype/asset/asset.json index 63b9167cc6..536b4dc522 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,39 @@ "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, + "translatable": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_on_submit": 0, @@ -1354,7 +1387,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2018-04-19 20:03:13.669957", + "modified": "2018-05-07 15:25:06.456992", "modified_by": "Administrator", "module": "Assets", "name": "Asset", diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py index a9cc924b8f..adcc986f66 100644 --- a/erpnext/assets/doctype/asset/asset.py +++ b/erpnext/assets/doctype/asset/asset.py @@ -10,7 +10,6 @@ from frappe.model.document import Document from erpnext.accounts.doctype.purchase_invoice.purchase_invoice import get_fixed_asset_account from erpnext.assets.doctype.asset.depreciation \ import get_disposal_account_and_cost_center, get_depreciation_accounts -from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos class Asset(Document): def validate(self): @@ -34,9 +33,6 @@ class Asset(Document): self.delete_depreciation_entries() self.set_status() - def on_update(self): - self.update_serial_nos() - def validate_item(self): item = frappe.db.get_value("Item", self.item_code, ["is_fixed_asset", "is_stock_item", "disabled"], as_dict=1) @@ -258,12 +254,6 @@ class Asset(Document): status = "Cancelled" return status - def update_serial_nos(self): - if self.serial_no: - serial_nos = get_serial_nos(self.serial_no) - frappe.db.sql(""" update `tabSerial No` set asset = '%s' where - name in(%s)"""%(self.name, ','.join(['%s'] * len(serial_nos))), tuple(serial_nos)) - def update_stock_movement(self): asset_movement = frappe.db.get_value('Asset Movement', {'asset': self.name, 'reference_name': self.purchase_receipt, 'docstatus': 0}, 'name') @@ -282,6 +272,10 @@ def update_maintenance_status(): if frappe.db.exists('Asset Repair', {'asset_name': asset.name, 'repair_status': 'Pending'}): asset.set_status('Out of Order') +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") 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..13ef66224d --- /dev/null +++ b/erpnext/assets/doctype/location/location.json @@ -0,0 +1,213 @@ +{ + "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": 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": "Parent 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": 1, + "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 12:54:49.527782", + "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..2483ca1b9d --- /dev/null +++ b/erpnext/assets/doctype/location/location.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 Location(Document): + pass 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/config/assets.py b/erpnext/config/assets.py index 73c1aee87a..be522469e6 100644 --- a/erpnext/config/assets.py +++ b/erpnext/config/assets.py @@ -14,6 +14,11 @@ def get_data(): "type": "doctype", "name": "Asset Category", }, + { + "type": "doctype", + "label": _("Asset Location"), + "name": "Location", + }, { "type": "doctype", "name": "Asset Settings", diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py index c340901e3b..798eee2b9d 100644 --- a/erpnext/controllers/buying_controller.py +++ b/erpnext/controllers/buying_controller.py @@ -441,9 +441,10 @@ class BuyingController(StockController): return if self.doctype in ['Purchase Receipt', 'Purchase Invoice']: - if self.doctype == 'Purchase Receipt': - self.process_fixed_asset() - self.update_fixed_asset() + 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) @@ -453,12 +454,13 @@ class BuyingController(StockController): update_last_purchase_rate(self, is_submit = 0) if self.doctype in ['Purchase Receipt', 'Purchase Invoice']: - if self.doctype == 'Purchase Receipt': - self.delete_linked_asset() - self.update_fixed_asset() + field = 'purchase_invoice' if self.doctype == 'Purchase Invoice' else 'purchase_receipt' + + self.delete_linked_asset(field) + self.update_fixed_asset(field) def process_fixed_asset(self): - if not self.doctype in ['Purchase Receipt', 'Purchase Invoice']: + if self.doctype == 'Purchase Invoice' and not self.update_stock: return asset_items = [d.item_code for d in self.items if d.is_fixed_asset] @@ -471,6 +473,9 @@ class BuyingController(StockController): 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 @@ -488,14 +493,11 @@ class BuyingController(StockController): 'company': self.company, 'actual_qty': d.qty, 'purchase_document_type': self.doctype, - 'purchase_document_no': self.name + 'purchase_document_no': self.name, + 'asset': d.asset }) d.db_set('serial_no', serial_nos) - if not d.asset: - asset = self.make_asset(d) - d.db_set('asset', asset) - if d.asset: self.make_asset_movement(d) @@ -503,9 +505,9 @@ class BuyingController(StockController): asset = frappe.get_doc({ 'doctype': 'Asset', 'item_code': row.item_code, - 'asset_name': '{0} - {1}'.format(self.name, row.item_code), + 'asset_name': row.item_name, + 'naming_series': frappe.db.get_value('Item', row.item_code, 'asset_naming_series') or 'AST', 'warehouse': row.warehouse, - 'serial_no': row.serial_no, 'company': self.company, 'purchase_date': self.posting_date, 'purchase_receipt': self.name if self.doctype == 'Purchase Receipt' else None, @@ -535,9 +537,7 @@ class BuyingController(StockController): return asset_movement.name - def update_fixed_asset(self): - field = 'purchase_invoice' if self.doctype == 'Purchase Invoice' else 'purchase_receipt' - + def update_fixed_asset(self, field): for d in self.get("items"): if d.is_fixed_asset and d.asset: asset = frappe.get_doc("Asset", d.asset) @@ -555,13 +555,11 @@ class BuyingController(StockController): asset.save() - def delete_linked_asset(self): - if not self.doctype in ['Purchase Receipt', 'Purchase Invoice']: - return - - if self.doctype == 'Purchase Invoice' and self.get('update_stock'): + def delete_linked_asset(self, field): + if self.doctype == 'Purchase Invoice' and not self.get('update_stock'): return + frappe.db.sql("delete from `tabAsset` where {0} = %s and docstatus = 0".format(field), self.name) 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) diff --git a/erpnext/setup/doctype/company/company.js b/erpnext/setup/doctype/company/company.js index d4095772cd..5ca2885547 100644 --- a/erpnext/setup/doctype/company/company.js +++ b/erpnext/setup/doctype/company/company.js @@ -5,14 +5,6 @@ frappe.provide("erpnext.company"); frappe.ui.form.on("Company", { setup: function(frm) { - frm.fields_dict.fixed_asset_account.get_query = function() { - return { - filters: { - account_type: "Fixed Asset", - company: frm.doc.name - } - } - } erpnext.company.setup_queries(frm); }, @@ -215,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 d236dda873..07051eeba8 100644 --- a/erpnext/setup/doctype/company/company.json +++ b/erpnext/setup/doctype/company/company.json @@ -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/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 251717e127..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, @@ -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", diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py index fafdaab51f..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: 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 a7b0a03c0a..87c9a757bf 100755 --- a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json +++ b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json @@ -1641,6 +1641,39 @@ "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, @@ -2459,7 +2492,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2018-04-23 14:07:48.438379", + "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.py b/erpnext/stock/doctype/serial_no/serial_no.py index 17bf1bb1c3..6ee679ab82 100644 --- a/erpnext/stock/doctype/serial_no/serial_no.py +++ b/erpnext/stock/doctype/serial_no/serial_no.py @@ -322,6 +322,7 @@ def make_serial_no(serial_no, args): 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') sr.insert() if args.get('purchase_document_type'): diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py index 0d03b4d2ec..7e456dd3d3 100644 --- a/erpnext/stock/get_item_details.py +++ b/erpnext/stock/get_item_details.py @@ -287,10 +287,6 @@ def get_default_income_account(args, item): or frappe.db.get_value("Item Group", item.item_group, "default_income_account")) def get_default_expense_account(args, item): - if item and item.is_fixed_asset: - return frappe.db.get_value("Company", args.company, "fixed_asset_account") - if account: return account - return (item.expense_account or args.expense_account or frappe.db.get_value("Item Group", item.item_group, "default_expense_account")) From af0599541867c130e51ac14dc13f1e970d296267 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Mon, 7 May 2018 18:46:53 +0530 Subject: [PATCH 27/40] Asset accounting --- .../purchase_invoice/purchase_invoice.py | 43 +++++++++++++++++++ erpnext/controllers/buying_controller.py | 24 +++++++---- .../purchase_receipt/purchase_receipt.py | 31 +++++++++++++ erpnext/stock/doctype/serial_no/serial_no.py | 2 +- 4 files changed, 91 insertions(+), 9 deletions(-) diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py index d2cc4eea9f..fea126945c 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -422,6 +422,49 @@ 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 and not self.update_stock: + 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_currency = get_account_currency(asset_accounts[2]) + + gl_entries.append(self.get_gl_dict({ + "account": asset_accounts[2], + "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) + })) + + 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({ diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py index 798eee2b9d..a1bc6d7aa7 100644 --- a/erpnext/controllers/buying_controller.py +++ b/erpnext/controllers/buying_controller.py @@ -79,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"]] @@ -88,6 +88,9 @@ 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): + 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 @@ -112,7 +115,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 @@ -456,14 +459,14 @@ class BuyingController(StockController): if self.doctype in ['Purchase Receipt', 'Purchase Invoice']: field = 'purchase_invoice' if self.doctype == 'Purchase Invoice' else 'purchase_receipt' - self.delete_linked_asset(field) - self.update_fixed_asset(field) + 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 = [d.item_code for d in self.items if d.is_fixed_asset] + asset_items = self.get_asset_items() if asset_items: self.make_serial_nos_for_asset(asset_items) @@ -537,10 +540,16 @@ class BuyingController(StockController): return asset_movement.name - def update_fixed_asset(self, field): + 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 @@ -555,11 +564,10 @@ class BuyingController(StockController): asset.save() - def delete_linked_asset(self, field): + def delete_linked_asset(self): if self.doctype == 'Purchase Invoice' and not self.get('update_stock'): return - frappe.db.sql("delete from `tabAsset` where {0} = %s and docstatus = 0".format(field), self.name) 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) diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py index c7083be286..984bf33b4b 100644 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py @@ -253,6 +253,37 @@ 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 + 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(asset_accounts[0]) + gl_entries.append(self.get_gl_dict({ + "account": asset_accounts[0], + "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"): diff --git a/erpnext/stock/doctype/serial_no/serial_no.py b/erpnext/stock/doctype/serial_no/serial_no.py index 6ee679ab82..333963bd66 100644 --- a/erpnext/stock/doctype/serial_no/serial_no.py +++ b/erpnext/stock/doctype/serial_no/serial_no.py @@ -323,12 +323,12 @@ def make_serial_no(serial_no, args): sr.company = args.get('company') sr.via_stock_ledger = args.get('via_stock_ledger') or True sr.asset = args.get('asset') - sr.insert() 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() From 255cd44abae989f0223721e71c96e6b8a3b04ff9 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Mon, 7 May 2018 19:22:15 +0530 Subject: [PATCH 28/40] Treeview for Location --- erpnext/assets/doctype/location/location.json | 99 ++++++++++++++++++- erpnext/assets/doctype/location/location.py | 41 +++++++- .../assets/doctype/location/location_tree.js | 28 ++++++ 3 files changed, 163 insertions(+), 5 deletions(-) create mode 100644 erpnext/assets/doctype/location/location_tree.js diff --git a/erpnext/assets/doctype/location/location.json b/erpnext/assets/doctype/location/location.json index 13ef66224d..d83fdf3667 100644 --- a/erpnext/assets/doctype/location/location.json +++ b/erpnext/assets/doctype/location/location.json @@ -83,7 +83,7 @@ "columns": 0, "fieldname": "parent_location", "fieldtype": "Link", - "hidden": 0, + "hidden": 1, "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, @@ -98,7 +98,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, @@ -106,6 +106,99 @@ "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, @@ -118,7 +211,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2018-05-07 12:54:49.527782", + "modified": "2018-05-07 19:21:06.051414", "modified_by": "Administrator", "module": "Assets", "name": "Location", diff --git a/erpnext/assets/doctype/location/location.py b/erpnext/assets/doctype/location/location.py index 2483ca1b9d..9d05720a0d 100644 --- a/erpnext/assets/doctype/location/location.py +++ b/erpnext/assets/doctype/location/location.py @@ -5,6 +5,43 @@ from __future__ import unicode_literals import frappe from frappe.model.document import Document +from frappe.utils.nestedset import NestedSet -class Location(Document): - pass +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 From f41e1ed191bf383356169549c8571e9ced8251e1 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Tue, 8 May 2018 12:38:28 +0530 Subject: [PATCH 29/40] Added default asset accounts in COA, CWIP account in asset category --- .../verified/standard_chart_of_accounts.py | 11 +++++- ...d_chart_of_accounts_with_account_number.py | 12 ++++++ .../purchase_invoice/purchase_invoice.py | 34 ++++++++--------- .../doctype/asset_category/asset_category.js | 11 ++++++ .../doctype/asset_category/asset_category.py | 7 ++++ .../asset_category_account.json | 38 ++++++++++++++++++- erpnext/setup/doctype/company/company.py | 3 ++ .../purchase_receipt/purchase_receipt.py | 7 +++- 8 files changed, 102 insertions(+), 21 deletions(-) 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/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py index fea126945c..fd0054ace2 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -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_cwip_account form_grid_templates = { "items": "templates/form_grid/item_grid.html" @@ -423,7 +424,7 @@ class PurchaseInvoice(BuyingController): "credit": flt(item.rm_supp_cost) }, warehouse_account[self.supplier_warehouse]["account_currency"])) - elif item.is_fixed_asset and not self.update_stock: + 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"]) @@ -432,7 +433,6 @@ class PurchaseInvoice(BuyingController): 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, @@ -442,10 +442,10 @@ class PurchaseInvoice(BuyingController): if asset_rbnb_currency == self.company_currency else asset_amount) })) else: - cwip_account_currency = get_account_currency(asset_accounts[2]) - + cwip_account = get_cwip_account(item.item_code, self.company) or asset_accounts[2] + cwip_account_currency = get_account_currency(cwip_account) gl_entries.append(self.get_gl_dict({ - "account": asset_accounts[2], + "account": cwip_account, "against": self.supplier, "remarks": self.get("remarks") or _("Accounting Entry for Asset"), "debit": base_asset_amount, @@ -453,18 +453,18 @@ class PurchaseInvoice(BuyingController): if cwip_account_currency == self.company_currency else asset_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) - })) - + 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({ 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.py b/erpnext/assets/doctype/asset_category/asset_category.py index 542bd12861..4ffd20b159 100644 --- a/erpnext/assets/doctype/asset_category/asset_category.py +++ b/erpnext/assets/doctype/asset_category/asset_category.py @@ -13,3 +13,10 @@ class AssetCategory(Document): 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) + +def get_cwip_account(item_code, company): + asset_category = frappe.db.get_value('Item', item_code, 'asset_category') + cwip_account = frappe.db.get_value('Asset Category Account', + {'parent': asset_category, 'company_name': company}, 'capital_work_in_progress_account') + + return cwip_account or None \ 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..3cace59a4c 100644 --- a/erpnext/assets/doctype/asset_category_account/asset_category_account.json +++ b/erpnext/assets/doctype/asset_category_account/asset_category_account.json @@ -41,6 +41,7 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -72,6 +73,7 @@ "reqd": 1, "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 }, { @@ -134,6 +137,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": "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, + "translatable": 0, "unique": 0 } ], @@ -147,7 +183,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2017-11-28 16:54:12.252271", + "modified": "2018-05-08 11:41:09.678234", "modified_by": "Administrator", "module": "Assets", "name": "Asset Category Account", 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/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py index 984bf33b4b..ab86c762cd 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_cwip_account form_grid_templates = { "items": "templates/form_grid/item_grid.html" @@ -258,12 +259,14 @@ class PurchaseReceipt(BuyingController): "asset_received_but_not_billed"]) # CWIP entry + cwip_account = get_cwip_account(d.item_code, self.company) 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(asset_accounts[0]) + cwip_account_currency = get_account_currency(cwip_account) gl_entries.append(self.get_gl_dict({ - "account": asset_accounts[0], + "account": cwip_account, "against": asset_accounts[1], "cost_center": d.cost_center, "remarks": self.get("remarks") or _("Accounting Entry for Asset"), From f2684ae83a8748ca796a4ec5b2407e1a742ef127 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Tue, 8 May 2018 13:22:22 +0530 Subject: [PATCH 30/40] Commonify get_asset_category_account and get_fixed_asset_account method --- .../purchase_invoice/purchase_invoice.js | 3 ++- .../purchase_invoice/purchase_invoice.py | 20 ++++--------------- erpnext/assets/doctype/asset/asset.py | 4 ++-- .../doctype/asset_category/asset_category.py | 17 +++++++++++----- erpnext/controllers/buying_controller.py | 6 +++++- .../purchase_receipt/purchase_receipt.py | 5 +++-- 6 files changed, 28 insertions(+), 27 deletions(-) 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 fd0054ace2..3e375e5051 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -19,7 +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_cwip_account +from erpnext.assets.doctype.asset_category.asset_category import get_asset_category_account form_grid_templates = { "items": "templates/form_grid/item_grid.html" @@ -442,7 +442,9 @@ class PurchaseInvoice(BuyingController): if asset_rbnb_currency == self.company_currency else asset_amount) })) else: - cwip_account = get_cwip_account(item.item_code, self.company) or asset_accounts[2] + 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, @@ -734,20 +736,6 @@ 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/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py index adcc986f66..ef6e376eae 100644 --- a/erpnext/assets/doctype/asset/asset.py +++ b/erpnext/assets/doctype/asset/asset.py @@ -7,7 +7,7 @@ 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 @@ -287,7 +287,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 diff --git a/erpnext/assets/doctype/asset_category/asset_category.py b/erpnext/assets/doctype/asset_category/asset_category.py index 4ffd20b159..d1dd8ed7e2 100644 --- a/erpnext/assets/doctype/asset_category/asset_category.py +++ b/erpnext/assets/doctype/asset_category/asset_category.py @@ -14,9 +14,16 @@ class AssetCategory(Document): if cint(self.get(field))<1: frappe.throw(_("{0} must be greater than 0").format(self.meta.get_label(field)), frappe.MandatoryError) -def get_cwip_account(item_code, company): - asset_category = frappe.db.get_value('Item', item_code, 'asset_category') - cwip_account = frappe.db.get_value('Asset Category Account', - {'parent': asset_category, 'company_name': company}, 'capital_work_in_progress_account') +@frappe.whitelist() +def get_asset_category_account(asset, fieldname, account=None): + if account: + if frappe.db.get_value("Account", account, "account_type") != "Fixed Asset": + account=None - return cwip_account or None \ No newline at end of file + 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/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py index a1bc6d7aa7..80bec0e889 100644 --- a/erpnext/controllers/buying_controller.py +++ b/erpnext/controllers/buying_controller.py @@ -505,11 +505,15 @@ class BuyingController(StockController): self.make_asset_movement(d) def make_asset(self, row): + item_data = frappe.db.get_value('Item', + row.item_code, ['asset_naming_series', 'asset_category'], as_dict=1) + asset = frappe.get_doc({ 'doctype': 'Asset', 'item_code': row.item_code, 'asset_name': row.item_name, - 'naming_series': frappe.db.get_value('Item', row.item_code, 'asset_naming_series') or 'AST', + 'naming_series': item_data.get('asset_naming_series') or 'AST', + 'asset_category': item_data.get('asset_category'), 'warehouse': row.warehouse, 'company': self.company, 'purchase_date': self.posting_date, diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py index ab86c762cd..573f7ed8f3 100644 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py @@ -13,7 +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_cwip_account +from erpnext.assets.doctype.asset_category.asset_category import get_asset_category_account form_grid_templates = { "items": "templates/form_grid/item_grid.html" @@ -259,7 +259,8 @@ class PurchaseReceipt(BuyingController): "asset_received_but_not_billed"]) # CWIP entry - cwip_account = get_cwip_account(d.item_code, self.company) or asset_accounts[0] + 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) From 0ea6fe4397051f3d7094dd2059913918f999a3e4 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Tue, 8 May 2018 23:31:58 +0530 Subject: [PATCH 31/40] Added new doctype Finance Book Detail in asset, asset category --- erpnext/assets/doctype/asset/asset.js | 4 +- erpnext/assets/doctype/asset/asset.json | 377 ++++++++++++++++-- erpnext/assets/doctype/asset/asset.py | 141 +++---- .../asset_category/asset_category.json | 65 ++- .../doctype/asset_finance_book/__init__.py | 0 .../asset_finance_book.json | 318 +++++++++++++++ .../asset_finance_book/asset_finance_book.py | 10 + .../depreciation_schedule.json | 62 ++- erpnext/controllers/buying_controller.py | 1 + 9 files changed, 859 insertions(+), 119 deletions(-) create mode 100644 erpnext/assets/doctype/asset_finance_book/__init__.py create mode 100644 erpnext/assets/doctype/asset_finance_book/asset_finance_book.json create mode 100644 erpnext/assets/doctype/asset_finance_book/asset_finance_book.py diff --git a/erpnext/assets/doctype/asset/asset.js b/erpnext/assets/doctype/asset/asset.js index edc1e364f5..b8bcc91d2a 100644 --- a/erpnext/assets/doctype/asset/asset.js +++ b/erpnext/assets/doctype/asset/asset.js @@ -131,9 +131,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); } } }) diff --git a/erpnext/assets/doctype/asset/asset.json b/erpnext/assets/doctype/asset/asset.json index 536b4dc522..a47c645359 100644 --- a/erpnext/assets/doctype/asset/asset.json +++ b/erpnext/assets/doctype/asset/asset.json @@ -42,7 +42,6 @@ "reqd": 0, "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 }, { @@ -105,7 +103,6 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -137,7 +134,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -169,7 +165,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -202,7 +197,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -234,7 +228,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -267,7 +260,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -300,7 +292,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -333,7 +324,37 @@ "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": "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 }, { @@ -364,7 +385,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -395,7 +415,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -425,7 +444,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -457,7 +475,6 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -489,7 +506,6 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -521,7 +537,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -552,7 +567,6 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -584,7 +598,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -616,7 +629,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -647,7 +659,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -678,7 +689,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -709,7 +719,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -741,7 +750,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -771,7 +779,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -803,7 +810,6 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -833,7 +839,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -866,7 +871,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -899,7 +903,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -929,7 +932,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -960,7 +962,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -992,7 +993,66 @@ "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_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": 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 }, { @@ -1026,7 +1086,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -1058,7 +1117,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -1089,7 +1147,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -1119,7 +1176,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -1151,7 +1207,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -1182,7 +1237,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -1214,7 +1268,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -1246,7 +1299,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -1278,7 +1330,245 @@ "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": "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 }, { @@ -1309,7 +1599,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -1341,7 +1630,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -1372,7 +1660,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 } ], @@ -1387,7 +1674,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2018-05-07 15:25:06.456992", + "modified": "2018-05-09 11:09:56.407423", "modified_by": "Administrator", "module": "Assets", "name": "Asset", @@ -1396,6 +1683,7 @@ "permissions": [ { "amend": 1, + "apply_user_permissions": 0, "cancel": 1, "create": 1, "delete": 1, @@ -1415,6 +1703,7 @@ }, { "amend": 0, + "apply_user_permissions": 0, "cancel": 1, "create": 1, "delete": 1, diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py index ef6e376eae..a6078c4209 100644 --- a/erpnext/assets/doctype/asset/asset.py +++ b/erpnext/assets/doctype/asset/asset.py @@ -16,11 +16,11 @@ class Asset(Document): self.status = self.get_status() self.validate_item() self.set_missing_values() - self.validate_asset_values() + # self.validate_asset_values() if self.calculate_depreciation: self.make_depreciation_schedule() self.set_accumulated_depreciation() - get_depreciation_accounts(self) + # get_depreciation_accounts(self) if self.get("schedules"): self.validate_expected_value_after_useful_life() @@ -46,11 +46,9 @@ 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 self.item_code and not self.finance_books: + finance_books = get_item_details(self.item_code) + self.set('finance_books', finance_books) def validate_asset_values(self): if not flt(self.gross_purchase_amount): @@ -65,8 +63,6 @@ class Asset(Document): 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) if flt(self.opening_accumulated_depreciation) > depreciable_amount: @@ -94,66 +90,69 @@ class Asset(Document): 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")) - 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) + if not self.get("schedules"): + total_depreciations = sum([d.total_number_of_depreciations for d in self.get('finance_books')]) - 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): + for d in self.get('finance_books'): + d.value_after_depreciation = ((flt(self.gross_purchase_amount * d.total_number_of_depreciations) / + total_depreciations) - flt(d.opening_accumulated_depreciation)) + value_after_depreciation = flt(d.value_after_depreciation) - 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) + number_of_pending_depreciations = cint(d.total_number_of_depreciations) - \ + cint(d.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(d.start_date) < next_depr_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) + 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.start_date, (n-1) * 12) + depreciation_amount = \ + self.get_depreciation_amount_prorata_temporis(value_after_depreciation, + previous_scheduled_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) + elif n == range(number_of_pending_depreciations)[0]: + schedule_date = d.start_date + depreciation_amount = \ + self.get_depreciation_amount_prorata_temporis(value_after_depreciation, + self.available_for_use_date, schedule_date) - if value_after_depreciation != 0: - value_after_depreciation -= flt(depreciation_amount) + else: + schedule_date = add_months(d.start_date, n * 12) + depreciation_amount = \ + self.get_depreciation_amount_prorata_temporis(value_after_depreciation) - 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)) + if value_after_depreciation != 0: + value_after_depreciation -= flt(depreciation_amount) - 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, + 'finance_book_id': d.name + }) + else: + for n in range(number_of_pending_depreciations): + schedule_date = add_months(d.start_date, + n * cint(d.frequency_of_depreciation)) - self.append("schedules", { - "schedule_date": schedule_date, - "depreciation_amount": depreciation_amount - }) + depreciation_amount = self.get_depreciation_amount(value_after_depreciation, d) + if depreciation_amount: + value_after_depreciation -= flt(depreciation_amount) + + self.append("schedules", { + "schedule_date": schedule_date, + "depreciation_amount": depreciation_amount, + 'finance_book_id': d.name + }) def set_accumulated_depreciation(self): accumulated_depreciation = flt(self.opening_accumulated_depreciation) @@ -171,13 +170,13 @@ class Asset(Document): 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)) + def get_depreciation_amount(self, depreciable_value, row): + if row.depreciation_method in ("Straight Line", "Manual"): + depreciation_amount = (flt(row.value_after_depreciation) - + flt(self.expected_value_after_useful_life)) / (cint(row.total_number_of_depreciations) - + cint(row.number_of_depreciations_booked)) else: - factor = 200.0 / self.total_number_of_depreciations + factor = 200.0 / row.total_number_of_depreciations depreciation_amount = flt(depreciable_value * factor / 100, 0) value_after_depreciation = flt(depreciable_value) - depreciation_amount @@ -345,11 +344,15 @@ def get_item_details(item_code): 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 ret + return books diff --git a/erpnext/assets/doctype/asset_category/asset_category.json b/erpnext/assets/doctype/asset_category/asset_category.json index 3331d05e85..d9776b8d91 100644 --- a/erpnext/assets/doctype/asset_category/asset_category.json +++ b/erpnext/assets/doctype/asset_category/asset_category.json @@ -164,6 +164,67 @@ "set_only_once": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "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": 0, + "in_standard_filter": 0, + "label": "Finance Book Detail", + "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": "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, @@ -236,7 +297,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2017-12-01 15:14:25.645077", + "modified": "2018-05-09 11:09:55.806482", "modified_by": "Administrator", "module": "Assets", "name": "Asset Category", @@ -312,4 +373,4 @@ "sort_order": "DESC", "track_changes": 0, "track_seen": 0 -} +} \ No newline at end of file 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..92991e9c85 --- /dev/null +++ b/erpnext/assets/doctype/asset_finance_book/asset_finance_book.json @@ -0,0 +1,318 @@ +{ + "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": "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": "Finance Book", + "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": "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\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": 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": "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": 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": 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": "Value After Depreciation", + "length": 0, + "no_copy": 0, + "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 + }, + { + "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": 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:parent.doctype == 'Asset'", + "fieldname": "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": "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": 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": "0", + "depends_on": "eval:parent.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": 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": "eval: (parent.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 + } + ], + "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 11:10:00.923786", + "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/depreciation_schedule/depreciation_schedule.json b/erpnext/assets/doctype/depreciation_schedule/depreciation_schedule.json index 330347240d..17b4aecc04 100644 --- a/erpnext/assets/doctype/depreciation_schedule/depreciation_schedule.json +++ b/erpnext/assets/doctype/depreciation_schedule/depreciation_schedule.json @@ -196,6 +196,66 @@ "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": "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": "Finance Book", + "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": "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 } ], "has_web_view": 0, @@ -208,7 +268,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2017-10-19 16:30:13.738170", + "modified": "2018-05-08 15:24:57.955533", "modified_by": "Administrator", "module": "Assets", "name": "Depreciation Schedule", diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py index 80bec0e889..d4399ad518 100644 --- a/erpnext/controllers/buying_controller.py +++ b/erpnext/controllers/buying_controller.py @@ -517,6 +517,7 @@ class BuyingController(StockController): 'warehouse': row.warehouse, 'company': self.company, 'purchase_date': self.posting_date, + 'calculate_depreciation': 1, 'purchase_receipt': self.name if self.doctype == 'Purchase Receipt' else None, 'purchase_invoice': self.name if self.doctype == 'Purchase Invoice' else None }) From aa7b43427004af20002ae2a1d4ae7b13736093ca Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Fri, 11 May 2018 01:56:05 +0530 Subject: [PATCH 32/40] Create asset adjustment doctype, post gl entry for the asset --- erpnext/assets/doctype/asset/asset.js | 28 +- erpnext/assets/doctype/asset/asset.json | 693 +++++++++--------- erpnext/assets/doctype/asset/asset.py | 322 +++++--- .../doctype/asset_adjustment/__init__.py | 0 .../asset_adjustment/asset_adjustment.js | 8 + .../asset_adjustment/asset_adjustment.json | 438 +++++++++++ .../asset_adjustment/asset_adjustment.py | 10 + .../asset_adjustment/test_asset_adjustment.js | 23 + .../asset_adjustment/test_asset_adjustment.py | 10 + .../asset_category/asset_category.json | 4 +- .../doctype/asset_category/asset_category.py | 17 +- .../asset_category_account.json | 13 +- .../asset_finance_book.json | 116 ++- .../asset_movement/asset_movement.json | 367 +++++++--- .../doctype/asset_movement/asset_movement.py | 41 +- .../depreciation_schedule.json | 94 ++- erpnext/config/assets.py | 5 +- erpnext/controllers/accounts_controller.py | 7 +- erpnext/controllers/buying_controller.py | 16 +- erpnext/hooks.py | 3 +- .../stock/doctype/serial_no/serial_no.json | 262 +++++-- .../stock/doctype/serial_no/test_serial_no.js | 23 + 22 files changed, 1695 insertions(+), 805 deletions(-) create mode 100644 erpnext/assets/doctype/asset_adjustment/__init__.py create mode 100644 erpnext/assets/doctype/asset_adjustment/asset_adjustment.js create mode 100644 erpnext/assets/doctype/asset_adjustment/asset_adjustment.json create mode 100644 erpnext/assets/doctype/asset_adjustment/asset_adjustment.py create mode 100644 erpnext/assets/doctype/asset_adjustment/test_asset_adjustment.js create mode 100644 erpnext/assets/doctype/asset_adjustment/test_asset_adjustment.py create mode 100644 erpnext/stock/doctype/serial_no/test_serial_no.js diff --git a/erpnext/assets/doctype/asset/asset.js b/erpnext/assets/doctype/asset/asset.js index b8bcc91d2a..4daeae2880 100644 --- a/erpnext/assets/doctype/asset/asset.js +++ b/erpnext/assets/doctype/asset/asset.js @@ -57,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"); @@ -139,7 +152,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) { @@ -289,15 +302,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] ] } }, @@ -324,8 +336,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 a47c645359..9a05cad65c 100644 --- a/erpnext/assets/doctype/asset/asset.json +++ b/erpnext/assets/doctype/asset/asset.json @@ -167,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, @@ -326,37 +294,6 @@ "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": 1, @@ -387,36 +324,6 @@ "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": 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, @@ -483,7 +390,7 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fieldname": "warehouse", + "fieldname": "location", "fieldtype": "Link", "hidden": 0, "ignore_user_permissions": 0, @@ -491,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, @@ -508,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, @@ -569,128 +507,6 @@ "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_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, @@ -812,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, @@ -841,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, @@ -968,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", @@ -1034,7 +880,7 @@ "columns": 0, "fieldname": "section_break_33", "fieldtype": "Section Break", - "hidden": 0, + "hidden": 1, "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, @@ -1178,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, @@ -1336,7 +1151,7 @@ "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, - "collapsible": 0, + "collapsible": 1, "columns": 0, "fieldname": "insurance_details", "fieldtype": "Section Break", @@ -1632,6 +1447,190 @@ "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_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, @@ -1674,7 +1673,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2018-05-09 11:09:56.407423", + "modified": "2018-05-11 01:48:18.711485", "modified_by": "Administrator", "module": "Assets", "name": "Asset", diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py index a6078c4209..bf70fbc17d 100644 --- a/erpnext/assets/doctype/asset/asset.py +++ b/erpnext/assets/doctype/asset/asset.py @@ -10,17 +10,20 @@ from frappe.model.document import Document 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() self.set_missing_values() - # self.validate_asset_values() + self.validate_asset_values() if self.calculate_depreciation: self.make_depreciation_schedule() self.set_accumulated_depreciation() - # get_depreciation_accounts(self) + get_depreciation_accounts(self) if self.get("schedules"): self.validate_expected_value_after_useful_life() @@ -46,8 +49,11 @@ 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 and not self.finance_books: - finance_books = get_item_details(self.item_code) + 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): @@ -57,14 +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")) + self.value_after_depreciation = (flt(self.gross_purchase_amount) - + flt(self.opening_accumulated_depreciation)) + + 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.value_after_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, + row, 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, + row, 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, row) + + 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) + + 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 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)) @@ -75,95 +172,38 @@ 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 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 make_depreciation_schedule(self): - - if self.depreciation_method != 'Manual': - self.schedules = [] - - if not self.get("schedules"): - total_depreciations = sum([d.total_number_of_depreciations for d in self.get('finance_books')]) - - for d in self.get('finance_books'): - d.value_after_depreciation = ((flt(self.gross_purchase_amount * d.total_number_of_depreciations) / - total_depreciations) - flt(d.opening_accumulated_depreciation)) - value_after_depreciation = flt(d.value_after_depreciation) - - number_of_pending_depreciations = cint(d.total_number_of_depreciations) - \ - cint(d.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(d.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.start_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 = d.start_date - depreciation_amount = \ - self.get_depreciation_amount_prorata_temporis(value_after_depreciation, - self.available_for_use_date, schedule_date) - - else: - schedule_date = add_months(d.start_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, - 'finance_book_id': d.name - }) - else: - for n in range(number_of_pending_depreciations): - schedule_date = add_months(d.start_date, - n * cint(d.frequency_of_depreciation)) - - depreciation_amount = self.get_depreciation_amount(value_after_depreciation, d) - if depreciation_amount: - value_after_depreciation -= flt(depreciation_amount) - - self.append("schedules", { - "schedule_date": schedule_date, - "depreciation_amount": depreciation_amount, - 'finance_book_id': d.name - }) + 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)) def set_accumulated_depreciation(self): - accumulated_depreciation = flt(self.opening_accumulated_depreciation) value_after_depreciation = flt(self.value_after_depreciation) + straight_line_idx = [d.idx for d in self.get("schedules") if d.depreciation_method == 'Straight Line'] + finance_books = [] + for i, d in enumerate(self.get("schedules")): + if d.finance_book_id not in finance_books: + accumulated_depreciation = flt(self.opening_accumulated_depreciation) + 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')[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 @@ -171,46 +211,44 @@ class Asset(Document): d.precision("accumulated_depreciation_amount")) def get_depreciation_amount(self, depreciable_value, row): - if row.depreciation_method in ("Straight Line", "Manual"): - depreciation_amount = (flt(row.value_after_depreciation) - - flt(self.expected_value_after_useful_life)) / (cint(row.total_number_of_depreciations) - - cint(row.number_of_depreciations_booked)) - else: - factor = 200.0 / row.total_number_of_depreciations - depreciation_amount = flt(depreciable_value * factor / 100, 0) + percentage_value = 100.0 if row.depreciation_method == 'Written Down Value' else 200.0 - 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) + factor = percentage_value / row.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"): + if row.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) - + 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"): @@ -243,9 +281,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' @@ -261,6 +305,37 @@ class Asset(Document): doc = frappe.get_doc('Asset Movement', asset_movement) doc.submit() + def make_gl_entries(self): + if self.purchase_receipt: + 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.gross_purchase_amount, + "credit_in_account_currency": self.gross_purchase_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.gross_purchase_amount, + "debit_in_account_currency": self.gross_purchase_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}) @@ -271,6 +346,14 @@ 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 @@ -295,7 +378,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, serial_no): +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") @@ -338,9 +421,7 @@ 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)) @@ -356,3 +437,16 @@ def get_item_details(item_code): }) return books + +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_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..0535743703 --- /dev/null +++ b/erpnext/assets/doctype/asset_adjustment/asset_adjustment.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('Asset Adjustment', { + refresh: function(frm) { + + } +}); 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..8a0e95775a --- /dev/null +++ b/erpnext/assets/doctype/asset_adjustment/asset_adjustment.json @@ -0,0 +1,438 @@ +{ + "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": "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": 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_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": 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": 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": "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": "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": "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": 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": "accumulated_depreciation_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": "Accumulated Depreciation 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 + }, + { + "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 00:25:07.222408", + "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..437f9bd902 --- /dev/null +++ b/erpnext/assets/doctype/asset_adjustment/asset_adjustment.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 AssetAdjustment(Document): + pass 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.json b/erpnext/assets/doctype/asset_category/asset_category.json index d9776b8d91..b655b40475 100644 --- a/erpnext/assets/doctype/asset_category/asset_category.json +++ b/erpnext/assets/doctype/asset_category/asset_category.json @@ -62,7 +62,7 @@ "label": "Depreciation Method", "length": 0, "no_copy": 0, - "options": "\nStraight Line\nDouble Declining Balance\nManual", + "options": "\nStraight Line\nDouble Declining Balance\nWritten Down Value\nManual", "permlevel": 0, "precision": "", "print_hide": 0, @@ -297,7 +297,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2018-05-09 11:09:55.806482", + "modified": "2018-05-10 15:12:05.954200", "modified_by": "Administrator", "module": "Assets", "name": "Asset Category", diff --git a/erpnext/assets/doctype/asset_category/asset_category.py b/erpnext/assets/doctype/asset_category/asset_category.py index d1dd8ed7e2..fa0bd83117 100644 --- a/erpnext/assets/doctype/asset_category/asset_category.py +++ b/erpnext/assets/doctype/asset_category/asset_category.py @@ -15,15 +15,16 @@ class AssetCategory(Document): frappe.throw(_("{0} must be greater than 0").format(self.meta.get_label(field)), frappe.MandatoryError) @frappe.whitelist() -def get_asset_category_account(asset, fieldname, account=None): - if account: - if frappe.db.get_value("Account", account, "account_type") != "Fixed Asset": - account=None +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"]) + 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) + 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 3cace59a4c..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, @@ -41,7 +41,6 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -49,7 +48,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, - "columns": 3, + "columns": 2, "fieldname": "fixed_asset_account", "fieldtype": "Link", "hidden": 0, @@ -73,7 +72,6 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -105,7 +103,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -137,7 +134,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -145,7 +141,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, - "columns": 0, + "columns": 2, "fieldname": "capital_work_in_progress_account", "fieldtype": "Link", "hidden": 0, @@ -169,7 +165,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 } ], @@ -183,7 +178,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2018-05-08 11:41:09.678234", + "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/asset_finance_book.json b/erpnext/assets/doctype/asset_finance_book/asset_finance_book.json index 92991e9c85..351f9d0c66 100644 --- a/erpnext/assets/doctype/asset_finance_book/asset_finance_book.json +++ b/erpnext/assets/doctype/asset_finance_book/asset_finance_book.json @@ -20,7 +20,7 @@ "columns": 0, "depends_on": "", "fieldname": "finance_book", - "fieldtype": "Data", + "fieldtype": "Link", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, @@ -31,6 +31,7 @@ "label": "Finance Book", "length": 0, "no_copy": 0, + "options": "Finance Book", "permlevel": 0, "precision": "", "print_hide": 0, @@ -61,7 +62,7 @@ "label": "Depreciation Method", "length": 0, "no_copy": 0, - "options": "\nStraight Line\nDouble Declining Balance\nManual", + "options": "\nStraight Line\nDouble Declining Balance\nWritten Down Value\nManual", "permlevel": 0, "precision": "", "print_hide": 0, @@ -104,37 +105,6 @@ "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": 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": "Value After Depreciation", - "length": 0, - "no_copy": 0, - "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 - }, { "allow_bulk_edit": 0, "allow_on_submit": 0, @@ -202,7 +172,7 @@ "collapsible": 0, "columns": 0, "depends_on": "eval:parent.doctype == 'Asset'", - "fieldname": "start_date", + "fieldname": "depreciation_start_date", "fieldtype": "Date", "hidden": 0, "ignore_user_permissions": 0, @@ -211,39 +181,7 @@ "in_global_search": 0, "in_list_view": 1, "in_standard_filter": 0, - "label": "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": 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": "0", - "depends_on": "eval:parent.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", + "label": "Depreciation Start Date", "length": 0, "no_copy": 0, "permlevel": 0, @@ -264,9 +202,9 @@ "bold": 0, "collapsible": 0, "columns": 0, - "depends_on": "eval: (parent.is_existing_asset && doc.opening_accumulated_depreciation)", - "fieldname": "number_of_depreciations_booked", - "fieldtype": "Int", + "default": "0", + "fieldname": "expected_value_after_useful_life", + "fieldtype": "Currency", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, @@ -274,9 +212,10 @@ "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, - "label": "Number of Depreciations Booked", + "label": "Expected Value After Useful Life", "length": 0, - "no_copy": 1, + "no_copy": 0, + "options": "Company:company:default_currency", "permlevel": 0, "precision": "", "print_hide": 0, @@ -288,6 +227,37 @@ "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, @@ -300,7 +270,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2018-05-09 11:10:00.923786", + "modified": "2018-05-10 18:05:58.900298", "modified_by": "Administrator", "module": "Assets", "name": "Asset Finance Book", diff --git a/erpnext/assets/doctype/asset_movement/asset_movement.json b/erpnext/assets/doctype/asset_movement/asset_movement.json index 3c3a1dc9cd..8adbf57b67 100644 --- a/erpnext/assets/doctype/asset_movement/asset_movement.json +++ b/erpnext/assets/doctype/asset_movement/asset_movement.json @@ -12,6 +12,37 @@ "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, @@ -31,7 +62,7 @@ "label": "Purpose", "length": 0, "no_copy": 0, - "options": "Receipt\nTransfer", + "options": "\nIssue\nReceipt\nTransfer", "permlevel": 0, "precision": "", "print_hide": 0, @@ -39,10 +70,9 @@ "read_only": 0, "remember_last_selected_value": 0, "report_hide": 0, - "reqd": 0, + "reqd": 1, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -74,7 +104,6 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -105,70 +134,6 @@ "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": 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, - "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, - "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 }, { @@ -198,7 +163,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -207,51 +171,18 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fieldname": "source_warehouse", - "fieldtype": "Link", + "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": 1, - "label": "Source Warehouse", + "in_standard_filter": 0, + "label": "Quantity", "length": 0, "no_copy": 0, - "options": "Warehouse", - "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": "target_warehouse", - "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": "Target Warehouse", - "length": 0, - "no_copy": 0, - "options": "Warehouse", "permlevel": 0, "precision": "", "print_hide": 0, @@ -259,10 +190,221 @@ "read_only": 0, "remember_last_selected_value": 0, "report_hide": 0, - "reqd": 1, + "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, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Source 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": "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, - "translatable": 0, "unique": 0 }, { @@ -293,7 +435,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -325,7 +466,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -357,7 +497,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -388,7 +527,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 } ], @@ -402,7 +540,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2018-04-20 15:45:54.156501", + "modified": "2018-05-10 23:16:20.791672", "modified_by": "Administrator", "module": "Assets", "name": "Asset Movement", @@ -411,6 +549,7 @@ "permissions": [ { "amend": 1, + "apply_user_permissions": 0, "cancel": 1, "create": 1, "delete": 1, @@ -430,6 +569,7 @@ }, { "amend": 1, + "apply_user_permissions": 0, "cancel": 1, "create": 1, "delete": 1, @@ -449,6 +589,7 @@ }, { "amend": 1, + "apply_user_permissions": 0, "cancel": 1, "create": 1, "delete": 1, diff --git a/erpnext/assets/doctype/asset_movement/asset_movement.py b/erpnext/assets/doctype/asset_movement/asset_movement.py index 42ed249959..32fc663837 100644 --- a/erpnext/assets/doctype/asset_movement/asset_movement.py +++ b/erpnext/assets/doctype/asset_movement/asset_movement.py @@ -5,6 +5,7 @@ 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): @@ -23,29 +24,41 @@ class AssetMovement(Document): if serial_no and not self.serial_no: self.serial_no = serial_no - def validate_warehouses(self): - if self.purpose == 'Transfer' and not self.source_warehouse: - self.source_warehouse = frappe.db.get_value("Asset", self.asset, "warehouse") + 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 self.source_warehouse == self.target_warehouse: - frappe.throw(_("Source and Target Warehouse cannot be 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 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 17b4aecc04..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, @@ -197,36 +228,6 @@ "set_only_once": 0, "unique": 0 }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "finance_book", - "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": "Finance Book", - "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, @@ -256,6 +257,37 @@ "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, @@ -268,7 +300,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2018-05-08 15:24:57.955533", + "modified": "2018-05-10 15:12:41.679436", "modified_by": "Administrator", "module": "Assets", "name": "Depreciation Schedule", diff --git a/erpnext/config/assets.py b/erpnext/config/assets.py index be522469e6..99a7a5c744 100644 --- a/erpnext/config/assets.py +++ b/erpnext/config/assets.py @@ -12,12 +12,11 @@ def get_data(): }, { "type": "doctype", - "name": "Asset Category", + "name": "Location", }, { "type": "doctype", - "label": _("Asset Location"), - "name": "Location", + "name": "Asset Category", }, { "type": "doctype", diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index 40028afb01..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, diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py index d4399ad518..f33ed25a06 100644 --- a/erpnext/controllers/buying_controller.py +++ b/erpnext/controllers/buying_controller.py @@ -11,7 +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 +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 @@ -505,6 +505,9 @@ class BuyingController(StockController): 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) @@ -512,18 +515,21 @@ class BuyingController(StockController): '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'), - 'warehouse': row.warehouse, + 'location': row.asset_location, 'company': self.company, 'purchase_date': self.posting_date, 'calculate_depreciation': 1, + 'gross_purchase_amount': flt(row.base_net_amount + row.item_tax_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)) @@ -533,10 +539,10 @@ class BuyingController(StockController): asset_movement = frappe.get_doc({ 'doctype': 'Asset Movement', 'asset': row.asset, - 'source_warehouse': '', - 'target_warehouse': row.warehouse, + '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, @@ -559,7 +565,7 @@ class BuyingController(StockController): asset.set(field, self.name) asset.purchase_date = self.posting_date asset.supplier = self.supplier - else: + elif self.docstatus == 2: asset.set(field, None) asset.supplier = None 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/stock/doctype/serial_no/serial_no.json b/erpnext/stock/doctype/serial_no/serial_no.json index fa4fa694c1..f84cbef2c8 100644 --- a/erpnext/stock/doctype/serial_no/serial_no.json +++ b/erpnext/stock/doctype/serial_no/serial_no.json @@ -41,7 +41,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -70,7 +69,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -102,7 +100,6 @@ "reqd": 1, "search_index": 1, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -135,7 +132,6 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -169,39 +165,6 @@ "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": "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, - "translatable": 0, "unique": 0 }, { @@ -230,7 +193,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -260,7 +222,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -292,7 +253,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0, "width": "300px" }, @@ -327,7 +287,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -360,7 +319,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -390,7 +348,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -419,7 +376,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0, "width": "50%" }, @@ -451,7 +407,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -482,7 +437,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -514,7 +468,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -544,7 +497,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -577,7 +529,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -606,7 +557,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0, "width": "50%" }, @@ -638,7 +588,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -668,7 +617,190 @@ "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_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 }, { @@ -699,7 +831,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -730,7 +861,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -761,7 +891,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -793,7 +922,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -823,7 +951,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -856,7 +983,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -885,7 +1011,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0, "width": "50%" }, @@ -919,7 +1044,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -951,7 +1075,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -982,7 +1105,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -1014,7 +1136,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -1044,7 +1165,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -1073,7 +1193,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0, "width": "50%" }, @@ -1107,7 +1226,6 @@ "reqd": 0, "search_index": 1, "set_only_once": 0, - "translatable": 0, "unique": 0, "width": "150px" }, @@ -1140,7 +1258,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0, "width": "150px" }, @@ -1170,7 +1287,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0, "width": "50%" }, @@ -1203,7 +1319,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0, "width": "150px" }, @@ -1236,7 +1351,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0, "width": "150px" }, @@ -1267,7 +1381,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -1297,7 +1410,6 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, "unique": 0 }, { @@ -1328,7 +1440,6 @@ "reqd": 1, "search_index": 1, "set_only_once": 0, - "translatable": 0, "unique": 0 } ], @@ -1343,7 +1454,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2018-04-19 20:25:52.066995", + "modified": "2018-05-10 23:38:20.646770", "modified_by": "Administrator", "module": "Stock", "name": "Serial No", @@ -1351,6 +1462,7 @@ "permissions": [ { "amend": 0, + "apply_user_permissions": 0, "cancel": 0, "create": 1, "delete": 1, @@ -1370,6 +1482,7 @@ }, { "amend": 0, + "apply_user_permissions": 0, "cancel": 0, "create": 0, "delete": 0, @@ -1389,6 +1502,7 @@ }, { "amend": 0, + "apply_user_permissions": 0, "cancel": 0, "create": 0, "delete": 0, 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() + ]); + +}); From 16bc853f6abe484a0e99ba259bc9859699f54f1c Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Sat, 12 May 2018 12:06:00 +0530 Subject: [PATCH 33/40] Reschedule for future depreciations and booked difference amount in accumulated depreciation account --- .../doctype/journal_entry/journal_entry.py | 14 ++- erpnext/assets/doctype/asset/asset.js | 6 ++ erpnext/assets/doctype/asset/asset.json | 32 ++++++- erpnext/assets/doctype/asset/asset.py | 38 ++++---- erpnext/assets/doctype/asset/depreciation.py | 10 +- .../asset_adjustment/asset_adjustment.js | 24 ++++- .../asset_adjustment/asset_adjustment.json | 93 +++++++++--------- .../asset_adjustment/asset_adjustment.py | 95 ++++++++++++++++++- erpnext/config/assets.py | 4 + erpnext/controllers/buying_controller.py | 4 +- 10 files changed, 247 insertions(+), 73 deletions(-) diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py index 51308e5008..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") diff --git a/erpnext/assets/doctype/asset/asset.js b/erpnext/assets/doctype/asset/asset.js index 4daeae2880..c05667a767 100644 --- a/erpnext/assets/doctype/asset/asset.js +++ b/erpnext/assets/doctype/asset/asset.js @@ -80,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"); } diff --git a/erpnext/assets/doctype/asset/asset.json b/erpnext/assets/doctype/asset/asset.json index 9a05cad65c..49a010d7d5 100644 --- a/erpnext/assets/doctype/asset/asset.json +++ b/erpnext/assets/doctype/asset/asset.json @@ -1600,6 +1600,36 @@ "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, @@ -1673,7 +1703,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2018-05-11 01:48:18.711485", + "modified": "2018-05-11 10:41:45.972686", "modified_by": "Administrator", "module": "Assets", "name": "Asset", diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py index bf70fbc17d..748849ecb2 100644 --- a/erpnext/assets/doctype/asset/asset.py +++ b/erpnext/assets/doctype/asset/asset.py @@ -63,9 +63,6 @@ class Asset(AccountsController): if not self.calculate_depreciation: return - self.value_after_depreciation = (flt(self.gross_purchase_amount) - - flt(self.opening_accumulated_depreciation)) - 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")) @@ -79,7 +76,9 @@ class Asset(AccountsController): for d in self.get('finance_books'): self.validate_asset_finance_books(d) - value_after_depreciation = flt(self.value_after_depreciation) + 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) @@ -139,7 +138,8 @@ class Asset(AccountsController): depreciation_amount = days * rate_per_day from_date = schedule_date else: - depreciation_amount = self.get_depreciation_amount(value_after_depreciation,d) + depreciation_amount = self.get_depreciation_amount(value_after_depreciation, + d.total_number_of_depreciations, d) if depreciation_amount: value_after_depreciation -= flt(depreciation_amount) @@ -187,21 +187,24 @@ class Asset(AccountsController): frappe.throw(_("Depreciation Row {0}: Next Depreciation Date cannot be before Available-for-use Date") .format(row.idx)) - def set_accumulated_depreciation(self): - value_after_depreciation = flt(self.value_after_depreciation) + 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 = [] 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 straight_line_idx and i == max(straight_line_idx) - 1: - book = self.get('finance_books')[d.finance_book_id - 1] + book = self.get('finance_books')[cint(d.finance_book_id) - 1] depreciation_amount += flt(value_after_depreciation - flt(book.expected_value_after_useful_life), d.precision("depreciation_amount")) @@ -210,10 +213,13 @@ class Asset(AccountsController): d.accumulated_depreciation_amount = flt(accumulated_depreciation, d.precision("accumulated_depreciation_amount")) - def get_depreciation_amount(self, depreciable_value, row): + def get_value_after_depreciation(self, idx): + return flt(self.get('finance_books')[cint(idx)-1].value_after_depreciation) + + 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 / row.total_number_of_depreciations + factor = percentage_value / total_number_of_depreciations depreciation_amount = flt(depreciable_value * factor / 100, 0) value_after_depreciation = flt(depreciable_value) - depreciation_amount @@ -229,7 +235,7 @@ class Asset(AccountsController): prorata_temporis = 1 if row.depreciation_method in ("Straight Line", "Manual"): - depreciation_amount = (flt(self.value_after_depreciation) - + 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 else: @@ -306,7 +312,7 @@ class Asset(AccountsController): doc.submit() def make_gl_entries(self): - if self.purchase_receipt: + if self.purchase_receipt and self.purchase_receipt_amount: from erpnext.accounts.general_ledger import make_gl_entries gl_entries = [] @@ -320,8 +326,8 @@ class Asset(AccountsController): "against": fixed_aseet_account, "remarks": self.get("remarks") or _("Accounting Entry for Asset"), "posting_date": self.available_for_use_date, - "credit": self.gross_purchase_amount, - "credit_in_account_currency": self.gross_purchase_amount + "credit": self.purchase_receipt_amount, + "credit_in_account_currency": self.purchase_receipt_amount })) gl_entries.append(self.get_gl_dict({ @@ -329,8 +335,8 @@ class Asset(AccountsController): "against": cwip_account, "remarks": self.get("remarks") or _("Accounting Entry for Asset"), "posting_date": self.available_for_use_date, - "debit": self.gross_purchase_amount, - "debit_in_account_currency": self.gross_purchase_amount + "debit": self.purchase_receipt_amount, + "debit_in_account_currency": self.purchase_receipt_amount })) make_gl_entries(gl_entries) 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/asset_adjustment.js b/erpnext/assets/doctype/asset_adjustment/asset_adjustment.js index 0535743703..11c02e105f 100644 --- a/erpnext/assets/doctype/asset_adjustment/asset_adjustment.js +++ b/erpnext/assets/doctype/asset_adjustment/asset_adjustment.js @@ -2,7 +2,29 @@ // For license information, please see license.txt frappe.ui.form.on('Asset Adjustment', { - refresh: function(frm) { + 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 index 8a0e95775a..faa36efe07 100644 --- a/erpnext/assets/doctype/asset_adjustment/asset_adjustment.json +++ b/erpnext/assets/doctype/asset_adjustment/asset_adjustment.json @@ -12,6 +12,37 @@ "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, @@ -38,7 +69,7 @@ "read_only": 0, "remember_last_selected_value": 0, "report_hide": 0, - "reqd": 0, + "reqd": 1, "search_index": 0, "set_only_once": 0, "unique": 0 @@ -100,37 +131,7 @@ "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": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, + "reqd": 1, "search_index": 0, "set_only_once": 0, "unique": 0 @@ -231,27 +232,26 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fieldname": "company", - "fieldtype": "Link", + "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": 0, + "in_list_view": 1, "in_standard_filter": 0, - "label": "Company", + "label": "Current Asset Value", "length": 0, "no_copy": 0, - "options": "Company", "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": 0, + "reqd": 1, "search_index": 0, "set_only_once": 0, "unique": 0 @@ -281,7 +281,7 @@ "read_only": 0, "remember_last_selected_value": 0, "report_hide": 0, - "reqd": 0, + "reqd": 1, "search_index": 0, "set_only_once": 0, "unique": 0 @@ -292,8 +292,8 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fieldname": "accumulated_depreciation_account", - "fieldtype": "Link", + "fieldname": "difference_amount", + "fieldtype": "Currency", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, @@ -301,15 +301,14 @@ "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, - "label": "Accumulated Depreciation Account", + "label": "Difference Amount", "length": 0, - "no_copy": 0, - "options": "Account", + "no_copy": 1, "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": 0, @@ -358,7 +357,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2018-05-11 00:25:07.222408", + "modified": "2018-05-11 21:45:03.459696", "modified_by": "Administrator", "module": "Assets", "name": "Asset Adjustment", diff --git a/erpnext/assets/doctype/asset_adjustment/asset_adjustment.py b/erpnext/assets/doctype/asset_adjustment/asset_adjustment.py index 437f9bd902..6b4b752e7f 100644 --- a/erpnext/assets/doctype/asset_adjustment/asset_adjustment.py +++ b/erpnext/assets/doctype/asset_adjustment/asset_adjustment.py @@ -4,7 +4,100 @@ 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): - pass + 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/config/assets.py b/erpnext/config/assets.py index 99a7a5c744..d52f1420cd 100644 --- a/erpnext/config/assets.py +++ b/erpnext/config/assets.py @@ -43,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/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py index f33ed25a06..c4e9fdd61e 100644 --- a/erpnext/controllers/buying_controller.py +++ b/erpnext/controllers/buying_controller.py @@ -511,6 +511,7 @@ class BuyingController(StockController): 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, @@ -522,7 +523,8 @@ class BuyingController(StockController): 'company': self.company, 'purchase_date': self.posting_date, 'calculate_depreciation': 1, - 'gross_purchase_amount': flt(row.base_net_amount + row.item_tax_amount), + '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 }) From 352df959765e8bff3edfdf4f178870fd100cddc7 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Sat, 12 May 2018 12:29:04 +0530 Subject: [PATCH 34/40] Patch to make location --- erpnext/patches.txt | 1 + .../v11_0/make_location_from_warehouse.py | 27 +++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 erpnext/patches/v11_0/make_location_from_warehouse.py diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 4bbb3e9e70..2828d7788b 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -528,3 +528,4 @@ 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.create_department_records_for_each_company +erpnext.patches.v11_0.make_location_from_warehouse \ 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..a3c66635b2 --- /dev/null +++ b/erpnext/patches/v11_0/make_location_from_warehouse.py @@ -0,0 +1,27 @@ +# Copyright (c) 2017, Frappe and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe + +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 + +def get_parent_warehouse_name(warehouse): + return frappe.db.get_value('Warehouse', warehouse, 'warehouse_name') + \ No newline at end of file From 11679884e4b7f629bbb39760c2d9ca67792c8dcc Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Sat, 12 May 2018 15:05:09 +0530 Subject: [PATCH 35/40] Patch to move asset fields to Asset Finance Book table --- .../asset_category/asset_category.json | 94 +------------------ .../doctype/asset_category/asset_category.py | 7 +- .../asset_finance_book.json | 9 +- ..._asset_finance_book_against_old_entries.py | 46 +++++++++ .../v11_0/make_location_from_warehouse.py | 3 + 5 files changed, 59 insertions(+), 100 deletions(-) create mode 100644 erpnext/patches/v11_0/make_asset_finance_book_against_old_entries.py diff --git a/erpnext/assets/doctype/asset_category/asset_category.json b/erpnext/assets/doctype/asset_category/asset_category.json index b655b40475..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\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, @@ -104,66 +72,6 @@ "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": "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, @@ -297,7 +205,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2018-05-10 15:12:05.954200", + "modified": "2018-05-12 14:56:04.116425", "modified_by": "Administrator", "module": "Assets", "name": "Asset Category", diff --git a/erpnext/assets/doctype/asset_category/asset_category.py b/erpnext/assets/doctype/asset_category/asset_category.py index fa0bd83117..bbdc6ec2cf 100644 --- a/erpnext/assets/doctype/asset_category/asset_category.py +++ b/erpnext/assets/doctype/asset_category/asset_category.py @@ -10,9 +10,10 @@ 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): diff --git a/erpnext/assets/doctype/asset_finance_book/asset_finance_book.json b/erpnext/assets/doctype/asset_finance_book/asset_finance_book.json index 351f9d0c66..f75c8510dc 100644 --- a/erpnext/assets/doctype/asset_finance_book/asset_finance_book.json +++ b/erpnext/assets/doctype/asset_finance_book/asset_finance_book.json @@ -70,7 +70,7 @@ "read_only": 0, "remember_last_selected_value": 0, "report_hide": 0, - "reqd": 0, + "reqd": 1, "search_index": 0, "set_only_once": 0, "unique": 0 @@ -100,7 +100,7 @@ "read_only": 0, "remember_last_selected_value": 0, "report_hide": 0, - "reqd": 0, + "reqd": 1, "search_index": 0, "set_only_once": 0, "unique": 0 @@ -160,7 +160,7 @@ "read_only": 0, "remember_last_selected_value": 0, "report_hide": 0, - "reqd": 0, + "reqd": 1, "search_index": 0, "set_only_once": 0, "unique": 0 @@ -203,6 +203,7 @@ "collapsible": 0, "columns": 0, "default": "0", + "depends_on": "eval:parent.doctype == 'Asset'", "fieldname": "expected_value_after_useful_life", "fieldtype": "Currency", "hidden": 0, @@ -270,7 +271,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2018-05-10 18:05:58.900298", + "modified": "2018-05-12 14:56:44.800046", "modified_by": "Administrator", "module": "Assets", "name": "Asset Finance Book", 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..75f0ce6450 --- /dev/null +++ b/erpnext/patches/v11_0/make_asset_finance_book_against_old_entries.py @@ -0,0 +1,46 @@ +# 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('stock', 'doctype', 'asset_finance_book') + frappe.reload_doc('stock', '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.warehoue_name where ast.warehoue = wh.name""") + + frappe.db.sql(""" update `tabAsset Movement` ast_mv + set ast_mv.source_location = (select warehoue_name from `tabWarehouse` where name = ast_mv.source_warehouse), + ast_mv.target_location = (select warehoue_name from `tabWarehouse` where name = ast_mv.target_warehouse)""") + + for d in frappe.get_all('Asset'): + doc = frappe.get_doc('Asset', d.name) + 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 index a3c66635b2..b838ec98bc 100644 --- a/erpnext/patches/v11_0/make_location_from_warehouse.py +++ b/erpnext/patches/v11_0/make_location_from_warehouse.py @@ -3,6 +3,7 @@ from __future__ import unicode_literals import frappe +from frappe.utils.nestedset import rebuild_tree def execute(): frappe.reload_doc('assets', 'doctype', 'location') @@ -22,6 +23,8 @@ def execute(): 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 From d644e6da16979bcd56c05b6fbcaffef0a7d89119 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Sat, 12 May 2018 15:27:18 +0530 Subject: [PATCH 36/40] Code cleanup --- erpnext/assets/doctype/asset/asset.py | 6 ++-- erpnext/controllers/buying_controller.py | 3 ++ erpnext/patches.txt | 3 +- ..._asset_finance_book_against_old_entries.py | 29 ++++++++++--------- 4 files changed, 23 insertions(+), 18 deletions(-) diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py index 748849ecb2..55a29bc0df 100644 --- a/erpnext/assets/doctype/asset/asset.py +++ b/erpnext/assets/doctype/asset/asset.py @@ -105,18 +105,18 @@ class Asset(AccountsController): previous_scheduled_date = add_months(d.depreciation_start_date, (n-1) * 12) depreciation_amount = \ self.get_depreciation_amount_prorata_temporis(value_after_depreciation, - row, previous_scheduled_date, schedule_date) + 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, - row, self.available_for_use_date, schedule_date) + 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, row) + self.get_depreciation_amount_prorata_temporis(value_after_depreciation, d) if value_after_depreciation != 0: value_after_depreciation -= flt(depreciation_amount) diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py index c4e9fdd61e..85fb3f0a66 100644 --- a/erpnext/controllers/buying_controller.py +++ b/erpnext/controllers/buying_controller.py @@ -89,6 +89,9 @@ class BuyingController(StockController): 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): diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 2828d7788b..69b11d65d3 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -528,4 +528,5 @@ 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.create_department_records_for_each_company -erpnext.patches.v11_0.make_location_from_warehouse \ No newline at end of file +erpnext.patches.v11_0.make_location_from_warehouse +erpnext.patches.v11_0.make_asset_finance_book_against_old_entries \ No newline at end of file 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 index 75f0ce6450..18622f2301 100644 --- 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 @@ -6,31 +6,32 @@ import frappe from frappe.utils.nestedset import rebuild_tree def execute(): - frappe.reload_doc('stock', 'doctype', 'asset_finance_book') - frappe.reload_doc('stock', 'doctype', 'depreciation_schedule') + 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.warehoue_name where ast.warehoue = wh.name""") + 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 warehoue_name from `tabWarehouse` where name = ast_mv.source_warehouse), - ast_mv.target_location = (select warehoue_name from `tabWarehouse` where name = ast_mv.target_warehouse)""") + 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) - 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 - }) + 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() + 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 """) From 75c53e5022ec9b513b4dadabe174560ea3614984 Mon Sep 17 00:00:00 2001 From: Jamsheer Date: Mon, 14 May 2018 19:17:16 +0530 Subject: [PATCH 37/40] Fix - missing semicolon --- .../additional_salary_component.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/hr/doctype/additional_salary_component/additional_salary_component.js b/erpnext/hr/doctype/additional_salary_component/additional_salary_component.js index 36bfdf2a08..13ed239b36 100644 --- a/erpnext/hr/doctype/additional_salary_component/additional_salary_component.js +++ b/erpnext/hr/doctype/additional_salary_component/additional_salary_component.js @@ -8,14 +8,14 @@ frappe.ui.form.on('Additional Salary Component', { filters: { type: "earning" } - } + }; }); frm.set_query("employee", function() { return { filters: { company: frm.doc.company } - } + }; }); } }); From 4bd5583e11608344ec31453ff6e7167eb43c2336 Mon Sep 17 00:00:00 2001 From: Shreya Date: Mon, 14 May 2018 16:14:41 +0530 Subject: [PATCH 38/40] Make Available Leave HTML Table --- .../leave_application/leave_application.js | 30 ++++++++++++++++++- .../leave_application/leave_application.py | 26 ++++++++++++++-- .../leave_application_dashboard.html | 30 +++++++++++++++++++ 3 files changed, 82 insertions(+), 4 deletions(-) create mode 100644 erpnext/hr/doctype/leave_application/leave_application_dashboard.html 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 23514e16e2..304afdd7ed 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) @@ -306,6 +307,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): @@ -316,16 +335,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)) @@ -333,6 +352,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") }}
+ + + + + + + + + + + + + + {% for(const [key, value] of Object.entries(data)) { %} + + + + + + + + {% } %} + +
{{ __("Leave Type") }}{{ __("Total Allocated Leaves") }}{{ __("Used Leaves") }}{{ __("Pending Leaves") }}{{ __("Available Leaves") }}
{%= 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 From b698846c300c9f42ea6951d41cbd54f4c19d31cd Mon Sep 17 00:00:00 2001 From: Manas Solanki Date: Thu, 10 May 2018 18:07:20 +0530 Subject: [PATCH 39/40] [feature] added the employee onboarding and separation doctype --- erpnext/hr/doctype/employee/employee.json | 66 +- erpnext/hr/doctype/employee/employee.py | 10 + .../employee_boarding_activity/__init__.py | 0 .../employee_boarding_activity.json | 291 +++++++++ .../employee_boarding_activity.py | 10 + .../doctype/employee_onboarding/__init__.py | 0 .../employee_onboarding.js | 59 ++ .../employee_onboarding.json | 569 ++++++++++++++++++ .../employee_onboarding.py | 50 ++ .../test_employee_onboarding.js | 23 + .../test_employee_onboarding.py | 10 + .../employee_onboarding_activity/__init__.py | 0 .../employee_onboarding_activity.json | 290 +++++++++ .../employee_onboarding_activity.py | 10 + .../employee_onboarding_template/__init__.py | 0 .../employee_onboarding_template.js | 8 + .../employee_onboarding_template.json | 284 +++++++++ .../employee_onboarding_template.py | 10 + .../test_employee_onboarding_template.js | 23 + .../test_employee_onboarding_template.py | 10 + .../doctype/employee_separation/__init__.py | 0 .../employee_separation.js | 49 ++ .../employee_separation.json | 567 +++++++++++++++++ .../employee_separation.py | 16 + .../test_employee_separation.js | 23 + .../test_employee_separation.py | 10 + .../employee_separation_template/__init__.py | 0 .../employee_separation_template.js | 8 + .../employee_separation_template.json | 284 +++++++++ .../employee_separation_template.py | 10 + .../test_employee_separation_template.js | 23 + .../test_employee_separation_template.py | 10 + erpnext/hr/utils.py | 100 ++- erpnext/projects/doctype/project/project.json | 97 +-- erpnext/projects/doctype/task/task.json | 73 ++- 35 files changed, 2913 insertions(+), 80 deletions(-) create mode 100644 erpnext/hr/doctype/employee_boarding_activity/__init__.py create mode 100644 erpnext/hr/doctype/employee_boarding_activity/employee_boarding_activity.json create mode 100644 erpnext/hr/doctype/employee_boarding_activity/employee_boarding_activity.py create mode 100644 erpnext/hr/doctype/employee_onboarding/__init__.py create mode 100644 erpnext/hr/doctype/employee_onboarding/employee_onboarding.js create mode 100644 erpnext/hr/doctype/employee_onboarding/employee_onboarding.json create mode 100644 erpnext/hr/doctype/employee_onboarding/employee_onboarding.py create mode 100644 erpnext/hr/doctype/employee_onboarding/test_employee_onboarding.js create mode 100644 erpnext/hr/doctype/employee_onboarding/test_employee_onboarding.py create mode 100644 erpnext/hr/doctype/employee_onboarding_activity/__init__.py create mode 100644 erpnext/hr/doctype/employee_onboarding_activity/employee_onboarding_activity.json create mode 100644 erpnext/hr/doctype/employee_onboarding_activity/employee_onboarding_activity.py create mode 100644 erpnext/hr/doctype/employee_onboarding_template/__init__.py create mode 100644 erpnext/hr/doctype/employee_onboarding_template/employee_onboarding_template.js create mode 100644 erpnext/hr/doctype/employee_onboarding_template/employee_onboarding_template.json create mode 100644 erpnext/hr/doctype/employee_onboarding_template/employee_onboarding_template.py create mode 100644 erpnext/hr/doctype/employee_onboarding_template/test_employee_onboarding_template.js create mode 100644 erpnext/hr/doctype/employee_onboarding_template/test_employee_onboarding_template.py create mode 100644 erpnext/hr/doctype/employee_separation/__init__.py create mode 100644 erpnext/hr/doctype/employee_separation/employee_separation.js create mode 100644 erpnext/hr/doctype/employee_separation/employee_separation.json create mode 100644 erpnext/hr/doctype/employee_separation/employee_separation.py create mode 100644 erpnext/hr/doctype/employee_separation/test_employee_separation.js create mode 100644 erpnext/hr/doctype/employee_separation/test_employee_separation.py create mode 100644 erpnext/hr/doctype/employee_separation_template/__init__.py create mode 100644 erpnext/hr/doctype/employee_separation_template/employee_separation_template.js create mode 100644 erpnext/hr/doctype/employee_separation_template/employee_separation_template.json create mode 100644 erpnext/hr/doctype/employee_separation_template/employee_separation_template.py create mode 100644 erpnext/hr/doctype/employee_separation_template/test_employee_separation_template.js create mode 100644 erpnext/hr/doctype/employee_separation_template/test_employee_separation_template.py diff --git a/erpnext/hr/doctype/employee/employee.json b/erpnext/hr/doctype/employee/employee.json index ef2c75dc83..3527197edc 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-10 07:52:24.326361", "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/utils.py b/erpnext/hr/utils.py index 686f79170c..076b1452df 100644 --- a/erpnext/hr/utils.py +++ b/erpnext/hr/utils.py @@ -6,11 +6,100 @@ import frappe from frappe import _ from frappe.utils import formatdate, format_datetime from frappe.utils import getdate, get_datetime +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 + " for " + 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 + " for " + 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 = [] @@ -39,17 +128,6 @@ def get_employee_field_property(employee, fieldname): else: return False -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 - def get_leave_period(from_date, to_date, company): leave_period = frappe.db.sql(""" select name, from_date, to_date 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, From 094e1841e023a4553ffe7bb29d18d9927bc98f12 Mon Sep 17 00:00:00 2001 From: Manas Solanki Date: Mon, 14 May 2018 20:33:28 +0530 Subject: [PATCH 40/40] minor changes and fixed the conflicts --- erpnext/hr/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/hr/utils.py b/erpnext/hr/utils.py index 076b1452df..213d46ea3d 100644 --- a/erpnext/hr/utils.py +++ b/erpnext/hr/utils.py @@ -22,7 +22,7 @@ class EmployeeBoardingController(Document): def on_submit(self): # create the project for the given employee onboarding - project_name = self.doctype + " for " + self.employee_name + project_name = _(self.doctype) + " : " + self.employee_name if self.doctype == "Employee Onboarding": project_name += " (" + self.job_applicant + ")" else: @@ -41,7 +41,7 @@ class EmployeeBoardingController(Document): task = frappe.get_doc({ "doctype": "Task", "project": project.name, - "subject": activity.activity_name + " for " + self.employee_name, + "subject": activity.activity_name + " : " + self.employee_name, "description": activity.description, "department": self.department, "company": self.company