diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.js b/erpnext/accounts/doctype/journal_entry/journal_entry.js index c98e77fdd2..fc261a5c9d 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 a17668033e..a13cc7dde2 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 d3dbd314cc..6528c8fd51 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 c56a83dcaf..82040fa336 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.json +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.json @@ -104,7 +104,7 @@ "columns": 0, "depends_on": "eval:in_list([\"Receive\", \"Pay\"], doc.payment_type)", "fieldname": "party_type", - "fieldtype": "Select", + "fieldtype": "Link", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, @@ -114,7 +114,7 @@ "label": "Party Type", "length": 0, "no_copy": 0, - "options": "Customer\nSupplier", + "options": "DocType", "permlevel": 0, "precision": "", "print_hide": 1, @@ -1561,7 +1561,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2016-11-07 05:33:40.371480", + "modified": "2016-12-26 14:32:36.900576", "modified_by": "Administrator", "module": "Accounts", "name": "Payment Entry", diff --git a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js index 6a951a0aff..272e47448e 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/party.py b/erpnext/accounts/party.py index 05a3c11d91..a8d166eef1 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/report/general_ledger/general_ledger.js b/erpnext/accounts/report/general_ledger/general_ledger.js index ab7ad499c9..a422871b05 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 0000000000..e69de29bb2 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 0000000000..811414aaf0 --- /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 0000000000..a1087c0a6b --- /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 0000000000..eee620b7cc --- /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/demo/user/hr.py b/erpnext/demo/user/hr.py index e18a123ec4..25366024c1 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/human-resources/employee_account.png b/erpnext/docs/assets/img/human-resources/employee_account.png new file mode 100644 index 0000000000..a9a60664ef 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 ddca1005e1..9647d3d7f0 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 0000000000..4b816040d4 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 0000000000..f6b6e5d8a0 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 0000000000..a499ccfb71 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 0000000000..1581bb77a4 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 da3b2eedff..1d4996dabc 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/hr/doctype/expense_claim/expense_claim.js b/erpnext/hr/doctype/expense_claim/expense_claim.js index 8b3c45140c..7d19051b62 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 67132bf698..f517b91d78 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 efdee97906..957753a46d 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 54073edef5..7cff8e2f21 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 59d686ef03..20df7be0c4 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/patches.txt b/erpnext/patches.txt index 87c070e069..9494fbd0cb 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -369,3 +369,4 @@ erpnext.patches.v7_2.mark_students_active 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.update_party_type diff --git a/erpnext/patches/v7_2/__init__.py b/erpnext/patches/v7_2/__init__.py index e69de29bb2..baffc48825 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 0000000000..147f5a3643 --- /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/setup/doctype/company/company.js b/erpnext/setup/doctype/company/company.js index f22e63ee96..5dd8ceb7bd 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 32ad8ebe1b..93f02f8e3f 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 0000000000..e69de29bb2 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 0000000000..7a96dc55ee --- /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 0000000000..f49e7b3e3d --- /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 0000000000..74db0376bb --- /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 0000000000..079fe2fe3b --- /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 1589b3b8f0..5e08203c5a 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")},