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:
Neil Trini Lasrado 2015-03-24 12:49:45 +05:30
parent 0f2b7bd2bf
commit 458b8885f0
10 changed files with 243 additions and 7 deletions

View File

@ -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"),
},
]
},
{

View File

@ -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."))

View 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"
}

View 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

View 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

View File

@ -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);
}
}

View File

@ -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",

View File

@ -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",

View File

@ -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):