diff --git a/erpnext/accounts/doctype/account/account.js b/erpnext/accounts/doctype/account/account.js index bb059f673cd..f7f1a5fb15a 100644 --- a/erpnext/accounts/doctype/account/account.js +++ b/erpnext/accounts/doctype/account/account.js @@ -42,15 +42,14 @@ frappe.ui.form.on('Account', { // show / hide convert buttons frm.trigger('add_toolbar_buttons'); } - frm.add_custom_button(__('Update Account Name / Number'), function () { - frm.trigger("update_account_number"); - }); - } - - if(!frm.doc.__islocal) { - frm.add_custom_button(__('Merge Account'), function () { - frm.trigger("merge_account"); - }); + if (frm.has_perm('write')) { + frm.add_custom_button(__('Update Account Name / Number'), function () { + frm.trigger("update_account_number"); + }); + frm.add_custom_button(__('Merge Account'), function () { + frm.trigger("merge_account"); + }); + } } }, account_type: function (frm) { diff --git a/erpnext/accounts/doctype/account/account.py b/erpnext/accounts/doctype/account/account.py index ecf67dd1dbd..68efe377190 100644 --- a/erpnext/accounts/doctype/account/account.py +++ b/erpnext/accounts/doctype/account/account.py @@ -268,7 +268,7 @@ def update_account_number(name, account_name, account_number=None): new_name = get_account_autoname(account_number, account_name, account.company) if name != new_name: - frappe.rename_doc("Account", name, new_name, ignore_permissions=1) + frappe.rename_doc("Account", name, new_name, force=1) return new_name @frappe.whitelist() @@ -287,7 +287,7 @@ def merge_account(old, new, is_group, root_type, company): frappe.db.set_value("Account", new, "parent_account", frappe.db.get_value("Account", old, "parent_account")) - frappe.rename_doc("Account", old, new, merge=1, ignore_permissions=1) + frappe.rename_doc("Account", old, new, merge=1, force=1) return new diff --git a/erpnext/accounts/doctype/accounts_settings/accounts_settings.json b/erpnext/accounts/doctype/accounts_settings/accounts_settings.json index be5407b9264..64a5951f940 100644 --- a/erpnext/accounts/doctype/accounts_settings/accounts_settings.json +++ b/erpnext/accounts/doctype/accounts_settings/accounts_settings.json @@ -1,837 +1,203 @@ { - "allow_copy": 0, - "allow_events_in_timeline": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "beta": 0, - "creation": "2013-06-24 15:49:57", - "custom": 0, - "description": "Settings for Accounts", - "docstatus": 0, - "doctype": "DocType", - "document_type": "Other", - "editable_grid": 1, - "engine": "InnoDB", + "creation": "2013-06-24 15:49:57", + "description": "Settings for Accounts", + "doctype": "DocType", + "document_type": "Other", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "auto_accounting_for_stock", + "acc_frozen_upto", + "frozen_accounts_modifier", + "determine_address_tax_category_from", + "column_break_4", + "credit_controller", + "check_supplier_invoice_uniqueness", + "make_payment_via_journal_entry", + "unlink_payment_on_cancellation_of_invoice", + "unlink_advance_payment_on_cancelation_of_order", + "book_asset_depreciation_entry_automatically", + "allow_cost_center_in_entry_of_bs_account", + "add_taxes_from_item_tax_template", + "automatically_fetch_payment_terms", + "print_settings", + "show_inclusive_tax_in_print", + "column_break_12", + "show_payment_schedule_in_print", + "currency_exchange_section", + "allow_stale", + "stale_days", + "report_settings_sb", + "use_custom_cash_flow" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "1", - "description": "If enabled, the system will post accounting entries for inventory automatically.", - "fetch_if_empty": 0, - "fieldname": "auto_accounting_for_stock", - "fieldtype": "Check", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Make Accounting Entry For Every Stock Movement", - "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 - }, + "default": "1", + "description": "If enabled, the system will post accounting entries for inventory automatically.", + "fieldname": "auto_accounting_for_stock", + "fieldtype": "Check", + "hidden": 1, + "in_list_view": 1, + "label": "Make Accounting Entry For Every Stock Movement" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "description": "Accounting entry frozen up to this date, nobody can do / modify entry except role specified below.", - "fetch_if_empty": 0, - "fieldname": "acc_frozen_upto", - "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": "Accounts Frozen Upto", - "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 - }, + "description": "Accounting entry frozen up to this date, nobody can do / modify entry except role specified below.", + "fieldname": "acc_frozen_upto", + "fieldtype": "Date", + "in_list_view": 1, + "label": "Accounts Frozen Upto" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "description": "Users with this role are allowed to set frozen accounts and create / modify accounting entries against frozen accounts", - "fetch_if_empty": 0, - "fieldname": "frozen_accounts_modifier", - "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 Allowed to Set Frozen Accounts & Edit Frozen Entries", - "length": 0, - "no_copy": 0, - "options": "Role", - "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 - }, + "description": "Users with this role are allowed to set frozen accounts and create / modify accounting entries against frozen accounts", + "fieldname": "frozen_accounts_modifier", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Role Allowed to Set Frozen Accounts & Edit Frozen Entries", + "options": "Role" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "Billing Address", - "description": "Address used to determine Tax Category in transactions.", - "fetch_if_empty": 0, - "fieldname": "determine_address_tax_category_from", - "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": "Determine Address Tax Category From", - "length": 0, - "no_copy": 0, - "options": "Billing Address\nShipping Address", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "default": "Billing Address", + "description": "Address used to determine Tax Category in transactions.", + "fieldname": "determine_address_tax_category_from", + "fieldtype": "Select", + "label": "Determine Address Tax Category From", + "options": "Billing Address\nShipping Address" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 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, - "translatable": 0, - "unique": 0 - }, + "fieldname": "column_break_4", + "fieldtype": "Column Break" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "description": "Role that is allowed to submit transactions that exceed credit limits set.", - "fetch_if_empty": 0, - "fieldname": "credit_controller", - "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": "Credit Controller", - "length": 0, - "no_copy": 0, - "options": "Role", - "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 - }, + "description": "Role that is allowed to submit transactions that exceed credit limits set.", + "fieldname": "credit_controller", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Credit Controller", + "options": "Role" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "check_supplier_invoice_uniqueness", - "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": "Check Supplier Invoice Number Uniqueness", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "check_supplier_invoice_uniqueness", + "fieldtype": "Check", + "label": "Check Supplier Invoice Number Uniqueness" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "make_payment_via_journal_entry", - "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": "Make Payment via Journal Entry", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "make_payment_via_journal_entry", + "fieldtype": "Check", + "label": "Make Payment via Journal Entry" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "1", - "fetch_if_empty": 0, - "fieldname": "unlink_payment_on_cancellation_of_invoice", - "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": "Unlink Payment on Cancellation of Invoice", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "default": "1", + "fieldname": "unlink_payment_on_cancellation_of_invoice", + "fieldtype": "Check", + "label": "Unlink Payment on Cancellation of Invoice" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "1", - "fetch_if_empty": 0, - "fieldname": "unlink_advance_payment_on_cancelation_of_order", - "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": "Unlink Advance Payment on Cancelation of Order", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "default": "1", + "fieldname": "unlink_advance_payment_on_cancelation_of_order", + "fieldtype": "Check", + "label": "Unlink Advance Payment on Cancelation of Order" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "1", - "fetch_if_empty": 0, - "fieldname": "book_asset_depreciation_entry_automatically", - "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": "Book Asset Depreciation Entry Automatically", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "default": "1", + "fieldname": "book_asset_depreciation_entry_automatically", + "fieldtype": "Check", + "label": "Book Asset Depreciation Entry Automatically" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "allow_cost_center_in_entry_of_bs_account", - "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Allow Cost Center In Entry of Balance Sheet Account", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "allow_cost_center_in_entry_of_bs_account", + "fieldtype": "Check", + "label": "Allow Cost Center In Entry of Balance Sheet Account" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "1", - "fetch_if_empty": 0, - "fieldname": "add_taxes_from_item_tax_template", - "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": "Automatically Add Taxes and Charges from Item Tax Template", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "default": "1", + "fieldname": "add_taxes_from_item_tax_template", + "fieldtype": "Check", + "label": "Automatically Add Taxes and Charges from Item Tax Template" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "print_settings", - "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": "Print Settings", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "print_settings", + "fieldtype": "Section Break", + "label": "Print Settings" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "show_inclusive_tax_in_print", - "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": "Show Inclusive Tax In Print", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "show_inclusive_tax_in_print", + "fieldtype": "Check", + "label": "Show Inclusive Tax In Print" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "column_break_12", - "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 - }, + "fieldname": "column_break_12", + "fieldtype": "Column Break" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "show_payment_schedule_in_print", - "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": "Show Payment Schedule in Print", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "show_payment_schedule_in_print", + "fieldtype": "Check", + "label": "Show Payment Schedule in Print" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "currency_exchange_section", - "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": "Currency Exchange Settings", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "currency_exchange_section", + "fieldtype": "Section Break", + "label": "Currency Exchange Settings" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "1", - "fetch_if_empty": 0, - "fieldname": "allow_stale", - "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": "Allow Stale Exchange Rates", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "default": "1", + "fieldname": "allow_stale", + "fieldtype": "Check", + "in_list_view": 1, + "label": "Allow Stale Exchange Rates" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "1", - "depends_on": "eval:doc.allow_stale==0", - "fetch_if_empty": 0, - "fieldname": "stale_days", - "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": "Stale Days", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "default": "1", + "depends_on": "eval:doc.allow_stale==0", + "fieldname": "stale_days", + "fieldtype": "Int", + "label": "Stale Days" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "report_settings_sb", - "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": "Report Settings", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "report_settings_sb", + "fieldtype": "Section Break", + "label": "Report Settings" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "0", - "description": "Only select if you have setup Cash Flow Mapper documents", - "fetch_if_empty": 0, - "fieldname": "use_custom_cash_flow", - "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": "Use Custom Cash Flow Format", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "default": "0", + "description": "Only select if you have setup Cash Flow Mapper documents", + "fieldname": "use_custom_cash_flow", + "fieldtype": "Check", + "label": "Use Custom Cash Flow Format" + }, + { + "fieldname": "automatically_fetch_payment_terms", + "fieldtype": "Check", + "label": "Automatically Fetch Payment Terms" } - ], - "has_web_view": 0, - "hide_toolbar": 0, - "icon": "icon-cog", - "idx": 1, - "in_create": 0, - "is_submittable": 0, - "issingle": 1, - "istable": 0, - "max_attachments": 0, - "modified": "2019-04-06 12:28:43.026250", - "modified_by": "Administrator", - "module": "Accounts", - "name": "Accounts Settings", - "owner": "Administrator", + ], + "icon": "icon-cog", + "idx": 1, + "issingle": 1, + "modified": "2019-04-28 18:20:55.789946", + "modified_by": "Administrator", + "module": "Accounts", + "name": "Accounts Settings", + "owner": "Administrator", "permissions": [ { - "amend": 0, - "cancel": 0, - "create": 1, - "delete": 0, - "email": 1, - "export": 0, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 0, - "role": "Accounts Manager", - "set_user_permissions": 0, - "share": 1, - "submit": 0, + "create": 1, + "email": 1, + "print": 1, + "read": 1, + "role": "Accounts Manager", + "share": 1, "write": 1 - }, + }, { - "amend": 0, - "cancel": 0, - "create": 0, - "delete": 0, - "email": 0, - "export": 0, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 0, - "read": 1, - "report": 0, - "role": "Sales User", - "set_user_permissions": 0, - "share": 0, - "submit": 0, - "write": 0 - }, + "read": 1, + "role": "Sales User" + }, { - "amend": 0, - "cancel": 0, - "create": 0, - "delete": 0, - "email": 0, - "export": 0, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 0, - "read": 1, - "report": 0, - "role": "Purchase User", - "set_user_permissions": 0, - "share": 0, - "submit": 0, - "write": 0 + "read": 1, + "role": "Purchase User" } - ], - "quick_entry": 1, - "read_only": 0, - "show_name_in_global_search": 0, - "sort_order": "ASC", - "track_changes": 1, - "track_seen": 0, - "track_views": 0 + ], + "quick_entry": 1, + "sort_order": "ASC", + "track_changes": 1 } \ No newline at end of file diff --git a/erpnext/accounts/report/gross_profit/gross_profit.js b/erpnext/accounts/report/gross_profit/gross_profit.js index 1f7d24db1e4..ba17a94e8d3 100644 --- a/erpnext/accounts/report/gross_profit/gross_profit.js +++ b/erpnext/accounts/report/gross_profit/gross_profit.js @@ -23,6 +23,12 @@ frappe.query_reports["Gross Profit"] = { "fieldtype": "Date", "default": frappe.defaults.get_user_default("year_end_date") }, + { + "fieldname":"sales_invoice", + "label": __("Sales Invoice"), + "fieldtype": "Link", + "options": "Sales Invoice" + }, { "fieldname":"group_by", "label": __("Group By"), diff --git a/erpnext/accounts/report/gross_profit/gross_profit.py b/erpnext/accounts/report/gross_profit/gross_profit.py index a5859e31b04..9a02d1b8e84 100644 --- a/erpnext/accounts/report/gross_profit/gross_profit.py +++ b/erpnext/accounts/report/gross_profit/gross_profit.py @@ -302,6 +302,12 @@ class GrossProfitGenerator(object): sales_person_cols = "" sales_team_table = "" + if self.filters.get("sales_invoice"): + conditions += " and `tabSales Invoice`.name = %(sales_invoice)s" + + if self.filters.get("item_code"): + conditions += " and `tabSales Invoice Item`.item_code = %(item_code)s" + self.si_list = frappe.db.sql(""" select `tabSales Invoice Item`.parenttype, `tabSales Invoice Item`.parent, diff --git a/erpnext/accounts/report/inactive_sales_items/inactive_sales_items.js b/erpnext/accounts/report/inactive_sales_items/inactive_sales_items.js index 36bd29efeb2..29db2276129 100644 --- a/erpnext/accounts/report/inactive_sales_items/inactive_sales_items.js +++ b/erpnext/accounts/report/inactive_sales_items/inactive_sales_items.js @@ -4,6 +4,12 @@ frappe.query_reports["Inactive Sales Items"] = { "filters": [ + { + fieldname: "territory", + label: __("Territory"), + fieldtype: "Link", + options: "Territory" + }, { fieldname: "item", label: __("Item"), diff --git a/erpnext/accounts/report/inactive_sales_items/inactive_sales_items.py b/erpnext/accounts/report/inactive_sales_items/inactive_sales_items.py index fd169f8f70f..42761a58b95 100644 --- a/erpnext/accounts/report/inactive_sales_items/inactive_sales_items.py +++ b/erpnext/accounts/report/inactive_sales_items/inactive_sales_items.py @@ -7,13 +7,11 @@ from frappe.utils import getdate, add_days, today, cint from frappe import _ def execute(filters=None): - columns = get_columns() data = get_data(filters) return columns, data def get_columns(): - columns = [ { "fieldname": "territory", @@ -74,36 +72,37 @@ def get_columns(): def get_data(filters): - data = [] items = get_items(filters) + territories = get_territories(filters) sales_invoice_data = get_sales_details(filters) - for item in items: - row = { + for territory in territories: + for item in items: + row = { + "territory": territory.name, "item_group": item.item_group, "item": item.name, "item_name": item.item_name - } + } - if sales_invoice_data.get(item.name): - item_obj = sales_invoice_data[item.name] - if item_obj.days_since_last_order > cint(filters['days']): - row.update({ - "territory": item_obj.territory, - "customer": item_obj.customer, - "last_order_date": item_obj.last_order_date, - "qty": item_obj.qty, - "days_since_last_order": item_obj.days_since_last_order - }) + if sales_invoice_data.get((territory.name,item.name)): + item_obj = sales_invoice_data[(territory.name,item.name)] + if item_obj.days_since_last_order > cint(filters['days']): + row.update({ + "territory": item_obj.territory, + "customer": item_obj.customer, + "last_order_date": item_obj.last_order_date, + "qty": item_obj.qty, + "days_since_last_order": item_obj.days_since_last_order + }) - data.append(row) + data.append(row) return data def get_sales_details(filters): - data = [] item_details_map = {} @@ -118,12 +117,21 @@ def get_sales_details(filters): .format(date_field = date_field, doctype = filters['based_on']), as_dict=1) for d in sales_data: - item_details_map.setdefault(d.item_name, d) + item_details_map.setdefault((d.territory,d.item_name), d) return item_details_map -def get_items(filters): +def get_territories(filters): + filter_dict = {} + if filters.get("territory"): + filter_dict.update({'name': filters['territory']}) + + territories = frappe.get_all("Territory", fields=["name"], filters=filter_dict) + + return territories + +def get_items(filters): filters_dict = { "disabled": 0, "is_stock_item": 1 diff --git a/erpnext/accounts/report/utils.py b/erpnext/accounts/report/utils.py index 8500aea4159..4a9af490cfc 100644 --- a/erpnext/accounts/report/utils.py +++ b/erpnext/accounts/report/utils.py @@ -135,3 +135,25 @@ def get_appropriate_company(filters): company = get_default_company() return company + +@frappe.whitelist() +def get_invoiced_item_gross_margin(sales_invoice=None, item_code=None, company=None, with_item_data=False): + from erpnext.accounts.report.gross_profit.gross_profit import GrossProfitGenerator + + sales_invoice = sales_invoice or frappe.form_dict.get('sales_invoice') + item_code = item_code or frappe.form_dict.get('item_code') + company = company or frappe.get_cached_value("Sales Invoice", sales_invoice, 'company') + + filters = { + 'sales_invoice': sales_invoice, + 'item_code': item_code, + 'company': company, + 'group_by': 'Invoice' + } + + gross_profit_data = GrossProfitGenerator(filters) + result = gross_profit_data.grouped_data + if not with_item_data: + result = sum([d.gross_profit for d in result]) + + return result diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py index e5156a32b7f..a9a2094f083 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/purchase_order.py @@ -369,7 +369,9 @@ def make_purchase_receipt(source_name, target_doc=None): "field_map": { "name": "purchase_order_item", "parent": "purchase_order", - "bom": "bom" + "bom": "bom", + "material_request": "material_request", + "material_request_item": "material_request_item" }, "postprocess": update_item, "condition": lambda doc: abs(doc.received_qty) < abs(doc.qty) and doc.delivered_by_supplier!=1 @@ -403,7 +405,7 @@ def make_purchase_invoice(source_name, target_doc=None): or item.get("buying_cost_center") or item_group.get("buying_cost_center")) - doc = get_mapped_doc("Purchase Order", source_name, { + fields = { "Purchase Order": { "doctype": "Purchase Invoice", "field_map": { @@ -426,8 +428,16 @@ def make_purchase_invoice(source_name, target_doc=None): "Purchase Taxes and Charges": { "doctype": "Purchase Taxes and Charges", "add_if_empty": True + }, + } + + if frappe.get_single("Accounts Settings").automatically_fetch_payment_terms == 1: + fields["Payment Schedule"] = { + "doctype": "Payment Schedule", + "add_if_empty": True } - }, target_doc, postprocess) + + doc = get_mapped_doc("Purchase Order", source_name, fields, target_doc, postprocess) return doc diff --git a/erpnext/buying/doctype/purchase_order/test_purchase_order.py b/erpnext/buying/doctype/purchase_order/test_purchase_order.py index 345490828a0..812aad8ea50 100644 --- a/erpnext/buying/doctype/purchase_order/test_purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/test_purchase_order.py @@ -6,7 +6,7 @@ import unittest import frappe import frappe.defaults from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry -from frappe.utils import flt, add_days, nowdate +from frappe.utils import flt, add_days, nowdate, getdate from erpnext.stock.doctype.item.test_item import make_item from erpnext.buying.doctype.purchase_order.purchase_order import (make_purchase_receipt, make_purchase_invoice, make_rm_stock_entry as make_subcontract_transfer_entry) from erpnext.stock.doctype.material_request.test_material_request import make_material_request @@ -142,9 +142,9 @@ class TestPurchaseOrder(unittest.TestCase): po.submit() self.assertEqual(po.payment_schedule[0].payment_amount, 2500.0) - self.assertEqual(po.payment_schedule[0].due_date, po.transaction_date) + self.assertEqual(getdate(po.payment_schedule[0].due_date), getdate(po.transaction_date)) self.assertEqual(po.payment_schedule[1].payment_amount, 2500.0) - self.assertEqual(po.payment_schedule[1].due_date, add_days(po.transaction_date, 30)) + self.assertEqual(getdate(po.payment_schedule[1].due_date), add_days(getdate(po.transaction_date), 30)) pi = make_purchase_invoice(po.name) pi.save() @@ -152,9 +152,9 @@ class TestPurchaseOrder(unittest.TestCase): self.assertEqual(len(pi.get("items", [])), 1) self.assertEqual(pi.payment_schedule[0].payment_amount, 2500.0) - self.assertEqual(pi.payment_schedule[0].due_date, po.transaction_date) + self.assertEqual(getdate(pi.payment_schedule[0].due_date), getdate(po.transaction_date)) self.assertEqual(pi.payment_schedule[1].payment_amount, 2500.0) - self.assertEqual(pi.payment_schedule[1].due_date, add_days(po.transaction_date, 30)) + self.assertEqual(getdate(pi.payment_schedule[1].due_date), add_days(getdate(po.transaction_date), 30)) def test_subcontracting(self): po = create_purchase_order(item_code="_Test FG Item", is_subcontracted="Yes") @@ -303,6 +303,10 @@ class TestPurchaseOrder(unittest.TestCase): make_stock_entry(target="_Test Warehouse - _TC", qty=10, basic_rate=100) make_stock_entry(target="_Test Warehouse - _TC", item_code="_Test Item Home Desktop 100", qty=20, basic_rate=100) + make_stock_entry(target="_Test Warehouse 1 - _TC", item_code="_Test Item", + qty=30, basic_rate=100) + make_stock_entry(target="_Test Warehouse 1 - _TC", item_code="_Test Item Home Desktop 100", + qty=30, basic_rate=100) bin1 = frappe.db.get_value("Bin", filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"}, @@ -349,6 +353,11 @@ class TestPurchaseOrder(unittest.TestCase): self.assertEquals(bin5.reserved_qty_for_sub_contract, bin2.reserved_qty_for_sub_contract - 6) + make_stock_entry(target="_Test Warehouse 1 - _TC", item_code="_Test Item", + qty=40, basic_rate=100) + make_stock_entry(target="_Test Warehouse 1 - _TC", item_code="_Test Item Home Desktop 100", + qty=40, basic_rate=100) + # make Purchase Receipt against PO pr = make_purchase_receipt(po.name) pr.supplier_warehouse = "_Test Warehouse 1 - _TC" diff --git a/erpnext/buying/report/procurement_tracker/__init__.py b/erpnext/buying/report/procurement_tracker/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/buying/report/procurement_tracker/procurement_tracker.js b/erpnext/buying/report/procurement_tracker/procurement_tracker.js new file mode 100644 index 00000000000..283d56c9469 --- /dev/null +++ b/erpnext/buying/report/procurement_tracker/procurement_tracker.js @@ -0,0 +1,39 @@ +// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors +// For license information, please see license.txt +/* eslint-disable */ + +frappe.query_reports["Procurement Tracker"] = { + "filters": [ + { + fieldname: "company", + label: __("Company"), + fieldtype: "Link", + options: "Company", + default: frappe.defaults.get_user_default("Company"), + }, + { + fieldname: "cost_center", + label: __("Cost Center"), + fieldtype: "Link", + options: "Cost Center", + }, + { + fieldname: "project", + label: __("Project"), + fieldtype: "Link", + options: "Project", + }, + { + fieldname: "from_date", + label: __("From Date"), + fieldtype: "Date", + default: frappe.defaults.get_user_default("year_start_date"), + }, + { + fieldname:"to_date", + label: __("To Date"), + fieldtype: "Date", + default: frappe.defaults.get_user_default("year_end_date"), + }, + ] +} diff --git a/erpnext/buying/report/procurement_tracker/procurement_tracker.json b/erpnext/buying/report/procurement_tracker/procurement_tracker.json new file mode 100644 index 00000000000..028736c7c41 --- /dev/null +++ b/erpnext/buying/report/procurement_tracker/procurement_tracker.json @@ -0,0 +1,20 @@ +{ + "add_total_row": 1, + "creation": "2019-03-29 17:05:45.196949", + "disable_prepared_report": 0, + "disabled": 0, + "docstatus": 0, + "doctype": "Report", + "idx": 0, + "is_standard": "Yes", + "modified": "2019-03-29 17:18:06.678728", + "modified_by": "Administrator", + "module": "Buying", + "name": "Procurement Tracker", + "owner": "Administrator", + "prepared_report": 0, + "ref_doctype": "Purchase Order", + "report_name": "Procurement Tracker", + "report_type": "Script Report", + "roles": [] +} \ No newline at end of file diff --git a/erpnext/buying/report/procurement_tracker/procurement_tracker.py b/erpnext/buying/report/procurement_tracker/procurement_tracker.py new file mode 100644 index 00000000000..d3ee4475450 --- /dev/null +++ b/erpnext/buying/report/procurement_tracker/procurement_tracker.py @@ -0,0 +1,282 @@ +# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +from __future__ import unicode_literals +import frappe +from frappe import _ + +def execute(filters=None): + columns = get_columns(filters) + data = get_data(filters) + return columns, data + +def get_columns(filters): + columns = [ + { + "label": _("Material Request Date"), + "fieldname": "material_request_date", + "fieldtype": "Date", + "width": 140 + }, + { + "label": _("Material Request No"), + "options": "Material Request", + "fieldname": "material_request_no", + "fieldtype": "Link", + "width": 140 + }, + { + "label": _("Cost Center"), + "options": "Cost Center", + "fieldname": "cost_center", + "fieldtype": "Link", + "width": 140 + }, + { + "label": _("Project"), + "options": "Project", + "fieldname": "project", + "fieldtype": "Link", + "width": 140 + }, + { + "label": _("Requesting Site"), + "options": "Warehouse", + "fieldname": "requesting_site", + "fieldtype": "Link", + "width": 140 + }, + { + "label": _("Requestor"), + "options": "Employee", + "fieldname": "requestor", + "fieldtype": "Link", + "width": 140 + }, + { + "label": _("Description"), + "fieldname": "description", + "fieldtype": "Data", + "width": 200 + }, + { + "label": _("Quantity"), + "fieldname": "quantity", + "fieldtype": "Int", + "width": 140 + }, + { + "label": _("Unit of Measure"), + "options": "UOM", + "fieldname": "unit_of_measurement", + "fieldtype": "Link", + "width": 140 + }, + { + "label": _("Status"), + "fieldname": "status", + "fieldtype": "data", + "width": 140 + }, + { + "label": _("Purchase Order Date"), + "fieldname": "purchase_order_date", + "fieldtype": "Date", + "width": 140 + }, + { + "label": _("Purchase Order"), + "options": "Purchase Order", + "fieldname": "purchase_order", + "fieldtype": "Link", + "width": 140 + }, + { + "label": _("Supplier"), + "options": "Supplier", + "fieldname": "supplier", + "fieldtype": "Link", + "width": 140 + }, + { + "label": _("Estimated Cost"), + "fieldname": "estimated_cost", + "fieldtype": "Float", + "width": 140 + }, + { + "label": _("Actual Cost"), + "fieldname": "actual_cost", + "fieldtype": "Float", + "width": 140 + }, + { + "label": _("Purchase Order Amount"), + "fieldname": "purchase_order_amt", + "fieldtype": "Float", + "width": 140 + }, + { + "label": _("Purchase Order Amount(Company Currency)"), + "fieldname": "purchase_order_amt_usd", + "fieldtype": "Float", + "width": 140 + }, + { + "label": _("Expected Delivery Date"), + "fieldname": "expected_delivery_date", + "fieldtype": "Date", + "width": 140 + }, + { + "label": _("Actual Delivery Date"), + "fieldname": "actual_delivery_date", + "fieldtype": "Date", + "width": 140 + }, + ] + return columns + +def get_conditions(filters): + conditions = "" + + if filters.get("company"): + conditions += " AND company='%s'"% filters.get('company') + + if filters.get("cost_center") or filters.get("project"): + conditions += """ + AND (cost_center='%s' + OR project='%s') + """% (filters.get('cost_center'), filters.get('project')) + + if filters.get("from_date"): + conditions += "AND transaction_date>=%s"% filters.get('from_date') + + if filters.get("to_date"): + conditions += "AND transaction_date<=%s"% filters.get('to_date') + return conditions + +def get_data(filters): + conditions = get_conditions(filters) + purchase_order_entry = get_po_entries(conditions) + mr_records, procurement_record_against_mr = get_mapped_mr_details(conditions) + pr_records = get_mapped_pr_records() + pi_records = get_mapped_pi_records() + print(pi_records) + + procurement_record=[] + if procurement_record_against_mr: + procurement_record += procurement_record_against_mr + for po in purchase_order_entry: + # fetch material records linked to the purchase order item + mr_record = mr_records.get(po.material_request_item, [{}])[0] + procurement_detail = { + "material_request_date": mr_record.get('transaction_date'), + "cost_center": po.cost_center, + "project": po.project, + "requesting_site": po.warehouse, + "requestor": po.owner, + "material_request_no": po.material_request, + "description": po.description, + "quantity": po.qty, + "unit_of_measurement": po.stock_uom, + "status": po.status, + "purchase_order_date": po.transaction_date, + "purchase_order": po.parent, + "supplier": po.supplier, + "estimated_cost": mr_record.get('amount'), + "actual_cost": pi_records.get(po.name), + "purchase_order_amt": po.amount, + "purchase_order_amt_in_company_currency": po.base_amount, + "expected_delivery_date": po.schedule_date, + "actual_delivery_date": pr_records.get(po.name) + } + procurement_record.append(procurement_detail) + return procurement_record + +def get_mapped_mr_details(conditions): + mr_records = {} + mr_details = frappe.db.sql(""" + SELECT + mr.transaction_date, + mr.per_ordered, + mr_item.name, + mr_item.parent, + mr_item.amount + FROM `tabMaterial Request` mr, `tabMaterial Request Item` mr_item + WHERE + mr.per_ordered>=0 + AND mr.name=mr_item.parent + AND mr.docstatus=1 + {conditions} + """.format(conditions=conditions), as_dict=1) #nosec + + procurement_record_against_mr = [] + for record in mr_details: + if record.per_ordered: + mr_records.setdefault(record.name, []).append(frappe._dict(record)) + else: + procurement_record_details = dict( + material_request_date=record.transaction_date, + material_request_no=record.parent, + estimated_cost=record.amount + ) + procurement_record_against_mr.append(procurement_record_details) + return mr_records, procurement_record_against_mr + +def get_mapped_pi_records(): + return frappe._dict(frappe.db.sql(""" + SELECT + pi_item.po_detail, + pi_item.base_amount + FROM `tabPurchase Invoice Item` as pi_item + INNER JOIN `tabPurchase Order` as po + ON pi_item.`purchase_order` = po.`name` + WHERE + pi_item.docstatus = 1 + AND po.status not in ("Closed","Completed","Cancelled") + AND pi_item.po_detail IS NOT NULL + """)) + +def get_mapped_pr_records(): + return frappe._dict(frappe.db.sql(""" + SELECT + pr_item.purchase_order_item, + pr.posting_date + FROM `tabPurchase Receipt` pr, `tabPurchase Receipt Item` pr_item + WHERE + pr.docstatus=1 + AND pr.name=pr_item.parent + AND pr_item.purchase_order_item IS NOT NULL + AND pr.status not in ("Closed","Completed","Cancelled") + """)) + +def get_po_entries(conditions): + return frappe.db.sql(""" + SELECT + po_item.name, + po_item.parent, + po_item.cost_center, + po_item.project, + po_item.warehouse, + po_item.material_request, + po_item.material_request_item, + po_item.description, + po_item.stock_uom, + po_item.qty, + po_item.amount, + po_item.base_amount, + po_item.schedule_date, + po.transaction_date, + po.supplier, + po.status, + po.owner + FROM `tabPurchase Order` po, `tabPurchase Order Item` po_item + WHERE + po.docstatus = 1 + AND po.name = po_item.parent + AND po.status not in ("Closed","Completed","Cancelled") + {conditions} + GROUP BY + po.name,po_item.item_code + """.format(conditions=conditions), as_dict=1) #nosec \ No newline at end of file diff --git a/erpnext/buying/report/procurement_tracker/test_procurement_tracker.py b/erpnext/buying/report/procurement_tracker/test_procurement_tracker.py new file mode 100644 index 00000000000..4a13f385bb4 --- /dev/null +++ b/erpnext/buying/report/procurement_tracker/test_procurement_tracker.py @@ -0,0 +1,67 @@ +# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +from __future__ import unicode_literals +import unittest +from datetime import datetime +import frappe +from erpnext.buying.report.procurement_tracker.procurement_tracker import execute +from erpnext.stock.doctype.material_request.test_material_request import make_material_request +from erpnext.stock.doctype.material_request.material_request import make_purchase_order +from erpnext.buying.doctype.purchase_order.purchase_order import make_purchase_receipt +from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse + +class TestProcurementTracker(unittest.TestCase): + def test_result_for_procurement_tracker(self): + filters = { + 'company': '_Test Procurement Company', + 'cost_center': '_Test Cost Center - _TC' + } + expected_data = self.generate_expected_data() + report = execute(filters) + + length = len(report[1]) + self.assertEqual(expected_data, report[1][length-1]) + + def generate_expected_data(self): + if not frappe.db.exists("Company", "_Test Procurement Company"): + frappe.get_doc(dict( + doctype="Company", + company_name="_Test Procurement Company", + abbr="_TPC", + default_currency="INR", + country="India" + )).insert() + warehouse = create_warehouse("_Test Procurement Warehouse", company="_Test Procurement Company") + mr = make_material_request(company="_Test Procurement Company", warehouse=warehouse) + po = make_purchase_order(mr.name) + po.supplier = "_Test Supplier" + po.get("items")[0].cost_center = "_Test Cost Center - _TC" + po.submit() + pr = make_purchase_receipt(po.name) + pr.submit() + frappe.db.commit() + date_obj = datetime.date(datetime.now()) + + expected_data = { + "material_request_date": date_obj, + "cost_center": "_Test Cost Center - _TC", + "project": None, + "requesting_site": "_Test Procurement Warehouse - _TPC", + "requestor": "Administrator", + "material_request_no": mr.name, + "description": '_Test Item 1', + "quantity": 10.0, + "unit_of_measurement": "_Test UOM", + "status": "To Bill", + "purchase_order_date": date_obj, + "purchase_order": po.name, + "supplier": "_Test Supplier", + "estimated_cost": 0.0, + "actual_cost": None, + "purchase_order_amt": 5000.0, + "purchase_order_amt_in_company_currency": 300000.0, + "expected_delivery_date": date_obj, + "actual_delivery_date": date_obj + } + return expected_data \ No newline at end of file diff --git a/erpnext/controllers/item_variant.py b/erpnext/controllers/item_variant.py index e0acd73edf6..631f7751b44 100644 --- a/erpnext/controllers/item_variant.py +++ b/erpnext/controllers/item_variant.py @@ -124,16 +124,8 @@ def find_variant(template, args, variant_item_code=None): conditions = " or ".join(conditions) - # use approximate match and shortlist possible variant matches - # it is approximate because we are matching using OR condition - # and it need not be exact match at this stage - # this uses a simpler query instead of using multiple exists conditions - possible_variants = frappe.db.sql_list("""select name from `tabItem` item - where variant_of=%s and exists ( - select name from `tabItem Variant Attribute` iv_attribute - where iv_attribute.parent=item.name - and ({conditions}) and parent != %s - )""".format(conditions=conditions), (template, cstr(variant_item_code))) + from erpnext.portal.product_configurator.utils import get_item_codes_by_attributes + possible_variants = [i for i in get_item_codes_by_attributes(args, template) if i != variant_item_code] for variant in possible_variants: variant = frappe.get_doc("Item", variant) @@ -317,7 +309,7 @@ def make_variant_item_code(template_item_code, template_item_name, variant): }, as_dict=True) if not item_attribute: - return + continue # frappe.throw(_('Invalid attribute {0} {1}').format(frappe.bold(attr.attribute), # frappe.bold(attr.attribute_value)), title=_('Invalid Attribute'), # exc=InvalidItemAttributeValueError) diff --git a/erpnext/controllers/status_updater.py b/erpnext/controllers/status_updater.py index 77d941c98ec..3107c9274fa 100644 --- a/erpnext/controllers/status_updater.py +++ b/erpnext/controllers/status_updater.py @@ -96,7 +96,9 @@ status_map = { ["Partially Ordered", "eval:self.status != 'Stopped' and self.per_ordered < 100 and self.per_ordered > 0 and self.docstatus == 1"], ["Ordered", "eval:self.status != 'Stopped' and self.per_ordered == 100 and self.docstatus == 1 and self.material_request_type == 'Purchase'"], ["Transferred", "eval:self.status != 'Stopped' and self.per_ordered == 100 and self.docstatus == 1 and self.material_request_type == 'Material Transfer'"], - ["Issued", "eval:self.status != 'Stopped' and self.per_ordered == 100 and self.docstatus == 1 and self.material_request_type == 'Material Issue'"] + ["Issued", "eval:self.status != 'Stopped' and self.per_ordered == 100 and self.docstatus == 1 and self.material_request_type == 'Material Issue'"], + ["Received", "eval:self.status != 'Stopped' and self.per_received == 100 and self.docstatus == 1 and self.material_request_type == 'Purchase'"], + ["Partially Received", "eval:self.status != 'Stopped' and self.per_received > 0 and self.per_received < 100 and self.docstatus == 1 and self.material_request_type == 'Purchase'"] ] } diff --git a/erpnext/crm/doctype/lead/lead.js b/erpnext/crm/doctype/lead/lead.js index 208b1f55fa0..8c1ab2f38f5 100644 --- a/erpnext/crm/doctype/lead/lead.js +++ b/erpnext/crm/doctype/lead/lead.js @@ -5,29 +5,32 @@ frappe.provide("erpnext"); cur_frm.email_field = "email_id"; erpnext.LeadController = frappe.ui.form.Controller.extend({ - setup: function() { - this.frm.fields_dict.customer.get_query = function(doc, cdt, cdn) { - return { query: "erpnext.controllers.queries.customer_query" } } + setup: function () { + this.frm.fields_dict.customer.get_query = function (doc, cdt, cdn) { + return { query: "erpnext.controllers.queries.customer_query" } + } + + this.frm.toggle_reqd("lead_name", !this.frm.doc.organization_lead); }, - onload: function() { - - if(cur_frm.fields_dict.lead_owner.df.options.match(/^User/)) { - cur_frm.fields_dict.lead_owner.get_query = function(doc, cdt, cdn) { + onload: function () { + if (cur_frm.fields_dict.lead_owner.df.options.match(/^User/)) { + cur_frm.fields_dict.lead_owner.get_query = function (doc, cdt, cdn) { return { query: "frappe.core.doctype.user.user.user_query" } } } - if(cur_frm.fields_dict.contact_by.df.options.match(/^User/)) { - cur_frm.fields_dict.contact_by.get_query = function(doc, cdt, cdn) { - return { query: "frappe.core.doctype.user.user.user_query" } } + if (cur_frm.fields_dict.contact_by.df.options.match(/^User/)) { + cur_frm.fields_dict.contact_by.get_query = function (doc, cdt, cdn) { + return { query: "frappe.core.doctype.user.user.user_query" } + } } }, - refresh: function() { + refresh: function () { var doc = this.frm.doc; erpnext.toggle_naming_series(); - frappe.dynamic_link = {doc: doc, fieldname: 'name', doctype: 'Lead'} + frappe.dynamic_link = { doc: doc, fieldname: 'name', doctype: 'Lead' } if(!doc.__islocal && doc.__onload && !doc.__onload.is_customer) { this.frm.add_custom_button(__("Customer"), this.create_customer, __('Create')); @@ -35,49 +38,46 @@ erpnext.LeadController = frappe.ui.form.Controller.extend({ this.frm.add_custom_button(__("Quotation"), this.make_quotation, __('Create')); } - if(!this.frm.doc.__islocal) { + if (!this.frm.doc.__islocal) { frappe.contacts.render_address_and_contact(cur_frm); } else { frappe.contacts.clear_address_and_contact(cur_frm); } }, - create_customer: function() { + create_customer: function () { frappe.model.open_mapped_doc({ method: "erpnext.crm.doctype.lead.lead.make_customer", frm: cur_frm }) }, - create_opportunity: function() { + create_opportunity: function () { frappe.model.open_mapped_doc({ method: "erpnext.crm.doctype.lead.lead.make_opportunity", frm: cur_frm }) }, - make_quotation: function() { + make_quotation: function () { frappe.model.open_mapped_doc({ method: "erpnext.crm.doctype.lead.lead.make_quotation", frm: cur_frm }) }, - organization_lead: function() { - if (this.frm.doc.organization_lead == 1) { - this.frm.set_df_property('company_name', 'reqd', 1); - } else { - this.frm.set_df_property('company_name', 'reqd', 0); - } + organization_lead: function () { + this.frm.toggle_reqd("lead_name", !this.frm.doc.organization_lead); + this.frm.toggle_reqd("company_name", this.frm.doc.organization_lead); }, - company_name: function() { + company_name: function () { if (this.frm.doc.organization_lead == 1) { this.frm.set_value("lead_name", this.frm.doc.company_name); } }, - contact_date: function() { + contact_date: function () { if (this.frm.doc.contact_date) { let d = moment(this.frm.doc.contact_date); d.add(1, "hours"); @@ -86,4 +86,4 @@ erpnext.LeadController = frappe.ui.form.Controller.extend({ } }); -$.extend(cur_frm.cscript, new erpnext.LeadController({frm: cur_frm})); +$.extend(cur_frm.cscript, new erpnext.LeadController({ frm: cur_frm })); diff --git a/erpnext/crm/doctype/lead/lead.json b/erpnext/crm/doctype/lead/lead.json index f1c2a9b4f12..600e070b7c1 100644 --- a/erpnext/crm/doctype/lead/lead.json +++ b/erpnext/crm/doctype/lead/lead.json @@ -145,7 +145,7 @@ "read_only": 0, "remember_last_selected_value": 0, "report_hide": 0, - "reqd": 1, + "reqd": 0, "search_index": 1, "set_only_once": 0, "translatable": 0, @@ -268,7 +268,7 @@ "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, - "in_list_view": 0, + "in_list_view": 1, "in_standard_filter": 0, "label": "Lead Owner", "length": 0, @@ -1419,17 +1419,18 @@ } ], "has_web_view": 0, + "hide_heading": 0, "hide_toolbar": 0, "icon": "fa fa-user", "idx": 5, "image_field": "image", + "image_view": 0, "in_create": 0, "is_submittable": 0, "issingle": 0, "istable": 0, "max_attachments": 0, - "menu_index": 0, - "modified": "2019-04-11 22:12:50.029368", + "modified": "2019-05-10 03:22:57.283628", "modified_by": "Administrator", "module": "CRM", "name": "Lead", diff --git a/erpnext/crm/doctype/lead/lead.py b/erpnext/crm/doctype/lead/lead.py index d42502dc3ba..6e98ebb6c09 100644 --- a/erpnext/crm/doctype/lead/lead.py +++ b/erpnext/crm/doctype/lead/lead.py @@ -109,7 +109,11 @@ class Lead(SellingController): def set_lead_name(self): if not self.lead_name: - frappe.db.set_value("Lead", self.name, "lead_name", self.company_name) + # Check for leads being created through data import + if not self.company_name: + frappe.throw(_("A Lead requires either a person's name or an organization's name")) + + self.lead_name = self.company_name @frappe.whitelist() def make_customer(source_name, target_doc=None): @@ -225,4 +229,4 @@ def make_lead_from_communication(communication, ignore_communication_links=False lead_name = lead.name link_communication_to_document(doc, "Lead", lead_name, ignore_communication_links) - return lead_name \ No newline at end of file + return lead_name diff --git a/erpnext/hr/doctype/hr_settings/hr_settings.js b/erpnext/hr/doctype/hr_settings/hr_settings.js index 6ab523eb763..58ce4226e91 100644 --- a/erpnext/hr/doctype/hr_settings/hr_settings.js +++ b/erpnext/hr/doctype/hr_settings/hr_settings.js @@ -4,5 +4,18 @@ frappe.ui.form.on('HR Settings', { refresh: function(frm) { + }, + + encrypt_salary_slips_in_emails: function(frm) { + let encrypt_state = frm.doc.encrypt_salary_slips_in_emails; + frm.set_df_property('password_policy', 'reqd', encrypt_state); + }, + + validate: function(frm) { + let policy = frm.doc.password_policy; + if (policy.includes(' ') || policy.includes('--')) { + frappe.msgprint("Password policy cannot contain spaces or simultaneous hyphens. The format will be restructured automatically"); + } + frm.set_value('password_policy', policy.split(new RegExp(" |-", 'g')).filter((token) => token).join('-')); } }); diff --git a/erpnext/hr/doctype/hr_settings/hr_settings.json b/erpnext/hr/doctype/hr_settings/hr_settings.json index 225785d305d..5502ce81e34 100644 --- a/erpnext/hr/doctype/hr_settings/hr_settings.json +++ b/erpnext/hr/doctype/hr_settings/hr_settings.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 0, "allow_rename": 0, @@ -13,10 +14,12 @@ "fields": [ { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "employee_settings", "fieldtype": "Section Break", "hidden": 0, @@ -43,12 +46,14 @@ }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, "columns": 0, "default": "", "description": "Enter retirement age in years", + "fetch_if_empty": 0, "fieldname": "retirement_age", "fieldtype": "Data", "hidden": 0, @@ -76,12 +81,14 @@ }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, "columns": 0, "default": "Naming Series", "description": "Employee record is created using selected field. ", + "fetch_if_empty": 0, "fieldname": "emp_created_by", "fieldtype": "Select", "hidden": 0, @@ -109,11 +116,13 @@ }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, "columns": 0, "default": "", + "fetch_if_empty": 0, "fieldname": "leave_approval_notification_template", "fieldtype": "Link", "hidden": 0, @@ -142,10 +151,12 @@ }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "leave_status_notification_template", "fieldtype": "Link", "hidden": 0, @@ -174,10 +185,12 @@ }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "column_break_4", "fieldtype": "Column Break", "hidden": 0, @@ -204,11 +217,13 @@ }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, "columns": 0, "description": "Don't send Employee Birthday Reminders", + "fetch_if_empty": 0, "fieldname": "stop_birthday_reminders", "fieldtype": "Check", "hidden": 0, @@ -235,10 +250,12 @@ }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "maintain_bill_work_hours_same", "fieldtype": "Check", "hidden": 0, @@ -266,11 +283,13 @@ }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, "columns": 0, "default": "1", + "fetch_if_empty": 0, "fieldname": "leave_approver_mandatory_in_leave_application", "fieldtype": "Check", "hidden": 0, @@ -298,11 +317,13 @@ }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, "columns": 0, "default": "1", + "fetch_if_empty": 0, "fieldname": "expense_approver_mandatory_in_expense_claim", "fieldtype": "Check", "hidden": 0, @@ -330,10 +351,13 @@ }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, "columns": 0, + "depends_on": "", + "fetch_if_empty": 0, "fieldname": "payroll_settings", "fieldtype": "Section Break", "hidden": 0, @@ -360,11 +384,13 @@ }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, "columns": 0, "description": "If checked, Total no. of Working Days will include holidays, and this will reduce the value of Salary Per Day", + "fetch_if_empty": 0, "fieldname": "include_holidays_in_total_working_days", "fieldtype": "Check", "hidden": 0, @@ -391,12 +417,14 @@ }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, "columns": 0, "default": "1", "description": "Emails salary slip to employee based on preferred email selected in Employee", + "fetch_if_empty": 0, "fieldname": "email_salary_slip_to_employee", "fieldtype": "Check", "hidden": 0, @@ -424,10 +452,82 @@ }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, "columns": 0, + "depends_on": "eval: doc.email_salary_slip_to_employee == 1;", + "description": "The salary slip emailed to the employee will be password protected, the password will be generated based on the password policy.", + "fetch_if_empty": 0, + "fieldname": "encrypt_salary_slips_in_emails", + "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": "Encrypt Salary Slips in Emails", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "eval: doc.encrypt_salary_slips_in_emails == 1", + "description": "Example: SAL-{first_name}-{date_of_birth.year}
This will generate a password like SAL-Jane-1972", + "fetch_if_empty": 0, + "fieldname": "password_policy", + "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": "Password Policy", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fetch_if_empty": 0, "fieldname": "max_working_hours_against_timesheet", "fieldtype": "Float", "hidden": 0, @@ -455,10 +555,12 @@ }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "leave_settings", "fieldtype": "Section Break", "hidden": 0, @@ -481,14 +583,17 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, "columns": 0, + "fetch_if_empty": 0, "fieldname": "show_leaves_of_all_department_members_in_calendar", "fieldtype": "Check", "hidden": 0, @@ -511,22 +616,21 @@ "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, "is_submittable": 0, "issingle": 1, "istable": 0, "max_attachments": 0, - "modified": "2018-05-03 15:36:13.015466", - "modified_by": "Administrator", + "modified": "2019-04-25 15:08:12.983571", + "modified_by": "shivam@example.com", "module": "HR", "name": "HR Settings", "owner": "Administrator", @@ -553,9 +657,9 @@ ], "quick_entry": 0, "read_only": 0, - "read_only_onload": 0, "show_name_in_global_search": 0, "sort_order": "ASC", "track_changes": 0, - "track_seen": 0 + "track_seen": 0, + "track_views": 0 } \ No newline at end of file diff --git a/erpnext/hr/doctype/hr_settings/hr_settings.py b/erpnext/hr/doctype/hr_settings/hr_settings.py index 964eaee7ed0..78095b30869 100644 --- a/erpnext/hr/doctype/hr_settings/hr_settings.py +++ b/erpnext/hr/doctype/hr_settings/hr_settings.py @@ -5,11 +5,21 @@ from __future__ import unicode_literals import frappe +from frappe import _ from frappe.model.document import Document class HRSettings(Document): def validate(self): + self.set_naming_series() + self.validate_password_policy() + + def set_naming_series(self): from erpnext.setup.doctype.naming_series.naming_series import set_by_naming_series set_by_naming_series("Employee", "employee_number", self.get("emp_created_by")=="Naming Series", hide_name_field=True) + + def validate_password_policy(self): + if self.email_salary_slip_to_employee and self.encrypt_salary_slips_in_emails: + if not self.password_policy: + frappe.throw(_("Password policy for Salary Slips is not set")) \ 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 fbfa3af6cd9..5f6ddfc8fc3 100644 --- a/erpnext/hr/doctype/salary_slip/salary_slip.py +++ b/erpnext/hr/doctype/salary_slip/salary_slip.py @@ -520,13 +520,20 @@ class SalarySlip(TransactionBase): def email_salary_slip(self): receiver = frappe.db.get_value("Employee", self.employee, "prefered_email") + hr_settings = frappe.get_single("HR Settings") + message = "Please see attachment" + password = None + if hr_settings.encrypt_salary_slips_in_emails: + password = generate_password_for_pdf(hr_settings.password_policy, self.employee) + message += """
Note: Your salary slip is password protected, + the password to unlock the PDF is of the format {0}. """.format(hr_settings.password_policy) if receiver: email_args = { "recipients": [receiver], - "message": _("Please see attachment"), + "message": _(message), "subject": 'Salary Slip - from {0} to {1}'.format(self.start_date, self.end_date), - "attachments": [frappe.attach_print(self.doctype, self.name, file_name=self.name)], + "attachments": [frappe.attach_print(self.doctype, self.name, file_name=self.name, password=password)], "reference_doctype": self.doctype, "reference_name": self.name } @@ -843,3 +850,7 @@ def unlink_ref_doc_from_salary_slip(ref_no): for ss in linked_ss: ss_doc = frappe.get_doc("Salary Slip", ss) frappe.db.set_value("Salary Slip", ss_doc.name, "journal_entry", "") + +def generate_password_for_pdf(policy_template, employee): + employee = frappe.get_doc("Employee", employee) + return policy_template.format(**employee.as_dict()) diff --git a/erpnext/hr/doctype/training_event/training_event.py b/erpnext/hr/doctype/training_event/training_event.py index 1b13b70f5bd..5064f033081 100644 --- a/erpnext/hr/doctype/training_event/training_event.py +++ b/erpnext/hr/doctype/training_event/training_event.py @@ -5,9 +5,19 @@ from __future__ import unicode_literals import frappe from frappe.model.document import Document +from frappe import _ +from frappe.utils import time_diff_in_seconds from erpnext.hr.doctype.employee.employee import get_employee_emails class TrainingEvent(Document): def validate(self): + self.set_employee_emails() + self.validate_period() + + def set_employee_emails(self): self.employee_emails = ', '.join(get_employee_emails([d.employee for d in self.employees])) + + def validate_period(self): + if time_diff_in_seconds(self.end_time, self.start_time) <= 0: + frappe.throw(_('End time cannot be before start time')) \ No newline at end of file diff --git a/erpnext/manufacturing/notification/__init__.py b/erpnext/manufacturing/notification/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/manufacturing/notification/material_request_receipt_notification/__init__.py b/erpnext/manufacturing/notification/material_request_receipt_notification/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/manufacturing/notification/material_request_receipt_notification/material_request_receipt_notification.json b/erpnext/manufacturing/notification/material_request_receipt_notification/material_request_receipt_notification.json new file mode 100644 index 00000000000..5391a31497a --- /dev/null +++ b/erpnext/manufacturing/notification/material_request_receipt_notification/material_request_receipt_notification.json @@ -0,0 +1,29 @@ +{ + "attach_print": 0, + "channel": "Email", + "condition": "doc.status == \"Received\" or doc.status == \"Partially Received\"", + "creation": "2019-04-29 11:53:23.981418", + "days_in_advance": 0, + "docstatus": 0, + "doctype": "Notification", + "document_type": "Material Request", + "enabled": 1, + "event": "Value Change", + "idx": 0, + "is_standard": 1, + "message": "Material Request Type: {{ doc.material_request_type }}
\nCompany: {{ doc.company }}\n\n

Order Summary

\n\n\n \n \n \n \n {% for item in doc.items %}\n {% if frappe.utils.flt(item.received_qty, 2) > 0.0 %}\n \n \n \n \n {% endif %}\n {% endfor %}\n
Item NameReceived Quantity
{{ item.item_code }}{{ frappe.utils.flt(item.received_qty, 2) }}
", + "method": "", + "modified": "2019-05-01 18:02:51.090037", + "modified_by": "Administrator", + "module": "Manufacturing", + "name": "Material Request Receipt Notification", + "owner": "Administrator", + "recipients": [ + { + "email_by_document_field": "requested_by" + } + ], + "sender_email": "", + "subject": "{{ doc.name }} has been received", + "value_changed": "status" +} \ No newline at end of file diff --git a/erpnext/manufacturing/notification/material_request_receipt_notification/material_request_receipt_notification.md b/erpnext/manufacturing/notification/material_request_receipt_notification/material_request_receipt_notification.md new file mode 100644 index 00000000000..e6feee971d6 --- /dev/null +++ b/erpnext/manufacturing/notification/material_request_receipt_notification/material_request_receipt_notification.md @@ -0,0 +1,19 @@ +Material Request Type: {{ doc.material_request_type }}
+Company: {{ doc.company }} + +

Order Summary

+ + + + + + + {% for item in doc.items %} + {% if frappe.utils.flt(item.received_qty, 2) > 0.0 %} + + + + + {% endif %} + {% endfor %} +
Item NameReceived Quantity
{{ item.item_code }}{{ frappe.utils.flt(item.received_qty, 2) }}
\ No newline at end of file diff --git a/erpnext/manufacturing/notification/material_request_receipt_notification/material_request_receipt_notification.py b/erpnext/manufacturing/notification/material_request_receipt_notification/material_request_receipt_notification.py new file mode 100644 index 00000000000..2334f8b26d8 --- /dev/null +++ b/erpnext/manufacturing/notification/material_request_receipt_notification/material_request_receipt_notification.py @@ -0,0 +1,7 @@ +from __future__ import unicode_literals + +import frappe + +def get_context(context): + # do your magic here + pass diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 97ad26e0839..bdc1ed4f100 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -512,6 +512,7 @@ erpnext.patches.v11_0.rename_employee_loan_to_loan erpnext.patches.v11_0.move_leave_approvers_from_employee #13-06-2018 erpnext.patches.v11_0.update_department_lft_rgt erpnext.patches.v11_0.add_default_email_template_for_leave +execute:frappe.reload_doc("HR", "doctype", "HR Settings") erpnext.patches.v11_0.set_default_email_template_in_hr #08-06-2018 erpnext.patches.v11_0.uom_conversion_data #30-06-2018 erpnext.patches.v10_0.taxes_issue_with_pos @@ -600,3 +601,4 @@ erpnext.patches.v11_1.woocommerce_set_creation_user erpnext.patches.v11_1.set_salary_details_submittable erpnext.patches.v11_1.rename_depends_on_lwp execute:frappe.delete_doc("Report", "Inactive Items") +erpnext.patches.v11_1.delete_scheduling_tool diff --git a/erpnext/patches/v11_0/set_default_email_template_in_hr.py b/erpnext/patches/v11_0/set_default_email_template_in_hr.py index e895eaeb653..14954fbeb31 100644 --- a/erpnext/patches/v11_0/set_default_email_template_in_hr.py +++ b/erpnext/patches/v11_0/set_default_email_template_in_hr.py @@ -2,7 +2,6 @@ from __future__ import unicode_literals import frappe def execute(): - hr_settings = frappe.get_single("HR Settings") hr_settings.leave_approval_notification_template = "Leave Approval Notification" hr_settings.leave_status_notification_template = "Leave Status Notification" diff --git a/erpnext/patches/v11_1/delete_scheduling_tool.py b/erpnext/patches/v11_1/delete_scheduling_tool.py new file mode 100644 index 00000000000..b7ad28a3fd6 --- /dev/null +++ b/erpnext/patches/v11_1/delete_scheduling_tool.py @@ -0,0 +1,9 @@ +# 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 + +def execute(): + if frappe.db.exists("DocType", "Scheduling Tool"): + frappe.delete_doc("DocType", "Scheduling Tool", ignore_permissions=True) diff --git a/erpnext/portal/product_configurator/item_variants_cache.py b/erpnext/portal/product_configurator/item_variants_cache.py index 39f0803812d..f33c8d605b4 100644 --- a/erpnext/portal/product_configurator/item_variants_cache.py +++ b/erpnext/portal/product_configurator/item_variants_cache.py @@ -66,15 +66,14 @@ class ItemVariantsCacheManager: as_list=1 ) - disabled_items = [i.name for i in frappe.db.get_all('Item', {'disabled': 1})] + disabled_items = set([i.name for i in frappe.db.get_all('Item', {'disabled': 1})]) attribute_value_item_map = frappe._dict({}) item_attribute_value_map = frappe._dict({}) + item_variants_data = [r for r in item_variants_data if r[0] not in disabled_items] for row in item_variants_data: item_code, attribute, attribute_value = row - if item_code in disabled_items: - continue # (attr, value) => [item1, item2] attribute_value_item_map.setdefault((attribute, attribute_value), []).append(item_code) # item => {attr1: value1, attr2: value2} @@ -97,6 +96,10 @@ class ItemVariantsCacheManager: for key in keys: frappe.cache().hdel(key, self.item_code) + def rebuild_cache(self): + self.clear_cache() + enqueue_build_cache(self.item_code) + def build_cache(item_code): frappe.cache().hset('item_cache_build_in_progress', item_code, 1) diff --git a/erpnext/portal/product_configurator/utils.py b/erpnext/portal/product_configurator/utils.py index 405a6d8c31c..61c50e5fe01 100644 --- a/erpnext/portal/product_configurator/utils.py +++ b/erpnext/portal/product_configurator/utils.py @@ -102,6 +102,9 @@ def get_item_codes_by_attributes(attribute_filters, template_item_code=None): for attribute, values in attribute_filters.items(): attribute_values = values + if not isinstance(attribute_values, list): + attribute_values = [attribute_values] + if not attribute_values: continue wheres = [] @@ -257,7 +260,8 @@ def get_items_with_selected_attributes(item_code, selected_attributes): items = [] for attribute, value in selected_attributes.items(): - items.append(set(attribute_value_item_map[(attribute, value)])) + filtered_items = attribute_value_item_map.get((attribute, value), []) + items.append(set(filtered_items)) return set.intersection(*items) diff --git a/erpnext/projects/doctype/project/project.js b/erpnext/projects/doctype/project/project.js index 6de6454a0e8..528c7cd0c71 100644 --- a/erpnext/projects/doctype/project/project.js +++ b/erpnext/projects/doctype/project/project.js @@ -109,6 +109,18 @@ frappe.ui.form.on("Project", { } }); }, + + status: function(frm) { + if (frm.doc.status === 'Cancelled') { + frappe.confirm(__('Set tasks in this project as cancelled?'), () => { + frm.doc.tasks = frm.doc.tasks.map(task => { + task.status = 'Cancelled'; + return task; + }); + frm.refresh_field('tasks'); + }); + } + } }); frappe.ui.form.on("Project Task", { diff --git a/erpnext/projects/doctype/project/project.py b/erpnext/projects/doctype/project/project.py index 9b92bda39fd..a66fac31c56 100644 --- a/erpnext/projects/doctype/project/project.py +++ b/erpnext/projects/doctype/project/project.py @@ -35,6 +35,9 @@ class Project(Document): def load_tasks(self): """Load `tasks` from the database""" + if frappe.flags.in_import: + return + self.tasks = [] for task in self.get_tasks(): task_map = { @@ -358,7 +361,8 @@ class Project(Document): if not self.get('deleted_task_list'): return for d in self.get('deleted_task_list'): - frappe.delete_doc("Task", d) + # unlink project + frappe.db.set_value('Task', d, 'project', '') self.deleted_task_list = [] @@ -481,16 +485,17 @@ def daily_reminder(): projects = get_projects_for_collect_progress("Daily", fields) for project in projects: - if not check_project_update_exists(project.name, project.get("daily_time_to_send")): + if allow_to_make_project_update(project.name, project.get("daily_time_to_send"), "Daily"): send_project_update_email_to_users(project.name) def twice_daily_reminder(): fields = ["first_email", "second_email"] projects = get_projects_for_collect_progress("Twice Daily", fields) + fields.remove("name") for project in projects: for d in fields: - if not check_project_update_exists(project.name, project.get(d)): + if allow_to_make_project_update(project.name, project.get(d), "Twicely"): send_project_update_email_to_users(project.name) def weekly_reminder(): @@ -502,14 +507,19 @@ def weekly_reminder(): if current_day != project.day_to_send: continue - if not check_project_update_exists(project.name, project.get("weekly_time_to_send")): + if allow_to_make_project_update(project.name, project.get("weekly_time_to_send"), "Weekly"): send_project_update_email_to_users(project.name) -def check_project_update_exists(project, time): +def allow_to_make_project_update(project, time, frequency): data = frappe.db.sql(""" SELECT name from `tabProject Update` - WHERE project = %s and date = %s and time >= %s """, (project, today(), time)) + WHERE project = %s and date = %s """, (project, today())) - return True if data and data[0][0] else False + # len(data) > 1 condition is checked for twicely frequency + if data and (frequency in ['Daily', 'Weekly'] or len(data) > 1): + return False + + if get_time(nowtime()) >= get_time(time): + return True def get_projects_for_collect_progress(frequency, fields): fields.extend(["name"]) diff --git a/erpnext/projects/doctype/task/task.py b/erpnext/projects/doctype/task/task.py index 84ee7151989..fa9a5a59af5 100755 --- a/erpnext/projects/doctype/task/task.py +++ b/erpnext/projects/doctype/task/task.py @@ -105,7 +105,7 @@ class Task(NestedSet): def update_project(self): if self.project and not self.flags.from_project: - frappe.get_doc("Project", self.project).update_project() + frappe.get_cached_doc("Project", self.project).update_project() def check_recursion(self): if self.flags.ignore_recursion_check: return @@ -150,7 +150,7 @@ class Task(NestedSet): def populate_depends_on(self): if self.parent_task: - parent = frappe.get_doc('Task', self.parent_task) + parent = frappe.get_cached_doc('Task', self.parent_task) if not self.name in [row.task for row in parent.depends_on]: parent.append("depends_on", { "doctype": "Task Depends On", diff --git a/erpnext/public/js/utils/item_quick_entry.js b/erpnext/public/js/utils/item_quick_entry.js index 62b82ac0124..2947d5b98eb 100644 --- a/erpnext/public/js/utils/item_quick_entry.js +++ b/erpnext/public/js/utils/item_quick_entry.js @@ -390,15 +390,6 @@ frappe.ui.form.ItemQuickEntryForm = frappe.ui.form.QuickEntryForm.extend({ } }) - if (mandatory.length) { - frappe.msgprint({ - title: __('Missing Values Required'), - message: __('Following fields have missing values:') + '

', - indicator: 'orange' - }); - return {}; - } - if (this.is_manufacturer) { $.each(this.manufacturer_fields, function(index, field) { attribute[field.fieldname] = me.dialog.fields_dict[field.fieldname].input.value; diff --git a/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py b/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py index 7faabf43ec9..01da810d76f 100644 --- a/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py +++ b/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py @@ -227,18 +227,18 @@ class GSTR3BReport(Document): for d in inter_state_supply.get("Unregistered", []): self.report_dict["inter_sup"]["unreg_details"].append(d) - self.report_dict["sup_details"]["osup_det"]["txval"] += d["txval"] - self.report_dict["sup_details"]["osup_det"]["iamt"] += d["iamt"] + self.report_dict["sup_details"]["osup_det"]["txval"] += flt(d["txval"], 2) + self.report_dict["sup_details"]["osup_det"]["iamt"] += flt(d["iamt"], 2) for d in inter_state_supply.get("Registered Composition", []): self.report_dict["inter_sup"]["comp_details"].append(d) - self.report_dict["sup_details"]["osup_det"]["txval"] += d["txval"] - self.report_dict["sup_details"]["osup_det"]["iamt"] += d["iamt"] + self.report_dict["sup_details"]["osup_det"]["txval"] += flt(d["txval"], 2) + self.report_dict["sup_details"]["osup_det"]["iamt"] += flt(d["iamt"], 2) for d in inter_state_supply.get("UIN Holders", []): self.report_dict["inter_sup"]["uin_details"].append(d) - self.report_dict["sup_details"]["osup_det"]["txval"] += d["txval"] - self.report_dict["sup_details"]["osup_det"]["iamt"] += d["iamt"] + self.report_dict["sup_details"]["osup_det"]["txval"] += flt(d["txval"], 2) + self.report_dict["sup_details"]["osup_det"]["iamt"] += flt(d["iamt"], 2) def get_total_taxable_value(self, doctype, reverse_charge): diff --git a/erpnext/regional/report/gstr_1/gstr_1.py b/erpnext/regional/report/gstr_1/gstr_1.py index a29d5b48a98..f6c4782e241 100644 --- a/erpnext/regional/report/gstr_1/gstr_1.py +++ b/erpnext/regional/report/gstr_1/gstr_1.py @@ -29,10 +29,10 @@ class Gstr1Report(object): place_of_supply, ecommerce_gstin, reverse_charge, - gst_category, + invoice_type, return_against, is_return, - gst_category, + invoice_type, export_type, port_code, shipping_bill_number, @@ -324,8 +324,8 @@ class Gstr1Report(object): "fieldtype": "Data" }, { - "fieldname": "gst_category", - "label": "GST Category", + "fieldname": "invoice_type", + "label": "Invoice Type", "fieldtype": "Data" }, { @@ -577,7 +577,7 @@ def get_json(): download_json_file(report_name, filters["type_of_business"], gst_json) def get_b2b_json(res, gstin): - inv_type, out = {"Registered Regular": "R", "Deemed Export": "DE", "URD": "URD", "SEZ": "SEZ"}, [] + inv_type, out = {"Regular": "R", "Deemed Export": "DE", "URD": "URD", "SEZ": "SEZ"}, [] for gst_in in res: b2b_item, inv = {"ctin": gst_in, "inv": []}, [] if not gst_in: continue @@ -586,7 +586,7 @@ def get_b2b_json(res, gstin): inv_item = get_basic_invoice_detail(invoice[0]) inv_item["pos"] = "%02d" % int(invoice[0]["place_of_supply"].split('-')[0]) inv_item["rchrg"] = invoice[0]["reverse_charge"] - inv_item["inv_typ"] = inv_type.get(invoice[0].get("gst_category", ""),"") + inv_item["inv_typ"] = inv_type.get(invoice[0].get("invoice_type", ""),"") if inv_item["pos"]=="00": continue inv_item["itms"] = [] diff --git a/erpnext/selling/doctype/customer/customer.js b/erpnext/selling/doctype/customer/customer.js index 031cf143cc6..178a21d4749 100644 --- a/erpnext/selling/doctype/customer/customer.js +++ b/erpnext/selling/doctype/customer/customer.js @@ -123,5 +123,6 @@ frappe.ui.form.on("Customer", { }, validate: function(frm) { if(frm.doc.lead_name) frappe.model.clear_doc("Lead", frm.doc.lead_name); + }, }); \ No newline at end of file diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py index ba20cbc73ee..365c2ed2494 100644 --- a/erpnext/selling/doctype/customer/customer.py +++ b/erpnext/selling/doctype/customer/customer.py @@ -60,6 +60,10 @@ class Customer(TransactionBase): if self.loyalty_program == customer.loyalty_program and not self.loyalty_program_tier: self.loyalty_program_tier = customer.loyalty_program_tier + if self.sales_team: + if sum([member.allocated_percentage for member in self.sales_team]) != 100: + frappe.throw(_("Total contribution percentage should be equal to 100")) + def check_customer_group_change(self): frappe.flags.customer_group_changed = False diff --git a/erpnext/stock/doctype/item/item.js b/erpnext/stock/doctype/item/item.js index 6c30d00d231..42c84da9335 100644 --- a/erpnext/stock/doctype/item/item.js +++ b/erpnext/stock/doctype/item/item.js @@ -585,7 +585,7 @@ $.extend(erpnext.item, { "label": row.attribute, "fieldname": row.attribute, "fieldtype": fieldtype, - "reqd": 1, + "reqd": 0, "description": desc }) } @@ -600,6 +600,7 @@ $.extend(erpnext.item, { if(!args) return; frappe.call({ method:"erpnext.controllers.item_variant.get_variant", + btn: d.get_primary_btn(), args: { "template": frm.doc.name, "args": d.get_values() diff --git a/erpnext/stock/doctype/item/item.json b/erpnext/stock/doctype/item/item.json index 9d0bd9d5064..07063444a19 100644 --- a/erpnext/stock/doctype/item/item.json +++ b/erpnext/stock/doctype/item/item.json @@ -3552,7 +3552,7 @@ "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, - "search_index": 0, + "search_index": 1, "set_only_once": 0, "translatable": 0, "unique": 0 @@ -3585,7 +3585,7 @@ "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, - "search_index": 0, + "search_index": 1, "set_only_once": 0, "translatable": 0, "unique": 0 @@ -4272,7 +4272,7 @@ "issingle": 0, "istable": 0, "max_attachments": 1, - "modified": "2019-04-08 11:47:59.269724", + "modified": "2019-05-09 18:47:30.475833", "modified_by": "Administrator", "module": "Stock", "name": "Item", diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py index ed02cee3a4a..5d4dbf4e76e 100644 --- a/erpnext/stock/doctype/item/item.py +++ b/erpnext/stock/doctype/item/item.py @@ -800,10 +800,12 @@ class Item(WebsiteGenerator): def validate_variant_attributes(self): if self.is_new() and self.variant_of and self.variant_based_on == 'Item Attribute': + # remove attributes with no attribute_value set + self.attributes = [d for d in self.attributes if cstr(d.attribute_value).strip()] + args = {} - for d in self.attributes: - if cstr(d.attribute_value).strip() == '': - frappe.throw(_("Please specify Attribute Value for attribute {0}").format(d.attribute)) + for i, d in enumerate(self.attributes): + d.idx = i + 1 args[d.attribute] = d.attribute_value variant = get_variant(self.variant_of, args, self.name) @@ -964,7 +966,7 @@ def invalidate_item_variants_cache_for_website(doc): if item_code: item_cache = ItemVariantsCacheManager(item_code) - item_cache.clear_cache() + item_cache.rebuild_cache() def check_stock_uom_with_bin(item, stock_uom): diff --git a/erpnext/stock/doctype/material_request/material_request.json b/erpnext/stock/doctype/material_request/material_request.json index d50404eb786..d0025d12ab0 100644 --- a/erpnext/stock/doctype/material_request/material_request.json +++ b/erpnext/stock/doctype/material_request/material_request.json @@ -1,990 +1,350 @@ { - "allow_copy": 0, - "allow_events_in_timeline": 0, - "allow_guest_to_view": 0, "allow_import": 1, - "allow_rename": 0, "autoname": "naming_series:", - "beta": 0, "creation": "2013-03-07 14:48:38", - "custom": 0, - "docstatus": 0, "doctype": "DocType", "document_type": "Document", - "editable_grid": 0, + "field_order": [ + "type_section", + "naming_series", + "title", + "material_request_type", + "customer", + "column_break_2", + "schedule_date", + "company", + "amended_from", + "items_section", + "scan_barcode", + "items", + "more_info", + "requested_by", + "transaction_date", + "column_break2", + "status", + "per_ordered", + "per_received", + "printing_details", + "letter_head", + "select_print_heading", + "terms_section_break", + "tc_name", + "terms", + "reference", + "job_card" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "type_section", - "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, - "options": "fa fa-pushpin", - "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 - }, + "fieldname": "type_section", + "fieldtype": "Section Break", + "options": "fa fa-pushpin" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "", - "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": "Series", - "length": 0, - "no_copy": 1, - "oldfieldname": "naming_series", - "oldfieldtype": "Select", - "options": "MAT-MR-.YYYY.-", - "permlevel": 0, - "print_hide": 1, - "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": 1, - "translatable": 0, - "unique": 0 - }, + "fieldname": "naming_series", + "fieldtype": "Select", + "label": "Series", + "no_copy": 1, + "oldfieldname": "naming_series", + "oldfieldtype": "Select", + "options": "MAT-MR-.YYYY.-", + "print_hide": 1, + "reqd": 1, + "set_only_once": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 1, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "{material_request_type}", - "fieldname": "title", - "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": "Title", - "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": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "allow_on_submit": 1, + "default": "{material_request_type}", + "fieldname": "title", + "fieldtype": "Data", + "hidden": 1, + "label": "Title", + "no_copy": 1, + "print_hide": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "material_request_type", - "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": "Type", - "length": 0, - "no_copy": 0, - "options": "Purchase\nMaterial Transfer\nMaterial Issue\nManufacture\nCustomer Provided", - "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 - }, + "fieldname": "material_request_type", + "fieldtype": "Select", + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Type", + "options": "Purchase\nMaterial Transfer\nMaterial Issue\nManufacture\nCustomer Provided", + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "eval:doc.material_request_type==\"Customer Provided\"", - "fieldname": "customer", - "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": "Customer", - "length": 0, - "no_copy": 0, - "options": "Customer", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "depends_on": "eval:doc.material_request_type==\"Customer Provided\"", + "fieldname": "customer", + "fieldtype": "Link", + "label": "Customer", + "options": "Customer" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break_2", - "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 - }, + "fieldname": "column_break_2", + "fieldtype": "Column Break" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 1, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "schedule_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": "Required 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_on_submit": 1, + "fieldname": "schedule_date", + "fieldtype": "Date", + "label": "Required Date" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "description": "", - "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, - "oldfieldname": "company", - "oldfieldtype": "Link", - "options": "Company", - "permlevel": 0, - "print_hide": 1, - "print_hide_if_no_value": 0, - "print_width": "150px", - "read_only": 0, - "remember_last_selected_value": 1, - "report_hide": 0, - "reqd": 1, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0, + "fieldname": "company", + "fieldtype": "Link", + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Company", + "oldfieldname": "company", + "oldfieldtype": "Link", + "options": "Company", + "print_hide": 1, + "print_width": "150px", + "remember_last_selected_value": 1, + "reqd": 1, + "search_index": 1, "width": "150px" - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "amended_from", - "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": "Amended From", - "length": 0, - "no_copy": 1, - "oldfieldname": "amended_from", - "oldfieldtype": "Data", - "options": "Material Request", - "permlevel": 0, - "print_hide": 1, - "print_hide_if_no_value": 0, - "print_width": "150px", - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0, + "fieldname": "amended_from", + "fieldtype": "Link", + "ignore_user_permissions": 1, + "label": "Amended From", + "no_copy": 1, + "oldfieldname": "amended_from", + "oldfieldtype": "Data", + "options": "Material Request", + "print_hide": 1, + "print_width": "150px", + "read_only": 1, "width": "150px" - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "items_section", - "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, - "oldfieldtype": "Section Break", - "options": "fa fa-shopping-cart", - "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 - }, + "fieldname": "items_section", + "fieldtype": "Section Break", + "oldfieldtype": "Section Break", + "options": "fa fa-shopping-cart" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "scan_barcode", "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": "Scan Barcode", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Scan Barcode" }, { "allow_bulk_edit": 1, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "items", "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": "Items", - "length": 0, - "no_copy": 0, "oldfieldname": "indent_details", "oldfieldtype": "Table", "options": "Material Request Item", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, + "reqd": 1 + }, + { + "collapsible": 1, + "fieldname": "more_info", + "fieldtype": "Section Break", + "label": "More Information", + "oldfieldtype": "Section Break", + "options": "fa fa-file-text" + }, + { + "fieldname": "requested_by", + "fieldtype": "Data", + "in_standard_filter": 1, + "label": "Requested For", + "options": "Email" + }, + { + "default": "Today", + "fieldname": "transaction_date", + "fieldtype": "Date", + "in_list_view": 1, + "label": "Transaction Date", + "no_copy": 1, + "oldfieldname": "transaction_date", + "oldfieldtype": "Date", + "print_width": "100px", "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 1, - "columns": 0, - "fieldname": "more_info", - "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": "More Information", - "length": 0, - "no_copy": 0, - "oldfieldtype": "Section Break", - "options": "fa fa-file-text", - "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_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "requested_by", - "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": 1, - "label": "Requested For", - "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_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "Today", - "fieldname": "transaction_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": "Transaction Date", - "length": 0, - "no_copy": 1, - "oldfieldname": "transaction_date", - "oldfieldtype": "Date", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "print_width": "100px", - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0, + "search_index": 1, "width": "100px" - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break2", - "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, - "oldfieldtype": "Column Break", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "print_width": "50%", - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0, + "fieldname": "column_break2", + "fieldtype": "Column Break", + "oldfieldtype": "Column Break", + "print_width": "50%", "width": "50%" - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "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": 1, - "label": "Status", - "length": 0, - "no_copy": 1, - "oldfieldname": "status", - "oldfieldtype": "Select", - "options": "\nDraft\nSubmitted\nStopped\nCancelled\nPending\nPartially Ordered\nOrdered\nIssued\nTransferred\nReceived", - "permlevel": 0, - "print_hide": 1, - "print_hide_if_no_value": 0, - "print_width": "100px", - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0, + "fieldname": "status", + "fieldtype": "Select", + "in_standard_filter": 1, + "label": "Status", + "no_copy": 1, + "oldfieldname": "status", + "oldfieldtype": "Select", + "options": "\nDraft\nSubmitted\nStopped\nCancelled\nPending\nPartially Ordered\nOrdered\nIssued\nTransferred\nReceived", + "print_hide": 1, + "print_width": "100px", + "read_only": 1, + "search_index": 1, "width": "100px" - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "description": "", - "fieldname": "per_ordered", - "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": "% Ordered", - "length": 0, - "no_copy": 1, - "oldfieldname": "per_ordered", - "oldfieldtype": "Currency", - "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 - }, + "fieldname": "per_ordered", + "fieldtype": "Percent", + "label": "% Ordered", + "no_copy": 1, + "oldfieldname": "per_ordered", + "oldfieldtype": "Currency", + "print_hide": 1, + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 1, - "columns": 0, - "fieldname": "printing_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": "Printing 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, - "translatable": 0, - "unique": 0 - }, + "fieldname": "per_received", + "fieldtype": "Percent", + "label": "% Received", + "no_copy": 1, + "print_hide": 1, + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 1, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "letter_head", - "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": "Letter Head", - "length": 0, - "no_copy": 0, - "oldfieldname": "letter_head", - "oldfieldtype": "Select", - "options": "Letter Head", - "permlevel": 0, - "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 - }, + "collapsible": 1, + "fieldname": "printing_details", + "fieldtype": "Section Break", + "label": "Printing Details" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 1, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "select_print_heading", - "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": "Print Heading", - "length": 0, - "no_copy": 0, - "options": "Print Heading", - "permlevel": 0, - "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_on_submit": 1, + "fieldname": "letter_head", + "fieldtype": "Link", + "label": "Letter Head", + "oldfieldname": "letter_head", + "oldfieldtype": "Select", + "options": "Letter Head", + "print_hide": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 1, - "collapsible_depends_on": "terms", - "columns": 0, - "fieldname": "terms_section_break", - "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": "Terms and Conditions", - "length": 0, - "no_copy": 0, - "oldfieldtype": "Section Break", - "options": "fa fa-legal", - "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_on_submit": 1, + "fieldname": "select_print_heading", + "fieldtype": "Link", + "label": "Print Heading", + "options": "Print Heading", + "print_hide": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "tc_name", - "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": "Terms", - "length": 0, - "no_copy": 0, - "oldfieldname": "tc_name", - "oldfieldtype": "Link", - "options": "Terms and Conditions", - "permlevel": 0, - "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 - }, + "collapsible": 1, + "collapsible_depends_on": "terms", + "fieldname": "terms_section_break", + "fieldtype": "Section Break", + "label": "Terms and Conditions", + "oldfieldtype": "Section Break", + "options": "fa fa-legal" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "terms", - "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": "Terms and Conditions Content", - "length": 0, - "no_copy": 0, - "oldfieldname": "terms", - "oldfieldtype": "Text Editor", - "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 - }, + "fieldname": "tc_name", + "fieldtype": "Link", + "label": "Terms", + "oldfieldname": "tc_name", + "oldfieldtype": "Link", + "options": "Terms and Conditions", + "print_hide": 1, + "report_hide": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 1, - "columns": 0, - "fieldname": "reference", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Reference", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "terms", + "fieldtype": "Text Editor", + "label": "Terms and Conditions Content", + "oldfieldname": "terms", + "oldfieldtype": "Text Editor" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "job_card", - "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 Card", - "length": 0, - "no_copy": 0, - "options": "Job Card", - "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 + "collapsible": 1, + "fieldname": "reference", + "fieldtype": "Section Break", + "label": "Reference" + }, + { + "fieldname": "job_card", + "fieldtype": "Link", + "label": "Job Card", + "options": "Job Card", + "print_hide": 1, + "read_only": 1 } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "icon": "fa fa-ticket", - "idx": 70, - "image_view": 0, - "in_create": 0, - "is_submittable": 1, - "issingle": 0, - "istable": 0, - "max_attachments": 0, - "menu_index": 0, - "modified": "2018-10-24 10:38:28.377919", - "modified_by": "Administrator", - "module": "Stock", - "name": "Material Request", - "owner": "Administrator", + ], + "icon": "fa fa-ticket", + "idx": 70, + "is_submittable": 1, + "modified": "2019-04-29 11:45:07.570292", + "modified_by": "Administrator", + "module": "Stock", + "name": "Material Request", + "owner": "Administrator", "permissions": [ { - "amend": 1, - "cancel": 1, - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 1, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Purchase Manager", - "set_user_permissions": 1, - "share": 1, - "submit": 1, + "amend": 1, + "cancel": 1, + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "import": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Purchase Manager", + "set_user_permissions": 1, + "share": 1, + "submit": 1, "write": 1 - }, + }, { - "amend": 1, - "cancel": 1, - "create": 1, - "delete": 1, - "email": 1, - "export": 0, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Stock Manager", - "set_user_permissions": 0, - "share": 1, - "submit": 1, + "amend": 1, + "cancel": 1, + "create": 1, + "delete": 1, + "email": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Stock Manager", + "share": 1, + "submit": 1, "write": 1 - }, + }, { - "amend": 1, - "cancel": 1, - "create": 1, - "delete": 1, - "email": 1, - "export": 0, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Stock User", - "set_user_permissions": 0, - "share": 1, - "submit": 1, + "amend": 1, + "cancel": 1, + "create": 1, + "delete": 1, + "email": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Stock User", + "share": 1, + "submit": 1, "write": 1 - }, + }, { - "amend": 1, - "cancel": 1, - "create": 1, - "delete": 1, - "email": 1, - "export": 0, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Purchase User", - "set_user_permissions": 0, - "share": 1, - "submit": 1, + "amend": 1, + "cancel": 1, + "create": 1, + "delete": 1, + "email": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Purchase User", + "share": 1, + "submit": 1, "write": 1 } - ], - "quick_entry": 1, - "read_only": 0, - "read_only_onload": 1, - "search_fields": "status,transaction_date", - "show_name_in_global_search": 1, - "sort_field": "modified", - "sort_order": "DESC", - "title_field": "title", - "track_changes": 0, - "track_seen": 0, - "track_views": 0 -} + ], + "quick_entry": 1, + "search_fields": "status,transaction_date", + "show_name_in_global_search": 1, + "sort_field": "modified", + "sort_order": "DESC", + "title_field": "title" +} \ No newline at end of file diff --git a/erpnext/stock/doctype/material_request/material_request_list.js b/erpnext/stock/doctype/material_request/material_request_list.js index e16e7d50a00..1cf971ff449 100644 --- a/erpnext/stock/doctype/material_request/material_request_list.js +++ b/erpnext/stock/doctype/material_request/material_request_list.js @@ -1,5 +1,5 @@ frappe.listview_settings['Material Request'] = { - add_fields: ["material_request_type", "status", "per_ordered"], + add_fields: ["material_request_type", "status", "per_ordered", "per_received"], get_indicator: function(doc) { if(doc.status=="Stopped") { return [__("Stopped"), "red", "status,=,Stopped"]; @@ -8,7 +8,11 @@ frappe.listview_settings['Material Request'] = { } else if(doc.docstatus==1 && flt(doc.per_ordered, 2) < 100) { return [__("Partially ordered"), "yellow", "per_ordered,<,100"]; } else if(doc.docstatus==1 && flt(doc.per_ordered, 2) == 100) { - if (doc.material_request_type == "Purchase") { + if (doc.material_request_type == "Purchase" && flt(doc.per_received, 2) < 100 && flt(doc.per_received, 2) > 0) { + return [__("Partially Received"), "yellow", "per_received,<,100"]; + } else if (doc.material_request_type == "Purchase" && flt(doc.per_received, 2) == 100) { + return [__("Received"), "green", "per_received,=,100"]; + } else if (doc.material_request_type == "Purchase") { return [__("Ordered"), "green", "per_ordered,=,100"]; } else if (doc.material_request_type == "Material Transfer") { return [__("Transfered"), "green", "per_ordered,=,100"]; diff --git a/erpnext/stock/doctype/material_request/test_material_request.py b/erpnext/stock/doctype/material_request/test_material_request.py index 7dc54d0e332..79cdc1ad18a 100644 --- a/erpnext/stock/doctype/material_request/test_material_request.py +++ b/erpnext/stock/doctype/material_request/test_material_request.py @@ -629,7 +629,8 @@ def make_material_request(**args): "item_code": args.item_code or "_Test Item", "qty": args.qty or 10, "schedule_date": args.schedule_date or today(), - "warehouse": args.warehouse or "_Test Warehouse - _TC" + "warehouse": args.warehouse or "_Test Warehouse - _TC", + "cost_center": args.cost_center or "_Test Cost Center - _TC" }) mr.insert() if not args.do_not_submit: diff --git a/erpnext/stock/doctype/material_request_item/material_request_item.json b/erpnext/stock/doctype/material_request_item/material_request_item.json index 965c6fe8445..75148057833 100644 --- a/erpnext/stock/doctype/material_request_item/material_request_item.json +++ b/erpnext/stock/doctype/material_request_item/material_request_item.json @@ -38,6 +38,7 @@ "projected_qty", "actual_qty", "ordered_qty", + "received_qty", "accounting_details", "expense_account", "column_break_35", @@ -364,11 +365,16 @@ { "fieldname": "section_break_37", "fieldtype": "Section Break" + }, + { + "fieldname": "received_qty", + "fieldtype": "Data", + "label": "Received Quantity" } ], "idx": 1, "istable": 1, - "modified": "2019-05-01 17:48:12.361976", + "modified": "2019-05-08 10:27:25.008801", "modified_by": "Administrator", "module": "Stock", "name": "Material Request Item", diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py index 6953279df7d..1bd55f812f1 100644 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py @@ -35,6 +35,17 @@ class PurchaseReceipt(BuyingController): 'percent_join_field': 'purchase_order', 'overflow_type': 'receipt' }, + { + 'source_dt': 'Purchase Receipt Item', + 'target_dt': 'Material Request Item', + 'join_field': 'material_request_item', + 'target_field': 'received_qty', + 'target_parent_dt': 'Material Request', + 'target_parent_field': 'per_received', + 'target_ref_field': 'qty', + 'source_field': 'qty', + 'percent_join_field': 'material_request' + }, { 'source_dt': 'Purchase Receipt Item', 'target_dt': 'Purchase Order Item', 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 f45d14836df..b3e75ac91a8 100644 --- a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json +++ b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json @@ -64,7 +64,9 @@ "rejected_warehouse", "quality_inspection", "purchase_order", + "material_request", "purchase_order_item", + "material_request_item", "column_break_40", "is_fixed_asset", "asset", @@ -753,11 +755,22 @@ "fieldname": "image_section", "fieldtype": "Section Break", "label": "Image" + }, + { + "fieldname": "material_request", + "fieldtype": "Link", + "label": "Material Request", + "options": "Material Request" + }, + { + "fieldname": "material_request_item", + "fieldtype": "Data", + "label": "Material Request Item" } ], "idx": 1, "istable": 1, - "modified": "2019-05-01 17:45:17.447900", + "modified": "2019-05-08 10:25:27.157675", "modified_by": "Administrator", "module": "Stock", "name": "Purchase Receipt Item", diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py index a6af4bd5544..d106ed126f6 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/stock_entry.py @@ -129,6 +129,10 @@ class StockEntry(StockController): if self.purpose not in valid_purposes: frappe.throw(_("Purpose must be one of {0}").format(comma_or(valid_purposes))) + if self.job_card and self.purpose != 'Material Transfer for Manufacture': + frappe.throw(_("For job card {0}, you can only make the 'Material Transfer for Manufacture' type stock entry") + .format(self.job_card)) + def set_transfer_qty(self): for item in self.get("items"): if not flt(item.qty): @@ -1116,7 +1120,7 @@ class StockEntry(StockController): frappe.MappingMismatchError) def validate_batch(self): - if self.purpose in ["Material Transfer for Manufacture", "Manufacture", "Repack", "Send to Subcontractor", "Material Issue"]: + if self.purpose in ["Material Transfer for Manufacture", "Manufacture", "Repack", "Send to Subcontractor"]: for item in self.get("items"): if item.batch_no: disabled = frappe.db.get_value("Batch", item.batch_no, "disabled") diff --git a/erpnext/templates/pages/demo.html b/erpnext/templates/pages/demo.html index a4b5e0122c7..178ca28ac76 100644 --- a/erpnext/templates/pages/demo.html +++ b/erpnext/templates/pages/demo.html @@ -40,6 +40,13 @@ $(document).ready(function() { right: 0%; width: 100%; } + {% include "templates/styles/card_style.css" %} + header, footer { + display: none; + } + html, body { + background-color: #f5f7fa; + } {% endblock %} diff --git a/erpnext/utilities/activation.py b/erpnext/utilities/activation.py index 5f261fac132..63c36b35d1f 100644 --- a/erpnext/utilities/activation.py +++ b/erpnext/utilities/activation.py @@ -5,50 +5,35 @@ from __future__ import unicode_literals import frappe, erpnext from frappe import _ +from six import iteritems def get_level(): activation_level = 0 + sales_data = [] + min_count = 0 + doctypes = {"Item": 5, "Customer": 5, "Sales Order": 2, "Sales Invoice": 2, "Purchase Order": 2, "Employee": 3, "Lead": 3, "Quotation": 3, + "Payment Entry": 2, "User": 5, "Student": 5, "Instructor": 5, "BOM": 3, "Journal Entry": 3, "Stock Entry": 3} + for doctype, min_count in iteritems(doctypes): + count = frappe.db.count(doctype) + if count > min_count: + activation_level += 1 + sales_data.append({doctype: count}) + if frappe.db.get_single_value('System Settings', 'setup_complete'): - activation_level = 1 - - if frappe.db.count('Item') > 5: activation_level += 1 - if frappe.db.count('Customer') > 5: - activation_level += 1 - - if frappe.db.count('Sales Order') > 2: - activation_level += 1 - - if frappe.db.count('Purchase Order') > 2: - activation_level += 1 - - if frappe.db.count('Employee') > 3: - activation_level += 1 - - if frappe.db.count('Lead') > 3: - activation_level += 1 - - if frappe.db.count('Payment Entry') > 2: - activation_level += 1 - - if frappe.db.count('Communication', dict(communication_medium='Email')) > 10: - activation_level += 1 - - if frappe.db.count('User') > 5: - activation_level += 1 - - if frappe.db.count('Student') > 5: - activation_level += 1 - - if frappe.db.count('Instructor') > 5: + communication_number = frappe.db.count('Communication', dict(communication_medium='Email')) + if communication_number > 10: activation_level += 1 + sales_data.append({"Communication": communication_number}) # recent login if frappe.db.sql('select name from tabUser where last_login > date_sub(now(), interval 2 day) limit 1'): activation_level += 1 - return activation_level + level = {"activation_level": activation_level, "sales_data": sales_data} + + return level def get_help_messages(): '''Returns help messages to be shown on Desktop'''