Task added to expense claim

all cost (expense claim and time log) against Task; task updates project cost.
This commit is contained in:
Neil Trini Lasrado 2015-03-31 10:59:29 +05:30
parent 8026137998
commit 50234cb0fe
8 changed files with 160 additions and 87 deletions

View File

@ -191,6 +191,14 @@
"permlevel": 0, "permlevel": 0,
"precision": "" "precision": ""
}, },
{
"fieldname": "task",
"fieldtype": "Link",
"label": "Task",
"options": "Task",
"permlevel": 0,
"precision": ""
},
{ {
"fieldname": "email_id", "fieldname": "email_id",
"fieldtype": "Data", "fieldtype": "Data",
@ -220,7 +228,7 @@
"icon": "icon-money", "icon": "icon-money",
"idx": 1, "idx": 1,
"is_submittable": 1, "is_submittable": 1,
"modified": "2015-03-26 04:41:50.473196", "modified": "2015-03-30 05:17:43.963137",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "HR", "module": "HR",
"name": "Expense Claim", "name": "Expense Claim",

View File

@ -21,17 +21,18 @@ class ExpenseClaim(Document):
self.validate_sanctioned_amount() self.validate_sanctioned_amount()
self.validate_exp_details() self.validate_exp_details()
self.validate_expense_approver() self.validate_expense_approver()
self.validate_task()
set_employee_name(self) set_employee_name(self)
def on_submit(self): def on_submit(self):
if self.approval_status=="Draft": if self.approval_status=="Draft":
frappe.throw(_("""Approval Status must be 'Approved' or 'Rejected'""")) frappe.throw(_("""Approval Status must be 'Approved' or 'Rejected'"""))
if self.project: if self.task:
self.update_project() self.update_task()
def on_cancel(self): def on_cancel(self):
if self.project: if self.project:
self.update_project() self.update_task()
def validate_exp_details(self): def validate_exp_details(self):
if not self.get('expenses'): if not self.get('expenses'):
@ -42,10 +43,14 @@ class ExpenseClaim(Document):
frappe.throw(_("{0} ({1}) must have role 'Expense Approver'")\ frappe.throw(_("{0} ({1}) must have role 'Expense Approver'")\
.format(get_fullname(self.exp_approver), self.exp_approver), InvalidExpenseApproverError) .format(get_fullname(self.exp_approver), self.exp_approver), InvalidExpenseApproverError)
def update_project(self): def update_task(self):
expense_amount = frappe.db.sql("""select sum(total_sanctioned_amount) from `tabExpense Claim` 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) where project = %s and task = %s and approval_status = "Approved" and docstatus=1""",(self.project, self.task))
frappe.db.set_value("Project", self.project, "total_expense_claims", expense_amount) frappe.db.set_value("Project", self.project, "total_expense_claim", expense_amount)
def validate_task(self):
if self.project and not self.task:
frappe.throw(_("Task is Mandatory if Time Log is against a project"))
def validate_sanctioned_amount(self): def validate_sanctioned_amount(self):
if self.total_sanctioned_amount > self.total_claimed_amount: if self.total_sanctioned_amount > self.total_claimed_amount:

View File

@ -206,9 +206,9 @@
"read_only": 1 "read_only": 1
}, },
{ {
"fieldname": "total_expense_claims", "fieldname": "total_expense_claim",
"fieldtype": "Currency", "fieldtype": "Currency",
"label": "Total Expense Claims", "label": "Total Expense Claim",
"permlevel": 0, "permlevel": 0,
"precision": "", "precision": "",
"read_only": 1 "read_only": 1
@ -278,7 +278,7 @@
"icon": "icon-puzzle-piece", "icon": "icon-puzzle-piece",
"idx": 1, "idx": 1,
"max_attachments": 4, "max_attachments": 4,
"modified": "2015-03-23 06:44:19.538443", "modified": "2015-03-30 08:42:33.940104",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Projects", "module": "Projects",
"name": "Project", "name": "Project",

View File

@ -25,6 +25,19 @@ erpnext.projects.Task = frappe.ui.form.Controller.extend({
this.frm.doc.project && frappe.model.remove_from_locals("Project", this.frm.doc.project && frappe.model.remove_from_locals("Project",
this.frm.doc.project); this.frm.doc.project);
}, },
refresh: function(doc) {
if(!doc.__islocal) {
cur_frm.add_custom_button(__("Time Logs"), function() {
frappe.route_options = {"project": doc.project, "task": doc.name}
frappe.set_route("List", "Time Log");
}, "icon-list", true);
cur_frm.add_custom_button(__("Expense Claims"), function() {
frappe.route_options = {"project": doc.project, "task": doc.name}
frappe.set_route("List", "Expense Claim");
}, "icon-list", true);
}
}
}); });

View File

@ -6,16 +6,6 @@
"doctype": "DocType", "doctype": "DocType",
"document_type": "Master", "document_type": "Master",
"fields": [ "fields": [
{
"fieldname": "task_details",
"fieldtype": "Section Break",
"label": "",
"oldfieldtype": "Section Break",
"permlevel": 0,
"print_width": "50%",
"search_index": 0,
"width": "50%"
},
{ {
"fieldname": "subject", "fieldname": "subject",
"fieldtype": "Data", "fieldtype": "Data",
@ -110,28 +100,27 @@
{ {
"fieldname": "time_and_budget", "fieldname": "time_and_budget",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"label": "Time and Budget", "label": "",
"oldfieldtype": "Section Break", "oldfieldtype": "Section Break",
"permlevel": 0 "permlevel": 0
}, },
{ {
"fieldname": "expected", "default": "0",
"fieldtype": "Column Break", "description": "in Hours",
"label": "Expected", "fieldname": "expected_time",
"oldfieldtype": "Column Break", "fieldtype": "Float",
"permlevel": 0, "label": "Expected Time",
"print_width": "50%",
"width": "50%"
},
{
"fieldname": "exp_total_hrs",
"fieldtype": "Data",
"label": "Total Hours (Expected)",
"oldfieldname": "exp_total_hrs", "oldfieldname": "exp_total_hrs",
"oldfieldtype": "Data", "oldfieldtype": "Data",
"permlevel": 0, "permlevel": 0,
"reqd": 0 "reqd": 0
}, },
{
"fieldname": "column_break_12",
"fieldtype": "Column Break",
"permlevel": 0,
"precision": ""
},
{ {
"fieldname": "allocated_budget", "fieldname": "allocated_budget",
"fieldtype": "Currency", "fieldtype": "Currency",
@ -143,8 +132,8 @@
}, },
{ {
"fieldname": "actual", "fieldname": "actual",
"fieldtype": "Column Break", "fieldtype": "Section Break",
"label": "Actual", "label": "",
"oldfieldtype": "Column Break", "oldfieldtype": "Column Break",
"permlevel": 0, "permlevel": 0,
"print_width": "50%", "print_width": "50%",
@ -156,7 +145,14 @@
"label": "Actual Start Date", "label": "Actual Start Date",
"oldfieldname": "act_start_date", "oldfieldname": "act_start_date",
"oldfieldtype": "Date", "oldfieldtype": "Date",
"permlevel": 0 "permlevel": 0,
"read_only": 1
},
{
"fieldname": "column_break_15",
"fieldtype": "Column Break",
"permlevel": 0,
"precision": ""
}, },
{ {
"fieldname": "act_end_date", "fieldname": "act_end_date",
@ -164,16 +160,50 @@
"label": "Actual End Date", "label": "Actual End Date",
"oldfieldname": "act_end_date", "oldfieldname": "act_end_date",
"oldfieldtype": "Date", "oldfieldtype": "Date",
"permlevel": 0 "permlevel": 0,
"read_only": 1
}, },
{ {
"fieldname": "actual_budget", "fieldname": "section_break_17",
"fieldtype": "Section Break",
"permlevel": 0,
"precision": ""
},
{
"default": "0",
"description": "in Hours",
"fieldname": "actual_time",
"fieldtype": "Float",
"label": "Actual Time",
"options": "",
"permlevel": 0,
"precision": "",
"read_only": 1
},
{
"fieldname": "column_break_20",
"fieldtype": "Column Break",
"permlevel": 0,
"precision": ""
},
{
"fieldname": "actual_cost",
"fieldtype": "Currency", "fieldtype": "Currency",
"label": "Actual Budget", "label": "Actual Cost",
"oldfieldname": "actual_budget", "oldfieldname": "actual_budget",
"oldfieldtype": "Currency", "oldfieldtype": "Currency",
"options": "Company:company:default_currency", "options": "Company:company:default_currency",
"permlevel": 0 "permlevel": 0,
"read_only": 1
},
{
"fieldname": "total_expense_claim",
"fieldtype": "Currency",
"label": "Total Expense Claim",
"options": "Company:company:default_currency",
"permlevel": 0,
"precision": "",
"read_only": 1
}, },
{ {
"fieldname": "more_details", "fieldname": "more_details",
@ -217,7 +247,7 @@
"icon": "icon-check", "icon": "icon-check",
"idx": 1, "idx": 1,
"max_attachments": 5, "max_attachments": 5,
"modified": "2015-02-20 05:09:27.295024", "modified": "2015-03-30 05:50:04.409614",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Projects", "module": "Projects",
"name": "Task", "name": "Task",

View File

@ -4,7 +4,7 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import frappe, json import frappe, json
from frappe.utils import getdate, today from frappe.utils import getdate
from frappe import _ from frappe import _
@ -26,28 +26,34 @@ class Task(Document):
return ret return ret
def validate(self): def validate(self):
self.validate_dates()
def validate_dates(self):
if self.exp_start_date and self.exp_end_date and getdate(self.exp_start_date) > getdate(self.exp_end_date): if self.exp_start_date and self.exp_end_date and getdate(self.exp_start_date) > getdate(self.exp_end_date):
frappe.throw(_("'Expected Start Date' can not be greater than 'Expected End Date'")) frappe.throw(_("'Expected Start Date' can not be greater than 'Expected End Date'"))
if self.act_start_date and self.act_end_date and getdate(self.act_start_date) > getdate(self.act_end_date): if self.act_start_date and self.act_end_date and getdate(self.act_start_date) > getdate(self.act_end_date):
frappe.throw(_("'Actual Start Date' can not be greater than 'Actual End Date'")) frappe.throw(_("'Actual Start Date' can not be greater than 'Actual End Date'"))
self.update_status()
def update_status(self):
status = frappe.db.get_value("Task", self.name, "status")
if self.status=="Working" and status !="Working" and not self.act_start_date:
self.act_start_date = today()
if self.status=="Closed" and status != "Closed" and not self.act_end_date:
self.act_end_date = today()
def on_update(self): def on_update(self):
self.update_percentage()
self.update_project()
def update_percentage(self):
"""update percent complete in project""" """update percent complete in project"""
if self.project and not self.flags.from_project: if self.project and not self.flags.from_project:
project = frappe.get_doc("Project", self.project) project = frappe.get_doc("Project", self.project)
project.run_method("update_percent_complete") project.run_method("update_percent_complete")
def update_project(self):
total_activity_cost = frappe.db.sql("""select sum(actual_cost) from `tabTask`
where project = %s""",self.project)
frappe.db.set_value("Project", self.project, "total_activity_cost", total_activity_cost)
total_expense_claim = frappe.db.sql("""select sum(total_expense_claim) from `tabTask`
where project = %s""",self.project)
frappe.db.set_value("Project", self.project, "total_expense_claim", total_expense_claim)
@frappe.whitelist() @frappe.whitelist()
def get_events(start, end, filters=None): def get_events(start, end, filters=None):
from frappe.desk.reportview import build_match_conditions from frappe.desk.reportview import build_match_conditions

View File

@ -91,6 +91,25 @@
"precision": "", "precision": "",
"read_only": 1 "read_only": 1
}, },
{
"depends_on": "",
"fieldname": "project",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Project",
"options": "Project",
"permlevel": 0,
"read_only": 0
},
{
"depends_on": "",
"fieldname": "task",
"fieldtype": "Link",
"label": "Task",
"options": "Task",
"permlevel": 0,
"read_only": 0
},
{ {
"depends_on": "eval:!doc.for_manufacturing", "depends_on": "eval:!doc.for_manufacturing",
"fieldname": "activity_type", "fieldname": "activity_type",
@ -102,15 +121,6 @@
"read_only": 0, "read_only": 0,
"reqd": 0 "reqd": 0
}, },
{
"depends_on": "eval:!doc.for_manufacturing",
"fieldname": "task",
"fieldtype": "Link",
"label": "Task",
"options": "Task",
"permlevel": 0,
"read_only": 0
},
{ {
"depends_on": "eval:doc.for_manufacturing", "depends_on": "eval:doc.for_manufacturing",
"fieldname": "section_break_11", "fieldname": "section_break_11",
@ -188,22 +198,6 @@
"permlevel": 0, "permlevel": 0,
"read_only": 0 "read_only": 0
}, },
{
"fieldname": "section_break_9",
"fieldtype": "Section Break",
"permlevel": 0,
"read_only": 0
},
{
"depends_on": "",
"fieldname": "project",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Project",
"options": "Project",
"permlevel": 0,
"read_only": 0
},
{ {
"depends_on": "", "depends_on": "",
"fieldname": "section_break_24", "fieldname": "section_break_24",

View File

@ -24,15 +24,20 @@ class TimeLog(Document):
self.check_workstation_timings() self.check_workstation_timings()
self.validate_production_order() self.validate_production_order()
self.validate_manufacturing() self.validate_manufacturing()
self.validate_task()
self.validate_cost() self.validate_cost()
def on_submit(self): def on_submit(self):
self.update_production_order() if self.for_manufacturing:
self.update_project() self.update_production_order()
if self.task:
self.update_task()
def on_cancel(self): def on_cancel(self):
self.update_production_order() if self.for_manufacturing:
self.update_project() self.update_production_order()
if self.task:
self.update_task()
def before_update_after_submit(self): def before_update_after_submit(self):
self.set_status() self.set_status()
@ -128,7 +133,7 @@ class TimeLog(Document):
def update_production_order(self): def update_production_order(self):
"""Updates `start_date`, `end_date`, `status` for operation in Production Order.""" """Updates `start_date`, `end_date`, `status` for operation in Production Order."""
if self.for_manufacturing and self.production_order: if self.production_order:
if not self.operation_id: if not self.operation_id:
frappe.throw(_("Operation ID not set")) frappe.throw(_("Operation ID not set"))
@ -217,10 +222,22 @@ class TimeLog(Document):
else: else:
self.billing_amount = 0 self.billing_amount = 0
def update_project(self): def validate_task(self):
activity_cost = frappe.db.sql("""select sum(billing_cost) from `tabTime Log` if self.project and not self.task:
where project = %s and docstatus=1""",self.project) frappe.throw(_("Task is Mandatory if Time Log is against a project"))
frappe.db.set_value("Project", self.project, "total_activity_cost", activity_cost)
def update_task(self):
tl = frappe.db.sql("""select min(from_time) as start_date, max(to_time) as end_date, sum(billing_amount) as cost, sum(hours) as time
from `tabTime Log` where project = %s and task = %s and docstatus=1""",(self.project, self.task),as_dict=1)[0]
task = frappe.get_doc("Task", self.task)
if task.status == "Open":
task.status = "Working"
task.actual_cost= tl.cost
task.actual_time= tl.time
task.act_start_date= tl.start_date
task.act_end_date= tl.end_date
task.save()
@frappe.whitelist() @frappe.whitelist()
def get_events(start, end, filters=None): def get_events(start, end, filters=None):