diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.js b/erpnext/accounts/doctype/journal_entry/journal_entry.js index c98e77fdd24..fc261a5c9da 100644 --- a/erpnext/accounts/doctype/journal_entry/journal_entry.js +++ b/erpnext/accounts/doctype/journal_entry/journal_entry.js @@ -86,9 +86,9 @@ erpnext.accounts.JournalEntry = frappe.ui.form.Controller.extend({ }; }); - me.frm.set_query("party_type", "accounts", function(doc, cdt, cdn) { - return { - filters: {"name": ["in", ["Customer", "Supplier"]]} + me.frm.set_query("party_type", "accounts", function() { + return{ + query: "erpnext.setup.doctype.party_type.party_type.get_party_type" } }); diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py index a17668033e6..a13cc7dde20 100644 --- a/erpnext/accounts/doctype/journal_entry/journal_entry.py +++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py @@ -9,6 +9,7 @@ from erpnext.controllers.accounts_controller import AccountsController from erpnext.accounts.utils import get_balance_on, get_account_currency from erpnext.setup.utils import get_company_currency from erpnext.accounts.party import get_party_account +from erpnext.hr.doctype.expense_claim.expense_claim import update_reimbursed_amount class JournalEntry(AccountsController): def __init__(self, arg1, arg2=None): @@ -375,7 +376,7 @@ class JournalEntry(AccountsController): bank_amount = party_amount = total_amount = 0.0 currency = bank_account_currency = party_account_currency = pay_to_recd_from= None for d in self.get('accounts'): - if d.party_type and d.party: + if d.party_type in ['Customer', 'Supplier'] and d.party: if not pay_to_recd_from: pay_to_recd_from = frappe.db.get_value(d.party_type, d.party, "customer_name" if d.party_type=="Customer" else "supplier_name") @@ -503,11 +504,9 @@ class JournalEntry(AccountsController): def update_expense_claim(self): for d in self.accounts: - if d.reference_type=="Expense Claim": - amt = frappe.db.sql("""select sum(debit) as amt from `tabJournal Entry Account` - where reference_type = "Expense Claim" and - reference_name = %s and docstatus = 1""", d.reference_name ,as_dict=1)[0].amt - frappe.db.set_value("Expense Claim", d.reference_name , "total_amount_reimbursed", amt) + if d.reference_type=="Expense Claim" and d.party: + doc = frappe.get_doc("Expense Claim", d.reference_name) + update_reimbursed_amount(doc) def validate_expense_claim(self): for d in self.accounts: diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.js b/erpnext/accounts/doctype/payment_entry/payment_entry.js index d3dbd314cc7..6528c8fd518 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.js +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.js @@ -26,6 +26,12 @@ frappe.ui.form.on('Payment Entry', { } }); + frm.set_query("party_type", function() { + return{ + query: "erpnext.setup.doctype.party_type.party_type.get_party_type" + } + }); + frm.set_query("paid_to", function() { var account_types = in_list(["Receive", "Internal Transfer"], frm.doc.payment_type) ? ["Bank", "Cash"] : party_account_type; diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.json b/erpnext/accounts/doctype/payment_entry/payment_entry.json index c56a83dcaf9..98fa445c9b1 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.json +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.json @@ -97,95 +97,6 @@ "set_only_once": 0, "unique": 0 }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "eval:in_list([\"Receive\", \"Pay\"], doc.payment_type)", - "fieldname": "party_type", - "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_list_view": 0, - "in_standard_filter": 1, - "label": "Party Type", - "length": 0, - "no_copy": 0, - "options": "Customer\nSupplier", - "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, - "unique": 0 - }, - { - "allow_on_submit": 0, - "bold": 1, - "collapsible": 0, - "columns": 0, - "depends_on": "eval:in_list([\"Receive\", \"Pay\"], doc.payment_type) && doc.party_type", - "fieldname": "party", - "fieldtype": "Dynamic Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_list_view": 0, - "in_standard_filter": 1, - "label": "Party", - "length": 0, - "no_copy": 0, - "options": "party_type", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_on_submit": 1, - "bold": 0, - "collapsible": 0, - "columns": 0, - "description": "", - "fieldname": "party_name", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Party Name", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, { "allow_on_submit": 0, "bold": 0, @@ -212,7 +123,7 @@ "search_index": 0, "set_only_once": 0, "unique": 0 - }, + }, { "allow_on_submit": 0, "bold": 1, @@ -300,6 +211,152 @@ "set_only_once": 0, "unique": 0 }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "eval:in_list([\"Receive\", \"Pay\"], doc.payment_type) && doc.party_type", + "fieldname": "party_section", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Payment From / To", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "eval:in_list([\"Receive\", \"Pay\"], doc.payment_type)", + "fieldname": "party_type", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "in_standard_filter": 1, + "label": "Party Type", + "length": 0, + "no_copy": 0, + "options": "DocType", + "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, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 1, + "collapsible": 0, + "columns": 0, + "depends_on": "eval:in_list([\"Receive\", \"Pay\"], doc.payment_type) && doc.party_type", + "fieldname": "party", + "fieldtype": "Dynamic Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "in_standard_filter": 1, + "label": "Party", + "length": 0, + "no_copy": 0, + "options": "party_type", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "column_break_11", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 1, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "eval:in_list([\"Receive\", \"Pay\"], doc.payment_type) && doc.party_type", + "description": "", + "fieldname": "party_name", + "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Party Name", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, { "allow_on_submit": 0, "bold": 0, @@ -1561,7 +1618,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2016-11-07 05:33:40.371480", + "modified": "2017-01-30 00:41:51.348616", "modified_by": "Administrator", "module": "Accounts", "name": "Payment Entry", @@ -1578,7 +1635,6 @@ "export": 1, "if_owner": 0, "import": 1, - "is_custom": 0, "permlevel": 0, "print": 1, "read": 1, @@ -1599,7 +1655,6 @@ "export": 1, "if_owner": 0, "import": 1, - "is_custom": 0, "permlevel": 0, "print": 1, "read": 1, @@ -1617,5 +1672,6 @@ "sort_field": "modified", "sort_order": "DESC", "title_field": "title", + "track_changes": 0, "track_seen": 0 } \ No newline at end of file diff --git a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js index 6a951a0aff6..272e47448ef 100644 --- a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js +++ b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js @@ -6,12 +6,10 @@ frappe.provide("erpnext.accounts"); erpnext.accounts.PaymentReconciliationController = frappe.ui.form.Controller.extend({ onload: function() { var me = this - this.frm.set_query('party_type', function() { - return { - filters: { - "name": ["in", ["Customer", "Supplier"]] - } - }; + this.frm.set_query("party_type", function() { + return{ + query: "erpnext.setup.doctype.party_type.party_type.get_party_type" + } }); this.frm.set_query('receivable_payable_account', function() { diff --git a/erpnext/accounts/doctype/payment_reconciliation_payment/payment_reconciliation_payment.json b/erpnext/accounts/doctype/payment_reconciliation_payment/payment_reconciliation_payment.json index f77560c1396..57fce656437 100644 --- a/erpnext/accounts/doctype/payment_reconciliation_payment/payment_reconciliation_payment.json +++ b/erpnext/accounts/doctype/payment_reconciliation_payment/payment_reconciliation_payment.json @@ -22,6 +22,7 @@ "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, + "in_standard_filter": 0, "label": "Reference Type", "length": 0, "no_copy": 0, @@ -30,6 +31,7 @@ "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 1, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, "search_index": 0, @@ -48,7 +50,8 @@ "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 1, - "label": "Reference_name", + "in_standard_filter": 0, + "label": "Reference Name", "length": 0, "no_copy": 0, "options": "reference_type", @@ -57,6 +60,7 @@ "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 1, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, "search_index": 0, @@ -75,6 +79,7 @@ "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, + "in_standard_filter": 0, "label": "Posting Date", "length": 0, "no_copy": 0, @@ -82,6 +87,7 @@ "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 1, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, "search_index": 0, @@ -100,6 +106,7 @@ "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, + "in_standard_filter": 0, "label": "Is Advance", "length": 0, "no_copy": 0, @@ -107,6 +114,7 @@ "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 1, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, "search_index": 0, @@ -125,6 +133,7 @@ "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, + "in_standard_filter": 0, "label": "Reference Row", "length": 0, "no_copy": 0, @@ -132,6 +141,7 @@ "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 1, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, "search_index": 0, @@ -150,6 +160,7 @@ "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, + "in_standard_filter": 0, "label": "", "length": 0, "no_copy": 0, @@ -157,6 +168,7 @@ "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, "search_index": 0, @@ -175,6 +187,7 @@ "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 1, + "in_standard_filter": 0, "label": "Invoice Number", "length": 0, "no_copy": 0, @@ -183,6 +196,7 @@ "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, @@ -201,6 +215,7 @@ "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 1, + "in_standard_filter": 0, "label": "Amount", "length": 0, "no_copy": 0, @@ -208,6 +223,7 @@ "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 1, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, "search_index": 0, @@ -226,6 +242,7 @@ "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 1, + "in_standard_filter": 0, "label": "Allocated amount", "length": 0, "no_copy": 0, @@ -234,6 +251,7 @@ "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, @@ -252,6 +270,7 @@ "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, + "in_standard_filter": 0, "label": "", "length": 0, "no_copy": 0, @@ -259,6 +278,7 @@ "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, "search_index": 0, @@ -277,6 +297,7 @@ "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 1, + "in_standard_filter": 0, "label": "Remark", "length": 0, "no_copy": 0, @@ -284,6 +305,7 @@ "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 1, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, "search_index": 0, @@ -302,7 +324,7 @@ "istable": 1, "max_attachments": 0, "menu_index": 0, - "modified": "2016-08-26 02:08:35.879133", + "modified": "2017-01-30 01:04:22.557237", "modified_by": "Administrator", "module": "Accounts", "name": "Payment Reconciliation Payment", @@ -314,5 +336,6 @@ "read_only_onload": 0, "sort_field": "modified", "sort_order": "DESC", + "track_changes": 0, "track_seen": 0 } \ No newline at end of file diff --git a/erpnext/accounts/doctype/sales_invoice/pos.py b/erpnext/accounts/doctype/sales_invoice/pos.py index bd547761770..070dbeb2b8f 100644 --- a/erpnext/accounts/doctype/sales_invoice/pos.py +++ b/erpnext/accounts/doctype/sales_invoice/pos.py @@ -30,6 +30,7 @@ def get_pos_data(): 'doc': doc, 'default_customer': pos_profile.get('customer'), 'items': get_items_list(pos_profile), + 'item_groups': get_item_group(pos_profile), 'customers': get_customers_list(pos_profile), 'serial_no_data': get_serial_no_data(pos_profile, doc.company), 'batch_no_data': get_batch_no_data(), @@ -140,6 +141,15 @@ def get_items_list(pos_profile): disabled = 0 and has_variants = 0 and is_sales_item = 1 and {cond} """.format(cond=cond), tuple(item_groups), as_dict=1) +def get_item_group(pos_profile): + if pos_profile.get('item_groups'): + item_groups = [] + for d in pos_profile.get('item_groups'): + item_groups.extend(get_child_nodes('Item Group', d.item_group)) + return item_groups + else: + return frappe.db.sql_list("""Select name from `tabItem Group` order by name""") + def get_customers_list(pos_profile): cond = "1=1" customer_groups = [] @@ -276,11 +286,33 @@ def validate_customer(doc): customer_doc = frappe.new_doc('Customer') customer_doc.customer_name = doc.get('customer') customer_doc.customer_type = 'Company' - customer_doc.customer_group = doc.get('customer_group') - customer_doc.territory = doc.get('territory') + customer_doc.customer_group = frappe.db.get_single_value('Selling Settings', 'customer_group') + customer_doc.territory = frappe.db.get_single_value('Selling Settings', 'territory') + customer_doc.flags.ignore_mandatory = True customer_doc.save(ignore_permissions = True) frappe.db.commit() doc['customer'] = customer_doc.name + if doc.get('contact_details'): + args = json.loads(doc.get("contact_details")) + make_address(doc, args, customer_doc.name) + +def make_address(doc, args, customer): + if args.get("address_line1"): + address = frappe.new_doc('Address') + address.address_line1 = args.get('address_line1') + address.address_line2 = args.get('address_line2') + address.city = args.get('city') + address.state = args.get('state') + address.zip_code = args.get('zip_code') + address.email_id = args.get('email_id') + address.flags.ignore_mandatory = True + address.country = frappe.db.get_value('Company', doc.get('company'), 'country') + address.append('links',{ + 'link_doctype': 'Customer', + 'link_name': customer + }) + address.save(ignore_permissions = True) + frappe.db.commit() def validate_item(doc): for item in doc.get('items'): diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json index 7ade3187e25..f026cb06fa2 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json @@ -28,7 +28,7 @@ "label": "", "length": 0, "no_copy": 0, - "options": "fa fa-user", + "options": "icon-user", "permlevel": 0, "print_hide": 0, "print_hide_if_no_value": 0, @@ -232,7 +232,7 @@ "in_standard_filter": 0, "label": "Offline POS Name", "length": 0, - "no_copy": 0, + "no_copy": 1, "permlevel": 0, "precision": "", "print_hide": 0, @@ -1035,7 +1035,7 @@ "length": 0, "no_copy": 0, "oldfieldtype": "Section Break", - "options": "fa fa-shopping-cart", + "options": "icon-shopping-cart", "permlevel": 0, "print_hide": 0, "print_hide_if_no_value": 0, @@ -1122,7 +1122,7 @@ "label": "Packing List", "length": 0, "no_copy": 0, - "options": "fa fa-suitcase", + "options": "icon-suitcase", "permlevel": 0, "print_hide": 1, "print_hide_if_no_value": 0, @@ -1462,7 +1462,7 @@ "length": 0, "no_copy": 0, "oldfieldtype": "Section Break", - "options": "fa fa-money", + "options": "icon-money", "permlevel": 0, "print_hide": 0, "print_hide_if_no_value": 0, @@ -1941,7 +1941,7 @@ "length": 0, "no_copy": 0, "oldfieldtype": "Section Break", - "options": "fa fa-money", + "options": "icon-money", "permlevel": 0, "print_hide": 1, "print_hide_if_no_value": 0, @@ -2238,7 +2238,7 @@ "length": 0, "no_copy": 0, "oldfieldtype": "Section Break", - "options": "fa fa-money", + "options": "icon-money", "permlevel": 0, "print_hide": 1, "print_hide_if_no_value": 0, @@ -2327,7 +2327,7 @@ "label": "Payments", "length": 0, "no_copy": 0, - "options": "fa fa-money", + "options": "icon-money", "permlevel": 0, "print_hide": 0, "print_hide_if_no_value": 0, @@ -3252,7 +3252,7 @@ "length": 0, "no_copy": 0, "oldfieldtype": "Section Break", - "options": "fa fa-file-text", + "options": "icon-file-text", "permlevel": 0, "print_hide": 1, "print_hide_if_no_value": 0, @@ -3515,7 +3515,7 @@ "length": 0, "no_copy": 0, "oldfieldtype": "Section Break", - "options": "fa fa-group", + "options": "icon-group", "permlevel": 0, "print_hide": 1, "print_hide_if_no_value": 0, @@ -3720,7 +3720,7 @@ "label": "Recurring", "length": 0, "no_copy": 0, - "options": "fa fa-time", + "options": "icon-time", "permlevel": 0, "print_hide": 1, "print_hide_if_no_value": 0, @@ -4173,7 +4173,7 @@ ], "hide_heading": 0, "hide_toolbar": 0, - "icon": "fa fa-file-text", + "icon": "icon-file-text", "idx": 181, "image_view": 0, "in_create": 0, @@ -4282,5 +4282,6 @@ "sort_order": "DESC", "timeline_field": "customer", "title_field": "title", + "track_changes": 1, "track_seen": 0 } \ No newline at end of file diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index 3eb2f7d7d18..3dfe6808830 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -963,40 +963,6 @@ class TestSalesInvoice(unittest.TestCase): si.insert() self.assertEqual(si.get("items")[0].rate, flt((price_list_rate*25)/100 + price_list_rate)) - def test_party_status(self): - from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry - from frappe.utils import random_string - - customer_name = 'test customer for status' - - if frappe.db.exists('Customer', customer_name): - customer = frappe.get_doc('Customer', customer_name) - customer.db_set('status', 'Active') - else: - customer = frappe.get_doc({ - 'doctype': 'Customer', - 'customer_name': customer_name, - 'customer_group': 'Commercial', - 'customer_type': 'Individual', - 'territory': 'Rest of the World' - }).insert() - - self.assertEquals(frappe.db.get_value('Customer', customer.name, 'status'), 'Active') - - invoice = create_sales_invoice(customer="test customer for status", - debit_to="_Test Receivable - _TC", - currency="USD", conversion_rate=50) - - self.assertEquals(frappe.db.get_value('Customer', customer.name, 'status'), 'Open') - - pe = get_payment_entry(invoice.doctype, invoice.name) - pe.reference_no = random_string(10) - pe.reference_date = invoice.posting_date - pe.insert() - pe.submit() - - self.assertEquals(frappe.db.get_value('Customer', customer.name, 'status'), 'Active') - def test_outstanding_amount_after_advance_jv_cancelation(self): from erpnext.accounts.doctype.journal_entry.test_journal_entry \ import test_records as jv_test_records diff --git a/erpnext/accounts/page/pos/pos.js b/erpnext/accounts/page/pos/pos.js index 13abe145495..ed54ab400ec 100644 --- a/erpnext/accounts/page/pos/pos.js +++ b/erpnext/accounts/page/pos/pos.js @@ -1,7 +1,7 @@ frappe.provide("erpnext.pos"); {% include "erpnext/public/js/controllers/taxes_and_totals.js" %} -frappe.pages['pos'].on_page_load = function(wrapper) { +frappe.pages['pos'].on_page_load = function (wrapper) { var page = frappe.ui.make_app_page({ parent: wrapper, title: __('Point of Sale'), @@ -11,15 +11,15 @@ frappe.pages['pos'].on_page_load = function(wrapper) { wrapper.pos = new erpnext.pos.PointOfSale(wrapper) } -frappe.pages['pos'].refresh = function(wrapper) { +frappe.pages['pos'].refresh = function (wrapper) { window.onbeforeunload = function () { return wrapper.pos.beforeunload() } } - erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ - init: function(wrapper){ + init: function (wrapper) { + this.page_len = 20; this.page = wrapper.page; this.wrapper = $(wrapper).find('.page-content'); this.set_indicator(); @@ -28,13 +28,13 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ this.si_docs = this.get_doc_from_localstorage(); }, - beforeunload: function(e){ - if(this.connection_status == false && frappe.get_route()[0] == "pos"){ + beforeunload: function (e) { + if (this.connection_status == false && frappe.get_route()[0] == "pos") { e = e || window.event; // For IE and Firefox prior to version 4 if (e) { - e.returnValue = __("You are in offline mode. You will not be able to reload until you have network."); + e.returnValue = __("You are in offline mode. You will not be able to reload until you have network."); return } @@ -43,23 +43,23 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ } }, - check_internet_connection: function(){ + check_internet_connection: function () { var me = this; //Check Internet connection after every 30 seconds - setInterval(function(){ + setInterval(function () { me.set_indicator(); }, 5000) }, - set_indicator: function(){ + set_indicator: function () { var me = this; // navigator.onLine this.connection_status = false; this.page.set_indicator(__("Offline"), "grey") frappe.call({ - method:"frappe.handler.ping", - callback: function(r){ - if(r.message){ + method: "frappe.handler.ping", + callback: function (r) { + if (r.message) { me.connection_status = true; me.page.set_indicator(__("Online"), "green") } @@ -67,27 +67,23 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ }) }, - onload: function(){ + onload: function () { var me = this; - this.get_data_from_server(function(){ + this.get_data_from_server(function () { me.create_new(); }); }, - make_menu_list: function(){ + make_menu_list: function () { var me = this; - this.page.add_menu_item(__("New Sales Invoice"), function() { + this.page.add_menu_item(__("New Sales Invoice"), function () { me.save_previous_entry(); me.create_new(); }) - this.page.add_menu_item(__("View Offline Records"), function(){ - me.show_unsync_invoice_list(); - }); - - this.page.add_menu_item(__("Sync Master Data"), function(){ - me.get_data_from_server(function(){ + this.page.add_menu_item(__("Sync Master Data"), function () { + me.get_data_from_server(function () { me.load_data(false); me.make_customer(); me.make_item_list(); @@ -95,83 +91,29 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ }) }); - this.page.add_menu_item(__("Sync Offline Invoices"), function(){ + this.page.add_menu_item(__("Sync Offline Invoices"), function () { me.sync_sales_invoice() }); - this.page.add_menu_item(__("POS Profile"), function() { + this.page.add_menu_item(__("POS Profile"), function () { frappe.set_route('List', 'POS Profile'); }); }, - show_unsync_invoice_list: function(){ - var me = this; - this.si_docs = this.get_doc_from_localstorage(); - this.list_dialog = new frappe.ui.Dialog({ - title: 'Invoice List' - }); - - this.list_dialog.show(); - this.list_body = this.list_dialog.body; - if(me.pos_profile_data["allow_delete"]) { - this.list_dialog.set_primary_action(__("Delete"), function() { - frappe.confirm(__("Delete permanently?"), function () { - me.delete_records(); - }) - }).addClass("btn-danger"); - this.toggle_primary_action(); - } - - if(this.si_docs.length > 0){ - me.render_offline_data(); - me.dialog_actions() - }else{ - $(this.list_body).append(repl('
%(message)s
', {'message': __("All records are synced.")})) - } - }, - - render_offline_data: function() { + dialog_actions: function () { var me = this; - this.removed_items = []; - $(this.list_body).empty(); - - $(this.list_body).append('
\ -
\ -
Customer
\ -
Status
\ -
Paid Amount
\ -
Grand Total
\ -
') - - $.each(this.si_docs, function(index, data){ - for(key in data) { - $(frappe.render_template("pos_invoice_list", { - sr: index + 1, - name: key, - customer: data[key].customer, - paid_amount: format_currency(data[key].paid_amount, me.frm.doc.currency), - grand_total: format_currency(data[key].grand_total, me.frm.doc.currency), - data: me.get_doctype_status(data[key]) - })).appendTo($(me.list_body)); - } - }) - }, - - dialog_actions: function() { - var me = this; - - $(this.list_body).find('.list-column').click(function() { + $(this.list_body).find('.list-column').click(function () { me.name = $(this).parents().attr('invoice-name') me.edit_record(); }) - $(this.list_body).find('.list-select-all').click(function() { + $(this.list_body).find('.list-select-all').click(function () { me.removed_items = []; $(me.list_body).find('.list-delete').prop("checked", $(this).is(":checked")) - if($(this).is(":checked")) { - $.each(me.si_docs, function(index, data){ - for(key in data) { + if ($(this).is(":checked")) { + $.each(me.si_docs, function (index, data) { + for (key in data) { me.removed_items.push(key) } }) @@ -180,9 +122,9 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ me.toggle_primary_action(); }) - $(this.list_body).find('.list-delete').click(function() { + $(this.list_body).find('.list-delete').click(function () { me.name = $(this).parent().parent().attr('invoice-name'); - if($(this).is(":checked")) { + if ($(this).is(":checked")) { me.removed_items.push(me.name); } else { me.removed_items.pop(me.name) @@ -192,101 +134,103 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ }) }, - edit_record: function() { + edit_record: function () { var me = this; doc_data = this.get_invoice_doc(this.si_docs); - if(doc_data){ + if (doc_data) { this.frm.doc = doc_data[0][this.name]; this.set_missing_values(); this.refresh(false); this.disable_input_field(); - this.list_dialog.hide(); + this.list_dialog && this.list_dialog.hide(); } }, - delete_records: function() { + delete_records: function () { var me = this; this.remove_doc_from_localstorage() this.update_localstorage(); - this.render_offline_data(); this.dialog_actions(); this.toggle_primary_action(); }, - toggle_primary_action: function() { + toggle_primary_action: function () { var me = this; - if(this.removed_items && this.removed_items.length > 0) { - $(this.list_dialog.wrapper).find('.btn-danger').show(); + if(this.frm.doc.allow_delete) { + if (this.removed_items && this.removed_items.length > 0) { + $(this.wrapper).find('.btn-danger').show(); + } else { + $(this.wrapper).find('.btn-danger').hide(); + } + } + }, + + get_doctype_status: function (doc) { + if (doc.docstatus == 0) { + return { status: "Draft", indicator: "red" } + } else if (doc.outstanding_amount == 0) { + return { status: "Paid", indicator: "green" } } else { - $(this.list_dialog.wrapper).find('.btn-danger').hide(); + return { status: "Submitted", indicator: "blue" } } }, - get_doctype_status: function(doc){ - if(doc.docstatus == 0) { - return {status: "Draft", indicator: "red"} - }else if(doc.outstanding_amount == 0) { - return {status: "Paid", indicator: "green"} - }else { - return {status: "Submitted", indicator: "blue"} - } - }, - - set_missing_values: function(){ + set_missing_values: function () { var me = this; doc = JSON.parse(localStorage.getItem('doc')) - if(this.frm.doc.payments.length == 0){ + if (this.frm.doc.payments.length == 0) { this.frm.doc.payments = doc.payments; this.calculate_outstanding_amount(); } - if(this.frm.doc.customer){ + if (this.frm.doc.customer) { this.party_field.$input.val(this.frm.doc.customer); } - if(!this.frm.doc.write_off_account){ + if (!this.frm.doc.write_off_account) { this.frm.doc.write_off_account = doc.write_off_account } - if(!this.frm.doc.account_for_change_amount){ + if (!this.frm.doc.account_for_change_amount) { this.frm.doc.account_for_change_amount = doc.account_for_change_amount } }, - get_invoice_doc: function(si_docs){ + get_invoice_doc: function (si_docs) { var me = this; this.si_docs = this.get_doc_from_localstorage(); - return $.grep(this.si_docs, function(data){ - for(key in data){ + return $.grep(this.si_docs, function (data) { + for (key in data) { return key == me.name } }) }, - get_data_from_server: function(callback){ + get_data_from_server: function (callback) { var me = this; frappe.call({ method: "erpnext.accounts.doctype.sales_invoice.pos.get_pos_data", freeze: true, freeze_message: __("Master data syncing, it might take some time"), - callback: function(r){ + callback: function (r) { me.init_master_data(r) localStorage.setItem('doc', JSON.stringify(r.message.doc)); me.set_interval_for_si_sync(); me.check_internet_connection(); - if(callback){ + if (callback) { callback(); } } }) }, - init_master_data: function(r){ + init_master_data: function (r) { var me = this; this.meta = r.message.meta; this.item_data = r.message.items; + this.item_groups = r.message.item_groups; this.customers = r.message.customers; this.serial_no_data = r.message.serial_no_data; this.batch_no_data = r.message.batch_no_data; @@ -301,48 +245,51 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ this.letter_head = (this.pos_profile_data.length > 0) ? frappe.boot.letter_heads[this.pos_profile_data[letter_head]] : {}; }, - save_previous_entry : function(){ - if(this.frm.doc.docstatus < 1 && this.frm.doc.items.length > 0){ - this.create_invoice() + save_previous_entry: function () { + if (this.frm.doc.docstatus < 1 && this.frm.doc.items.length > 0) { + this.create_invoice(); } }, - create_new: function(){ + create_new: function () { var me = this; this.frm = {} - this.name = ''; + this.name = null; this.load_data(true); this.setup(); }, - load_data: function(load_doc){ + load_data: function (load_doc) { var me = this; this.items = this.item_data; this.actual_qty_dict = {}; - if(load_doc) { - this.frm.doc = JSON.parse(localStorage.getItem('doc')); + if (load_doc) { + this.frm.doc = JSON.parse(localStorage.getItem('doc')); } - $.each(this.meta, function(i, data){ + $.each(this.meta, function (i, data) { frappe.meta.sync(data) locals["DocType"][data.name] = data; }) - this.print_template_data = frappe.render_template("print_template", {content: this.print_template, - title:"POS", base_url: frappe.urllib.get_base_url(), print_css: frappe.boot.print_css, - print_settings: this.print_settings, header: this.letter_head.header, footer: this.letter_head.footer}) + this.print_template_data = frappe.render_template("print_template", { + content: this.print_template, + title: "POS", base_url: frappe.urllib.get_base_url(), print_css: frappe.boot.print_css, + print_settings: this.print_settings, header: this.letter_head.header, footer: this.letter_head.footer + }) }, - setup: function(){ + setup: function () { + this.frm.doc.allow_delete = this.pos_profile_data["allow_delete"]; this.wrapper.html(frappe.render_template("pos", this.frm.doc)); this.set_transaction_defaults("Customer"); this.make(); this.set_primary_action(); }, - set_transaction_defaults: function(party) { + set_transaction_defaults: function (party) { var me = this; this.party = party; this.price_list = (party == "Customer" ? @@ -351,34 +298,54 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ this.sales_or_purchase = (party == "Customer" ? "Sales" : "Purchase"); }, - make: function() { + make: function () { this.make_search(); + this.make_list_customers(); this.make_customer(); this.make_item_list(); this.make_discount_field() }, - make_search: function() { + make_search: function () { var me = this; - this.search = frappe.ui.form.make_control({ + this.serach_item = frappe.ui.form.make_control({ df: { "fieldtype": "Data", "label": "Item", "fieldname": "pos_item", "placeholder": __("Search Item") }, - parent: this.wrapper.find(".search-area"), + parent: this.wrapper.find(".search-item"), only_input: true, }); - this.search.make_input(); - this.search.$input.on("keyup", function() { - setTimeout(function() { + this.serach_item.make_input(); + this.serach_item.$input.on("keyup", function () { + setTimeout(function () { me.items = me.get_items(); me.make_item_list(); }, 1000); }); + this.search_item_group = frappe.ui.form.make_control({ + df: { + "fieldtype": "Select", + "options": me.item_groups, + "label": __("Item Group"), + "fieldname": "item_group", + "placeholder": __("Item Group") + }, + parent: this.wrapper.find(".search-item-group"), + only_input: true, + }); + + this.search_item_group.make_input(); + this.search_item_group.$input.on("change", function () { + me.page_len = 20; + me.items = me.get_items(); + me.make_item_list(); + }); + this.party_field = frappe.ui.form.make_control({ df: { "fieldtype": "Data", @@ -392,21 +359,139 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ }); this.party_field.make_input(); - this.set_focus() + setTimeout(this.set_focus.bind(this), 500); + + this.wrapper.find(".btn-more").on("click", function() { + me.page_len += 20; + me.items = me.get_items(); + me.make_item_list(); + }) }, - set_focus: function(){ - if(this.default_customer){ - this.search.$input.focus(); - }else{ + make_list_customers: function () { + var me = this; + this.list_customers_btn = this.wrapper.find('.list-customers-btn'); + this.add_customer_btn = this.wrapper.find('.add-customer-btn'); + this.pos_bill = this.wrapper.find('.pos-bill').hide(); + this.list_customers = this.wrapper.find('.list-customers'); + + this.list_customers_btn.on('click', function () { + $(this).toggleClass("view_customer"); + if($(this).hasClass("view_customer")) { + me.render_list_customers(); + me.bind_delete_event() + me.party_field.$input.attr('disabled', true); + me.list_customers.show(); + me.pos_bill.hide(); + } else { + if(me.frm.doc.docstatus == 0) { + me.party_field.$input.attr('disabled', false); + } + me.pos_bill.show(); + me.list_customers.hide() + } + }); + this.add_customer_btn.on('click', function() { + me.save_previous_entry(); + me.create_new(); + me.refresh(); + me.set_focus(); + }); + }, + + render_list_customers: function () { + var me = this; + + this.removed_items = []; + this.list_customers.empty(); + this.si_docs = this.get_doc_from_localstorage(); + + if (!this.si_docs.length) { + this.list_customers.append( + '
' + __("No offline records.") + '
' + ) + return; + } + var html = '
\ +
\ +
Customer
\ +
Status
\ +
Paid Amount
\ +
Grand Total
\ +
'; + this.si_docs.forEach(function (data, i) { + for (key in data) { + html += frappe.render_template("pos_invoice_list", { + sr: i + 1, + name: key, + customer: data[key].customer, + paid_amount: format_currency(data[key].paid_amount, me.frm.doc.currency), + grand_total: format_currency(data[key].grand_total, me.frm.doc.currency), + data: me.get_doctype_status(data[key]) + }); + } + }); + this.list_customers.append(html); + + this.list_customers.find('.list-column').click(function () { + me.list_customers.hide(); + me.list_customers_btn.toggleClass("view_customer"); + me.pos_bill.show(); + me.list_customers_btn.show(); + me.name = $(this).parents().attr('invoice-name') + me.edit_record(); + }) + + //actions + $(this.wrapper).find('.list-select-all').click(function () { + me.list_customers.find('.list-delete').prop("checked", $(this).is(":checked")) + me.removed_items = []; + if ($(this).is(":checked")) { + $.each(me.si_docs, function (index, data) { + for (key in data) { + me.removed_items.push(key) + } + }); + } + + me.toggle_primary_action(); + }); + + $(this.wrapper).find('.list-delete').click(function () { + me.name = $(this).parent().parent().attr('invoice-name'); + if ($(this).is(":checked")) { + me.removed_items.push(me.name); + } else { + me.removed_items.pop(me.name) + } + + me.toggle_primary_action(); + }); + }, + + bind_delete_event: function() { + var me = this; + + $(this.wrapper).find('.btn-danger').click(function(){ + frappe.confirm(__("Delete permanently?"), function () { + me.delete_records(); + me.render_list_customers(); + }) + }) + }, + + set_focus: function () { + if (this.default_customer || this.frm.doc.customer) { + this.serach_item.$input.focus(); + } else { this.party_field.$input.focus(); } }, - make_customer: function() { + make_customer: function () { var me = this; - if(this.default_customer && !this.frm.doc.customer){ + if (this.default_customer && !this.frm.doc.customer) { this.party_field.$input.val(this.default_customer); this.frm.doc.customer = this.default_customer; } @@ -417,14 +502,14 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ maxItems: 99, autoFirst: true, list: [], - filter: function(item, input) { + filter: function (item, input) { var value = item.value.toLowerCase(); - if(value.indexOf('is_action') !== -1 || + if (value.indexOf('is_action') !== -1 || value.indexOf(input) !== -1) { return true; } }, - item: function(item, input) { + item: function (item, input) { var d = item; var html = "" + __(d.label || d.value) + ""; return $('
  • ') @@ -433,7 +518,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ .get(0); } }); - var items = this.customers.map(function(c) { + var customers = this.customers.map(function (c) { return { label: c.name, value: c.name, @@ -441,44 +526,47 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ territory: c.territory } }); - items.push({ + + customers.push({ label: "" - + " " - + __("Create a new Customer") - + "", + + " " + + __("Create a new Customer") + + "", value: 'is_action', action: me.new_customer }); - this.party_field.awesomeplete.list = items; + this.party_field.awesomeplete.list = customers; this.party_field.$input - .on('input', function(e) { - me.party_field.awesomeplete.list = items; + .on('input', function (e) { + me.party_field.awesomeplete.list = customers; }) - .on('awesomplete-select', function(e) { - var item = me.party_field.awesomeplete + .on('awesomplete-select', function (e) { + var customer = me.party_field.awesomeplete .get_item(e.originalEvent.text.value); - if(!item) return; - if(item.action) { - item.action.apply(me); + if (!customer) return; + // create customer link + if (customer.action) { + customer.action.apply(me); return; } - me.update_customer_data(item); + me.update_customer_data(customer); me.refresh(); + me.set_focus(); }) - .on('change', function(e) { - if(!e.originalEvent.text) { + .on('change', function (e) { + if (!e.originalEvent.text) { me.frm.doc.customer = $(this).val(); } }) - .on('focus', function(e) { + .on('focus', function (e) { $(e.target).val('').trigger('input'); }) - .on("awesomplete-selectcomplete", function(e) { + .on("awesomplete-selectcomplete", function (e) { var item = me.party_field.awesomeplete .get_item(e.originalEvent.text.value); // clear text input if item is action - if(item.action) { + if (item.action) { $(this).val(""); } }); @@ -486,45 +574,119 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ new_customer: function () { var me = this; - if(!this.connection_status) return; - frappe.ui.form.quick_entry('Customer', function (doc) { - me.customers.push(doc); - me.party_field.$input.val(doc.name); - me.update_customer_data(doc); + if (!this.connection_status) return; + + this.customer_doc = new frappe.ui.Dialog({ + 'title': 'Customer', + fields: [ + { + "label": __("Full Name"), + "fieldname": "full_name", + "fieldtype": "Data", + "reqd": 1 + }, + { + "fieldtype": "Section Break" + }, + { + "label": __("Email Id"), + "fieldname": "email_id", + "fieldtype": "Data" + }, + { + "fieldtype": "Column Break" + }, + { + "label": __("Contact Number"), + "fieldname": "contact_no", + "fieldtype": "Data" + }, + { + "fieldtype": "Section Break" + }, + { + "label": __("Address Line 1"), + "fieldname": "address_line1", + "fieldtype": "Data" + }, + { + "label": __("Address Line 2"), + "fieldname": "address_line2", + "fieldtype": "Data" + }, + { + "fieldtype": "Column Break" + }, + { + "label": __("City"), + "fieldname": "city", + "fieldtype": "Data" + }, + { + "label": __("State"), + "fieldname": "state", + "fieldtype": "Data" + }, + { + "label": __("ZIP Code"), + "fieldname": "zip_code", + "fieldtype": "Data" + } + ] }) + + this.customer_doc.show() + + this.customer_doc.set_primary_action(__("Save"), function () { + me.make_offline_customer(); + me.pos_bill.show(); + }); }, - update_customer_data: function(doc) { + make_offline_customer: function() { + this.frm.doc.customer = this.customer_doc.get_values().full_name; + this.frm.doc.contact_details = JSON.stringify(this.customer_doc.get_values()); + this.party_field.$input.val(this.frm.doc.customer); + this.customers.push({ + name: this.frm.doc.customer, + customer_name: this.frm.doc.customer + }); + + this.customer_doc.hide() + }, + + update_customer_data: function (doc) { var me = this; this.frm.doc.customer = doc.label || doc.name; this.frm.doc.customer_name = doc.customer_name; this.frm.doc.customer_group = doc.customer_group; this.frm.doc.territory = doc.territory; + this.pos_bill.show(); }, - get_customers: function(key){ + get_customers: function (key) { var me = this; key = key.toLowerCase().trim() var re = new RegExp('%', 'g'); var reg = new RegExp(key.replace(re, '\\w*\\s*[a-zA-Z0-9]*')) - if(key){ - return $.grep(this.customers, function(data) { - if(reg.test(data.name.toLowerCase()) + if (key) { + return $.grep(this.customers, function (data) { + if (reg.test(data.name.toLowerCase()) || reg.test(data.customer_name.toLowerCase()) - || (data.customer_group && reg.test(data.customer_group.toLowerCase()))){ + || (data.customer_group && reg.test(data.customer_group.toLowerCase()))) { return data } }) - }else{ - customers = this.customers.sort(function(a,b){ return a.idx < b.idx }) + } else { + customers = this.customers.sort(function (a, b) { return a.idx < b.idx }) return customers.slice(0, 20) } }, - make_item_list: function() { + make_item_list: function () { var me = this; - if(!this.price_list) { + if (!this.price_list) { msgprint(__("Price List not found or disabled")); return; } @@ -536,11 +698,11 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ if (this.items.length > 0) { $.each(this.items, function(index, obj) { - if(index < 30){ + if(index < me.page_len){ $(frappe.render_template("pos_item", { item_code: obj.name, item_price: format_currency(me.price_list_data[obj.name], me.frm.doc.currency), - item_name: obj.name===obj.item_name ? "" : obj.item_name, + item_name: obj.name === obj.item_name ? "" : obj.item_name, item_image: obj.image ? "url('" + obj.image + "')" : null, color: frappe.get_palette(obj.item_name), abbr: frappe.get_abbr(obj.item_name) @@ -548,143 +710,173 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ } }); } else { - $("

    Searching record not found.

    ").appendTo($wrap) + $("

    " + +__("Not items found")+"

    ").appendTo($wrap) } - if(this.items.length == 1 - && this.search.$input.val()) { - this.search.$input.val(""); + if (this.items.length == 1 + && this.serach_item.$input.val()) { + this.serach_item.$input.val(""); this.add_to_cart(); } // if form is local then allow this function - $(me.wrapper).find("div.pos-item").on("click", function() { + $(me.wrapper).find("div.pos-item").on("click", function () { + if(me.list_customers_btn.hasClass("view_customer")) return; + me.customer_validate(); - if(me.frm.doc.docstatus==0) { + if (me.frm.doc.docstatus == 0) { me.items = me.get_items($(this).attr("data-item-code")) me.add_to_cart(); } }); }, - get_items: function(item_code){ + get_items: function (item_code) { // To search item as per the key enter var me = this; this.item_serial_no = {}; this.item_batch_no = {}; - if(item_code){ - return $.grep(this.item_data, function(item){ - if(item.item_code == item_code ){ + if (item_code) { + return $.grep(this.item_data, function (item) { + if (item.item_code == item_code) { return true } }) } - key = this.search.$input.val().toLowerCase().replace(/[&\/\\#,+()\[\]$~.'":*?<>{}]/g,'\\$&'); + this.items_list = this.apply_category(); + + key = this.serach_item.$input.val().toLowerCase().replace(/[&\/\\#,+()\[\]$~.'":*?<>{}]/g, '\\$&'); var re = new RegExp('%', 'g'); var reg = new RegExp(key.replace(re, '[\\w*\\s*[a-zA-Z0-9]*]*')) search_status = true - if(key){ - return $.grep(this.item_data, function(item){ - if(search_status){ - if(in_list(me.batch_no_data[item.item_code], me.search.$input.val())){ + if (key) { + return $.grep(this.items_list, function (item) { + if (search_status) { + if (in_list(me.batch_no_data[item.item_code], me.serach_item.$input.val())) { search_status = false; - return me.item_batch_no[item.item_code] = me.search.$input.val() - } else if( me.serial_no_data[item.item_code] - && in_list(Object.keys(me.serial_no_data[item.item_code]), me.search.$input.val())) { + return me.item_batch_no[item.item_code] = me.serach_item.$input.val() + } else if (me.serial_no_data[item.item_code] + && in_list(Object.keys(me.serial_no_data[item.item_code]), me.serach_item.$input.val())) { search_status = false; - me.item_serial_no[item.item_code] = [me.search.$input.val(), me.serial_no_data[item.item_code][me.search.$input.val()]] + me.item_serial_no[item.item_code] = [me.serach_item.$input.val(), me.serial_no_data[item.item_code][me.serach_item.$input.val()]] return true - } else if(item.barcode == me.search.$input.val()) { + } else if (item.barcode == me.serach_item.$input.val()) { search_status = false; - return item.barcode == me.search.$input.val(); - } else if(reg.test(item.item_code.toLowerCase()) || reg.test(item.description.toLowerCase()) || - reg.test(item.item_name.toLowerCase()) || reg.test(item.item_group.toLowerCase()) ){ + return item.barcode == me.serach_item.$input.val(); + } else if (reg.test(item.item_code.toLowerCase()) || reg.test(item.description.toLowerCase()) || + reg.test(item.item_name.toLowerCase()) || reg.test(item.item_group.toLowerCase())) { return true } } }) - }else{ - return this.item_data; + } else { + return this.items_list; } }, - bind_qty_event: function() { + apply_category: function() { + var me = this; + category = this.search_item_group.$input.val(); + + if(category == 'All Item Groups') { + return this.item_data + } else { + return this.item_data.filter(function(element, index, array){ + return element.item_group == category; + }); + } + }, + + bind_qty_event: function () { var me = this; - $(this.wrapper).find(".pos-item-qty").on("change", function(){ + $(this.wrapper).find(".pos-item-qty").on("change", function () { var item_code = $(this).parents(".pos-bill-item").attr("data-item-code"); var qty = $(this).val(); me.update_qty(item_code, qty) }) - $(this.wrapper).find("[data-action='increase-qty']").on("click", function(){ + $(this.wrapper).find("[data-action='increase-qty']").on("click", function () { var item_code = $(this).parents(".pos-bill-item").attr("data-item-code"); var qty = flt($(this).parents(".pos-bill-item").find('.pos-item-qty').val()) + 1; me.update_qty(item_code, qty) }) - $(this.wrapper).find("[data-action='decrease-qty']").on("click", function(){ + $(this.wrapper).find("[data-action='decrease-qty']").on("click", function () { var item_code = $(this).parents(".pos-bill-item").attr("data-item-code"); var qty = flt($(this).parents(".pos-bill-item").find('.pos-item-qty').val()) - 1; me.update_qty(item_code, qty) }) - }, - update_qty: function(item_code, qty) { - var me = this; - this.items = this.get_items(item_code); - this.validate_serial_no() - this.update_qty_rate_against_item_code(item_code, "qty", qty); - }, - - update_rate: function() { - var me = this; - - $(this.wrapper).find(".pos-item-rate").on("change", function(){ + $(this.wrapper).find(".pos-item-discount").on("change", function () { var item_code = $(this).parents(".pos-bill-item").attr("data-item-code"); - me.update_qty_rate_against_item_code(item_code, "rate", $(this).val()); + var discount = $(this).val(); + me.update_discount(item_code, discount) }) }, - update_qty_rate_against_item_code: function(item_code, field, value){ + update_qty: function (item_code, qty) { var me = this; - if(value < 0){ + this.items = this.get_items(item_code); + this.validate_serial_no() + this.set_item_details(item_code, "qty", qty); + }, + + update_discount: function(item_code, discount) { + var me = this; + this.items = this.get_items(item_code); + this.set_item_details(item_code, "discount_percentage", discount); + }, + + update_rate: function () { + var me = this; + + $(this.wrapper).find(".pos-item-rate").on("change", function () { + var item_code = $(this).parents(".pos-bill-item").attr("data-item-code"); + me.set_item_details(item_code, "rate", $(this).val()); + }) + }, + + set_item_details: function (item_code, field, value) { + var me = this; + if (value < 0) { frappe.throw(__("Enter value must be positive")); } this.remove_item = [] - $.each(this.frm.doc["items"] || [], function(i, d) { - if(d.serial_no && field == 'qty'){ - me.validate_serial_no_qty(d, item_code, field, value) - } - + $.each(this.frm.doc["items"] || [], function (i, d) { if (d.item_code == item_code) { + if (d.serial_no && field == 'qty') { + me.validate_serial_no_qty(d, item_code, field, value) + } + d[field] = flt(value); d.amount = flt(d.rate) * flt(d.qty); - if(d.qty==0){ + if (d.qty == 0) { me.remove_item.push(d.idx) } } }); - if(field == 'qty'){ + if (field == 'qty') { this.remove_zero_qty_item(); } this.update_paid_amount_status(false) }, - remove_zero_qty_item: function(){ + remove_zero_qty_item: function () { var me = this; idx = 0 this.items = [] idx = 0 - $.each(this.frm.doc["items"] || [], function(i, d) { - if(!in_list(me.remove_item, d.idx)){ + $.each(this.frm.doc["items"] || [], function (i, d) { + if (!in_list(me.remove_item, d.idx)) { d.idx = idx; me.items.push(d); idx++; @@ -694,23 +886,23 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ this.frm.doc["items"] = this.items; }, - make_discount_field: function(){ + make_discount_field: function () { var me = this; - this.wrapper.find('input.discount-percentage').on("change", function() { + this.wrapper.find('input.discount-percentage').on("change", function () { me.frm.doc.additional_discount_percentage = flt($(this).val(), precision("additional_discount_percentage")); total = me.frm.doc.grand_total - if(me.frm.doc.apply_discount_on == 'Net Total'){ + if (me.frm.doc.apply_discount_on == 'Net Total') { total = me.frm.doc.net_total } - me.frm.doc.discount_amount = flt(total*flt(me.frm.doc.additional_discount_percentage) / 100, precision("discount_amount")); + me.frm.doc.discount_amount = flt(total * flt(me.frm.doc.additional_discount_percentage) / 100, precision("discount_amount")); me.wrapper.find('input.discount-amount').val(me.frm.doc.discount_amount) me.refresh(); }); - this.wrapper.find('input.discount-amount').on("change", function() { + this.wrapper.find('input.discount-amount').on("change", function () { me.frm.doc.discount_amount = flt($(this).val(), precision("discount_amount")); me.frm.doc.additional_discount_percentage = 0.0; me.wrapper.find('input.discount-percentage').val(0); @@ -718,14 +910,14 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ }); }, - customer_validate: function(){ + customer_validate: function () { var me = this; - if(!this.frm.doc.customer){ + if (!this.frm.doc.customer) { frappe.throw(__("Please select customer")) } }, - add_to_cart: function() { + add_to_cart: function () { var me = this; var caught = false; var no_of_items = me.wrapper.find(".pos-bill-item").length; @@ -736,17 +928,17 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ this.validate_warehouse(); if (no_of_items != 0) { - $.each(this.frm.doc["items"] || [], function(i, d) { + $.each(this.frm.doc["items"] || [], function (i, d) { if (d.item_code == me.items[0].item_code) { caught = true; d.qty += 1; d.amount = flt(d.rate) * flt(d.qty); - if(me.item_serial_no[d.item_code]){ + if (me.item_serial_no[d.item_code]) { d.serial_no += '\n' + me.item_serial_no[d.item_code][0] d.warehouse = me.item_serial_no[d.item_code][1] } - if(me.item_batch_no.length){ + if (me.item_batch_no.length) { d.batch_no = me.item_batch_no[d.item_code] } } @@ -760,7 +952,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ this.update_paid_amount_status(false) }, - add_new_item_to_grid: function() { + add_new_item_to_grid: function () { var me = this; this.child = frappe.model.add_child(this.frm.doc, this.frm.doc.doctype + " Item", "items"); this.child.item_code = this.items[0].item_code; @@ -772,7 +964,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ this.child.cost_center = this.pos_profile_data['cost_center'] || this.items[0].cost_center; this.child.income_account = this.pos_profile_data['income_account'] || this.items[0].income_account; this.child.warehouse = (this.item_serial_no[this.child.item_code] - ? this.item_serial_no[this.child.item_code][1] : (this.pos_profile_data['warehouse'] || this.items[0].default_warehouse) ); + ? this.item_serial_no[this.child.item_code][1] : (this.pos_profile_data['warehouse'] || this.items[0].default_warehouse)); this.child.price_list_rate = flt(this.price_list_data[this.child.item_code], 9) / flt(this.frm.doc.conversion_rate, 9); this.child.rate = flt(this.price_list_data[this.child.item_code], 9) / flt(this.frm.doc.conversion_rate, 9); this.child.actual_qty = me.get_actual_qty(this.items[0]); @@ -783,15 +975,15 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ this.child.item_tax_rate = JSON.stringify(this.tax_data[this.child.item_code]); }, - update_paid_amount_status: function(update_paid_amount){ - if(this.name){ + update_paid_amount_status: function (update_paid_amount) { + if (this.name) { update_paid_amount = update_paid_amount ? false : true; } this.refresh(update_paid_amount); }, - refresh: function(update_paid_amount) { + refresh: function (update_paid_amount) { var me = this; this.refresh_fields(update_paid_amount); this.bind_qty_event(); @@ -799,7 +991,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ this.set_primary_action(); }, - refresh_fields: function(update_paid_amount) { + refresh_fields: function (update_paid_amount) { this.apply_pricing_rule(); this.discount_amount_applied = false; this._calculate_taxes_and_totals(); @@ -810,40 +1002,45 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ this.set_totals(); }, - get_company_currency: function() { + get_company_currency: function () { return erpnext.get_currency(this.frm.doc.company); }, - show_item_wise_taxes: function(){ + show_item_wise_taxes: function () { return null; }, - show_items_in_item_cart: function() { + show_items_in_item_cart: function () { var me = this; var $items = this.wrapper.find(".items").empty(); - $.each(this.frm.doc.items|| [], function(i, d) { + $.each(this.frm.doc.items || [], function (i, d) { $(frappe.render_template("pos_bill_item", { item_code: d.item_code, - item_name: (d.item_name===d.item_code || !d.item_name) ? "" : ("
    " + d.item_name), + item_name: (d.item_name === d.item_code || !d.item_name) ? "" : ("
    " + d.item_name), qty: d.qty, - actual_qty: me.actual_qty_dict[d.item_code] || 0, + discount_percentage: d.discount_percentage || 0.0, + actual_qty: me.actual_qty_dict[d.item_code] || 0.0, projected_qty: d.projected_qty, rate: format_number(d.rate, me.frm.doc.currency), - enabled: me.pos_profile_data["allow_user_to_edit_rate"] ? true: false, + enabled: me.pos_profile_data["allow_user_to_edit_rate"] ? true : false, amount: format_currency(d.amount, me.frm.doc.currency) })).appendTo($items); }); - this.wrapper.find("input.pos-item-qty").on("focus", function() { + this.wrapper.find("input.pos-item-qty").on("focus", function () { $(this).select(); }); - this.wrapper.find("input.pos-item-rate").on("focus", function() { + this.wrapper.find("input.pos-item-discount").on("focus", function () { + $(this).select(); + }); + + this.wrapper.find("input.pos-item-rate").on("focus", function () { $(this).select(); }); }, - set_taxes: function(){ + set_taxes: function () { var me = this; me.frm.doc.total_taxes_and_charges = 0.0 @@ -852,7 +1049,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ .find(".tax-area").toggleClass("hide", (taxes && taxes.length) ? false : true) .find(".tax-table").empty(); - $.each(taxes, function(i, d) { + $.each(taxes, function (i, d) { if (d.tax_amount && cint(d.included_in_print_rate) == 0) { $(frappe.render_template("pos_tax_row", { description: d.description, @@ -863,104 +1060,106 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ }); }, - set_totals: function() { + set_totals: function () { var me = this; this.wrapper.find(".net-total").text(format_currency(me.frm.doc.total, me.frm.doc.currency)); this.wrapper.find(".grand-total").text(format_currency(me.frm.doc.grand_total, me.frm.doc.currency)); }, - set_primary_action: function() { + set_primary_action: function () { var me = this; - if (this.frm.doc.docstatus==0) { - this.page.set_primary_action(__("Pay"), function() { + if (this.frm.doc.docstatus == 0) { + this.page.set_primary_action(__("Pay"), function () { me.validate(); me.update_paid_amount_status(true); me.create_invoice(); me.make_payment(); - }, "octicon octfa fa-credit-card"); - }else if(this.frm.doc.docstatus == 1) { - this.page.set_primary_action(__("Print"), function() { + }, "fa fa-credit-card"); + } else if (this.frm.doc.docstatus == 1) { + this.page.set_primary_action(__("Print"), function () { html = frappe.render(me.print_template_data, me.frm.doc) me.print_document(html) }) - }else { + } else { this.page.clear_primary_action() } - this.page.set_secondary_action(__("New"), function() { - me.save_previous_entry(); - me.create_new(); - }, "octicon octfa fa-plus").addClass("btn-primary"); + // this.page.set_secondary_action(__("New"), function () { + // me.save_previous_entry(); + // me.create_new(); + // }, "fa fa-plus").addClass("btn-primary"); }, - print_dialog: function(){ + print_dialog: function () { var me = this; msgprint = frappe.msgprint(format('{0}\ {1}', [ - __('Print'), __('New') - ])); + __('Print'), __('New') + ])); - $('.print_doc').click(function(){ + $('.print_doc').click(function () { html = frappe.render(me.print_template_data, me.frm.doc) me.print_document(html) }) - $('.new_doc').click(function(){ + $('.new_doc').click(function () { msgprint.hide() me.create_new(); }) }, - print_document: function(html){ + print_document: function (html) { var w = window.open(); w.document.write(html); w.document.close(); - setTimeout(function(){ + setTimeout(function () { w.print(); w.close(); }, 1000) }, - submit_invoice: function(){ + submit_invoice: function () { var me = this; this.change_status(); - if(this.frm.doc.docstatus == 1){ + if (this.frm.doc.docstatus == 1) { this.print_dialog() } }, - change_status: function(){ - if(this.frm.doc.docstatus == 0){ + change_status: function () { + if (this.frm.doc.docstatus == 0) { this.frm.doc.docstatus = 1; this.update_invoice(); this.disable_input_field(); } }, - disable_input_field: function(){ + disable_input_field: function () { var pointer_events = 'inherit' $(this.wrapper).find('input').attr("disabled", false); + $(this.wrapper).find('select').attr("disabled", false); - if(this.frm.doc.docstatus == 1){ + if (this.frm.doc.docstatus == 1) { pointer_events = 'none'; $(this.wrapper).find('input').attr("disabled", true); + $(this.wrapper).find('select').attr("disabled", true); } - $(this.wrapper).find('.pos-bill-wrapper').css('pointer-events', pointer_events); + $(this.wrapper).find('.pos-bill').css('pointer-events', pointer_events); $(this.wrapper).find('.pos-items-section').css('pointer-events', pointer_events); this.set_primary_action(); }, - create_invoice: function(){ + create_invoice: function () { var me = this; var invoice_data = {} this.si_docs = this.get_doc_from_localstorage(); - if(this.name){ + if (this.name) { this.update_invoice() - }else{ + } else { this.name = $.now(); this.frm.doc.offline_pos_name = this.name; this.frm.doc.posting_date = frappe.datetime.get_today(); @@ -970,14 +1169,15 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ this.update_localstorage(); this.set_primary_action(); } + return invoice_data; }, - update_invoice: function(){ + update_invoice: function () { var me = this; this.si_docs = this.get_doc_from_localstorage(); - $.each(this.si_docs, function(index, data){ - for(key in data){ - if(key == me.name){ + $.each(this.si_docs, function (index, data) { + for (key in data) { + if (key == me.name) { me.si_docs[index][key] = me.frm.doc; me.update_localstorage(); } @@ -985,41 +1185,41 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ }) }, - update_localstorage: function(){ - try{ + update_localstorage: function () { + try { localStorage.setItem('sales_invoice_doc', JSON.stringify(this.si_docs)); - }catch(e){ + } catch (e) { frappe.throw(__("LocalStorage is full , did not save")) } }, - get_doc_from_localstorage: function(){ - try{ + get_doc_from_localstorage: function () { + try { return JSON.parse(localStorage.getItem('sales_invoice_doc')) || []; - }catch(e){ + } catch (e) { return [] } }, - set_interval_for_si_sync: function(){ + set_interval_for_si_sync: function () { var me = this; - setInterval(function(){ + setInterval(function () { me.sync_sales_invoice() }, 60000) }, - sync_sales_invoice: function(){ + sync_sales_invoice: function () { var me = this; this.si_docs = this.get_submitted_invoice(); - if(this.si_docs.length){ + if (this.si_docs.length) { frappe.call({ method: "erpnext.accounts.doctype.sales_invoice.pos.make_invoice", args: { doc_list: me.si_docs }, - callback: function(r){ - if(r.message){ + callback: function (r) { + if (r.message) { me.removed_items = r.message; me.remove_doc_from_localstorage(); } @@ -1028,14 +1228,14 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ } }, - get_submitted_invoice: function(){ + get_submitted_invoice: function () { var invoices = []; var index = 1; docs = this.get_doc_from_localstorage(); - if(docs){ - invoices = $.map(docs, function(data){ - for(key in data){ - if(data[key].docstatus == 1 && index < 50){ + if (docs) { + invoices = $.map(docs, function (data) { + for (key in data) { + if (data[key].docstatus == 1 && index < 50) { index++ data[key].docstatus = 0; return data @@ -1047,14 +1247,14 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ return invoices }, - remove_doc_from_localstorage: function(){ + remove_doc_from_localstorage: function () { var me = this; this.si_docs = this.get_doc_from_localstorage(); this.new_si_docs = []; - if(this.removed_items){ - $.each(this.si_docs, function(index, data){ - for(key in data){ - if(!in_list(me.removed_items, key)){ + if (this.removed_items) { + $.each(this.si_docs, function (index, data) { + for (key in data) { + if (!in_list(me.removed_items, key)) { me.new_si_docs.push(data); } } @@ -1064,44 +1264,44 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ } }, - validate: function(){ + validate: function () { var me = this; this.customer_validate(); this.item_validate(); this.validate_mode_of_payments(); }, - item_validate: function(){ - if(this.frm.doc.items.length == 0){ + item_validate: function () { + if (this.frm.doc.items.length == 0) { frappe.throw(__("Select items to save the invoice")) } }, - validate_mode_of_payments: function(){ - if (this.frm.doc.payments.length === 0){ + validate_mode_of_payments: function () { + if (this.frm.doc.payments.length === 0) { frappe.throw(__("Payment Mode is not configured. Please check, whether account has been set on Mode of Payments or on POS Profile.")) } }, - validate_serial_no: function(){ + validate_serial_no: function () { var me = this; var item_code = serial_no = ''; - for (key in this.item_serial_no){ + for (key in this.item_serial_no) { item_code = key; serial_no = me.item_serial_no[key][0]; } - if(this.items[0].has_serial_no && serial_no == ""){ + if (this.items[0].has_serial_no && serial_no == "") { this.refresh(); frappe.throw(__(repl("Error: Serial no is mandatory for item %(item)s", { 'item': this.items[0].item_code }))) } - if(item_code && serial_no){ - $.each(this.frm.doc.items, function(index, data){ - if(data.item_code == item_code){ - if(in_list(data.serial_no.split('\n'), serial_no)){ + if (item_code && serial_no) { + $.each(this.frm.doc.items, function (index, data) { + if (data.item_code == item_code) { + if (in_list(data.serial_no.split('\n'), serial_no)) { frappe.throw(__(repl("Serial no %(serial_no)s is already taken", { 'serial_no': serial_no }))) @@ -1111,7 +1311,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ } }, - validate_serial_no_qty: function(args, item_code, field, value){ + validate_serial_no_qty: function (args, item_code, field, value) { var me = this; if (args.item_code == item_code && args.serial_no && field == 'qty' && cint(value) != value) { @@ -1120,7 +1320,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ frappe.throw(__("Serial no item cannot be a fraction")) } - if(args.item_code == item_code && args.serial_no && args.serial_no.split('\n').length != cint(value)){ + if (args.item_code == item_code && args.serial_no && args.serial_no.split('\n').length != cint(value)) { args.qty = 0.0; args.serial_no = '' this.refresh(); @@ -1130,42 +1330,44 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ } }, - mandatory_batch_no: function(){ + mandatory_batch_no: function () { var me = this; - if(this.items[0].has_batch_no && !this.item_batch_no[this.items[0].item_code]){ + if (this.items[0].has_batch_no && !this.item_batch_no[this.items[0].item_code]) { frappe.throw(__(repl("Error: Batch no is mandatory for item %(item)s", { 'item': this.items[0].item_code }))) } }, - apply_pricing_rule: function(){ + apply_pricing_rule: function () { var me = this; - $.each(this.frm.doc["items"], function(n, item) { + $.each(this.frm.doc["items"], function (n, item) { pricing_rule = me.get_pricing_rule(item) me.validate_pricing_rule(pricing_rule) - if(pricing_rule.length){ + if (pricing_rule.length) { + item.pricing_rule = pricing_rule[0].name; item.margin_type = pricing_rule[0].margin_type; item.price_list_rate = pricing_rule[0].price || item.price_list_rate; item.margin_rate_or_amount = pricing_rule[0].margin_rate_or_amount; item.discount_percentage = pricing_rule[0].discount_percentage || 0.0; - me.apply_pricing_rule_on_item(item) - } else if(item.discount_percentage > 0 || item.margin_rate_or_amount > 0) { + } else if ((item.discount_percentage > 0 || item.margin_rate_or_amount > 0) && item.pricing_rule) { item.margin_rate_or_amount = 0.0; item.discount_percentage = 0.0; - me.apply_pricing_rule_on_item(item) + item.pricing_rule = null; } + + me.apply_pricing_rule_on_item(item) }) }, - get_pricing_rule: function(item){ + get_pricing_rule: function (item) { var me = this; - return $.grep(this.pricing_rules, function(data){ - if(item.qty >= data.min_qty && (item.qty <= (data.max_qty ? data.max_qty : item.qty)) ){ - if(data.item_code == item.item_code || in_list(['All Item Groups', item.item_group], data.item_group)) { - if(in_list(['Customer', 'Customer Group', 'Territory', 'Campaign'], data.applicable_for)){ + return $.grep(this.pricing_rules, function (data) { + if (item.qty >= data.min_qty && (item.qty <= (data.max_qty ? data.max_qty : item.qty))) { + if (data.item_code == item.item_code || in_list(['All Item Groups', item.item_group], data.item_group)) { + if (in_list(['Customer', 'Customer Group', 'Territory', 'Campaign'], data.applicable_for)) { return me.validate_condition(data) - }else{ + } else { return true } } @@ -1173,15 +1375,15 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ }) }, - validate_condition: function(data){ + validate_condition: function (data) { //This method check condition based on applicable for condition = this.get_mapper_for_pricing_rule(data)[data.applicable_for] - if(in_list(condition[1], condition[0])){ + if (in_list(condition[1], condition[0])) { return true } }, - get_mapper_for_pricing_rule: function(data){ + get_mapper_for_pricing_rule: function (data) { return { 'Customer': [data.customer, [this.frm.doc.customer]], 'Customer Group': [data.customer_group, [this.frm.doc.customer_group, 'All Customer Groups']], @@ -1190,32 +1392,32 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ } }, - validate_pricing_rule: function(pricing_rule){ + validate_pricing_rule: function (pricing_rule) { //This method validate duplicate pricing rule var pricing_rule_name = ''; var priority = 0; var pricing_rule_list = []; var priority_list = [] - if(pricing_rule.length > 1){ + if (pricing_rule.length > 1) { - $.each(pricing_rule, function(index, data){ + $.each(pricing_rule, function (index, data) { pricing_rule_name += data.name + ',' priority_list.push(data.priority) - if(priority <= data.priority){ + if (priority <= data.priority) { priority = data.priority pricing_rule_list.push(data) } }) count = 0 - $.each(priority_list, function(index, value){ - if(value == priority){ + $.each(priority_list, function (index, value) { + if (value == priority) { count++ } }) - if(priority == 0 || count > 1){ + if (priority == 0 || count > 1) { frappe.throw(__(repl("Multiple Price Rules exists with same criteria, please resolve conflict by assigning priority. Price Rules: %(pricing_rule)s", { 'pricing_rule': pricing_rule_name }))) @@ -1225,17 +1427,17 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ } }, - validate_warehouse: function(){ - if(this.items[0].is_stock_item && !this.items[0].default_warehouse && !this.pos_profile_data['warehouse']){ + validate_warehouse: function () { + if (this.items[0].is_stock_item && !this.items[0].default_warehouse && !this.pos_profile_data['warehouse']) { frappe.throw(__("Default warehouse is required for selected item")) } }, - get_actual_qty: function(item) { + get_actual_qty: function (item) { this.actual_qty = 0.0; var warehouse = this.pos_profile_data['warehouse'] || item.default_warehouse; - if(warehouse && this.bin_data[item.item_code]) { + if (warehouse && this.bin_data[item.item_code]) { this.actual_qty = this.bin_data[item.item_code][warehouse] || 0; this.actual_qty_dict[item.item_code] = this.actual_qty } diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py index 05a3c11d91b..a8d166eef11 100644 --- a/erpnext/accounts/party.py +++ b/erpnext/accounts/party.py @@ -171,13 +171,13 @@ def get_party_account(party_type, party, company): account = frappe.db.get_value("Party Account", {"parenttype": party_type, "parent": party, "company": company}, "account") - if not account: + if not account and party_type in ['Customer', 'Supplier']: party_group_doctype = "Customer Group" if party_type=="Customer" else "Supplier Type" group = frappe.db.get_value(party_type, party, scrub(party_group_doctype)) account = frappe.db.get_value("Party Account", {"parenttype": party_group_doctype, "parent": group, "company": company}, "account") - if not account: + if not account and party_type in ['Customer', 'Supplier']: default_account_name = "default_receivable_account" \ if party_type=="Customer" else "default_payable_account" account = frappe.db.get_value("Company", company, default_account_name) @@ -249,7 +249,7 @@ def validate_party_accounts(doc): if existing_gle_currency and party_account_currency != existing_gle_currency: frappe.throw(_("Accounting entries have already been made in currency {0} for company {1}. Please select a receivable or payable account with currency {0}.").format(existing_gle_currency, account.company)) - if doc.default_currency and party_account_currency and company_default_currency: + if doc.get("default_currency") and party_account_currency and company_default_currency: if doc.default_currency != party_account_currency and doc.default_currency != company_default_currency: frappe.throw(_("Billing currency must be equal to either default comapany's currency or party account currency")) diff --git a/erpnext/accounts/party_status.py b/erpnext/accounts/party_status.py deleted file mode 100644 index 6d9efb190b6..00000000000 --- a/erpnext/accounts/party_status.py +++ /dev/null @@ -1,81 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals - -import frappe - -from frappe.utils import evaluate_filters -from frappe.desk.notifications import get_filters_for - -# NOTE: if you change this also update triggers in erpnext/hooks.py -status_depends_on = { - 'Customer': ('Opportunity', 'Quotation', 'Sales Order', 'Delivery Note', 'Sales Invoice', 'Project', 'Issue'), - 'Supplier': ('Supplier Quotation', 'Purchase Order', 'Purchase Receipt', 'Purchase Invoice') -} - -default_status = { - 'Customer': 'Active', - 'Supplier': None -} - -def notify_status(doc, method=None): - '''Notify status to customer, supplier''' - - party_type = None - for key, doctypes in status_depends_on.iteritems(): - if doc.doctype in doctypes: - party_type = key - break - - if not party_type: - return - - name = doc.get(party_type.lower()) - if not name: - return - - party = frappe.get_doc(party_type, name) - filters = get_filters_for(doc.doctype) - party.flags.ignore_mandatory = True - - status = None - if filters: - if evaluate_filters(doc, filters): - # filters match, passed document is open - status = 'Open' - - if status=='Open': - if party.status != 'Open': - # party not open, make it open - party.status = 'Open' - party.save(ignore_permissions=True) - - else: - if party.status == 'Open': - # may be open elsewhere, check - # default status - update_status(party) - - party.update_modified() - party.notify_update() - -def get_party_status(doc): - '''return party status based on open documents''' - status = default_status[doc.doctype] - for doctype in status_depends_on[doc.doctype]: - filters = get_filters_for(doctype) - filters[doc.doctype.lower()] = doc.name - if filters: - open_count = frappe.get_all(doctype, fields='name', filters=filters, limit_page_length=1) - if len(open_count) > 0: - status = 'Open' - break - - return status - -def update_status(doc): - '''Set status as open if there is any open notification''' - status = get_party_status(doc) - if doc.status != status: - doc.db_set('status', status) diff --git a/erpnext/accounts/report/general_ledger/general_ledger.js b/erpnext/accounts/report/general_ledger/general_ledger.js index ab7ad499c96..a422871b05b 100644 --- a/erpnext/accounts/report/general_ledger/general_ledger.js +++ b/erpnext/accounts/report/general_ledger/general_ledger.js @@ -59,8 +59,8 @@ frappe.query_reports["General Ledger"] = { { "fieldname":"party_type", "label": __("Party Type"), - "fieldtype": "Select", - "options": ["", "Customer", "Supplier"], + "fieldtype": "Link", + "options": "Party Type", "default": "" }, { diff --git a/erpnext/accounts/report/unpaid_expense_claim/__init__.py b/erpnext/accounts/report/unpaid_expense_claim/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/accounts/report/unpaid_expense_claim/unpaid_expense_claim.js b/erpnext/accounts/report/unpaid_expense_claim/unpaid_expense_claim.js new file mode 100644 index 00000000000..811414aaf07 --- /dev/null +++ b/erpnext/accounts/report/unpaid_expense_claim/unpaid_expense_claim.js @@ -0,0 +1,12 @@ +// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors +// For license information, please see license.txt + +frappe.query_reports["Unpaid Expense Claim"] = { + "filters": [ + { + "fieldname":"employee", + "label": __("Employee"), + "fieldtype": "Link" + } + ] +} diff --git a/erpnext/accounts/report/unpaid_expense_claim/unpaid_expense_claim.json b/erpnext/accounts/report/unpaid_expense_claim/unpaid_expense_claim.json new file mode 100644 index 00000000000..a1087c0a6b8 --- /dev/null +++ b/erpnext/accounts/report/unpaid_expense_claim/unpaid_expense_claim.json @@ -0,0 +1,18 @@ +{ + "add_total_row": 0, + "apply_user_permissions": 1, + "creation": "2017-01-04 16:26:18.309717", + "disabled": 0, + "docstatus": 0, + "doctype": "Report", + "idx": 0, + "is_standard": "Yes", + "modified": "2017-01-04 16:26:18.309717", + "modified_by": "Administrator", + "module": "Accounts", + "name": "Unpaid Expense Claim", + "owner": "Administrator", + "ref_doctype": "Expense Claim", + "report_name": "Unpaid Expense Claim", + "report_type": "Script Report" +} \ No newline at end of file diff --git a/erpnext/accounts/report/unpaid_expense_claim/unpaid_expense_claim.py b/erpnext/accounts/report/unpaid_expense_claim/unpaid_expense_claim.py new file mode 100644 index 00000000000..eee620b7cc8 --- /dev/null +++ b/erpnext/accounts/report/unpaid_expense_claim/unpaid_expense_claim.py @@ -0,0 +1,34 @@ +# 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, data = [], [] + columns = get_columns() + data = get_unclaimed_expese_claims(filters) + return columns, data + +def get_columns(): + return [_("Employee") + ":Link/Employee:120", _("Employee Name") + "::120",_("Expense Claim") + ":Link/Expense Claim:120", + _("Sanctioned Amount") + ":Currency:120", _("Paid Amount") + ":Currency:120", _("Outstanding Amount") + ":Currency:150"] + +def get_unclaimed_expese_claims(filters): + cond = "1=1" + if filters.get("employee"): + cond = "ec.employee = %(employee)s" + + return frappe.db.sql(""" + select + ec.employee, ec.employee_name, ec.name, ec.total_sanctioned_amount, ec.total_amount_reimbursed, + sum(gle.credit_in_account_currency - gle.debit_in_account_currency) as outstanding_amt + from + `tabExpense Claim` ec, `tabGL Entry` gle + where + gle.against_voucher_type = "Expense Claim" and gle.against_voucher = ec.name + and gle.party is not null and ec.docstatus = 1 and ec.is_paid = 0 and {cond} group by ec.name + having + outstanding_amt > 0 + """.format(cond=cond), filters, as_list=1) diff --git a/erpnext/buying/doctype/supplier/supplier.json b/erpnext/buying/doctype/supplier/supplier.json index 4b8f8c52318..277a5b96a9b 100644 --- a/erpnext/buying/doctype/supplier/supplier.json +++ b/erpnext/buying/doctype/supplier/supplier.json @@ -158,35 +158,6 @@ "set_only_once": 0, "unique": 0 }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "status", - "fieldtype": "Select", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Status", - "length": 0, - "no_copy": 0, - "options": "\nOpen", - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, { "allow_on_submit": 0, "bold": 0, @@ -796,7 +767,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2016-11-07 05:24:30.465053", + "modified": "2017-01-30 00:52:31.193443", "modified_by": "Administrator", "module": "Buying", "name": "Supplier", @@ -813,7 +784,6 @@ "export": 0, "if_owner": 0, "import": 0, - "is_custom": 0, "permlevel": 0, "print": 1, "read": 1, @@ -834,7 +804,6 @@ "export": 0, "if_owner": 0, "import": 0, - "is_custom": 0, "permlevel": 0, "print": 1, "read": 1, @@ -855,7 +824,6 @@ "export": 0, "if_owner": 0, "import": 0, - "is_custom": 0, "permlevel": 0, "print": 1, "read": 1, @@ -876,7 +844,6 @@ "export": 0, "if_owner": 0, "import": 0, - "is_custom": 0, "permlevel": 0, "print": 0, "read": 1, @@ -897,7 +864,6 @@ "export": 0, "if_owner": 0, "import": 0, - "is_custom": 0, "permlevel": 0, "print": 1, "read": 1, @@ -918,7 +884,6 @@ "export": 0, "if_owner": 0, "import": 0, - "is_custom": 0, "permlevel": 0, "print": 0, "read": 1, @@ -939,7 +904,6 @@ "export": 0, "if_owner": 0, "import": 0, - "is_custom": 0, "permlevel": 0, "print": 1, "read": 1, @@ -957,5 +921,6 @@ "search_fields": "supplier_name, supplier_type", "sort_order": "ASC", "title_field": "supplier_name", + "track_changes": 0, "track_seen": 0 } \ No newline at end of file diff --git a/erpnext/buying/doctype/supplier/supplier.py b/erpnext/buying/doctype/supplier/supplier.py index 7f927672794..704e8285b1f 100644 --- a/erpnext/buying/doctype/supplier/supplier.py +++ b/erpnext/buying/doctype/supplier/supplier.py @@ -11,7 +11,6 @@ from frappe.geo.address_and_contact import (load_address_and_contact, from erpnext.utilities.transaction_base import TransactionBase from erpnext.accounts.party import validate_party_accounts, get_timeline_data # keep this -from erpnext.accounts.party_status import get_party_status class Supplier(TransactionBase): def get_feed(self): @@ -59,7 +58,6 @@ class Supplier(TransactionBase): msgprint(_("Series is mandatory"), raise_exception=1) validate_party_accounts(self) - self.status = get_party_status(self) def on_trash(self): delete_contact_and_address('Supplier', self.name) diff --git a/erpnext/buying/doctype/supplier/supplier_list.js b/erpnext/buying/doctype/supplier/supplier_list.js index acf8e68ee33..dd98c434f1e 100644 --- a/erpnext/buying/doctype/supplier/supplier_list.js +++ b/erpnext/buying/doctype/supplier/supplier_list.js @@ -1,8 +1,3 @@ frappe.listview_settings['Supplier'] = { - add_fields: ["supplier_name", "supplier_type", 'status'], - get_indicator: function(doc) { - if(doc.status==="Open") { - return [doc.status, "red", "status,=," + doc.status]; - } - } + add_fields: ["supplier_name", "supplier_type"], }; diff --git a/erpnext/config/stock.py b/erpnext/config/stock.py index 14e79999f04..a98c40e091d 100644 --- a/erpnext/config/stock.py +++ b/erpnext/config/stock.py @@ -49,6 +49,11 @@ def get_data(): "name": "Stock Projected Qty", "doctype": "Item", }, + { + "type": "page", + "name": "stock-balance", + "label": _("Stock Summary") + }, { "type": "report", "is_query_report": True, diff --git a/erpnext/controllers/status_updater.py b/erpnext/controllers/status_updater.py index 4fbee58c842..55bcaf387f7 100644 --- a/erpnext/controllers/status_updater.py +++ b/erpnext/controllers/status_updater.py @@ -6,7 +6,6 @@ import frappe from frappe.utils import flt, comma_or, nowdate, getdate from frappe import _ from frappe.model.document import Document -from erpnext.accounts.party_status import notify_status def validate_status(status, options): if status not in options: @@ -287,7 +286,6 @@ class StatusUpdater(Document): target = frappe.get_doc(args["target_parent_dt"], args["name"]) target.set_status(update=True) target.notify_update() - notify_status(target) def _update_modified(self, args, update_modified): args['update_modified'] = '' diff --git a/erpnext/crm/doctype/lead/lead.py b/erpnext/crm/doctype/lead/lead.py index 411f59730e1..a268ea22352 100644 --- a/erpnext/crm/doctype/lead/lead.py +++ b/erpnext/crm/doctype/lead/lead.py @@ -4,7 +4,8 @@ from __future__ import unicode_literals import frappe from frappe import _ -from frappe.utils import cstr, validate_email_add, cint, comma_and, has_gravatar, nowdate +from frappe.utils import (cstr, validate_email_add, cint, comma_and, has_gravatar, + getdate, nowdate) from frappe.model.mapper import get_mapped_doc from erpnext.controllers.selling_controller import SellingController @@ -45,7 +46,7 @@ class Lead(SellingController): self.image = has_gravatar(self.email_id) - if self.contact_date and self.contact_date < nowdate(): + if self.contact_date and getdate(self.contact_date) < nowdate(): frappe.throw(_("Next Contact Date cannot be in the past")) def on_update(self): @@ -87,7 +88,7 @@ class Lead(SellingController): "lead": self.name, "docstatus": 1, "status": ["!=", "Lost"] - + }) def has_lost_quotation(self): diff --git a/erpnext/demo/user/hr.py b/erpnext/demo/user/hr.py index e18a123ec44..25366024c1c 100644 --- a/erpnext/demo/user/hr.py +++ b/erpnext/demo/user/hr.py @@ -6,6 +6,7 @@ from frappe.utils import random_string, add_days, get_last_day, getdate from erpnext.projects.doctype.timesheet.test_timesheet import make_timesheet from erpnext.projects.doctype.timesheet.timesheet import make_salary_slip, make_sales_invoice from frappe.utils.make_random import get_random +from erpnext.hr.doctype.expense_claim.test_expense_claim import get_payable_account from erpnext.hr.doctype.expense_claim.expense_claim import get_expense_approver, make_bank_entry from erpnext.hr.doctype.leave_application.leave_application import (get_leave_balance_on, OverlapError, AttendanceAlreadyMarkedError) @@ -50,6 +51,7 @@ def work(): expense_claim.extend('expenses', get_expenses()) expense_claim.employee = get_random("Employee") expense_claim.company = frappe.flags.company + expense_claim.payable_account = get_payable_account(expense_claim.company) expense_claim.posting_date = frappe.flags.current_date expense_claim.exp_approver = filter((lambda x: x[0] != 'Administrator'), get_expense_approver(None, '', None, 0, 20, None))[0][0] expense_claim.insert() diff --git a/erpnext/docs/assets/img/accounts/offline-records.png b/erpnext/docs/assets/img/accounts/offline-records.png index 78bb730b091..a73f696e800 100644 Binary files a/erpnext/docs/assets/img/accounts/offline-records.png and b/erpnext/docs/assets/img/accounts/offline-records.png differ diff --git a/erpnext/docs/assets/img/accounts/pos-customer.png b/erpnext/docs/assets/img/accounts/pos-customer.png index ffb058ae0f0..c3cbb8a6083 100644 Binary files a/erpnext/docs/assets/img/accounts/pos-customer.png and b/erpnext/docs/assets/img/accounts/pos-customer.png differ diff --git a/erpnext/docs/assets/img/accounts/pos-item.png b/erpnext/docs/assets/img/accounts/pos-item.png index 321e8dc392a..14bd371ea4e 100644 Binary files a/erpnext/docs/assets/img/accounts/pos-item.png and b/erpnext/docs/assets/img/accounts/pos-item.png differ diff --git a/erpnext/docs/assets/img/human-resources/employee_account.png b/erpnext/docs/assets/img/human-resources/employee_account.png new file mode 100644 index 00000000000..a9a60664eff Binary files /dev/null and b/erpnext/docs/assets/img/human-resources/employee_account.png differ diff --git a/erpnext/docs/assets/img/human-resources/expense_claim.png b/erpnext/docs/assets/img/human-resources/expense_claim.png index ddca1005e1e..9647d3d7f0e 100644 Binary files a/erpnext/docs/assets/img/human-resources/expense_claim.png and b/erpnext/docs/assets/img/human-resources/expense_claim.png differ diff --git a/erpnext/docs/assets/img/human-resources/expense_claim_book.png b/erpnext/docs/assets/img/human-resources/expense_claim_book.png new file mode 100644 index 00000000000..4b816040d49 Binary files /dev/null and b/erpnext/docs/assets/img/human-resources/expense_claim_book.png differ diff --git a/erpnext/docs/assets/img/human-resources/payment.png b/erpnext/docs/assets/img/human-resources/payment.png new file mode 100644 index 00000000000..f6b6e5d8a0d Binary files /dev/null and b/erpnext/docs/assets/img/human-resources/payment.png differ diff --git a/erpnext/docs/assets/img/human-resources/payment_entry.png b/erpnext/docs/assets/img/human-resources/payment_entry.png new file mode 100644 index 00000000000..a499ccfb71f Binary files /dev/null and b/erpnext/docs/assets/img/human-resources/payment_entry.png differ diff --git a/erpnext/docs/assets/img/human-resources/unclaimed_expense_claims.png b/erpnext/docs/assets/img/human-resources/unclaimed_expense_claims.png new file mode 100644 index 00000000000..1581bb77a4f Binary files /dev/null and b/erpnext/docs/assets/img/human-resources/unclaimed_expense_claims.png differ diff --git a/erpnext/docs/user/manual/en/human-resources/expense-claim.md b/erpnext/docs/user/manual/en/human-resources/expense-claim.md index da3b2eedffd..1d4996dabcd 100644 --- a/erpnext/docs/user/manual/en/human-resources/expense-claim.md +++ b/erpnext/docs/user/manual/en/human-resources/expense-claim.md @@ -9,6 +9,10 @@ To make a new Expense Claim, go to: Set the Employee ID, date and the list of expenses that are to be claimed and “Submit” the record. +### Set Account for Employee +Set employee's expense account on the employee form, system books an expense amount of an employee under this account. +Expense Claim + ### Approving Expenses Approver for the Expense Claim is selected by an Employee himself. Users to whom `Expense Approver` role is assigned will shown in the Expense Claim Approver field. @@ -18,11 +22,25 @@ After saving Expense Claim, Employee should [Assign document to Approver]({{docs Expense Claim Approver can update the “Sanctioned Amounts” against Claimed Amount of an Employee. If submitting, Approval Status should be submitted to Approved or Rejected. If Approved, then Expense Claim gets submitted. If rejected, then Expen Comments can be added in the Comments section explaining why the claim was approved or rejected. -### Booking the Expense and Reimbursement +### Booking the Expense -The approved Expense Claim must then be converted into a Journal Entry and a -payment must be made. Note: This amount should not be clubbed with Salary -because the amount will then be taxable to the Employee. +On submission of Expense Claim, system books an expense against the expense account and the employee account +Expense Claim + +User can view unpaid expense claim using report "Unclaimed Expense Claims" +Expense Claim + +### Payment for Expense Claim + +To make payment against the expense claim, user has to click on Make > Bank Entry +#### Expense Claim +Expense Claim + +#### Payment Entry +Expense Claim + + +Note: This amount should not be clubbed with Salary because the amount will then be taxable to the Employee. ### Linking with Task & Project diff --git a/erpnext/hooks.py b/erpnext/hooks.py index 66acdb1b8ba..14ea74b70b5 100644 --- a/erpnext/hooks.py +++ b/erpnext/hooks.py @@ -147,13 +147,6 @@ doc_events = { "on_update": "erpnext.shopping_cart.doctype.shopping_cart_settings.shopping_cart_settings.validate_cart_settings" }, - # bubble transaction notification on master - ('Opportunity', 'Quotation', 'Sales Order', 'Delivery Note', 'Sales Invoice', - 'Supplier Quotation', 'Purchase Order', 'Purchase Receipt', - 'Purchase Invoice', 'Project', 'Issue'): { - 'on_change': 'erpnext.accounts.party_status.notify_status' - }, - "Website Settings": { "validate": "erpnext.portal.doctype.products_settings.products_settings.home_page_is_products" }, diff --git a/erpnext/hr/doctype/employee_loan/employee_loan.py b/erpnext/hr/doctype/employee_loan/employee_loan.py index 4d7a9f38dfb..568596ee255 100644 --- a/erpnext/hr/doctype/employee_loan/employee_loan.py +++ b/erpnext/hr/doctype/employee_loan/employee_loan.py @@ -111,12 +111,11 @@ def check_repayment_method(repayment_method, loan_amount, monthly_repayment_amou frappe.throw(_("Monthly Repayment Amount cannot be greater than Loan Amount")) def get_monthly_repayment_amount(repayment_method, loan_amount, rate_of_interest, repayment_periods): - if repayment_method == "Repay Over Number of Periods": - if rate_of_interest: - monthly_interest_rate = flt(rate_of_interest) / (12 *100) - monthly_repayment_amount = math.ceil((loan_amount * monthly_interest_rate * - (1 + monthly_interest_rate)**repayment_periods) \ - / ((1 + monthly_interest_rate)**repayment_periods - 1)) + if rate_of_interest: + monthly_interest_rate = flt(rate_of_interest) / (12 *100) + monthly_repayment_amount = math.ceil((loan_amount * monthly_interest_rate * + (1 + monthly_interest_rate)**repayment_periods) \ + / ((1 + monthly_interest_rate)**repayment_periods - 1)) else: monthly_repayment_amount = math.ceil(flt(loan_amount) / repayment_periods) return monthly_repayment_amount diff --git a/erpnext/hr/doctype/expense_claim/expense_claim.js b/erpnext/hr/doctype/expense_claim/expense_claim.js index 8b3c45140c6..7d19051b62a 100644 --- a/erpnext/hr/doctype/expense_claim/expense_claim.js +++ b/erpnext/hr/doctype/expense_claim/expense_claim.js @@ -158,6 +158,21 @@ erpnext.expense_claim = { } } +frappe.ui.form.on("Expense Claim", { + refresh: function(frm) { + if(frm.doc.docstatus == 1) { + frm.add_custom_button(__('Accounting Ledger'), function() { + frappe.route_options = { + voucher_no: frm.doc.name, + company: frm.doc.company, + group_by_voucher: false + }; + frappe.set_route("query-report", "General Ledger"); + }, __("View")); + } + } +}) + frappe.ui.form.on("Expense Claim Detail", { claim_amount: function(frm, cdt, cdn) { var child = locals[cdt][cdn]; @@ -176,6 +191,47 @@ frappe.ui.form.on("Expense Claim Detail", { } }) +frappe.ui.form.on("Expense Claim",{ + setup: function(frm) { + frm.trigger("set_query_for_cost_center") + frm.trigger("set_query_for_payable_account") + frm.add_fetch("company", "cost_center", "cost_center"); + frm.add_fetch("company", "default_payable_account", "payable_account"); + }, + + refresh: function(frm) { + frm.trigger("toggle_fields") + }, + + set_query_for_cost_center: function(frm) { + frm.fields_dict["cost_center"].get_query = function() { + return { + filters: { + "company": frm.doc.company + } + } + } + }, + + set_query_for_payable_account: function(frm) { + frm.fields_dict["payable_account"].get_query = function() { + return { + filters: { + "root_type": "Liability", + "account_type": "Payable" + } + } + } + }, + + is_paid: function(frm) { + frm.trigger("toggle_fields") + }, + + toggle_fields: function(frm) { + frm.toggle_reqd("mode_of_payment", frm.doc.is_paid) + } +}); frappe.ui.form.on("Expense Claim", "employee_name", function(frm) { erpnext.expense_claim.set_title(frm); diff --git a/erpnext/hr/doctype/expense_claim/expense_claim.json b/erpnext/hr/doctype/expense_claim/expense_claim.json index 67132bf6984..f517b91d78e 100644 --- a/erpnext/hr/doctype/expense_claim/expense_claim.json +++ b/erpnext/hr/doctype/expense_claim/expense_claim.json @@ -41,6 +41,34 @@ "set_only_once": 0, "unique": 0 }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "is_paid", + "fieldtype": "Check", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Is Paid", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, { "allow_on_submit": 0, "bold": 0, @@ -55,7 +83,7 @@ "ignore_xss_filter": 0, "in_filter": 1, "in_list_view": 0, - "in_standard_filter": 1, + "in_standard_filter": 0, "label": "Approval Status", "length": 0, "no_copy": 1, @@ -86,7 +114,7 @@ "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, - "in_standard_filter": 1, + "in_standard_filter": 0, "label": "Approver", "length": 0, "no_copy": 0, @@ -175,7 +203,7 @@ "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, - "in_list_view": 0, + "in_list_view": 1, "in_standard_filter": 0, "label": "Total Sanctioned Amount", "length": 0, @@ -322,7 +350,7 @@ "ignore_xss_filter": 0, "in_filter": 1, "in_list_view": 0, - "in_standard_filter": 1, + "in_standard_filter": 0, "label": "From Employee", "length": 0, "no_copy": 0, @@ -370,36 +398,6 @@ "unique": 0, "width": "150px" }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "company", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 1, - "in_list_view": 0, - "in_standard_filter": 1, - "label": "Company", - "length": 0, - "no_copy": 0, - "oldfieldname": "company", - "oldfieldtype": "Link", - "options": "Company", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 1, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, { "allow_on_submit": 0, "bold": 0, @@ -429,90 +427,6 @@ "set_only_once": 0, "unique": 0 }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "cb1", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 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, - "unique": 0 - }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "total_amount_reimbursed", - "fieldtype": "Currency", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Total Amount Reimbursed", - "length": 0, - "no_copy": 1, - "options": "Company:company:default_currency", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "remark", - "fieldtype": "Small Text", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Remark", - "length": 0, - "no_copy": 1, - "oldfieldname": "remark", - "oldfieldtype": "Small 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, - "unique": 0 - }, { "allow_on_submit": 0, "bold": 0, @@ -571,6 +485,90 @@ "set_only_once": 0, "unique": 0 }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "cb1", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 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, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "total_amount_reimbursed", + "fieldtype": "Currency", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Total Amount Reimbursed", + "length": 0, + "no_copy": 1, + "options": "Company:company:default_currency", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "remark", + "fieldtype": "Small Text", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Remark", + "length": 0, + "no_copy": 1, + "oldfieldname": "remark", + "oldfieldtype": "Small 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, + "unique": 0 + }, { "allow_on_submit": 1, "bold": 0, @@ -613,7 +611,7 @@ "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, - "label": "Employees Email Address", + "label": "Employees Email Id", "length": 0, "no_copy": 0, "oldfieldname": "email_id", @@ -629,6 +627,238 @@ "set_only_once": 0, "unique": 0 }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "accounting_details", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Accounting Details", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "company", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 1, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Company", + "length": 0, + "no_copy": 0, + "oldfieldname": "company", + "oldfieldtype": "Link", + "options": "Company", + "permlevel": 0, + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 1, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "is_paid", + "fieldname": "mode_of_payment", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Mode of Payment", + "length": 0, + "no_copy": 0, + "options": "Mode of Payment", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "column_break_24", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "", + "fieldname": "payable_account", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Payable Account", + "length": 0, + "no_copy": 0, + "options": "Account", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "cost_center", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Employees Email Address", + "length": 0, + "no_copy": 0, + "options": "Cost Center", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 1, + "columns": 0, + "fieldname": "more_details", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "More Details", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "default": "Draft", + "fieldname": "status", + "fieldtype": "Select", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 1, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Status", + "length": 0, + "no_copy": 1, + "options": "Draft\nPaid\nUnpaid\nSubmitted\nCancelled", + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, { "allow_on_submit": 0, "bold": 0, @@ -663,7 +893,7 @@ ], "hide_heading": 0, "hide_toolbar": 0, - "icon": "fa fa-money", + "icon": "icon-money", "idx": 1, "image_view": 0, "in_create": 0, @@ -673,10 +903,11 @@ "istable": 0, "max_attachments": 0, "menu_index": 0, - "modified": "2016-11-07 05:52:48.548201", + "modified": "2017-01-19 18:15:35.968292", "modified_by": "Administrator", "module": "HR", "name": "Expense Claim", + "name_case": "Title Case", "owner": "harshada@webnotestech.com", "permissions": [ { @@ -689,7 +920,6 @@ "export": 1, "if_owner": 0, "import": 0, - "is_custom": 0, "permlevel": 0, "print": 1, "read": 1, @@ -710,7 +940,6 @@ "export": 0, "if_owner": 0, "import": 0, - "is_custom": 0, "permlevel": 0, "print": 1, "read": 1, @@ -732,7 +961,6 @@ "export": 0, "if_owner": 0, "import": 0, - "is_custom": 0, "permlevel": 0, "print": 1, "read": 1, @@ -754,7 +982,6 @@ "export": 0, "if_owner": 0, "import": 0, - "is_custom": 0, "permlevel": 0, "print": 1, "read": 1, @@ -775,5 +1002,6 @@ "sort_order": "DESC", "timeline_field": "employee", "title_field": "title", + "track_changes": 0, "track_seen": 0 } \ No newline at end of file diff --git a/erpnext/hr/doctype/expense_claim/expense_claim.py b/erpnext/hr/doctype/expense_claim/expense_claim.py index efdee97906b..957753a46d4 100644 --- a/erpnext/hr/doctype/expense_claim/expense_claim.py +++ b/erpnext/hr/doctype/expense_claim/expense_claim.py @@ -4,13 +4,17 @@ from __future__ import unicode_literals import frappe from frappe import _ -from frappe.utils import get_fullname, flt +from frappe.utils import get_fullname, flt, cstr from frappe.model.document import Document from erpnext.hr.utils import set_employee_name +from erpnext.accounts.party import get_party_account +from erpnext.accounts.general_ledger import make_gl_entries +from erpnext.accounts.doctype.sales_invoice.sales_invoice import get_bank_cash_account +from erpnext.controllers.accounts_controller import AccountsController class InvalidExpenseApproverError(frappe.ValidationError): pass -class ExpenseClaim(Document): +class ExpenseClaim(AccountsController): def get_feed(self): return _("{0}: From {0} for {1}").format(self.approval_status, self.employee_name, self.total_claimed_amount) @@ -21,16 +25,53 @@ class ExpenseClaim(Document): self.calculate_total_amount() set_employee_name(self) self.set_expense_account() + self.set_payable_account() + self.set_cost_center() + self.set_status() if self.task and not self.project: self.project = frappe.db.get_value("Task", self.task, "project") + def set_status(self): + self.status = { + "0": "Draft", + "1": "Submitted", + "2": "Cancelled" + }[cstr(self.docstatus or 0)] + + if self.total_sanctioned_amount == self.total_amount_reimbursed and self.docstatus == 1: + self.status = "Paid" + elif self.docstatus == 1: + self.status = "Unpaid" + + def set_payable_account(self): + if not self.payable_account and not self.is_paid: + self.payable_account = frappe.db.get_value("Company", self.company, "default_payable_account") + + def set_cost_center(self): + if not self.cost_center: + self.cost_center = frappe.db.get_value('Company', self.company, 'cost_center') + def on_submit(self): if self.approval_status=="Draft": frappe.throw(_("""Approval Status must be 'Approved' or 'Rejected'""")) + self.update_task_and_project() + self.make_gl_entries() + + if self.is_paid: + update_reimbursed_amount(self) + + self.set_status() def on_cancel(self): self.update_task_and_project() + if self.payable_account: + self.make_gl_entries(cancel=True) + + if self.is_paid: + update_reimbursed_amount(self) + + self.set_status() def update_task_and_project(self): if self.task: @@ -38,6 +79,79 @@ class ExpenseClaim(Document): elif self.project: frappe.get_doc("Project", self.project).update_project() + def make_gl_entries(self, cancel = False): + if flt(self.total_sanctioned_amount) > 0: + gl_entries = self.get_gl_entries() + make_gl_entries(gl_entries, cancel) + + def get_gl_entries(self): + gl_entry = [] + self.validate_account_details() + + # payable entry + gl_entry.append( + self.get_gl_dict({ + "account": self.payable_account, + "credit": self.total_sanctioned_amount, + "credit_in_account_currency": self.total_sanctioned_amount, + "against": ",".join([d.default_account for d in self.expenses]), + "party_type": "Employee", + "party": self.employee, + "against_voucher_type": self.doctype, + "against_voucher": self.name + }) + ) + + # expense entries + for data in self.expenses: + gl_entry.append( + self.get_gl_dict({ + "account": data.default_account, + "debit": data.sanctioned_amount, + "debit_in_account_currency": data.sanctioned_amount, + "against": self.employee, + "cost_center": self.cost_center + }) + ) + + if self.is_paid: + # payment entry + payment_account = get_bank_cash_account(self.mode_of_payment, self.company).get("account") + gl_entry.append( + self.get_gl_dict({ + "account": payment_account, + "credit": self.total_sanctioned_amount, + "credit_in_account_currency": self.total_sanctioned_amount, + "against": self.employee + }) + ) + + gl_entry.append( + self.get_gl_dict({ + "account": self.payable_account, + "party_type": "Employee", + "party": self.employee, + "against": payment_account, + "debit": self.total_sanctioned_amount, + "debit_in_account_currency": self.total_sanctioned_amount, + "against_voucher": self.name, + "against_voucher_type": self.doctype, + }) + ) + + return gl_entry + + def validate_account_details(self): + if not self.cost_center: + frappe.throw(_("Cost center is required to book an expense claim")) + + if not self.payable_account: + frappe.throw(_("Please set default payable account in the employee {0}").format(self.employee)) + + if self.is_paid: + if not self.mode_of_payment: + frappe.throw(_("Mode of payment is required to make a payment").format(self.employee)) + def calculate_total_amount(self): self.total_claimed_amount = 0 self.total_sanctioned_amount = 0 @@ -64,7 +178,18 @@ class ExpenseClaim(Document): for expense in self.expenses: if not expense.default_account: expense.default_account = get_expense_claim_account(expense.expense_type, self.company)["account"] - + +def update_reimbursed_amount(doc): + amt = frappe.db.sql("""select ifnull(sum(debit_in_account_currency), 0) as amt + from `tabGL Entry` where against_voucher_type = 'Expense Claim' and against_voucher = %s + and party = %s """, (doc.name, doc.employee) ,as_dict=1)[0].amt + + doc.total_amount_reimbursed = amt + frappe.db.set_value("Expense Claim", doc.name , "total_amount_reimbursed", amt) + + doc.set_status() + frappe.db.set_value("Expense Claim", doc.name , "status", doc.status) + @frappe.whitelist() def get_expense_approver(doctype, txt, searchfield, start, page_len, filters): return frappe.db.sql(""" @@ -80,23 +205,26 @@ def make_bank_entry(docname): expense_claim = frappe.get_doc("Expense Claim", docname) default_bank_cash_account = get_default_bank_cash_account(expense_claim.company, "Bank") + if not default_bank_cash_account: + default_bank_cash_account = get_default_bank_cash_account(expense_claim.company, "Cash") je = frappe.new_doc("Journal Entry") je.voucher_type = 'Bank Entry' je.company = expense_claim.company je.remark = 'Payment against Expense Claim: ' + docname; - for expense in expense_claim.expenses: - je.append("accounts", { - "account": expense.default_account, - "debit_in_account_currency": expense.sanctioned_amount, - "reference_type": "Expense Claim", - "reference_name": expense_claim.name - }) + je.append("accounts", { + "account": expense_claim.payable_account, + "debit_in_account_currency": flt(expense_claim.total_sanctioned_amount - expense_claim.total_amount_reimbursed), + "reference_type": "Expense Claim", + "party_type": "Employee", + "party": expense_claim.employee, + "reference_name": expense_claim.name + }) je.append("accounts", { "account": default_bank_cash_account.account, - "credit_in_account_currency": expense_claim.total_sanctioned_amount, + "credit_in_account_currency": flt(expense_claim.total_sanctioned_amount - expense_claim.total_amount_reimbursed), "reference_type": "Expense Claim", "reference_name": expense_claim.name, "balance": default_bank_cash_account.balance, diff --git a/erpnext/hr/doctype/expense_claim/expense_claim_list.js b/erpnext/hr/doctype/expense_claim/expense_claim_list.js index 54073edef5e..7cff8e2f212 100644 --- a/erpnext/hr/doctype/expense_claim/expense_claim_list.js +++ b/erpnext/hr/doctype/expense_claim/expense_claim_list.js @@ -2,7 +2,10 @@ frappe.listview_settings['Expense Claim'] = { add_fields: ["approval_status", "total_claimed_amount", "docstatus"], filters:[["approval_status","!=", "Rejected"]], get_indicator: function(doc) { - return [__(doc.approval_status), frappe.utils.guess_colour(doc.approval_status), - "approval_status,=," + doc.approval_status]; + if(doc.status == "Paid") { + return [__("Paid"), "green", "status,=,'Paid'"]; + } else { + return [__("Unpaid"), "orange"]; + } } }; diff --git a/erpnext/hr/doctype/expense_claim/test_expense_claim.py b/erpnext/hr/doctype/expense_claim/test_expense_claim.py index 59d686ef036..20df7be0c4a 100644 --- a/erpnext/hr/doctype/expense_claim/test_expense_claim.py +++ b/erpnext/hr/doctype/expense_claim/test_expense_claim.py @@ -4,6 +4,8 @@ from __future__ import unicode_literals import frappe import unittest +from frappe.utils import random_string, nowdate +from erpnext.hr.doctype.expense_claim.expense_claim import make_bank_entry test_records = frappe.get_test_records('Expense Claim') @@ -11,8 +13,6 @@ class TestExpenseClaim(unittest.TestCase): def test_total_expense_claim_for_project(self): frappe.db.sql("""delete from `tabTask` where project = "_Test Project 1" """) frappe.db.sql("""delete from `tabProject` where name = "_Test Project 1" """) - frappe.db.sql("""delete from `tabExpense Claim`""") - frappe.db.sql("""delete from `tabExpense Claim Detail`""") frappe.get_doc({ "project_name": "_Test Project 1", @@ -22,15 +22,17 @@ class TestExpenseClaim(unittest.TestCase): }).save() task_name = frappe.db.get_value("Task", {"project": "_Test Project 1"}) + payable_account = get_payable_account("Wind Power LLC") expense_claim = frappe.get_doc({ "doctype": "Expense Claim", "employee": "_T-Employee-0001", + "payable_account": payable_account, "approval_status": "Approved", "project": "_Test Project 1", "task": task_name, "expenses": - [{ "expense_type": "Food", "default_account": "Entertainment Expenses - _TC", "claim_amount": 300, "sanctioned_amount": 200 }] + [{ "expense_type": "Travel", "default_account": "Travel Expenses - WP", "claim_amount": 300, "sanctioned_amount": 200 }] }) expense_claim.submit() @@ -44,7 +46,7 @@ class TestExpenseClaim(unittest.TestCase): "project": "_Test Project 1", "task": task_name, "expenses": - [{ "expense_type": "Food", "default_account": "Entertainment Expenses - _TC", "claim_amount": 600, "sanctioned_amount": 500 }] + [{ "expense_type": "Travel", "default_account": "Travel Expenses - WP", "claim_amount": 600, "sanctioned_amount": 500 }] }) expense_claim2.submit() @@ -52,6 +54,64 @@ class TestExpenseClaim(unittest.TestCase): self.assertEqual(frappe.db.get_value("Project", "_Test Project 1", "total_expense_claim"), 700) expense_claim2.cancel() + frappe.delete_doc("Expenses Claim", expense_claim2.name) self.assertEqual(frappe.db.get_value("Task", task_name, "total_expense_claim"), 200) self.assertEqual(frappe.db.get_value("Project", "_Test Project 1", "total_expense_claim"), 200) + + def test_expense_claim_status(self): + payable_account = get_payable_account("Wind Power LLC") + expense_claim = frappe.get_doc({ + "doctype": "Expense Claim", + "employee": "_T-Employee-0001", + "payable_account": payable_account, + "approval_status": "Approved", + "expenses": + [{ "expense_type": "Travel", "default_account": "Travel Expenses - WP", "claim_amount": 300, "sanctioned_amount": 200 }] + }) + expense_claim.submit() + + je_dict = make_bank_entry(expense_claim.name) + je = frappe.get_doc(je_dict) + je.posting_date = nowdate() + je.cheque_no = random_string(5) + je.cheque_date = nowdate() + je.submit() + + expense_claim = frappe.get_doc("Expense Claim", expense_claim.name) + self.assertEqual(expense_claim.status, "Paid") + + je.cancel() + expense_claim = frappe.get_doc("Expense Claim", expense_claim.name) + self.assertEqual(expense_claim.status, "Unpaid") + + def test_expense_claim_gl_entry(self): + payable_account = get_payable_account("Wind Power LLC") + expense_claim = frappe.get_doc({ + "doctype": "Expense Claim", + "employee": "_T-Employee-0001", + "payable_account": payable_account, + "approval_status": "Approved", + "expenses": + [{ "expense_type": "Travel", "default_account": "Travel Expenses - WP", "claim_amount": 300, "sanctioned_amount": 200 }] + }) + expense_claim.submit() + + gl_entries = frappe.db.sql("""select account, debit, credit + from `tabGL Entry` where voucher_type='Expense Claim' and voucher_no=%s + order by account asc""", expense_claim.name, as_dict=1) + + self.assertTrue(gl_entries) + + expected_values = dict((d[0], d) for d in [ + [payable_account, 0.0, 200.0], + ["Travel Expenses - WP", 200.0, 0.0] + ]) + + for gle in gl_entries: + self.assertEquals(expected_values[gle.account][0], gle.account) + self.assertEquals(expected_values[gle.account][1], gle.debit) + self.assertEquals(expected_values[gle.account][2], gle.credit) + +def get_payable_account(company): + return frappe.db.get_value('Company', company, 'default_payable_account') diff --git a/erpnext/hr/doctype/salary_slip/salary_slip.py b/erpnext/hr/doctype/salary_slip/salary_slip.py index de205e3bdd2..5ff1248717d 100644 --- a/erpnext/hr/doctype/salary_slip/salary_slip.py +++ b/erpnext/hr/doctype/salary_slip/salary_slip.py @@ -89,8 +89,8 @@ class SalarySlip(TransactionBase): frappe.throw(_("Name error: {0}".format(err))) except SyntaxError as err: frappe.throw(_("Syntax error in formula or condition: {0}".format(err))) - except: - frappe.throw(_("Error in formula or condition")) + except Exception, e: + frappe.throw(_("Error in formula or condition: {0}".format(e))) raise def get_data_for_eval(self): @@ -99,7 +99,7 @@ class SalarySlip(TransactionBase): for d in self._salary_structure_doc.employees: if d.employee == self.employee: - data.base, data.variable = d.base, d.variable + data.update(frappe.get_doc("Salary Structure Employee", {"employee": self.employee}).as_dict()) data.update(frappe.get_doc("Employee", self.employee).as_dict()) data.update(self.as_dict()) @@ -108,7 +108,6 @@ class SalarySlip(TransactionBase): salary_components = frappe.get_all("Salary Component", fields=["salary_component_abbr"]) for salary_component in salary_components: data[salary_component.salary_component_abbr] = 0 - return data diff --git a/erpnext/hr/doctype/salary_structure/salary_structure.json b/erpnext/hr/doctype/salary_structure/salary_structure.json index ca59ded9405..b34cff19a1d 100644 --- a/erpnext/hr/doctype/salary_structure/salary_structure.json +++ b/erpnext/hr/doctype/salary_structure/salary_structure.json @@ -21,7 +21,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "length": 0, @@ -48,7 +47,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 1, "in_list_view": 0, "in_standard_filter": 0, "label": "Company", @@ -76,7 +74,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Letter Head", @@ -107,7 +104,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Payroll Frequency", @@ -136,7 +132,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "length": 0, @@ -164,7 +159,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 1, "in_list_view": 1, "in_standard_filter": 1, "label": "Is Active", @@ -195,7 +189,6 @@ "hidden": 1, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Is Default", @@ -224,7 +217,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 1, "in_standard_filter": 0, "label": "From Date", @@ -253,7 +245,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 1, "in_standard_filter": 0, "label": "To Date", @@ -282,7 +273,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "length": 0, @@ -310,7 +300,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Employees", @@ -339,7 +328,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "", @@ -368,7 +356,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Salary Slip Based on Timesheet", @@ -396,7 +383,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "length": 0, @@ -425,7 +411,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Salary Component", @@ -455,7 +440,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Hour Rate", @@ -485,7 +469,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "", @@ -515,7 +498,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Earning", @@ -546,7 +528,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Earnings", @@ -576,7 +557,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Deduction", @@ -606,7 +586,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Deductions", @@ -637,7 +616,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "length": 0, @@ -664,7 +642,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "length": 0, @@ -691,7 +668,6 @@ "hidden": 1, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Total Earning", @@ -721,7 +697,6 @@ "hidden": 1, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Total Deduction", @@ -751,7 +726,6 @@ "hidden": 1, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Net Pay", @@ -779,7 +753,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Account", @@ -807,7 +780,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Mode of Payment", @@ -836,7 +808,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "length": 0, @@ -863,7 +834,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Payment Account", @@ -894,7 +864,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2017-01-11 02:02:10.848614", + "modified": "2017-02-02 01:23:49.179497", "modified_by": "Administrator", "module": "HR", "name": "Salary Structure", @@ -910,7 +880,6 @@ "export": 0, "if_owner": 0, "import": 0, - "is_custom": 0, "permlevel": 0, "print": 1, "read": 1, @@ -928,10 +897,9 @@ "create": 1, "delete": 1, "email": 1, - "export": 0, + "export": 1, "if_owner": 0, - "import": 0, - "is_custom": 0, + "import": 1, "permlevel": 0, "print": 1, "read": 1, @@ -950,5 +918,6 @@ "sort_order": "DESC", "timeline_field": "", "title_field": "", + "track_changes": 0, "track_seen": 0 -} +} \ No newline at end of file diff --git a/erpnext/hr/doctype/salary_structure/salary_structure.py b/erpnext/hr/doctype/salary_structure/salary_structure.py index 13622c35b3e..0e2dd1bb4ad 100644 --- a/erpnext/hr/doctype/salary_structure/salary_structure.py +++ b/erpnext/hr/doctype/salary_structure/salary_structure.py @@ -4,8 +4,7 @@ from __future__ import unicode_literals import frappe -from frappe.utils import cstr, flt, getdate, cint -from frappe.model.naming import make_autoname +from frappe.utils import flt, cint from frappe import _ from frappe.model.mapper import get_mapped_doc from frappe.model.document import Document @@ -15,7 +14,6 @@ class SalaryStructure(Document): def validate(self): self.validate_amount() - self.validate_joining_date() for e in self.get('employees'): set_employee_name(e) @@ -29,12 +27,6 @@ class SalaryStructure(Document): def validate_amount(self): if flt(self.net_pay) < 0 and self.salary_slip_based_on_timesheet: frappe.throw(_("Net pay cannot be negative")) - - def validate_joining_date(self): - for e in self.get('employees'): - joining_date = getdate(frappe.db.get_value("Employee", e.employee, "date_of_joining")) - if getdate(self.from_date) < joining_date: - frappe.throw(_("From Date in Salary Structure cannot be lesser than Employee Joining Date.")) @frappe.whitelist() @@ -42,6 +34,7 @@ def make_salary_slip(source_name, target_doc = None, employee = None, as_print = def postprocess(source, target): if employee: target.employee = employee + target.employee_name = frappe.get_value("Employee",employee, "employee_name") target.run_method('process_salary_structure') doc = get_mapped_doc("Salary Structure", source_name, { diff --git a/erpnext/hr/doctype/salary_structure_employee/salary_structure_employee.json b/erpnext/hr/doctype/salary_structure_employee/salary_structure_employee.json index aae33e3cac5..f5ac764171c 100644 --- a/erpnext/hr/doctype/salary_structure_employee/salary_structure_employee.json +++ b/erpnext/hr/doctype/salary_structure_employee/salary_structure_employee.json @@ -15,13 +15,14 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "employee", "fieldtype": "Link", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 1, + "in_standard_filter": 0, "label": "Employee", "length": 0, "no_copy": 0, @@ -31,6 +32,7 @@ "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, @@ -41,21 +43,24 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "employee_name", - "fieldtype": "Data", + "fieldtype": "Read Only", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, + "in_standard_filter": 0, "label": "Employee Name", "length": 0, "no_copy": 0, + "options": "employee.employee_name", "permlevel": 0, "precision": "", "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 1, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, "search_index": 0, @@ -66,13 +71,14 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "base", "fieldtype": "Currency", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 1, + "in_standard_filter": 0, "label": "Base", "length": 0, "no_copy": 0, @@ -81,6 +87,7 @@ "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, @@ -91,13 +98,14 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "variable", "fieldtype": "Currency", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 1, + "in_standard_filter": 0, "label": "Variable", "length": 0, "no_copy": 0, @@ -106,6 +114,7 @@ "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, "search_index": 0, @@ -123,7 +132,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2016-08-11 12:18:14.526977", + "modified": "2017-02-02 02:06:33.809285", "modified_by": "Administrator", "module": "HR", "name": "Salary Structure Employee", @@ -135,5 +144,6 @@ "read_only_onload": 0, "sort_field": "modified", "sort_order": "DESC", + "track_changes": 0, "track_seen": 0 } \ No newline at end of file diff --git a/erpnext/hr/page/team_updates/team_update_row.html b/erpnext/hr/page/team_updates/team_update_row.html index c81a4cb95f2..e3adcb88887 100644 --- a/erpnext/hr/page/team_updates/team_update_row.html +++ b/erpnext/hr/page/team_updates/team_update_row.html @@ -7,7 +7,7 @@
    {{ avatar }}
    -
    +
    {{ content }}
    diff --git a/erpnext/hr/page/team_updates/team_updates.css b/erpnext/hr/page/team_updates/team_updates.css index 7f6a40a05b4..d37e7826b19 100644 --- a/erpnext/hr/page/team_updates/team_updates.css +++ b/erpnext/hr/page/team_updates/team_updates.css @@ -23,9 +23,25 @@ background: #5e64ff; } +.activity-row { +} + .activity-message { border-left: 1px solid #d1d8dd; +} + +.activity-message .row { padding: 15px; + margin-right: 0px; + border-bottom: 1px solid #d1d8dd; +} + +.activity-row:last-child .activity-message .row { + border-bottom: none; +} + +.activity-row .content { + padding-left: 0px; padding-right: 30px; } diff --git a/erpnext/manufacturing/doctype/bom/bom.json b/erpnext/manufacturing/doctype/bom/bom.json index c2c9b642a53..51018d36068 100644 --- a/erpnext/manufacturing/doctype/bom/bom.json +++ b/erpnext/manufacturing/doctype/bom/bom.json @@ -21,7 +21,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 1, "in_list_view": 1, "in_standard_filter": 1, "label": "Item", @@ -51,7 +50,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Item Name", @@ -81,7 +79,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Quantity", @@ -110,7 +107,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "length": 0, @@ -137,7 +133,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 1, "in_standard_filter": 0, "label": "Is Active", @@ -167,7 +162,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 1, "in_standard_filter": 0, "label": "Is Default", @@ -197,7 +191,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "With Operations", @@ -224,7 +217,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Rate Of Materials Based On", @@ -253,7 +245,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Price List", @@ -281,7 +272,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "", @@ -309,7 +299,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Currency", @@ -338,7 +327,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "length": 0, @@ -365,7 +353,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Conversion Rate", @@ -395,7 +382,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Operations", @@ -423,7 +409,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Operations", @@ -453,7 +438,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Materials", @@ -481,7 +465,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Items", @@ -511,7 +494,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Scrap", @@ -539,7 +521,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Scrap Items", @@ -568,7 +549,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Costing", @@ -596,7 +576,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Operating Cost", @@ -624,7 +603,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Raw Material Cost", @@ -652,7 +630,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Scrap Material Cost", @@ -681,7 +658,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "length": 0, @@ -707,7 +683,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Operating Cost (Company Currency)", @@ -736,7 +711,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Raw Material Cost(Company Currency)", @@ -765,7 +739,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Scrap Material Cost(Company Currency)", @@ -794,7 +767,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "length": 0, @@ -821,7 +793,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 1, "in_standard_filter": 0, "label": "Total Cost", @@ -849,7 +820,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "length": 0, @@ -876,7 +846,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Total Cost(Company Currency)", @@ -905,7 +874,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "", @@ -932,7 +900,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 1, "in_list_view": 0, "in_standard_filter": 0, "label": "Project", @@ -962,7 +929,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Company", @@ -991,7 +957,6 @@ "hidden": 0, "ignore_user_permissions": 1, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Amended From", @@ -1019,7 +984,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "length": 0, @@ -1045,7 +1009,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Item UOM", @@ -1073,7 +1036,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "length": 0, @@ -1100,7 +1062,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Item Description", @@ -1127,7 +1088,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "length": 0, @@ -1154,7 +1114,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Image", @@ -1182,7 +1141,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Image View", @@ -1212,7 +1170,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Materials Required (Exploded)", @@ -1239,7 +1196,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Exploded_items", @@ -1271,8 +1227,8 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2016-11-21 17:06:49.349654", - "modified_by": "rohit@erpnext.com", + "modified": "2017-02-01 14:27:17.949390", + "modified_by": "Administrator", "module": "Manufacturing", "name": "BOM", "owner": "Administrator", @@ -1287,7 +1243,6 @@ "export": 1, "if_owner": 0, "import": 0, - "is_custom": 0, "permlevel": 0, "print": 1, "read": 1, @@ -1308,7 +1263,6 @@ "export": 0, "if_owner": 0, "import": 0, - "is_custom": 0, "permlevel": 0, "print": 1, "read": 1, @@ -1329,7 +1283,6 @@ "export": 0, "if_owner": 0, "import": 0, - "is_custom": 0, "permlevel": 0, "print": 1, "read": 1, @@ -1347,5 +1300,6 @@ "search_fields": "item", "sort_field": "modified", "sort_order": "DESC", + "track_changes": 0, "track_seen": 0 } \ No newline at end of file diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py index f4fed6e097f..8102057a663 100644 --- a/erpnext/manufacturing/doctype/bom/bom.py +++ b/erpnext/manufacturing/doctype/bom/bom.py @@ -500,10 +500,15 @@ def validate_bom_no(item, bom_no): @frappe.whitelist() def get_children(): if frappe.form_dict.parent: - return frappe.db.sql("""select item_code, - bom_no as value, qty, - if(ifnull(bom_no, "")!="", 1, 0) as expandable - from `tabBOM Item` - where parent=%s - order by idx + return frappe.db.sql("""select + bom_item.item_code, + bom_item.bom_no as value, + bom_item.qty, + if(ifnull(bom_item.bom_no, "")!="", 1, 0) as expandable, + item.image, + item.description + from `tabBOM Item` bom_item, tabItem item + where bom_item.parent=%s + and bom_item.item_code = item.name + order by bom_item.idx """, frappe.form_dict.parent, as_dict=True) \ No newline at end of file diff --git a/erpnext/manufacturing/doctype/bom/bom_item_preview.html b/erpnext/manufacturing/doctype/bom/bom_item_preview.html new file mode 100644 index 00000000000..9db19a03b00 --- /dev/null +++ b/erpnext/manufacturing/doctype/bom/bom_item_preview.html @@ -0,0 +1,21 @@ +
    + {% if data.image %} + +
    + {% endif %} +

    + {{ __("Description") }} +

    +
    + {{ data.description }} +
    +
    +

    + {% if data.value %} + + {{ __("Open BOM {0}", [data.value.bold()]) }} + {% endif %} + + {{ __("Open Item {0}", [data.item_code.bold()]) }} +

    +
    \ No newline at end of file diff --git a/erpnext/manufacturing/doctype/bom/bom_tree.js b/erpnext/manufacturing/doctype/bom/bom_tree.js index f6a205f4609..09fe0378313 100644 --- a/erpnext/manufacturing/doctype/bom/bom_tree.js +++ b/erpnext/manufacturing/doctype/bom/bom_tree.js @@ -20,14 +20,14 @@ frappe.treeview_settings["BOM"] = { } }, toolbar: [ - {toggle_btn: true}, + { toggle_btn: true }, { label:__("Edit"), condition: function(node) { return node.expandable; }, click: function(node) { - + frappe.set_route("Form", "BOM", node.data.value); } } @@ -40,5 +40,6 @@ frappe.treeview_settings["BOM"] = { }, condition: 'frappe.boot.user.can_create.indexOf("BOM") !== -1' } - ] + ], + view_template: 'bom_item_preview' } \ No newline at end of file diff --git a/erpnext/manufacturing/doctype/production_order/production_order_calendar.js b/erpnext/manufacturing/doctype/production_order/production_order_calendar.js index 2832494805a..47cac288f4d 100644 --- a/erpnext/manufacturing/doctype/production_order/production_order_calendar.js +++ b/erpnext/manufacturing/doctype/production_order/production_order_calendar.js @@ -7,7 +7,10 @@ frappe.views.calendar["Production Order"] = { "end": "planned_end_date", "id": "name", "title": "name", - "allDay": "allDay" + "allDay": "allDay", + "progress": function(data) { + return flt(data.produced_qty) / data.qty * 100; + } }, gantt: true, get_css_class: function(data) { diff --git a/erpnext/patches.txt b/erpnext/patches.txt index d6d30690b6c..e041a2b5178 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -370,3 +370,4 @@ erpnext.patches.v7_2.set_null_value_to_fields erpnext.patches.v7_2.update_guardian_name_in_student_master erpnext.patches.v7_2.update_abbr_in_salary_slips erpnext.patches.v7_2.rename_evaluation_criteria +erpnext.patches.v7_2.update_party_type \ No newline at end of file diff --git a/erpnext/patches/v7_0/update_party_status.py b/erpnext/patches/v7_0/update_party_status.py index 208b47639bf..f3733dbd843 100644 --- a/erpnext/patches/v7_0/update_party_status.py +++ b/erpnext/patches/v7_0/update_party_status.py @@ -1,8 +1,7 @@ import frappe -from erpnext.accounts.party_status import status_depends_on, default_status -from frappe.desk.notifications import get_filters_for def execute(): + return for party_type in ('Customer', 'Supplier'): frappe.reload_doctype(party_type) diff --git a/erpnext/patches/v7_2/__init__.py b/erpnext/patches/v7_2/__init__.py index e69de29bb2d..baffc488252 100644 --- a/erpnext/patches/v7_2/__init__.py +++ b/erpnext/patches/v7_2/__init__.py @@ -0,0 +1 @@ +from __future__ import unicode_literals diff --git a/erpnext/patches/v7_2/update_party_type.py b/erpnext/patches/v7_2/update_party_type.py new file mode 100644 index 00000000000..147f5a36435 --- /dev/null +++ b/erpnext/patches/v7_2/update_party_type.py @@ -0,0 +1,16 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe + +def execute(): + frappe.reload_doc('setup', 'doctype', 'party_type') + make_party_type() + +def make_party_type(): + for party_type in ["Customer", "Supplier", "Employee"]: + if not frappe.db.get_value("Party Type", party_type): + doc = frappe.new_doc("Party Type") + doc.party_type = party_type + doc.save(ignore_permissions=True) \ No newline at end of file diff --git a/erpnext/projects/doctype/task/task_calendar.js b/erpnext/projects/doctype/task/task_calendar.js index f8fc3d3465c..d7468a56f97 100644 --- a/erpnext/projects/doctype/task/task_calendar.js +++ b/erpnext/projects/doctype/task/task_calendar.js @@ -7,7 +7,8 @@ frappe.views.calendar["Task"] = { "end": "exp_end_date", "id": "name", "title": "subject", - "allDay": "allDay" + "allDay": "allDay", + "progress": "progress" }, gantt: true, filters: [ diff --git a/erpnext/public/css/erpnext.css b/erpnext/public/css/erpnext.css index 7f85de9315b..cfe9f63ac8d 100644 --- a/erpnext/public/css/erpnext.css +++ b/erpnext/public/css/erpnext.css @@ -67,7 +67,6 @@ .pos-toolbar, .pos-bill-toolbar { padding: 10px 0px; - border-bottom: 1px solid #d1d8dd; height: 51px; } .pos-item-toolbar .form-group { @@ -79,6 +78,7 @@ margin-right: -1px; } .pos-bill { + border-top: 1px solid #d1d8dd; margin-left: -15px; margin-right: -15px; } @@ -171,6 +171,9 @@ .payment-toolbar { padding-right: 30px; } +.list-row-head.pos-invoice-list { + border-top: 1px solid #d1d8dd; +} body[data-route="pos"] .modal-dialog { width: 750px; } diff --git a/erpnext/public/js/pos/pos.html b/erpnext/public/js/pos/pos.html index 9d0ab60fb03..44e42d79b11 100644 --- a/erpnext/public/js/pos/pos.html +++ b/erpnext/public/js/pos/pos.html @@ -1,14 +1,26 @@
    -
    -
    -
    +
    +
    +
    + + + {% if (allow_delete) { %} + + {% } %}
    -
    {%= __("Item") %}
    -
    {%= __("Quantity") %}
    +
    {%= __("Item") %}
    +
    {%= __("Quantity") %}
    +
    {%= __("Discount") %}
    {%= __("Rate") %}
    @@ -48,18 +60,27 @@
    +
    + +
    -
    +
    -
    +
    +
    -
    +
    +
    +
    + +
    +
    diff --git a/erpnext/public/js/pos/pos_bill_item.html b/erpnext/public/js/pos/pos_bill_item.html index f5d1a7652e8..1a1f1e2a5b2 100644 --- a/erpnext/public/js/pos/pos_bill_item.html +++ b/erpnext/public/js/pos/pos_bill_item.html @@ -1,25 +1,30 @@
    -
    {%= item_code || "" %}{%= item_name || "" %}
    -
    +
    {%= item_code || "" %}{%= __(item_name) || "" %}
    +
    - +
    {% if(actual_qty != null) { %}
    - {%= actual_qty || 0 %} + {%= __("In Stock: ") %} {%= actual_qty || 0.0 %}
    {% } %}
    +
    +
    + +
    +
    {% if(enabled) { %} - + {% } else { %}
    {%= format_currency(rate) %}
    {% } %} diff --git a/erpnext/public/less/erpnext.less b/erpnext/public/less/erpnext.less index 790a031736d..495e618f7e8 100644 --- a/erpnext/public/less/erpnext.less +++ b/erpnext/public/less/erpnext.less @@ -82,7 +82,7 @@ .pos-toolbar, .pos-bill-toolbar { padding: 10px 0px; - border-bottom: 1px solid #d1d8dd; + // border-bottom: 1px solid #d1d8dd; height: 51px; } @@ -97,6 +97,7 @@ } .pos-bill { + border-top: 1px solid @border-color; margin-left: -15px; margin-right: -15px; } @@ -213,6 +214,10 @@ padding-right: 30px; } +.list-row-head.pos-invoice-list { + border-top: 1px solid @border-color; +} + body[data-route="pos"] .modal-dialog { width: 750px; diff --git a/erpnext/schools/doctype/assessment_plan/assessment_plan.js b/erpnext/schools/doctype/assessment_plan/assessment_plan.js index 5973ac562e2..9685e0ef836 100644 --- a/erpnext/schools/doctype/assessment_plan/assessment_plan.js +++ b/erpnext/schools/doctype/assessment_plan/assessment_plan.js @@ -7,6 +7,17 @@ cur_frm.add_fetch("examiner", "instructor_name", "examiner_name"); cur_frm.add_fetch("supervisor", "instructor_name", "supervisor_name"); frappe.ui.form.on("Assessment Plan", { + refresh: function(frm) { + if (!frm.doc.__islocal) { + frm.add_custom_button(__("Assessment Result"), function() { + frappe.route_options = { + assessment_plan: frm.doc.name + } + frappe.set_route("Form", "Assessment Result Tool"); + }); + } + }, + course: function(frm) { if (frm.doc.course && frm.doc.maximum_assessment_score) { frappe.call({ diff --git a/erpnext/schools/doctype/guardian/guardian.json b/erpnext/schools/doctype/guardian/guardian.json index 8368f4a097d..6f5e25dd365 100644 --- a/erpnext/schools/doctype/guardian/guardian.json +++ b/erpnext/schools/doctype/guardian/guardian.json @@ -129,14 +129,15 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fieldname": "column_break_3", - "fieldtype": "Column Break", + "fieldname": "date_of_birth", + "fieldtype": "Date", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, + "label": "Date of Birth", "length": 0, "no_copy": 0, "permlevel": 0, @@ -156,15 +157,14 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fieldname": "date_of_birth", - "fieldtype": "Date", + "fieldname": "column_break_3", + "fieldtype": "Column Break", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, - "label": "Date of Birth", "length": 0, "no_copy": 0, "permlevel": 0, @@ -263,61 +263,6 @@ "set_only_once": 0, "unique": 0 }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "image", - "fieldtype": "Attach Image", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Image", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "section_break_9", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, { "allow_on_submit": 0, "bold": 0, @@ -346,6 +291,91 @@ "set_only_once": 0, "unique": 0 }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "image", + "fieldtype": "Attach Image", + "hidden": 1, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Image", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "section_break_13", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Guardian Of ", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "students", + "fieldtype": "Table", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Students", + "length": 0, + "no_copy": 0, + "options": "Guardian Student", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, { "allow_on_submit": 0, "bold": 0, @@ -359,6 +389,7 @@ "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, + "label": "Guardian Interests", "length": 0, "no_copy": 0, "permlevel": 0, @@ -414,7 +445,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2016-12-28 16:14:58.836437", + "modified": "2017-01-31 16:47:23.436075", "modified_by": "Administrator", "module": "Schools", "name": "Guardian", @@ -431,7 +462,6 @@ "export": 1, "if_owner": 0, "import": 0, - "is_custom": 0, "permlevel": 0, "print": 1, "read": 1, @@ -449,5 +479,6 @@ "sort_field": "modified", "sort_order": "DESC", "title_field": "guardian_name", + "track_changes": 0, "track_seen": 0 } \ No newline at end of file diff --git a/erpnext/schools/doctype/guardian/guardian.py b/erpnext/schools/doctype/guardian/guardian.py index 1388cfe5349..38597f0fed2 100644 --- a/erpnext/schools/doctype/guardian/guardian.py +++ b/erpnext/schools/doctype/guardian/guardian.py @@ -7,4 +7,22 @@ import frappe from frappe.model.document import Document class Guardian(Document): - pass + def __setup__(self): + self.onload() + + def onload(self): + """Load Students for quick view""" + self.load_students() + + def load_students(self): + """Load `students` from the database""" + self.students = [] + students = frappe.get_all("Student Guardian", filters={"guardian":self.name}, fields=["parent"]) + for student in students: + self.append("students", { + "student":student.parent, + "student_name": frappe.db.get_value("Student", student.parent, "title") + }) + + def validate(self): + self.students = [] \ No newline at end of file diff --git a/erpnext/schools/doctype/guardian_student/__init__.py b/erpnext/schools/doctype/guardian_student/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/schools/doctype/guardian_student/guardian_student.json b/erpnext/schools/doctype/guardian_student/guardian_student.json new file mode 100644 index 00000000000..948ed70faef --- /dev/null +++ b/erpnext/schools/doctype/guardian_student/guardian_student.json @@ -0,0 +1,123 @@ +{ + "allow_copy": 0, + "allow_import": 0, + "allow_rename": 0, + "beta": 0, + "creation": "2017-01-31 11:53:21.580099", + "custom": 0, + "docstatus": 0, + "doctype": "DocType", + "document_type": "", + "editable_grid": 1, + "engine": "InnoDB", + "fields": [ + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "student", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Student", + "length": 0, + "no_copy": 0, + "options": "Student", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_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_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "student_name", + "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Student Name", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + } + ], + "hide_heading": 0, + "hide_toolbar": 0, + "idx": 0, + "image_view": 0, + "in_create": 0, + "in_dialog": 0, + "is_submittable": 0, + "issingle": 0, + "istable": 1, + "max_attachments": 0, + "modified": "2017-01-31 16:40:26.551040", + "modified_by": "Administrator", + "module": "Schools", + "name": "Guardian Student", + "name_case": "", + "owner": "Administrator", + "permissions": [], + "quick_entry": 1, + "read_only": 0, + "read_only_onload": 0, + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1, + "track_seen": 0 +} \ No newline at end of file diff --git a/erpnext/schools/doctype/guardian_student/guardian_student.py b/erpnext/schools/doctype/guardian_student/guardian_student.py new file mode 100644 index 00000000000..bf6f5c13730 --- /dev/null +++ b/erpnext/schools/doctype/guardian_student/guardian_student.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +from __future__ import unicode_literals +import frappe +from frappe.model.document import Document + +class GuardianStudent(Document): + pass diff --git a/erpnext/selling/doctype/customer/customer.json b/erpnext/selling/doctype/customer/customer.json index 77cc62458ba..81e17a6fb92 100644 --- a/erpnext/selling/doctype/customer/customer.json +++ b/erpnext/selling/doctype/customer/customer.json @@ -23,7 +23,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Name and Type", @@ -52,7 +51,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Series", @@ -80,7 +78,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 1, "in_list_view": 0, "in_standard_filter": 0, "label": "Full Name", @@ -109,7 +106,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Type", @@ -139,7 +135,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 1, "in_list_view": 0, "in_standard_filter": 0, "label": "From Lead", @@ -169,7 +164,6 @@ "hidden": 1, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Image", @@ -187,36 +181,6 @@ "set_only_once": 0, "unique": 0 }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "Active", - "fieldname": "status", - "fieldtype": "Select", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Status", - "length": 0, - "no_copy": 0, - "options": "Active\nDormant\nOpen", - "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, - "unique": 0 - }, { "allow_on_submit": 0, "bold": 0, @@ -227,7 +191,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "length": 0, @@ -255,7 +218,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 1, "in_list_view": 1, "in_standard_filter": 1, "label": "Customer Group", @@ -286,7 +248,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 1, "in_standard_filter": 1, "label": "Territory", @@ -316,7 +277,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Tax ID", @@ -345,7 +305,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Disabled", @@ -373,7 +332,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Currency and Price List", @@ -401,7 +359,6 @@ "hidden": 0, "ignore_user_permissions": 1, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Billing Currency", @@ -429,7 +386,6 @@ "hidden": 0, "ignore_user_permissions": 1, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Default Price List", @@ -457,7 +413,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "length": 0, @@ -484,7 +439,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Print Language", @@ -514,7 +468,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Address and Contact", @@ -542,7 +495,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Address HTML", @@ -569,7 +521,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Website", @@ -596,7 +547,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "length": 0, @@ -623,7 +573,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Contact HTML", @@ -652,7 +601,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Accounting", @@ -681,7 +629,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Accounts", @@ -710,7 +657,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Credit Limit", @@ -738,7 +684,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Credit Days Based On", @@ -768,7 +713,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Credit Days", @@ -797,7 +741,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Credit Limit", @@ -828,7 +771,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "More Information", @@ -858,7 +800,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Customer Details", @@ -887,7 +828,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Is Frozen", @@ -916,7 +856,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Sales Partner and Commission", @@ -945,7 +884,6 @@ "hidden": 0, "ignore_user_permissions": 1, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Sales Partner", @@ -975,7 +913,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Commission Rate", @@ -1005,7 +942,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Sales Team", @@ -1033,7 +969,6 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Sales Team Details", @@ -1066,7 +1001,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2016-11-07 05:26:57.948263", + "modified": "2017-02-01 12:00:06.045170", "modified_by": "Administrator", "module": "Selling", "name": "Customer", @@ -1083,7 +1018,6 @@ "export": 0, "if_owner": 0, "import": 0, - "is_custom": 0, "permlevel": 0, "print": 1, "read": 1, @@ -1104,7 +1038,6 @@ "export": 0, "if_owner": 0, "import": 0, - "is_custom": 0, "permlevel": 1, "print": 0, "read": 1, @@ -1125,7 +1058,6 @@ "export": 0, "if_owner": 0, "import": 0, - "is_custom": 0, "permlevel": 0, "print": 1, "read": 1, @@ -1146,7 +1078,6 @@ "export": 0, "if_owner": 0, "import": 0, - "is_custom": 0, "permlevel": 0, "print": 1, "read": 1, @@ -1167,7 +1098,6 @@ "export": 0, "if_owner": 0, "import": 0, - "is_custom": 0, "permlevel": 1, "print": 0, "read": 1, @@ -1188,7 +1118,6 @@ "export": 0, "if_owner": 0, "import": 0, - "is_custom": 0, "permlevel": 0, "print": 1, "read": 1, @@ -1209,7 +1138,6 @@ "export": 0, "if_owner": 0, "import": 0, - "is_custom": 0, "permlevel": 0, "print": 1, "read": 1, @@ -1230,7 +1158,6 @@ "export": 0, "if_owner": 0, "import": 0, - "is_custom": 0, "permlevel": 0, "print": 1, "read": 1, @@ -1251,7 +1178,6 @@ "export": 0, "if_owner": 0, "import": 0, - "is_custom": 0, "permlevel": 0, "print": 1, "read": 1, @@ -1269,5 +1195,6 @@ "search_fields": "customer_name,customer_group,territory", "sort_order": "ASC", "title_field": "customer_name", + "track_changes": 1, "track_seen": 0 } \ No newline at end of file diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py index e14cde07dbe..e4101af4bfc 100644 --- a/erpnext/selling/doctype/customer/customer.py +++ b/erpnext/selling/doctype/customer/customer.py @@ -11,7 +11,6 @@ from frappe.desk.reportview import build_match_conditions from erpnext.utilities.transaction_base import TransactionBase from frappe.geo.address_and_contact import load_address_and_contact, delete_contact_and_address from erpnext.accounts.party import validate_party_accounts, get_timeline_data # keep this -from erpnext.accounts.party_status import get_party_status from erpnext import get_default_currency class Customer(TransactionBase): @@ -70,7 +69,6 @@ class Customer(TransactionBase): self.flags.is_new_doc = self.is_new() self.flags.old_lead = self.lead_name validate_party_accounts(self) - self.status = get_party_status(self) self.validate_credit_limit_on_change() def on_update(self): diff --git a/erpnext/selling/doctype/customer/customer_list.js b/erpnext/selling/doctype/customer/customer_list.js index 57cebd4b313..09c3e93c1ce 100644 --- a/erpnext/selling/doctype/customer/customer_list.js +++ b/erpnext/selling/doctype/customer/customer_list.js @@ -1,12 +1,3 @@ frappe.listview_settings['Customer'] = { - add_fields: ["customer_name", "territory", "customer_group", "customer_type", 'status'], - get_indicator: function(doc) { - color = { - 'Open': 'red', - 'Active': 'green', - 'Dormant': 'darkgrey' - } - return [__(doc.status), color[doc.status], "status,=," + doc.status]; - } - + add_fields: ["customer_name", "territory", "customer_group", "customer_type"], }; diff --git a/erpnext/selling/doctype/quotation/test_quotation.py b/erpnext/selling/doctype/quotation/test_quotation.py index 7a59dd72bf5..36cc472574c 100644 --- a/erpnext/selling/doctype/quotation/test_quotation.py +++ b/erpnext/selling/doctype/quotation/test_quotation.py @@ -68,47 +68,6 @@ class TestQuotation(unittest.TestCase): self.assertEquals(quotation.get("items")[0].rate, total_margin) si.save() - def test_party_status_open(self): - from erpnext.selling.doctype.customer.test_customer import get_customer_dict - - customer = frappe.get_doc(get_customer_dict('Party Status Test')).insert() - self.assertEquals(frappe.db.get_value('Customer', customer.name, 'status'), 'Active') - - quotation = frappe.get_doc(get_quotation_dict(customer=customer.name)).insert() - self.assertEquals(frappe.db.get_value('Customer', customer.name, 'status'), 'Open') - - quotation.submit() - self.assertEquals(frappe.db.get_value('Customer', customer.name, 'status'), 'Active') - - quotation.cancel() - quotation.delete() - customer.delete() - - def test_party_status_close(self): - from erpnext.selling.doctype.customer.test_customer import get_customer_dict - - customer = frappe.get_doc(get_customer_dict('Party Status Test')).insert() - self.assertEquals(frappe.db.get_value('Customer', customer.name, 'status'), 'Active') - - # open quotation - quotation = frappe.get_doc(get_quotation_dict(customer=customer.name)).insert() - self.assertEquals(frappe.db.get_value('Customer', customer.name, 'status'), 'Open') - - # close quotation (submit) - quotation.submit() - - quotation1 = frappe.get_doc(get_quotation_dict(customer=customer.name)).insert() - - # still open - self.assertEquals(frappe.db.get_value('Customer', customer.name, 'status'), 'Open') - - quotation.cancel() - quotation.delete() - - quotation1.delete() - - customer.delete() - test_records = frappe.get_test_records('Quotation') def get_quotation_dict(customer=None, item_code=None): diff --git a/erpnext/setup/doctype/company/company.js b/erpnext/setup/doctype/company/company.js index f22e63ee96a..5dd8ceb7bd6 100644 --- a/erpnext/setup/doctype/company/company.js +++ b/erpnext/setup/doctype/company/company.js @@ -4,6 +4,17 @@ frappe.provide("erpnext.company"); frappe.ui.form.on("Company", { + setup: function(frm) { + frm.fields_dict['default_payable_account'].get_query = function() { + return{ + filters: { + "root_type": "Liability", + "account_type": "Payable" + } + } + } + }, + onload: function(frm) { erpnext.company.setup_queries(frm); }, diff --git a/erpnext/setup/doctype/company/company.py b/erpnext/setup/doctype/company/company.py index 32ad8ebe1b6..93f02f8e3fe 100644 --- a/erpnext/setup/doctype/company/company.py +++ b/erpnext/setup/doctype/company/company.py @@ -153,6 +153,8 @@ class Company(Document): self.db_set("default_income_account", frappe.db.get_value("Account", {"account_name": _("Sales"), "company": self.name})) + if not self.default_payable_account: + self.db_set("default_payable_account", self.default_payable_account) def _set_default_account(self, fieldname, account_type): if self.get(fieldname): diff --git a/erpnext/setup/doctype/party_type/__init__.py b/erpnext/setup/doctype/party_type/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/setup/doctype/party_type/party_type.js b/erpnext/setup/doctype/party_type/party_type.js new file mode 100644 index 00000000000..7a96dc55ee9 --- /dev/null +++ b/erpnext/setup/doctype/party_type/party_type.js @@ -0,0 +1,15 @@ +// Copyright (c) 2016, Frappe Technologies and contributors +// For license information, please see license.txt + +frappe.ui.form.on('Party Type', { + setup: function(frm) { + frm.fields_dict["party_type"].get_query = function(frm) { + return { + filters: { + "istable": 0, + "is_submittable": 0 + } + } + } + } +}); diff --git a/erpnext/setup/doctype/party_type/party_type.json b/erpnext/setup/doctype/party_type/party_type.json new file mode 100644 index 00000000000..f49e7b3e3de --- /dev/null +++ b/erpnext/setup/doctype/party_type/party_type.json @@ -0,0 +1,130 @@ +{ + "allow_copy": 0, + "allow_import": 0, + "allow_rename": 0, + "autoname": "field:party_type", + "beta": 0, + "creation": "2016-12-26 11:26:51.508286", + "custom": 0, + "docstatus": 0, + "doctype": "DocType", + "document_type": "", + "editable_grid": 1, + "engine": "InnoDB", + "fields": [ + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "party_type", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Party Type", + "length": 0, + "no_copy": 0, + "options": "DocType", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + } + ], + "hide_heading": 0, + "hide_toolbar": 0, + "idx": 0, + "image_view": 0, + "in_create": 0, + "in_dialog": 0, + "is_submittable": 0, + "issingle": 0, + "istable": 0, + "max_attachments": 0, + "modified": "2017-01-19 17:55:33.428335", + "modified_by": "Administrator", + "module": "Setup", + "name": "Party Type", + "name_case": "", + "owner": "Administrator", + "permissions": [ + { + "amend": 0, + "apply_user_permissions": 0, + "cancel": 0, + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "if_owner": 0, + "import": 0, + "permlevel": 0, + "print": 1, + "read": 1, + "report": 1, + "role": "System Manager", + "set_user_permissions": 0, + "share": 1, + "submit": 0, + "write": 1 + }, + { + "amend": 0, + "apply_user_permissions": 0, + "cancel": 0, + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "if_owner": 0, + "import": 0, + "permlevel": 0, + "print": 1, + "read": 1, + "report": 1, + "role": "Accounts User", + "set_user_permissions": 0, + "share": 1, + "submit": 0, + "write": 1 + }, + { + "amend": 0, + "apply_user_permissions": 0, + "cancel": 0, + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "if_owner": 0, + "import": 0, + "permlevel": 0, + "print": 1, + "read": 1, + "report": 1, + "role": "Accounts Manager", + "set_user_permissions": 0, + "share": 1, + "submit": 0, + "write": 1 + } + ], + "quick_entry": 1, + "read_only": 0, + "read_only_onload": 0, + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1, + "track_seen": 0 +} \ No newline at end of file diff --git a/erpnext/setup/doctype/party_type/party_type.py b/erpnext/setup/doctype/party_type/party_type.py new file mode 100644 index 00000000000..74db0376bba --- /dev/null +++ b/erpnext/setup/doctype/party_type/party_type.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2015, Frappe Technologies and contributors +# For license information, please see license.txt + +from __future__ import unicode_literals +import frappe +from frappe.model.document import Document + +class PartyType(Document): + pass + +@frappe.whitelist() +def get_party_type(doctype, txt, searchfield, start, page_len, filters): + return frappe.db.sql("""select name from `tabParty Type` + where `{key}` LIKE %(txt)s + order by name limit %(start)s, %(page_len)s""" + .format(key=searchfield), { + 'txt': "%%%s%%" % frappe.db.escape(txt), + 'start': start, 'page_len': page_len + }) diff --git a/erpnext/setup/doctype/party_type/test_party_type.py b/erpnext/setup/doctype/party_type/test_party_type.py new file mode 100644 index 00000000000..079fe2fe3b7 --- /dev/null +++ b/erpnext/setup/doctype/party_type/test_party_type.py @@ -0,0 +1,12 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors +# See license.txt +from __future__ import unicode_literals + +import frappe +import unittest + +# test_records = frappe.get_test_records('Party Type') + +class TestPartyType(unittest.TestCase): + pass diff --git a/erpnext/setup/setup_wizard/install_fixtures.py b/erpnext/setup/setup_wizard/install_fixtures.py index 1589b3b8f0f..5e08203c5af 100644 --- a/erpnext/setup/setup_wizard/install_fixtures.py +++ b/erpnext/setup/setup_wizard/install_fixtures.py @@ -171,6 +171,10 @@ def install(country=None): {'doctype': "Email Account", "email_id": "support@example.com", "append_to": "Issue"}, {'doctype': "Email Account", "email_id": "jobs@example.com", "append_to": "Job Applicant"}, + {'doctype': "Party Type", "party_type": "Customer"}, + {'doctype': "Party Type", "party_type": "Supplier"}, + {'doctype': "Party Type", "party_type": "Employee"}, + {"doctype": "Offer Term", "offer_term": _("Date of Joining")}, {"doctype": "Offer Term", "offer_term": _("Annual Salary")}, {"doctype": "Offer Term", "offer_term": _("Probationary Period")}, diff --git a/erpnext/startup/notifications.py b/erpnext/startup/notifications.py index a1b90f96a24..554243f147b 100644 --- a/erpnext/startup/notifications.py +++ b/erpnext/startup/notifications.py @@ -11,8 +11,6 @@ def get_notification_config(): "Task": {"status": "Overdue"}, "Project": {"status": "Open"}, "Item": {"total_projected_qty": ("<", 0)}, - "Customer": {"status": "Open"}, - "Supplier": {"status": "Open"}, "Lead": {"status": "Open"}, "Contact": {"status": "Open"}, "Opportunity": {"status": "Open"}, @@ -23,11 +21,11 @@ def get_notification_config(): }, "Journal Entry": {"docstatus": 0}, "Sales Invoice": { - "outstanding_amount": (">", 0), - "docstatus": ("<", 2) + "outstanding_amount": (">", 0), + "docstatus": ("<", 2) }, "Purchase Invoice": { - "outstanding_amount": (">", 0), + "outstanding_amount": (">", 0), "docstatus": ("<", 2) }, "Payment Entry": {"docstatus": 0}, diff --git a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py index ba303bb72fc..a7480e8bf6d 100644 --- a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py +++ b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py @@ -117,6 +117,10 @@ class StockReconciliation(StockController): if buying_rate: row.valuation_rate = buying_rate + else: + # get valuation rate from Item + row.valuation_rate = frappe.get_value('Item', row.item_code, 'valuation_rate') + # throw all validation messages if self.validation_messages: for msg in self.validation_messages: