This reverts commit cdd6ded790cb31a44acb70c219cde0d30da09bde.
This commit is contained in:
parent
4ebac3380d
commit
3b61552836
@ -8,7 +8,7 @@ from frappe import msgprint, _, scrub
|
||||
from erpnext.controllers.accounts_controller import AccountsController
|
||||
from erpnext.accounts.utils import get_balance_on, get_account_currency
|
||||
from erpnext.accounts.party import get_party_account
|
||||
from erpnext.hr.doctype.expense_claim.expense_claim import update_paid_amount
|
||||
from erpnext.hr.doctype.expense_claim.expense_claim import update_reimbursed_amount
|
||||
from erpnext.hr.doctype.employee_loan.employee_loan import update_disbursement_status
|
||||
|
||||
class JournalEntry(AccountsController):
|
||||
@ -215,8 +215,8 @@ class JournalEntry(AccountsController):
|
||||
if d.reference_type in ("Sales Invoice", "Purchase Invoice"):
|
||||
if (against_voucher[0] != d.party or against_voucher[1] != d.account):
|
||||
frappe.throw(_("Row {0}: Party / Account does not match with {1} / {2} in {3} {4}")
|
||||
.format(d.idx, field_dict.get(d.reference_type)[0],
|
||||
field_dict.get(d.reference_type)[1], d.reference_type, d.reference_name))
|
||||
.format(d.idx, field_dict.get(d.reference_type)[0], field_dict.get(d.reference_type)[1],
|
||||
d.reference_type, d.reference_name))
|
||||
|
||||
# check if party matches for Sales / Purchase Order
|
||||
if d.reference_type in ("Sales Order", "Purchase Order"):
|
||||
@ -225,17 +225,6 @@ class JournalEntry(AccountsController):
|
||||
frappe.throw(_("Row {0}: {1} {2} does not match with {3}") \
|
||||
.format(d.idx, d.party_type, d.party, d.reference_type))
|
||||
|
||||
if d.reference_type == "Expense Claim":
|
||||
ref_doc = frappe.get_doc("Expense Claim", d.reference_name)
|
||||
if ref_doc.employee != d.party:
|
||||
frappe.throw(_("Row {0}# Party must be {1}, same as Expense Claim {2}")
|
||||
.format(d.idx, ref_doc.employee, d.reference_name))
|
||||
|
||||
account_field = "advance_account" if ref_doc.docstatus==0 else "payable_account"
|
||||
if ref_doc.get(account_field) != d.account:
|
||||
frappe.throw(_("Row {0}# Account must be {1}, same as Expense Claim {2}")
|
||||
.format(d.idx, ref_doc.get(account_field), d.reference_name))
|
||||
|
||||
self.validate_orders()
|
||||
self.validate_invoices()
|
||||
|
||||
@ -527,7 +516,7 @@ class JournalEntry(AccountsController):
|
||||
for d in self.accounts:
|
||||
if d.reference_type=="Expense Claim" and d.reference_name:
|
||||
doc = frappe.get_doc("Expense Claim", d.reference_name)
|
||||
update_paid_amount(doc, d.account)
|
||||
update_reimbursed_amount(doc)
|
||||
|
||||
def update_employee_loan(self):
|
||||
for d in self.accounts:
|
||||
|
@ -12,7 +12,7 @@ from erpnext.accounts.doctype.journal_entry.journal_entry \
|
||||
import get_average_exchange_rate, get_default_bank_cash_account
|
||||
from erpnext.setup.utils import get_exchange_rate
|
||||
from erpnext.accounts.general_ledger import make_gl_entries
|
||||
from erpnext.hr.doctype.expense_claim.expense_claim import update_paid_amount
|
||||
from erpnext.hr.doctype.expense_claim.expense_claim import update_reimbursed_amount
|
||||
from erpnext.controllers.accounts_controller import AccountsController
|
||||
|
||||
class InvalidPaymentEntry(ValidationError): pass
|
||||
@ -219,20 +219,15 @@ class PaymentEntry(AccountsController):
|
||||
elif self.party_type=="Supplier":
|
||||
ref_party_account = ref_doc.credit_to
|
||||
elif self.party_type=="Employee":
|
||||
ref_party_account = ref_doc.payable_account \
|
||||
if ref_doc.docstatus==1 else ref_doc.advance_account
|
||||
ref_party_account = ref_doc.payable_account
|
||||
|
||||
if ref_party_account != self.party_account:
|
||||
frappe.throw(_("{0} {1} is associated with {2}, but Party Account is {3}")
|
||||
.format(d.reference_doctype, d.reference_name, ref_party_account, self.party_account))
|
||||
|
||||
if ref_doc.docstatus != 1:
|
||||
if d.reference_doctype!="Expense Claim":
|
||||
frappe.throw(_("{0} {1} must be submitted")
|
||||
.format(d.reference_doctype, d.reference_name))
|
||||
elif not ref_doc.advance_required:
|
||||
frappe.throw(_("Advance Payment Required should be checked in Expense Claim {0}")
|
||||
.format(d.reference_name))
|
||||
frappe.throw(_("{0} {1} must be submitted")
|
||||
.format(d.reference_doctype, d.reference_name))
|
||||
|
||||
def validate_journal_entry(self):
|
||||
for d in self.get("references"):
|
||||
@ -486,11 +481,11 @@ class PaymentEntry(AccountsController):
|
||||
frappe.get_doc(d.reference_doctype, d.reference_name).set_total_advance_paid()
|
||||
|
||||
def update_expense_claim(self):
|
||||
if self.payment_type =="Pay" and self.party:
|
||||
if self.payment_type in ("Pay") and self.party:
|
||||
for d in self.get("references"):
|
||||
if d.reference_doctype=="Expense Claim" and d.reference_name:
|
||||
doc = frappe.get_doc("Expense Claim", d.reference_name)
|
||||
update_paid_amount(doc, self.paid_to)
|
||||
update_reimbursed_amount(doc)
|
||||
|
||||
def on_recurring(self, reference_doc, subscription_doc):
|
||||
self.reference_no = reference_doc.name
|
||||
@ -702,8 +697,6 @@ def get_payment_entry(dt, dn, party_amount=None, bank_account=None, bank_amount=
|
||||
party_account = doc.debit_to
|
||||
elif dt == "Purchase Invoice":
|
||||
party_account = doc.credit_to
|
||||
elif dt == "Expense Claim":
|
||||
party_account = doc.payable_account if doc.docstatus==1 else doc.advance_account
|
||||
elif dt == "Fees":
|
||||
party_account = doc.receivable_account
|
||||
else:
|
||||
@ -723,13 +716,11 @@ def get_payment_entry(dt, dn, party_amount=None, bank_account=None, bank_amount=
|
||||
if party_amount:
|
||||
grand_total = outstanding_amount = party_amount
|
||||
elif dt in ("Sales Invoice", "Purchase Invoice"):
|
||||
grand_total = doc.base_grand_total \
|
||||
if party_account_currency == doc.company_currency else doc.grand_total
|
||||
grand_total = doc.base_grand_total if party_account_currency == doc.company_currency else doc.grand_total
|
||||
outstanding_amount = doc.outstanding_amount
|
||||
elif dt in ("Expense Claim"):
|
||||
grand_total = doc.total_sanctioned_amount
|
||||
outstanding_amount = flt(doc.total_sanctioned_amount) - flt(doc.total_amount_reimbursed) \
|
||||
- flt(doc.total_advance_paid)
|
||||
outstanding_amount = doc.total_sanctioned_amount - doc.total_amount_reimbursed
|
||||
elif dt == "Fees":
|
||||
grand_total = doc.grand_total
|
||||
outstanding_amount = doc.outstanding_amount
|
||||
|
@ -86,8 +86,9 @@ class TestPaymentEntry(unittest.TestCase):
|
||||
self.assertEqual(outstanding_amount, 0)
|
||||
|
||||
def test_payment_entry_against_ec(self):
|
||||
|
||||
payable = frappe.db.get_value('Company', "_Test Company", 'default_payable_account')
|
||||
ec = make_expense_claim(300, 300, "Travel Expenses - _TC", "_Test Company", payable)
|
||||
ec = make_expense_claim(payable, 300, 300, "_Test Company","Travel Expenses - _TC")
|
||||
pe = get_payment_entry("Expense Claim", ec.name, bank_account="_Test Bank USD - _TC", bank_amount=300)
|
||||
pe.reference_no = "1"
|
||||
pe.reference_date = "2016-01-01"
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 27 KiB |
Binary file not shown.
Before Width: | Height: | Size: 21 KiB |
Binary file not shown.
Before Width: | Height: | Size: 29 KiB |
@ -51,30 +51,6 @@ Set the Payment Type to "Pay", the Party Type to Employee, the Party to the empl
|
||||
from. All outstanding expense claims will be pulled in and payments amounts can be allocated to each expense.
|
||||
<img class="screenshot" alt="Expense Claim" src="{{docs_base_url}}/assets/img/human-resources/expense_claim_payment_entry.png">
|
||||
|
||||
### Managing Advance Payments
|
||||
|
||||
Sometimes an employee requires some advance payment before making expenses on behalf of the organisation. This can be managed from the Expense Claim
|
||||
|
||||
First make sure that the Default Advance Account has been set in the Company Master:
|
||||
|
||||
> Erpnext > Setup > Company
|
||||
|
||||
<img class="screenshot" alt="Expense Claim" src="{{docs_base_url}}/assets/img/human-resources/company_advance_account.png">
|
||||
|
||||
When creating the Expense Claim, check the 'Advance Payment Required' option
|
||||
|
||||
<img class="screenshot" alt="Expense Claim" src="{{docs_base_url}}/assets/img/human-resources/advance_payment_required.png">
|
||||
|
||||
After the Expense Claim is Saved and Approved by the Expense Approver, Journal Entry for Advance Payment can be raised by the accountant or user with appropriate permissions. To do that, just click on:
|
||||
|
||||
> Make > Advance Payment
|
||||
|
||||
<img class="screenshot" alt="Expense Claim" src="{{docs_base_url}}/assets/img/human-resources/make_advance_payment.png">
|
||||
|
||||
Note: Once the Expense Claim is Submitted, the button for making Advance Payment is no longer available. This is because expenses get booked on Submission of the Expense Claim and as such, the next logical step is settlement/reimbursement
|
||||
|
||||
Advance Payments are expected to be made 'before' the actual expenditure gets booked and settlement/reimbursement should be done against the Employee's Advance Account after submission of the Expense Claim
|
||||
|
||||
### Linking with Task & Project
|
||||
|
||||
* To Link Expense Claim with Task or Project specify the Task or the Project while making an Expense Claim
|
||||
|
@ -2432,7 +2432,7 @@
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2017-07-11 14:30:13.694009",
|
||||
"modified": "2017-06-13 14:29:13.694009",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Employee",
|
||||
|
@ -34,6 +34,9 @@ erpnext.hr.ExpenseClaimController = frappe.ui.form.Controller.extend({
|
||||
|
||||
$.extend(cur_frm.cscript, new erpnext.hr.ExpenseClaimController({frm: cur_frm}));
|
||||
|
||||
cur_frm.add_fetch('employee', 'company', 'company');
|
||||
cur_frm.add_fetch('employee','employee_name','employee_name');
|
||||
|
||||
cur_frm.cscript.onload = function(doc) {
|
||||
if(!doc.approval_status)
|
||||
cur_frm.set_value("approval_status", "Draft");
|
||||
@ -68,6 +71,34 @@ cur_frm.cscript.clear_sanctioned = function(doc) {
|
||||
refresh_many(['sanctioned_amount', 'total_sanctioned_amount']);
|
||||
};
|
||||
|
||||
cur_frm.cscript.refresh = function(doc) {
|
||||
cur_frm.cscript.set_help(doc);
|
||||
|
||||
if(!doc.__islocal) {
|
||||
cur_frm.toggle_enable("exp_approver", doc.approval_status=="Draft");
|
||||
cur_frm.toggle_enable("approval_status", (doc.exp_approver==frappe.session.user && doc.docstatus==0));
|
||||
|
||||
if (doc.docstatus==0 && doc.exp_approver==frappe.session.user && doc.approval_status=="Approved")
|
||||
cur_frm.savesubmit();
|
||||
|
||||
if (doc.docstatus===1 && doc.approval_status=="Approved") {
|
||||
/* eslint-disable */
|
||||
// no idea how `me` works here
|
||||
if (cint(doc.total_amount_reimbursed) > 0 && frappe.model.can_read("Journal Entry")) {
|
||||
cur_frm.add_custom_button(__('Bank Entries'), function() {
|
||||
frappe.route_options = {
|
||||
"Journal Entry Account.reference_type": me.frm.doc.doctype,
|
||||
"Journal Entry Account.reference_name": me.frm.doc.name,
|
||||
company: me.frm.doc.company
|
||||
};
|
||||
frappe.set_route("List", "Journal Entry");
|
||||
}, __("View"));
|
||||
}
|
||||
/* eslint-enable */
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
cur_frm.cscript.set_help = function(doc) {
|
||||
cur_frm.set_intro("");
|
||||
if(doc.__islocal && !in_list(frappe.user_roles, "HR User")) {
|
||||
@ -123,75 +154,30 @@ erpnext.expense_claim = {
|
||||
frappe.ui.form.on("Expense Claim", {
|
||||
setup: function(frm) {
|
||||
frm.trigger("set_query_for_cost_center");
|
||||
frm.trigger("set_query_for_advance_account");
|
||||
frm.trigger("set_query_for_payable_account");
|
||||
frm.add_fetch("company", "cost_center", "cost_center");
|
||||
frm.add_fetch("company", "default_advance_account", "advance_account");
|
||||
frm.add_fetch("company", "default_payable_account", "payable_account");
|
||||
frm.add_fetch('employee', 'company', 'company');
|
||||
frm.add_fetch('employee','employee_name','employee_name');
|
||||
},
|
||||
|
||||
refresh: function(frm) {
|
||||
cur_frm.cscript.set_help(frm.doc);
|
||||
frm.trigger("toggle_fields");
|
||||
|
||||
if(!frm.doc.__islocal) {
|
||||
frm.trigger("toggle_fields");
|
||||
frm.toggle_enable("exp_approver", frm.doc.approval_status=="Draft");
|
||||
frm.toggle_enable("approval_status",
|
||||
(frm.doc.exp_approver==frappe.session.user && frm.doc.docstatus==0));
|
||||
frm.toggle_enable("employee", !(frm.doc.status=="Approved" || frm.doc.total_advance_paid));
|
||||
frm.toggle_enable("advance_account", !frm.doc.total_advance_paid);
|
||||
frm.toggle_enable("company", !(frm.doc.status=="Approved" || frm.doc.total_advance_paid));
|
||||
if(frm.doc.docstatus == 1 && frm.doc.approval_status == 'Approved') {
|
||||
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"));
|
||||
}
|
||||
|
||||
if (frm.doc.docstatus==0 && frm.doc.exp_approver==frappe.session.user
|
||||
&& frm.doc.approval_status=="Approved" && frm.doc.advance_required==0) {
|
||||
frm.savesubmit();
|
||||
}
|
||||
|
||||
if (frm.doc.docstatus==0 && frm.doc.approval_status=="Approved"
|
||||
&& frm.doc.advance_required
|
||||
&& cint(frm.doc.total_advance_paid) < cint(frm.doc.total_sanctioned_amount)
|
||||
&& frappe.model.can_create("Payment Entry")) {
|
||||
|
||||
frm.add_custom_button(__('Advance Payment'),
|
||||
function() { frm.events.make_payment_entry(frm); }, __("Make"));
|
||||
frm.page.set_inner_btn_group_as_primary(__("Make"));
|
||||
}
|
||||
|
||||
if (frm.doc.docstatus===1 && frm.doc.approval_status=="Approved"
|
||||
&& (cint(frm.doc.total_amount_reimbursed) < cint(frm.doc.total_sanctioned_amount))
|
||||
&& frappe.model.can_create("Payment Entry")) {
|
||||
frm.add_custom_button(__('Payment'),
|
||||
function() { frm.events.make_payment_entry(frm); }, __("Make"));
|
||||
}
|
||||
|
||||
if(frm.doc.docstatus == 1 && frm.doc.approval_status == 'Approved') {
|
||||
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"));
|
||||
}
|
||||
|
||||
if (frm.doc.docstatus===1 && frm.doc.approval_status=="Approved") {
|
||||
/* eslint-disable */
|
||||
// no idea how `me` works here
|
||||
if (cint(frm.doc.total_amount_reimbursed) > 0 && frappe.model.can_read("Journal Entry")) {
|
||||
frm.add_custom_button(__('Bank Entries'), function() {
|
||||
frappe.route_options = {
|
||||
"Journal Entry Account.reference_type": frm.doc.doctype,
|
||||
"Journal Entry Account.reference_name": frm.doc.name,
|
||||
company: frm.doc.company
|
||||
};
|
||||
frappe.set_route("List", "Journal Entry");
|
||||
}, __("View"));
|
||||
}
|
||||
/* eslint-enable */
|
||||
}
|
||||
if (frm.doc.docstatus===1 && frm.doc.approval_status=="Approved"
|
||||
&& (cint(frm.doc.total_amount_reimbursed) < cint(frm.doc.total_sanctioned_amount))
|
||||
&& frappe.model.can_create("Payment Entry")) {
|
||||
frm.add_custom_button(__('Payment'),
|
||||
function() { frm.events.make_payment_entry(frm); }, __("Make"));
|
||||
}
|
||||
},
|
||||
|
||||
@ -213,10 +199,6 @@ frappe.ui.form.on("Expense Claim", {
|
||||
});
|
||||
},
|
||||
|
||||
advance_required: function(frm) {
|
||||
frm.refresh();
|
||||
},
|
||||
|
||||
set_query_for_cost_center: function(frm) {
|
||||
frm.fields_dict["cost_center"].get_query = function() {
|
||||
return {
|
||||
@ -227,18 +209,6 @@ frappe.ui.form.on("Expense Claim", {
|
||||
};
|
||||
},
|
||||
|
||||
set_query_for_advance_account: function(frm) {
|
||||
frm.fields_dict["advance_account"].get_query = function() {
|
||||
return {
|
||||
filters: {
|
||||
"report_type": "Balance Sheet",
|
||||
"account_type": "Receivable",
|
||||
"company": frm.doc.company
|
||||
}
|
||||
};
|
||||
};
|
||||
},
|
||||
|
||||
set_query_for_payable_account: function(frm) {
|
||||
frm.fields_dict["payable_account"].get_query = function() {
|
||||
return {
|
||||
|
@ -172,36 +172,6 @@
|
||||
"unique": 0,
|
||||
"width": "50%"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "advance_required",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Advance Payment Required",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
@ -576,37 +546,6 @@
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "total_advance_paid",
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Total Advance Paid",
|
||||
"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_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
@ -854,38 +793,6 @@
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "",
|
||||
"fieldname": "advance_account",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Advance 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_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
@ -1057,7 +964,7 @@
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"menu_index": 0,
|
||||
"modified": "2017-07-17 15:48:23.255142",
|
||||
"modified": "2017-07-17 15:47:23.255142",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Expense Claim",
|
||||
|
@ -33,7 +33,6 @@ class ExpenseClaim(AccountsController):
|
||||
self.set_payable_account()
|
||||
self.set_cost_center()
|
||||
self.set_status()
|
||||
self.validate_advance_payment()
|
||||
if self.task and not self.project:
|
||||
self.project = frappe.db.get_value("Task", self.task, "project")
|
||||
|
||||
@ -44,8 +43,7 @@ class ExpenseClaim(AccountsController):
|
||||
"2": "Cancelled"
|
||||
}[cstr(self.docstatus or 0)]
|
||||
|
||||
total_paid_amount = flt(self.total_amount_reimbursed) + flt(self.total_advance_paid)
|
||||
if self.total_sanctioned_amount > 0 and self.total_sanctioned_amount == total_paid_amount \
|
||||
if self.total_sanctioned_amount > 0 and self.total_sanctioned_amount == self.total_amount_reimbursed \
|
||||
and self.docstatus == 1 and self.approval_status == 'Approved':
|
||||
self.status = "Paid"
|
||||
elif self.total_sanctioned_amount > 0 and self.docstatus == 1 and self.approval_status == 'Approved':
|
||||
@ -69,7 +67,7 @@ class ExpenseClaim(AccountsController):
|
||||
self.make_gl_entries()
|
||||
|
||||
if self.is_paid:
|
||||
update_paid_amount(self, self.payable_account)
|
||||
update_reimbursed_amount(self)
|
||||
|
||||
self.set_status()
|
||||
|
||||
@ -79,7 +77,7 @@ class ExpenseClaim(AccountsController):
|
||||
self.make_gl_entries(cancel=True)
|
||||
|
||||
if self.is_paid:
|
||||
update_paid_amount(self, self.payable_account)
|
||||
update_reimbursed_amount(self)
|
||||
|
||||
self.set_status()
|
||||
|
||||
@ -98,36 +96,19 @@ class ExpenseClaim(AccountsController):
|
||||
gl_entry = []
|
||||
self.validate_account_details()
|
||||
|
||||
outstanding_amount = flt(self.total_sanctioned_amount) - flt(self.total_advance_paid)
|
||||
|
||||
# payable entry
|
||||
if outstanding_amount:
|
||||
gl_entry.append(
|
||||
self.get_gl_dict({
|
||||
"account": self.payable_account,
|
||||
"credit": outstanding_amount,
|
||||
"credit_in_account_currency": outstanding_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
|
||||
})
|
||||
)
|
||||
|
||||
if self.total_advance_paid:
|
||||
gl_entry.append(
|
||||
self.get_gl_dict({
|
||||
"account": self.advance_account,
|
||||
"credit": self.total_advance_paid,
|
||||
"credit_in_account_currency": self.total_advance_paid,
|
||||
"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
|
||||
})
|
||||
)
|
||||
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:
|
||||
@ -141,15 +122,14 @@ class ExpenseClaim(AccountsController):
|
||||
})
|
||||
)
|
||||
|
||||
if self.is_paid and outstanding_amount:
|
||||
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": outstanding_amount,
|
||||
"credit_in_account_currency": outstanding_amount,
|
||||
"credit": self.total_sanctioned_amount,
|
||||
"credit_in_account_currency": self.total_sanctioned_amount,
|
||||
"against": self.employee
|
||||
})
|
||||
)
|
||||
@ -160,8 +140,8 @@ class ExpenseClaim(AccountsController):
|
||||
"party_type": "Employee",
|
||||
"party": self.employee,
|
||||
"against": payment_account,
|
||||
"debit": outstanding_amount,
|
||||
"debit_in_account_currency": outstanding_amount,
|
||||
"debit": self.total_sanctioned_amount,
|
||||
"debit_in_account_currency": self.total_sanctioned_amount,
|
||||
"against_voucher": self.name,
|
||||
"against_voucher_type": self.doctype,
|
||||
})
|
||||
@ -208,37 +188,18 @@ class ExpenseClaim(AccountsController):
|
||||
def set_expense_account(self):
|
||||
for expense in self.expenses:
|
||||
if not expense.default_account:
|
||||
expense.default_account = get_expense_claim_account(expense.expense_type,
|
||||
self.company)["account"]
|
||||
expense.default_account = get_expense_claim_account(expense.expense_type, self.company)["account"]
|
||||
|
||||
def validate_advance_payment(self):
|
||||
if self.advance_required:
|
||||
if self.docstatus == 1 and not self.total_advance_paid:
|
||||
frappe.throw(_("Advance payment required before submission of the Expense Claim"))
|
||||
elif self.total_advance_paid:
|
||||
frappe.throw(_("As advance payment already done, cannot unset 'Advance Payment Required'"))
|
||||
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
|
||||
|
||||
def update_paid_amount(doc, party_account):
|
||||
paid_amount = frappe.db.sql("""
|
||||
select ifnull(sum(debit_in_account_currency), 0) as amount
|
||||
from `tabGL Entry`
|
||||
where
|
||||
against_voucher_type = 'Expense Claim' and against_voucher = %s
|
||||
and party = %s and account = %s
|
||||
""", (doc.name, doc.employee, party_account) ,as_dict=1)[0].amount
|
||||
doc.total_amount_reimbursed = amt
|
||||
frappe.db.set_value("Expense Claim", doc.name , "total_amount_reimbursed", amt)
|
||||
|
||||
paid_amount_field = None
|
||||
if party_account == doc.payable_account:
|
||||
paid_amount_field = "total_amount_reimbursed"
|
||||
elif party_account == doc.advance_account:
|
||||
paid_amount_field = "total_advance_paid"
|
||||
|
||||
if paid_amount_field:
|
||||
doc.set(paid_amount_field, paid_amount)
|
||||
frappe.db.set_value("Expense Claim", doc.name , paid_amount_field, paid_amount)
|
||||
|
||||
doc.set_status()
|
||||
frappe.db.set_value("Expense Claim", doc.name , "status", doc.status)
|
||||
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):
|
||||
@ -258,31 +219,25 @@ def make_bank_entry(dt, dn):
|
||||
if not default_bank_cash_account:
|
||||
default_bank_cash_account = get_default_bank_cash_account(expense_claim.company, "Cash")
|
||||
|
||||
if expense_claim.docstatus == 0:
|
||||
party_account = expense_claim.advance_account
|
||||
else:
|
||||
party_account = expense_claim.payable_account
|
||||
|
||||
payment_amount = flt(expense_claim.total_sanctioned_amount) \
|
||||
- flt(expense_claim.total_amount_reimbursed) - flt(expense_claim.total_advance_paid)
|
||||
|
||||
je = frappe.new_doc("Journal Entry")
|
||||
je.voucher_type = 'Bank Entry'
|
||||
je.company = expense_claim.company
|
||||
je.remark = 'Advance ' if expense_claim.docstatus==0 else '' + 'Payment against Expense Claim: ' + dn;
|
||||
je.remark = 'Payment against Expense Claim: ' + dn;
|
||||
|
||||
je.append("accounts", {
|
||||
"account": party_account,
|
||||
"debit_in_account_currency": payment_amount,
|
||||
"account": expense_claim.payable_account,
|
||||
"debit_in_account_currency": flt(expense_claim.total_sanctioned_amount - expense_claim.total_amount_reimbursed),
|
||||
"reference_type": "Expense Claim",
|
||||
"reference_name": expense_claim.name,
|
||||
"party_type": "Employee",
|
||||
"party": expense_claim.employee
|
||||
"party": expense_claim.employee,
|
||||
"reference_name": expense_claim.name
|
||||
})
|
||||
|
||||
je.append("accounts", {
|
||||
"account": default_bank_cash_account.account,
|
||||
"credit_in_account_currency": payment_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,
|
||||
"account_currency": default_bank_cash_account.account_currency,
|
||||
"account_type": default_bank_cash_account.account_type
|
||||
|
@ -6,7 +6,6 @@ import frappe
|
||||
import unittest
|
||||
from frappe.utils import random_string, nowdate
|
||||
from erpnext.hr.doctype.expense_claim.expense_claim import make_bank_entry
|
||||
from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry
|
||||
|
||||
test_records = frappe.get_test_records('Expense Claim')
|
||||
|
||||
@ -23,35 +22,28 @@ class TestExpenseClaim(unittest.TestCase):
|
||||
[{ "title": "_Test Project Task 1", "status": "Open" }]
|
||||
}).save()
|
||||
|
||||
existing_claimed_amount = frappe.db.get_value("Project", "_Test Project 1", "total_expense_claim")
|
||||
task_name = frappe.db.get_value("Task", {"project": "_Test Project 1"})
|
||||
payable_account = get_payable_account("Wind Power LLC")
|
||||
|
||||
make_expense_claim(300, 200,"Travel Expenses - WP", "Wind Power LLC",
|
||||
payable_account, "_Test Project 1", task_name)
|
||||
make_expense_claim(payable_account, 300, 200, "Wind Power LLC","Travel Expenses - WP", "_Test Project 1", task_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"),
|
||||
existing_claimed_amount + 200)
|
||||
self.assertEqual(frappe.db.get_value("Project", "_Test Project 1", "total_expense_claim"), 200)
|
||||
|
||||
expense_claim2 = make_expense_claim(600, 500, "Travel Expenses - WP", "Wind Power LLC",
|
||||
payable_account, "_Test Project 1", task_name)
|
||||
expense_claim2 = make_expense_claim(payable_account, 600, 500, "Wind Power LLC", "Travel Expenses - WP","_Test Project 1", task_name)
|
||||
|
||||
self.assertEqual(frappe.db.get_value("Task", task_name, "total_expense_claim"), 700)
|
||||
self.assertEqual(frappe.db.get_value("Project", "_Test Project 1", "total_expense_claim"),
|
||||
existing_claimed_amount + 700)
|
||||
self.assertEqual(frappe.db.get_value("Project", "_Test Project 1", "total_expense_claim"), 700)
|
||||
|
||||
expense_claim2.cancel()
|
||||
frappe.delete_doc("Expense 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"),
|
||||
existing_claimed_amount+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 = make_expense_claim(300, 200, "Travel Expenses - WP",
|
||||
"Wind Power LLC", payable_account)
|
||||
expense_claim = make_expense_claim(payable_account, 300, 200, "Wind Power LLC", "Travel Expenses - WP")
|
||||
|
||||
je_dict = make_bank_entry("Expense Claim", expense_claim.name)
|
||||
je = frappe.get_doc(je_dict)
|
||||
@ -69,8 +61,7 @@ class TestExpenseClaim(unittest.TestCase):
|
||||
|
||||
def test_expense_claim_gl_entry(self):
|
||||
payable_account = get_payable_account("Wind Power LLC")
|
||||
expense_claim = make_expense_claim(300, 200, "Travel Expenses - WP",
|
||||
"Wind Power LLC", payable_account)
|
||||
expense_claim = make_expense_claim(payable_account, 300, 200, "Wind Power LLC", "Travel Expenses - WP")
|
||||
expense_claim.submit()
|
||||
|
||||
gl_entries = frappe.db.sql("""select account, debit, credit
|
||||
@ -107,82 +98,25 @@ class TestExpenseClaim(unittest.TestCase):
|
||||
gl_entry = frappe.get_all('GL Entry', {'voucher_type': 'Expense Claim', 'voucher_no': expense_claim.name})
|
||||
self.assertEquals(len(gl_entry), 0)
|
||||
|
||||
def test_advance_payment(self):
|
||||
expense_claim = make_expense_claim(150, 150, "Travel Expenses - _TC",
|
||||
advance_required=1, submit=False)
|
||||
|
||||
payment_entry = get_payment_entry("Expense Claim", expense_claim.name, bank_amount=50)
|
||||
payment_entry.received_amount = payment_entry.paid_amount = 50
|
||||
payment_entry.get("references")[0].allocated_amount = 50
|
||||
payment_entry.reference_no = "1"
|
||||
payment_entry.reference_date = "2016-01-01"
|
||||
payment_entry.save()
|
||||
payment_entry.submit()
|
||||
|
||||
expense_claim.load_from_db()
|
||||
self.assertEqual(expense_claim.total_advance_paid, 50)
|
||||
|
||||
expense_claim.submit()
|
||||
payment_entry = get_payment_entry("Expense Claim", expense_claim.name)
|
||||
payment_entry.reference_no = "1"
|
||||
payment_entry.reference_date = "2016-01-01"
|
||||
payment_entry.save()
|
||||
payment_entry.submit()
|
||||
|
||||
expense_claim.load_from_db()
|
||||
self.assertEqual(expense_claim.total_advance_paid, 50)
|
||||
self.assertEqual(expense_claim.total_amount_reimbursed, 100)
|
||||
|
||||
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 [
|
||||
[get_advance_account("_Test Company"), 0.0, 50.0],
|
||||
[get_payable_account("_Test Company"), 0.0, 100.0],
|
||||
["Travel Expenses - _TC", 150.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')
|
||||
|
||||
def get_advance_account(company):
|
||||
return frappe.db.get_value('Company', company, 'default_advance_account') \
|
||||
or frappe.db.get_value('Company', company, 'default_receivable_account')
|
||||
|
||||
def make_expense_claim(claim_amount, sanctioned_amount, expense_account, company="_Test Company",
|
||||
payable_account=None, project=None, task_name=None,
|
||||
advance_required=0, advance_account=None, submit=True):
|
||||
def make_expense_claim(payable_account,claim_amount, sanctioned_amount, company, account, project=None, task_name=None):
|
||||
expense_claim = frappe.get_doc({
|
||||
"doctype": "Expense Claim",
|
||||
"employee": "_T-Employee-0001",
|
||||
"payable_account": payable_account or get_payable_account(company),
|
||||
"advance_account": advance_account or get_advance_account(company),
|
||||
"advance_required": advance_required,
|
||||
"payable_account": payable_account,
|
||||
"approval_status": "Approved",
|
||||
"company": company,
|
||||
"expenses": [{
|
||||
"expense_type": "Travel",
|
||||
"default_account": expense_account,
|
||||
"claim_amount": claim_amount,
|
||||
"sanctioned_amount": sanctioned_amount
|
||||
}]
|
||||
})
|
||||
"expenses":
|
||||
[{ "expense_type": "Travel", "default_account": account, "claim_amount": claim_amount, "sanctioned_amount": sanctioned_amount }]
|
||||
})
|
||||
if project:
|
||||
expense_claim.project = project
|
||||
if task_name:
|
||||
expense_claim.task = task_name
|
||||
|
||||
expense_claim.save()
|
||||
if submit:
|
||||
expense_claim.submit()
|
||||
expense_claim.submit()
|
||||
return expense_claim
|
||||
|
||||
|
||||
|
@ -149,7 +149,6 @@ erpnext.company.setup_queries = function(frm) {
|
||||
["default_bank_account", {"account_type": "Bank"}],
|
||||
["default_cash_account", {"account_type": "Cash"}],
|
||||
["default_receivable_account", {"account_type": "Receivable"}],
|
||||
["default_advance_account", {"account_type": "Receivable"}],
|
||||
["default_payable_account", {"account_type": "Payable"}],
|
||||
["default_expense_account", {"root_type": "Expense"}],
|
||||
["default_income_account", {"root_type": "Income"}],
|
||||
|
@ -901,38 +901,6 @@
|
||||
"unique": 0,
|
||||
"width": "50%"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "eval:!doc.__islocal",
|
||||
"fieldname": "default_advance_account",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 1,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Default Advance Account",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"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_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
@ -2023,7 +1991,7 @@
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"menu_index": 0,
|
||||
"modified": "2017-09-14 18:12:10.008743",
|
||||
"modified": "2017-08-31 11:48:56.278568",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Setup",
|
||||
"name": "Company",
|
||||
|
Loading…
x
Reference in New Issue
Block a user