completed Time Log / Time Log Batch
diff --git a/accounts/doctype/sales_invoice/sales_invoice.py b/accounts/doctype/sales_invoice/sales_invoice.py
index 9973398..7068c72 100644
--- a/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/accounts/doctype/sales_invoice/sales_invoice.py
@@ -75,6 +75,7 @@
self.set_aging_date()
self.set_against_income_account()
self.validate_c_form()
+ self.validate_time_logs_are_submitted()
self.validate_recurring_invoice()
def on_submit(self):
@@ -104,7 +105,7 @@
self.update_against_document_in_jv()
self.update_c_form()
-
+ self.update_time_log_batch(self.doc.name)
self.convert_to_recurring()
@@ -122,12 +123,28 @@
self.check_next_docstatus()
sales_com_obj.update_prevdoc_detail(0, self)
+ self.update_time_log_batch(None)
self.make_gl_entries(is_cancel=1)
def on_update_after_submit(self):
self.validate_recurring_invoice()
self.convert_to_recurring()
+ def update_time_log_batch(self, sales_invoice):
+ for d in self.doclist.get({"doctype":"Sales Invoice Item"}):
+ if d.time_log_batch:
+ tlb = webnotes.bean("Time Log Batch", d.time_log_batch)
+ tlb.doc.sales_invoice = sales_invoice
+ tlb.update_after_submit()
+
+ def validate_time_logs_are_submitted(self):
+ for d in self.doclist.get({"doctype":"Sales Invoice Item"}):
+ if d.time_log_batch:
+ status = webnotes.conn.get_value("Time Log Batch", d.time_log_batch, "status")
+ if status!="Submitted":
+ webnotes.msgprint(_("Time Log Batch status must be 'Submitted'") + ":" + d.time_log_batch,
+ raise_exception=True)
+
def set_pos_fields(self):
"""Set retail related fields from pos settings"""
pos = webnotes.conn.sql("select * from `tabPOS Setting` where ifnull(user,'') = '%s' and company = '%s'" % (session['user'], self.doc.company), as_dict=1)
diff --git a/accounts/doctype/sales_invoice/sales_invoice_map.js b/accounts/doctype/sales_invoice/sales_invoice_map.js
new file mode 100644
index 0000000..dec4c6f
--- /dev/null
+++ b/accounts/doctype/sales_invoice/sales_invoice_map.js
@@ -0,0 +1,16 @@
+wn.model.map_info["Sales Invoice"] = {
+ "Time Log Batch": {
+ table_map: {
+ "Sales Invoice Item": "Time Log Batch",
+ },
+ field_map: {
+ "Sales Invoice Item": {
+ "basic_rate": "rate",
+ "time_log_batch": "name",
+ "qty": "total_hours",
+ "stock_uom": "=Hour",
+ "description": "=via Time Logs"
+ }
+ },
+ }
+}
\ No newline at end of file
diff --git a/accounts/doctype/sales_invoice/test_sales_invoice.py b/accounts/doctype/sales_invoice/test_sales_invoice.py
index 6dcb713..9059978 100644
--- a/accounts/doctype/sales_invoice/test_sales_invoice.py
+++ b/accounts/doctype/sales_invoice/test_sales_invoice.py
@@ -28,6 +28,31 @@
jv.cancel()
self.assertEquals(webnotes.conn.get_value("Sales Invoice", w.doc.name, "outstanding_amount"),
561.8)
+
+ def test_time_log_batch(self):
+ tlb = webnotes.bean("Time Log Batch", "_T-Time Log Batch-00001")
+ tlb.submit()
+
+ w = webnotes.bean(webnotes.copy_doclist(test_records[0]))
+ w.doclist[1].time_log_batch = "_T-Time Log Batch-00001"
+ w.insert()
+ w.submit()
+
+ self.assertEquals(webnotes.conn.get_value("Time Log Batch", "_T-Time Log Batch-00001", "status"),
+ "Billed")
+
+ self.assertEquals(webnotes.conn.get_value("Time Log", "_T-Time Log-00001", "status"),
+ "Billed")
+
+ w.cancel()
+
+ self.assertEquals(webnotes.conn.get_value("Time Log Batch", "_T-Time Log Batch-00001", "status"),
+ "Submitted")
+
+ self.assertEquals(webnotes.conn.get_value("Time Log", "_T-Time Log-00001", "status"),
+ "Batched for Billing")
+
+
test_dependencies = ["Journal Voucher"]
diff --git a/accounts/doctype/sales_invoice_item/sales_invoice_item.txt b/accounts/doctype/sales_invoice_item/sales_invoice_item.txt
index 88c5aa8..ae1afe9 100644
--- a/accounts/doctype/sales_invoice_item/sales_invoice_item.txt
+++ b/accounts/doctype/sales_invoice_item/sales_invoice_item.txt
@@ -1,8 +1,8 @@
[
{
- "creation": "2013-01-10 16:34:09",
+ "creation": "2013-01-29 19:25:49",
"docstatus": 0,
- "modified": "2013-01-29 16:27:51",
+ "modified": "2013-03-01 13:41:51",
"modified_by": "Administrator",
"owner": "Administrator"
},
@@ -322,6 +322,13 @@
},
{
"doctype": "DocField",
+ "fieldname": "time_log_batch",
+ "fieldtype": "Link",
+ "label": "Time Log Batch",
+ "options": "Time Log Batch"
+ },
+ {
+ "doctype": "DocField",
"fieldname": "item_tax_rate",
"fieldtype": "Small Text",
"hidden": 1,
diff --git a/hr/doctype/leave_application/leave_application.py b/hr/doctype/leave_application/leave_application.py
index 313f27f..e8cc446 100755
--- a/hr/doctype/leave_application/leave_application.py
+++ b/hr/doctype/leave_application/leave_application.py
@@ -22,6 +22,7 @@
from webnotes import msgprint
class LeaveDayBlockedError(Exception): pass
+class OverlapError(Exception): pass
from webnotes.model.controller import DocListController
class DocType(DocListController):
@@ -129,17 +130,22 @@
(self.doc.leave_type,), raise_exception=1)
def validate_leave_overlap(self):
+ if not self.doc.name:
+ self.doc.name = "New Leave Application"
+
for d in webnotes.conn.sql("""select name, leave_type, posting_date,
from_date, to_date
from `tabLeave Application`
where
- (from_date <= %(to_date)s and to_date >= %(from_date)s)
- and employee = %(employee)s
+ employee = %(employee)s
and docstatus < 2
and status in ("Open", "Approved")
+ and (from_date between %(from_date)s and %(to_date)s
+ or to_date between %(from_date)s and %(to_date)s
+ or %(from_date)s between from_date and to_date)
and name != %(name)s""", self.doc.fields, as_dict = 1):
- msgprint("Employee : %s has already applied for %s between %s and %s on %s. Please refer Leave Application : <a href=\"#Form/Leave Application/%s\">%s</a>" % (self.doc.employee, cstr(d['leave_type']), formatdate(d['from_date']), formatdate(d['to_date']), formatdate(d['posting_date']), d['name'], d['name']), raise_exception = 1)
+ msgprint("Employee : %s has already applied for %s between %s and %s on %s. Please refer Leave Application : <a href=\"#Form/Leave Application/%s\">%s</a>" % (self.doc.employee, cstr(d['leave_type']), formatdate(d['from_date']), formatdate(d['to_date']), formatdate(d['posting_date']), d['name'], d['name']), raise_exception = OverlapError)
def validate_max_days(self):
max_days = webnotes.conn.sql("select max_days_allowed from `tabLeave Type` where name = '%s'" %(self.doc.leave_type))
diff --git a/hr/doctype/leave_application/test_leave_application.py b/hr/doctype/leave_application/test_leave_application.py
index dc1b463..bc4a38c 100644
--- a/hr/doctype/leave_application/test_leave_application.py
+++ b/hr/doctype/leave_application/test_leave_application.py
@@ -1,7 +1,7 @@
import webnotes
import unittest
-from hr.doctype.leave_application.leave_application import LeaveDayBlockedError
+from hr.doctype.leave_application.leave_application import LeaveDayBlockedError, OverlapError
class TestLeaveApplication(unittest.TestCase):
def get_application(self, doclist):
@@ -23,13 +23,22 @@
from webnotes.profile import add_role
add_role("test1@example.com", "HR User")
+
+ # clear other applications
+ webnotes.conn.sql("delete from `tabLeave Application`")
application = self.get_application(test_records[1])
self.assertTrue(application.insert())
+
+ def test_overlap(self):
+ application = self.get_application(test_records[1])
+ self.assertRaises(OverlapError, application.insert)
def test_global_block_list(self):
+
application = self.get_application(test_records[3])
application.doc.leave_approver = "test@example.com"
+
webnotes.conn.set_value("Leave Block List", "_Test Leave Block List",
"applies_to_all_departments", 1)
webnotes.conn.set_value("Employee", "_T-Employee-0002", "department",
diff --git a/patches/patch_list.py b/patches/patch_list.py
index 1160809..42fc554 100644
--- a/patches/patch_list.py
+++ b/patches/patch_list.py
@@ -200,4 +200,5 @@
'execute:webnotes.reload_doc("accounts", "Print Format", "Sales Invoice Modern") # 2013-02-26',
'execute:webnotes.reload_doc("accounts", "Print Format", "Sales Invoice Spartan") # 2013-02-26',
"execute:(not webnotes.conn.exists('Role', 'Projects Manager')) and webnotes.doc({'doctype':'Role', 'role_name':'Projects Manager'}).insert()",
+ "execute:(not webnotes.conn.exists('UOM', 'Hour')) and webnotes.doc({'uom_name': 'Unit', 'doctype': 'UOM', 'name': 'Hour'}).insert()",
]
\ No newline at end of file
diff --git a/projects/doctype/activity_type/test_activity_type.py b/projects/doctype/activity_type/test_activity_type.py
new file mode 100644
index 0000000..77ef7b3
--- /dev/null
+++ b/projects/doctype/activity_type/test_activity_type.py
@@ -0,0 +1,5 @@
+test_records = [
+ [{"activity_type":"_Test Activity Type"}],
+ [{"activity_type":"_Test Activity Type 1"}],
+ [{"activity_type":"_Test Activity Type 2"}]
+]
\ No newline at end of file
diff --git a/projects/doctype/project/test_project.py b/projects/doctype/project/test_project.py
new file mode 100644
index 0000000..bd7460d
--- /dev/null
+++ b/projects/doctype/project/test_project.py
@@ -0,0 +1,8 @@
+test_records = [[{
+ "project_name": "_Test Project",
+ "status": "Open"
+}],
+[{
+ "project_name": "_Test Project 1",
+ "status": "Open"
+}]]
\ No newline at end of file
diff --git a/projects/doctype/task/test_task.py b/projects/doctype/task/test_task.py
new file mode 100644
index 0000000..2e95806
--- /dev/null
+++ b/projects/doctype/task/test_task.py
@@ -0,0 +1,7 @@
+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"]
\ No newline at end of file
diff --git a/projects/doctype/time_log/test_time_log.py b/projects/doctype/time_log/test_time_log.py
new file mode 100644
index 0000000..1168c01
--- /dev/null
+++ b/projects/doctype/time_log/test_time_log.py
@@ -0,0 +1,19 @@
+import webnotes
+import unittest
+
+from 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 = [[{
+ "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"]
\ No newline at end of file
diff --git a/projects/doctype/time_log/time_log.js b/projects/doctype/time_log/time_log.js
new file mode 100644
index 0000000..a602332
--- /dev/null
+++ b/projects/doctype/time_log/time_log.js
@@ -0,0 +1,5 @@
+$.extend(cur_frm.cscript, {
+ refresh: function(doc) {
+
+ }
+});
\ No newline at end of file
diff --git a/projects/doctype/time_log/time_log.py b/projects/doctype/time_log/time_log.py
index a605998..34969a9 100644
--- a/projects/doctype/time_log/time_log.py
+++ b/projects/doctype/time_log/time_log.py
@@ -6,6 +6,8 @@
from webnotes.widgets.reportview import build_match_conditions
+class OverlapError(webnotes.ValidationError): pass
+
class DocType:
def __init__(self, d, dl):
self.doc, self.doclist = d, dl
@@ -13,28 +15,46 @@
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):
- if self.doc.docstatus==0:
- self.doc.status = "Draft"
- elif self.doc.docstatus==1:
- self.doc.status = "Submitted"
- elif self.doc.docstatus==2:
- self.doc.status = "Cancelled"
+ self.doc.status = {
+ "0": "Draft",
+ "1": "Submitted",
+ "2": "Cancelled"
+ }[str(self.doc.docstatus or 0)]
+
+ if self.doc.time_log_batch:
+ self.doc.status="Batched for Billing"
- # billed will be set directly
-
- def validate_overlap(self):
+ 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)) and name!=%s""",
+ (
+ (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 docstatus < 2""",
(self.doc.owner, self.doc.from_time, self.doc.to_time, self.doc.from_time,
- self.doc.to_time, self.doc.name))
+ self.doc.to_time, self.doc.from_time, self.doc.name or "No Name"))
if existing:
webnotes.msgprint(_("This Time Log conflicts with") + ":" + ', '.join(existing),
- raise_exception=True)
+ 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):
match = build_match_conditions("Time Log")
diff --git a/projects/doctype/time_log/time_log.txt b/projects/doctype/time_log/time_log.txt
index a6ad667..0e52464 100644
--- a/projects/doctype/time_log/time_log.txt
+++ b/projects/doctype/time_log/time_log.txt
@@ -2,13 +2,13 @@
{
"creation": "2013-02-26 14:58:28",
"docstatus": 0,
- "modified": "2013-02-28 18:41:40",
+ "modified": "2013-03-01 17:48:09",
"modified_by": "Administrator",
"owner": "Administrator"
},
{
"allow_attach": 1,
- "autoname": "TL-.######",
+ "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",
@@ -40,14 +40,12 @@
},
{
"doctype": "DocField",
- "fieldname": "status",
+ "fieldname": "naming_series",
"fieldtype": "Select",
- "in_list_view": 1,
- "label": "Status",
- "options": "Draft\nSubmitted\nBatched for Billing\nBilled\nCancelled",
+ "label": "Naming Series",
+ "options": "TL-",
"permlevel": 0,
- "read_only": 1,
- "reqd": 0
+ "reqd": 1
},
{
"doctype": "DocField",
@@ -69,12 +67,31 @@
},
{
"doctype": "DocField",
+ "fieldname": "hours",
+ "fieldtype": "Float",
+ "label": "Hours",
+ "permlevel": 0,
+ "read_only": 1
+ },
+ {
+ "doctype": "DocField",
"fieldname": "column_break_3",
"fieldtype": "Column Break",
"permlevel": 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,
@@ -128,6 +145,26 @@
"permlevel": 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": "file_list",
"fieldtype": "Text",
@@ -143,7 +180,7 @@
"fieldtype": "Link",
"label": "Amended From",
"no_copy": 1,
- "options": "Sales Invoice",
+ "options": "Time Log",
"permlevel": 1,
"print_hide": 1
},
diff --git a/projects/doctype/time_log/time_log_list.js b/projects/doctype/time_log/time_log_list.js
index 13d35c1..85c9b2a 100644
--- a/projects/doctype/time_log/time_log_list.js
+++ b/projects/doctype/time_log/time_log_list.js
@@ -1,5 +1,6 @@
// 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() {
@@ -16,12 +17,28 @@
msgprint(wn._("Time Log is not billable") + ": " + d.name);
return;
}
- if(d.sales_invoice) {
- msgprint(wn._("Time Log has been Invoiced") + ": " + d.name);
+ 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");
}
diff --git a/projects/doctype/time_log_batch/test_time_log_batch.py b/projects/doctype/time_log_batch/test_time_log_batch.py
new file mode 100644
index 0000000..54195c2
--- /dev/null
+++ b/projects/doctype/time_log_batch/test_time_log_batch.py
@@ -0,0 +1,20 @@
+import webnotes, unittest
+
+class TimeLogBatchTest(unittest.TestCase):
+ def test_time_log_status(self):
+ self.assertEquals(webnotes.conn.get_value("Time Log", "_T-Time Log-00001", "status"), "Submitted")
+ tlb = webnotes.bean("Time Log Batch", "_T-Time Log Batch-00001")
+ tlb.submit()
+ self.assertEquals(webnotes.conn.get_value("Time Log", "_T-Time Log-00001", "status"), "Batched for Billing")
+ tlb.cancel()
+ self.assertEquals(webnotes.conn.get_value("Time Log", "_T-Time Log-00001", "status"), "Submitted")
+
+test_records = [[
+ {"rate": "500"},
+ {
+ "doctype": "Time Log Batch Detail",
+ "parenttype": "Time Log Batch",
+ "parentfield": "time_log_batch_details",
+ "time_log": "_T-Time Log-00001",
+ }
+]]
\ No newline at end of file
diff --git a/projects/doctype/time_log_batch/time_log_batch.js b/projects/doctype/time_log_batch/time_log_batch.js
index bd47c0b..6e5165b 100644
--- a/projects/doctype/time_log_batch/time_log_batch.js
+++ b/projects/doctype/time_log_batch/time_log_batch.js
@@ -1,5 +1,6 @@
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 {
@@ -12,7 +13,24 @@
});
$.extend(cur_frm.cscript, {
- refresh: function() {
+ 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("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"
+ });
}
-})
\ No newline at end of file
+});
\ No newline at end of file
diff --git a/projects/doctype/time_log_batch/time_log_batch.py b/projects/doctype/time_log_batch/time_log_batch.py
index fe4e9a3..6ec0e5b 100644
--- a/projects/doctype/time_log_batch/time_log_batch.py
+++ b/projects/doctype/time_log_batch/time_log_batch.py
@@ -2,10 +2,59 @@
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):
- # update time logs as batched
\ No newline at end of file
+ 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()
+
+
+
\ No newline at end of file
diff --git a/projects/doctype/time_log_batch/time_log_batch.txt b/projects/doctype/time_log_batch/time_log_batch.txt
index b217f23..7fe1827 100644
--- a/projects/doctype/time_log_batch/time_log_batch.txt
+++ b/projects/doctype/time_log_batch/time_log_batch.txt
@@ -2,7 +2,7 @@
{
"creation": "2013-02-28 17:57:33",
"docstatus": 0,
- "modified": "2013-02-28 18:36:28",
+ "modified": "2013-03-01 17:54:57",
"modified_by": "Administrator",
"owner": "Administrator"
},
@@ -24,6 +24,7 @@
"permlevel": 0
},
{
+ "amend": 1,
"cancel": 1,
"create": 1,
"doctype": "DocPerm",
@@ -59,17 +60,49 @@
},
{
"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"
+ "options": "Time Log Batch Detail",
+ "reqd": 1
},
{
"description": "In Hours",
"doctype": "DocField",
- "fieldname": "total_time",
+ "fieldname": "total_hours",
"fieldtype": "Float",
- "label": "Total Time",
+ "in_list_view": 1,
+ "label": "Total Hours",
"read_only": 1
},
{
diff --git a/projects/doctype/time_log_batch_detail/time_log_batch_detail.txt b/projects/doctype/time_log_batch_detail/time_log_batch_detail.txt
index 0f7d23f..d1e1eae 100644
--- a/projects/doctype/time_log_batch_detail/time_log_batch_detail.txt
+++ b/projects/doctype/time_log_batch_detail/time_log_batch_detail.txt
@@ -2,7 +2,7 @@
{
"creation": "2013-02-28 17:56:12",
"docstatus": 0,
- "modified": "2013-02-28 17:56:12",
+ "modified": "2013-03-01 15:20:17",
"modified_by": "Administrator",
"owner": "Administrator"
},
@@ -47,5 +47,11 @@
"fieldtype": "Data",
"label": "Activity Type",
"read_only": 1
+ },
+ {
+ "doctype": "DocField",
+ "fieldname": "hours",
+ "fieldtype": "Float",
+ "label": "Hours"
}
]
\ No newline at end of file
diff --git a/projects/page/projects_home/projects_home.js b/projects/page/projects_home/projects_home.js
index 36e3c0b..d9476e9 100644
--- a/projects/page/projects_home/projects_home.js
+++ b/projects/page/projects_home/projects_home.js
@@ -56,7 +56,18 @@
},
]
},
-]
+ {
+ title: wn._("Reports"),
+ right: true,
+ icon: "icon-list",
+ items: [
+ {
+ "label":wn._("Time Log Summary"),
+ route: "Report2/Time Log/Time Log Summary",
+ doctype: "Time Log"
+ },
+ ]
+ }]
pscript['onload_projects-home'] = function(wrapper) {
wn.views.moduleview.make(wrapper, "Projects");
diff --git a/projects/report/__init__.py b/projects/report/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/projects/report/__init__.py
diff --git a/projects/report/time_log_summary/__init__.py b/projects/report/time_log_summary/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/projects/report/time_log_summary/__init__.py
diff --git a/projects/report/time_log_summary/time_log_summary.txt b/projects/report/time_log_summary/time_log_summary.txt
new file mode 100644
index 0000000..3925a2d
--- /dev/null
+++ b/projects/report/time_log_summary/time_log_summary.txt
@@ -0,0 +1,22 @@
+[
+ {
+ "creation": "2013-03-01 17:36:35",
+ "docstatus": 0,
+ "modified": "2013-03-01 18:17:13",
+ "modified_by": "Administrator",
+ "owner": "Administrator"
+ },
+ {
+ "doctype": "Report",
+ "is_standard": "Yes",
+ "json": "{\"filters\":[],\"columns\":[[\"name\",\"Time Log\"],[\"status\",\"Time Log\"],[\"from_time\",\"Time Log\"],[\"hours\",\"Time Log\"],[\"activity_type\",\"Time Log\"],[\"owner\",\"Time Log\"],[\"billable\",\"Time Log\"],[\"time_log_batch\",\"Time Log\"],[\"sales_invoice\",\"Time Log\"]],\"sort_by\":\"Time Log.name\",\"sort_order\":\"desc\",\"sort_by_next\":\"\",\"sort_order_next\":\"desc\"}",
+ "name": "__common__",
+ "ref_doctype": "Time Log",
+ "report_name": "Time Log Summary",
+ "report_type": "Report Builder"
+ },
+ {
+ "doctype": "Report",
+ "name": "Time Log Summary"
+ }
+]
\ No newline at end of file
diff --git a/startup/install.py b/startup/install.py
index 5ddbf09..f584769 100644
--- a/startup/install.py
+++ b/startup/install.py
@@ -162,6 +162,7 @@
# UOM
{'uom_name': 'Unit', 'doctype': 'UOM', 'name': 'Unit'},
+ {'uom_name': 'Unit', 'doctype': 'UOM', 'name': 'Hour'},
{'uom_name': 'Box', 'doctype': 'UOM', 'name': 'Box'},
{'uom_name': 'Ft', 'doctype': 'UOM', 'name': 'Ft'},
{'uom_name': 'Kg', 'doctype': 'UOM', 'name': 'Kg'},
diff --git a/startup/observers.py b/startup/observers.py
index 0e17c9d..89980e4 100644
--- a/startup/observers.py
+++ b/startup/observers.py
@@ -19,5 +19,4 @@
"*:on_submit": "home.update_feed",
"Stock Entry:on_submit": "stock.doctype.material_request.material_request.update_completed_qty",
"Stock Entry:on_cancel": "stock.doctype.material_request.material_request.update_completed_qty",
-# "*:on_update": "webnotes.widgets.moduleview.update_count"
}
\ No newline at end of file
diff --git a/startup/open_count.py b/startup/open_count.py
index 7d8dcf8..916ecbd 100644
--- a/startup/open_count.py
+++ b/startup/open_count.py
@@ -27,4 +27,6 @@
"Production Order": {"docstatus":0},
"BOM": {"docstatus":0},
"Timesheet": {"docstatus":0},
+ "Time Log": {"status":"Draft"},
+ "Time Log Batch": {"status":"Draft"},
}
\ No newline at end of file