Merge remote-tracking branch 'webnotes/4.0.0-wip' into permissions

Conflicts:
	erpnext/accounts/page/accounts_browser/accounts_browser.css
	erpnext/controllers/buying_controller.py
	erpnext/manufacturing/doctype/production_order/production_order.py
	erpnext/patches/patch_list.py
	erpnext/selling/doctype/customer/customer.txt
	erpnext/selling/doctype/sales_order/sales_order.py
	erpnext/selling/doctype/sales_order/test_sales_order.py
	erpnext/setup/doctype/features_setup/features_setup.txt
	erpnext/stock/doctype/stock_entry/test_stock_entry.py
	erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py
	startup/query_handlers.py
This commit is contained in:
Anand Doshi
2013-12-26 18:30:39 +05:30
1813 changed files with 12064 additions and 18858 deletions

View File

View File

@@ -0,0 +1 @@
from __future__ import unicode_literals

View File

@@ -0,0 +1 @@
Type of Activity (set in Task, Time Log)

View File

@@ -0,0 +1,9 @@
# 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 webnotes
class DocType:
def __init__(self, d, dl):
self.doc, self.doclist = d, dl

View File

@@ -0,0 +1,60 @@
[
{
"creation": "2013-03-05 10:14:59",
"docstatus": 0,
"modified": "2013-12-20 19:23:54",
"modified_by": "Administrator",
"owner": "Administrator"
},
{
"allow_import": 1,
"autoname": "field:activity_type",
"doctype": "DocType",
"document_type": "Master",
"icon": "icon-flag",
"in_dialog": 0,
"module": "Projects",
"name": "__common__"
},
{
"doctype": "DocField",
"fieldname": "activity_type",
"fieldtype": "Data",
"label": "Activity Type",
"name": "__common__",
"parent": "Activity Type",
"parentfield": "fields",
"parenttype": "DocType",
"permlevel": 0,
"reqd": 1
},
{
"create": 1,
"doctype": "DocPerm",
"email": 1,
"name": "__common__",
"parent": "Activity Type",
"parentfield": "permissions",
"parenttype": "DocType",
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"write": 1
},
{
"doctype": "DocType",
"name": "Activity Type"
},
{
"doctype": "DocField"
},
{
"doctype": "DocPerm",
"role": "System Manager"
},
{
"doctype": "DocPerm",
"role": "Projects User"
}
]

View File

@@ -0,0 +1,8 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
test_records = [
[{"activity_type":"_Test Activity Type"}],
[{"activity_type":"_Test Activity Type 1"}],
[{"activity_type":"_Test Activity Type 2"}]
]

View File

@@ -0,0 +1 @@
Project details. Projects can be internal or external and can have Tasks, Milestones associated to it.

View File

@@ -0,0 +1 @@
from __future__ import unicode_literals

View File

@@ -0,0 +1,5 @@
You can use projects to:
1. Track budgets (Purchase Orders, Invoices).
2. Track material consumption.
3. Create and assign tasks (and view them on a Gantt Chart).

View File

@@ -0,0 +1,22 @@
// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
// show tasks
cur_frm.cscript.refresh = function(doc) {
if(!doc.__islocal) {
cur_frm.appframe.add_button(wn._("Gantt Chart"), function() {
wn.route_options = {"project": doc.name}
wn.set_route("Gantt", "Task");
}, "icon-tasks");
cur_frm.add_custom_button(wn._("Tasks"), function() {
wn.route_options = {"project": doc.name}
wn.set_route("List", "Task");
}, "icon-list");
}
}
cur_frm.fields_dict.customer.get_query = function(doc,cdt,cdn) {
return{
query: "erpnext.controllers.queries.customer_query"
}
}

View File

@@ -0,0 +1,63 @@
# 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 webnotes
from webnotes.utils import flt, getdate
from webnotes import msgprint
from erpnext.utilities.transaction_base import delete_events
class DocType:
def __init__(self, doc, doclist=None):
self.doc = doc
self.doclist = doclist
def get_gross_profit(self):
pft, per_pft =0, 0
pft = flt(self.doc.project_value) - flt(self.doc.est_material_cost)
#if pft > 0:
per_pft = (flt(pft) / flt(self.doc.project_value)) * 100
ret = {'gross_margin_value': pft, 'per_gross_margin': per_pft}
return ret
def validate(self):
"""validate start date before end date"""
if self.doc.project_start_date and self.doc.completion_date:
if getdate(self.doc.completion_date) < getdate(self.doc.project_start_date):
msgprint("Expected Completion Date can not be less than Project Start Date")
raise Exception
def on_update(self):
self.add_calendar_event()
def update_percent_complete(self):
total = webnotes.conn.sql("""select count(*) from tabTask where project=%s""",
self.doc.name)[0][0]
if total:
completed = webnotes.conn.sql("""select count(*) from tabTask where
project=%s and status in ('Closed', 'Cancelled')""", self.doc.name)[0][0]
webnotes.conn.set_value("Project", self.doc.name, "percent_complete",
int(float(completed) / total * 100))
def add_calendar_event(self):
# delete any earlier event for this project
delete_events(self.doc.doctype, self.doc.name)
# add events
for milestone in self.doclist.get({"parentfield": "project_milestones"}):
if milestone.milestone_date:
description = (milestone.milestone or "Milestone") + " for " + self.doc.name
webnotes.bean({
"doctype": "Event",
"owner": self.doc.owner,
"subject": description,
"description": description,
"starts_on": milestone.milestone_date + " 10:00:00",
"event_type": "Private",
"ref_type": self.doc.doctype,
"ref_name": self.doc.name
}).insert()
def on_trash(self):
delete_events(self.doc.doctype, self.doc.name)

View File

@@ -0,0 +1,308 @@
[
{
"creation": "2013-03-07 11:55:07",
"docstatus": 0,
"modified": "2013-12-20 19:24:17",
"modified_by": "Administrator",
"owner": "Administrator"
},
{
"allow_attach": 1,
"allow_import": 1,
"autoname": "field:project_name",
"doctype": "DocType",
"document_type": "Master",
"icon": "icon-puzzle-piece",
"max_attachments": 4,
"module": "Projects",
"name": "__common__",
"search_fields": "customer, status, priority, is_active"
},
{
"doctype": "DocField",
"name": "__common__",
"parent": "Project",
"parentfield": "fields",
"parenttype": "DocType",
"permlevel": 0
},
{
"amend": 0,
"doctype": "DocPerm",
"name": "__common__",
"parent": "Project",
"parentfield": "permissions",
"parenttype": "DocType",
"read": 1,
"report": 1,
"submit": 0
},
{
"doctype": "DocType",
"name": "Project"
},
{
"doctype": "DocField",
"fieldname": "overview",
"fieldtype": "Section Break",
"label": "Overview",
"options": "icon-file"
},
{
"doctype": "DocField",
"fieldname": "cb_project_status",
"fieldtype": "Column Break",
"label": "Status"
},
{
"description": "Project will get saved and will be searchable with project name given",
"doctype": "DocField",
"fieldname": "project_name",
"fieldtype": "Data",
"label": "Project Name",
"no_copy": 0,
"oldfieldname": "project_name",
"oldfieldtype": "Data",
"reqd": 1
},
{
"default": "Open",
"doctype": "DocField",
"fieldname": "status",
"fieldtype": "Select",
"in_filter": 1,
"label": "Status",
"no_copy": 1,
"oldfieldname": "status",
"oldfieldtype": "Select",
"options": "Open\nCompleted\nCancelled",
"reqd": 1,
"search_index": 1
},
{
"doctype": "DocField",
"fieldname": "is_active",
"fieldtype": "Select",
"label": "Is Active",
"no_copy": 0,
"oldfieldname": "is_active",
"oldfieldtype": "Select",
"options": "Yes\nNo",
"search_index": 0
},
{
"doctype": "DocField",
"fieldname": "priority",
"fieldtype": "Select",
"label": "Priority",
"no_copy": 0,
"oldfieldname": "priority",
"oldfieldtype": "Select",
"options": "Medium\nLow\nHigh",
"search_index": 0
},
{
"doctype": "DocField",
"fieldname": "cb_project_dates",
"fieldtype": "Column Break",
"label": "Dates"
},
{
"doctype": "DocField",
"fieldname": "project_start_date",
"fieldtype": "Date",
"in_filter": 1,
"label": "Project Start Date",
"no_copy": 0,
"oldfieldname": "project_start_date",
"oldfieldtype": "Date",
"search_index": 0
},
{
"doctype": "DocField",
"fieldname": "completion_date",
"fieldtype": "Date",
"label": "Completion Date",
"no_copy": 0,
"oldfieldname": "completion_date",
"oldfieldtype": "Date",
"search_index": 0
},
{
"doctype": "DocField",
"fieldname": "act_completion_date",
"fieldtype": "Date",
"label": "Actual Completion Date",
"no_copy": 0,
"oldfieldname": "act_completion_date",
"oldfieldtype": "Date",
"search_index": 0
},
{
"doctype": "DocField",
"fieldname": "project_type",
"fieldtype": "Select",
"label": "Project Type",
"no_copy": 0,
"oldfieldname": "project_type",
"oldfieldtype": "Data",
"options": "Internal\nExternal\nOther",
"search_index": 0
},
{
"doctype": "DocField",
"fieldname": "sb_milestones",
"fieldtype": "Section Break",
"label": "Milestones",
"oldfieldtype": "Section Break",
"options": "icon-flag"
},
{
"description": "Milestones will be added as Events in the Calendar",
"doctype": "DocField",
"fieldname": "project_milestones",
"fieldtype": "Table",
"label": "Project Milestones",
"no_copy": 0,
"oldfieldname": "project_milestones",
"oldfieldtype": "Table",
"options": "Project Milestone",
"search_index": 0
},
{
"doctype": "DocField",
"fieldname": "section_break0",
"fieldtype": "Section Break",
"label": "Project Details",
"oldfieldtype": "Section Break",
"options": "icon-list"
},
{
"doctype": "DocField",
"fieldname": "notes",
"fieldtype": "Text Editor",
"label": "Notes",
"no_copy": 0,
"oldfieldname": "notes",
"oldfieldtype": "Text Editor",
"search_index": 0
},
{
"doctype": "DocField",
"fieldname": "percent_complete",
"fieldtype": "Percent",
"in_list_view": 1,
"label": "Percent Complete",
"read_only": 1
},
{
"doctype": "DocField",
"fieldname": "company",
"fieldtype": "Link",
"label": "Company",
"options": "Company"
},
{
"doctype": "DocField",
"fieldname": "project_details",
"fieldtype": "Section Break",
"label": "Project Costing",
"oldfieldtype": "Section Break",
"options": "icon-money"
},
{
"doctype": "DocField",
"fieldname": "project_value",
"fieldtype": "Currency",
"in_list_view": 1,
"label": "Project Value",
"no_copy": 0,
"oldfieldname": "project_value",
"oldfieldtype": "Currency",
"options": "Company:company:default_currency",
"reqd": 0,
"search_index": 0
},
{
"doctype": "DocField",
"fieldname": "est_material_cost",
"fieldtype": "Currency",
"label": "Estimated Material Cost",
"no_copy": 0,
"oldfieldname": "est_material_cost",
"oldfieldtype": "Currency",
"options": "Company:company:default_currency",
"search_index": 0
},
{
"doctype": "DocField",
"fieldname": "column_break0",
"fieldtype": "Column Break",
"label": "Margin",
"oldfieldtype": "Column Break",
"width": "50%"
},
{
"doctype": "DocField",
"fieldname": "gross_margin_value",
"fieldtype": "Currency",
"label": "Gross Margin Value",
"no_copy": 0,
"oldfieldname": "gross_margin_value",
"oldfieldtype": "Currency",
"options": "Company:company:default_currency",
"reqd": 0,
"search_index": 0
},
{
"doctype": "DocField",
"fieldname": "per_gross_margin",
"fieldtype": "Currency",
"label": "Gross Margin %",
"no_copy": 0,
"oldfieldname": "per_gross_margin",
"oldfieldtype": "Currency",
"options": "Company:company:default_currency",
"reqd": 0,
"search_index": 0
},
{
"doctype": "DocField",
"fieldname": "customer_details",
"fieldtype": "Section Break",
"label": "Customer Details",
"oldfieldtype": "Section Break",
"options": "icon-user"
},
{
"doctype": "DocField",
"fieldname": "customer",
"fieldtype": "Link",
"in_filter": 1,
"label": "Customer",
"no_copy": 0,
"oldfieldname": "customer",
"oldfieldtype": "Link",
"options": "Customer",
"print_hide": 1,
"reqd": 0,
"search_index": 1
},
{
"cancel": 1,
"create": 1,
"doctype": "DocPerm",
"email": 1,
"permlevel": 0,
"print": 1,
"role": "Projects User",
"write": 1
},
{
"cancel": 0,
"create": 0,
"doctype": "DocPerm",
"permlevel": 1,
"role": "All"
}
]

View File

@@ -0,0 +1,11 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
test_records = [[{
"project_name": "_Test Project",
"status": "Open"
}],
[{
"project_name": "_Test Project 1",
"status": "Open"
}]]

View File

@@ -0,0 +1 @@
Important date in the project lifecycle.

View File

@@ -0,0 +1 @@
from __future__ import unicode_literals

View File

@@ -0,0 +1,9 @@
# 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 webnotes
class DocType:
def __init__(self, d, dl):
self.doc, self.doclist = d, dl

View File

@@ -0,0 +1,56 @@
[
{
"creation": "2013-02-22 01:27:50",
"docstatus": 0,
"modified": "2013-12-20 19:23:27",
"modified_by": "Administrator",
"owner": "Administrator"
},
{
"doctype": "DocType",
"istable": 1,
"module": "Projects",
"name": "__common__"
},
{
"doctype": "DocField",
"in_list_view": 1,
"name": "__common__",
"parent": "Project Milestone",
"parentfield": "fields",
"parenttype": "DocType",
"permlevel": 0
},
{
"doctype": "DocType",
"name": "Project Milestone"
},
{
"doctype": "DocField",
"fieldname": "milestone_date",
"fieldtype": "Date",
"label": "Milestone Date",
"oldfieldname": "milestone_date",
"oldfieldtype": "Date"
},
{
"doctype": "DocField",
"fieldname": "milestone",
"fieldtype": "Text",
"label": "Milestone",
"oldfieldname": "milestone",
"oldfieldtype": "Text",
"print_width": "300px",
"width": "300px"
},
{
"doctype": "DocField",
"fieldname": "status",
"fieldtype": "Select",
"label": "Status",
"no_copy": 1,
"oldfieldname": "status",
"oldfieldtype": "Select",
"options": "Pending\nCompleted"
}
]

View File

@@ -0,0 +1 @@
Task to be completed for a Project (optional).

View File

@@ -0,0 +1 @@
from __future__ import unicode_literals

View File

@@ -0,0 +1,32 @@
// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
wn.provide("erpnext.projects");
cur_frm.add_fetch("project", "company", "company");
erpnext.projects.Task = wn.ui.form.Controller.extend({
setup: function() {
this.frm.fields_dict.project.get_query = function() {
return {
query: "projects.doctype.task.task.get_project"
}
};
},
project: function() {
if(this.frm.doc.project) {
return get_server_fields('get_project_details', '','', this.frm.doc, this.frm.doc.doctype,
this.frm.doc.name, 1);
}
},
validate: function() {
this.frm.doc.project && wn.model.remove_from_locals("Project",
this.frm.doc.project);
},
});
cur_frm.cscript = new erpnext.projects.Task({frm: cur_frm});

View File

@@ -0,0 +1,90 @@
# 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 webnotes, json
from webnotes.utils import getdate, today
from webnotes.model import db_exists
from webnotes.model.bean import copy_doclist
from webnotes import msgprint
class DocType:
def __init__(self,doc,doclist=[]):
self.doc = doc
self.doclist = doclist
def get_project_details(self):
cust = webnotes.conn.sql("select customer, customer_name from `tabProject` where name = %s", self.doc.project)
if cust:
ret = {'customer': cust and cust[0][0] or '', 'customer_name': cust and cust[0][1] or ''}
return ret
def get_customer_details(self):
cust = webnotes.conn.sql("select customer_name from `tabCustomer` where name=%s", self.doc.customer)
if cust:
ret = {'customer_name': cust and cust[0][0] or ''}
return ret
def validate(self):
if self.doc.exp_start_date and self.doc.exp_end_date and getdate(self.doc.exp_start_date) > getdate(self.doc.exp_end_date):
msgprint("'Expected Start Date' can not be greater than 'Expected End Date'")
raise Exception
if self.doc.act_start_date and self.doc.act_end_date and getdate(self.doc.act_start_date) > getdate(self.doc.act_end_date):
msgprint("'Actual Start Date' can not be greater than 'Actual End Date'")
raise Exception
self.update_status()
def update_status(self):
status = webnotes.conn.get_value("Task", self.doc.name, "status")
if self.doc.status=="Working" and status !="Working" and not self.doc.act_start_date:
self.doc.act_start_date = today()
if self.doc.status=="Closed" and status != "Closed" and not self.doc.act_end_date:
self.doc.act_end_date = today()
def on_update(self):
"""update percent complete in project"""
if self.doc.project:
project = webnotes.bean("Project", self.doc.project)
project.run_method("update_percent_complete")
@webnotes.whitelist()
def get_events(start, end, filters=None):
from webnotes.widgets.reportview import build_match_conditions
if not webnotes.has_permission("Task"):
webnotes.msgprint(_("No Permission"), raise_exception=1)
conditions = build_match_conditions("Task")
conditions and (" and " + conditions) or ""
if filters:
filters = json.loads(filters)
for key in filters:
if filters[key]:
conditions += " and " + key + ' = "' + filters[key].replace('"', '\"') + '"'
data = webnotes.conn.sql("""select name, exp_start_date, exp_end_date,
subject, status, project from `tabTask`
where ((exp_start_date between '%(start)s' and '%(end)s') \
or (exp_end_date between '%(start)s' and '%(end)s'))
%(conditions)s""" % {
"start": start,
"end": end,
"conditions": conditions
}, as_dict=True, update={"allDay": 0})
return data
def get_project(doctype, txt, searchfield, start, page_len, filters):
from erpnext.controllers.queries import get_match_cond
return webnotes.conn.sql(""" select name from `tabProject`
where %(key)s like "%(txt)s"
%(mcond)s
order by name
limit %(start)s, %(page_len)s """ % {'key': searchfield,
'txt': "%%%s%%" % txt, 'mcond':get_match_cond(doctype, searchfield),
'start': start, 'page_len': page_len})

View File

@@ -0,0 +1,259 @@
[
{
"creation": "2013-01-29 19:25:50",
"docstatus": 0,
"modified": "2013-12-20 19:24:38",
"modified_by": "Administrator",
"owner": "Administrator"
},
{
"allow_attach": 1,
"allow_import": 1,
"autoname": "TASK.#####",
"doctype": "DocType",
"document_type": "Master",
"icon": "icon-check",
"max_attachments": 5,
"module": "Projects",
"name": "__common__"
},
{
"doctype": "DocField",
"name": "__common__",
"parent": "Task",
"parentfield": "fields",
"parenttype": "DocType",
"permlevel": 0
},
{
"cancel": 1,
"create": 1,
"doctype": "DocPerm",
"email": 1,
"name": "__common__",
"parent": "Task",
"parentfield": "permissions",
"parenttype": "DocType",
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Projects User",
"submit": 0,
"write": 1
},
{
"doctype": "DocType",
"name": "Task"
},
{
"doctype": "DocField",
"fieldname": "task_details",
"fieldtype": "Section Break",
"label": "Task Details",
"oldfieldtype": "Section Break",
"print_width": "50%",
"search_index": 0,
"width": "50%"
},
{
"doctype": "DocField",
"fieldname": "subject",
"fieldtype": "Data",
"in_filter": 1,
"in_list_view": 1,
"label": "Subject",
"oldfieldname": "subject",
"oldfieldtype": "Data",
"reqd": 1
},
{
"doctype": "DocField",
"fieldname": "exp_start_date",
"fieldtype": "Date",
"label": "Expected Start Date",
"oldfieldname": "exp_start_date",
"oldfieldtype": "Date",
"reqd": 0
},
{
"doctype": "DocField",
"fieldname": "exp_end_date",
"fieldtype": "Date",
"in_filter": 1,
"label": "Expected End Date",
"oldfieldname": "exp_end_date",
"oldfieldtype": "Date",
"reqd": 0,
"search_index": 1
},
{
"doctype": "DocField",
"fieldname": "column_break0",
"fieldtype": "Column Break",
"oldfieldtype": "Column Break",
"print_width": "50%",
"width": "50%"
},
{
"doctype": "DocField",
"fieldname": "project",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Project",
"oldfieldname": "project",
"oldfieldtype": "Link",
"options": "Project"
},
{
"doctype": "DocField",
"fieldname": "status",
"fieldtype": "Select",
"in_list_view": 1,
"label": "Status",
"no_copy": 1,
"oldfieldname": "status",
"oldfieldtype": "Select",
"options": "Open\nWorking\nPending Review\nClosed\nCancelled"
},
{
"doctype": "DocField",
"fieldname": "priority",
"fieldtype": "Select",
"in_filter": 1,
"in_list_view": 1,
"label": "Priority",
"oldfieldname": "priority",
"oldfieldtype": "Select",
"options": "Low\nMedium\nHigh\nUrgent",
"reqd": 0,
"search_index": 1
},
{
"doctype": "DocField",
"fieldname": "section_break0",
"fieldtype": "Section Break",
"oldfieldtype": "Section Break",
"options": "Simple"
},
{
"doctype": "DocField",
"fieldname": "description",
"fieldtype": "Text Editor",
"label": "Details",
"oldfieldname": "description",
"oldfieldtype": "Text Editor",
"print_width": "300px",
"reqd": 0,
"width": "300px"
},
{
"doctype": "DocField",
"fieldname": "time_and_budget",
"fieldtype": "Section Break",
"label": "Time and Budget",
"oldfieldtype": "Section Break"
},
{
"doctype": "DocField",
"fieldname": "expected",
"fieldtype": "Column Break",
"label": "Expected",
"oldfieldtype": "Column Break",
"print_width": "50%",
"width": "50%"
},
{
"doctype": "DocField",
"fieldname": "exp_total_hrs",
"fieldtype": "Data",
"label": "Total Hours (Expected)",
"oldfieldname": "exp_total_hrs",
"oldfieldtype": "Data",
"reqd": 0
},
{
"doctype": "DocField",
"fieldname": "allocated_budget",
"fieldtype": "Currency",
"label": "Allocated Budget",
"oldfieldname": "allocated_budget",
"oldfieldtype": "Currency",
"options": "Company:company:default_currency"
},
{
"doctype": "DocField",
"fieldname": "actual",
"fieldtype": "Column Break",
"label": "Actual",
"oldfieldtype": "Column Break",
"print_width": "50%",
"width": "50%"
},
{
"doctype": "DocField",
"fieldname": "act_start_date",
"fieldtype": "Date",
"label": "Actual Start Date",
"oldfieldname": "act_start_date",
"oldfieldtype": "Date"
},
{
"doctype": "DocField",
"fieldname": "act_end_date",
"fieldtype": "Date",
"label": "Actual End Date",
"oldfieldname": "act_end_date",
"oldfieldtype": "Date"
},
{
"doctype": "DocField",
"fieldname": "actual_budget",
"fieldtype": "Currency",
"label": "Actual Budget",
"oldfieldname": "actual_budget",
"oldfieldtype": "Currency",
"options": "Company:company:default_currency"
},
{
"doctype": "DocField",
"fieldname": "more_details",
"fieldtype": "Section Break",
"label": "More Details"
},
{
"depends_on": "eval:doc.status == \"Closed\" || doc.status == \"Pending Review\"",
"doctype": "DocField",
"fieldname": "review_date",
"fieldtype": "Date",
"hidden": 0,
"label": "Review Date",
"oldfieldname": "review_date",
"oldfieldtype": "Date"
},
{
"depends_on": "eval:doc.status == \"Closed\"",
"doctype": "DocField",
"fieldname": "closing_date",
"fieldtype": "Date",
"hidden": 0,
"label": "Closing Date",
"oldfieldname": "closing_date",
"oldfieldtype": "Date"
},
{
"doctype": "DocField",
"fieldname": "column_break_22",
"fieldtype": "Column Break"
},
{
"doctype": "DocField",
"fieldname": "company",
"fieldtype": "Link",
"label": "Company",
"options": "Company"
},
{
"doctype": "DocPerm"
}
]

View File

@@ -0,0 +1,22 @@
// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
wn.views.calendar["Task"] = {
field_map: {
"start": "exp_start_date",
"end": "exp_end_date",
"id": "name",
"title": wn._("subject"),
"allDay": "allDay"
},
gantt: true,
filters: [
{
"fieldtype": "Link",
"fieldname": "project",
"options": "Project",
"label": wn._("Project")
}
],
get_events_method: "erpnext.projects.doctype.task.task.get_events"
}

View File

@@ -0,0 +1,10 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
test_records = [
[{"subject": "_Test Task", "project":"_Test Project", "status":"Open"}],
[{"subject": "_Test Task 1", "status":"Open"}],
[{"subject": "_Test Task 2", "status":"Open"}]
]
test_ignore = ["Customer"]

View File

@@ -0,0 +1 @@
Log of activity done by a user in a particular period.

View File

@@ -0,0 +1,23 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
import webnotes
import unittest
from erpnext.projects.doctype.time_log.time_log import OverlapError
class TestTimeLog(unittest.TestCase):
def test_duplication(self):
ts = webnotes.bean(webnotes.copy_doclist(test_records[0]))
self.assertRaises(OverlapError, ts.insert)
test_records = [[{
"doctype": "Time Log",
"from_time": "2013-01-01 10:00:00",
"to_time": "2013-01-01 11:00:00",
"activity_type": "_Test Activity Type",
"note": "_Test Note",
"docstatus": 1
}]]
test_ignore = ["Sales Invoice", "Time Log Batch"]

View File

@@ -0,0 +1,14 @@
// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
wn.provide("erpnext.projects");
erpnext.projects.TimeLog = wn.ui.form.Controller.extend({
onload: function() {
this.frm.set_query("task", erpnext.queries.task);
}
});
cur_frm.cscript = new erpnext.projects.TimeLog({frm: cur_frm});
cur_frm.add_fetch('task','project','project');

View File

@@ -0,0 +1,86 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
# For license information, please see license.txt
from __future__ import unicode_literals
import webnotes
from webnotes import _
from webnotes.utils import cstr
class OverlapError(webnotes.ValidationError): pass
class DocType:
def __init__(self, d, dl):
self.doc, self.doclist = d, dl
def validate(self):
self.set_status()
self.validate_overlap()
self.calculate_total_hours()
def calculate_total_hours(self):
from webnotes.utils import time_diff_in_hours
self.doc.hours = time_diff_in_hours(self.doc.to_time, self.doc.from_time)
def set_status(self):
self.doc.status = {
0: "Draft",
1: "Submitted",
2: "Cancelled"
}[self.doc.docstatus or 0]
if self.doc.time_log_batch:
self.doc.status="Batched for Billing"
if self.doc.sales_invoice:
self.doc.status="Billed"
def validate_overlap(self):
existing = webnotes.conn.sql_list("""select name from `tabTime Log` where owner=%s and
(
(from_time between %s and %s) or
(to_time between %s and %s) or
(%s between from_time and to_time))
and name!=%s
and ifnull(task, "")=%s
and docstatus < 2""",
(self.doc.owner, self.doc.from_time, self.doc.to_time, self.doc.from_time,
self.doc.to_time, self.doc.from_time, self.doc.name or "No Name",
cstr(self.doc.task)))
if existing:
webnotes.msgprint(_("This Time Log conflicts with") + ":" + ', '.join(existing),
raise_exception=OverlapError)
def before_cancel(self):
self.set_status()
def before_update_after_submit(self):
self.set_status()
@webnotes.whitelist()
def get_events(start, end):
from webnotes.widgets.reportview import build_match_conditions
if not webnotes.has_permission("Time Log"):
webnotes.msgprint(_("No Permission"), raise_exception=1)
match = build_match_conditions("Time Log")
data = webnotes.conn.sql("""select name, from_time, to_time,
activity_type, task, project from `tabTime Log`
where from_time between '%(start)s' and '%(end)s' or to_time between '%(start)s' and '%(end)s'
%(match)s""" % {
"start": start,
"end": end,
"match": match and (" and " + match) or ""
}, as_dict=True, update={"allDay": 0})
for d in data:
d.title = d.name + ": " + (d.activity_type or "[Activity Type not set]")
if d.task:
d.title += " for Task: " + d.task
if d.project:
d.title += " for Project: " + d.project
return data

View File

@@ -0,0 +1,214 @@
[
{
"creation": "2013-04-03 16:38:41",
"docstatus": 0,
"modified": "2013-12-20 19:24:39",
"modified_by": "Administrator",
"owner": "Administrator"
},
{
"allow_attach": 1,
"allow_import": 1,
"autoname": "naming_series:",
"description": "Log of Activities performed by users against Tasks that can be used for tracking time, billing.",
"doctype": "DocType",
"document_type": "Master",
"icon": "icon-time",
"is_submittable": 1,
"module": "Projects",
"name": "__common__"
},
{
"doctype": "DocField",
"name": "__common__",
"parent": "Time Log",
"parentfield": "fields",
"parenttype": "DocType"
},
{
"amend": 1,
"cancel": 1,
"doctype": "DocPerm",
"email": 1,
"name": "__common__",
"parent": "Time Log",
"parentfield": "permissions",
"parenttype": "DocType",
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"submit": 1,
"write": 1
},
{
"doctype": "DocType",
"name": "Time Log"
},
{
"doctype": "DocField",
"fieldname": "naming_series",
"fieldtype": "Select",
"label": "Series",
"options": "TL-",
"permlevel": 0,
"read_only": 0,
"reqd": 1
},
{
"doctype": "DocField",
"fieldname": "from_time",
"fieldtype": "Datetime",
"in_list_view": 1,
"label": "From Time",
"permlevel": 0,
"read_only": 0,
"reqd": 1
},
{
"doctype": "DocField",
"fieldname": "to_time",
"fieldtype": "Datetime",
"in_list_view": 0,
"label": "To Time",
"permlevel": 0,
"read_only": 0,
"reqd": 1
},
{
"doctype": "DocField",
"fieldname": "hours",
"fieldtype": "Float",
"label": "Hours",
"permlevel": 0,
"read_only": 1
},
{
"doctype": "DocField",
"fieldname": "column_break_3",
"fieldtype": "Column Break",
"permlevel": 0,
"read_only": 0
},
{
"doctype": "DocField",
"fieldname": "status",
"fieldtype": "Select",
"in_list_view": 1,
"label": "Status",
"options": "Draft\nSubmitted\nBatched for Billing\nBilled\nCancelled",
"permlevel": 0,
"read_only": 1,
"reqd": 0
},
{
"doctype": "DocField",
"fieldname": "activity_type",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Activity Type",
"options": "Activity Type",
"permlevel": 0,
"read_only": 0,
"reqd": 1
},
{
"doctype": "DocField",
"fieldname": "task",
"fieldtype": "Link",
"label": "Task",
"options": "Task",
"permlevel": 0,
"read_only": 0
},
{
"doctype": "DocField",
"fieldname": "billable",
"fieldtype": "Check",
"in_list_view": 1,
"label": "Billable",
"permlevel": 0,
"read_only": 0
},
{
"doctype": "DocField",
"fieldname": "section_break_7",
"fieldtype": "Section Break",
"permlevel": 0,
"read_only": 0
},
{
"doctype": "DocField",
"fieldname": "note",
"fieldtype": "Text Editor",
"label": "Note",
"permlevel": 0,
"read_only": 0
},
{
"doctype": "DocField",
"fieldname": "section_break_9",
"fieldtype": "Section Break",
"permlevel": 0,
"read_only": 0
},
{
"doctype": "DocField",
"fieldname": "project",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Project",
"options": "Project",
"permlevel": 0,
"read_only": 0
},
{
"description": "Will be updated when batched.",
"doctype": "DocField",
"fieldname": "time_log_batch",
"fieldtype": "Link",
"label": "Time Log Batch",
"options": "Time Log Batch",
"permlevel": 0,
"read_only": 1
},
{
"description": "Will be updated when billed.",
"doctype": "DocField",
"fieldname": "sales_invoice",
"fieldtype": "Link",
"label": "Sales Invoice",
"options": "Sales Invoice",
"permlevel": 0,
"read_only": 1
},
{
"doctype": "DocField",
"fieldname": "column_break_16",
"fieldtype": "Column Break",
"permlevel": 0,
"read_only": 0
},
{
"doctype": "DocField",
"fieldname": "amended_from",
"fieldtype": "Link",
"ignore_restrictions": 1,
"label": "Amended From",
"no_copy": 1,
"options": "Time Log",
"permlevel": 1,
"print_hide": 1,
"read_only": 0
},
{
"create": 1,
"doctype": "DocPerm",
"match": "owner",
"role": "Projects User"
},
{
"doctype": "DocPerm",
"role": "Projects Manager"
}
]

View File

@@ -0,0 +1,13 @@
// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
wn.views.calendar["Time Log"] = {
field_map: {
"start": "from_time",
"end": "to_time",
"id": "name",
"title": "title",
"allDay": "allDay"
},
get_events_method: "erpnext.projects.doctype.time_log.time_log.get_events"
}

View File

@@ -0,0 +1,48 @@
// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
// render
wn.listview_settings['Time Log'] = {
add_fields: ["`tabTime Log`.`status`", "`tabTime Log`.`billable`", "`tabTime Log`.`activity_type`"],
selectable: true,
onload: function(me) {
me.appframe.add_button(wn._("Make Time Log Batch"), function() {
var selected = me.get_checked_items() || [];
if(!selected.length) {
msgprint(wn._("Please select Time Logs."))
}
// select only billable time logs
for(var i in selected) {
var d = selected[i];
if(!d.billable) {
msgprint(wn._("Time Log is not billable") + ": " + d.name);
return;
}
if(d.status!="Submitted") {
msgprint(wn._("Time Log Status must be Submitted."));
}
}
// make batch
wn.model.with_doctype("Time Log Batch", function() {
var tlb = wn.model.get_new_doc("Time Log Batch");
$.each(selected, function(i, d) {
var detail = wn.model.get_new_doc("Time Log Batch Detail");
$.extend(detail, {
"parenttype": "Time Log Batch",
"parentfield": "time_log_batch_details",
"parent": tlb.name,
"time_log": d.name,
"activity_type": d.activity_type,
"created_by": d.owner,
"idx": i+1
});
})
wn.set_route("Form", "Time Log Batch", tlb.name);
})
}, "icon-file-alt");
}
};

View File

@@ -0,0 +1 @@
Group of Time Logs that can be batched for billing.

View File

@@ -0,0 +1,39 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
import webnotes, unittest
class TimeLogBatchTest(unittest.TestCase):
def test_time_log_status(self):
from erpnext.projects.doctype.time_log.test_time_log import test_records as time_log_records
time_log = webnotes.bean(copy=time_log_records[0])
time_log.doc.fields.update({
"from_time": "2013-01-02 10:00:00",
"to_time": "2013-01-02 11:00:00",
"docstatus": 0
})
time_log.insert()
time_log.submit()
self.assertEquals(webnotes.conn.get_value("Time Log", time_log.doc.name, "status"), "Submitted")
tlb = webnotes.bean(copy=test_records[0])
tlb.doclist[1].time_log = time_log.doc.name
tlb.insert()
tlb.submit()
self.assertEquals(webnotes.conn.get_value("Time Log", time_log.doc.name, "status"), "Batched for Billing")
tlb.cancel()
self.assertEquals(webnotes.conn.get_value("Time Log", time_log.doc.name, "status"), "Submitted")
test_records = [[
{
"doctype": "Time Log Batch",
"rate": "500"
},
{
"doctype": "Time Log Batch Detail",
"parenttype": "Time Log Batch",
"parentfield": "time_log_batch_details",
"time_log": "_T-Time Log-00001",
}
]]

View File

@@ -0,0 +1,39 @@
// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
cur_frm.add_fetch("time_log", "activity_type", "activity_type");
cur_frm.add_fetch("time_log", "owner", "created_by");
cur_frm.add_fetch("time_log", "hours", "hours");
cur_frm.set_query("time_log", "time_log_batch_details", function(doc) {
return {
query: "projects.utils.get_time_log_list",
filters: {
"billable": 1,
"status": "Submitted"
}
}
});
$.extend(cur_frm.cscript, {
refresh: function(doc) {
cur_frm.set_intro({
"Draft": wn._("Select Time Logs and Submit to create a new Sales Invoice."),
"Submitted": wn._("Click on 'Make Sales Invoice' button to create a new Sales Invoice."),
"Billed": wn._("This Time Log Batch has been billed."),
"Cancelled": wn._("This Time Log Batch has been cancelled.")
}[doc.status]);
if(doc.status=="Submitted") {
cur_frm.add_custom_button(wn._("Make Sales Invoice"), function() { cur_frm.cscript.make_invoice() },
"icon-file-alt");
}
},
make_invoice: function() {
var doc = cur_frm.doc;
wn.model.map({
source: wn.model.get_doclist(doc.doctype, doc.name),
target: "Sales Invoice"
});
}
});

View File

@@ -0,0 +1,63 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
# For license information, please see license.txt
from __future__ import unicode_literals
import webnotes
from webnotes import _
class DocType:
def __init__(self, d, dl):
self.doc, self.doclist = d, dl
def validate(self):
self.set_status()
self.doc.total_hours = 0.0
for d in self.doclist.get({"doctype":"Time Log Batch Detail"}):
tl = webnotes.doc("Time Log", d.time_log)
self.update_time_log_values(d, tl)
self.validate_time_log_is_submitted(tl)
self.doc.total_hours += float(tl.hours or 0.0)
def update_time_log_values(self, d, tl):
d.fields.update({
"hours": tl.hours,
"activity_type": tl.activity_type,
"created_by": tl.owner
})
def validate_time_log_is_submitted(self, tl):
if tl.status != "Submitted":
webnotes.msgprint(_("Time Log must have status 'Submitted'") + \
" :" + tl.name + " (" + _(tl.status) + ")", raise_exception=True)
def set_status(self):
self.doc.status = {
"0": "Draft",
"1": "Submitted",
"2": "Cancelled"
}[str(self.doc.docstatus or 0)]
if self.doc.sales_invoice:
self.doc.status = "Billed"
def on_submit(self):
self.update_status(self.doc.name)
def before_cancel(self):
self.update_status(None)
def before_update_after_submit(self):
self.update_status(self.doc.name)
def update_status(self, time_log_batch):
self.set_status()
for d in self.doclist.get({"doctype":"Time Log Batch Detail"}):
tl = webnotes.bean("Time Log", d.time_log)
tl.doc.time_log_batch = time_log_batch
tl.doc.sales_invoice = self.doc.sales_invoice
tl.update_after_submit()

View File

@@ -0,0 +1,125 @@
[
{
"creation": "2013-02-28 17:57:33",
"docstatus": 0,
"modified": "2013-12-20 19:24:39",
"modified_by": "Administrator",
"owner": "Administrator"
},
{
"autoname": "naming_series:",
"description": "Batch Time Logs for Billing.",
"doctype": "DocType",
"document_type": "Transaction",
"icon": "icon-time",
"is_submittable": 1,
"module": "Projects",
"name": "__common__"
},
{
"doctype": "DocField",
"name": "__common__",
"parent": "Time Log Batch",
"parentfield": "fields",
"parenttype": "DocType",
"permlevel": 0
},
{
"amend": 1,
"cancel": 1,
"create": 1,
"doctype": "DocPerm",
"email": 1,
"name": "__common__",
"parent": "Time Log Batch",
"parentfield": "permissions",
"parenttype": "DocType",
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Projects User",
"submit": 1,
"write": 1
},
{
"doctype": "DocType",
"name": "Time Log Batch"
},
{
"doctype": "DocField",
"fieldname": "naming_series",
"fieldtype": "Select",
"label": "Series",
"options": "TLB-",
"reqd": 1
},
{
"description": "For Sales Invoice",
"doctype": "DocField",
"fieldname": "rate",
"fieldtype": "Currency",
"label": "Rate"
},
{
"doctype": "DocField",
"fieldname": "column_break_3",
"fieldtype": "Column Break"
},
{
"default": "Draft",
"doctype": "DocField",
"fieldname": "status",
"fieldtype": "Select",
"in_list_view": 1,
"label": "Status",
"options": "Draft\nSubmitted\nBilled\nCancelled",
"read_only": 1
},
{
"description": "Will be updated after Sales Invoice is Submitted.",
"doctype": "DocField",
"fieldname": "sales_invoice",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Sales Invoice",
"options": "Sales Invoice",
"read_only": 1
},
{
"doctype": "DocField",
"fieldname": "section_break_5",
"fieldtype": "Section Break"
},
{
"doctype": "DocField",
"fieldname": "time_log_batch_details",
"fieldtype": "Table",
"label": "Time Log Batch Details",
"options": "Time Log Batch Detail",
"reqd": 1
},
{
"description": "In Hours",
"doctype": "DocField",
"fieldname": "total_hours",
"fieldtype": "Float",
"in_list_view": 1,
"label": "Total Hours",
"read_only": 1
},
{
"doctype": "DocField",
"fieldname": "amended_from",
"fieldtype": "Link",
"ignore_restrictions": 1,
"label": "Amended From",
"no_copy": 1,
"options": "Time Log Batch",
"print_hide": 1,
"read_only": 1
},
{
"doctype": "DocPerm"
}
]

View File

@@ -0,0 +1 @@
Time Log detail for parent Time Log Batch.

View File

@@ -0,0 +1,11 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
# For license information, please see license.txt
from __future__ import unicode_literals
import webnotes
class DocType:
def __init__(self, d, dl):
self.doc, self.doclist = d, dl

View File

@@ -0,0 +1,59 @@
[
{
"creation": "2013-03-05 09:11:06",
"docstatus": 0,
"modified": "2013-12-20 19:21:53",
"modified_by": "Administrator",
"owner": "Administrator"
},
{
"doctype": "DocType",
"istable": 1,
"module": "Projects",
"name": "__common__"
},
{
"doctype": "DocField",
"in_list_view": 1,
"name": "__common__",
"parent": "Time Log Batch Detail",
"parentfield": "fields",
"parenttype": "DocType",
"permlevel": 0
},
{
"doctype": "DocType",
"name": "Time Log Batch Detail"
},
{
"doctype": "DocField",
"fieldname": "time_log",
"fieldtype": "Link",
"label": "Time Log",
"options": "Time Log",
"print_width": "200px",
"reqd": 1,
"width": "200px"
},
{
"doctype": "DocField",
"fieldname": "created_by",
"fieldtype": "Link",
"label": "Created By",
"options": "Profile",
"read_only": 1
},
{
"doctype": "DocField",
"fieldname": "activity_type",
"fieldtype": "Data",
"label": "Activity Type",
"read_only": 1
},
{
"doctype": "DocField",
"fieldname": "hours",
"fieldtype": "Float",
"label": "Hours"
}
]

View File

@@ -0,0 +1 @@
from __future__ import unicode_literals

View File

@@ -0,0 +1 @@
from __future__ import unicode_literals

View File

@@ -0,0 +1,80 @@
// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt"
wn.module_page["Projects"] = [
{
title: wn._("Top"),
icon: "icon-copy",
top: true,
items: [
{
label: wn._("Task"),
description: wn._("Project activity / task."),
doctype:"Task"
},
{
label: wn._("Project"),
description: wn._("Project master."),
doctype:"Project"
},
{
label: wn._("Time Log"),
description: wn._("Time Log for tasks."),
doctype:"Time Log"
},
]
},
{
title: wn._("Documents"),
icon: "icon-copy",
items: [
{
label: wn._("Time Log Batch"),
description: wn._("Batch Time Logs for billing."),
doctype:"Time Log Batch"
},
]
},
{
title: wn._("Tools"),
icon: "icon-wrench",
items: [
{
route: "Gantt/Task",
label: wn._("Gantt Chart"),
"description":wn._("Gantt chart of all tasks.")
},
]
},
{
title: wn._("Masters"),
icon: "icon-book",
items: [
{
label: wn._("Activity Type"),
description: wn._("Types of activities for Time Sheets"),
doctype:"Activity Type"
},
]
},
{
title: wn._("Reports"),
right: true,
icon: "icon-list",
items: [
{
"label":wn._("Daily Time Log Summary"),
route: "query-report/Daily Time Log Summary",
doctype: "Time Log"
},
{
"label":wn._("Project wise Stock Tracking"),
route: "query-report/Project wise Stock Tracking",
doctype: "Project"
},
]
}]
pscript['onload_projects-home'] = function(wrapper) {
wn.views.moduleview.make(wrapper, "Projects");
}

View File

@@ -0,0 +1,22 @@
[
{
"creation": "2012-02-21 13:24:22",
"docstatus": 0,
"modified": "2013-07-11 14:43:49",
"modified_by": "Administrator",
"owner": "Administrator"
},
{
"doctype": "Page",
"icon": "icon-th",
"module": "Projects",
"name": "__common__",
"page_name": "projects-home",
"standard": "Yes",
"title": "Projects Home"
},
{
"doctype": "Page",
"name": "projects-home"
}
]

View File

View File

@@ -0,0 +1,19 @@
// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
wn.query_reports["Daily Time Log Summary"] = {
"filters": [
{
"fieldname":"from_date",
"label": wn._("From Date"),
"fieldtype": "Date",
"default": wn.datetime.get_today()
},
{
"fieldname":"to_date",
"label": wn._("To Date"),
"fieldtype": "Date",
"default": wn.datetime.get_today()
},
]
}

View File

@@ -0,0 +1,81 @@
# 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 webnotes
from webnotes.utils import flt
def execute(filters=None):
if not filters:
filters = {}
elif filters.get("to_date"):
filters["to_date"] = filters.get("to_date") + "24:00:00"
columns = ["Time Log:Link/Time Log:120", "Employee::150", "From Datetime::140",
"To Datetime::140", "Hours::70", "Activity Type::120", "Task:Link/Task:150",
"Task Subject::180", "Project:Link/Project:120", "Status::70"]
profile_map = get_profile_map()
task_map = get_task_map()
conditions = build_conditions(filters)
time_logs = webnotes.conn.sql("""select * from `tabTime Log`
where docstatus < 2 %s order by owner asc""" % (conditions, ), filters, as_dict=1)
if time_logs:
profiles = [time_logs[0].owner]
data = []
total_hours = total_employee_hours = count = 0
for tl in time_logs:
if tl.owner not in profiles:
profiles.append(tl.owner)
data.append(["", "", "", "Total", total_employee_hours, "", "", "", "", ""])
total_employee_hours = 0
data.append([tl.name, profile_map[tl.owner], tl.from_time, tl.to_time, tl.hours,
tl.activity_type, tl.task, task_map.get(tl.task), tl.project, tl.status])
count += 1
total_hours += flt(tl.hours)
total_employee_hours += flt(tl.hours)
if count == len(time_logs):
data.append(["", "", "", "Total Hours", total_employee_hours, "", "", "", "", ""])
if total_hours:
data.append(["", "", "", "Grand Total", total_hours, "", "", "", "", ""])
return columns, data
def get_profile_map():
profiles = webnotes.conn.sql("""select name,
concat(first_name, if(last_name, (' ' + last_name), '')) as fullname
from tabProfile""", as_dict=1)
profile_map = {}
for p in profiles:
profile_map.setdefault(p.name, []).append(p.fullname)
return profile_map
def get_task_map():
tasks = webnotes.conn.sql("""select name, subject from tabTask""", as_dict=1)
task_map = {}
for t in tasks:
task_map.setdefault(t.name, []).append(t.subject)
return task_map
def build_conditions(filters):
conditions = ""
if filters.get("from_date"):
conditions += " and from_time >= %(from_date)s"
if filters.get("to_date"):
conditions += " and to_time <= %(to_date)s"
from webnotes.widgets.reportview import build_match_conditions
match_conditions = build_match_conditions("Time Log")
if match_conditions:
conditions += " and %s" % match_conditions
return conditions

View File

@@ -0,0 +1,21 @@
[
{
"creation": "2013-04-03 11:27:52",
"docstatus": 0,
"modified": "2013-04-03 11:48:07",
"modified_by": "Administrator",
"owner": "Administrator"
},
{
"doctype": "Report",
"is_standard": "Yes",
"name": "__common__",
"ref_doctype": "Time Log",
"report_name": "Daily Time Log Summary",
"report_type": "Script Report"
},
{
"doctype": "Report",
"name": "Daily Time Log Summary"
}
]

View File

@@ -0,0 +1,77 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
import webnotes
def execute(filters=None):
columns = get_columns()
proj_details = get_project_details()
pr_item_map = get_purchased_items_cost()
se_item_map = get_issued_items_cost()
dn_item_map = get_delivered_items_cost()
data = []
for project in proj_details:
data.append([project.name, pr_item_map.get(project.name, 0),
se_item_map.get(project.name, 0), dn_item_map.get(project.name, 0),
project.project_name, project.status, project.company,
project.customer, project.project_value, project.project_start_date,
project.completion_date])
return columns, data
def get_columns():
return ["Project Id:Link/Project:140", "Cost of Purchased Items:Currency:160",
"Cost of Issued Items:Currency:160", "Cost of Delivered Items:Currency:160",
"Project Name::120", "Project Status::120", "Company:Link/Company:100",
"Customer:Link/Customer:140", "Project Value:Currency:120",
"Project Start Date:Date:120", "Completion Date:Date:120"]
def get_project_details():
return webnotes.conn.sql(""" select name, project_name, status, company, customer, project_value,
project_start_date, completion_date from tabProject where docstatus < 2""", as_dict=1)
def get_purchased_items_cost():
pr_items = webnotes.conn.sql("""select project_name, sum(amount) as amount
from `tabPurchase Receipt Item` where ifnull(project_name, '') != ''
and docstatus = 1 group by project_name""", as_dict=1)
pr_item_map = {}
for item in pr_items:
pr_item_map.setdefault(item.project_name, item.amount)
return pr_item_map
def get_issued_items_cost():
se_items = webnotes.conn.sql("""select se.project_name, sum(se_item.amount) as amount
from `tabStock Entry` se, `tabStock Entry Detail` se_item
where se.name = se_item.parent and se.docstatus = 1 and ifnull(se_item.t_warehouse, '') = ''
and ifnull(se.project_name, '') != '' group by se.project_name""", as_dict=1)
se_item_map = {}
for item in se_items:
se_item_map.setdefault(item.project_name, item.amount)
return se_item_map
def get_delivered_items_cost():
dn_items = webnotes.conn.sql("""select dn.project_name, sum(dn_item.amount) as amount
from `tabDelivery Note` dn, `tabDelivery Note Item` dn_item
where dn.name = dn_item.parent and dn.docstatus = 1 and ifnull(dn.project_name, '') != ''
group by dn.project_name""", as_dict=1)
si_items = webnotes.conn.sql("""select si.project_name, sum(si_item.amount) as amount
from `tabSales Invoice` si, `tabSales Invoice Item` si_item
where si.name = si_item.parent and si.docstatus = 1 and ifnull(si.update_stock, 0) = 1
and ifnull(si.is_pos, 0) = 1 and ifnull(si.project_name, '') != ''
group by si.project_name""", as_dict=1)
dn_item_map = {}
for item in dn_items:
dn_item_map.setdefault(item.project_name, item.amount)
for item in si_items:
dn_item_map.setdefault(item.project_name, item.amount)
return dn_item_map

View File

@@ -0,0 +1,21 @@
[
{
"creation": "2013-06-03 17:37:41",
"docstatus": 0,
"modified": "2013-06-03 17:37:41",
"modified_by": "Administrator",
"owner": "Administrator"
},
{
"doctype": "Report",
"is_standard": "Yes",
"name": "__common__",
"ref_doctype": "Project",
"report_name": "Project wise Stock Tracking ",
"report_type": "Report Builder"
},
{
"doctype": "Report",
"name": "Project wise Stock Tracking"
}
]

32
erpnext/projects/utils.py Normal file
View File

@@ -0,0 +1,32 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
# For license information, please see license.txt
from __future__ import unicode_literals
import webnotes
@webnotes.whitelist()
def get_time_log_list(doctype, txt, searchfield, start, page_len, filters):
return webnotes.conn.get_values("Time Log", filters, ["name", "activity_type", "owner"])
@webnotes.whitelist()
def query_task(doctype, txt, searchfield, start, page_len, filters):
from webnotes.widgets.reportview import build_match_conditions
search_string = "%%%s%%" % txt
order_by_string = "%s%%" % txt
match_conditions = build_match_conditions("Task")
match_conditions = ("and" + match_conditions) if match_conditions else ""
return webnotes.conn.sql("""select name, subject from `tabTask`
where (`%s` like %s or `subject` like %s) %s
order by
case when `subject` like %s then 0 else 1 end,
case when `%s` like %s then 0 else 1 end,
`%s`,
subject
limit %s, %s""" %
(searchfield, "%s", "%s", match_conditions, "%s",
searchfield, "%s", searchfield, "%s", "%s"),
(search_string, search_string, order_by_string, order_by_string, start, page_len))