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/in_standard_chart_of_accounts.json b/erpnext/accounts/doctype/account/chart_of_accounts/verified/in_standard_chart_of_accounts.json index bc7f9659564..2ec0b7f70c8 100644 --- a/erpnext/accounts/doctype/account/chart_of_accounts/verified/in_standard_chart_of_accounts.json +++ b/erpnext/accounts/doctype/account/chart_of_accounts/verified/in_standard_chart_of_accounts.json @@ -147,8 +147,9 @@ } }, "Duties and Taxes": { - "account_type": "Tax", - "is_group": 1 + "TDS": { + "account_type": "Tax" + } }, "Loans (Liabilities)": { "Secured Loans": {}, diff --git a/erpnext/accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts.py b/erpnext/accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts.py index 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/opening_invoice_creation_tool/opening_invoice_creation_tool.py b/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py index 753540eb42c..5712bf83ab1 100644 --- a/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py +++ b/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py @@ -120,12 +120,12 @@ class OpeningInvoiceCreationTool(Document): if party_type == "Customer": party_doc.customer_name = party else: - supplier_type = frappe.db.get_single_value("Buying Settings", "supplier_type") - if not supplier_type: - frappe.throw(_("Please Set Supplier Type in Buying Settings.")) + supplier_group = frappe.db.get_single_value("Buying Settings", "supplier_group") + if not supplier_group: + frappe.throw(_("Please Set Supplier Group in Buying Settings.")) party_doc.supplier_name = party - party_doc.supplier_type = supplier_type + party_doc.supplier_group = supplier_group party_doc.flags.ignore_mandatory = True party_doc.save(ignore_permissions=True) diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py index f983868a0f0..0a22ae0a471 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py @@ -7,7 +7,7 @@ import frappe, erpnext, json from frappe import _, scrub, ValidationError from frappe.utils import flt, comma_or, nowdate from erpnext.accounts.utils import get_outstanding_invoices, get_account_currency, get_balance_on -from erpnext.accounts.party import get_party_account +from erpnext.accounts.party import get_party_account, get_patry_tax_withholding_details from erpnext.accounts.doctype.journal_entry.journal_entry import get_default_bank_cash_account from erpnext.setup.utils import get_exchange_rate from erpnext.accounts.general_ledger import make_gl_entries @@ -43,6 +43,7 @@ class PaymentEntry(AccountsController): def validate(self): self.setup_party_account_field() + self.set_tax_withholding() self.set_missing_values() self.validate_payment_type() self.validate_party_details() @@ -510,6 +511,27 @@ class PaymentEntry(AccountsController): def on_recurring(self, reference_doc, subscription_doc): self.reference_no = reference_doc.name self.reference_date = nowdate() + + def set_tax_withholding(self): + if self.party_type != 'Supplier': + return + + self.supplier = self.party + tax_withholding_details = get_patry_tax_withholding_details(self) + + for tax_details in tax_withholding_details: + if self.deductions: + if tax_details['tax']['account_head'] not in [deduction.account for deduction in self.deductions]: + self.append('deductions', self.calculate_deductions(tax_details)) + else: + self.append('deductions', self.calculate_deductions(tax_details)) + + def calculate_deductions(self, tax_details): + return { + "account": tax_details['tax']['account_head'], + "cost_center": frappe.db.get_value("Company", self.company, "cost_center"), + "amount": self.total_allocated_amount * (tax_details['tax']['rate'] / 100) + } @frappe.whitelist() def get_outstanding_reference_documents(args): diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.js b/erpnext/accounts/doctype/pricing_rule/pricing_rule.js index dcbf354c16c..4be09deb4bc 100644 --- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.js +++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.js @@ -33,7 +33,7 @@ frappe.ui.form.on("Pricing Rule", "refresh", function(frm) { ${__("Pricing Rule is first selected based on 'Apply On' field, which can be Item, Item Group or Brand.")}
  • - ${__("Then Pricing Rules are filtered out based on Customer, Customer Group, Territory, Supplier, Supplier Type, Campaign, Sales Partner etc.")} + ${__("Then Pricing Rules are filtered out based on Customer, Customer Group, Territory, Supplier, Supplier Group, Campaign, Sales Partner etc.")}
  • ${__('Pricing Rules are further filtered based on quantity.')} @@ -51,7 +51,7 @@ frappe.ui.form.on("Pricing Rule", "refresh", function(frm) { ${__('Customer > Customer Group > Territory')}
  • - ${__('Supplier > Supplier Type')} + ${__('Supplier > Supplier Group')}
  • @@ -75,7 +75,7 @@ cur_frm.cscript.set_options_for_applicable_for = function() { options = $.merge(options, ["Customer", "Customer Group", "Territory", "Sales Partner", "Campaign"]); } if(cur_frm.doc.buying) { - $.merge(options, ["Supplier", "Supplier Type"]); + $.merge(options, ["Supplier", "Supplier Group"]); } set_field_options("applicable_for", options.join("\n")); diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.json b/erpnext/accounts/doctype/pricing_rule/pricing_rule.json index 1c30fa43577..ac5990427ec 100644 --- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.json +++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.json @@ -39,6 +39,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -69,6 +70,7 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -100,6 +102,7 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -131,6 +134,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -162,6 +166,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -193,6 +198,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -222,6 +228,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -253,6 +260,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -282,6 +290,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -311,6 +320,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -340,6 +350,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -369,6 +380,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -398,6 +410,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -419,7 +432,7 @@ "label": "Applicable For", "length": 0, "no_copy": 0, - "options": "\nCustomer\nCustomer Group\nTerritory\nSales Partner\nCampaign\nSupplier\nSupplier Type", + "options": "\nCustomer\nCustomer Group\nTerritory\nSales Partner\nCampaign\nSupplier\nSupplier Group", "permlevel": 0, "print_hide": 0, "print_hide_if_no_value": 0, @@ -429,6 +442,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -460,6 +474,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -491,6 +506,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -522,6 +538,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -553,6 +570,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -584,6 +602,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -615,6 +634,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -623,8 +643,8 @@ "bold": 0, "collapsible": 0, "columns": 0, - "depends_on": "eval:doc.applicable_for==\"Supplier Type\"", - "fieldname": "supplier_type", + "depends_on": "eval:doc.applicable_for==\"Supplier Group\"", + "fieldname": "supplier_group", "fieldtype": "Link", "hidden": 0, "ignore_user_permissions": 0, @@ -633,10 +653,10 @@ "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, - "label": "Supplier Type", + "label": "Supplier Group", "length": 0, "no_copy": 0, - "options": "Supplier Type", + "options": "Supplier Group", "permlevel": 0, "print_hide": 0, "print_hide_if_no_value": 0, @@ -646,6 +666,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -675,6 +696,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -704,6 +726,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -733,6 +756,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -762,6 +786,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -791,6 +816,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -821,6 +847,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -850,6 +877,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -878,6 +906,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -908,6 +937,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -940,6 +970,7 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -971,6 +1002,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -1003,6 +1035,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -1032,6 +1065,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -1064,6 +1098,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -1093,6 +1128,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -1124,6 +1160,7 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -1152,6 +1189,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -1182,6 +1220,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -1212,6 +1251,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -1243,6 +1283,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -1273,6 +1314,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -1302,6 +1344,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 } ], @@ -1316,7 +1359,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2018-02-12 17:21:22.559996", + "modified": "2018-04-19 07:52:41.024618", "modified_by": "Administrator", "module": "Accounts", "name": "Pricing Rule", @@ -1324,7 +1367,6 @@ "permissions": [ { "amend": 0, - "apply_user_permissions": 0, "cancel": 0, "create": 1, "delete": 1, @@ -1344,7 +1386,6 @@ }, { "amend": 0, - "apply_user_permissions": 0, "cancel": 0, "create": 1, "delete": 1, @@ -1364,7 +1405,6 @@ }, { "amend": 0, - "apply_user_permissions": 0, "cancel": 0, "create": 1, "delete": 1, @@ -1384,7 +1424,6 @@ }, { "amend": 0, - "apply_user_permissions": 0, "cancel": 0, "create": 1, "delete": 1, @@ -1404,7 +1443,6 @@ }, { "amend": 0, - "apply_user_permissions": 0, "cancel": 0, "create": 1, "delete": 1, diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py index e047b6d67e0..9b73fcd968c 100644 --- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py +++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py @@ -41,7 +41,7 @@ class PricingRule(Document): throw(_("Selling must be checked, if Applicable For is selected as {0}" .format(self.applicable_for))) - if not self.buying and self.applicable_for in ["Supplier", "Supplier Type"]: + if not self.buying and self.applicable_for in ["Supplier", "Supplier Group"]: throw(_("Buying must be checked, if Applicable For is selected as {0}" .format(self.applicable_for))) @@ -85,7 +85,7 @@ def apply_pricing_rule(args): "customer_group": "something", "territory": "something", "supplier": "something", - "supplier_type": "something", + "supplier_group": "something", "currency": "something", "conversion_rate": "something", "price_list": "something", @@ -165,10 +165,10 @@ def get_pricing_rule_for_item(args): if customer: args.customer_group, args.territory = customer - args.supplier = args.supplier_type = None + args.supplier = args.supplier_group = None - elif args.supplier and not args.supplier_type: - args.supplier_type = frappe.db.get_value("Supplier", args.supplier, "supplier_type") + elif args.supplier and not args.supplier_group: + args.supplier_group = frappe.db.get_value("Supplier", args.supplier, "supplier_group") args.customer = args.customer_group = args.territory = None pricing_rules = get_pricing_rules(args) @@ -258,7 +258,7 @@ def get_pricing_rules(args): conditions = item_variant_condition = "" values = {"item_code": args.get("item_code"), "brand": args.get("brand")} - for field in ["company", "customer", "supplier", "supplier_type", "campaign", "sales_partner"]: + for field in ["company", "customer", "supplier", "supplier_group", "campaign", "sales_partner"]: if args.get(field): conditions += " and ifnull("+field+", '') in (%("+field+")s, '')" values[field] = args.get(field) @@ -324,11 +324,11 @@ def filter_pricing_rules(args, pricing_rules): # apply internal priority all_fields = ["item_code", "item_group", "brand", "customer", "customer_group", "territory", - "supplier", "supplier_type", "campaign", "sales_partner", "variant_of"] + "supplier", "supplier_group", "campaign", "sales_partner", "variant_of"] if len(pricing_rules) > 1: for field_set in [["item_code", "variant_of", "item_group", "brand"], - ["customer", "customer_group", "territory"], ["supplier", "supplier_type"]]: + ["customer", "customer_group", "territory"], ["supplier", "supplier_group"]]: remaining_fields = list(set(all_fields) - set(field_set)) if if_all_rules_same(pricing_rules, remaining_fields): pricing_rules = apply_internal_priority(pricing_rules, field_set, args) diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js index 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..c9cf47d114a 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -8,7 +8,7 @@ from frappe import _, throw import frappe.defaults from erpnext.controllers.buying_controller import BuyingController -from erpnext.accounts.party import get_party_account, get_due_date +from erpnext.accounts.party import get_party_account, get_due_date, get_patry_tax_withholding_details from erpnext.accounts.utils import get_account_currency, get_fiscal_year from erpnext.stock.doctype.purchase_receipt.purchase_receipt import update_billed_amount_based_on_po from erpnext.stock import get_warehouse_account_map @@ -19,6 +19,7 @@ from erpnext.accounts.general_ledger import get_round_off_account_and_cost_cente from frappe.model.mapper import get_mapped_doc from erpnext.accounts.doctype.sales_invoice.sales_invoice import validate_inter_company_party, update_linked_invoice,\ unlink_inter_company_invoice +from erpnext.assets.doctype.asset_category.asset_category import get_asset_category_account form_grid_templates = { "items": "templates/form_grid/item_grid.html" @@ -45,6 +46,7 @@ class PurchaseInvoice(BuyingController): self.is_opening = 'No' self.validate_posting_time() + self.set_tax_withholding() super(PurchaseInvoice, self).validate() if not self.is_return: @@ -52,7 +54,6 @@ class PurchaseInvoice(BuyingController): self.pr_required() self.validate_supplier_invoice() - # validate cash purchase if (self.is_paid == 1): self.validate_cash() @@ -167,7 +168,6 @@ class PurchaseInvoice(BuyingController): super(PurchaseInvoice, self).validate_warehouse() - def validate_item_code(self): for d in self.get('items'): if not d.item_code: @@ -305,24 +305,8 @@ class PurchaseInvoice(BuyingController): self.make_gl_entries() self.update_project() - self.update_fixed_asset() update_linked_invoice(self.doctype, self.name, self.inter_company_invoice_reference) - def update_fixed_asset(self): - for d in self.get("items"): - if d.is_fixed_asset: - asset = frappe.get_doc("Asset", d.asset) - if self.docstatus==1: - asset.purchase_invoice = self.name - asset.purchase_date = self.posting_date - asset.supplier = self.supplier - else: - asset.purchase_invoice = None - asset.supplier = None - - asset.flags.ignore_validate_update_after_submit = True - asset.save() - def make_gl_entries(self, gl_entries=None, repost_future_gle=True, from_repost=False): if not self.grand_total: return @@ -438,6 +422,50 @@ class PurchaseInvoice(BuyingController): "remarks": self.get("remarks") or _("Accounting Entry for Stock"), "credit": flt(item.rm_supp_cost) }, warehouse_account[self.supplier_warehouse]["account_currency"])) + + elif item.is_fixed_asset: + asset_accounts = self.get_company_default(["asset_received_but_not_billed", + "expenses_included_in_asset_valuation", "capital_work_in_progress_account"]) + + asset_amount = flt(item.net_amount) + flt(item.item_tax_amount/self.conversion_rate) + base_asset_amount = flt(item.base_net_amount + item.item_tax_amount) + + if not self.update_stock: + asset_rbnb_currency = get_account_currency(asset_accounts[0]) + gl_entries.append(self.get_gl_dict({ + "account": asset_accounts[0], + "against": self.supplier, + "remarks": self.get("remarks") or _("Accounting Entry for Asset"), + "debit": base_asset_amount, + "debit_in_account_currency": (base_asset_amount + if asset_rbnb_currency == self.company_currency else asset_amount) + })) + else: + cwip_account = get_asset_category_account(item.asset, + 'capital_work_in_progress_account') or asset_accounts[2] + + cwip_account_currency = get_account_currency(cwip_account) + gl_entries.append(self.get_gl_dict({ + "account": cwip_account, + "against": self.supplier, + "remarks": self.get("remarks") or _("Accounting Entry for Asset"), + "debit": base_asset_amount, + "debit_in_account_currency": (base_asset_amount + if cwip_account_currency == self.company_currency else asset_amount) + })) + + if item.item_tax_amount: + asset_eiiav_currency = get_account_currency(asset_accounts[0]) + gl_entries.append(self.get_gl_dict({ + "account": asset_accounts[1], + "against": self.supplier, + "remarks": self.get("remarks") or _("Accounting Entry for Asset"), + "cost_center": item.cost_center, + "credit": item.item_tax_amount, + "credit_in_account_currency": (item.item_tax_amount + if asset_eiiav_currency == self.company_currency else + item.item_tax_amount / self.conversion_rate) + })) else: gl_entries.append( self.get_gl_dict({ @@ -636,7 +664,6 @@ class PurchaseInvoice(BuyingController): self.make_gl_entries_on_cancel() self.update_project() - self.update_fixed_asset() frappe.db.set(self, 'status', 'Cancelled') unlink_inter_company_invoice(self.doctype, self.name, self.inter_company_invoice_reference) @@ -703,25 +730,25 @@ class PurchaseInvoice(BuyingController): def on_recurring(self, reference_doc, subscription_doc): self.due_date = None + def set_tax_withholding(self): + """ + 1. Get TDS Configurations against Supplier + """ + + tax_withholding_details = get_patry_tax_withholding_details(self) + for tax_details in tax_withholding_details: + if flt(self.get("rounded_total") or self.grand_total) >= flt(tax_details['threshold']): + if self.taxes: + if tax_details['tax']['description'] not in [tax.description for tax in self.taxes]: + self.append('taxes', tax_details['tax']) + else: + self.append('taxes', tax_details['tax']) + @frappe.whitelist() def make_debit_note(source_name, target_doc=None): from erpnext.controllers.sales_and_purchase_return import make_return_doc return make_return_doc("Purchase Invoice", source_name, target_doc) -@frappe.whitelist() -def get_fixed_asset_account(asset, account=None): - if account: - if frappe.db.get_value("Account", account, "account_type") != "Fixed Asset": - account=None - - if not account: - asset_category, company = frappe.db.get_value("Asset", asset, ["asset_category", "company"]) - - account = frappe.db.get_value("Asset Category Account", - filters={"parent": asset_category, "company_name": company}, fieldname="fixed_asset_account") - - return account - @frappe.whitelist() def make_stock_entry(source_name, target_doc=None): doc = get_mapped_doc("Purchase Invoice", source_name, { diff --git a/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json b/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json index 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/accounts/doctype/tax_rule/tax_rule.js b/erpnext/accounts/doctype/tax_rule/tax_rule.js index 84c42a3da34..370890e4d8e 100644 --- a/erpnext/accounts/doctype/tax_rule/tax_rule.js +++ b/erpnext/accounts/doctype/tax_rule/tax_rule.js @@ -2,7 +2,7 @@ // License: GNU General Public License v3. See license.txt cur_frm.add_fetch("customer", "customer_group", "customer_group" ); -cur_frm.add_fetch("supplier", "supplier_type", "supplier_type" ); +cur_frm.add_fetch("supplier", "supplier_group_name", "supplier_group" ); frappe.ui.form.on("Tax Rule", "tax_type", function(frm) { frm.toggle_reqd("sales_tax_template", frm.doc.tax_type=="Sales"); diff --git a/erpnext/accounts/doctype/tax_rule/tax_rule.json b/erpnext/accounts/doctype/tax_rule/tax_rule.json index a746dafa04a..56ca055770c 100644 --- a/erpnext/accounts/doctype/tax_rule/tax_rule.json +++ b/erpnext/accounts/doctype/tax_rule/tax_rule.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_guest_to_view": 0, "allow_import": 1, "allow_rename": 0, "autoname": "TR.####", @@ -12,6 +13,7 @@ "editable_grid": 0, "fields": [ { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -40,9 +42,11 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -69,9 +73,11 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -97,9 +103,11 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -128,9 +136,11 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -159,9 +169,11 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -188,9 +200,11 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -219,9 +233,11 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -250,9 +266,11 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -279,9 +297,11 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -308,9 +328,11 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -337,9 +359,11 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -367,9 +391,11 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -395,9 +421,11 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -426,15 +454,17 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, "columns": 0, "depends_on": "eval:doc.tax_type==\"Purchase\"", - "fieldname": "supplier_type", + "fieldname": "supplier_group", "fieldtype": "Link", "hidden": 0, "ignore_user_permissions": 0, @@ -443,10 +473,10 @@ "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, - "label": "Supplier Type", + "label": "Supplier Group", "length": 0, "no_copy": 0, - "options": "Supplier Type", + "options": "Supplier Group", "permlevel": 0, "precision": "", "print_hide": 0, @@ -457,9 +487,11 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -486,9 +518,11 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -515,9 +549,11 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -544,9 +580,11 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -574,9 +612,11 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -603,9 +643,11 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -632,9 +674,11 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -660,9 +704,11 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -689,9 +735,11 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -717,9 +765,11 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -747,9 +797,11 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -775,9 +827,11 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -805,20 +859,21 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 } ], + "has_web_view": 0, "hide_heading": 0, "hide_toolbar": 0, "idx": 0, "image_view": 0, "in_create": 0, - "in_dialog": 0, "is_submittable": 0, "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2017-02-17 16:22:42.501765", + "modified": "2018-04-19 07:53:43.020808", "modified_by": "Administrator", "module": "Accounts", "name": "Tax Rule", @@ -827,7 +882,6 @@ "permissions": [ { "amend": 0, - "apply_user_permissions": 0, "cancel": 0, "create": 1, "delete": 1, diff --git a/erpnext/accounts/doctype/tax_rule/tax_rule.py b/erpnext/accounts/doctype/tax_rule/tax_rule.py index ddef65799b0..56bd2870baf 100644 --- a/erpnext/accounts/doctype/tax_rule/tax_rule.py +++ b/erpnext/accounts/doctype/tax_rule/tax_rule.py @@ -30,7 +30,7 @@ class TaxRule(Document): def validate_tax_template(self): if self.tax_type== "Sales": - self.purchase_tax_template = self.supplier = self.supplier_type = None + self.purchase_tax_template = self.supplier = self.supplier_group = None if self.customer: self.customer_group = None @@ -38,7 +38,7 @@ class TaxRule(Document): self.sales_tax_template = self.customer = self.customer_group = None if self.supplier: - self.supplier_type = None + self.supplier_group = None if not (self.sales_tax_template or self.purchase_tax_template): frappe.throw(_("Tax Template is mandatory.")) @@ -53,7 +53,7 @@ class TaxRule(Document): "customer": self.customer, "customer_group": self.customer_group, "supplier": self.supplier, - "supplier_type": self.supplier_type, + "supplier_group": self.supplier_group, "billing_city": self.billing_city, "billing_county": self.billing_county, "billing_state": self.billing_state, diff --git a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.json b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.json index f02a52043ef..a590776e684 100644 --- a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.json +++ b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.json @@ -13,6 +13,68 @@ "editable_grid": 1, "engine": "InnoDB", "fields": [ + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "is_default", + "fieldtype": "Check", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Is Default", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "enabled", + "fieldtype": "Check", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Enabled", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_on_submit": 0, @@ -271,7 +333,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2018-04-13 19:17:12.494050", + "modified": "2018-05-11 14:25:07.474461", "modified_by": "Administrator", "module": "Accounts", "name": "Tax Withholding Category", diff --git a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py index 4940c4f3feb..61f4b60c8b1 100644 --- a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py +++ b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py @@ -7,4 +7,7 @@ import frappe from frappe.model.document import Document class TaxWithholdingCategory(Document): - pass + def validate(self): + if not frappe.db.get_value("Tax Withholding Category", + {"is_default": 1, "name": ("!=", self.name)}, "name"): + self.is_default = 1 \ No newline at end of file diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py index 6f272cf8336..75089b2ff4c 100644 --- a/erpnext/accounts/party.py +++ b/erpnext/accounts/party.py @@ -47,7 +47,7 @@ def _get_party_details(party=None, account=None, party_type="Customer", company= set_contact_details(out, party, party_type) set_other_values(out, party, party_type) set_price_list(out, party, party_type, price_list) - out["taxes_and_charges"] = set_taxes(party.name, party_type, posting_date, company, out.customer_group, out.supplier_type) + out["taxes_and_charges"] = set_taxes(party.name, party_type, posting_date, company, out.customer_group, out.supplier_group) out["payment_terms_template"] = get_pyt_term_template(party.name, party_type, company) if not out.get("currency"): @@ -105,7 +105,7 @@ def set_other_values(out, party, party_type): if party_type=="Customer": to_copy = ["customer_name", "customer_group", "territory", "language"] else: - to_copy = ["supplier_name", "supplier_type", "language"] + to_copy = ["supplier_name", "supplier_group", "language"] for f in to_copy: out[f] = party.get(f) @@ -169,7 +169,7 @@ def set_account_and_due_date(party, account, party_type, company, posting_date, def get_party_account(party_type, party, company): """Returns the account for the given `party`. Will first search in party (Customer / Supplier) record, if not found, - will search in group (Customer Group / Supplier Type), + will search in group (Customer Group / Supplier Group), finally will return default.""" if not company: frappe.throw(_("Please select a Company")) @@ -181,7 +181,7 @@ def get_party_account(party_type, party, company): {"parenttype": party_type, "parent": party, "company": company}, "account") if not account and party_type in ['Customer', 'Supplier']: - party_group_doctype = "Customer Group" if party_type=="Customer" else "Supplier Type" + party_group_doctype = "Customer Group" if party_type=="Customer" else "Supplier Group" group = frappe.db.get_value(party_type, party, scrub(party_group_doctype)) account = frappe.db.get_value("Party Account", {"parenttype": party_group_doctype, "parent": group, "company": company}, "account") @@ -274,8 +274,8 @@ def get_due_date(posting_date, party_type, party, company=None, bill_date=None): due_date = get_due_date_from_template(template_name, posting_date, bill_date).strftime("%Y-%m-%d") else: if party_type == "Supplier": - supplier_type = frappe.db.get_value(party_type, party, fieldname="supplier_type") - template_name = frappe.db.get_value("Supplier Type", supplier_type, fieldname="payment_terms") + supplier_group = frappe.db.get_value(party_type, party, fieldname="supplier_group") + template_name = frappe.db.get_value("Supplier Group", supplier_group, fieldname="payment_terms") if template_name: due_date = get_due_date_from_template(template_name, posting_date, bill_date).strftime("%Y-%m-%d") # If due date is calculated from bill_date, check this condition @@ -321,7 +321,7 @@ def validate_due_date(posting_date, due_date, party_type, party, company=None, b .format(formatdate(default_due_date))) @frappe.whitelist() -def set_taxes(party, party_type, posting_date, company, customer_group=None, supplier_type=None, +def set_taxes(party, party_type, posting_date, company, customer_group=None, supplier_group=None, billing_address=None, shipping_address=None, use_for_shopping_cart=None): from erpnext.accounts.doctype.tax_rule.tax_rule import get_tax_template, get_party_details args = { @@ -332,8 +332,8 @@ def set_taxes(party, party_type, posting_date, company, customer_group=None, sup if customer_group: args['customer_group'] = customer_group - if supplier_type: - args['supplier_type'] = supplier_type + if supplier_group: + args['supplier_group'] = supplier_group if billing_address or shipping_address: args.update(get_party_details(party, party_type, {"billing_address": billing_address, \ @@ -371,10 +371,10 @@ def get_pyt_term_template(party_name, party_type, company=None): customer.customer_group, fieldname='payment_terms') else: supplier = frappe.db.get_value("Supplier", party_name, - fieldname=['payment_terms', "supplier_type"], as_dict=1) + fieldname=['payment_terms', "supplier_group"], as_dict=1) template = supplier.payment_terms - if not template and supplier.supplier_type: - template = frappe.db.get_value("Supplier Type", supplier.supplier_type, fieldname='payment_terms') + if not template and supplier.supplier_group: + template = frappe.db.get_value("Supplier Group", supplier.supplier_group, fieldname='payment_terms') if not template and company: template = frappe.db.get_value("Company", company, fieldname='payment_terms') @@ -448,7 +448,6 @@ def get_dashboard_info(party_type, party): return info - def get_party_shipping_address(doctype, name): """ Returns an Address name (best guess) for the given doctype and name for which `address_type == 'Shipping'` is true. @@ -476,3 +475,60 @@ def get_party_shipping_address(doctype, name): return out[0][0] else: return '' + +def get_patry_tax_withholding_details(ref_doc): + supplier = frappe.get_doc("Supplier", ref_doc.supplier) + tax_withholding_details = [] + print(supplier) + for tax in supplier.tax_withholding_config: + tax_mapper = get_tax_mapper() + + set_tax_withholding_details(tax_mapper, ref_doc, tax_withholding_category=tax.tax_withholding_category) + + if tax.valid_till and date_diff(tax.valid_till, ref_doc.posting_date) > 0: + tax_mapper.update({ + "rate": tax.applicable_percentage + }) + + prepare_tax_withholding_details(tax_mapper, tax_withholding_details) + + return tax_withholding_details + +def prepare_tax_withholding_details(tax_mapper, tax_withholding_details): + if tax_mapper.get('account_head'): + + tax_withholding_details.append({ + "threshold": tax_mapper['threshold'], + "tax": tax_mapper + }) + + del tax_mapper['threshold'] + +def set_tax_withholding_details(tax_mapper, ref_doc, tax_withholding_category=None, use_default=0): + if tax_withholding_category: + tax_withholding = frappe.get_doc("Tax Withholding Category", tax_withholding_category) + else: + tax_withholding = frappe.get_doc("Tax Withholding Category", {'is_default': 1, 'enabled': 1}) + + if tax_withholding.book_on_invoice and ref_doc.doctype=='Purchase Invoice' \ + or tax_withholding.book_on_advance and ref_doc.doctype in ('Payment Entry', 'Journal Entry'): + + for account_detail in tax_withholding.accounts: + if ref_doc.company == account_detail.company: + tax_mapper.update({ + "account_head": account_detail.account, + "rate": tax_withholding.percent_of_tax_withheld, + "threshold": tax_withholding.threshold, + "description": tax_withholding.name + }) + +def get_tax_mapper(): + return { + "category": "Total", + "add_deduct_tax": "Deduct", + "charge_type": "On Net Total", + "rate": 0, + "description": '', + "account_head": '', + "threshold": 0.0 + } diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py index fc76be406e1..ca806bfc4a7 100644 --- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py +++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py @@ -112,7 +112,7 @@ class ReceivablePayableReport(object): _("Customer Group") + ":Link/Customer Group:120" ] if args.get("party_type") == "Supplier": - columns += [_("Supplier Type") + ":Link/Supplier Type:80"] + columns += [_("Supplier Group") + ":Link/Supplier Group:80"] columns.append(_("Remarks") + "::200") @@ -194,11 +194,11 @@ class ReceivablePayableReport(object): # Delivery Note row += [voucher_details.get(gle.voucher_no, {}).get("delivery_note")] - # customer territory / supplier type + # customer territory / supplier group if args.get("party_type") == "Customer": row += [self.get_territory(gle.party), self.get_customer_group(gle.party)] if args.get("party_type") == "Supplier": - row += [self.get_supplier_type(gle.party)] + row += [self.get_supplier_group(gle.party)] row.append(gle.remarks) data.append(row) @@ -260,15 +260,15 @@ class ReceivablePayableReport(object): def get_customer_group(self, party_name): return self.get_party_map("Customer").get(party_name, {}).get("customer_group") or "" - def get_supplier_type(self, party_name): - return self.get_party_map("Supplier").get(party_name, {}).get("supplier_type") or "" + def get_supplier_group(self, party_name): + return self.get_party_map("Supplier").get(party_name, {}).get("supplier_group") or "" def get_party_map(self, party_type): if not hasattr(self, "party_map"): if party_type == "Customer": select_fields = "name, customer_name, territory, customer_group" elif party_type == "Supplier": - select_fields = "name, supplier_name, supplier_type" + select_fields = "name, supplier_name, supplier_group" self.party_map = dict(((r.name, r) for r in frappe.db.sql("select {0} from `tab{1}`" .format(select_fields, party_type), as_dict=True))) diff --git a/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py b/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py index 08b24fb1478..9b50960f4b6 100644 --- a/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py +++ b/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py @@ -35,7 +35,7 @@ class AccountsReceivableSummary(ReceivablePayableReport): _("Customer Group") + ":Link/Customer Group:120" ] if args.get("party_type") == "Supplier": - columns += [_("Supplier Type") + ":Link/Supplier Type:80"] + columns += [_("Supplier Group") + ":Link/Supplier Group:80"] columns.append({ "fieldname": "currency", @@ -66,7 +66,7 @@ class AccountsReceivableSummary(ReceivablePayableReport): if args.get("party_type") == "Customer": row += [self.get_territory(party), self.get_customer_group(party)] if args.get("party_type") == "Supplier": - row += [self.get_supplier_type(party)] + row += [self.get_supplier_group(party)] row.append(party_dict.currency) data.append(row) @@ -113,7 +113,7 @@ class AccountsReceivableSummary(ReceivablePayableReport): "outstanding_amt", "age", "range1", "range2", "range3", "range4", "currency"] if args.get("party_type") == "Supplier": - cols += ["supplier_type", "remarks"] + cols += ["supplier_group", "remarks"] if args.get("party_type") == "Customer": cols += ["territory", "customer_group", "remarks"] diff --git a/erpnext/accounts/report/purchase_register/purchase_register.py b/erpnext/accounts/report/purchase_register/purchase_register.py index cf599a0ccc6..7a298b322f2 100644 --- a/erpnext/accounts/report/purchase_register/purchase_register.py +++ b/erpnext/accounts/report/purchase_register/purchase_register.py @@ -42,7 +42,7 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum row.append(inv.get(col)) row += [ - supplier_details.get(inv.supplier), # supplier_type + supplier_details.get(inv.supplier), # supplier_group inv.tax_id, inv.credit_to, inv.mode_of_payment, ", ".join(project), inv.bill_no, inv.bill_date, inv.remarks, ", ".join(purchase_order), ", ".join(purchase_receipt), company_currency @@ -83,7 +83,7 @@ def get_columns(invoice_list, additional_table_columns): columns += additional_table_columns columns += [ - _("Supplier Type") + ":Link/Supplier Type:120", _("Tax Id") + "::80", _("Payable Account") + ":Link/Account:120", + _("Supplier Group") + ":Link/Supplier Group:120", _("Tax Id") + "::80", _("Payable Account") + ":Link/Account:120", _("Mode of Payment") + ":Link/Mode of Payment:80", _("Project") + ":Link/Project:80", _("Bill No") + "::120", _("Bill Date") + ":Date:80", _("Remarks") + "::150", _("Purchase Order") + ":Link/Purchase Order:100", @@ -229,8 +229,8 @@ def get_account_details(invoice_list): def get_supplier_details(suppliers): supplier_details = {} - for supp in frappe.db.sql("""select name, supplier_type from `tabSupplier` + for supp in frappe.db.sql("""select name, supplier_group from `tabSupplier` where name in (%s)""" % ", ".join(["%s"]*len(suppliers)), tuple(suppliers), as_dict=1): - supplier_details.setdefault(supp.name, supp.supplier_type) + supplier_details.setdefault(supp.name, supp.supplier_group) return supplier_details diff --git a/erpnext/assets/doctype/asset/asset.js b/erpnext/assets/doctype/asset/asset.js index 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/setup/doctype/supplier_type/test_supplier_type.js b/erpnext/assets/doctype/location/test_location.js similarity index 72% rename from erpnext/setup/doctype/supplier_type/test_supplier_type.js rename to erpnext/assets/doctype/location/test_location.js index 085dddd0b6f..236b5c65b0a 100644 --- a/erpnext/setup/doctype/supplier_type/test_supplier_type.js +++ b/erpnext/assets/doctype/location/test_location.js @@ -2,15 +2,15 @@ // rename this file from _test_[name] to test_[name] to activate // and remove above this line -QUnit.test("test: Supplier Type", function (assert) { +QUnit.test("test: Location", function (assert) { let done = assert.async(); // number of asserts assert.expect(1); frappe.run_serially([ - // insert a new Supplier Type - () => frappe.tests.make('Supplier Type', [ + // insert a new Location + () => frappe.tests.make('Location', [ // values to be set {key: 'value'} ]), 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/buying/doctype/buying_settings/buying_settings.json b/erpnext/buying/doctype/buying_settings/buying_settings.json index bb2b47def79..c0684f939a9 100644 --- a/erpnext/buying/doctype/buying_settings/buying_settings.json +++ b/erpnext/buying/doctype/buying_settings/buying_settings.json @@ -1,188 +1,263 @@ { "allow_copy": 0, + "allow_guest_to_view": 0, "allow_import": 0, "allow_rename": 0, + "beta": 0, "creation": "2013-06-25 11:04:03", "custom": 0, "description": "Settings for Buying Module", "docstatus": 0, "doctype": "DocType", "document_type": "Other", + "editable_grid": 0, "fields": [ { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "default": "Supplier Name", "fieldname": "supp_master_name", "fieldtype": "Select", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, + "in_global_search": 0, "in_list_view": 0, + "in_standard_filter": 0, "label": "Supplier Naming By", + "length": 0, "no_copy": 0, "options": "Supplier Name\nNaming Series", "permlevel": 0, "print_hide": 0, + "print_hide_if_no_value": 0, "read_only": 0, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, - "fieldname": "supplier_type", + "columns": 0, + "fieldname": "supplier_group", "fieldtype": "Link", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, + "in_global_search": 0, "in_list_view": 0, - "label": "Default Supplier Type", + "in_standard_filter": 0, + "label": "Default Supplier Group", + "length": 0, "no_copy": 0, - "options": "Supplier Type", + "options": "Supplier Group", "permlevel": 0, "print_hide": 0, + "print_hide_if_no_value": 0, "read_only": 0, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "buying_price_list", "fieldtype": "Link", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, + "in_global_search": 0, "in_list_view": 0, + "in_standard_filter": 0, "label": "Default Buying Price List", + "length": 0, "no_copy": 0, "options": "Price List", "permlevel": 0, "print_hide": 0, + "print_hide_if_no_value": 0, "read_only": 0, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "column_break_3", "fieldtype": "Column Break", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, + "in_global_search": 0, "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, "no_copy": 0, "permlevel": 0, "print_hide": 0, + "print_hide_if_no_value": 0, "read_only": 0, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "po_required", "fieldtype": "Select", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, + "in_global_search": 0, "in_list_view": 0, + "in_standard_filter": 0, "label": "Purchase Order Required", + "length": 0, "no_copy": 0, "options": "No\nYes", "permlevel": 0, "print_hide": 0, + "print_hide_if_no_value": 0, "read_only": 0, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "pr_required", "fieldtype": "Select", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, + "in_global_search": 0, "in_list_view": 0, + "in_standard_filter": 0, "label": "Purchase Receipt Required", + "length": 0, "no_copy": 0, "options": "No\nYes", "permlevel": 0, "print_hide": 0, + "print_hide_if_no_value": 0, "read_only": 0, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "maintain_same_rate", "fieldtype": "Check", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, + "in_global_search": 0, "in_list_view": 0, + "in_standard_filter": 0, "label": "Maintain same rate throughout purchase cycle", + "length": 0, "no_copy": 0, "permlevel": 0, "print_hide": 0, + "print_hide_if_no_value": 0, "read_only": 0, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "allow_multiple_items", "fieldtype": "Check", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, + "in_global_search": 0, "in_list_view": 0, + "in_standard_filter": 0, "label": "Allow Item to be added multiple times in a transaction", + "length": 0, "no_copy": 0, "permlevel": 0, "precision": "", "print_hide": 0, + "print_hide_if_no_value": 0, "read_only": 0, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { "allow_bulk_edit": 0, "allow_on_submit": 0, @@ -213,19 +288,22 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 } ], + "has_web_view": 0, "hide_heading": 0, "hide_toolbar": 0, "icon": "fa fa-cog", "idx": 1, + "image_view": 0, "in_create": 0, - "in_dialog": 0, "is_submittable": 0, "issingle": 1, "istable": 0, - "modified": "2017-12-27 15:20:06.052342", + "max_attachments": 0, + "modified": "2018-04-19 07:56:42.888821", "modified_by": "Administrator", "module": "Buying", "name": "Buying Settings", @@ -233,7 +311,6 @@ "permissions": [ { "amend": 0, - "apply_user_permissions": 0, "cancel": 0, "create": 1, "delete": 0, @@ -252,6 +329,10 @@ "write": 1 } ], + "quick_entry": 0, "read_only": 0, - "read_only_onload": 0 + "read_only_onload": 0, + "show_name_in_global_search": 0, + "track_changes": 0, + "track_seen": 0 } \ No newline at end of file diff --git a/erpnext/buying/doctype/buying_settings/buying_settings.py b/erpnext/buying/doctype/buying_settings/buying_settings.py index 1f0184b82c9..a634a0908b0 100644 --- a/erpnext/buying/doctype/buying_settings/buying_settings.py +++ b/erpnext/buying/doctype/buying_settings/buying_settings.py @@ -10,7 +10,7 @@ from frappe.model.document import Document class BuyingSettings(Document): def validate(self): - for key in ["supplier_type", "supp_master_name", "maintain_same_rate", "buying_price_list"]: + for key in ["supplier_group", "supp_master_name", "maintain_same_rate", "buying_price_list"]: frappe.db.set_default(key, self.get(key, "")) from erpnext.setup.doctype.naming_series.naming_series import set_by_naming_series diff --git a/erpnext/buying/doctype/party_tax_withholding_config/__init__.py b/erpnext/buying/doctype/party_tax_withholding_config/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/buying/doctype/party_tax_withholding_config/party_tax_withholding_config.json b/erpnext/buying/doctype/party_tax_withholding_config/party_tax_withholding_config.json new file mode 100644 index 00000000000..320485b318b --- /dev/null +++ b/erpnext/buying/doctype/party_tax_withholding_config/party_tax_withholding_config.json @@ -0,0 +1,166 @@ +{ + "allow_copy": 0, + "allow_guest_to_view": 0, + "allow_import": 0, + "allow_rename": 0, + "beta": 0, + "creation": "2018-05-11 13:32:33.825307", + "custom": 0, + "docstatus": 0, + "doctype": "DocType", + "document_type": "", + "editable_grid": 1, + "engine": "InnoDB", + "fields": [ + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "tax_withholding_category", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Tax Withholding Category", + "length": 0, + "no_copy": 0, + "options": "Tax Withholding Category", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "valid_till", + "fieldtype": "Date", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Valid Till", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "applicable_percent", + "fieldtype": "Float", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Applicable Percent", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "certificate_received", + "fieldtype": "Check", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Certificate Received", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + } + ], + "has_web_view": 0, + "hide_heading": 0, + "hide_toolbar": 0, + "idx": 0, + "image_view": 0, + "in_create": 0, + "is_submittable": 0, + "issingle": 0, + "istable": 1, + "max_attachments": 0, + "modified": "2018-05-11 13:35:44.424855", + "modified_by": "Administrator", + "module": "Buying", + "name": "Party Tax Withholding Config", + "name_case": "", + "owner": "Administrator", + "permissions": [], + "quick_entry": 1, + "read_only": 0, + "read_only_onload": 0, + "show_name_in_global_search": 0, + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1, + "track_seen": 0 +} \ No newline at end of file diff --git a/erpnext/buying/doctype/party_tax_withholding_config/party_tax_withholding_config.py b/erpnext/buying/doctype/party_tax_withholding_config/party_tax_withholding_config.py new file mode 100644 index 00000000000..bec7e83f237 --- /dev/null +++ b/erpnext/buying/doctype/party_tax_withholding_config/party_tax_withholding_config.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +from __future__ import unicode_literals +import frappe +from frappe.model.document import Document + +class PartyTaxWithholdingConfig(Document): + pass diff --git a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.js b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.js index de87e044437..2ff80755df6 100644 --- a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.js +++ b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.js @@ -61,11 +61,11 @@ frappe.ui.form.on("Request for Quotation",{ fields: [ { "fieldtype": "Select", "label": __("Get Suppliers By"), "fieldname": "search_type", - "options": "Tag\nSupplier Type", "reqd": 1 }, - { "fieldtype": "Link", "label": __("Supplier Type"), - "fieldname": "supplier_type", - "options": "Supplier Type", "reqd": 0, - "depends_on": "eval:doc.search_type == 'Supplier Type'"}, + "options": "Tag\nSupplier Group", "reqd": 1 }, + { "fieldtype": "Link", "label": __("Supplier Group"), + "fieldname": "supplier_group", + "options": "Supplier Group", "reqd": 0, + "depends_on": "eval:doc.search_type == 'Supplier Group'"}, { "fieldtype": "Data", "label": __("Tag"), "fieldname": "tag", "reqd": 0, "depends_on": "eval:doc.search_type == 'Tag'" }, @@ -121,14 +121,14 @@ frappe.ui.form.on("Request for Quotation",{ }, callback: load_suppliers }); - } else if (args.supplier_type) { + } else if (args.supplier_group) { return frappe.call({ method: "frappe.client.get_list", args: { doctype: "Supplier", order_by: "name", fields: ["name"], - filters: [["Supplier", "supplier_type", "=", args.supplier_type]] + filters: [["Supplier", "supplier_group_name", "=", args.supplier_group]] }, callback: load_suppliers diff --git a/erpnext/buying/doctype/request_for_quotation/test_request_for_quotation.py b/erpnext/buying/doctype/request_for_quotation/test_request_for_quotation.py index 7eb741f06a8..dbd9f022789 100644 --- a/erpnext/buying/doctype/request_for_quotation/test_request_for_quotation.py +++ b/erpnext/buying/doctype/request_for_quotation/test_request_for_quotation.py @@ -56,7 +56,7 @@ class TestRequestforQuotation(unittest.TestCase): frappe.delete_doc_if_exists("Supplier", "_Test Supplier '1", force=1) supplier = frappe.new_doc("Supplier") supplier.supplier_name = "_Test Supplier '1" - supplier.supplier_type = "_Test Supplier Type" + supplier.supplier_group = "_Test Supplier Group" supplier.insert() rfq = make_request_for_quotation(supplier_wt_appos) diff --git a/erpnext/buying/doctype/supplier/supplier.json b/erpnext/buying/doctype/supplier/supplier.json index afb8899dcb9..eedbac1dffe 100644 --- a/erpnext/buying/doctype/supplier/supplier.json +++ b/erpnext/buying/doctype/supplier/supplier.json @@ -43,7 +43,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, + "translatable": 0, "unique": 0 }, { @@ -76,7 +76,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 1, - "translatable": 0, + "translatable": 0, "unique": 0 }, { @@ -108,7 +108,7 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, - "translatable": 0, + "translatable": 0, "unique": 0 }, { @@ -140,7 +140,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, + "translatable": 0, "unique": 0 }, { @@ -171,7 +171,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, + "translatable": 0, "unique": 0 }, { @@ -233,7 +233,7 @@ "read_only": 0, "remember_last_selected_value": 0, "report_hide": 0, - "reqd": 1, + "reqd": 0, "search_index": 0, "set_only_once": 0, "translatable": 0, @@ -267,7 +267,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, + "translatable": 0, "unique": 0 }, { @@ -296,7 +296,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, + "translatable": 0, "unique": 0, "width": "50%" }, @@ -306,7 +306,7 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fieldname": "supplier_type", + "fieldname": "supplier_group", "fieldtype": "Link", "hidden": 0, "ignore_user_permissions": 0, @@ -315,12 +315,12 @@ "in_global_search": 0, "in_list_view": 1, "in_standard_filter": 1, - "label": "Supplier Type", + "label": "Supplier Group", "length": 0, "no_copy": 0, "oldfieldname": "supplier_type", "oldfieldtype": "Link", - "options": "Supplier Type", + "options": "Supplier Group", "permlevel": 0, "print_hide": 0, "print_hide_if_no_value": 0, @@ -330,7 +330,7 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, - "translatable": 0, + "translatable": 0, "unique": 0 }, { @@ -362,7 +362,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, + "translatable": 0, "unique": 0 }, { @@ -394,7 +394,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, + "translatable": 0, "unique": 0 }, { @@ -425,7 +425,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, + "translatable": 0, "unique": 0 }, { @@ -456,7 +456,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, + "translatable": 0, "unique": 0 }, { @@ -487,7 +487,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, + "translatable": 0, "unique": 0 }, { @@ -518,7 +518,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, + "translatable": 0, "unique": 0 }, { @@ -614,7 +614,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, + "translatable": 0, "unique": 0 }, { @@ -645,7 +645,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, + "translatable": 0, "unique": 0 }, { @@ -675,7 +675,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, + "translatable": 0, "unique": 0 }, { @@ -706,7 +706,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, + "translatable": 0, "unique": 0 }, { @@ -737,7 +737,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, + "translatable": 0, "unique": 0 }, { @@ -770,7 +770,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, + "translatable": 0, "unique": 0 }, { @@ -803,7 +803,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, + "translatable": 0, "unique": 0 }, { @@ -833,7 +833,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, + "translatable": 0, "unique": 0 }, { @@ -862,7 +862,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, + "translatable": 0, "unique": 0, "width": "50%" }, @@ -893,7 +893,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, + "translatable": 0, "unique": 0 }, { @@ -924,7 +924,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, + "translatable": 0, "unique": 0 }, { @@ -957,6 +957,69 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 1, + "columns": 0, + "fieldname": "default_tax_withholding_config", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Default Tax Withholding Config", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "tax_withholding_config", + "fieldtype": "Table", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Tax Withholding Account", + "length": 0, + "no_copy": 0, + "options": "Party Tax Withholding Config", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, "translatable": 0, "unique": 0 }, @@ -988,7 +1051,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, + "translatable": 0, "unique": 0, "width": "50%" }, @@ -1021,7 +1084,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "translatable": 0, + "translatable": 0, "unique": 0 }, { @@ -1117,38 +1180,6 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "tax_withholding_category", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Tax Withholding Category", - "length": 0, - "no_copy": 0, - "options": "Tax Withholding Category", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 } ], "has_web_view": 0, @@ -1163,7 +1194,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2018-04-19 12:19:52.519026", + "modified": "2018-05-11 15:15:19.912308", "modified_by": "Administrator", "module": "Buying", "name": "Supplier", @@ -1307,7 +1338,7 @@ "quick_entry": 1, "read_only": 0, "read_only_onload": 0, - "search_fields": "supplier_name, supplier_type", + "search_fields": "supplier_name, supplier_group", "show_name_in_global_search": 1, "sort_order": "ASC", "title_field": "supplier_name", diff --git a/erpnext/buying/doctype/supplier/supplier_list.js b/erpnext/buying/doctype/supplier/supplier_list.js index ab25d2c8fcf..d99e3f8f0f2 100644 --- a/erpnext/buying/doctype/supplier/supplier_list.js +++ b/erpnext/buying/doctype/supplier/supplier_list.js @@ -1,3 +1,3 @@ frappe.listview_settings['Supplier'] = { - add_fields: ["supplier_name", "supplier_type", "image"], + add_fields: ["supplier_name", "supplier_group", "image"], }; diff --git a/erpnext/buying/doctype/supplier/test_records.json b/erpnext/buying/doctype/supplier/test_records.json index 2536721326b..9c019898cb6 100644 --- a/erpnext/buying/doctype/supplier/test_records.json +++ b/erpnext/buying/doctype/supplier/test_records.json @@ -2,39 +2,39 @@ { "doctype": "Supplier", "supplier_name": "_Test Supplier With Template 1", - "supplier_type": "_Test Supplier Type", + "supplier_group": "_Test Supplier Group", "payment_terms": "_Test Payment Term Template 3" }, { "doctype": "Supplier", "supplier_name": "_Test Supplier P", - "supplier_type": "_Test Supplier Type" + "supplier_group": "_Test Supplier Group" }, { "doctype": "Supplier", "supplier_name": "_Test Supplier with Country", - "supplier_type": "_Test Supplier Type", + "supplier_group": "_Test Supplier Group", "country": "Greece" }, { "doctype": "Supplier", "supplier_name": "_Test Supplier", - "supplier_type": "_Test Supplier Type" + "supplier_group": "_Test Supplier Group" }, { "doctype": "Supplier", "supplier_name": "_Test Supplier 1", - "supplier_type": "_Test Supplier Type" + "supplier_group": "_Test Supplier Group" }, { "doctype": "Supplier", "supplier_name": "_Test Supplier 2", - "supplier_type": "_Test Supplier Type" + "supplier_group": "_Test Supplier Group" }, { "doctype": "Supplier", "supplier_name": "_Test Supplier USD", - "supplier_type": "_Test Supplier Type", + "supplier_group": "_Test Supplier Group", "accounts": [{ "company": "_Test Company", "account": "_Test Payable USD - _TC" diff --git a/erpnext/buying/doctype/supplier/test_supplier.js b/erpnext/buying/doctype/supplier/test_supplier.js index 51e3c097882..bf7c192c91c 100644 --- a/erpnext/buying/doctype/supplier/test_supplier.js +++ b/erpnext/buying/doctype/supplier/test_supplier.js @@ -7,7 +7,7 @@ QUnit.test("test: supplier", function(assert) { () => { return frappe.tests.make('Supplier', [ {supplier_name: 'Test Supplier'}, - {supplier_type: 'Hardware'}, + {supplier_group: 'Hardware'}, {country: 'India'}, {default_currency: 'INR'}, {accounts: [ @@ -66,7 +66,7 @@ QUnit.test("test: supplier", function(assert) { () => { assert.ok(cur_frm.doc.supplier_name == 'Test Supplier', "Name correct"); - assert.ok(cur_frm.doc.supplier_type == 'Hardware', "Type correct"); + assert.ok(cur_frm.doc.supplier_group == 'Hardware', "Type correct"); assert.ok(cur_frm.doc.default_currency == 'INR', "Currency correct"); assert.ok(cur_frm.doc.accounts[0].account == 'Creditors - '+frappe.get_abbr('For Testing'), " Account Head abbr correct"); assert.ok($('.address-box:nth-child(3) p').text().includes('Shipping City 3'), "Address correct"); diff --git a/erpnext/buying/doctype/supplier/test_supplier.py b/erpnext/buying/doctype/supplier/test_supplier.py index 16dda5c5ffc..2211db7e0d0 100644 --- a/erpnext/buying/doctype/supplier/test_supplier.py +++ b/erpnext/buying/doctype/supplier/test_supplier.py @@ -36,14 +36,14 @@ class TestSupplier(unittest.TestCase): frappe.db.set_value("Supplier", "_Test Supplier With Template 1", "payment_terms", "") - # Set credit limit for the supplier type instead of supplier and evaluate the due date - frappe.db.set_value("Supplier Type", "_Test Supplier Type", "payment_terms", "_Test Payment Term Template 3") + # Set credit limit for the supplier group instead of supplier and evaluate the due date + frappe.db.set_value("Supplier Group", "_Test Supplier Group", "payment_terms", "_Test Payment Term Template 3") due_date = get_due_date("2016-01-22", "Supplier", "_Test Supplier With Template 1") self.assertEqual(due_date, "2016-02-21") - # Payment terms for Supplier Type instead of supplier and evaluate the due date - frappe.db.set_value("Supplier Type", "_Test Supplier Type", "payment_terms", "_Test Payment Term Template 1") + # Payment terms for Supplier Group instead of supplier and evaluate the due date + frappe.db.set_value("Supplier Group", "_Test Supplier Group", "payment_terms", "_Test Payment Term Template 1") # Leap year due_date = get_due_date("2016-01-22", "Supplier", "_Test Supplier With Template 1") @@ -53,7 +53,7 @@ class TestSupplier(unittest.TestCase): self.assertEqual(due_date, "2017-02-28") # Supplier with no default Payment Terms Template - frappe.db.set_value("Supplier Type", "_Test Supplier Type", "payment_terms", "") + frappe.db.set_value("Supplier Group", "_Test Supplier Group", "payment_terms", "") frappe.db.set_value("Supplier", "_Test Supplier", "payment_terms", "") due_date = get_due_date("2016-01-22", "Supplier", "_Test Supplier") diff --git a/erpnext/buying/page/purchase_analytics/purchase_analytics.js b/erpnext/buying/page/purchase_analytics/purchase_analytics.js index 442a8bbd3ea..06764a3c603 100644 --- a/erpnext/buying/page/purchase_analytics/purchase_analytics.js +++ b/erpnext/buying/page/purchase_analytics/purchase_analytics.js @@ -19,7 +19,7 @@ erpnext.PurchaseAnalytics = frappe.views.TreeGridReport.extend({ title: __("Purchase Analytics"), parent: $(wrapper).find('.layout-main'), page: wrapper.page, - doctypes: ["Item", "Item Group", "Supplier", "Supplier Type", "Company", "Fiscal Year", + doctypes: ["Item", "Item Group", "Supplier", "Supplier Group", "Company", "Fiscal Year", "Purchase Invoice", "Purchase Invoice Item", "Purchase Order", "Purchase Order Item[Purchase Analytics]", "Purchase Receipt", "Purchase Receipt Item[Purchase Analytics]"], @@ -27,11 +27,11 @@ erpnext.PurchaseAnalytics = frappe.views.TreeGridReport.extend({ }); this.tree_grids = { - "Supplier Type": { - label: __("Supplier Type / Supplier"), + "Supplier Group": { + label: __("Supplier Group / Supplier"), show: true, item_key: "supplier", - parent_field: "parent_supplier_type", + parent_field: "parent_supplier_group", formatter: function(item) { return item.supplier_name ? item.supplier_name + " (" + item.name + ")" : item.name; } @@ -77,7 +77,7 @@ erpnext.PurchaseAnalytics = frappe.views.TreeGridReport.extend({ }, filters: [ {fieldtype:"Select", label: __("Tree Type"), fieldname: "tree_type", - options:["Supplier Type", "Supplier", "Item Group", "Item"], + options:["Supplier Group", "Supplier", "Item Group", "Item"], filter: function(val, item, opts, me) { return me.apply_zero_filter(val, item, opts, me); }}, @@ -110,22 +110,10 @@ erpnext.PurchaseAnalytics = frappe.views.TreeGridReport.extend({ var me = this; if (!this.tl) { // add 'Not Set' Supplier & Item - // Add 'All Supplier Types' Supplier Type // (Supplier / Item are not mandatory!!) - // Set parent supplier type for tree view - - $.each(frappe.report_dump.data["Supplier Type"], function(i, v) { - v['parent_supplier_type'] = __("All Supplier Types") - }) - - frappe.report_dump.data["Supplier Type"] = [{ - name: __("All Supplier Types"), - id: "All Supplier Types", - }].concat(frappe.report_dump.data["Supplier Type"]); - frappe.report_dump.data["Supplier"].push({ name: __("Not Set"), - parent_supplier_type: __("All Supplier Types"), + parent_supplier_group: __("All Supplier Groups"), id: "Not Set", }); @@ -142,14 +130,15 @@ erpnext.PurchaseAnalytics = frappe.views.TreeGridReport.extend({ if(!this.data || me.item_type != me.tree_type) { + var items; if(me.tree_type=='Supplier') { - var items = frappe.report_dump.data["Supplier"]; - } if(me.tree_type=='Supplier Type') { - var items = this.prepare_tree("Supplier", "Supplier Type"); + items = frappe.report_dump.data["Supplier"]; + } else if(me.tree_type=='Supplier Group') { + items = this.prepare_tree("Supplier", "Supplier Group"); } else if(me.tree_type=="Item Group") { - var items = this.prepare_tree("Item", "Item Group"); + items = this.prepare_tree("Item", "Item Group"); } else if(me.tree_type=="Item") { - var items = frappe.report_dump.data["Item"]; + items = frappe.report_dump.data["Item"]; } me.item_type = me.tree_type diff --git a/erpnext/config/assets.py b/erpnext/config/assets.py index 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/buying.py b/erpnext/config/buying.py index ba29125ca0e..e20d514a231 100644 --- a/erpnext/config/buying.py +++ b/erpnext/config/buying.py @@ -39,8 +39,8 @@ def get_data(): }, { "type": "doctype", - "name": "Supplier Type", - "description": _("Supplier Type master.") + "name": "Supplier Group", + "description": _("Supplier Group master.") }, { "type": "doctype", diff --git a/erpnext/config/hr.py b/erpnext/config/hr.py index 6ec5c26e7d3..5da0fbc20c4 100644 --- a/erpnext/config/hr.py +++ b/erpnext/config/hr.py @@ -119,6 +119,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/controllers/queries.py b/erpnext/controllers/queries.py index fd13c1353e2..3bf720fd5dc 100644 --- a/erpnext/controllers/queries.py +++ b/erpnext/controllers/queries.py @@ -102,9 +102,9 @@ def customer_query(doctype, txt, searchfield, start, page_len, filters): def supplier_query(doctype, txt, searchfield, start, page_len, filters): supp_master_name = frappe.defaults.get_user_default("supp_master_name") if supp_master_name == "Supplier Name": - fields = ["name", "supplier_type"] + fields = ["name", "supplier_group"] else: - fields = ["name", "supplier_name", "supplier_type"] + fields = ["name", "supplier_name", "supplier_group"] fields = ", ".join(fields) return frappe.db.sql("""select {field} from `tabSupplier` diff --git a/erpnext/controllers/trends.py b/erpnext/controllers/trends.py index ef698c2a16f..28a8fddfacb 100644 --- a/erpnext/controllers/trends.py +++ b/erpnext/controllers/trends.py @@ -235,16 +235,16 @@ def based_wise_columns_query(based_on, trans): based_on_details["addl_tables"] = '' elif based_on == 'Supplier': - based_on_details["based_on_cols"] = ["Supplier:Link/Supplier:120", "Supplier Type:Link/Supplier Type:140"] - based_on_details["based_on_select"] = "t1.supplier, t3.supplier_type," + based_on_details["based_on_cols"] = ["Supplier:Link/Supplier:120", "Supplier Group:Link/Supplier Group:140"] + based_on_details["based_on_select"] = "t1.supplier, t3.supplier_group," based_on_details["based_on_group_by"] = 't1.supplier' based_on_details["addl_tables"] = ',`tabSupplier` t3' based_on_details["addl_tables_relational_cond"] = " and t1.supplier = t3.name" - elif based_on == 'Supplier Type': - based_on_details["based_on_cols"] = ["Supplier Type:Link/Supplier Type:140"] - based_on_details["based_on_select"] = "t3.supplier_type," - based_on_details["based_on_group_by"] = 't3.supplier_type' + elif based_on == 'Supplier Group': + based_on_details["based_on_cols"] = ["Supplier Group:Link/Supplier Group:140"] + based_on_details["based_on_select"] = "t3.supplier_group," + based_on_details["based_on_group_by"] = 't3.supplier_group' based_on_details["addl_tables"] = ',`tabSupplier` t3' based_on_details["addl_tables_relational_cond"] = " and t1.supplier = t3.name" diff --git a/erpnext/demo/setup/setup_data.py b/erpnext/demo/setup/setup_data.py index 4ed4df9176d..42d079db348 100644 --- a/erpnext/demo/setup/setup_data.py +++ b/erpnext/demo/setup/setup_data.py @@ -275,7 +275,7 @@ def setup_supplier(): frappe.get_doc({ "doctype": "Supplier", "supplier_name": s, - "supplier_type": random.choice(["Services", "Raw Material"]), + "supplier_group": random.choice(["Services", "Raw Material"]), }).insert() def setup_warehouse(): diff --git a/erpnext/docs/assets/img/human-resources/shift-assignment-calendar.png b/erpnext/docs/assets/img/human-resources/shift-assignment-calendar.png new file mode 100644 index 00000000000..7c8ec779c0e Binary files /dev/null and b/erpnext/docs/assets/img/human-resources/shift-assignment-calendar.png differ diff --git a/erpnext/docs/assets/img/human-resources/shift-assignment.png b/erpnext/docs/assets/img/human-resources/shift-assignment.png new file mode 100644 index 00000000000..39c2857efcd Binary files /dev/null and b/erpnext/docs/assets/img/human-resources/shift-assignment.png differ diff --git a/erpnext/docs/assets/img/human-resources/shift-request.png b/erpnext/docs/assets/img/human-resources/shift-request.png new file mode 100644 index 00000000000..77a7ad59a7b Binary files /dev/null and b/erpnext/docs/assets/img/human-resources/shift-request.png differ diff --git a/erpnext/docs/assets/img/human-resources/shift-type.png b/erpnext/docs/assets/img/human-resources/shift-type.png new file mode 100644 index 00000000000..e03e45c64be Binary files /dev/null and b/erpnext/docs/assets/img/human-resources/shift-type.png differ diff --git a/erpnext/docs/user/manual/en/human-resources/shift-management.md b/erpnext/docs/user/manual/en/human-resources/shift-management.md new file mode 100644 index 00000000000..2279538cc2a --- /dev/null +++ b/erpnext/docs/user/manual/en/human-resources/shift-management.md @@ -0,0 +1,44 @@ +# Shift Management + +Shift Management section of Human Resources helps your Organization manage shifts of your employees. + +To use Shift Management in ERPNext, + + 1. Set Up a Shift Type. + 2. Enter Shift Request. + 3. View and Manage Shift Assignments. + +### Shift Type + +The Shift Type Set Up allows you to define the different types of Shifts in your Organization. + +To create a new Shift Type go to: + +Human Resources > Shift Management > Shift Type + +* Enter Shift Type, Start Time and End Time for quick entry. + + Shift Type + +### Shift Request + +Shift Request is used by an employee to request for a particular Shift Type. + +To create a new Shift Request Log go to: + +Human Resources > Shift Management > Shift Request + +* Enter Shift Type, Employee, Company, From Date and To Date. + + Shift Request + +### Shift Assignment + +* Once the Shift Request is submitted it automatically creates the Shift Assignments for an Employee. + + Shift Assignment + +* You can also view Calendar view of Shift Assignments. + + Shift Assignment Calendar \ No newline at end of file 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..cc3fb7ff20b 100644 --- a/erpnext/hr/doctype/employee/employee.json +++ b/erpnext/hr/doctype/employee/employee.json @@ -393,6 +393,38 @@ "translatable": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "job_applicant", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Job Applicant", + "length": 0, + "no_copy": 0, + "options": "Job Applicant", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_on_submit": 0, @@ -1262,38 +1294,6 @@ "translatable": 0, "unique": 0 }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "leave_policy", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Leave Policy", - "length": 0, - "no_copy": 0, - "options": "Leave Policy", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, { "allow_bulk_edit": 0, "allow_on_submit": 0, @@ -2766,7 +2766,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2018-04-25 09:08:06.852604", + "modified": "2018-05-11 12:48:46.435484", "modified_by": "Administrator", "module": "HR", "name": "Employee", diff --git a/erpnext/hr/doctype/employee/employee.py b/erpnext/hr/doctype/employee/employee.py index 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 %} +
    {{ __("Allocated Leaves") }}
    + + + + + + + + + + + + + + {% for(const [key, value] of Object.entries(data)) { %} + + + + + + + + {% } %} + +
    {{ __("Leave Type") }}{{ __("Total Allocated Leaves") }}{{ __("Used Leaves") }}{{ __("Pending Leaves") }}{{ __("Available Leaves") }}
    {%= key %} {%= value["total_leaves"] %} {%= value["leaves_taken"] %} {%= value["pending_leaves"] %} {%= value["remaining_leaves"] %}
    +{% } else { %} +

    No Leaves have been allocated.

    +{% } %} \ No newline at end of file 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 1025bc7daea..0dd2b4cb07e 100644 --- a/erpnext/hr/doctype/payroll_entry/payroll_entry.py +++ b/erpnext/hr/doctype/payroll_entry/payroll_entry.py @@ -38,18 +38,19 @@ class PayrollEntry(Document): ifnull(salary_slip_based_on_timesheet,0) = %(salary_slip_based_on_timesheet)s {condition}""".format(condition=condition), {"company": self.company, "salary_slip_based_on_timesheet":self.salary_slip_based_on_timesheet}) - if sal_struct: - cond += "and t2.parent IN %(sal_struct)s " + cond += "and t2.salary_structure IN %(sal_struct)s " + cond += "and ((%(from_date)s between t2.from_date and ifnull(t2.to_date, '2199-12-31')) or (%(to_date)s between t2.from_date and ifnull(t2.to_date, '2199-12-31')) or (t2.from_date between %(from_date)s and %(to_date)s))" emp_list = frappe.db.sql(""" select - t1.name as employee, t1.employee_name, t1.department, t1.designation + t1.name as employee, t1.employee_name, t1.department, t1.designation, t2.name from - `tabEmployee` t1, `tabSalary Structure Employee` t2 + `tabEmployee` t1, `tabSalary Structure Assignment` t2 where t1.docstatus!=2 and t1.name = t2.employee - %s """% cond, {"sal_struct": sal_struct}, as_dict=True) + and t2.docstatus = 1 + %s """% cond, {"sal_struct": sal_struct, "from_date": self.start_date, "to_date": self.end_date}, as_dict=True) return emp_list def fill_employee_details(self): diff --git a/erpnext/hr/doctype/salary_component/salary_component.json b/erpnext/hr/doctype/salary_component/salary_component.json index 27b4bef0368..f08b1d7a0bd 100644 --- a/erpnext/hr/doctype/salary_component/salary_component.json +++ b/erpnext/hr/doctype/salary_component/salary_component.json @@ -610,6 +610,634 @@ "set_only_once": 0, "translatable": 0, "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 1, + "columns": 0, + "fieldname": "condition_and_formula", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Condition and Formula", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "condition", + "fieldtype": "Code", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Condition", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "description": "If selected, the value specified or calculated in this component will not contribute to the earnings or deductions. However, it's value can be referenced by other components that can be added or deducted. ", + "fieldname": "statistical_component", + "fieldtype": "Check", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Statistical Component", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "depends_on_lwp", + "fieldtype": "Check", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Depends on Leave Without Pay", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "do_not_include_in_total", + "fieldtype": "Check", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Do not include in total", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "default": "1", + "fieldname": "amount_based_on_formula", + "fieldtype": "Check", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Amount based on formula", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "eval:doc.amount_based_on_formula!==0", + "fieldname": "formula", + "fieldtype": "Code", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Formula", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "eval:doc.amount_based_on_formula!==1", + "fieldname": "amount", + "fieldtype": "Currency", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Amount", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "column_break_28", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "help", + "fieldtype": "HTML", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Help", + "length": 0, + "no_copy": 0, + "options": "

    Help

    \n\n

    Notes:

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

    Examples

    \n
      \n
    1. Calculating Basic Salary based on base\n
      Condition: base < 10000
      \n
      Formula: base * .2
    2. \n
    3. Calculating HRA based on Basic SalaryBS \n
      Condition: BS > 2000
      \n
      Formula: BS * .1
    4. \n
    5. Calculating TDS based on Employment Typeemployment_type \n
      Condition: employment_type==\"Intern\"
      \n
      Amount: 1000
    6. \n
    ", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 1, + "columns": 0, + "fieldname": "condition_and_formula", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Condition and Formula", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "condition", + "fieldtype": "Code", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Condition", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "description": "If selected, the value specified or calculated in this component will not contribute to the earnings or deductions. However, it's value can be referenced by other components that can be added or deducted. ", + "fieldname": "statistical_component", + "fieldtype": "Check", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Statistical Component", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "depends_on_lwp", + "fieldtype": "Check", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Depends on Leave Without Pay", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "do_not_include_in_total", + "fieldtype": "Check", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Do not include in total", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "default": "1", + "fieldname": "amount_based_on_formula", + "fieldtype": "Check", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Amount based on formula", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "eval:doc.amount_based_on_formula!==0", + "fieldname": "formula", + "fieldtype": "Code", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Formula", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "eval:doc.amount_based_on_formula!==1", + "fieldname": "amount", + "fieldtype": "Currency", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Amount", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "column_break_28", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "help", + "fieldtype": "HTML", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Help", + "length": 0, + "no_copy": 0, + "options": "

    Help

    \n\n

    Notes:

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

    Examples

    \n
      \n
    1. Calculating Basic Salary based on base\n
      Condition: base < 10000
      \n
      Formula: base * .2
    2. \n
    3. Calculating HRA based on Basic SalaryBS \n
      Condition: BS > 2000
      \n
      Formula: BS * .1
    4. \n
    5. Calculating TDS based on Employment Typeemployment_type \n
      Condition: employment_type==\"Intern\"
      \n
      Amount: 1000
    6. \n
    ", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 } ], "has_web_view": 0, @@ -623,7 +1251,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2018-04-27 13:23:34.503504", + "modified": "2018-05-09 17:35:11.073733", "modified_by": "Administrator", "module": "HR", "name": "Salary Component", @@ -658,4 +1286,4 @@ "sort_order": "DESC", "track_changes": 0, "track_seen": 0 -} \ No newline at end of file +} diff --git a/erpnext/hr/doctype/salary_slip/salary_slip.py b/erpnext/hr/doctype/salary_slip/salary_slip.py index 75eb73b5327..984a78c75ff 100644 --- a/erpnext/hr/doctype/salary_slip/salary_slip.py +++ b/erpnext/hr/doctype/salary_slip/salary_slip.py @@ -12,6 +12,7 @@ from erpnext.hr.doctype.payroll_entry.payroll_entry import get_start_end_dates from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee from erpnext.utilities.transaction_base import TransactionBase from frappe.utils.background_jobs import enqueue +from erpnext.hr.doctype.additional_salary_component.additional_salary_component import get_additional_salary_component class SalarySlip(TransactionBase): def autoname(self): @@ -58,6 +59,12 @@ class SalarySlip(TransactionBase): if amount and struct_row.statistical_component == 0: self.update_component_row(struct_row, amount, key) + additional_components = get_additional_salary_component(self.employee, self.start_date, self.end_date) + if additional_components: + for additional_component in additional_components: + additional_component = frappe._dict(additional_component) + self.update_component_row(frappe._dict(additional_component.struct_row), additional_component.amount, "earnings") + def update_component_row(self, struct_row, amount, key): component_row = None for d in self.get(key): @@ -104,8 +111,8 @@ class SalarySlip(TransactionBase): '''Returns data for evaluating formula''' data = frappe._dict() - data.update(frappe.get_doc("Salary Structure Employee", - {"employee": self.employee, "parent": self.salary_structure}).as_dict()) + data.update(frappe.get_doc("Salary Structure Assignment", + {"employee": self.employee, "salary_structure": self.salary_structure}).as_dict()) data.update(frappe.get_doc("Employee", self.employee).as_dict()) data.update(self.as_dict()) @@ -166,10 +173,10 @@ class SalarySlip(TransactionBase): if self.payroll_frequency: cond = """and payroll_frequency = '%(payroll_frequency)s'""" % {"payroll_frequency": self.payroll_frequency} - st_name = frappe.db.sql("""select parent from `tabSalary Structure Employee` + st_name = frappe.db.sql("""select salary_structure from `tabSalary Structure Assignment` where employee=%s and (from_date <= %s or from_date <= %s) and (to_date is null or to_date >= %s or to_date >= %s) - and parent in (select name from `tabSalary Structure` + and salary_structure in (select name from `tabSalary Structure` where is_active = 'Yes'%s) """% ('%s', '%s', '%s','%s','%s', cond),(self.employee, self.start_date, joining_date, self.end_date, relieving_date)) @@ -327,7 +334,7 @@ class SalarySlip(TransactionBase): def sum_components(self, component_type, total_field): joining_date, relieving_date = frappe.db.get_value("Employee", self.employee, ["date_of_joining", "relieving_date"]) - + if not relieving_date: relieving_date = getdate(self.end_date) @@ -463,4 +470,4 @@ def unlink_ref_doc_from_salary_slip(ref_no): if linked_ss: for ss in linked_ss: ss_doc = frappe.get_doc("Salary Slip", ss) - frappe.db.set_value("Salary Slip", ss_doc.name, "journal_entry", "") \ No newline at end of file + frappe.db.set_value("Salary Slip", ss_doc.name, "journal_entry", "") diff --git a/erpnext/hr/doctype/salary_slip/test_salary_slip.py b/erpnext/hr/doctype/salary_slip/test_salary_slip.py index cced29d7d98..ae58298bff2 100644 --- a/erpnext/hr/doctype/salary_slip/test_salary_slip.py +++ b/erpnext/hr/doctype/salary_slip/test_salary_slip.py @@ -7,6 +7,7 @@ import frappe import erpnext import calendar from erpnext.accounts.utils import get_fiscal_year +from frappe.utils.make_random import get_random from frappe.utils import getdate, nowdate, add_days, add_months, flt from erpnext.hr.doctype.salary_structure.salary_structure import make_salary_slip from erpnext.hr.doctype.payroll_entry.test_payroll_entry import get_salary_component_account @@ -272,33 +273,31 @@ def make_salary_structure(sal_struct, payroll_frequency, employee): frappe.get_doc({ "doctype": "Salary Structure", "name": sal_struct, - "company": erpnext.get_default_company(), - "employees": get_employee_details(employee), + "company": "_Test Company", "earnings": get_earnings_component(), "deductions": get_deductions_component(), "payroll_frequency": payroll_frequency, - "payment_account": frappe.get_value('Account', {'account_type': 'Cash', 'company': erpnext.get_default_company(),'is_group':0}, "name") + "payment_account": get_random("Account") }).insert() - elif not frappe.db.get_value("Salary Structure Employee",{'parent':sal_struct, 'employee':employee},'name'): + create_salary_structure_assignment(employee, sal_struct) + + elif not frappe.db.get_value("Salary Structure Assignment",{'salary_structure':sal_struct, 'employee':employee},'name'): sal_struct = frappe.get_doc("Salary Structure", sal_struct) - sal_struct.append("employees", {"employee": employee, - "employee_name": employee, - "base": 32000, - "variable": 3200, - "from_date": add_months(nowdate(),-1) - }) - sal_struct.save() + create_salary_structure_assignment(employee, sal_struct) sal_struct = sal_struct.name return sal_struct -def get_employee_details(employee): - return [{"employee": employee, - "base": 50000, - "variable": 5000, - "from_date": add_months(nowdate(),-1) - } - ] +def create_salary_structure_assignment(employee, salary_structure): + salary_structure_assignment = frappe.new_doc("Salary Structure Assignment") + salary_structure_assignment.employee = employee + salary_structure_assignment.base = 50000 + salary_structure_assignment.variable = 5000 + salary_structure_assignment.from_date = add_months(nowdate(), -1) + salary_structure_assignment.salary_structure = salary_structure + salary_structure_assignment.company = erpnext.get_default_company() + salary_structure_assignment.save(ignore_permissions=True) + return salary_structure_assignment def get_earnings_component(): return [ @@ -353,4 +352,4 @@ def get_deductions_component(): "formula": 'base*.1', "idx": 3 } - ] \ No newline at end of file + ] diff --git a/erpnext/hr/doctype/salary_structure/salary_structure.js b/erpnext/hr/doctype/salary_structure/salary_structure.js index 3de01cd303f..6f5c923a35c 100755 --- a/erpnext/hr/doctype/salary_structure/salary_structure.js +++ b/erpnext/hr/doctype/salary_structure/salary_structure.js @@ -165,5 +165,46 @@ frappe.ui.form.on('Salary Detail', { deductions_remove: function(frm) { calculate_totals(frm.doc); + }, + + salary_component: function(frm, cdt, cdn) { + var child = locals[cdt][cdn]; + if(child.salary_component){ + frappe.call({ + method: "frappe.client.get", + args: { + doctype: "Salary Component", + name: child.salary_component + }, + callback: function(data) { + if(data.message){ + var result = data.message; + frappe.model.set_value(cdt, cdn, 'condition',result.condition); + frappe.model.set_value(cdt, cdn, 'amount_based_on_formula',result.amount_based_on_formula); + if(result.amount_based_on_formula == 1){ + frappe.model.set_value(cdt, cdn, 'formula',result.formula); + } + else{ + frappe.model.set_value(cdt, cdn, 'amount',result.amount); + } + frappe.model.set_value(cdt, cdn, 'statistical_component',result.statistical_component); + frappe.model.set_value(cdt, cdn, 'depends_on_lwp',result.depends_on_lwp); + frappe.model.set_value(cdt, cdn, 'do_not_include_in_total',result.do_not_include_in_total); + refresh_field("earnings"); + refresh_field("deductions"); + } + } + }); + } + }, + + amount_based_on_formula: function(frm, cdt, cdn) { + var child = locals[cdt][cdn]; + if(child.amount_based_on_formula == 1){ + frappe.model.set_value(cdt, cdn, 'amount', null); + } + else{ + frappe.model.set_value(cdt, cdn, 'formula', null); + } } }) diff --git a/erpnext/hr/doctype/salary_structure_assignment/salary_structure_assignment.js b/erpnext/hr/doctype/salary_structure_assignment/salary_structure_assignment.js index e7c65986531..56a05e04956 100644 --- a/erpnext/hr/doctype/salary_structure_assignment/salary_structure_assignment.js +++ b/erpnext/hr/doctype/salary_structure_assignment/salary_structure_assignment.js @@ -11,9 +11,36 @@ frappe.ui.form.on('Salary Structure Assignment', { } } }); + frm.set_query("salary_structure", function() { + return { + filters: { + company: frm.doc.company, + docstatus: 1, + is_active: "Yes" + } + } + }); }, - - refresh: function(frm) { - + employee: function(frm) { + if(frm.doc.employee){ + frappe.call({ + method: "frappe.client.get_value", + args:{ + doctype: "Employee", + fieldname: "company", + filters:{ + name: frm.doc.employee + } + }, + callback: function(data) { + if(data.message){ + frm.set_value("company", data.message.company); + } + } + }); + } + else{ + frm.set_value("company", null); + } } }); diff --git a/erpnext/hr/doctype/salary_structure_assignment/salary_structure_assignment.py b/erpnext/hr/doctype/salary_structure_assignment/salary_structure_assignment.py index c9269d7c92b..ee2920be2ce 100644 --- a/erpnext/hr/doctype/salary_structure_assignment/salary_structure_assignment.py +++ b/erpnext/hr/doctype/salary_structure_assignment/salary_structure_assignment.py @@ -11,6 +11,7 @@ from frappe.model.document import Document class SalaryStructureAssignment(Document): def validate(self): self.validate_dates() + self.validate_duplicate_assignments() def validate_dates(self): joining_date, relieving_date = frappe.db.get_value("Employee", self.employee, @@ -33,10 +34,14 @@ class SalaryStructureAssignment(Document): .format(self.to_date, relieving_date)) def validate_duplicate_assignments(self): + if not self.name: + # hack! if name is null, it could cause problems with != + self.name = "New "+self.doctype assignment = frappe.db.sql(""" select name from `tabSalary Structure Assignment` where employee=%(employee)s - and name != %(salary_struct)s + and name != %(name)s + and docstatus != 2 and ( (%(from_date)s between from_date and ifnull(to_date, '2199-12-31')) or (%(to_date)s between from_date and ifnull(to_date, '2199-12-31')) @@ -45,8 +50,8 @@ class SalaryStructureAssignment(Document): 'employee': self.employee, 'from_date': self.from_date, 'to_date': (self.to_date or '2199-12-31'), - 'salary_struct': self.salary_struct + 'name': self.name }) if assignment: - frappe.throw(_("Active Salary Structure Assignment {0} found for employee {1} for the given dates").format(assignment[0][0], self.employee)) \ No newline at end of file + frappe.throw(_("Active Salary Structure Assignment {0} found for employee {1} for the given dates").format(assignment[0][0], self.employee)) diff --git a/erpnext/hr/doctype/shift_request/test_shift_request.py b/erpnext/hr/doctype/shift_request/test_shift_request.py index 0b8bcb811c1..d32443a9524 100644 --- a/erpnext/hr/doctype/shift_request/test_shift_request.py +++ b/erpnext/hr/doctype/shift_request/test_shift_request.py @@ -5,6 +5,24 @@ from __future__ import unicode_literals import frappe import unittest +from frappe.utils import nowdate class TestShiftRequest(unittest.TestCase): - pass + def test_make_shift_request(self): + shift_request = frappe.get_doc({ + "doctype": "Shift Request", + "shift_type": "Day Shift", + "company": "_Test Company", + "employee": "_T-Employee-00001", + "employee_name": "_Test Employee", + "start_date": nowdate(), + "end_date": nowdate() + }) + shift_request.insert() + shift_request.submit() + shift_assignment = frappe.db.sql("""select employee + from `tabShift Assignment` + where shift_request = %s""", shift_request.name) + if shift_assignment: + employee = shift_assignment[0][0] + self.assertEqual(shift_request.employee, employee) \ No newline at end of file diff --git a/erpnext/hr/doctype/shift_type/test_shift_type.py b/erpnext/hr/doctype/shift_type/test_shift_type.py index bc4f0eafcd5..d5afdf519b3 100644 --- a/erpnext/hr/doctype/shift_type/test_shift_type.py +++ b/erpnext/hr/doctype/shift_type/test_shift_type.py @@ -7,4 +7,11 @@ import frappe import unittest class TestShiftType(unittest.TestCase): - pass + def test_make_shift_type(self): + shift_type = frappe.get_doc({ + "doctype": "Shift Type", + "name": "Day Shift", + "start_time": "9:00:00", + "end_time": "18:00:00" + }) + shift_type.insert() diff --git a/erpnext/hr/doctype/staffing_plan/staffing_plan.js b/erpnext/hr/doctype/staffing_plan/staffing_plan.js index 1c1a7200886..ca57d9f19de 100644 --- a/erpnext/hr/doctype/staffing_plan/staffing_plan.js +++ b/erpnext/hr/doctype/staffing_plan/staffing_plan.js @@ -17,6 +17,14 @@ frappe.ui.form.on('Staffing Plan', { ] } }); + + frm.set_query("department", function() { + return { + "filters": { + "company": frm.doc.company, + } + }; + }); } }); diff --git a/erpnext/hr/utils.py b/erpnext/hr/utils.py index 040134b3bcf..8ab053719d8 100644 --- a/erpnext/hr/utils.py +++ b/erpnext/hr/utils.py @@ -6,11 +6,100 @@ import frappe from frappe import _ from frappe.utils import formatdate, format_datetime from frappe.utils import getdate, get_datetime +from frappe.model.document import Document +from frappe.desk.form import assign_to + +class EmployeeBoardingController(Document): + ''' + Create the project and the task for the boarding process + Assign to the concerned person and roles as per the onboarding/separation template + ''' + def validate(self): + # remove the task if linked before submitting the form + if self.amended_from: + for activity in self.activities: + activity.task = '' + + def on_submit(self): + # create the project for the given employee onboarding + project_name = _(self.doctype) + " : " + self.employee_name + if self.doctype == "Employee Onboarding": + project_name += " (" + self.job_applicant + ")" + else: + project_name += " (" + self.employee + ")" + project = frappe.get_doc({ + "doctype": "Project", + "project_name": project_name, + "expected_start_date": self.date_of_joining if self.doctype == "Employee Onboarding" else self.resignation_letter_date, + "department": self.department, + "company": self.company + }).insert(ignore_permissions=True) + self.db_set("project", project.name) + + # create the task for the given project and assign to the concerned person + for activity in self.activities: + task = frappe.get_doc({ + "doctype": "Task", + "project": project.name, + "subject": activity.activity_name + " : " + self.employee_name, + "description": activity.description, + "department": self.department, + "company": self.company + }).insert(ignore_permissions=True) + activity.db_set("task", task.name) + users = [activity.user] if activity.user else [] + if activity.role: + user_list = frappe.db.sql_list('''select distinct(parent) from `tabHas Role` + where parenttype='User' and role=%s''', activity.role) + users = users + user_list + + # assign the task the users + if users: + self.assign_task_to_users(task, set(users)) + + def assign_task_to_users(self, task, users): + for user in users: + args = { + 'assign_to' : user, + 'doctype' : task.doctype, + 'name' : task.name, + 'description' : task.description or task.subject, + } + assign_to.add(args) + + def on_cancel(self): + # delete task project + for task in frappe.get_all("Task", filters={"project": self.project}): + frappe.delete_doc("Task", task.name) + frappe.delete_doc("Project", self.project) + self.db_set('project', '') + for activity in self.activities: + activity.db_set("task", "") + + +@frappe.whitelist() +def get_onboarding_details(parent, parenttype): + return frappe.get_list("Employee Boarding Activity", + fields=["activity_name", "role", "user", "required_for_employee_creation", "description"], + filters={"parent": parent, "parenttype": parenttype}, + order_by= "idx") + def set_employee_name(doc): if doc.employee and not doc.employee_name: doc.employee_name = frappe.db.get_value("Employee", doc.employee, "employee_name") +def update_employee(employee, details, cancel=False): + for item in details: + fieldtype = frappe.get_meta("Employee").get_field(item.fieldname).fieldtype + new_data = item.new if not cancel else item.current + if fieldtype == "Date" and new_data: + new_data = getdate(new_data) + elif fieldtype =="Datetime" and new_data: + new_data = get_datetime(new_data) + setattr(employee, item.fieldname, new_data) + return employee + @frappe.whitelist() def get_employee_fields_label(): fields = [] @@ -62,3 +151,21 @@ def validate_tax_declaration(declarations): if declaration.amount > max_amount: frappe.throw(_("Max exemption amount for {0} is {1}").format(\ declaration.exemption_sub_category, max_amount), frappe.ValidationError) + +def get_leave_period(from_date, to_date, company): + leave_period = frappe.db.sql(""" + select name, from_date, to_date + from `tabLeave Period` + where company=%(company)s and is_active=1 + and (from_date between %(from_date)s and %(to_date)s + or to_date between %(from_date)s and %(to_date)s + or (from_date < %(from_date)s and to_date > %(to_date)s)) + """, { + "from_date": from_date, + "to_date": to_date, + "company": company + }, as_dict=1) + + if leave_period: + return leave_period + diff --git a/erpnext/hub_node/__init__.py b/erpnext/hub_node/__init__.py index 89ee926d55a..65b1386466f 100644 --- a/erpnext/hub_node/__init__.py +++ b/erpnext/hub_node/__init__.py @@ -187,7 +187,7 @@ def make_supplier(supplier): supplier_doc = frappe.get_doc({ 'doctype': 'Supplier', 'supplier_name': supplier.supplier_name, - 'supplier_type': supplier.supplier_type, + 'supplier_group': supplier.supplier_group, 'supplier_email': supplier.supplier_email }).insert() else: diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 3fffade9bb5..70f4ecd71e1 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -527,3 +527,7 @@ erpnext.patches.v11_0.rename_field_max_days_allowed erpnext.patches.v11_0.create_salary_structure_assignments erpnext.patches.v11_0.rename_health_insurance erpnext.patches.v11_0.rebuild_tree_for_company +erpnext.patches.v11_0.rename_supplier_type_to_supplier_group +erpnext.patches.v11_0.create_department_records_for_each_company +erpnext.patches.v11_0.make_location_from_warehouse +erpnext.patches.v11_0.make_asset_finance_book_against_old_entries diff --git a/erpnext/patches/v11_0/create_department_records_for_each_company.py b/erpnext/patches/v11_0/create_department_records_for_each_company.py new file mode 100644 index 00000000000..94071857d79 --- /dev/null +++ b/erpnext/patches/v11_0/create_department_records_for_each_company.py @@ -0,0 +1,73 @@ +import frappe +from frappe.utils.nestedset import rebuild_tree + +def execute(): + frappe.reload_doc("hr", "doctype", "department") + companies = frappe.db.get_all("Company", fields=["name", "abbr"]) + departments = frappe.db.get_all("Department") + comp_dict = {} + + # create a blank list for each company + for company in companies: + comp_dict[company.name] = {} + + for department in departments: + # skip root node + if department.name == "All Departments": + continue + + # for each company, create a copy of the doc + department_doc = frappe.get_doc("Department", department) + for company in companies: + copy_doc = frappe.copy_doc(department_doc) + copy_doc.update({"company": company.name}) + copy_doc.insert() + + # append list of new department for each company + comp_dict[company.name][department.name] = copy_doc.name + + rebuild_tree('Department', 'parent_department') + doctypes = ["Asset", "Employee", "Leave Period", "Payroll Entry", "Staffing Plan", "Job Opening"] + + for d in doctypes: + update_records(d, comp_dict) + + update_instructors(comp_dict) + +def update_records(doctype, comp_dict): + when_then = [] + for company in comp_dict: + records = comp_dict[company] + + for department in records: + when_then.append(''' + WHEN company = "%s" and department = "%s" + THEN "%s" + '''%(company, department, records[department])) + + frappe.db.sql(""" + update + `tab%s` + set + department = CASE %s END + """%(doctype, " ".join(when_then))) + +def update_instructors(comp_dict): + when_then = [] + emp_details = frappe.get_all("Employee", fields=["name", "company"]) + + for employee in emp_details: + records = comp_dict[employee.company] + + for department in records: + when_then.append(''' + WHEN employee = "%s" and department = "%s" + THEN "%s" + '''%(employee.name, department, records[department])) + + frappe.db.sql(""" + update + `tabInstructor` + set + department = CASE %s END + """%(" ".join(when_then))) diff --git a/erpnext/patches/v11_0/make_asset_finance_book_against_old_entries.py b/erpnext/patches/v11_0/make_asset_finance_book_against_old_entries.py new file mode 100644 index 00000000000..18622f23011 --- /dev/null +++ b/erpnext/patches/v11_0/make_asset_finance_book_against_old_entries.py @@ -0,0 +1,47 @@ +# Copyright (c) 2017, Frappe and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe +from frappe.utils.nestedset import rebuild_tree + +def execute(): + frappe.reload_doc('assets', 'doctype', 'asset_finance_book') + frappe.reload_doc('assets', 'doctype', 'depreciation_schedule') + frappe.reload_doc('assets', 'doctype', 'asset_category') + frappe.reload_doc('assets', 'doctype', 'asset') + frappe.reload_doc('assets', 'doctype', 'asset_movement') + + frappe.db.sql(""" update `tabAsset` ast, `tabWarehouse` wh + set ast.location = wh.warehouse_name where ast.warehouse = wh.name""") + + frappe.db.sql(""" update `tabAsset Movement` ast_mv + set ast_mv.source_location = (select warehouse_name from `tabWarehouse` where name = ast_mv.source_warehouse), + ast_mv.target_location = (select warehouse_name from `tabWarehouse` where name = ast_mv.target_warehouse)""") + + for d in frappe.get_all('Asset'): + doc = frappe.get_doc('Asset', d.name) + if doc.calculate_depreciation: + fb = doc.append('finance_books', { + 'depreciation_method': doc.depreciation_method, + 'total_number_of_depreciations': doc.total_number_of_depreciations, + 'frequency_of_depreciation': doc.frequency_of_depreciation, + 'depreciation_start_date': doc.next_depreciation_date, + 'expected_value_after_useful_life': doc.expected_value_after_useful_life, + 'value_after_depreciation': doc.value_after_depreciation + }) + + fb.db_update() + + frappe.db.sql(""" update `tabDepreciation Schedule` ds, `tabAsset` ast + set ds.depreciation_method = ast.depreciation_method, ds.finance_book_id = 1 where ds.parent = ast.name """) + + for catergory in frappe.get_all('Asset Category'): + asset_category_doc = frappe.get_doc("Asset Category", catergory) + row = asset_category_doc.append('finance_books', { + 'depreciation_method': asset_category_doc.depreciation_method, + 'total_number_of_depreciations': asset_category_doc.total_number_of_depreciations, + 'frequency_of_depreciation': asset_category_doc.frequency_of_depreciation + }) + + row.db_update() \ No newline at end of file diff --git a/erpnext/patches/v11_0/make_location_from_warehouse.py b/erpnext/patches/v11_0/make_location_from_warehouse.py new file mode 100644 index 00000000000..b838ec98bc5 --- /dev/null +++ b/erpnext/patches/v11_0/make_location_from_warehouse.py @@ -0,0 +1,30 @@ +# Copyright (c) 2017, Frappe and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe +from frappe.utils.nestedset import rebuild_tree + +def execute(): + frappe.reload_doc('assets', 'doctype', 'location') + frappe.reload_doc('stock', 'doctype', 'warehouse') + + for d in frappe.get_all('Warehouse', + fields = ['warehouse_name', 'is_group', 'parent_warehouse'], order_by="is_group desc"): + try: + loc = frappe.new_doc('Location') + loc.location_name = d.warehouse_name + loc.is_group = d.is_group + loc.flags.ignore_mandatory = True + if d.parent_warehouse: + loc.parent_location = get_parent_warehouse_name(d.parent_warehouse) + + loc.save(ignore_permissions=True) + except frappe.DuplicateEntryError: + continue + + rebuild_tree("Location", "parent_location") + +def get_parent_warehouse_name(warehouse): + return frappe.db.get_value('Warehouse', warehouse, 'warehouse_name') + \ No newline at end of file diff --git a/erpnext/patches/v11_0/rename_supplier_type_to_supplier_group.py b/erpnext/patches/v11_0/rename_supplier_type_to_supplier_group.py new file mode 100644 index 00000000000..f0907af333e --- /dev/null +++ b/erpnext/patches/v11_0/rename_supplier_type_to_supplier_group.py @@ -0,0 +1,34 @@ +import frappe +from frappe.model.rename_doc import rename_doc +from frappe.model.utils.rename_field import rename_field +from frappe import _ +from frappe.utils.nestedset import rebuild_tree + +def execute(): + if frappe.db.table_exists("Supplier Type") and not frappe.db.table_exists("Supplier Group"): + rename_doc("DocType", "Supplier Type", "Supplier Group", force=True) + frappe.reload_doc('setup', 'doctype', 'supplier_group') + frappe.reload_doc("accounts", "doctype", "pricing_rule") + frappe.reload_doc("accounts", "doctype", "tax_rule") + frappe.reload_doc("buying", "doctype", "buying_settings") + frappe.reload_doc("buying", "doctype", "supplier") + rename_field("Supplier Group", "supplier_type", "supplier_group_name") + rename_field("Supplier", "supplier_type", "supplier_group") + rename_field("Buying Settings", "supplier_type", "supplier_group") + rename_field("Pricing Rule", "supplier_type", "supplier_group") + rename_field("Tax Rule", "supplier_type", "supplier_group") + + build_tree() + +def build_tree(): + frappe.db.sql("""update `tabSupplier Group` set parent_supplier_group = '{0}' + where is_group = 0""".format(_('All Supplier Groups'))) + + if not frappe.db.exists("Supplier Group", _('All Supplier Groups')): + frappe.get_doc({ + 'doctype': 'Supplier Group', + 'supplier_group_name': _('All Supplier Groups'), + 'is_group': 1 + }).insert(ignore_permissions=True) + + rebuild_tree("Supplier Group", "parent_supplier_group") diff --git a/erpnext/projects/doctype/project/project.json b/erpnext/projects/doctype/project/project.json index 43cee681c6d..184656bbd0f 100644 --- a/erpnext/projects/doctype/project/project.json +++ b/erpnext/projects/doctype/project/project.json @@ -178,6 +178,36 @@ "translatable": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 1, + "collapsible": 0, + "columns": 0, + "fieldname": "percent_complete", + "fieldtype": "Percent", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "% Completed", + "length": 0, + "no_copy": 1, + "permlevel": 0, + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_on_submit": 0, @@ -208,6 +238,38 @@ "translatable": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "department", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Department", + "length": 0, + "no_copy": 0, + "options": "Department", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_on_submit": 0, @@ -305,36 +367,6 @@ "translatable": 0, "unique": 0 }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 1, - "collapsible": 0, - "columns": 0, - "fieldname": "percent_complete", - "fieldtype": "Percent", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "% Completed", - "length": 0, - "no_copy": 1, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, { "allow_bulk_edit": 0, "allow_on_submit": 0, @@ -1709,7 +1741,7 @@ "issingle": 0, "istable": 0, "max_attachments": 4, - "modified": "2018-03-28 10:19:32.743900", + "modified": "2018-05-10 04:21:25.764015", "modified_by": "Administrator", "module": "Projects", "name": "Project", @@ -1717,7 +1749,6 @@ "permissions": [ { "amend": 0, - "apply_user_permissions": 0, "cancel": 0, "create": 1, "delete": 1, @@ -1737,7 +1768,6 @@ }, { "amend": 0, - "apply_user_permissions": 0, "cancel": 0, "create": 0, "delete": 0, @@ -1757,7 +1787,6 @@ }, { "amend": 0, - "apply_user_permissions": 0, "cancel": 0, "create": 1, "delete": 1, diff --git a/erpnext/projects/doctype/task/task.json b/erpnext/projects/doctype/task/task.json index 8e72d0339e7..c1b7aa1c609 100644 --- a/erpnext/projects/doctype/task/task.json +++ b/erpnext/projects/doctype/task/task.json @@ -40,6 +40,7 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -72,6 +73,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -103,6 +105,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -133,6 +136,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0, "width": "50%" }, @@ -166,6 +170,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -198,6 +203,7 @@ "reqd": 0, "search_index": 1, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -229,6 +235,7 @@ "reqd": 0, "search_index": 1, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -260,6 +267,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -292,6 +300,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -326,6 +335,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -357,6 +367,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -386,6 +397,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -418,6 +430,7 @@ "reqd": 0, "search_index": 1, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -449,6 +462,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -480,6 +494,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -512,6 +527,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -545,6 +561,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0, "width": "300px" }, @@ -578,6 +595,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -610,6 +628,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -641,6 +660,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -675,6 +695,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0, "width": "50%" }, @@ -708,6 +729,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -742,6 +764,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -771,6 +794,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -803,6 +827,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -833,6 +858,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -866,6 +892,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -898,6 +925,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -927,6 +955,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -958,6 +987,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -987,6 +1017,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -1019,6 +1050,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -1051,6 +1083,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -1079,6 +1112,39 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "department", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Department", + "length": 0, + "no_copy": 0, + "options": "Department", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -1109,6 +1175,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -1139,6 +1206,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -1169,6 +1237,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -1199,6 +1268,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 } ], @@ -1214,7 +1284,7 @@ "istable": 0, "max_attachments": 5, "menu_index": 0, - "modified": "2017-11-10 18:37:19.660293", + "modified": "2018-05-10 03:47:12.256088", "modified_by": "Administrator", "module": "Projects", "name": "Task", @@ -1222,7 +1292,6 @@ "permissions": [ { "amend": 0, - "apply_user_permissions": 0, "cancel": 0, "create": 1, "delete": 1, diff --git a/erpnext/projects/doctype/timesheet/test_timesheet.py b/erpnext/projects/doctype/timesheet/test_timesheet.py index 2458db0cba1..d2017c5712c 100644 --- a/erpnext/projects/doctype/timesheet/test_timesheet.py +++ b/erpnext/projects/doctype/timesheet/test_timesheet.py @@ -118,30 +118,21 @@ class TestTimesheet(unittest.TestCase): def make_salary_structure(employee): - name = frappe.db.get_value('Salary Structure Employee', {'employee': employee}, 'parent') + name = frappe.db.get_value('Salary Structure Assignment', {'employee': employee}, 'salary_structure') if name: salary_structure = frappe.get_doc('Salary Structure', name) else: salary_structure = frappe.new_doc("Salary Structure") salary_structure.name = "Timesheet Salary Structure Test" salary_structure.salary_slip_based_on_timesheet = 1 - salary_structure.from_date = add_days(nowdate(), -30) salary_structure.salary_component = "Basic" salary_structure.hour_rate = 50.0 salary_structure.company = "_Test Company" salary_structure.payment_account = get_random("Account") - salary_structure.set('employees', []) salary_structure.set('earnings', []) salary_structure.set('deductions', []) - es = salary_structure.append('employees', { - "employee": employee, - "base": 1200, - "from_date": add_months(nowdate(),-1) - }) - - es = salary_structure.append('earnings', { "salary_component": "_Test Allowance", "amount": 100 @@ -154,6 +145,14 @@ def make_salary_structure(employee): salary_structure.save(ignore_permissions=True) + salary_structure_assignment = frappe.new_doc("Salary Structure Assignment") + salary_structure_assignment.employee = employee + salary_structure_assignment.base = 1200 + salary_structure_assignment.from_date = add_months(nowdate(), -1) + salary_structure_assignment.salary_structure = salary_structure.name + salary_structure_assignment.company = "_Test Company" + salary_structure_assignment.save(ignore_permissions=True) + return salary_structure def make_timesheet(employee, simulate=False, billable = 0, activity_type="_Test Activity Type", project=None, task=None, company=None): diff --git a/erpnext/public/js/conf.js b/erpnext/public/js/conf.js index d256c08e13e..08f8d43e508 100644 --- a/erpnext/public/js/conf.js +++ b/erpnext/public/js/conf.js @@ -49,7 +49,7 @@ $.extend(frappe.create_routes, { $.extend(frappe.breadcrumbs.preferred, { "Item Group": "Stock", "Customer Group": "Selling", - "Supplier Type": "Buying", + "Supplier Group": "Buying", "Territory": "Selling", "Sales Person": "Selling", "Sales Partner": "Selling", diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js index 1551b1dfc30..eb4a7001f3f 100644 --- a/erpnext/public/js/controllers/transaction.js +++ b/erpnext/public/js/controllers/transaction.js @@ -980,7 +980,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ "customer_group": me.frm.doc.customer_group, "territory": me.frm.doc.territory, "supplier": me.frm.doc.supplier, - "supplier_type": me.frm.doc.supplier_type, + "supplier_group": me.frm.doc.supplier_group, "currency": me.frm.doc.currency, "conversion_rate": me.frm.doc.conversion_rate, "price_list": me.frm.doc.selling_price_list || me.frm.doc.buying_price_list, diff --git a/erpnext/public/js/hub/hub_form.js b/erpnext/public/js/hub/hub_form.js index 62c44fcb333..4a8c4eb3ec1 100644 --- a/erpnext/public/js/hub/hub_form.js +++ b/erpnext/public/js/hub/hub_form.js @@ -444,8 +444,8 @@ erpnext.hub.ItemPage = class ItemPage extends erpnext.hub.HubDetailsPage { { label: __('Supplier Name'), fieldtype: 'Data', fieldname: 'supplier_name', default: item.company_name }, { label: __('Supplier Email'), fieldtype: 'Data', fieldname: 'supplier_email', default: item.seller }, { fieldtype: 'Column Break' }, - { label: __('Supplier Type'), fieldname: 'supplier_type', - fieldtype: 'Link', options: 'Supplier Type' } + { label: __('Supplier Group'), fieldname: 'supplier_group', + fieldtype: 'Link', options: 'Supplier Group' } ]; fields = fields.map(f => { f.reqd = 1; return f; }); diff --git a/erpnext/public/js/purchase_trends_filters.js b/erpnext/public/js/purchase_trends_filters.js index 117d4eb08cd..595a138f12d 100644 --- a/erpnext/public/js/purchase_trends_filters.js +++ b/erpnext/public/js/purchase_trends_filters.js @@ -23,7 +23,7 @@ erpnext.get_purchase_trends_filters = function() { { "value": "Item", "label": __("Item") }, { "value": "Item Group", "label": __("Item Group") }, { "value": "Supplier", "label": __("Supplier") }, - { "value": "Supplier Type", "label": __("Supplier Type") }, + { "value": "Supplier Group", "label": __("Supplier Group") }, { "value": "Project", "label": __("Project") } ], "default": "Item" diff --git a/erpnext/regional/india/setup.py b/erpnext/regional/india/setup.py index 0073d3311c2..70960d714bd 100644 --- a/erpnext/regional/india/setup.py +++ b/erpnext/regional/india/setup.py @@ -16,7 +16,7 @@ def setup(company=None, patch=True): add_print_formats() if not patch: update_address_template() - make_fixtures() + make_fixtures(company) def update_address_template(): with open(os.path.join(os.path.dirname(__file__), 'address_template.html'), 'r') as f: @@ -189,15 +189,13 @@ def make_custom_fields(): create_custom_fields(custom_fields, ignore_validate = frappe.flags.in_patch) -def make_fixtures(): - docs = [ - {'doctype': 'Salary Component', 'salary_component': 'Professional Tax', 'description': 'Professional Tax', 'type': 'Deduction'}, - {'doctype': 'Salary Component', 'salary_component': 'Provident Fund', 'description': 'Provident fund', 'type': 'Deduction'}, - {'doctype': 'Salary Component', 'salary_component': 'House Rent Allowance', 'description': 'House Rent Allowance', 'type': 'Earning'}, - {'doctype': 'Salary Component', 'salary_component': 'Basic', 'description': 'Basic', 'type': 'Earning'}, - {'doctype': 'Salary Component', 'salary_component': 'Arrear', 'description': 'Arrear', 'type': 'Earning'}, - {'doctype': 'Salary Component', 'salary_component': 'Leave Encashment', 'description': 'Leave Encashment', 'type': 'Earning'} - ] +def make_fixtures(company=None): + docs = [] + company = company.name if company else frappe.db.get_value("Global Defaults", None, "default_company") + + set_salary_components(docs) + set_tds_account(docs, company) + set_tax_withholding_category(docs, company) for d in docs: try: @@ -206,3 +204,43 @@ def make_fixtures(): doc.insert() except frappe.NameError: pass + +def set_salary_components(docs): + docs.extend([ + {'doctype': 'Salary Component', 'salary_component': 'Professional Tax', 'description': 'Professional Tax', 'type': 'Deduction'}, + {'doctype': 'Salary Component', 'salary_component': 'Provident Fund', 'description': 'Provident fund', 'type': 'Deduction'}, + {'doctype': 'Salary Component', 'salary_component': 'House Rent Allowance', 'description': 'House Rent Allowance', 'type': 'Earning'}, + {'doctype': 'Salary Component', 'salary_component': 'Basic', 'description': 'Basic', 'type': 'Earning'}, + {'doctype': 'Salary Component', 'salary_component': 'Arrear', 'description': 'Arrear', 'type': 'Earning'}, + {'doctype': 'Salary Component', 'salary_component': 'Leave Encashment', 'description': 'Leave Encashment', 'type': 'Earning'} + ]) + +def set_tax_withholding_category(docs, company): + accounts = [] + tds_account = frappe.db.get_value("Account", filter={"account_type": "Payable", + "account_name": "TDS", "company": company}) + + if company and tds_account: + accounts = [ + { + 'company': company, + 'account': tds_account + } + ] + + docs.extend([ + { + 'doctype': 'Tax Withholding Category', '__newname': 'TDS', + 'percent_of_tax_withheld': 10,'threshold': 150000, 'book_on_invoice': 1, + 'book_on_advance': 0, "withhold_cumulative_tax_amount": 0, + 'accounts': accounts + } + ]) + +def set_tds_account(docs, company): + docs.extend([ + { + 'doctype': 'Account', 'account_name': 'TDS', 'account_type': 'Tax', + 'parent_account': 'Duties and Taxes', 'company': company + } + ]) \ No newline at end of file diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index 40c2cf0358d..72723eb115b 100755 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -755,9 +755,9 @@ def make_purchase_order_for_drop_shipment(source_name, for_supplier, target_doc= def get_supplier(doctype, txt, searchfield, start, page_len, filters): supp_master_name = frappe.defaults.get_user_default("supp_master_name") if supp_master_name == "Supplier Name": - fields = ["name", "supplier_type"] + fields = ["name", "supplier_group"] else: - fields = ["name", "supplier_name", "supplier_type"] + fields = ["name", "supplier_name", "supplier_group"] fields = ", ".join(fields) return frappe.db.sql("""select {field} from `tabSupplier` diff --git a/erpnext/setup/doctype/company/company.js b/erpnext/setup/doctype/company/company.js index e164d6949fa..5ca28855474 100644 --- a/erpnext/setup/doctype/company/company.js +++ b/erpnext/setup/doctype/company/company.js @@ -207,6 +207,9 @@ erpnext.company.setup_queries = function(frm) { ["round_off_cost_center", {}], ["depreciation_cost_center", {}], ["default_employee_advance_account", {"root_type": "Asset"}], + ["expenses_included_in_asset_valuation", {"account_type": "Expenses Included In Asset Valuation"}], + ["capital_work_in_progress_account", {"account_type": "Capital Work in Progress"}], + ["asset_received_but_not_billed", {"account_type": "Asset Received But Not Billed"}] ], function(i, v) { erpnext.company.set_custom_query(frm, v); }); diff --git a/erpnext/setup/doctype/company/company.json b/erpnext/setup/doctype/company/company.json index 66b1433eb11..07051eeba84 100644 --- a/erpnext/setup/doctype/company/company.json +++ b/erpnext/setup/doctype/company/company.json @@ -456,7 +456,38 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fieldname": "default_letter_head", + "fieldname": "default_currency", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 1, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Default Currency", + "length": 0, + "no_copy": 0, + "options": "Currency", + "permlevel": 0, + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "default_letter_head", "fieldtype": "Link", "hidden": 0, "ignore_user_permissions": 0, @@ -465,10 +496,10 @@ "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, - "label": "Default Letter Head", + "label": "Default Letter Head", "length": 0, "no_copy": 0, - "options": "Letter Head", + "options": "Letter Head", "permlevel": 0, "precision": "", "print_hide": 0, @@ -488,7 +519,7 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fieldname": "default_holiday_list", + "fieldname": "default_holiday_list", "fieldtype": "Link", "hidden": 0, "ignore_user_permissions": 0, @@ -497,12 +528,12 @@ "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, - "label": "Default Holiday List", + "label": "Default Holiday List", "length": 0, "no_copy": 0, - "options": "Holiday List", + "options": "Holiday List", "permlevel": 0, - "precision": "", + "precision": "", "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, @@ -520,57 +551,26 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fieldname": "default_terms", + "fieldname": "default_terms", "fieldtype": "Link", "hidden": 0, - "ignore_user_permissions": 0, + "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, - "label": "Default Terms", + "label": "Default Terms", "length": 0, "no_copy": 0, - "options": "Terms and Conditions", + "options": "Terms and Conditions", "permlevel": 0, "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, "remember_last_selected_value": 0, "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "default_currency", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Default Currency", - "length": 0, - "no_copy": 0, - "options": "Currency", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, + "reqd": 0, "search_index": 0, "set_only_once": 0, "translatable": 0, @@ -1785,6 +1785,38 @@ "translatable": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "expenses_included_in_asset_valuation", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Expenses Included In Asset Valuation", + "length": 0, + "no_copy": 0, + "options": "Account", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_on_submit": 0, @@ -1879,6 +1911,70 @@ "translatable": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "capital_work_in_progress_account", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Capital Work In Progress Account", + "length": 0, + "no_copy": 0, + "options": "Account", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "asset_received_but_not_billed", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Asset Received But Not Billed", + "length": 0, + "no_copy": 0, + "options": "Account", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_on_submit": 0, @@ -2400,7 +2496,7 @@ "istable": 0, "max_attachments": 0, "menu_index": 0, - "modified": "2018-05-05 13:08:07.351655", + "modified": "2018-05-07 15:35:06.736602", "modified_by": "Administrator", "module": "Setup", "name": "Company", diff --git a/erpnext/setup/doctype/company/company.py b/erpnext/setup/doctype/company/company.py index 1b68b8a6b6b..9040bb7c8f5 100644 --- a/erpnext/setup/doctype/company/company.py +++ b/erpnext/setup/doctype/company/company.py @@ -168,6 +168,9 @@ class Company(NestedSet): self._set_default_account("round_off_account", "Round Off") self._set_default_account("accumulated_depreciation_account", "Accumulated Depreciation") self._set_default_account("depreciation_expense_account", "Depreciation") + self._set_default_account("capital_work_in_progress_account", "Capital Work in Progress") + self._set_default_account("asset_received_but_not_billed", "Asset Received But Not Billed") + self._set_default_account("expenses_included_in_asset_valuation", "Expenses Included In Asset Valuation") if self.enable_perpetual_inventory: self._set_default_account("stock_received_but_not_billed", "Stock Received But Not Billed") diff --git a/erpnext/setup/doctype/supplier_type/__init__.py b/erpnext/setup/doctype/supplier_group/__init__.py similarity index 100% rename from erpnext/setup/doctype/supplier_type/__init__.py rename to erpnext/setup/doctype/supplier_group/__init__.py diff --git a/erpnext/setup/doctype/supplier_group/supplier_group.js b/erpnext/setup/doctype/supplier_group/supplier_group.js new file mode 100644 index 00000000000..ac5bda6e2c6 --- /dev/null +++ b/erpnext/setup/doctype/supplier_group/supplier_group.js @@ -0,0 +1,37 @@ +// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors +// For license information, please see license.txt + +cur_frm.cscript.refresh = function(doc) { + cur_frm.set_intro(doc.__islocal ? "" : __("There is nothing to edit.")); + cur_frm.cscript.set_root_readonly(doc); +}; + +cur_frm.cscript.set_root_readonly = function(doc) { + // read-only for root customer group + if(!doc.parent_supplier_group) { + cur_frm.set_read_only(); + cur_frm.set_intro(__("This is a root supplier group and cannot be edited.")); + } else { + cur_frm.set_intro(null); + } +}; + +// get query select Customer Group +cur_frm.fields_dict['parent_supplier_group'].get_query = function() { + return { + filters: { + 'is_group': 1 + } + }; +}; + +cur_frm.fields_dict['accounts'].grid.get_field('account').get_query = function(doc, cdt, cdn) { + var d = locals[cdt][cdn]; + return { + filters: { + 'account_type': 'Payable', + 'company': d.company, + "is_group": 0 + } + }; +}; diff --git a/erpnext/setup/doctype/supplier_type/supplier_type.json b/erpnext/setup/doctype/supplier_group/supplier_group.json similarity index 62% rename from erpnext/setup/doctype/supplier_type/supplier_type.json rename to erpnext/setup/doctype/supplier_group/supplier_group.json index d7d7084d7ff..dc8b2631f19 100644 --- a/erpnext/setup/doctype/supplier_type/supplier_type.json +++ b/erpnext/setup/doctype/supplier_group/supplier_group.json @@ -3,7 +3,7 @@ "allow_guest_to_view": 0, "allow_import": 1, "allow_rename": 1, - "autoname": "field:supplier_type", + "autoname": "field:supplier_group_name", "beta": 0, "creation": "2013-01-10 16:34:24", "custom": 0, @@ -18,16 +18,16 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fieldname": "supplier_type", + "fieldname": "supplier_group_name", "fieldtype": "Data", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, - "in_list_view": 1, + "in_list_view": 0, "in_standard_filter": 0, - "label": "Supplier Type", + "label": "Supplier Group Name", "length": 0, "no_copy": 0, "oldfieldname": "supplier_type", @@ -41,8 +41,72 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 1, + "collapsible": 0, + "columns": 0, + "fieldname": "parent_supplier_group", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 1, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Parent Supplier Group", + "length": 0, + "no_copy": 0, + "options": "Supplier Group", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 1, + "collapsible": 0, + "columns": 0, + "fieldname": "is_group", + "fieldtype": "Check", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Is Group", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_on_submit": 0, @@ -71,6 +135,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -102,6 +167,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -131,6 +197,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -163,6 +230,101 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "lft", + "fieldtype": "Int", + "hidden": 1, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "lft", + "length": 0, + "no_copy": 1, + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 1, + "reqd": 0, + "search_index": 1, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "rgt", + "fieldtype": "Int", + "hidden": 1, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "rgt", + "length": 0, + "no_copy": 1, + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 1, + "reqd": 0, + "search_index": 1, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "old_parent", + "fieldtype": "Link", + "hidden": 1, + "ignore_user_permissions": 1, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Old Parent", + "length": 0, + "no_copy": 1, + "options": "Supplier Group", + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 1, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 } ], @@ -177,15 +339,14 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2017-09-04 18:54:10.093500", + "modified": "2018-04-20 00:54:48.724120", "modified_by": "Administrator", "module": "Setup", - "name": "Supplier Type", + "name": "Supplier Group", "owner": "Administrator", "permissions": [ { "amend": 0, - "apply_user_permissions": 0, "cancel": 0, "create": 0, "delete": 0, @@ -205,7 +366,6 @@ }, { "amend": 0, - "apply_user_permissions": 0, "cancel": 0, "create": 0, "delete": 0, @@ -225,7 +385,6 @@ }, { "amend": 0, - "apply_user_permissions": 0, "cancel": 0, "create": 1, "delete": 1, @@ -245,7 +404,6 @@ }, { "amend": 0, - "apply_user_permissions": 0, "cancel": 0, "create": 0, "delete": 0, @@ -265,7 +423,6 @@ }, { "amend": 0, - "apply_user_permissions": 0, "cancel": 0, "create": 0, "delete": 0, @@ -285,7 +442,6 @@ }, { "amend": 0, - "apply_user_permissions": 0, "cancel": 0, "create": 0, "delete": 0, diff --git a/erpnext/setup/doctype/supplier_group/supplier_group.py b/erpnext/setup/doctype/supplier_group/supplier_group.py new file mode 100644 index 00000000000..747560a5339 --- /dev/null +++ b/erpnext/setup/doctype/supplier_group/supplier_group.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +from __future__ import unicode_literals +import frappe +from frappe.utils.nestedset import NestedSet + +class SupplierGroup(NestedSet): + nsm_parent_field = 'parent_supplier_group'; + + def update_nsm_model(self): + frappe.utils.nestedset.update_nsm(self) + + def on_update(self): + self.update_nsm_model() + self.validate_one_root() + + def on_trash(self): + self.update_nsm_model() diff --git a/erpnext/setup/doctype/supplier_group/supplier_group_tree.js b/erpnext/setup/doctype/supplier_group/supplier_group_tree.js new file mode 100644 index 00000000000..73926992e8f --- /dev/null +++ b/erpnext/setup/doctype/supplier_group/supplier_group_tree.js @@ -0,0 +1,3 @@ +frappe.treeview_settings["Supplier Group"] = { + ignore_fields:["parent_supplier_group"] +}; \ No newline at end of file diff --git a/erpnext/setup/doctype/supplier_group/test_records.json b/erpnext/setup/doctype/supplier_group/test_records.json new file mode 100644 index 00000000000..1681e2a6478 --- /dev/null +++ b/erpnext/setup/doctype/supplier_group/test_records.json @@ -0,0 +1,7 @@ +[ + { + "doctype": "Supplier Group", + "supplier_group_name": "_Test Supplier Group" + } +] + \ No newline at end of file diff --git a/erpnext/setup/doctype/supplier_group/test_supplier_group.js b/erpnext/setup/doctype/supplier_group/test_supplier_group.js new file mode 100644 index 00000000000..976dd2cc4f3 --- /dev/null +++ b/erpnext/setup/doctype/supplier_group/test_supplier_group.js @@ -0,0 +1,23 @@ +/* eslint-disable */ +// rename this file from _test_[name] to test_[name] to activate +// and remove above this line + +QUnit.test("test: Supplier Group", function (assert) { + let done = assert.async(); + + // number of asserts + assert.expect(1); + + frappe.run_serially([ + // insert a new Supplier Group + () => frappe.tests.make('Supplier Group', [ + // values to be set + {key: 'value'} + ]), + () => { + assert.equal(cur_frm.doc.key, 'value'); + }, + () => done() + ]); + +}); diff --git a/erpnext/setup/doctype/supplier_group/test_supplier_group.py b/erpnext/setup/doctype/supplier_group/test_supplier_group.py new file mode 100644 index 00000000000..0e3d23d6bd3 --- /dev/null +++ b/erpnext/setup/doctype/supplier_group/test_supplier_group.py @@ -0,0 +1,7 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors +# See license.txt +from __future__ import unicode_literals + +import frappe +test_records = frappe.get_test_records('Supplier Group') diff --git a/erpnext/setup/doctype/supplier_type/README.md b/erpnext/setup/doctype/supplier_type/README.md deleted file mode 100644 index 0da4c708ac7..00000000000 --- a/erpnext/setup/doctype/supplier_type/README.md +++ /dev/null @@ -1 +0,0 @@ -Supplier classification. \ No newline at end of file diff --git a/erpnext/setup/doctype/supplier_type/supplier_type.js b/erpnext/setup/doctype/supplier_type/supplier_type.js deleted file mode 100644 index f1c5d70640d..00000000000 --- a/erpnext/setup/doctype/supplier_type/supplier_type.js +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -// License: GNU General Public License v3. See license.txt - -cur_frm.cscript.refresh = function(doc) { - cur_frm.set_intro(doc.__islocal ? "" : __("There is nothing to edit.")) -} - -cur_frm.fields_dict['accounts'].grid.get_field('account').get_query = function(doc, cdt, cdn) { - var d = locals[cdt][cdn]; - return { - filters: { - 'account_type': 'Payable', - 'company': d.company, - "is_group": 0 - } - } -} diff --git a/erpnext/setup/doctype/supplier_type/supplier_type.py b/erpnext/setup/doctype/supplier_type/supplier_type.py deleted file mode 100644 index 0d237469e37..00000000000 --- a/erpnext/setup/doctype/supplier_type/supplier_type.py +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import frappe - -from frappe.model.document import Document - -class SupplierType(Document): - pass \ No newline at end of file diff --git a/erpnext/setup/doctype/supplier_type/test_records.json b/erpnext/setup/doctype/supplier_type/test_records.json deleted file mode 100644 index fd632c5afde..00000000000 --- a/erpnext/setup/doctype/supplier_type/test_records.json +++ /dev/null @@ -1,6 +0,0 @@ -[ - { - "doctype": "Supplier Type", - "supplier_type": "_Test Supplier Type" - } -] diff --git a/erpnext/setup/doctype/supplier_type/test_supplier_type.py b/erpnext/setup/doctype/supplier_type/test_supplier_type.py deleted file mode 100644 index 9fa8a44b1d8..00000000000 --- a/erpnext/setup/doctype/supplier_type/test_supplier_type.py +++ /dev/null @@ -1,7 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals - - -import frappe -test_records = frappe.get_test_records('Supplier Type') \ No newline at end of file diff --git a/erpnext/setup/setup_wizard/operations/install_fixtures.py b/erpnext/setup/setup_wizard/operations/install_fixtures.py index 8f761e59465..c686ed30803 100644 --- a/erpnext/setup/setup_wizard/operations/install_fixtures.py +++ b/erpnext/setup/setup_wizard/operations/install_fixtures.py @@ -147,14 +147,15 @@ def install(country=None): {'doctype': 'Customer Group', 'customer_group_name': _('Non Profit'), 'is_group': 0, 'parent_customer_group': _('All Customer Groups')}, {'doctype': 'Customer Group', 'customer_group_name': _('Government'), 'is_group': 0, 'parent_customer_group': _('All Customer Groups')}, - # supplier type - {'doctype': 'Supplier Type', 'supplier_type': _('Services')}, - {'doctype': 'Supplier Type', 'supplier_type': _('Local')}, - {'doctype': 'Supplier Type', 'supplier_type': _('Raw Material')}, - {'doctype': 'Supplier Type', 'supplier_type': _('Electrical')}, - {'doctype': 'Supplier Type', 'supplier_type': _('Hardware')}, - {'doctype': 'Supplier Type', 'supplier_type': _('Pharmaceutical')}, - {'doctype': 'Supplier Type', 'supplier_type': _('Distributor')}, + # supplier group + {'doctype': 'Supplier Group', 'supplier_group_name': _('All Supplier Groups'), 'is_group': 1, 'name': _('All Supplier Groups'), 'parent_supplier_group': ''}, + {'doctype': 'Supplier Group', 'supplier_group_name': _('Services'), 'is_group': 0, 'parent_supplier_group': _('All Supplier Groups')}, + {'doctype': 'Supplier Group', 'supplier_group_name': _('Local'), 'is_group': 0, 'parent_supplier_group': _('All Supplier Groups')}, + {'doctype': 'Supplier Group', 'supplier_group_name': _('Raw Material'), 'is_group': 0, 'parent_supplier_group': _('All Supplier Groups')}, + {'doctype': 'Supplier Group', 'supplier_group_name': _('Electrical'), 'is_group': 0, 'parent_supplier_group': _('All Supplier Groups')}, + {'doctype': 'Supplier Group', 'supplier_group_name': _('Hardware'), 'is_group': 0, 'parent_supplier_group': _('All Supplier Groups')}, + {'doctype': 'Supplier Group', 'supplier_group_name': _('Pharmaceutical'), 'is_group': 0, 'parent_supplier_group': _('All Supplier Groups')}, + {'doctype': 'Supplier Group', 'supplier_group_name': _('Distributor'), 'is_group': 0, 'parent_supplier_group': _('All Supplier Groups')}, # Sales Person {'doctype': 'Sales Person', 'sales_person_name': _('Sales Team'), 'is_group': 1, "parent_sales_person": ""}, diff --git a/erpnext/startup/report_data_map.py b/erpnext/startup/report_data_map.py index daf6fdd3bd5..5de7998c7d4 100644 --- a/erpnext/startup/report_data_map.py +++ b/erpnext/startup/report_data_map.py @@ -208,15 +208,15 @@ data_map = { }, "Supplier": { "columns": ["name", "if(supplier_name=name, '', supplier_name) as supplier_name", - "supplier_type as parent_supplier_type"], + "supplier_group as parent_supplier_group"], "conditions": ["docstatus < 2"], "order_by": "name", "links": { - "parent_supplier_type": ["Supplier Type", "name"], + "parent_supplier_group": ["Supplier Group", "name"], } }, - "Supplier Type": { - "columns": ["name"], + "Supplier Group": { + "columns": ["name", "parent_supplier_group"], "conditions": ["docstatus < 2"], "order_by": "name" }, diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.js b/erpnext/stock/doctype/delivery_note/delivery_note.js index e6029aa4eaf..7ee0c5c2d02 100644 --- a/erpnext/stock/doctype/delivery_note/delivery_note.js +++ b/erpnext/stock/doctype/delivery_note/delivery_note.js @@ -34,7 +34,7 @@ frappe.ui.form.on("Delivery Note", { frm.set_query('transporter_name', function(doc) { return { - filters: { 'supplier_type': "transporter" } + filters: { 'supplier_group': "transporter" } } }); diff --git a/erpnext/stock/doctype/item/item.js b/erpnext/stock/doctype/item/item.js index f98cbb62683..fbf0deddc72 100644 --- a/erpnext/stock/doctype/item/item.js +++ b/erpnext/stock/doctype/item/item.js @@ -19,7 +19,9 @@ frappe.ui.form.on("Item", { // should never check Private frm.fields_dict["website_image"].df.is_private = 0; - + if (frm.doc.is_fixed_asset) { + frm.trigger("set_asset_naming_series"); + } }, refresh: function(frm) { @@ -124,7 +126,20 @@ frappe.ui.form.on("Item", { }, is_fixed_asset: function(frm) { - frm.set_value("is_stock_item", frm.doc.is_fixed_asset ? 0 : 1); + frm.call({ + method: "set_asset_naming_series", + doc: frm.doc, + callback: function() { + frm.set_value("is_stock_item", frm.doc.is_fixed_asset ? 0 : 1); + frm.trigger("set_asset_naming_series"); + } + }) + }, + + set_asset_naming_series: function(frm) { + if (frm.doc.__onload && frm.doc.__onload.asset_naming_series) { + frm.set_df_property("asset_naming_series", "options", frm.doc.__onload.asset_naming_series); + } }, page_name: frappe.utils.warn_page_name_change, diff --git a/erpnext/stock/doctype/item/item.json b/erpnext/stock/doctype/item/item.json index 21900ad4403..b8621719c47 100644 --- a/erpnext/stock/doctype/item/item.json +++ b/erpnext/stock/doctype/item/item.json @@ -395,7 +395,7 @@ "search_index": 0, "set_only_once": 0, "translatable": 0, - "unique": 0 + "unique": 0 }, { "allow_bulk_edit": 0, @@ -559,6 +559,38 @@ "translatable": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "is_fixed_asset", + "fieldname": "asset_naming_series", + "fieldtype": "Select", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Asset Naming Series", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_on_submit": 0, @@ -1285,7 +1317,7 @@ "collapsible": 1, "collapsible_depends_on": "eval:doc.has_batch_no || doc.has_serial_no", "columns": 0, - "depends_on": "is_stock_item", + "depends_on": "eval:doc.is_stock_item || doc.is_fixed_asset", "fieldname": "serial_nos_and_batches", "fieldtype": "Section Break", "hidden": 0, @@ -1513,7 +1545,7 @@ "collapsible": 0, "columns": 0, "default": "", - "depends_on": "eval:doc.is_stock_item", + "depends_on": "eval:doc.is_stock_item || doc.is_fixed_asset", "description": "", "fieldname": "has_serial_no", "fieldtype": "Check", @@ -3717,7 +3749,7 @@ "issingle": 0, "istable": 0, "max_attachments": 1, - "modified": "2018-04-30 12:21:48.715529", + "modified": "2018-05-07 14:54:24.479267", "modified_by": "Administrator", "module": "Stock", "name": "Item", @@ -3725,7 +3757,6 @@ "permissions": [ { "amend": 0, - "apply_user_permissions": 0, "cancel": 0, "create": 1, "delete": 1, @@ -3745,7 +3776,6 @@ }, { "amend": 0, - "apply_user_permissions": 0, "cancel": 0, "create": 0, "delete": 0, @@ -3765,7 +3795,6 @@ }, { "amend": 0, - "apply_user_permissions": 0, "cancel": 0, "create": 0, "delete": 0, @@ -3785,7 +3814,6 @@ }, { "amend": 0, - "apply_user_permissions": 0, "cancel": 0, "create": 0, "delete": 0, @@ -3805,7 +3833,6 @@ }, { "amend": 0, - "apply_user_permissions": 0, "cancel": 0, "create": 0, "delete": 0, @@ -3825,7 +3852,6 @@ }, { "amend": 0, - "apply_user_permissions": 0, "cancel": 0, "create": 0, "delete": 0, @@ -3845,7 +3871,6 @@ }, { "amend": 0, - "apply_user_permissions": 0, "cancel": 0, "create": 0, "delete": 0, @@ -3865,7 +3890,6 @@ }, { "amend": 0, - "apply_user_permissions": 0, "cancel": 0, "create": 0, "delete": 0, diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py index 123e73f652d..94b907b914b 100644 --- a/erpnext/stock/doctype/item/item.py +++ b/erpnext/stock/doctype/item/item.py @@ -16,6 +16,7 @@ from frappe.utils import (cint, cstr, flt, formatdate, get_timestamp, getdate, from frappe.utils.html_utils import clean_html from frappe.website.doctype.website_slideshow.website_slideshow import \ get_slideshow + from frappe.website.render import clear_cache from frappe.website.website_generator import WebsiteGenerator @@ -42,10 +43,18 @@ class Item(WebsiteGenerator): super(Item, self).onload() self.set_onload('stock_exists', self.stock_ledger_created()) + self.set_asset_naming_series() if self.is_fixed_asset: asset = frappe.db.get_all("Asset", filters={"item_code": self.name, "docstatus": 1}, limit=1) self.set_onload("asset_exists", True if asset else False) + def set_asset_naming_series(self): + if not hasattr(self, '_asset_naming_series'): + from erpnext.assets.doctype.asset.asset import get_asset_naming_series + self._asset_naming_series = get_asset_naming_series() + + self.set_onload('asset_naming_series', self._asset_naming_series) + def autoname(self): if frappe.db.get_default("item_naming_by") == "Naming Series": if self.variant_of: @@ -444,7 +453,7 @@ class Item(WebsiteGenerator): _("Conversion factor for default Unit of Measure must be 1 in row {0}").format(d.idx)) def validate_item_type(self): - if self.has_serial_no == 1 and self.is_stock_item == 0: + if self.has_serial_no == 1 and self.is_stock_item == 0 and not self.is_fixed_asset: msgprint(_("'Has Serial No' can not be 'Yes' for non-stock item"), raise_exception=1) if self.has_serial_no == 0 and self.serial_no_series: diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js index 791b2532f70..69d2f2a3d78 100644 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js @@ -65,6 +65,20 @@ erpnext.stock.PurchaseReceiptController = erpnext.buying.BuyingController.extend if (erpnext.is_perpetual_inventory_enabled(this.frm.doc.company)) { this.show_general_ledger(); } + + this.frm.add_custom_button(__('Asset'), function() { + frappe.route_options = { + purchase_receipt: me.frm.doc.name, + }; + frappe.set_route("List", "Asset"); + }, __("View")); + + this.frm.add_custom_button(__('Asset Movement'), function() { + frappe.route_options = { + reference_name: me.frm.doc.name, + }; + frappe.set_route("List", "Asset Movement"); + }, __("View")); } if(!this.frm.doc.is_return && this.frm.doc.status!="Closed") { diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py index 46eee31e901..573f7ed8f35 100644 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py @@ -13,6 +13,7 @@ from erpnext.controllers.buying_controller import BuyingController from erpnext.accounts.utils import get_account_currency from frappe.desk.notifications import clear_doctype_notifications from erpnext.buying.utils import check_for_closed_status +from erpnext.assets.doctype.asset_category.asset_category import get_asset_category_account form_grid_templates = { "items": "templates/form_grid/item_grid.html" @@ -253,6 +254,40 @@ class PurchaseReceipt(BuyingController): d.rejected_warehouse not in warehouse_with_no_account: warehouse_with_no_account.append(d.warehouse) + elif d.is_fixed_asset: + asset_accounts = self.get_company_default(["capital_work_in_progress_account", + "asset_received_but_not_billed"]) + + # CWIP entry + cwip_account = get_asset_category_account(d.asset, + 'capital_work_in_progress_account') or asset_accounts[0] + + asset_amount = flt(d.net_amount) + flt(d.item_tax_amount/self.conversion_rate) + base_asset_amount = flt(d.base_net_amount + d.item_tax_amount) + + cwip_account_currency = get_account_currency(cwip_account) + gl_entries.append(self.get_gl_dict({ + "account": cwip_account, + "against": asset_accounts[1], + "cost_center": d.cost_center, + "remarks": self.get("remarks") or _("Accounting Entry for Asset"), + "debit": base_asset_amount, + "debit_in_account_currency": (base_asset_amount + if cwip_account_currency == self.company_currency else asset_amount) + })) + + # Asset received but not billed + asset_rbnb_currency = get_account_currency(asset_accounts[1]) + gl_entries.append(self.get_gl_dict({ + "account": asset_accounts[1], + "against": asset_accounts[0], + "cost_center": d.cost_center, + "remarks": self.get("remarks") or _("Accounting Entry for Asset"), + "credit": base_asset_amount, + "credit_in_account_currency": (base_asset_amount + if asset_rbnb_currency == self.company_currency else asset_amount) + })) + # Cost center-wise amount breakup for other charges included for valuation valuation_tax = {} for tax in self.get("taxes"): @@ -393,6 +428,8 @@ def make_purchase_invoice(source_name, target_doc=None): "parent": "purchase_receipt", "purchase_order_item": "po_detail", "purchase_order": "purchase_order", + "is_fixed_asset": "is_fixed_asset", + "asset": "asset", }, "postprocess": update_item, "filter": lambda d: abs(d.qty) - abs(invoiced_qty_map.get(d.name, 0))<=0 diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt_dashboard.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt_dashboard.py index 9ade1afd8a0..bcedd7179a1 100644 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt_dashboard.py +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt_dashboard.py @@ -5,6 +5,7 @@ def get_data(): 'fieldname': 'purchase_receipt_no', 'non_standard_fieldnames': { 'Purchase Invoice': 'purchase_receipt', + 'Asset': 'purchase_receipt', 'Landed Cost Voucher': 'receipt_document', 'Subscription': 'reference_document' }, @@ -16,7 +17,7 @@ def get_data(): 'transactions': [ { 'label': _('Related'), - 'items': ['Purchase Invoice', 'Landed Cost Voucher'] + 'items': ['Purchase Invoice', 'Landed Cost Voucher', 'Asset'] }, { 'label': _('Reference'), diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py index d9f40cca90d..ffcc954df14 100644 --- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py @@ -289,13 +289,53 @@ class TestPurchaseReceipt(unittest.TestCase): serial_no=serial_no, basic_rate=100, do_not_submit=True) self.assertRaises(SerialNoDuplicateError, se.submit) + def test_serialized_asset_item(self): + asset_item = "Test Serialized Asset Item" + + if not frappe.db.exists('Item', asset_item): + asset_category = frappe.get_all('Asset Category') + + if asset_category: + asset_category = asset_category[0].name + + if not asset_category: + doc = frappe.get_doc({ + 'doctype': 'Asset Category', + 'asset_category_name': 'Test Asset Category', + 'depreciation_method': 'Straight Line', + 'total_number_of_depreciations': 12, + 'frequency_of_depreciation': 1, + 'accounts': [{ + 'company_name': '_Test Company', + 'fixed_asset_account': '_Test Fixed Asset - _TC', + 'accumulated_depreciation_account': 'Depreciation - _TC', + 'depreciation_expense_account': 'Depreciation - _TC' + }] + }).insert() + + asset_category = doc.name + + asset_item = make_item(asset_item, {'is_stock_item':0, + 'stock_uom': 'Box', 'is_fixed_asset': 1, 'has_serial_no': 1, + 'asset_category': asset_category, 'serial_no_series': 'ABC.###'}) + + pr = make_purchase_receipt(item_code=asset_item, qty=3) + asset = frappe.db.get_value('Asset', {'purchase_receipt': pr.name}, 'name') + asset_movement = frappe.db.get_value('Asset Movement', {'reference_name': pr.name}, 'name') + serial_nos = frappe.get_all('Serial No', {'asset': asset}, 'name') + + self.assertEquals(len(serial_nos), 3) + pr.cancel() + serial_nos = frappe.get_all('Serial No', {'asset': asset}, 'name') or [] + self.assertEquals(len(serial_nos), 0) + frappe.db.sql("delete from `tabAsset Category`") + frappe.db.sql("delete from `tabAsset`") def get_gl_entries(voucher_type, voucher_no): return frappe.db.sql("""select account, debit, credit from `tabGL Entry` where voucher_type=%s and voucher_no=%s order by account desc""", (voucher_type, voucher_no), as_dict=1) - def make_purchase_receipt(**args): frappe.db.set_value("Buying Settings", None, "allow_multiple_items", 1) pr = frappe.new_doc("Purchase Receipt") diff --git a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json index 754bd718790..87c9a757bf8 100755 --- a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json +++ b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json @@ -1577,6 +1577,103 @@ "translatable": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "is_fixed_asset", + "fieldtype": "Check", + "hidden": 1, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Is Fixed Asset", + "length": 0, + "no_copy": 1, + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "is_fixed_asset", + "fieldname": "asset", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Asset", + "length": 0, + "no_copy": 1, + "options": "Asset", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "is_fixed_asset", + "fieldname": "asset_location", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Asset Location", + "length": 0, + "no_copy": 0, + "options": "Location", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_on_submit": 0, @@ -2395,7 +2492,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2018-02-22 15:15:38.793425", + "modified": "2018-05-07 13:42:05.061386", "modified_by": "Administrator", "module": "Stock", "name": "Purchase Receipt Item", diff --git a/erpnext/stock/doctype/serial_no/serial_no.json b/erpnext/stock/doctype/serial_no/serial_no.json index b37713be965..f84cbef2c85 100644 --- a/erpnext/stock/doctype/serial_no/serial_no.json +++ b/erpnext/stock/doctype/serial_no/serial_no.json @@ -619,6 +619,190 @@ "set_only_once": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "asset_details", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Asset Details", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "asset", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Asset", + "length": 0, + "no_copy": 1, + "options": "Asset", + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "asset", + "fieldname": "asset_status", + "fieldtype": "Select", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Asset Status", + "length": 0, + "no_copy": 0, + "options": "\nIssue\nReceipt\nTransfer", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "column_break_24", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "location", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Location", + "length": 0, + "no_copy": 0, + "options": "Location", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "employee", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Employee", + "length": 0, + "no_copy": 0, + "options": "Employee", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_on_submit": 0, @@ -1270,7 +1454,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2017-05-15 18:22:23.685286", + "modified": "2018-05-10 23:38:20.646770", "modified_by": "Administrator", "module": "Stock", "name": "Serial No", diff --git a/erpnext/stock/doctype/serial_no/serial_no.py b/erpnext/stock/doctype/serial_no/serial_no.py index 98f15a831af..333963bd661 100644 --- a/erpnext/stock/doctype/serial_no/serial_no.py +++ b/erpnext/stock/doctype/serial_no/serial_no.py @@ -4,6 +4,7 @@ from __future__ import unicode_literals import frappe +from frappe.model.naming import make_autoname from frappe.utils import cint, cstr, flt, add_days, nowdate, getdate from frappe import _, ValidationError @@ -276,24 +277,31 @@ def allow_serial_nos_with_different_item(sle_serial_no, sle): def update_serial_nos(sle, item_det): if sle.is_cancelled == "No" and not sle.serial_no and sle.actual_qty > 0 \ and item_det.has_serial_no == 1 and item_det.serial_no_series: - from frappe.model.naming import make_autoname - serial_nos = [] - for i in range(cint(sle.actual_qty)): - serial_nos.append(make_autoname(item_det.serial_no_series, "Serial No")) - frappe.db.set(sle, "serial_no", "\n".join(serial_nos)) + serial_nos = get_auto_serial_nos(item_det.serial_no_series, sle.actual_qty) + frappe.db.set(sle, "serial_no", serial_nos) validate_serial_no(sle, item_det) if sle.serial_no: - serial_nos = get_serial_nos(sle.serial_no) - for serial_no in serial_nos: - if frappe.db.exists("Serial No", serial_no): - sr = frappe.get_doc("Serial No", serial_no) - sr.via_stock_ledger = True - sr.item_code = sle.item_code - sr.warehouse = sle.warehouse if sle.actual_qty > 0 else None - sr.save(ignore_permissions=True) - elif sle.actual_qty > 0: - make_serial_no(serial_no, sle) + auto_make_serial_nos(sle) + +def get_auto_serial_nos(serial_no_series, qty): + serial_nos = [] + for i in range(cint(qty)): + serial_nos.append(make_autoname(serial_no_series, "Serial No")) + + return "\n".join(serial_nos) + +def auto_make_serial_nos(args): + serial_nos = get_serial_nos(args.get('serial_no')) + for serial_no in serial_nos: + if frappe.db.exists("Serial No", serial_no): + sr = frappe.get_doc("Serial No", serial_no) + sr.via_stock_ledger = True + sr.item_code = args.get('item_code') + sr.warehouse = args.get('warehouse') if args.get('actual_qty', 0) > 0 else None + sr.save(ignore_permissions=True) + elif args.get('actual_qty', 0) > 0: + make_serial_no(serial_no, args) def get_item_details(item_code): return frappe.db.sql("""select name, has_batch_no, docstatus, @@ -304,20 +312,27 @@ def get_serial_nos(serial_no): return [s.strip() for s in cstr(serial_no).strip().upper().replace(',', '\n').split('\n') if s.strip()] -def make_serial_no(serial_no, sle): +def make_serial_no(serial_no, args): sr = frappe.new_doc("Serial No") sr.warehouse = None sr.dont_update_if_missing.append("warehouse") sr.flags.ignore_permissions = True sr.serial_no = serial_no - sr.item_code = sle.item_code - sr.company = sle.company - sr.via_stock_ledger = True - sr.insert() + sr.item_code = args.get('item_code') + sr.company = args.get('company') + sr.via_stock_ledger = args.get('via_stock_ledger') or True + sr.asset = args.get('asset') + + if args.get('purchase_document_type'): + sr.purchase_document_type = args.get('purchase_document_type') + sr.purchase_document_no = args.get('purchase_document_no') + + sr.insert() + if args.get('warehouse'): + sr.warehouse = args.get('warehouse') + sr.save() - sr.warehouse = sle.warehouse - sr.save() frappe.msgprint(_("Serial No {0} created").format(sr.name)) return sr.name diff --git a/erpnext/stock/doctype/serial_no/test_serial_no.js b/erpnext/stock/doctype/serial_no/test_serial_no.js new file mode 100644 index 00000000000..bf8293257c3 --- /dev/null +++ b/erpnext/stock/doctype/serial_no/test_serial_no.js @@ -0,0 +1,23 @@ +/* eslint-disable */ +// rename this file from _test_[name] to test_[name] to activate +// and remove above this line + +QUnit.test("test: Serial No", function (assert) { + let done = assert.async(); + + // number of asserts + assert.expect(1); + + frappe.run_serially([ + // insert a new Serial No + () => frappe.tests.make('Serial No', [ + // values to be set + {key: 'value'} + ]), + () => { + assert.equal(cur_frm.doc.key, 'value'); + }, + () => done() + ]); + +}); diff --git a/erpnext/utilities/user_progress_utils.py b/erpnext/utilities/user_progress_utils.py index 5bd855f7191..20e533e91a1 100644 --- a/erpnext/utilities/user_progress_utils.py +++ b/erpnext/utilities/user_progress_utils.py @@ -63,7 +63,7 @@ def create_suppliers(args_data): doc = frappe.get_doc({ "doctype":"Supplier", "supplier_name": supplier, - "supplier_type": _("Local"), + "supplier_group": _("Local"), "company": defaults.get("company") }).insert()