diff --git a/erpnext/accounts/doctype/account/account.json b/erpnext/accounts/doctype/account/account.json index 668164ca641..de28a59f8ca 100644 --- a/erpnext/accounts/doctype/account/account.json +++ b/erpnext/accounts/doctype/account/account.json @@ -412,7 +412,7 @@ "no_copy": 0, "oldfieldname": "account_type", "oldfieldtype": "Select", - "options": "\nAccumulated Depreciation\nBank\nCash\nChargeable\nCost of Goods Sold\nDepreciation\nEquity\nExpense Account\nExpenses Included In Valuation\nFixed Asset\nIncome Account\nPayable\nReceivable\nRound Off\nStock\nStock Adjustment\nStock Received But Not Billed\nTax\nTemporary", + "options": "\nAccumulated Depreciation\nAsset Received But Not Billed\nBank\nCash\nChargeable\nCapital Work in Progress\nCost of Goods Sold\nDepreciation\nEquity\nExpense Account\nExpenses Included In Asset Valuation\nExpenses Included In Valuation\nFixed Asset\nIncome Account\nPayable\nReceivable\nRound Off\nStock\nStock Adjustment\nStock Received But Not Billed\nTax\nTemporary", "permlevel": 0, "print_hide": 0, "print_hide_if_no_value": 0, @@ -625,7 +625,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2018-05-02 11:00:34.108490", + "modified": "2018-05-07 15:37:25.962506", "modified_by": "Administrator", "module": "Accounts", "name": "Account", diff --git a/erpnext/accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts.py b/erpnext/accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts.py index 5452040fb6c..6e1637165a8 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 bad84533a5a..5ed3e45086c 100644 --- a/erpnext/accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts_with_account_number.py +++ b/erpnext/accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts_with_account_number.py @@ -85,6 +85,10 @@ def get(): "account_type": "Accumulated Depreciation", "account_number": "1780" }, + _("CWIP Account"): { + "account_type": "Capital Work in Progress", + "account_number": "1790" + }, "account_number": "1700" }, _("Investments"): { @@ -108,6 +112,10 @@ def get(): "account_type": "Cost of Goods Sold", "account_number": "5111" }, + _("Expenses Included In Asset Valuation"): { + "account_type": "Expenses Included In Asset Valuation", + "account_number": "5112" + }, _("Expenses Included In Valuation"): { "account_type": "Expenses Included In Valuation", "account_number": "5118" @@ -228,6 +236,10 @@ def get(): "account_type": "Stock Received But Not Billed", "account_number": "2210" }, + _("Asset Received But Not Billed"): { + "account_type": "Asset Received But Not Billed", + "account_number": "2211" + }, "account_number": "2200" }, _("Duties and Taxes"): { diff --git a/erpnext/accounts/doctype/accounting_period/accounting_period.js b/erpnext/accounts/doctype/accounting_period/accounting_period.js index 1fb57eabcfd..e3d805a1681 100644 --- a/erpnext/accounts/doctype/accounting_period/accounting_period.js +++ b/erpnext/accounts/doctype/accounting_period/accounting_period.js @@ -2,7 +2,23 @@ // For license information, please see license.txt frappe.ui.form.on('Accounting Period', { - refresh: function(frm) { - + onload: function(frm) { + if(frm.doc.closed_documents.length === 0 || (frm.doc.closed_documents.length === 1 && frm.doc.closed_documents[0].document_type == undefined)) { + frappe.call({ + method: "get_doctypes_for_closing", + doc:frm.doc, + callback: function(r) { + if(r.message) { + cur_frm.clear_table("closed_documents"); + r.message.forEach(function(element) { + var c = frm.add_child("closed_documents"); + c.document_type = element.document_type; + c.closed = element.closed; + }); + refresh_field("closed_documents"); + } + } + }); + } } }); diff --git a/erpnext/accounts/doctype/accounting_period/accounting_period.py b/erpnext/accounts/doctype/accounting_period/accounting_period.py index 31f18490a35..32441db2c1b 100644 --- a/erpnext/accounts/doctype/accounting_period/accounting_period.py +++ b/erpnext/accounts/doctype/accounting_period/accounting_period.py @@ -7,4 +7,48 @@ import frappe from frappe.model.document import Document class AccountingPeriod(Document): - pass + def validate(self): + self.validate_overlap() + + def before_insert(self): + self.bootstrap_doctypes_for_closing() + + def autoname(self): + company_abbr = frappe.db.get_value("Company", self.company, "abbr") + self.name = " - ".join([self.period_name, company_abbr]) + + def validate_overlap(self): + existing_accounting_period = frappe.db.sql("""select name from `tabAccounting Period` + where ( + (%(start_date)s between start_date and end_date) + or (%(end_date)s between start_date and end_date) + or (start_date between %(start_date)s and %(end_date)s) + or (end_date between %(start_date)s and %(end_date)s) + ) and name!=%(name)s and company=%(company)s""", + { + "start_date": self.start_date, + "end_date": self.end_date, + "name": self.name, + "company": self.company + }, as_dict=True) + + if len(existing_accounting_period) > 0: + frappe.throw("Accounting Period overlaps with {0}".format(existing_accounting_period[0].get("name"))) + + def get_doctypes_for_closing(self): + docs_for_closing = [] + #if not self.closed_documents or len(self.closed_documents) == 0: + doctypes = ["Sales Invoice", "Purchase Invoice", "Journal Entry", "Payroll Entry", "Bank Reconciliation", "Asset", "Purchase Order", "Sales Order", "Leave Application", "Leave Allocation", "Stock Entry"] + closed_doctypes = [{"document_type": doctype, "closed": 1} for doctype in doctypes] + for closed_doctype in closed_doctypes: + docs_for_closing.append(closed_doctype) + + return docs_for_closing + + def bootstrap_doctypes_for_closing(self): + if len(self.closed_documents) == 0: + for doctype_for_closing in self.get_doctypes_for_closing(): + self.append('closed_documents', { + "document_type": doctype_for_closing.document_type, + "closed": doctype_for_closing.closed + }) diff --git a/erpnext/accounts/doctype/accounting_period/test_accounting_period.py b/erpnext/accounts/doctype/accounting_period/test_accounting_period.py index 99694d2136e..cc2e6a9fc6f 100644 --- a/erpnext/accounts/doctype/accounting_period/test_accounting_period.py +++ b/erpnext/accounts/doctype/accounting_period/test_accounting_period.py @@ -7,4 +7,21 @@ import frappe import unittest class TestAccountingPeriod(unittest.TestCase): - pass + def test_overlap(self): + ap1 = create_accounting_period({"start_date":"2018-04-01", "end_date":"2018-06-30", "company":"Wind Power LLC"}) + ap1.save() + ap2 = create_accounting_period({"start_date":"2018-06-30", "end_date":"2018-07-10", "company":"Wind Power LLC"}) + self.assertRaises(frappe.OverlapError, accounting_period_2.save()) + + def tearDown(self): + pass + + +def create_accounting_period(**args): + accounting_period = frappe.new_doc("Accounting Period") + accounting_period.start_date = args.start_date or frappe.utils.datetime.date(2018, 4, 1) + accounting_period.end_date = args.end_date or frappe.utils.datetime.date(2018, 6, 30) + accounting_period.company = args.company + accounting_period.period_name = "_Test_Period_Name_1" + + return accounting_period diff --git a/erpnext/accounts/doctype/cost_center/cost_center.js b/erpnext/accounts/doctype/cost_center/cost_center.js index cbc37fff8d3..a5bcaf47c1c 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 9eddeec04ff..4da21f11fea 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 fe1e9076de4..24af0ce3769 100644 --- a/erpnext/accounts/doctype/cost_center/cost_center.py +++ b/erpnext/accounts/doctype/cost_center/cost_center.py @@ -4,6 +4,7 @@ from __future__ import unicode_literals import frappe from frappe import _ +from frappe.utils import cint, cstr from frappe.utils.nestedset import NestedSet class CostCenter(NestedSet): @@ -62,8 +63,68 @@ class CostCenter(NestedSet): super(CostCenter, self).after_rename(olddn, newdn, merge) if not merge: - frappe.db.set_value("Cost Center", newdn, "cost_center_name", - " - ".join(newdn.split(" - ")[:-1])) + new_cost_center = frappe.db.get_value("Cost Center", newdn, ["cost_center_name", "cost_center_number"], as_dict=1) + + # exclude company abbr + new_parts = newdn.split(" - ")[:-1] + # update cost center number and remove from parts + if new_parts[0][0].isdigit(): + if len(new_parts) == 1: + new_parts = newdn.split(" ") + if new_cost_center.cost_center_number != new_parts[0]: + validate_field_number("Cost Center", self.name, new_parts[0], self.company, "cost_center_number") + self.cost_center_number = new_parts[0] + self.db_set("cost_center_number", new_parts[0]) + new_parts = new_parts[1:] + + # update cost center name + cost_center_name = " - ".join(new_parts) + if new_cost_center.cost_center_name != cost_center_name: + self.cost_center_name = cost_center_name + self.db_set("cost_center_name", cost_center_name) def on_doctype_update(): - frappe.db.add_index("Cost Center", ["lft", "rgt"]) \ No newline at end of file + frappe.db.add_index("Cost Center", ["lft", "rgt"]) + +def get_doc_name_autoname(field_value, doc_title, name, company): + if company: + name_split=name.split("-") + parts = [doc_title.strip(), name_split[len(name_split)-1].strip()] + else: + parts = [doc_title.strip()] + if cstr(field_value).strip(): + parts.insert(0, cstr(field_value).strip()) + return ' - '.join(parts) + +def validate_field_number(doctype_name, name, field_value, company, field_name): + if field_value: + if company: + doctype_with_same_number = frappe.db.get_value(doctype_name, + {field_name: field_value, "company": company, "name": ["!=", name]}) + else: + doctype_with_same_number = frappe.db.get_value(doctype_name, + {field_name: field_value, "name": ["!=", name]}) + if doctype_with_same_number: + frappe.throw(_("{0} Number {1} already used in account {2}") + .format(doctype_name, field_value, doctype_with_same_number)) + +@frappe.whitelist() +def update_number_field(doctype_name, name, field_name, field_value, company): + + doc_title = frappe.db.get_value(doctype_name, name, frappe.scrub(doctype_name)+"_name") + + validate_field_number(doctype_name, name, field_value, company, field_name) + + frappe.db.set_value(doctype_name, name, field_name, field_value) + + if doc_title[0].isdigit(): + separator = " - " if " - " in doc_title else " " + doc_title = doc_title.split(separator, 1)[1] + + frappe.db.set_value(doctype_name, name, frappe.scrub(doctype_name)+"_name", doc_title) + + new_name = get_doc_name_autoname(field_value, doc_title, name, company) + + if name != new_name: + frappe.rename_doc(doctype_name, name, new_name) + return new_name \ No newline at end of file diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py index 51308e50083..9bbd1371598 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/accounts/doctype/purchase_invoice/purchase_invoice.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js index e7fdd64a6d8..d2c41938fe4 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 67b41a3248d..3e375e50511 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_asset_category_account form_grid_templates = { "items": "templates/form_grid/item_grid.html" @@ -305,24 +306,8 @@ class PurchaseInvoice(BuyingController): self.make_gl_entries() self.update_project() - self.update_fixed_asset() update_linked_invoice(self.doctype, self.name, self.inter_company_invoice_reference) - def update_fixed_asset(self): - for d in self.get("items"): - if d.is_fixed_asset: - asset = frappe.get_doc("Asset", d.asset) - if self.docstatus==1: - asset.purchase_invoice = self.name - asset.purchase_date = self.posting_date - asset.supplier = self.supplier - else: - asset.purchase_invoice = None - asset.supplier = None - - asset.flags.ignore_validate_update_after_submit = True - asset.save() - def make_gl_entries(self, gl_entries=None, repost_future_gle=True, from_repost=False): if not self.grand_total: return @@ -438,6 +423,50 @@ class PurchaseInvoice(BuyingController): "remarks": self.get("remarks") or _("Accounting Entry for Stock"), "credit": flt(item.rm_supp_cost) }, warehouse_account[self.supplier_warehouse]["account_currency"])) + + elif item.is_fixed_asset: + asset_accounts = self.get_company_default(["asset_received_but_not_billed", + "expenses_included_in_asset_valuation", "capital_work_in_progress_account"]) + + asset_amount = flt(item.net_amount) + flt(item.item_tax_amount/self.conversion_rate) + base_asset_amount = flt(item.base_net_amount + item.item_tax_amount) + + if not self.update_stock: + asset_rbnb_currency = get_account_currency(asset_accounts[0]) + gl_entries.append(self.get_gl_dict({ + "account": asset_accounts[0], + "against": self.supplier, + "remarks": self.get("remarks") or _("Accounting Entry for Asset"), + "debit": base_asset_amount, + "debit_in_account_currency": (base_asset_amount + if asset_rbnb_currency == self.company_currency else asset_amount) + })) + else: + cwip_account = get_asset_category_account(item.asset, + 'capital_work_in_progress_account') or asset_accounts[2] + + cwip_account_currency = get_account_currency(cwip_account) + gl_entries.append(self.get_gl_dict({ + "account": cwip_account, + "against": self.supplier, + "remarks": self.get("remarks") or _("Accounting Entry for Asset"), + "debit": base_asset_amount, + "debit_in_account_currency": (base_asset_amount + if cwip_account_currency == self.company_currency else asset_amount) + })) + + if item.item_tax_amount: + asset_eiiav_currency = get_account_currency(asset_accounts[0]) + gl_entries.append(self.get_gl_dict({ + "account": asset_accounts[1], + "against": self.supplier, + "remarks": self.get("remarks") or _("Accounting Entry for Asset"), + "cost_center": item.cost_center, + "credit": item.item_tax_amount, + "credit_in_account_currency": (item.item_tax_amount + if asset_eiiav_currency == self.company_currency else + item.item_tax_amount / self.conversion_rate) + })) else: gl_entries.append( self.get_gl_dict({ @@ -636,7 +665,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) @@ -708,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/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json b/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json index d1f99ab3eb6..ef9b2f69b60 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 236c4f9f9b0..c05667a7677 100644 --- a/erpnext/assets/doctype/asset/asset.js +++ b/erpnext/assets/doctype/asset/asset.js @@ -23,6 +23,14 @@ frappe.ui.form.on('Asset', { } }; }); + + frm.set_query("department", function() { + return { + "filters": { + "company": frm.doc.company, + } + }; + }); }, refresh: function(frm) { @@ -49,6 +57,19 @@ frappe.ui.form.on('Asset', { erpnext.asset.restore_asset(frm); }); } + + if (frm.doc.purchase_receipt) { + frm.add_custom_button("General Ledger", function() { + frappe.route_options = { + "voucher_no": frm.doc.name, + "from_date": frm.doc.available_for_use_date, + "to_date": frm.doc.available_for_use_date, + "company": frm.doc.company + }; + frappe.set_route("query-report", "General Ledger"); + }); + } + if (frm.doc.status=='Submitted' && !frm.doc.is_existing_asset && !frm.doc.purchase_invoice) { frm.add_custom_button(__("Purchase Invoice"), function() { frm.trigger("make_purchase_invoice"); @@ -59,6 +80,12 @@ frappe.ui.form.on('Asset', { frm.trigger("create_asset_maintenance"); }, __("Make")); } + if (frm.doc.status != 'Fully Depreciated') { + frm.add_custom_button(__("Asset Adjustment"), function() { + frm.trigger("create_asset_maintenance"); + }, __("Make")); + } + frm.page.set_inner_btn_group_as_primary(__("Make")); frm.trigger("setup_chart"); } @@ -123,9 +150,7 @@ frappe.ui.form.on('Asset', { }, callback: function(r, rt) { if(r.message) { - $.each(r.message, function(field, value) { - frm.set_value(field, value); - }) + frm.set_value('finance_books', r.message); } } }) @@ -133,7 +158,7 @@ frappe.ui.form.on('Asset', { }, is_existing_asset: function(frm) { - frm.toggle_reqd("next_depreciation_date", (!frm.doc.is_existing_asset && frm.doc.calculate_depreciation)); + // frm.toggle_reqd("next_depreciation_date", (!frm.doc.is_existing_asset && frm.doc.calculate_depreciation)); }, opening_accumulated_depreciation: function(frm) { @@ -173,7 +198,8 @@ frappe.ui.form.on('Asset', { args: { "asset": frm.doc.name, "item_code": frm.doc.item_code, - "company": frm.doc.company + "company": frm.doc.company, + "serial_no": frm.doc.serial_no }, method: "erpnext.assets.doctype.asset.asset.make_sales_invoice", callback: function(r) { @@ -282,15 +308,14 @@ erpnext.asset.transfer_asset = function(frm) { title: __("Transfer Asset"), fields: [ { - "label": __("Target Warehouse"), - "fieldname": "target_warehouse", + "label": __("Target Location"), + "fieldname": "target_location", "fieldtype": "Link", - "options": "Warehouse", + "options": "Location", "get_query": function () { return { filters: [ - ["Warehouse", "company", "in", ["", cstr(frm.doc.company)]], - ["Warehouse", "is_group", "=", 0] + ["Location", "is_group", "=", 0] ] } }, @@ -317,8 +342,8 @@ erpnext.asset.transfer_asset = function(frm) { args: { "asset": frm.doc.name, "transaction_date": args.transfer_date, - "source_warehouse": frm.doc.warehouse, - "target_warehouse": args.target_warehouse, + "source_warehouse": frm.doc.location, + "target_warehouse": args.target_location, "company": frm.doc.company } }, diff --git a/erpnext/assets/doctype/asset/asset.json b/erpnext/assets/doctype/asset/asset.json index 49b574d3b0f..49a010d7d59 100644 --- a/erpnext/assets/doctype/asset/asset.json +++ b/erpnext/assets/doctype/asset/asset.json @@ -3,7 +3,7 @@ "allow_guest_to_view": 0, "allow_import": 1, "allow_rename": 1, - "autoname": "field:asset_name", + "autoname": "naming_series:", "beta": 0, "creation": "2016-03-01 17:01:27.920130", "custom": 0, @@ -12,6 +12,38 @@ "document_type": "Document", "editable_grid": 0, "fields": [ + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "default": "AST", + "fieldname": "naming_series", + "fieldtype": "Select", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Naming Series", + "length": 0, + "no_copy": 0, + "options": "AST\nAT", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_on_submit": 0, @@ -135,38 +167,6 @@ "set_only_once": 0, "unique": 0 }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 1, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "Draft", - "fieldname": "status", - "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 1, - "label": "Status", - "length": 0, - "no_copy": 1, - "options": "Draft\nSubmitted\nPartially Depreciated\nFully Depreciated\nSold\nScrapped\nIn Maintenance\nOut of Order", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, { "allow_bulk_edit": 0, "allow_on_submit": 0, @@ -390,7 +390,7 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fieldname": "warehouse", + "fieldname": "location", "fieldtype": "Link", "hidden": 0, "ignore_user_permissions": 0, @@ -398,11 +398,11 @@ "in_filter": 0, "in_global_search": 0, "in_list_view": 0, - "in_standard_filter": 1, - "label": "Warehouse", + "in_standard_filter": 0, + "label": "Location", "length": 0, "no_copy": 0, - "options": "Warehouse", + "options": "Location", "permlevel": 0, "precision": "", "print_hide": 0, @@ -415,6 +415,37 @@ "set_only_once": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "custodian", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Custodian", + "length": 0, + "no_copy": 0, + "options": "Employee", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_on_submit": 0, @@ -476,97 +507,6 @@ "set_only_once": 0, "unique": 0 }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "purchase_invoice", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Purchase Invoice", - "length": 0, - "no_copy": 1, - "options": "Purchase Invoice", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "available_for_use_date", - "fieldtype": "Date", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Available-for-use Date", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "is_existing_asset", - "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Is Existing Asset", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, { "allow_bulk_edit": 0, "allow_on_submit": 0, @@ -688,6 +628,36 @@ "set_only_once": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "available_for_use_date", + "fieldtype": "Date", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Available-for-use Date", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_on_submit": 0, @@ -717,99 +687,6 @@ "set_only_once": 0, "unique": 0 }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "description": "", - "fieldname": "expected_value_after_useful_life", - "fieldtype": "Currency", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Expected Value After Useful Life", - "length": 0, - "no_copy": 0, - "options": "Company:company:default_currency", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "is_existing_asset", - "fieldname": "opening_accumulated_depreciation", - "fieldtype": "Currency", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Opening Accumulated Depreciation", - "length": 0, - "no_copy": 1, - "options": "Company:company:default_currency", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "section_break_20", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, { "allow_bulk_edit": 0, "allow_on_submit": 0, @@ -844,7 +721,100 @@ "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, - "collapsible": 1, + "collapsible": 0, + "columns": 0, + "fieldname": "is_existing_asset", + "fieldtype": "Check", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Is Existing Asset", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "is_existing_asset", + "fieldname": "opening_accumulated_depreciation", + "fieldtype": "Currency", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Opening Accumulated Depreciation", + "length": 0, + "no_copy": 1, + "options": "Company:company:default_currency", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "eval:(doc.is_existing_asset && doc.opening_accumulated_depreciation)", + "fieldname": "number_of_depreciations_booked", + "fieldtype": "Int", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Number of Depreciations Booked", + "length": 0, + "no_copy": 1, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, "columns": 0, "depends_on": "calculate_depreciation", "fieldname": "section_break_23", @@ -871,6 +841,66 @@ "set_only_once": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "finance_books", + "fieldtype": "Table", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Finance Books", + "length": 0, + "no_copy": 0, + "options": "Asset Finance Book", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "section_break_33", + "fieldtype": "Section Break", + "hidden": 1, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_on_submit": 0, @@ -994,37 +1024,6 @@ "set_only_once": 0, "unique": 0 }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "eval:(doc.is_existing_asset && doc.opening_accumulated_depreciation)", - "fieldname": "number_of_depreciations_booked", - "fieldtype": "Int", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Number of Depreciations Booked", - "length": 0, - "no_copy": 1, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, { "allow_bulk_edit": 0, "allow_on_submit": 0, @@ -1148,6 +1147,245 @@ "set_only_once": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 1, + "columns": 0, + "fieldname": "insurance_details", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Insurance details", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "policy_number", + "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Policy number", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "insurer", + "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Insurer", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "insured_value", + "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Insured value", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "column_break_48", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "insurance_start_date", + "fieldtype": "Date", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Insurance Start Date", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "insurance_end_date", + "fieldtype": "Date", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Insurance End Date", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "comprehensive_insurance", + "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Comprehensive Insurance", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_on_submit": 0, @@ -1209,6 +1447,220 @@ "set_only_once": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 1, + "columns": 0, + "fieldname": "other_details", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Other Details", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 1, + "bold": 0, + "collapsible": 0, + "columns": 0, + "default": "Draft", + "fieldname": "status", + "fieldtype": "Select", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Status", + "length": 0, + "no_copy": 1, + "options": "Draft\nSubmitted\nPartially Depreciated\nFully Depreciated\nSold\nScrapped\nIn Maintenance\nOut of Order\nIssue\nReceipt", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "default": "0", + "fieldname": "booked_fixed_asset", + "fieldtype": "Check", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Booked Fixed Asset", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "column_break_51", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "purchase_receipt", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Purchase Receipt", + "length": 0, + "no_copy": 1, + "options": "Purchase Receipt", + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "purchase_receipt_amount", + "fieldtype": "Currency", + "hidden": 1, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Purchase Receipt Amount", + "length": 0, + "no_copy": 1, + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "purchase_invoice", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Purchase Invoice", + "length": 0, + "no_copy": 1, + "options": "Purchase Invoice", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_on_submit": 0, @@ -1251,7 +1703,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2018-01-05 09:53:05.945328", + "modified": "2018-05-11 10:41:45.972686", "modified_by": "Administrator", "module": "Assets", "name": "Asset", @@ -1307,4 +1759,4 @@ "sort_order": "DESC", "track_changes": 0, "track_seen": 0 -} +} \ No newline at end of file diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py index baffdd757d2..55a29bc0df8 100644 --- a/erpnext/assets/doctype/asset/asset.py +++ b/erpnext/assets/doctype/asset/asset.py @@ -7,11 +7,14 @@ import frappe from frappe import _ from frappe.utils import flt, add_months, cint, nowdate, getdate, today, date_diff from frappe.model.document import Document -from erpnext.accounts.doctype.purchase_invoice.purchase_invoice import get_fixed_asset_account +from erpnext.assets.doctype.asset_category.asset_category import get_asset_category_account from erpnext.assets.doctype.asset.depreciation \ import get_disposal_account_and_cost_center, get_depreciation_accounts +from erpnext.accounts.general_ledger import make_gl_entries +from erpnext.accounts.utils import get_account_currency +from erpnext.controllers.accounts_controller import AccountsController -class Asset(Document): +class Asset(AccountsController): def validate(self): self.status = self.get_status() self.validate_item() @@ -26,6 +29,7 @@ class Asset(Document): def on_submit(self): self.set_status() + self.update_stock_movement() def on_cancel(self): self.validate_cancellation() @@ -45,11 +49,12 @@ class Asset(Document): frappe.throw(_("Item {0} must be a non-stock item").format(self.item_code)) def set_missing_values(self): - if self.item_code: - item_details = get_item_details(self.item_code) - for field, value in item_details.items(): - if not self.get(field): - self.set(field, value) + if not self.asset_category: + self.asset_category = frappe.db.get_value("Item", self.item_code, "asset_category") + + if self.item_code and not self.get('finance_books'): + finance_books = get_item_details(self.item_code, self.asset_category) + self.set('finance_books', finance_books) def validate_asset_values(self): if not flt(self.gross_purchase_amount): @@ -58,16 +63,105 @@ class Asset(Document): if not self.calculate_depreciation: return - if flt(self.expected_value_after_useful_life) >= flt(self.gross_purchase_amount): - frappe.throw(_("Expected Value After Useful Life must be less than Gross Purchase Amount")) + if self.available_for_use_date and getdate(self.available_for_use_date) < getdate(nowdate()): + frappe.throw(_("Available-for-use Date is entered as past date")) + + def make_depreciation_schedule(self): + if self.depreciation_method != 'Manual': + self.schedules = [] + + if not self.get("schedules") and self.available_for_use_date: + total_depreciations = sum([d.total_number_of_depreciations for d in self.get('finance_books')]) + + for d in self.get('finance_books'): + self.validate_asset_finance_books(d) + + value_after_depreciation = (flt(self.gross_purchase_amount) - + flt(self.opening_accumulated_depreciation)) + + d.value_after_depreciation = value_after_depreciation + + no_of_depreciations = cint(d.total_number_of_depreciations - 1) - cint(self.number_of_depreciations_booked) + end_date = add_months(d.depreciation_start_date, + no_of_depreciations * cint(d.frequency_of_depreciation)) + + total_days = date_diff(end_date, self.available_for_use_date) + rate_per_day = value_after_depreciation / total_days + + number_of_pending_depreciations = cint(d.total_number_of_depreciations) - \ + cint(self.number_of_depreciations_booked) + + from_date = self.available_for_use_date + if number_of_pending_depreciations: + next_depr_date = getdate(add_months(self.available_for_use_date, + number_of_pending_depreciations * 12)) + if (cint(frappe.db.get_value("Asset Settings", None, "schedule_based_on_fiscal_year")) == 1 + and getdate(d.depreciation_start_date) < next_depr_date): + + number_of_pending_depreciations += 1 + for n in range(number_of_pending_depreciations): + if n == range(number_of_pending_depreciations)[-1]: + schedule_date = add_months(self.available_for_use_date, n * 12) + previous_scheduled_date = add_months(d.depreciation_start_date, (n-1) * 12) + depreciation_amount = \ + self.get_depreciation_amount_prorata_temporis(value_after_depreciation, + d, previous_scheduled_date, schedule_date) + + elif n == range(number_of_pending_depreciations)[0]: + schedule_date = d.depreciation_start_date + depreciation_amount = \ + self.get_depreciation_amount_prorata_temporis(value_after_depreciation, + d, self.available_for_use_date, schedule_date) + + else: + schedule_date = add_months(d.depreciation_start_date, n * 12) + depreciation_amount = \ + self.get_depreciation_amount_prorata_temporis(value_after_depreciation, d) + + if value_after_depreciation != 0: + value_after_depreciation -= flt(depreciation_amount) + + self.append("schedules", { + "schedule_date": schedule_date, + "depreciation_amount": depreciation_amount, + "depreciation_method": d.depreciation_method, + "finance_book": d.finance_book, + "finance_book_id": d.idx + }) + else: + for n in range(number_of_pending_depreciations): + schedule_date = add_months(d.depreciation_start_date, + n * cint(d.frequency_of_depreciation)) + + if d.depreciation_method in ("Straight Line", "Manual"): + days = date_diff(schedule_date, from_date) + depreciation_amount = days * rate_per_day + from_date = schedule_date + else: + depreciation_amount = self.get_depreciation_amount(value_after_depreciation, + d.total_number_of_depreciations, d) + + if depreciation_amount: + value_after_depreciation -= flt(depreciation_amount) + + self.append("schedules", { + "schedule_date": schedule_date, + "depreciation_amount": depreciation_amount, + "depreciation_method": d.depreciation_method, + "finance_book": d.finance_book, + "finance_book_id": d.idx + }) + + def validate_asset_finance_books(self, row): + if flt(row.expected_value_after_useful_life) >= flt(self.gross_purchase_amount): + frappe.throw(_("Row {0}: Expected Value After Useful Life must be less than Gross Purchase Amount") + .format(row.idx)) if not self.is_existing_asset: self.opening_accumulated_depreciation = 0 self.number_of_depreciations_booked = 0 - if not self.next_depreciation_date: - frappe.throw(_("Next Depreciation Date is mandatory for new asset")) else: - depreciable_amount = flt(self.gross_purchase_amount) - flt(self.expected_value_after_useful_life) + depreciable_amount = flt(self.gross_purchase_amount) - flt(row.expected_value_after_useful_life) if flt(self.opening_accumulated_depreciation) > depreciable_amount: frappe.throw(_("Opening Accumulated Depreciation must be less than equal to {0}") .format(depreciable_amount)) @@ -78,139 +172,89 @@ class Asset(Document): else: self.number_of_depreciations_booked = 0 - if cint(self.number_of_depreciations_booked) > cint(self.total_number_of_depreciations): + if cint(self.number_of_depreciations_booked) > cint(row.total_number_of_depreciations): frappe.throw(_("Number of Depreciations Booked cannot be greater than Total Number of Depreciations")) - self.value_after_depreciation = (flt(self.gross_purchase_amount) - - flt(self.opening_accumulated_depreciation)) + if row.depreciation_start_date and getdate(row.depreciation_start_date) < getdate(nowdate()): + frappe.msgprint(_("Depreciation Row {0}: Depreciation Start Date is entered as past date") + .format(row.idx), title=_('Warning'), indicator='red') - if self.next_depreciation_date and getdate(self.next_depreciation_date) < getdate(nowdate()): - frappe.msgprint(_("Next Depreciation Date is entered as past date"), title=_('Warning'), indicator='red') + if row.depreciation_start_date and getdate(row.depreciation_start_date) < getdate(self.purchase_date): + frappe.throw(_("Depreciation Row {0}: Next Depreciation Date cannot be before Purchase Date") + .format(row.idx)) - if self.next_depreciation_date and getdate(self.next_depreciation_date) < getdate(self.purchase_date): - frappe.throw(_("Next Depreciation Date cannot be before Purchase Date")) + if row.depreciation_start_date and getdate(row.depreciation_start_date) < getdate(self.available_for_use_date): + frappe.throw(_("Depreciation Row {0}: Next Depreciation Date cannot be before Available-for-use Date") + .format(row.idx)) - if self.next_depreciation_date and getdate(self.next_depreciation_date) < getdate(self.available_for_use_date): - frappe.throw(_("Next Depreciation Date cannot be before Available-for-use Date")) + def set_accumulated_depreciation(self, ignore_booked_entry = False): + straight_line_idx = [d.idx for d in self.get("schedules") if d.depreciation_method == 'Straight Line'] + finance_books = [] - if (flt(self.value_after_depreciation) > flt(self.expected_value_after_useful_life) - and not self.next_depreciation_date and self.calculate_depreciation): - frappe.throw(_("Please set Next Depreciation Date")) - - def make_depreciation_schedule(self): - - if self.depreciation_method != 'Manual': - self.schedules = [] - - if not self.get("schedules") and self.next_depreciation_date: - value_after_depreciation = flt(self.value_after_depreciation) - - number_of_pending_depreciations = cint(self.total_number_of_depreciations) - \ - cint(self.number_of_depreciations_booked) - if number_of_pending_depreciations: - next_depr_date = getdate(add_months(self.available_for_use_date, - number_of_pending_depreciations * 12)) - if (cint(frappe.db.get_value("Asset Settings", None, "schedule_based_on_fiscal_year")) == 1 - and getdate(self.next_depreciation_date) < next_depr_date): - - number_of_pending_depreciations += 1 - for n in range(number_of_pending_depreciations): - if n == range(number_of_pending_depreciations)[-1]: - schedule_date = add_months(self.available_for_use_date, n * 12) - previous_scheduled_date = add_months(self.next_depreciation_date, (n-1) * 12) - depreciation_amount = \ - self.get_depreciation_amount_prorata_temporis(value_after_depreciation, - previous_scheduled_date, schedule_date) - - elif n == range(number_of_pending_depreciations)[0]: - schedule_date = self.next_depreciation_date - depreciation_amount = \ - self.get_depreciation_amount_prorata_temporis(value_after_depreciation, - self.available_for_use_date, schedule_date) - - else: - schedule_date = add_months(self.next_depreciation_date, n * 12) - depreciation_amount = \ - self.get_depreciation_amount_prorata_temporis(value_after_depreciation) - - if value_after_depreciation != 0: - value_after_depreciation -= flt(depreciation_amount) - - self.append("schedules", { - "schedule_date": schedule_date, - "depreciation_amount": depreciation_amount - }) - else: - for n in range(number_of_pending_depreciations): - schedule_date = add_months(self.next_depreciation_date, - n * cint(self.frequency_of_depreciation)) - - depreciation_amount = self.get_depreciation_amount(value_after_depreciation) - if depreciation_amount: - value_after_depreciation -= flt(depreciation_amount) - - self.append("schedules", { - "schedule_date": schedule_date, - "depreciation_amount": depreciation_amount - }) - - def set_accumulated_depreciation(self): - accumulated_depreciation = flt(self.opening_accumulated_depreciation) - value_after_depreciation = flt(self.value_after_depreciation) for i, d in enumerate(self.get("schedules")): + if ignore_booked_entry and d.journal_entry: + continue + + if d.finance_book_id not in finance_books: + accumulated_depreciation = flt(self.opening_accumulated_depreciation) + value_after_depreciation = flt(self.get_value_after_depreciation(d.finance_book_id)) + finance_books.append(d.finance_book_id) + depreciation_amount = flt(d.depreciation_amount, d.precision("depreciation_amount")) value_after_depreciation -= flt(depreciation_amount) - if i==len(self.get("schedules"))-1 and self.depreciation_method == "Straight Line": + if straight_line_idx and i == max(straight_line_idx) - 1: + book = self.get('finance_books')[cint(d.finance_book_id) - 1] depreciation_amount += flt(value_after_depreciation - - flt(self.expected_value_after_useful_life), d.precision("depreciation_amount")) + flt(book.expected_value_after_useful_life), d.precision("depreciation_amount")) d.depreciation_amount = depreciation_amount accumulated_depreciation += d.depreciation_amount d.accumulated_depreciation_amount = flt(accumulated_depreciation, d.precision("accumulated_depreciation_amount")) - def get_depreciation_amount(self, depreciable_value): - if self.depreciation_method in ("Straight Line", "Manual"): - depreciation_amount = (flt(self.value_after_depreciation) - - flt(self.expected_value_after_useful_life)) / (cint(self.total_number_of_depreciations) - - cint(self.number_of_depreciations_booked)) - else: - factor = 200.0 / self.total_number_of_depreciations - depreciation_amount = flt(depreciable_value * factor / 100, 0) + def get_value_after_depreciation(self, idx): + return flt(self.get('finance_books')[cint(idx)-1].value_after_depreciation) - value_after_depreciation = flt(depreciable_value) - depreciation_amount - if value_after_depreciation < flt(self.expected_value_after_useful_life): - depreciation_amount = flt(depreciable_value) - flt(self.expected_value_after_useful_life) + def get_depreciation_amount(self, depreciable_value, total_number_of_depreciations, row): + percentage_value = 100.0 if row.depreciation_method == 'Written Down Value' else 200.0 + + factor = percentage_value / total_number_of_depreciations + depreciation_amount = flt(depreciable_value * factor / 100, 0) + + value_after_depreciation = flt(depreciable_value) - depreciation_amount + if value_after_depreciation < flt(row.expected_value_after_useful_life): + depreciation_amount = flt(depreciable_value) - flt(row.expected_value_after_useful_life) return depreciation_amount - def get_depreciation_amount_prorata_temporis(self, depreciable_value, start_date=None, end_date=None): + def get_depreciation_amount_prorata_temporis(self, depreciable_value, row, start_date=None, end_date=None): if start_date and end_date: prorata_temporis = min(abs(flt(date_diff(str(end_date), str(start_date)))) / flt(frappe.db.get_value("Asset Settings", None, "number_of_days_in_fiscal_year")), 1) else: prorata_temporis = 1 - if self.depreciation_method in ("Straight Line", "Manual"): - depreciation_amount = (flt(self.value_after_depreciation) - - flt(self.expected_value_after_useful_life)) / (cint(self.total_number_of_depreciations) - + if row.depreciation_method in ("Straight Line", "Manual"): + depreciation_amount = (flt(row.value_after_depreciation) - + flt(row.expected_value_after_useful_life)) / (cint(row.total_number_of_depreciations) - cint(self.number_of_depreciations_booked)) * prorata_temporis - - return depreciation_amount else: - self.get_depreciation_amount(depreciable_value) + depreciation_amount = self.get_depreciation_amount(depreciable_value, row) + + return depreciation_amount def validate_expected_value_after_useful_life(self): - accumulated_depreciation_after_full_schedule = \ - max([d.accumulated_depreciation_amount for d in self.get("schedules")]) + for row in self.get('finance_books'): + accumulated_depreciation_after_full_schedule = \ + max([d.accumulated_depreciation_amount for d in self.get("schedules") if d.finance_book_id == row.idx]) - asset_value_after_full_schedule = flt(flt(self.gross_purchase_amount) - - flt(accumulated_depreciation_after_full_schedule), - self.precision('expected_value_after_useful_life')) + asset_value_after_full_schedule = flt(flt(self.gross_purchase_amount) - + flt(accumulated_depreciation_after_full_schedule), + self.precision('gross_purchase_amount')) - if self.expected_value_after_useful_life < asset_value_after_full_schedule: - frappe.throw(_("Expected value after useful life must be greater than or equal to {0}") - .format(asset_value_after_full_schedule)) + if row.expected_value_after_useful_life < asset_value_after_full_schedule: + frappe.throw(_("Depreciation Row {0}: Expected value after useful life must be greater than or equal to {1}") + .format(row.idx, asset_value_after_full_schedule)) def validate_cancellation(self): if self.status not in ("Submitted", "Partially Depreciated", "Fully Depreciated"): @@ -219,6 +263,9 @@ class Asset(Document): if self.purchase_invoice: frappe.throw(_("Please cancel Purchase Invoice {0} first").format(self.purchase_invoice)) + if self.purchase_receipt: + frappe.throw(_("Please cancel Purchase Receipt {0} first").format(self.purchase_receipt)) + def delete_depreciation_entries(self): for d in self.get("schedules"): if d.journal_entry: @@ -240,9 +287,15 @@ class Asset(Document): status = "Draft" elif self.docstatus == 1: status = "Submitted" + expected_value_after_useful_life = flt(sum([d.expected_value_after_useful_life + for d in self.get('finance_books')])) + + value_after_depreciation = flt(sum([d.value_after_depreciation + for d in self.get('finance_books')])) + if self.journal_entry_for_scrap: status = "Scrapped" - elif flt(self.value_after_depreciation) <= flt(self.expected_value_after_useful_life): + elif flt(value_after_depreciation) <= expected_value_after_useful_life: status = "Fully Depreciated" elif flt(self.value_after_depreciation) < flt(self.gross_purchase_amount): status = 'Partially Depreciated' @@ -250,6 +303,45 @@ class Asset(Document): status = "Cancelled" return status + def update_stock_movement(self): + asset_movement = frappe.db.get_value('Asset Movement', + {'asset': self.name, 'reference_name': self.purchase_receipt, 'docstatus': 0}, 'name') + + if asset_movement: + doc = frappe.get_doc('Asset Movement', asset_movement) + doc.submit() + + def make_gl_entries(self): + if self.purchase_receipt and self.purchase_receipt_amount: + from erpnext.accounts.general_ledger import make_gl_entries + + gl_entries = [] + + cwip_account = get_cwip_account(self.name, self.asset_category, self.company) + fixed_aseet_account = get_asset_category_account(self.name, 'fixed_asset_account', + asset_category = self.asset_category, company = self.company) + + gl_entries.append(self.get_gl_dict({ + "account": cwip_account, + "against": fixed_aseet_account, + "remarks": self.get("remarks") or _("Accounting Entry for Asset"), + "posting_date": self.available_for_use_date, + "credit": self.purchase_receipt_amount, + "credit_in_account_currency": self.purchase_receipt_amount + })) + + gl_entries.append(self.get_gl_dict({ + "account": fixed_aseet_account, + "against": cwip_account, + "remarks": self.get("remarks") or _("Accounting Entry for Asset"), + "posting_date": self.available_for_use_date, + "debit": self.purchase_receipt_amount, + "debit_in_account_currency": self.purchase_receipt_amount + })) + + make_gl_entries(gl_entries) + self.db_set('booked_fixed_asset', 1) + def update_maintenance_status(): assets = frappe.get_all('Asset', filters = {'docstatus': 1, 'maintenance_required': 1}) @@ -260,6 +352,18 @@ def update_maintenance_status(): if frappe.db.exists('Asset Repair', {'asset_name': asset.name, 'repair_status': 'Pending'}): asset.set_status('Out of Order') +def make_post_gl_entry(): + assets = frappe.db.sql_list(""" select name from `tabAsset` + where ifnull(booked_fixed_asset, 0) = 0 and available_for_use_date = %s""", nowdate()) + + for asset in assets: + doc = frappe.get_doc('Asset', asset) + doc.make_gl_entries() + +def get_asset_naming_series(): + meta = frappe.get_meta('Asset') + return meta.get_field("naming_series").options + @frappe.whitelist() def make_purchase_invoice(asset, item_code, gross_purchase_amount, company, posting_date): pi = frappe.new_doc("Purchase Invoice") @@ -271,7 +375,7 @@ def make_purchase_invoice(asset, item_code, gross_purchase_amount, company, post "item_code": item_code, "is_fixed_asset": 1, "asset": asset, - "expense_account": get_fixed_asset_account(asset), + "expense_account": get_asset_category_account(asset, 'fixed_asset_account'), "qty": 1, "price_list_rate": gross_purchase_amount, "rate": gross_purchase_amount @@ -280,7 +384,7 @@ def make_purchase_invoice(asset, item_code, gross_purchase_amount, company, post return pi @frappe.whitelist() -def make_sales_invoice(asset, item_code, company): +def make_sales_invoice(asset, item_code, company, serial_no=None): si = frappe.new_doc("Sales Invoice") si.company = company si.currency = frappe.db.get_value("Company", company, "default_currency") @@ -290,6 +394,7 @@ def make_sales_invoice(asset, item_code, company): "is_fixed_asset": 1, "asset": asset, "income_account": disposal_account, + "serial_no": serial_no, "cost_center": depreciation_cost_center, "qty": 1 }) @@ -322,17 +427,32 @@ def transfer_asset(args): frappe.msgprint(_("Asset Movement record {0} created").format("{0}".format(movement_entry.name))) @frappe.whitelist() -def get_item_details(item_code): - asset_category = frappe.db.get_value("Item", item_code, "asset_category") - +def get_item_details(item_code, asset_category=None): if not asset_category: frappe.throw(_("Please enter Asset Category in Item {0}").format(item_code)) - ret = frappe.db.get_value("Asset Category", asset_category, - ["depreciation_method", "total_number_of_depreciations", "frequency_of_depreciation"], as_dict=1) + asset_category_doc = frappe.get_doc('Asset Category', asset_category) + books = [] + for d in asset_category_doc.finance_books: + books.append({ + 'finance_book': d.finance_book, + 'depreciation_method': d.depreciation_method, + 'total_number_of_depreciations': d.total_number_of_depreciations, + 'frequency_of_depreciation': d.frequency_of_depreciation, + 'start_date': nowdate() + }) - ret.update({ - "asset_category": asset_category - }) + return books - return ret +def get_cwip_account(asset, asset_category=None, company=None): + cwip_account = get_asset_category_account(asset, 'capital_work_in_progress_account', + asset_category = asset_category, company = company) + + if not cwip_account: + cwip_account = frappe.db.get_value('Company', company, 'capital_work_in_progress_account') + + if not cwip_account: + frappe.throw(_("Set Capital Work In Progress Account in asset category {0} or company {1}") + .format(asset_category, company)) + + return cwip_account diff --git a/erpnext/assets/doctype/asset/asset_dashboard.py b/erpnext/assets/doctype/asset/asset_dashboard.py index 94dad1b311e..89699f3edbd 100644 --- a/erpnext/assets/doctype/asset/asset_dashboard.py +++ b/erpnext/assets/doctype/asset/asset_dashboard.py @@ -1,6 +1,9 @@ def get_data(): return { 'fieldname': 'asset_name', + 'non_standard_fieldnames': { + 'Asset Movement': 'asset' + }, 'transactions': [ { 'label': ['Maintenance'], @@ -9,6 +12,10 @@ def get_data(): { 'label': ['Repair'], 'items': ['Asset Repair'] + }, + { + 'label': ['Movement'], + 'items': ['Asset Movement'] } ] } \ No newline at end of file diff --git a/erpnext/assets/doctype/asset/depreciation.py b/erpnext/assets/doctype/asset/depreciation.py index 92a251e4fa8..aacaef54144 100644 --- a/erpnext/assets/doctype/asset/depreciation.py +++ b/erpnext/assets/doctype/asset/depreciation.py @@ -5,7 +5,7 @@ from __future__ import unicode_literals import frappe from frappe import _ -from frappe.utils import flt, today, getdate +from frappe.utils import flt, today, getdate, cint def post_depreciation_entries(date=None): # Return if automatic booking of asset depreciation is disabled @@ -47,6 +47,7 @@ def make_depreciation_entry(asset_name, date=None): je.naming_series = depreciation_series je.posting_date = d.schedule_date je.company = asset.company + je.finance_book = d.finance_book je.remark = "Depreciation Entry against {0} worth {1}".format(asset_name, d.depreciation_amount) je.append("accounts", { @@ -68,9 +69,12 @@ def make_depreciation_entry(asset_name, date=None): je.submit() d.db_set("journal_entry", je.name) - asset.value_after_depreciation -= d.depreciation_amount + + idx = cint(d.finance_book_id) + finance_books = asset.get('finance_books')[idx - 1] + finance_books.value_after_depreciation -= d.depreciation_amount + finance_books.db_update() - asset.db_set("value_after_depreciation", asset.value_after_depreciation) asset.set_status() return asset diff --git a/erpnext/assets/doctype/asset_adjustment/__init__.py b/erpnext/assets/doctype/asset_adjustment/__init__.py new file mode 100644 index 00000000000..e69de29bb2d 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 00000000000..11c02e105f8 --- /dev/null +++ b/erpnext/assets/doctype/asset_adjustment/asset_adjustment.js @@ -0,0 +1,30 @@ +// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors +// For license information, please see license.txt + +frappe.ui.form.on('Asset Adjustment', { + asset: function(frm) { + frm.trigger("set_current_asset_value"); + }, + + finance_book: function(frm) { + frm.trigger("set_current_asset_value"); + }, + + set_current_asset_value: function(frm) { + debugger + if (frm.doc.finance_book && frm.doc.asset) { + frm.call({ + method: "erpnext.assets.doctype.asset_adjustment.asset_adjustment.get_current_asset_value", + args: { + asset: frm.doc.asset, + finance_book: frm.doc.finance_book + }, + callback: function(r) { + if (r.message) { + frm.set_value('current_asset_value', r.message); + } + } + }); + } + } +}); diff --git a/erpnext/assets/doctype/asset_adjustment/asset_adjustment.json b/erpnext/assets/doctype/asset_adjustment/asset_adjustment.json new file mode 100644 index 00000000000..faa36efe077 --- /dev/null +++ b/erpnext/assets/doctype/asset_adjustment/asset_adjustment.json @@ -0,0 +1,437 @@ +{ + "allow_copy": 0, + "allow_guest_to_view": 0, + "allow_import": 0, + "allow_rename": 0, + "beta": 0, + "creation": "2018-05-11 00:22:43.695151", + "custom": 0, + "docstatus": 0, + "doctype": "DocType", + "document_type": "", + "editable_grid": 1, + "engine": "InnoDB", + "fields": [ + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "company", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Company", + "length": 0, + "no_copy": 0, + "options": "Company", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "asset", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Asset", + "length": 0, + "no_copy": 0, + "options": "Asset", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "asset_category", + "fieldtype": "Read Only", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Asset Category", + "length": 0, + "no_copy": 0, + "options": "asset.asset_category", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "finance_book", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Finance Book", + "length": 0, + "no_copy": 0, + "options": "Finance Book", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "journal_entry", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Journal Entry", + "length": 0, + "no_copy": 0, + "options": "Journal Entry", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "column_break_4", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "date", + "fieldtype": "Datetime", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Date", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "current_asset_value", + "fieldtype": "Currency", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Current Asset Value", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "new_asset_value", + "fieldtype": "Currency", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "New Asset Value", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "difference_amount", + "fieldtype": "Currency", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Difference Amount", + "length": 0, + "no_copy": 1, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "amended_from", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Amended From", + "length": 0, + "no_copy": 1, + "options": "Asset Adjustment", + "permlevel": 0, + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + } + ], + "has_web_view": 0, + "hide_heading": 0, + "hide_toolbar": 0, + "idx": 0, + "image_view": 0, + "in_create": 0, + "is_submittable": 1, + "issingle": 0, + "istable": 0, + "max_attachments": 0, + "modified": "2018-05-11 21:45:03.459696", + "modified_by": "Administrator", + "module": "Assets", + "name": "Asset Adjustment", + "name_case": "", + "owner": "Administrator", + "permissions": [ + { + "amend": 1, + "apply_user_permissions": 0, + "cancel": 1, + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "if_owner": 0, + "import": 0, + "permlevel": 0, + "print": 1, + "read": 1, + "report": 1, + "role": "System Manager", + "set_user_permissions": 0, + "share": 1, + "submit": 1, + "write": 1 + }, + { + "amend": 1, + "apply_user_permissions": 0, + "cancel": 1, + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "if_owner": 0, + "import": 0, + "permlevel": 0, + "print": 1, + "read": 1, + "report": 1, + "role": "Accounts User", + "set_user_permissions": 0, + "share": 1, + "submit": 1, + "write": 1 + }, + { + "amend": 1, + "apply_user_permissions": 0, + "cancel": 1, + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "if_owner": 0, + "import": 0, + "permlevel": 0, + "print": 1, + "read": 1, + "report": 1, + "role": "Accounts Manager", + "set_user_permissions": 0, + "share": 1, + "submit": 1, + "write": 1 + } + ], + "quick_entry": 1, + "read_only": 0, + "read_only_onload": 0, + "show_name_in_global_search": 0, + "sort_field": "modified", + "sort_order": "DESC", + "title_field": "asset", + "track_changes": 1, + "track_seen": 0 +} \ No newline at end of file diff --git a/erpnext/assets/doctype/asset_adjustment/asset_adjustment.py b/erpnext/assets/doctype/asset_adjustment/asset_adjustment.py new file mode 100644 index 00000000000..6b4b752e7fd --- /dev/null +++ b/erpnext/assets/doctype/asset_adjustment/asset_adjustment.py @@ -0,0 +1,103 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +from __future__ import unicode_literals +import frappe +from frappe import _ +from frappe.utils import flt, getdate, cint, date_diff +from erpnext.assets.doctype.asset.depreciation import get_depreciation_accounts +from frappe.model.document import Document + +class AssetAdjustment(Document): + def validate(self): + self.set_difference_amount() + self.set_current_asset_value() + + def on_submit(self): + self.make_depreciation_entry() + self.reschedule_depreciations() + + def on_cancel(self): + if self.journal_entry: + frappe.throw(_("Cancel the journal entry {0} first").format(self.journal_entry)) + + def set_difference_amount(self): + self.difference_amount = flt(self.current_asset_value - self.new_asset_value) + + def set_current_asset_value(self): + if not self.current_asset_value and self.asset and self.finance_book: + self.current_asset_value = get_current_asset_value(self.asset, self.finance_book) + + def make_depreciation_entry(self): + asset = frappe.get_doc("Asset", self.asset) + fixed_asset_account, accumulated_depreciation_account, depreciation_expense_account = \ + get_depreciation_accounts(asset) + + depreciation_cost_center, depreciation_series = frappe.db.get_value("Company", asset.company, + ["depreciation_cost_center", "series_for_depreciation_entry"]) + + je = frappe.new_doc("Journal Entry") + je.voucher_type = "Depreciation Entry" + je.naming_series = depreciation_series + je.posting_date = self.date + je.company = self.company + je.remark = "Depreciation Entry against {0} worth {1}".format(self.asset, self.difference_amount) + + je.append("accounts", { + "account": accumulated_depreciation_account, + "credit_in_account_currency": self.difference_amount, + }) + + je.append("accounts", { + "account": depreciation_expense_account, + "debit_in_account_currency": self.difference_amount, + "cost_center": depreciation_cost_center + }) + + je.flags.ignore_permissions = True + je.submit() + + self.db_set("journal_entry", je.name) + + def reschedule_depreciations(self): + asset = frappe.get_doc('Asset', self.asset) + + for d in asset.finance_books: + d.value_after_depreciation = self.new_asset_value + + if d.depreciation_method in ("Straight Line", "Manual"): + end_date = max([s.schedule_date for s in asset.schedules if cint(s.finance_book_id) == d.idx]) + total_days = date_diff(end_date, self.date) + rate_per_day = flt(d.value_after_depreciation) / flt(total_days) + from_date = self.date + else: + no_of_depreciations = len([e.name for e in asset.schedules + if (cint(s.finance_book_id) == d.idx and not e.journal_entry)]) + + value_after_depreciation = d.value_after_depreciation + for data in asset.schedules: + if cint(data.finance_book_id) == d.idx and not data.journal_entry: + if d.depreciation_method in ("Straight Line", "Manual"): + days = date_diff(data.schedule_date, from_date) + depreciation_amount = days * rate_per_day + from_date = data.schedule_date + else: + depreciation_amount = asset.get_depreciation_amount(value_after_depreciation, + no_of_depreciations, d) + + if depreciation_amount: + value_after_depreciation -= flt(depreciation_amount) + data.depreciation_amount = depreciation_amount + + d.db_update() + + asset.set_accumulated_depreciation(ignore_booked_entry=True) + for asset_data in asset.schedules: + if not asset_data.journal_entry: + asset_data.db_update() + +@frappe.whitelist() +def get_current_asset_value(asset, finance_book): + return frappe.db.get_value('Asset Finance Book', + {'parent': asset, 'parenttype': 'Asset', 'finance_book': finance_book}, 'value_after_depreciation', debug=1) diff --git a/erpnext/assets/doctype/asset_adjustment/test_asset_adjustment.js b/erpnext/assets/doctype/asset_adjustment/test_asset_adjustment.js new file mode 100644 index 00000000000..29d070af521 --- /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 00000000000..209692e04cd --- /dev/null +++ b/erpnext/assets/doctype/asset_adjustment/test_asset_adjustment.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors +# See license.txt +from __future__ import unicode_literals + +import frappe +import unittest + +class TestAssetAdjustment(unittest.TestCase): + pass diff --git a/erpnext/assets/doctype/asset_category/asset_category.js b/erpnext/assets/doctype/asset_category/asset_category.js index aafe8a69a0e..6f0c428c4db 100644 --- a/erpnext/assets/doctype/asset_category/asset_category.js +++ b/erpnext/assets/doctype/asset_category/asset_category.js @@ -40,5 +40,16 @@ frappe.ui.form.on('Asset Category', { }; }); + frm.set_query('capital_work_in_progress_account', 'accounts', function(doc, cdt, cdn) { + var d = locals[cdt][cdn]; + return { + "filters": { + "account_type": "Capital Work in Progress", + "is_group": 0, + "company": d.company_name + } + }; + }); + } }); \ No newline at end of file diff --git a/erpnext/assets/doctype/asset_category/asset_category.json b/erpnext/assets/doctype/asset_category/asset_category.json index 3331d05e855..882cbe2eaa8 100644 --- a/erpnext/assets/doctype/asset_category/asset_category.json +++ b/erpnext/assets/doctype/asset_category/asset_category.json @@ -43,38 +43,6 @@ "set_only_once": 0, "unique": 0 }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "Straight Line", - "fieldname": "depreciation_method", - "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 1, - "label": "Depreciation Method", - "length": 0, - "no_copy": 0, - "options": "\nStraight Line\nDouble Declining Balance\nManual", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, { "allow_bulk_edit": 0, "allow_on_submit": 0, @@ -110,16 +78,16 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fieldname": "total_number_of_depreciations", - "fieldtype": "Int", + "fieldname": "finance_book_detail", + "fieldtype": "Section Break", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, - "in_list_view": 1, + "in_list_view": 0, "in_standard_filter": 0, - "label": "Total Number of Depreciations", + "label": "Finance Book Detail", "length": 0, "no_copy": 0, "permlevel": 0, @@ -129,7 +97,7 @@ "read_only": 0, "remember_last_selected_value": 0, "report_hide": 0, - "reqd": 1, + "reqd": 0, "search_index": 0, "set_only_once": 0, "unique": 0 @@ -140,18 +108,19 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fieldname": "frequency_of_depreciation", - "fieldtype": "Int", + "fieldname": "finance_books", + "fieldtype": "Table", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, - "in_list_view": 1, + "in_list_view": 0, "in_standard_filter": 0, - "label": "Frequency of Depreciation (Months)", + "label": "Finance Books", "length": 0, "no_copy": 0, + "options": "Asset Finance Book", "permlevel": 0, "precision": "", "print_hide": 0, @@ -159,7 +128,7 @@ "read_only": 0, "remember_last_selected_value": 0, "report_hide": 0, - "reqd": 1, + "reqd": 0, "search_index": 0, "set_only_once": 0, "unique": 0 @@ -236,7 +205,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2017-12-01 15:14:25.645077", + "modified": "2018-05-12 14:56:04.116425", "modified_by": "Administrator", "module": "Assets", "name": "Asset Category", @@ -312,4 +281,4 @@ "sort_order": "DESC", "track_changes": 0, "track_seen": 0 -} +} \ No newline at end of file diff --git a/erpnext/assets/doctype/asset_category/asset_category.py b/erpnext/assets/doctype/asset_category/asset_category.py index 542bd12861c..bbdc6ec2cfa 100644 --- a/erpnext/assets/doctype/asset_category/asset_category.py +++ b/erpnext/assets/doctype/asset_category/asset_category.py @@ -10,6 +10,22 @@ from frappe.model.document import Document class AssetCategory(Document): def validate(self): - for field in ("total_number_of_depreciations", "frequency_of_depreciation"): - if cint(self.get(field))<1: - frappe.throw(_("{0} must be greater than 0").format(self.meta.get_label(field)), frappe.MandatoryError) + for d in self.finance_books: + for field in ("Total Number of Depreciations", "Frequency of Depreciation"): + if cint(d.get(frappe.scrub(field)))<1: + frappe.throw(_("Row {0}: {1} must be greater than 0").format(d.idx, field), frappe.MandatoryError) + +@frappe.whitelist() +def get_asset_category_account(asset, fieldname, account=None, asset_category = None, company = None): + if not asset_category and company: + if account: + if frappe.db.get_value("Account", account, "account_type") != "Fixed Asset": + account=None + + if not account: + asset_category, company = frappe.db.get_value("Asset", asset, ["asset_category", "company"]) + + account = frappe.db.get_value("Asset Category Account", + filters={"parent": asset_category, "company_name": company}, fieldname=fieldname) + + return account \ No newline at end of file diff --git a/erpnext/assets/doctype/asset_category_account/asset_category_account.json b/erpnext/assets/doctype/asset_category_account/asset_category_account.json index 679cc5271d8..b7df5575528 100644 --- a/erpnext/assets/doctype/asset_category_account/asset_category_account.json +++ b/erpnext/assets/doctype/asset_category_account/asset_category_account.json @@ -17,7 +17,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, - "columns": 3, + "columns": 2, "fieldname": "company_name", "fieldtype": "Link", "hidden": 0, @@ -48,7 +48,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, - "columns": 3, + "columns": 2, "fieldname": "fixed_asset_account", "fieldtype": "Link", "hidden": 0, @@ -135,6 +135,37 @@ "search_index": 0, "set_only_once": 0, "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 2, + "fieldname": "capital_work_in_progress_account", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Capital Work In Progress Account", + "length": 0, + "no_copy": 0, + "options": "Account", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 } ], "has_web_view": 0, @@ -147,7 +178,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2017-11-28 16:54:12.252271", + "modified": "2018-05-10 17:06:48.839347", "modified_by": "Administrator", "module": "Assets", "name": "Asset Category Account", diff --git a/erpnext/assets/doctype/asset_finance_book/__init__.py b/erpnext/assets/doctype/asset_finance_book/__init__.py new file mode 100644 index 00000000000..e69de29bb2d 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 00000000000..f75c8510dcb --- /dev/null +++ b/erpnext/assets/doctype/asset_finance_book/asset_finance_book.json @@ -0,0 +1,289 @@ +{ + "allow_copy": 0, + "allow_guest_to_view": 0, + "allow_import": 0, + "allow_rename": 0, + "beta": 0, + "creation": "2018-05-08 14:44:37.095570", + "custom": 0, + "docstatus": 0, + "doctype": "DocType", + "document_type": "", + "editable_grid": 1, + "engine": "InnoDB", + "fields": [ + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "", + "fieldname": "finance_book", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Finance Book", + "length": 0, + "no_copy": 0, + "options": "Finance Book", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "depreciation_method", + "fieldtype": "Select", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Depreciation Method", + "length": 0, + "no_copy": 0, + "options": "\nStraight Line\nDouble Declining Balance\nWritten Down Value\nManual", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "total_number_of_depreciations", + "fieldtype": "Int", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Total Number of Depreciations", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "column_break_5", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "frequency_of_depreciation", + "fieldtype": "Int", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Frequency of Depreciation (Months)", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "eval:parent.doctype == 'Asset'", + "fieldname": "depreciation_start_date", + "fieldtype": "Date", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Depreciation Start Date", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "default": "0", + "depends_on": "eval:parent.doctype == 'Asset'", + "fieldname": "expected_value_after_useful_life", + "fieldtype": "Currency", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Expected Value After Useful Life", + "length": 0, + "no_copy": 0, + "options": "Company:company:default_currency", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "value_after_depreciation", + "fieldtype": "Currency", + "hidden": 1, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Value After Depreciation", + "length": 0, + "no_copy": 1, + "options": "Company:company:default_currency", + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + } + ], + "has_web_view": 0, + "hide_heading": 0, + "hide_toolbar": 0, + "idx": 0, + "image_view": 0, + "in_create": 0, + "is_submittable": 0, + "issingle": 0, + "istable": 1, + "max_attachments": 0, + "modified": "2018-05-12 14:56:44.800046", + "modified_by": "Administrator", + "module": "Assets", + "name": "Asset Finance Book", + "name_case": "", + "owner": "Administrator", + "permissions": [], + "quick_entry": 1, + "read_only": 0, + "read_only_onload": 0, + "show_name_in_global_search": 0, + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1, + "track_seen": 0 +} \ No newline at end of file diff --git a/erpnext/assets/doctype/asset_finance_book/asset_finance_book.py b/erpnext/assets/doctype/asset_finance_book/asset_finance_book.py new file mode 100644 index 00000000000..bdc2acfb792 --- /dev/null +++ b/erpnext/assets/doctype/asset_finance_book/asset_finance_book.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +from __future__ import unicode_literals +import frappe +from frappe.model.document import Document + +class AssetFinanceBook(Document): + pass diff --git a/erpnext/assets/doctype/asset_maintenance/asset_maintenance.json b/erpnext/assets/doctype/asset_maintenance/asset_maintenance.json index 72d96b0db01..f36fe4e078c 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 7551eae229e..b30685f108a 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 0c05552962e..8adbf57b67a 100644 --- a/erpnext/assets/doctype/asset_movement/asset_movement.json +++ b/erpnext/assets/doctype/asset_movement/asset_movement.json @@ -12,6 +12,69 @@ "document_type": "", "editable_grid": 0, "fields": [ + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "company", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Company", + "length": 0, + "no_copy": 0, + "options": "Company", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 1, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "default": "Transfer", + "fieldname": "purpose", + "fieldtype": "Select", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Purpose", + "length": 0, + "no_copy": 0, + "options": "\nIssue\nReceipt\nTransfer", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_on_submit": 0, @@ -73,37 +136,6 @@ "set_only_once": 0, "unique": 0 }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "company", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 1, - "label": "Company", - "length": 0, - "no_copy": 0, - "options": "Company", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 1, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, { "allow_bulk_edit": 0, "allow_on_submit": 0, @@ -139,7 +171,96 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fieldname": "source_warehouse", + "fieldname": "quantity", + "fieldtype": "Float", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Quantity", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "serial_no", + "fieldtype": "Small Text", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Serial No", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "section_break_7", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "source_location", "fieldtype": "Link", "hidden": 0, "ignore_user_permissions": 0, @@ -147,11 +268,194 @@ "in_filter": 0, "in_global_search": 0, "in_list_view": 0, - "in_standard_filter": 1, - "label": "Source Warehouse", + "in_standard_filter": 0, + "label": "Source Location", "length": 0, "no_copy": 0, - "options": "Warehouse", + "options": "Location", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "target_location", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Target Location", + "length": 0, + "no_copy": 0, + "options": "Location", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "column_break_10", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "from_employee", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "From Employee", + "length": 0, + "no_copy": 0, + "options": "Employee", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "to_employee", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "To Employee", + "length": 0, + "no_copy": 0, + "options": "Employee", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "reference", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Reference", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "reference_doctype", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Reference DocType", + "length": 0, + "no_copy": 1, + "options": "DocType", "permlevel": 0, "precision": "", "print_hide": 0, @@ -170,27 +474,27 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fieldname": "target_warehouse", - "fieldtype": "Link", + "fieldname": "reference_name", + "fieldtype": "Dynamic Link", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 1, - "label": "Target Warehouse", + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Reference Name", "length": 0, - "no_copy": 0, - "options": "Warehouse", + "no_copy": 1, + "options": "reference_doctype", "permlevel": 0, "precision": "", "print_hide": 0, "print_hide_if_no_value": 0, - "read_only": 0, + "read_only": 1, "remember_last_selected_value": 0, "report_hide": 0, - "reqd": 1, + "reqd": 0, "search_index": 0, "set_only_once": 0, "unique": 0 @@ -236,7 +540,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2017-10-19 16:08:17.389257", + "modified": "2018-05-10 23:16:20.791672", "modified_by": "Administrator", "module": "Assets", "name": "Asset Movement", diff --git a/erpnext/assets/doctype/asset_movement/asset_movement.py b/erpnext/assets/doctype/asset_movement/asset_movement.py index 574c49992b4..32fc6638373 100644 --- a/erpnext/assets/doctype/asset_movement/asset_movement.py +++ b/erpnext/assets/doctype/asset_movement/asset_movement.py @@ -5,44 +5,60 @@ from __future__ import unicode_literals import frappe from frappe import _ +from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos from frappe.model.document import Document class AssetMovement(Document): def validate(self): self.validate_asset() self.validate_warehouses() - + def validate_asset(self): - status, company = frappe.db.get_value("Asset", self.asset, ["status", "company"]) - if status in ("Draft", "Scrapped", "Sold"): + status, company, serial_no = frappe.db.get_value("Asset", self.asset, ["status", "company", "serial_no"]) + if self.purpose == 'Transfer' and status in ("Draft", "Scrapped", "Sold"): frappe.throw(_("{0} asset cannot be transferred").format(status)) - + if company != self.company: frappe.throw(_("Asset {0} does not belong to company {1}").format(self.asset, self.company)) - + + if serial_no and not self.serial_no: + self.serial_no = serial_no + + if self.serial_no and len(get_serial_nos(self.serial_no)) != self.quantity: + frappe.throw(_("Number of serial nos and quantity must be the same")) + + if not(self.source_location or self.target_location or self.from_employee or self.to_employee): + frappe.throw(_("Either location or employee must be required")) + def validate_warehouses(self): - if not self.source_warehouse: - self.source_warehouse = frappe.db.get_value("Asset", self.asset, "warehouse") - - if self.source_warehouse == self.target_warehouse: - frappe.throw(_("Source and Target Warehouse cannot be same")) + if self.purpose in ['Transfer', 'Issue']: + self.source_location = frappe.db.get_value("Asset", self.asset, "location") + + if self.source_location == self.target_location: + frappe.throw(_("Source and Target Location cannot be same")) def on_submit(self): - self.set_latest_warehouse_in_asset() + self.set_latest_location_in_asset() def on_cancel(self): - self.set_latest_warehouse_in_asset() - - def set_latest_warehouse_in_asset(self): - latest_movement_entry = frappe.db.sql("""select target_warehouse from `tabAsset Movement` + self.set_latest_location_in_asset() + + def set_latest_location_in_asset(self): + latest_movement_entry = frappe.db.sql("""select target_location from `tabAsset Movement` where asset=%s and docstatus=1 and company=%s order by transaction_date desc limit 1""", (self.asset, self.company)) if latest_movement_entry: - warehouse = latest_movement_entry[0][0] + location = latest_movement_entry[0][0] else: - warehouse = frappe.db.sql("""select source_warehouse from `tabAsset Movement` + location = frappe.db.sql("""select source_location from `tabAsset Movement` where asset=%s and docstatus=2 and company=%s order by transaction_date asc limit 1""", (self.asset, self.company))[0][0] - - frappe.db.set_value("Asset", self.asset, "warehouse", warehouse) \ No newline at end of file + + frappe.db.set_value("Asset", self.asset, "location", location) + + if self.serial_no: + serial_nos = get_serial_nos(self.serial_no) + + frappe.db.sql(""" update `tabSerial No` set location = %s where name in (%s)""" + %('%s', ','.join(['%s'] * len(serial_nos))), (location, tuple(serial_nos))) diff --git a/erpnext/assets/doctype/depreciation_schedule/depreciation_schedule.json b/erpnext/assets/doctype/depreciation_schedule/depreciation_schedule.json index 330347240dd..35a2c9dd7f3 100644 --- a/erpnext/assets/doctype/depreciation_schedule/depreciation_schedule.json +++ b/erpnext/assets/doctype/depreciation_schedule/depreciation_schedule.json @@ -13,6 +13,37 @@ "editable_grid": 1, "engine": "InnoDB", "fields": [ + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "finance_book", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Finance Book", + "length": 0, + "no_copy": 0, + "options": "Finance Book", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_on_submit": 0, @@ -196,6 +227,67 @@ "search_index": 0, "set_only_once": 0, "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "finance_book_id", + "fieldtype": "Data", + "hidden": 1, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Finance Book Id", + "length": 0, + "no_copy": 1, + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "depreciation_method", + "fieldtype": "Select", + "hidden": 1, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Depreciation Method", + "length": 0, + "no_copy": 1, + "options": "\nStraight Line\nDouble Declining Balance\nWritten Down Value\nManual", + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 } ], "has_web_view": 0, @@ -208,7 +300,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2017-10-19 16:30:13.738170", + "modified": "2018-05-10 15:12:41.679436", "modified_by": "Administrator", "module": "Assets", "name": "Depreciation Schedule", diff --git a/erpnext/assets/doctype/location/__init__.py b/erpnext/assets/doctype/location/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/assets/doctype/location/location.js b/erpnext/assets/doctype/location/location.js new file mode 100644 index 00000000000..c3783dfae70 --- /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 00000000000..d83fdf3667e --- /dev/null +++ b/erpnext/assets/doctype/location/location.json @@ -0,0 +1,306 @@ +{ + "allow_copy": 0, + "allow_guest_to_view": 0, + "allow_import": 0, + "allow_rename": 0, + "autoname": "field:location_name", + "beta": 0, + "creation": "2018-05-07 12:49:22.595974", + "custom": 0, + "docstatus": 0, + "doctype": "DocType", + "document_type": "", + "editable_grid": 1, + "engine": "InnoDB", + "fields": [ + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "location_name", + "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Location Name", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "is_group", + "fieldtype": "Check", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Is Group", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "parent_location", + "fieldtype": "Link", + "hidden": 1, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Parent Location", + "length": 0, + "no_copy": 0, + "options": "Location", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 1, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "lft", + "fieldtype": "Int", + "hidden": 1, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "lft", + "length": 0, + "no_copy": 1, + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "rgt", + "fieldtype": "Int", + "hidden": 1, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "rgt", + "length": 0, + "no_copy": 1, + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "old_parent", + "fieldtype": "Data", + "hidden": 1, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Old Parent", + "length": 0, + "no_copy": 1, + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + } + ], + "has_web_view": 0, + "hide_heading": 0, + "hide_toolbar": 0, + "idx": 0, + "image_view": 0, + "in_create": 0, + "is_submittable": 0, + "issingle": 0, + "istable": 0, + "max_attachments": 0, + "modified": "2018-05-07 19:21:06.051414", + "modified_by": "Administrator", + "module": "Assets", + "name": "Location", + "name_case": "", + "owner": "Administrator", + "permissions": [ + { + "amend": 0, + "cancel": 0, + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "if_owner": 0, + "import": 0, + "permlevel": 0, + "print": 1, + "read": 1, + "report": 1, + "role": "System Manager", + "set_user_permissions": 0, + "share": 1, + "submit": 0, + "write": 1 + }, + { + "amend": 0, + "cancel": 0, + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "if_owner": 0, + "import": 0, + "permlevel": 0, + "print": 1, + "read": 1, + "report": 1, + "role": "Stock User", + "set_user_permissions": 0, + "share": 1, + "submit": 0, + "write": 1 + }, + { + "amend": 0, + "cancel": 0, + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "if_owner": 0, + "import": 0, + "permlevel": 0, + "print": 1, + "read": 1, + "report": 1, + "role": "Accounts User", + "set_user_permissions": 0, + "share": 1, + "submit": 0, + "write": 1 + }, + { + "amend": 0, + "cancel": 0, + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "if_owner": 0, + "import": 0, + "permlevel": 0, + "print": 1, + "read": 1, + "report": 1, + "role": "Stock Manager", + "set_user_permissions": 0, + "share": 1, + "submit": 0, + "write": 1 + } + ], + "quick_entry": 1, + "read_only": 0, + "read_only_onload": 0, + "show_name_in_global_search": 0, + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1, + "track_seen": 0 +} \ No newline at end of file diff --git a/erpnext/assets/doctype/location/location.py b/erpnext/assets/doctype/location/location.py new file mode 100644 index 00000000000..9d05720a0d8 --- /dev/null +++ b/erpnext/assets/doctype/location/location.py @@ -0,0 +1,47 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +from __future__ import unicode_literals +import frappe +from frappe.model.document import Document +from frappe.utils.nestedset import NestedSet + +class Location(NestedSet): + def on_update(self): + self.update_nsm_model() + + def on_trash(self): + self.update_nsm_model() + + def update_nsm_model(self): + frappe.utils.nestedset.update_nsm(self) + +@frappe.whitelist() +def get_children(doctype, parent=None, location=None, is_root=False): + if parent == None or parent == "All Locations": + parent = "" + + return frappe.db.sql(""" + select + name as value, + is_group as expandable + from + `tab{doctype}` comp + where + ifnull(parent_location, "")="{parent}" + """.format( + doctype = frappe.db.escape(doctype), + parent=frappe.db.escape(parent) + ), as_dict=1) + +@frappe.whitelist() +def add_node(): + from frappe.desk.treeview import make_tree_args + args = frappe.form_dict + args = make_tree_args(**args) + + if args.parent_location == 'All Locations': + args.parent_location = None + + frappe.get_doc(args).insert() \ No newline at end of file diff --git a/erpnext/assets/doctype/location/location_tree.js b/erpnext/assets/doctype/location/location_tree.js new file mode 100644 index 00000000000..523dd63cedd --- /dev/null +++ b/erpnext/assets/doctype/location/location_tree.js @@ -0,0 +1,28 @@ +frappe.treeview_settings["Location"] = { + ignore_fields:["parent_location"], + get_tree_nodes: 'erpnext.assets.doctype.location.location.get_children', + add_tree_node: 'erpnext.assets.doctype.location.location.add_node', + filters: [ + { + fieldname: "location", + fieldtype:"Link", + options: "Location", + label: __("Location") + }, + ], + breadcrumb: "Assets", + root_label: "All Locations", + get_tree_root: false, + menu_items: [ + { + label: __("New Location"), + action: function() { + frappe.new_doc("Location", true); + }, + condition: 'frappe.boot.user.can_create.indexOf("Location") !== -1' + } + ], + onload: function(treeview) { + treeview.make_tree(); + } +}; \ No newline at end of file diff --git a/erpnext/assets/doctype/location/test_location.js b/erpnext/assets/doctype/location/test_location.js new file mode 100644 index 00000000000..236b5c65b0a --- /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 00000000000..9a46fd93efc --- /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 73c1aee87a4..d52f1420cd0 100644 --- a/erpnext/config/assets.py +++ b/erpnext/config/assets.py @@ -10,6 +10,10 @@ def get_data(): "type": "doctype", "name": "Asset", }, + { + "type": "doctype", + "name": "Location", + }, { "type": "doctype", "name": "Asset Category", @@ -39,6 +43,10 @@ def get_data(): "type": "doctype", "name": "Asset Maintenance Log", }, + { + "type": "doctype", + "name": "Asset Adjustment", + }, { "type": "doctype", "name": "Asset Repair", diff --git a/erpnext/config/hr.py b/erpnext/config/hr.py index 4e9e91ef3b8..e1c589fe09e 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/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index c70cfcd8111..186aad3a5ab 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -273,15 +273,16 @@ class AccountsController(TransactionBase): def get_gl_dict(self, args, account_currency=None): """this method populates the common properties of a gl entry record""" - fiscal_years = get_fiscal_years(self.posting_date, company=self.company) + posting_date = args.get('posting_date') or self.get('posting_date') + fiscal_years = get_fiscal_years(posting_date, company=self.company) if len(fiscal_years) > 1: - frappe.throw(_("Multiple fiscal years exist for the date {0}. Please set company in Fiscal Year").format(formatdate(self.posting_date))) + frappe.throw(_("Multiple fiscal years exist for the date {0}. Please set company in Fiscal Year").format(formatdate(posting_date))) else: fiscal_year = fiscal_years[0][0] gl_dict = frappe._dict({ 'company': self.company, - 'posting_date': self.posting_date, + 'posting_date': posting_date, 'fiscal_year': fiscal_year, 'voucher_type': self.doctype, 'voucher_no': self.name, @@ -600,40 +601,36 @@ class AccountsController(TransactionBase): if d.qty > 1: frappe.throw(_("Row #{0}: Qty must be 1, as item is a fixed asset. Please use separate row for multiple qty.").format(d.idx)) - if d.meta.get_field("asset"): - if not d.asset: - frappe.throw(_("Row #{0}: Asset is mandatory for fixed asset purchase/sale") - .format(d.idx)) - else: - asset = frappe.get_doc("Asset", d.asset) + if d.meta.get_field("asset") and d.asset: + asset = frappe.get_doc("Asset", d.asset) - if asset.company != self.company: - frappe.throw(_("Row #{0}: Asset {1} does not belong to company {2}") - .format(d.idx, d.asset, self.company)) + if asset.company != self.company: + frappe.throw(_("Row #{0}: Asset {1} does not belong to company {2}") + .format(d.idx, d.asset, self.company)) - elif asset.item_code != d.item_code: - frappe.throw(_("Row #{0}: Asset {1} does not linked to Item {2}") - .format(d.idx, d.asset, d.item_code)) + elif asset.item_code != d.item_code: + frappe.throw(_("Row #{0}: Asset {1} does not linked to Item {2}") + .format(d.idx, d.asset, d.item_code)) - elif asset.docstatus != 1: - frappe.throw(_("Row #{0}: Asset {1} must be submitted").format(d.idx, d.asset)) + elif asset.docstatus != 1: + frappe.throw(_("Row #{0}: Asset {1} must be submitted").format(d.idx, d.asset)) - elif self.doctype == "Purchase Invoice": - if asset.status != "Submitted": - frappe.throw(_("Row #{0}: Asset {1} is already {2}") - .format(d.idx, d.asset, asset.status)) - elif getdate(asset.purchase_date) != getdate(self.posting_date): - frappe.throw(_("Row #{0}: Posting Date must be same as purchase date {1} of asset {2}").format(d.idx, asset.purchase_date, d.asset)) - elif asset.is_existing_asset: - frappe.throw(_("Row #{0}: Purchase Invoice cannot be made against an existing asset {1}").format(d.idx, d.asset)) + elif self.doctype == "Purchase Invoice": + if asset.status != "Submitted": + frappe.throw(_("Row #{0}: Asset {1} is already {2}") + .format(d.idx, d.asset, asset.status)) + elif getdate(asset.purchase_date) != getdate(self.posting_date): + frappe.throw(_("Row #{0}: Posting Date must be same as purchase date {1} of asset {2}").format(d.idx, asset.purchase_date, d.asset)) + elif asset.is_existing_asset: + frappe.throw(_("Row #{0}: Purchase Invoice cannot be made against an existing asset {1}").format(d.idx, d.asset)) - elif self.docstatus=="Sales Invoice" and self.docstatus == 1: - if self.update_stock: - frappe.throw(_("'Update Stock' cannot be checked for fixed asset sale")) + elif self.docstatus=="Sales Invoice" and self.docstatus == 1: + if self.update_stock: + frappe.throw(_("'Update Stock' cannot be checked for fixed asset sale")) - elif asset.status in ("Scrapped", "Cancelled", "Sold"): - frappe.throw(_("Row #{0}: Asset {1} cannot be submitted, it is already {2}") - .format(d.idx, d.asset, asset.status)) + elif asset.status in ("Scrapped", "Cancelled", "Sold"): + frappe.throw(_("Row #{0}: Asset {1} cannot be submitted, it is already {2}") + .format(d.idx, d.asset, asset.status)) def delink_advance_entries(self, linked_doc_name): total_allocated_amount = 0 diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py index de6ed793512..85fb3f0a66e 100644 --- a/erpnext/controllers/buying_controller.py +++ b/erpnext/controllers/buying_controller.py @@ -11,6 +11,7 @@ from erpnext.stock.get_item_details import get_conversion_factor from erpnext.buying.utils import validate_for_items, update_last_purchase_rate from erpnext.stock.stock_ledger import get_valuation_rate from erpnext.stock.doctype.stock_entry.stock_entry import get_used_alternative_items +from erpnext.stock.doctype.serial_no.serial_no import get_auto_serial_nos, auto_make_serial_nos, get_serial_nos from erpnext.controllers.stock_controller import StockController @@ -78,7 +79,7 @@ class BuyingController(StockController): break def validate_stock_or_nonstock_items(self): - if self.meta.get_field("taxes") and not self.get_stock_items(): + if self.meta.get_field("taxes") and not self.get_stock_items() and not self.get_asset_items(): tax_for_valuation = [d for d in self.get("taxes") if d.category in ["Valuation", "Valuation and Total"]] @@ -87,6 +88,12 @@ class BuyingController(StockController): d.category = 'Total' msgprint(_('Tax Category has been changed to "Total" because all the Items are non-stock items')) + def get_asset_items(self): + if self.doctype not in ['Purchase Invoice', 'Purchase Receipt']: + return [] + + return [d.item_code for d in self.items if d.is_fixed_asset] + def set_landed_cost_voucher_amount(self): for d in self.get("items"): lc_voucher_data = frappe.db.sql("""select sum(applicable_charges), cost_center @@ -111,7 +118,7 @@ class BuyingController(StockController): TODO: rename item_tax_amount to valuation_tax_amount """ - stock_items = self.get_stock_items() + stock_items = self.get_stock_items() + self.get_asset_items() stock_items_qty, stock_items_amount = 0, 0 last_stock_item_idx = 1 @@ -439,6 +446,12 @@ class BuyingController(StockController): if self.get('is_return'): return + if self.doctype in ['Purchase Receipt', 'Purchase Invoice']: + field = 'purchase_invoice' if self.doctype == 'Purchase Invoice' else 'purchase_receipt' + + self.process_fixed_asset() + self.update_fixed_asset(field) + update_last_purchase_rate(self, is_submit = 1) def on_cancel(self): @@ -446,6 +459,133 @@ class BuyingController(StockController): return update_last_purchase_rate(self, is_submit = 0) + if self.doctype in ['Purchase Receipt', 'Purchase Invoice']: + field = 'purchase_invoice' if self.doctype == 'Purchase Invoice' else 'purchase_receipt' + + self.delete_linked_asset() + self.update_fixed_asset(field, delete_asset=True) + + def process_fixed_asset(self): + if self.doctype == 'Purchase Invoice' and not self.update_stock: + return + + asset_items = self.get_asset_items() + if asset_items: + self.make_serial_nos_for_asset(asset_items) + + def make_serial_nos_for_asset(self, asset_items): + items_data = get_asset_item_details(asset_items) + + for d in self.items: + if d.is_fixed_asset: + item_data = items_data.get(d.item_code) + if not d.asset: + asset = self.make_asset(d) + d.db_set('asset', asset) + + if item_data.get('has_serial_no'): + # If item has serial no + if item_data.get('serial_no_series') and not d.serial_no: + serial_nos = get_auto_serial_nos(item_data.get('serial_no_series'), d.qty) + elif d.serial_no: + serial_nos = d.serial_no + elif not d.serial_no: + frappe.throw(_("Serial no is mandatory for the item {0}").format(d.item_code)) + + auto_make_serial_nos({ + 'serial_no': serial_nos, + 'item_code': d.item_code, + 'via_stock_ledger': False, + 'company': self.company, + 'actual_qty': d.qty, + 'purchase_document_type': self.doctype, + 'purchase_document_no': self.name, + 'asset': d.asset + }) + d.db_set('serial_no', serial_nos) + + if d.asset: + self.make_asset_movement(d) + + def make_asset(self, row): + if not row.asset_location: + frappe.throw(_("Row {0}: Enter location for the asset item {1}").format(row.idx, row.item_code)) + + item_data = frappe.db.get_value('Item', + row.item_code, ['asset_naming_series', 'asset_category'], as_dict=1) + + purchase_amount = flt(row.base_net_amount + row.item_tax_amount) + asset = frappe.get_doc({ + 'doctype': 'Asset', + 'item_code': row.item_code, + 'asset_name': row.item_name, + 'status': 'Receipt', + 'naming_series': item_data.get('asset_naming_series') or 'AST', + 'asset_category': item_data.get('asset_category'), + 'location': row.asset_location, + 'company': self.company, + 'purchase_date': self.posting_date, + 'calculate_depreciation': 1, + 'purchase_receipt_amount': purchase_amount, + 'gross_purchase_amount': purchase_amount, + 'purchase_receipt': self.name if self.doctype == 'Purchase Receipt' else None, + 'purchase_invoice': self.name if self.doctype == 'Purchase Invoice' else None + }) + + asset.flags.ignore_validate = True + asset.flags.ignore_mandatory = True + asset.set_missing_values() + asset.insert() + + frappe.msgprint(_("Asset {0} created").format(asset.name)) + return asset.name + + def make_asset_movement(self, row): + asset_movement = frappe.get_doc({ + 'doctype': 'Asset Movement', + 'asset': row.asset, + 'target_location': row.asset_location, + 'purpose': 'Receipt', + 'serial_no': row.serial_no, + 'quantity': len(get_serial_nos(row.serial_no)), + 'company': self.company, + 'transaction_date': self.posting_date, + 'reference_doctype': self.doctype, + 'reference_name': self.name + }).insert() + + return asset_movement.name + + def update_fixed_asset(self, field, delete_asset = False): + for d in self.get("items"): + if d.is_fixed_asset and d.asset: + asset = frappe.get_doc("Asset", d.asset) + + if delete_asset and asset.docstatus == 0: + frappe.delete_doc("Asset", asset.name) + d.db_set('asset', None) + continue + + if self.docstatus in [0, 1] and not asset.get(field): + asset.set(field, self.name) + asset.purchase_date = self.posting_date + asset.supplier = self.supplier + elif self.docstatus == 2: + asset.set(field, None) + asset.supplier = None + + asset.flags.ignore_validate_update_after_submit = True + if asset.docstatus == 0: + asset.flags.ignore_validate = True + + asset.save() + + def delete_linked_asset(self): + if self.doctype == 'Purchase Invoice' and not self.get('update_stock'): + return + + frappe.db.sql("delete from `tabAsset Movement` where reference_name=%s and docstatus = 0", self.name) + frappe.db.sql("delete from `tabSerial No` where purchase_document_no=%s", self.name) def validate_schedule_date(self): if not self.schedule_date: @@ -480,3 +620,11 @@ def get_items_from_bom(item_code, bom, exploded_item=1): msgprint(_("Specified BOM {0} does not exist for Item {1}").format(bom, item_code), raise_exception=1) return bom_items + +def get_asset_item_details(asset_items): + asset_items_data = {} + for d in frappe.get_all('Item', fields = ["name", "has_serial_no", "serial_no_series"], + filters = {'name': ('in', asset_items)}): + asset_items_data.setdefault(d.name, d) + + return asset_items_data diff --git a/erpnext/education/doctype/instructor/instructor.js b/erpnext/education/doctype/instructor/instructor.js index 62d73b32eef..f9c7a2a13da 100644 --- a/erpnext/education/doctype/instructor/instructor.js +++ b/erpnext/education/doctype/instructor/instructor.js @@ -1,31 +1,53 @@ cur_frm.add_fetch("employee", "department", "department"); cur_frm.add_fetch("employee", "image", "image"); -frappe.ui.form.on("Instructor", "refresh", function(frm) { - if(!frm.doc.__islocal) { - frm.add_custom_button(__("Student Group"), function() { - frappe.route_options = { - instructor: frm.doc.name - } - frappe.set_route("List", "Student Group"); +frappe.ui.form.on("Instructor", { + employee: function(frm) { + if(!frm.doc.employee) return; + frappe.db.get_value('Employee', {name: frm.doc.employee}, 'company', (company) => { + frm.set_query("department", function() { + return { + "filters": { + "company": company, + } + }; + }); + + frm.set_query("department", "instructor_log", function() { + return { + "filters": { + "company": company, + } + }; + }); }); - frm.add_custom_button(__("Course Schedule"), function() { - frappe.route_options = { - instructor: frm.doc.name - } - frappe.set_route("List", "Course Schedule"); - }); - frm.add_custom_button(__("As Examiner"), function() { - frappe.route_options = { - examiner: frm.doc.name - } - frappe.set_route("List", "Assessment Plan"); - }, __("Assessment Plan")); - frm.add_custom_button(__("As Supervisor"), function() { - frappe.route_options = { - supervisor: frm.doc.name - } - frappe.set_route("List", "Assessment Plan"); - }, __("Assessment Plan")); + }, + refresh: function(frm) { + if(!frm.doc.__islocal) { + frm.add_custom_button(__("Student Group"), function() { + frappe.route_options = { + instructor: frm.doc.name + } + frappe.set_route("List", "Student Group"); + }); + frm.add_custom_button(__("Course Schedule"), function() { + frappe.route_options = { + instructor: frm.doc.name + } + frappe.set_route("List", "Course Schedule"); + }); + frm.add_custom_button(__("As Examiner"), function() { + frappe.route_options = { + examiner: frm.doc.name + } + frappe.set_route("List", "Assessment Plan"); + }, __("Assessment Plan")); + frm.add_custom_button(__("As Supervisor"), function() { + frappe.route_options = { + supervisor: frm.doc.name + } + frappe.set_route("List", "Assessment Plan"); + }, __("Assessment Plan")); + } } }); diff --git a/erpnext/hooks.py b/erpnext/hooks.py index 57e83e63be7..627455b0218 100644 --- a/erpnext/hooks.py +++ b/erpnext/hooks.py @@ -234,7 +234,8 @@ scheduler_events = { "erpnext.buying.doctype.supplier_scorecard.supplier_scorecard.refresh_scorecards", "erpnext.setup.doctype.company.company.cache_companies_monthly_sales_history", "erpnext.manufacturing.doctype.bom_update_tool.bom_update_tool.update_latest_price_in_all_boms", - "erpnext.assets.doctype.asset.asset.update_maintenance_status" + "erpnext.assets.doctype.asset.asset.update_maintenance_status", + "erpnext.assets.doctype.asset.asset.make_post_gl_entry" ] } diff --git a/erpnext/hr/doctype/additional_salary_component/__init__.py b/erpnext/hr/doctype/additional_salary_component/__init__.py new file mode 100644 index 00000000000..e69de29bb2d 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 00000000000..13ed239b36e --- /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 00000000000..47b090469e0 --- /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 00000000000..216dea04037 --- /dev/null +++ b/erpnext/hr/doctype/additional_salary_component/additional_salary_component.py @@ -0,0 +1,76 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +from __future__ import unicode_literals +import frappe +from frappe.model.document import Document +from frappe import _ +from frappe.utils import getdate, date_diff + +class AdditionalSalaryComponent(Document): + def validate(self): + self.validate_dates() + if self.amount <= 0: + frappe.throw(_("Amount should be greater than zero.")) + + def validate_dates(self): + date_of_joining, relieving_date = frappe.db.get_value("Employee", self.employee, + ["date_of_joining", "relieving_date"]) + if getdate(self.from_date) > getdate(self.to_date): + frappe.throw(_("To date can not be less than from date")) + elif date_of_joining and getdate(self.from_date) < getdate(date_of_joining): + frappe.throw(_("From date can not be less than employee's joining date")) + elif relieving_date and getdate(self.to_date) > getdate(relieving_date): + frappe.throw(_("To date can not greater than employee's relieving date")) + + def get_amount(self, sal_start_date, sal_end_date): + start_date = getdate(sal_start_date) + end_date = getdate(sal_end_date) + total_days = date_diff(getdate(self.to_date), getdate(self.from_date)) + 1 + amount_per_day = self.amount / total_days + if getdate(sal_start_date) <= getdate(self.from_date): + start_date = getdate(self.from_date) + if getdate(sal_end_date) > getdate(self.to_date): + end_date = getdate(self.end_date) + no_of_days = date_diff(getdate(end_date), getdate(start_date)) + return amount_per_day * no_of_days + + + + +@frappe.whitelist() +def get_additional_salary_component(employee, start_date, end_date): + additional_components = frappe.db.sql(""" + select name from `tabAdditional Salary Component` + where employee=%(employee)s + and docstatus = 1 + and ( + (%(from_date)s between from_date and to_date) + or (%(to_date)s between from_date and to_date) + or (from_date between %(from_date)s and %(to_date)s) + )""", { + 'employee': employee, + 'from_date': start_date, + 'to_date': end_date + }) + + if additional_components: + additional_components_array = [] + for additional_component in additional_components: + struct_row = {} + additional_components_dict = {} + additional_component_obj = frappe.get_doc("Additional Salary Component", additional_component[0]) + amount = additional_component_obj.get_amount(start_date, end_date) + salary_component = frappe.get_doc("Salary Component", additional_component_obj.salary_component) + struct_row['depends_on_lwp'] = salary_component.depends_on_lwp + struct_row['salary_component'] = salary_component.name + struct_row['abbr'] = salary_component.salary_component_abbr + struct_row['do_not_include_in_total'] = salary_component.do_not_include_in_total + additional_components_dict['amount'] = amount + additional_components_dict['struct_row'] = struct_row + additional_components_array.append(additional_components_dict) + + if len(additional_components_array) > 0: + return additional_components_array + return False diff --git a/erpnext/hr/doctype/additional_salary_component/test_additional_salary_component.js b/erpnext/hr/doctype/additional_salary_component/test_additional_salary_component.js new file mode 100644 index 00000000000..118290bcfaa --- /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 00000000000..eda2f79dc9f --- /dev/null +++ b/erpnext/hr/doctype/additional_salary_component/test_additional_salary_component.py @@ -0,0 +1,8 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors +# See license.txt +from __future__ import unicode_literals +import unittest + +class TestAdditionalSalaryComponent(unittest.TestCase): + pass diff --git a/erpnext/hr/doctype/department/department.json b/erpnext/hr/doctype/department/department.json index a1c8dc16ff2..664679d3f1e 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 fda1b69de27..19994ae5efb 100644 --- a/erpnext/hr/doctype/department/department.py +++ b/erpnext/hr/doctype/department/department.py @@ -10,6 +10,10 @@ from frappe.model.document import Document class Department(NestedSet): nsm_parent_field = 'parent_department' + def autoname(self): + abbr = frappe.db.get_value('Company', self.company, 'abbr') + self.name = '{0} - {1}'.format(self.department_name, abbr) + def update_nsm_model(self): frappe.utils.nestedset.update_nsm(self) @@ -21,4 +25,23 @@ class Department(NestedSet): delete_events(self.doctype, self.name) def on_doctype_update(): - frappe.db.add_index("Department", ["lft", "rgt"]) \ No newline at end of file + frappe.db.add_index("Department", ["lft", "rgt"]) + +@frappe.whitelist() +def get_children(doctype, parent=None, company=None, is_root=False): + condition = '' + if company == parent: + condition = 'name="All Departments"' + elif company: + condition = "parent_department='{0}' and company='{1}'".format(parent, company) + else: + condition = "parent_department = '{0}'".format(parent) + + return frappe.db.sql(""" + select + name as value, + is_group as expandable + from `tab{doctype}` + where + {condition} + order by name""".format(doctype=doctype, condition=condition), as_dict=1) diff --git a/erpnext/hr/doctype/department/department_tree.js b/erpnext/hr/doctype/department/department_tree.js index 5652ad61a02..1f891fd1e5b 100644 --- a/erpnext/hr/doctype/department/department_tree.js +++ b/erpnext/hr/doctype/department/department_tree.js @@ -1,3 +1,27 @@ frappe.treeview_settings["Department"] = { - ignore_fields:["parent_department"] + ignore_fields:["parent_department"], + get_tree_nodes: 'erpnext.hr.doctype.department.department.get_children', + filters: [ + { + fieldname: "company", + fieldtype:"Link", + options: "Company", + label: __("Company"), + }, + ], + breadcrumb: "HR", + root_label: "All Departments", + get_tree_root: true, + menu_items: [ + { + label: __("New Department"), + action: function() { + frappe.new_doc("Department", true); + }, + condition: 'frappe.boot.user.can_create.indexOf("Department") !== -1' + } + ], + onload: function(treeview) { + treeview.make_tree(); + } }; \ No newline at end of file diff --git a/erpnext/hr/doctype/employee/employee.js b/erpnext/hr/doctype/employee/employee.js index 240411dcfa0..6f6873ac1d1 100755 --- a/erpnext/hr/doctype/employee/employee.js +++ b/erpnext/hr/doctype/employee/employee.js @@ -37,6 +37,15 @@ erpnext.hr.EmployeeController = frappe.ui.form.Controller.extend({ }); frappe.ui.form.on('Employee',{ + onload:function(frm) { + frm.set_query("department", function() { + return { + "filters": { + "company": frm.doc.company, + } + }; + }); + }, prefered_contact_email:function(frm){ frm.events.update_contact(frm) }, diff --git a/erpnext/hr/doctype/employee/employee.json b/erpnext/hr/doctype/employee/employee.json index ef2c75dc835..3527197edc1 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 4cf28a16ecb..824ddf5aa7f 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 00000000000..e69de29bb2d 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 00000000000..95d693994e0 --- /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 00000000000..496f1653ba0 --- /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 00000000000..e69de29bb2d 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 00000000000..e95e260fa9c --- /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 00000000000..bd2ec4ce9da --- /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 00000000000..3390e8ffe5d --- /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 00000000000..d15cef77dca --- /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 00000000000..b37ae883b6d --- /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 00000000000..e69de29bb2d 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 00000000000..4e91b723844 --- /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 00000000000..d1706318191 --- /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 00000000000..e69de29bb2d 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 00000000000..2a531f31a22 --- /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 00000000000..d0d3a62ba88 --- /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 00000000000..6f1c3167315 --- /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 00000000000..10912edb6ac --- /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 00000000000..f4b5b883428 --- /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 00000000000..e69de29bb2d 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 00000000000..33830796b6c --- /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 00000000000..7d9cfb1c596 --- /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 00000000000..b908b632c83 --- /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 00000000000..d6c635951f7 --- /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 00000000000..0773fb6ae90 --- /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 00000000000..e69de29bb2d 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 00000000000..172ff9fc5be --- /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 00000000000..f1f440a0209 --- /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 00000000000..0508fc462e2 --- /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 00000000000..66fd4508046 --- /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 00000000000..3fd3d398bd1 --- /dev/null +++ b/erpnext/hr/doctype/employee_separation_template/test_employee_separation_template.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors +# See license.txt +from __future__ import unicode_literals + +import frappe +import unittest + +class TestEmployeeSeparationTemplate(unittest.TestCase): + pass diff --git a/erpnext/hr/doctype/job_opening/job_opening.js b/erpnext/hr/doctype/job_opening/job_opening.js index 960f5b3c650..7b0e447a9e3 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_application/leave_application.js b/erpnext/hr/doctype/leave_application/leave_application.js index 242c987e58b..76b5ae54faf 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 23514e16e20..304afdd7ed6 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 00000000000..95e74a671ad --- /dev/null +++ b/erpnext/hr/doctype/leave_application/leave_application_dashboard.html @@ -0,0 +1,30 @@ + +{% if 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"] %} | +
No Leaves have been allocated.
+{% } %} \ No newline at end of file diff --git a/erpnext/hr/doctype/leave_control_panel/leave_control_panel.js b/erpnext/hr/doctype/leave_control_panel/leave_control_panel.js index 0eb64144069..7aeb8ea65d2 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 2a6010e44f6..a54147d18aa 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 1e6dc510b04..d02e1f1dc3f 100644 --- a/erpnext/hr/doctype/payroll_entry/payroll_entry.js +++ b/erpnext/hr/doctype/payroll_entry/payroll_entry.js @@ -9,6 +9,14 @@ frappe.ui.form.on('Payroll Entry', { frm.doc.posting_date = frappe.datetime.nowdate(); } frm.toggle_reqd(['payroll_frequency'], !frm.doc.salary_slip_based_on_timesheet); + + frm.set_query("department", function() { + return { + "filters": { + "company": frm.doc.company, + } + }; + }); }, refresh: function(frm) { diff --git a/erpnext/hr/doctype/payroll_entry/payroll_entry.py b/erpnext/hr/doctype/payroll_entry/payroll_entry.py index e1b841f9b92..0dd2b4cb07e 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): diff --git a/erpnext/hr/doctype/salary_component/salary_component.json b/erpnext/hr/doctype/salary_component/salary_component.json index 5f875a99482..f08b1d7a0bd 100644 --- a/erpnext/hr/doctype/salary_component/salary_component.json +++ b/erpnext/hr/doctype/salary_component/salary_component.json @@ -893,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": "Notes:
\n\nbase for using base salary of the EmployeeBS = Basic SalaryEmployment Type = employment_typeBranch = branchPayment Days = payment_daysLeave without pay = leave_without_paybase\nCondition: base < 10000\nFormula: base * .2BS \nCondition: BS > 2000\nFormula: BS * .1employment_type \nCondition: employment_type==\"Intern\"\nAmount: 1000