New Document Activity Cost created.
In TL - billing rate and internal rate added In Project - total expense claim and total activity cost. Buttons addded - show time logs and show expense claims. In Expense Claim - Employee and project link added. update cost in project on submit and on trash. Validation added to check sanctioned amount is not greater than claim amount.
This commit is contained in:
parent
0f2b7bd2bf
commit
458b8885f0
@ -32,6 +32,11 @@ def get_data():
|
||||
"name": "Activity Type",
|
||||
"description": _("Types of activities for Time Sheets"),
|
||||
},
|
||||
{
|
||||
"type": "doctype",
|
||||
"name": "Activity Cost",
|
||||
"description": _("Cost of various activities"),
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -18,6 +18,7 @@ class ExpenseClaim(Document):
|
||||
|
||||
def validate(self):
|
||||
validate_fiscal_year(self.posting_date, self.fiscal_year, _("Posting Date"), self)
|
||||
self.validate_sanctioned_amount()
|
||||
self.validate_exp_details()
|
||||
self.validate_expense_approver()
|
||||
set_employee_name(self)
|
||||
@ -25,6 +26,12 @@ class ExpenseClaim(Document):
|
||||
def on_submit(self):
|
||||
if self.approval_status=="Draft":
|
||||
frappe.throw(_("""Approval Status must be 'Approved' or 'Rejected'"""))
|
||||
if self.project:
|
||||
self.update_project()
|
||||
|
||||
def on_cancel(self):
|
||||
if self.project:
|
||||
self.update_project()
|
||||
|
||||
def validate_exp_details(self):
|
||||
if not self.get('expenses'):
|
||||
@ -34,3 +41,12 @@ class ExpenseClaim(Document):
|
||||
if self.exp_approver and "Expense Approver" not in frappe.get_roles(self.exp_approver):
|
||||
frappe.throw(_("{0} ({1}) must have role 'Expense Approver'")\
|
||||
.format(get_fullname(self.exp_approver), self.exp_approver), InvalidExpenseApproverError)
|
||||
|
||||
def update_project(self):
|
||||
expense_amount = frappe.db.sql("""select sum(total_sanctioned_amount) from `tabExpense Claim`
|
||||
where project = %s and approval_status = "Approved" and docstatus=1""",self.project)
|
||||
frappe.db.set_value("Project", self.project, "total_expense_claims", expense_amount)
|
||||
|
||||
def validate_sanctioned_amount(self):
|
||||
if self.total_sanctioned_amount > self.total_claimed_amount:
|
||||
frappe.throw(_("Total sanctioned amount cannot be greater than total claimed amount."))
|
0
erpnext/projects/doctype/activity_cost/__init__.py
Normal file
0
erpnext/projects/doctype/activity_cost/__init__.py
Normal file
146
erpnext/projects/doctype/activity_cost/activity_cost.json
Normal file
146
erpnext/projects/doctype/activity_cost/activity_cost.json
Normal file
@ -0,0 +1,146 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_import": 1,
|
||||
"allow_rename": 1,
|
||||
"creation": "2015-03-23 02:00:21.861546",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "",
|
||||
"fields": [
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"fieldname": "employee",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "Employee",
|
||||
"no_copy": 0,
|
||||
"options": "Employee",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"read_only": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_2",
|
||||
"fieldtype": "Column Break",
|
||||
"permlevel": 0,
|
||||
"precision": ""
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"fieldname": "activity_type",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "Activity Type",
|
||||
"no_copy": 0,
|
||||
"options": "Activity Type",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"read_only": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "section_break_4",
|
||||
"fieldtype": "Section Break",
|
||||
"permlevel": 0,
|
||||
"precision": ""
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"fieldname": "billing_rate",
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "Billing Rate",
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"read_only": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_6",
|
||||
"fieldtype": "Column Break",
|
||||
"permlevel": 0,
|
||||
"precision": ""
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"fieldname": "intrernal_rate",
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "Internal Rate",
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"read_only": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0
|
||||
}
|
||||
],
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"in_create": 0,
|
||||
"in_dialog": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"modified": "2015-03-23 02:01:53.789728",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Projects",
|
||||
"name": "Activity Cost",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"amend": 0,
|
||||
"apply_user_permissions": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Projects User",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC"
|
||||
}
|
10
erpnext/projects/doctype/activity_cost/activity_cost.py
Normal file
10
erpnext/projects/doctype/activity_cost/activity_cost.py
Normal file
@ -0,0 +1,10 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
class ActivityCost(Document):
|
||||
pass
|
12
erpnext/projects/doctype/activity_cost/test_activity_cost.py
Normal file
12
erpnext/projects/doctype/activity_cost/test_activity_cost.py
Normal file
@ -0,0 +1,12 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors and Contributors
|
||||
# See license.txt
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import frappe
|
||||
import unittest
|
||||
|
||||
# test_records = frappe.get_test_records('Activity Cost')
|
||||
|
||||
class TestActivityCost(unittest.TestCase):
|
||||
pass
|
@ -21,6 +21,14 @@ cur_frm.cscript.refresh = function(doc) {
|
||||
frappe.route_options = {"project": doc.name}
|
||||
frappe.set_route("List", "Task");
|
||||
}, "icon-list", true);
|
||||
cur_frm.add_custom_button(__("Time Logs"), function() {
|
||||
frappe.route_options = {"project": doc.name}
|
||||
frappe.set_route("List", "Time Log");
|
||||
}, "icon-list", true);
|
||||
cur_frm.add_custom_button(__("Expense Claims"), function() {
|
||||
frappe.route_options = {"project": doc.name}
|
||||
frappe.set_route("List", "Expense Claim");
|
||||
}, "icon-list", true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -197,6 +197,22 @@
|
||||
"permlevel": 0,
|
||||
"search_index": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "total_activity_cost",
|
||||
"fieldtype": "Currency",
|
||||
"label": "Total Activity Cost",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "total_expense_claims",
|
||||
"fieldtype": "Currency",
|
||||
"label": "Total Expense Claims",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "cost_center",
|
||||
"fieldtype": "Link",
|
||||
@ -262,7 +278,7 @@
|
||||
"icon": "icon-puzzle-piece",
|
||||
"idx": 1,
|
||||
"max_attachments": 4,
|
||||
"modified": "2015-02-22 11:17:49.051755",
|
||||
"modified": "2015-03-23 06:44:19.538443",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Projects",
|
||||
"name": "Project",
|
||||
|
@ -50,6 +50,14 @@
|
||||
"permlevel": 0,
|
||||
"precision": ""
|
||||
},
|
||||
{
|
||||
"fieldname": "employee",
|
||||
"fieldtype": "Link",
|
||||
"label": "Employee",
|
||||
"options": "Employee",
|
||||
"permlevel": 0,
|
||||
"precision": ""
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_3",
|
||||
"fieldtype": "Column Break",
|
||||
@ -195,6 +203,26 @@
|
||||
"permlevel": 0,
|
||||
"read_only": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "billing_rate",
|
||||
"fieldtype": "Currency",
|
||||
"label": "Billing Rate",
|
||||
"permlevel": 0,
|
||||
"precision": ""
|
||||
},
|
||||
{
|
||||
"fieldname": "internal_rate",
|
||||
"fieldtype": "Currency",
|
||||
"label": "Internal Rate",
|
||||
"permlevel": 0,
|
||||
"precision": ""
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_25",
|
||||
"fieldtype": "Column Break",
|
||||
"permlevel": 0,
|
||||
"precision": ""
|
||||
},
|
||||
{
|
||||
"description": "Will be updated when batched.",
|
||||
"fieldname": "time_log_batch",
|
||||
@ -213,12 +241,6 @@
|
||||
"permlevel": 0,
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_16",
|
||||
"fieldtype": "Column Break",
|
||||
"permlevel": 0,
|
||||
"read_only": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "amended_from",
|
||||
"fieldtype": "Link",
|
||||
|
@ -63,6 +63,7 @@ class TimeLog(Document):
|
||||
def validate_overlap(self):
|
||||
"""Checks if 'Time Log' entries overlap for a user, workstation. """
|
||||
self.validate_overlap_for("user")
|
||||
self.validate_overlap_for("employee")
|
||||
self.validate_overlap_for("workstation")
|
||||
|
||||
def validate_overlap_for(self, fieldname):
|
||||
|
Loading…
x
Reference in New Issue
Block a user