From b3fe6a45a7e6cd361c301f09686a242cf6f38fac Mon Sep 17 00:00:00 2001 From: Kanchan Chauhan Date: Wed, 16 Mar 2016 18:01:22 +0530 Subject: [PATCH 1/2] WIP Collaborative Project Management first commit --- erpnext/projects/doctype/project/project.json | 2 +- erpnext/projects/doctype/project/project.py | 12 ++ erpnext/shopping_cart/cart.py | 3 + erpnext/shopping_cart/utils.py | 3 +- erpnext/support/doctype/issue/issue.json | 78 ++++++- erpnext/templates/includes/cart.css | 7 + erpnext/templates/includes/cart.js | 5 + erpnext/templates/includes/project_row.html | 29 +++ .../includes/project_search_box.html | 20 ++ erpnext/templates/includes/projects.css | 132 ++++++++++++ .../includes/projects/project_issues.html | 31 +++ .../includes/projects/project_tasks.html | 30 +++ .../includes/projects/project_timelogs.html | 20 ++ .../templates/includes/projects/timeline.html | 44 ++++ erpnext/templates/pages/cart.html | 9 + erpnext/templates/pages/cart_terms.html | 2 + erpnext/templates/pages/projects.html | 98 +++++++++ erpnext/templates/pages/projects.js | 204 ++++++++++++++++++ erpnext/templates/pages/projects.py | 140 ++++++++++++ erpnext/templates/pages/task_info.html | 149 +++++++++++++ erpnext/templates/pages/task_info.py | 14 ++ erpnext/templates/pages/timelog_info.html | 48 +++++ erpnext/templates/pages/timelog_info.py | 11 + 23 files changed, 1088 insertions(+), 3 deletions(-) create mode 100644 erpnext/templates/includes/project_row.html create mode 100644 erpnext/templates/includes/project_search_box.html create mode 100644 erpnext/templates/includes/projects.css create mode 100644 erpnext/templates/includes/projects/project_issues.html create mode 100644 erpnext/templates/includes/projects/project_tasks.html create mode 100644 erpnext/templates/includes/projects/project_timelogs.html create mode 100644 erpnext/templates/includes/projects/timeline.html create mode 100644 erpnext/templates/pages/cart_terms.html create mode 100644 erpnext/templates/pages/projects.html create mode 100644 erpnext/templates/pages/projects.js create mode 100644 erpnext/templates/pages/projects.py create mode 100644 erpnext/templates/pages/task_info.html create mode 100644 erpnext/templates/pages/task_info.py create mode 100644 erpnext/templates/pages/timelog_info.html create mode 100644 erpnext/templates/pages/timelog_info.py diff --git a/erpnext/projects/doctype/project/project.json b/erpnext/projects/doctype/project/project.json index 1f1943c85a..02a3fd0760 100644 --- a/erpnext/projects/doctype/project/project.json +++ b/erpnext/projects/doctype/project/project.json @@ -921,7 +921,7 @@ "issingle": 0, "istable": 0, "max_attachments": 4, - "modified": "2016-03-10 05:10:21.779365", + "modified": "2016-03-15 05:10:21.779365", "modified_by": "Administrator", "module": "Projects", "name": "Project", diff --git a/erpnext/projects/doctype/project/project.py b/erpnext/projects/doctype/project/project.py index ec4f523b47..c2b8fb1bba 100644 --- a/erpnext/projects/doctype/project/project.py +++ b/erpnext/projects/doctype/project/project.py @@ -123,7 +123,19 @@ class Project(Document): from `tabPurchase Invoice Item` where project = %s and docstatus=1""", self.name) self.total_purchase_cost = total_purchase_cost and total_purchase_cost[0][0] or 0 + + +def get_project_list(doctype, txt, filters, limit_start, limit_page_length=20): + from frappe.templates.pages.list import get_list + return get_list(doctype, txt, filters, limit_start, limit_page_length, ignore_permissions=True) + +def get_list_context(context=None): + return { + "title": _("My Projects"), + "get_list": get_project_list, + "row_template": "templates/includes/project_row.html" + } @frappe.whitelist() def get_cost_center_name(project): return frappe.db.get_value("Project", project, "cost_center") diff --git a/erpnext/shopping_cart/cart.py b/erpnext/shopping_cart/cart.py index 012aaf7750..334a1f376e 100644 --- a/erpnext/shopping_cart/cart.py +++ b/erpnext/shopping_cart/cart.py @@ -437,3 +437,6 @@ def get_address_territory(address_name): break return territory + +def show_terms(doc): + return doc.tc_name diff --git a/erpnext/shopping_cart/utils.py b/erpnext/shopping_cart/utils.py index b8d5054e87..3e1afe27fa 100644 --- a/erpnext/shopping_cart/utils.py +++ b/erpnext/shopping_cart/utils.py @@ -30,9 +30,10 @@ def update_website_context(context): def update_my_account_context(context): context["my_account_list"].extend([ + {"label": _("Projects"), "url": "project"}, {"label": _("Orders"), "url": "orders"}, {"label": _("Invoices"), "url": "invoices"}, {"label": _("Shipments"), "url": "shipments"}, {"label": _("Issues"), "url": "issues"}, - {"label": _("Addresses"), "url": "addresses"}, + {"label": _("Addresses"), "url": "addresses"} ]) diff --git a/erpnext/support/doctype/issue/issue.json b/erpnext/support/doctype/issue/issue.json index 1f40a211a5..2a6f7a031d 100644 --- a/erpnext/support/doctype/issue/issue.json +++ b/erpnext/support/doctype/issue/issue.json @@ -16,6 +16,7 @@ "fieldtype": "Section Break", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, "label": "Subject", @@ -40,6 +41,7 @@ "fieldtype": "Select", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, "label": "Series", @@ -64,6 +66,7 @@ "fieldtype": "Data", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 1, "in_list_view": 0, "label": "Subject", @@ -87,6 +90,7 @@ "fieldtype": "Column Break", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, "length": 0, @@ -110,6 +114,7 @@ "fieldtype": "Select", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 1, "label": "Status", @@ -137,6 +142,7 @@ "fieldtype": "Data", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 1, "in_list_view": 1, "label": "Raised By (Email)", @@ -163,6 +169,7 @@ "fieldtype": "Fold", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, "length": 0, @@ -185,6 +192,7 @@ "fieldtype": "Section Break", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, "length": 0, @@ -209,6 +217,7 @@ "fieldtype": "Text", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, "label": "Description", @@ -234,6 +243,7 @@ "fieldtype": "Column Break", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, "length": 0, @@ -258,6 +268,7 @@ "fieldtype": "Datetime", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, "label": "Resolution Date", @@ -283,6 +294,7 @@ "fieldtype": "Datetime", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, "label": "First Responded On", @@ -306,6 +318,7 @@ "fieldtype": "Section Break", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, "label": "", @@ -330,6 +343,7 @@ "fieldtype": "Link", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, "label": "Lead", @@ -354,6 +368,7 @@ "fieldtype": "Link", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, "label": "Contact", @@ -378,6 +393,7 @@ "fieldtype": "Column Break", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, "length": 0, @@ -401,6 +417,7 @@ "fieldtype": "Link", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 1, "in_list_view": 0, "label": "Customer", @@ -427,6 +444,7 @@ "fieldtype": "Data", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 1, "in_list_view": 0, "label": "Customer Name", @@ -452,6 +470,7 @@ "fieldtype": "Section Break", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, "length": 0, @@ -476,6 +495,7 @@ "fieldtype": "Small Text", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, "label": "Resolution Details", @@ -502,6 +522,7 @@ "fieldtype": "Column Break", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, "length": 0, @@ -526,6 +547,7 @@ "fieldtype": "Date", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, "label": "Opening Date", @@ -551,6 +573,7 @@ "fieldtype": "Time", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, "label": "Opening Time", @@ -576,6 +599,7 @@ "fieldtype": "Link", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, "label": "Company", @@ -600,6 +624,7 @@ "fieldtype": "Data", "hidden": 1, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, "label": "Content Type", @@ -623,6 +648,7 @@ "fieldtype": "Attach", "hidden": 1, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, "label": "Attachment", @@ -638,6 +664,32 @@ "search_index": 0, "set_only_once": 0, "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "project", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Project", + "length": 0, + "no_copy": 0, + "options": "Project", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 } ], "hide_heading": 0, @@ -650,7 +702,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2016-02-03 01:08:48.180242", + "modified": "2016-03-09 18:31:10.404549", "modified_by": "Administrator", "module": "Support", "name": "Issue", @@ -661,6 +713,26 @@ "apply_user_permissions": 1, "cancel": 0, "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "if_owner": 0, + "import": 0, + "permlevel": 0, + "print": 1, + "read": 1, + "report": 1, + "role": "Projects User", + "set_user_permissions": 0, + "share": 1, + "submit": 0, + "write": 1 + }, + { + "amend": 0, + "apply_user_permissions": 0, + "cancel": 0, + "create": 1, "delete": 0, "email": 1, "export": 0, @@ -670,6 +742,8 @@ "print": 1, "read": 1, "report": 1, + "restrict": 0, + "restricted": 0, "role": "Customer", "set_user_permissions": 0, "share": 1, @@ -690,6 +764,8 @@ "print": 1, "read": 1, "report": 1, + "restrict": 0, + "restricted": 0, "role": "Support Team", "set_user_permissions": 0, "share": 1, diff --git a/erpnext/templates/includes/cart.css b/erpnext/templates/includes/cart.css index 7a18530286..07302dbfe0 100644 --- a/erpnext/templates/includes/cart.css +++ b/erpnext/templates/includes/cart.css @@ -23,3 +23,10 @@ margin-top: 80px; margin-bottom: 60px; } + +.cart-link { + margin-top: 40px; + text-align: right; + + +} \ No newline at end of file diff --git a/erpnext/templates/includes/cart.js b/erpnext/templates/includes/cart.js index 0c29569b9e..9cb5e6ee88 100644 --- a/erpnext/templates/includes/cart.js +++ b/erpnext/templates/includes/cart.js @@ -147,3 +147,8 @@ $(document).ready(function() { $(".cart-icon").hide(); shopping_cart.bind_events(); }); + +function show_terms() { + var html = $(".cart-terms").html(); + frappe.msgprint(html); +} diff --git a/erpnext/templates/includes/project_row.html b/erpnext/templates/includes/project_row.html new file mode 100644 index 0000000000..3c7331bea4 --- /dev/null +++ b/erpnext/templates/includes/project_row.html @@ -0,0 +1,29 @@ +{% if doc.status=="Open" %} +
+ +
+
+ + {{ doc.name }} +
+
+ {% if doc.percent_complete %} +
+
+ {{ doc.percent_complete|round|int }}% Complete +
+
+ {% else %} + + {{ doc.status }} + {% endif %} +
+
+ {{ frappe.utils.pretty_date(doc.modified) }} +
+
+
+
+{% endif %} diff --git a/erpnext/templates/includes/project_search_box.html b/erpnext/templates/includes/project_search_box.html new file mode 100644 index 0000000000..8788fcd807 --- /dev/null +++ b/erpnext/templates/includes/project_search_box.html @@ -0,0 +1,20 @@ + + + \ No newline at end of file diff --git a/erpnext/templates/includes/projects.css b/erpnext/templates/includes/projects.css new file mode 100644 index 0000000000..e08088092f --- /dev/null +++ b/erpnext/templates/includes/projects.css @@ -0,0 +1,132 @@ +/* CSS used here will be applied after bootstrap.css */ + +.underline { + text-decoration: underline; +} + +.page-container .indicator { + font-weight: normal; +} + +.page-container .project-item { + padding-top: 5px; + padding-bottom: 5px; +} + +.row-header { + font-size: 14px; + font-weight: 500; + padding-bottom: 8px; + border-bottom: 2px solid #d1d8dd; + margin: 0!important; +} + +.content_display{ + padding: 5px; +} + +.task-btn, .issue-btn, .timelog-btn{ + padding: 8px; +} + +.timeline-centered { + position: relative; + margin-bottom: 30px; +} + +.timeline-centered:before { + content: ''; + position: absolute; + display: block; + width: 4px; + background: #f5f5f6; + /*left: 50%;*/ + top: 20px; + bottom: 20px; + margin-left: 30px; +} + +.timeline-centered .timeline-entry { + position: relative; + /*width: 50%; +float: right;*/ + margin-top: 5px; + margin-left: 30px; + margin-bottom: 10px; + clear: both; +} + + + +.timeline-centered .timeline-entry.left-aligned .timeline-entry-inner .timeline-label:after { + left: auto; + right: 0; + margin-left: 0; + margin-right: -9px; + -moz-transform: rotate(180deg); + -o-transform: rotate(180deg); + -webkit-transform: rotate(180deg); + -ms-transform: rotate(180deg); + transform: rotate(180deg); +} + +.timeline-centered .timeline-entry .timeline-entry-inner { + position: relative; + margin-left: -20px; +} + + +.timeline-centered .timeline-entry .timeline-entry-inner .timeline-icon { + background: #fff; + color: #737881; + display: block; + width: 40px; + height: 40px; + -webkit-background-clip: padding-box; + -moz-background-clip: padding; + background-clip: padding-box; + -webkit-border-radius: 20px; + -moz-border-radius: 20px; + border-radius: 20px; + text-align: center; + -moz-box-shadow: 0 0 0 5px #f5f5f6; + -webkit-box-shadow: 0 0 0 5px #f5f5f6; + box-shadow: 0 0 0 5px #f5f5f6; + line-height: 40px; + font-size: 15px; + float: left; +} + + +.timeline-centered .timeline-entry .timeline-entry-inner .timeline-icon.bg-warning { + background-color: #fad839; + color: #fff; +} + + +.timeline-centered .timeline-entry .timeline-entry-inner .timeline-label { + position: relative; + background: #f5f5f6; + padding: 1em; + margin-left: 60px; + -webkit-background-clip: padding-box; + -moz-background-clip: padding; + background-clip: padding-box; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} + +.timeline-centered .timeline-entry .timeline-entry-inner .timeline-label:after { + content: ''; + display: block; + position: absolute; + width: 0; + height: 0; + border-style: solid; + border-width: 9px 9px 9px 0; + border-color: transparent #f5f5f6 transparent transparent; + left: 0; + top: 10px; + margin-left: -9px; +} diff --git a/erpnext/templates/includes/projects/project_issues.html b/erpnext/templates/includes/projects/project_issues.html new file mode 100644 index 0000000000..14ce70f1ad --- /dev/null +++ b/erpnext/templates/includes/projects/project_issues.html @@ -0,0 +1,31 @@ +{% for issue in doc.issues %} +
+ +
+{% endfor %} diff --git a/erpnext/templates/includes/projects/project_tasks.html b/erpnext/templates/includes/projects/project_tasks.html new file mode 100644 index 0000000000..84de0e8914 --- /dev/null +++ b/erpnext/templates/includes/projects/project_tasks.html @@ -0,0 +1,30 @@ +{% for task in doc.tasks %} +
+
+ +
+
+ {% if task.todo %} + {% else %} + + {% endif %} +
+
+ {% if task.status != "Closed" %} + + {% endif %} +
+
+
+
+{% endfor %} \ No newline at end of file diff --git a/erpnext/templates/includes/projects/project_timelogs.html b/erpnext/templates/includes/projects/project_timelogs.html new file mode 100644 index 0000000000..4934032e8c --- /dev/null +++ b/erpnext/templates/includes/projects/project_timelogs.html @@ -0,0 +1,20 @@ +{% for timelog in doc.timelogs %} +
+ +
+{% endfor %} \ No newline at end of file diff --git a/erpnext/templates/includes/projects/timeline.html b/erpnext/templates/includes/projects/timeline.html new file mode 100644 index 0000000000..77b0c7609a --- /dev/null +++ b/erpnext/templates/includes/projects/timeline.html @@ -0,0 +1,44 @@ +{% for timeline in doc.timelines %} +
+
+
+ + + {{timeline.reference_name}} {{timeline.subject }} + + + {{ frappe.utils.pretty_date(timeline.creation) }} + +
+
+
+{% endfor %} + \ No newline at end of file diff --git a/erpnext/templates/pages/cart.html b/erpnext/templates/pages/cart.html index 6891bceb1b..f2104f9ecb 100644 --- a/erpnext/templates/pages/cart.html +++ b/erpnext/templates/pages/cart.html @@ -61,6 +61,15 @@
+ {% if doc.tc_name %} + + + {% endif %}
{% include "templates/includes/cart/cart_address.html" %}
diff --git a/erpnext/templates/pages/cart_terms.html b/erpnext/templates/pages/cart_terms.html new file mode 100644 index 0000000000..521c583cb6 --- /dev/null +++ b/erpnext/templates/pages/cart_terms.html @@ -0,0 +1,2 @@ + +
{{doc.terms}}
\ No newline at end of file diff --git a/erpnext/templates/pages/projects.html b/erpnext/templates/pages/projects.html new file mode 100644 index 0000000000..bbc5c6ebc8 --- /dev/null +++ b/erpnext/templates/pages/projects.html @@ -0,0 +1,98 @@ +{% extends "templates/web.html" %} + +{% block title %}{{ doc.project_name }}{% endblock %} + +{% block header %} +

+{{ doc.project_name }} +

+{% endblock %} + +{% block style %} + +{% endblock %} + + +{% block page_content %} + +{% include 'templates/includes/project_search_box.html' %} + +{% if frappe.form_dict.q %} +

+ Filtered by "{{ frappe.form_dict.q }}" Clear

+{% else %} +

{{ _("Activity Feed") }}

+
+ {% include "erpnext/templates/includes/projects/timeline.html" %} +
+ {% if doc.timelines|length > 9 %} +

{{ _("More") }}

+ {% endif %} +{% endif %} + +{% if doc.tasks %} +

+
+ New +

{{ _("Tasks") }}

+
+
+ + +
+
+ {% include "erpnext/templates/includes/projects/project_tasks.html" %} +
+ + {% if doc.tasks|length > 4 %} +

{{ _("More") }}

+ {% endif %} +

+{% else %} +

No tasks

+{% endif %} + +{% if doc.issues %} +
+
+ New +

{{ _("Issues") }}

+
+
+ + +
+
+ {% include "erpnext/templates/includes/projects/project_issues.html" %} +
+ + {% if doc.issues|length > 4 %} +

{{ _("More") }}

+ {% endif %} +

+{% else %} +

No Issues

+{% endif %} + +{% if doc.timelogs %} +

{{ _("Time Logs") }}

+
+ {% include "erpnext/templates/includes/projects/project_timelogs.html" %} +
+ {% if doc.timelogs|length > 1 %} +

{{ _("More") }}

+ {% endif %} +{% else %} +

No time logs

+{% endif %} + + + + +{% endblock %} \ No newline at end of file diff --git a/erpnext/templates/pages/projects.js b/erpnext/templates/pages/projects.js new file mode 100644 index 0000000000..87a1ab7b5a --- /dev/null +++ b/erpnext/templates/pages/projects.js @@ -0,0 +1,204 @@ +frappe.ready(function() { + var reload_tasks = function(taskstatus) { + $.ajax({ + method: "GET", + url: "/", + dataType: "json", + data: { + cmd: "erpnext.templates.pages.projects.get_tasks_html", + project: '{{ doc.name }}', + taskstatus: taskstatus, + }, + dataType: "json", + success: function(data) { + $('.project-tasks').html(data.message); + + $('.project-tasks-section .btn-group .btn-primary').removeClass('btn-primary'); + $('.btn-'+ taskstatus +'-tasks').addClass( "btn-primary" ); + } + }); + + } + + $('.btn-closed-tasks').click(function() { + reload_tasks('closed'); + }); + $('.btn-open-tasks').click(function() { + reload_tasks('open'); + }); + + var reload_issues = function(issuestatus) { + $.ajax({ + method: "GET", + url: "/", + dataType: "json", + data: { + cmd: "erpnext.templates.pages.projects.get_issues_html", + project: '{{ doc.name }}', + issuestatus: issuestatus, + }, + dataType: "json", + success: function(data) { + $('.project-issues').html(data.message); + + $('.project-issues-section .btn-group .btn-primary').removeClass('btn-primary'); + $('.btn-'+ issuestatus +'-issues').addClass( "btn-primary" ); + } + }); + + } + + $('.btn-closed-issues').click(function() { + reload_issues('closed'); + }); + $('.btn-open-issues').click(function() { + reload_issues('open'); + }); + + var taskstart = 5; + $(".more-tasks").click(function() { + var task_status = $('.project-tasks-section .btn-group .btn-primary').hasClass('btn-closed-tasks') + ? 'closed' : 'open'; + + $.ajax({ + method: "GET", + url: "/", + dataType: "json", + data: { + cmd: "erpnext.templates.pages.projects.get_tasks_html", + project: '{{ doc.name }}', + start: taskstart, + taskstatus: task_status, + }, + dataType: "json", + success: function(data) { + $(data.message).appendTo('.project-tasks'); + if(typeof data.message == 'undefined') { + $(".more-tasks").toggle(false); + } + taskstart = taskstart+5; + } + }); + + }); + + var issuestart = 2; + $(".more-issues").click(function() { + var issue_status = $('.project-issues-section .btn-group .btn-primary').hasClass('btn-closed-issues') + ? 'closed' : 'open'; + + $.ajax({ + method: "GET", + url: "/", + dataType: "json", + data: { + cmd: "erpnext.templates.pages.projects.get_issues_html", + project: '{{ doc.name }}', + start: issuestart, + issuestatus: issue_status, + }, + dataType: "json", + success: function(data) { + $(data.message).appendTo('.project-issues'); + if(typeof data.message == 'undefined') + { + $(".more-issues").toggle(false); + } + issuestart = issuestart+5; + } + }); + }); + + var timelogstart = 2; + $(".more-timelogs").click(function() { + $.ajax({ + method: "GET", + url: "/", + dataType: "json", + data: { + cmd: "erpnext.templates.pages.projects.get_timelogs_html", + project: '{{ doc.name }}', + start: timelogstart, + }, + dataType: "json", + success: function(data) { + $(data.message).appendTo('.project-timelogs'); + if(typeof data.message == 'undefined') + { + $(".more-timelogs").toggle(false); + } + timelogstart = timelogstart+2; + + } + }); + + }); + + var timelinestart = 10; + $(".more-timelines").click(function() { + $.ajax({ + method: "GET", + url: "/", + dataType: "json", + data: { + cmd: "erpnext.templates.pages.projects.get_timeline_html", + project: '{{ doc.name }}', + start: timelinestart, + + }, + dataType: "json", + success: function(data) { + $(data.message).appendTo('.project-timeline'); + if(typeof data.message == 'undefined') + { + $(".more-timelines").toggle(false); + } + timelinestart = timelinestart+10; + } + }); + }); + + $( ".project-tasks" ).on('click', '.task-x', function() { + var args = { + project: '{{ doc.name }}', + task_name: $(this).attr('id'), + } + frappe.call({ + btn: this, + type: "POST", + method: "erpnext.templates.pages.projects.set_task_status", + args: args, + callback: function(r) { + if(r.exc) { + if(r._server_messages) + frappe.msgprint(r._server_messages); + } else { + $(this).remove(); + } + } + }) + return false; + }); + + $( ".project-issues" ).on('click', '.issue-x', function() { + var args = { + project: '{{ doc.name }}', + issue_name: $(this).attr('id'), + } + frappe.call({ + btn: this, + type: "POST", + method: "erpnext.templates.pages.projects.set_issue_status", + args: args, + callback: function(r) { + if(r.exc) { + if(r._server_messages) + frappe.msgprint(r._server_messages); + } else { + $(this).remove(); + } + } + }) + return false; + }); +}); diff --git a/erpnext/templates/pages/projects.py b/erpnext/templates/pages/projects.py new file mode 100644 index 0000000000..7d0d2009fe --- /dev/null +++ b/erpnext/templates/pages/projects.py @@ -0,0 +1,140 @@ +# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe + +from frappe import _ + +def get_context(context): + context.no_cache = 1 + + project = frappe.get_doc('Project', frappe.form_dict.project) + + project.has_permission('read') + + context.issues = frappe.get_all('Issue', filters={'project': project.project_name}, + fields=['subject', 'opening_date', 'resolution_date', 'status', 'name', 'resolution_details','modified','modified_by']) + + project.tasks = get_tasks(project.name, start=0, search=frappe.form_dict.get("q")) + + project.timelogs = get_timelogs(project.name, start=0, search=frappe.form_dict.get("q")) + + project.issues = get_issues(project.name, start=0, search=frappe.form_dict.get("q")) + + project.timelines = get_timeline(project.project_name, start=0) + + + + context.doc = project + + +def get_timeline(project, start=10): + issue_names = '({0})'.format(", ".join(["'{0}'".format(i.name) for i in get_issues(project)])) + + print issue_names + + timelines = frappe.db.sql("""select sender_full_name, + subject, communication_date, comment_type, name, creation, modified_by, reference_doctype, reference_name, + _liked_by, comment_type, _comments + from tabCommunication + where (reference_doctype='Project' and reference_name=%s) + or (timeline_doctype='Project' and timeline_name=%s) + or (reference_doctype='Issue' and reference_name IN {issue_names}) + order by modified DESC limit {start}, {limit}""".format( + issue_names=issue_names, start=start, limit=10), + (project, project), as_dict=True); + for timeline in timelines: + timeline.user_image = frappe.db.get_value('User', timeline.modified_by, 'user_image') + return timelines + +@frappe.whitelist() +def get_timeline_html(project, start=0): + return frappe.render_template("erpnext/templates/includes/projects/timeline.html", + {"doc": {"timelines": get_timeline(project, start)}}, is_path=True) + +def get_issue_list(project): + return [issue.name for issue in get_issues(project)] + +def get_tasks(project, start=0, search=None, taskstatus=None): + filters = {"project": project} + if search: + filters["subject"] = ("like", "%{0}%".format(search)) + if taskstatus: + filters = {"status": taskstatus} + tasks = frappe.get_all("Task", filters=filters, + fields=["name", "subject", "status", "exp_start_date", "exp_end_date", "priority"], + limit_start=start, limit_page_length=5) + + for task in tasks: + task.todo = frappe.get_all('ToDo',filters={'reference_name':task.name, 'reference_type':'Task'}, + fields=["assigned_by", "owner", "modified", "modified_by"]) + if task.todo: + task.todo=task.todo[0] + task.todo.user_image = frappe.db.get_value('User', task.todo.owner, 'user_image') + + return tasks + +@frappe.whitelist() +def get_tasks_html(project, start=0, taskstatus=None): + return frappe.render_template("erpnext/templates/includes/projects/project_tasks.html", + {"doc": {"tasks": get_tasks(project, start, taskstatus=taskstatus)}}, is_path=True) + + +def get_issues(project, start=0, search=None, issuestatus=None): + print issuestatus + filters = {"project": project} + if search: + filters["subject"] = ("like", "%{0}%".format(search)) + if issuestatus: + filters = {"status": issuestatus} + issues = frappe.get_all("Issue", filters=filters, + fields=["name", "subject", "status", "opening_date", "resolution_date", "resolution_details"], + order_by='modified desc', + limit_start=start, limit_page_length=5) + + for issue in issues: + issue.todo = frappe.get_all('ToDo',filters={'reference_name':issue.name, 'reference_type':'Issue'}, + fields=["assigned_by", "owner", "modified", "modified_by"]) + if issue.todo: + issue.todo=issue.todo[0] + issue.todo.user_image = frappe.db.get_value('User', issue.todo.owner, 'user_image') + + return issues + +@frappe.whitelist() +def get_issues_html(project, start=0, issuestatus=None): + print issuestatus + return frappe.render_template("erpnext/templates/includes/projects/project_issues.html", + {"doc": {"issues": get_issues(project, start, issuestatus=issuestatus)}}, is_path=True) + +def get_timelogs(project, start=0, search=None): + filters = {"project": project} + if search: + filters["title"] = ("like", "%{0}%".format(search)) + + timelogs = frappe.get_all('Time Log', filters=filters, + fields=['name','title','task','activity_type','from_time','to_time','hours','status','modified','modified_by'], + limit_start=start, limit_page_length=2) + for timelog in timelogs: + timelog.user_image = frappe.db.get_value('User', timelog.modified_by, 'user_image') + return timelogs + +@frappe.whitelist() +def get_timelogs_html(project, start=0): + return frappe.render_template("erpnext/templates/includes/projects/project_timelogs.html", + {"doc": {"timelogs": get_timelogs(project, start)}}, is_path=True) + +@frappe.whitelist() +def set_task_status(project, task_name): + task = frappe.get_doc("Task", task_name) + task.status = 'Closed' + task.save(ignore_permissions=True) + +@frappe.whitelist() +def set_issue_status(project, issue_name): + issue = frappe.get_doc("Issue", issue_name) + issue.status = 'Closed' + issue.save(ignore_permissions=True) + + \ No newline at end of file diff --git a/erpnext/templates/pages/task_info.html b/erpnext/templates/pages/task_info.html new file mode 100644 index 0000000000..c756cd5679 --- /dev/null +++ b/erpnext/templates/pages/task_info.html @@ -0,0 +1,149 @@ +{% extends "templates/web.html" %} +{% block title %} {{ doc.name }} {% endblock %} +{% block breadcrumbs %} + +{% endblock %} +{% block page_content %} +
+
+

{{ doc.subject }}

+
+ +
+
+ + + Cancel +
+
+
+ +
+
+ + + + + +
+
+
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+
+
+
+
+ +
+

Comments

+
+ {% for comment in comments %} +

{{comment.sender_full_name}} : {{comment.subject}} on {{comment.communication_date.strftime('%Y-%m-%d')}}

+ {% endfor %} +
+
+ Add Comment + +
+
+ + +{% endblock %} \ No newline at end of file diff --git a/erpnext/templates/pages/task_info.py b/erpnext/templates/pages/task_info.py new file mode 100644 index 0000000000..b832b88048 --- /dev/null +++ b/erpnext/templates/pages/task_info.py @@ -0,0 +1,14 @@ +from __future__ import unicode_literals +import frappe + +from frappe import _ + +def get_context(context): + context.no_cache = 1 + + task = frappe.get_doc('Task', frappe.form_dict.task) + + context.comments = frappe.get_all('Communication', filters={'reference_name': task.name, 'comment_type': 'comment'}, + fields=['subject', 'sender_full_name', 'communication_date']) + + context.doc = task \ No newline at end of file diff --git a/erpnext/templates/pages/timelog_info.html b/erpnext/templates/pages/timelog_info.html new file mode 100644 index 0000000000..76dbc3271e --- /dev/null +++ b/erpnext/templates/pages/timelog_info.html @@ -0,0 +1,48 @@ +{% extends "templates/web.html" %} +{% block title %} {{ doc.name }} {% endblock %} +{% block breadcrumbs %} + +{% endblock %} + +{% block page_content %} +
+

{{ doc.name }}

+
+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+
+
+{% endblock %} \ No newline at end of file diff --git a/erpnext/templates/pages/timelog_info.py b/erpnext/templates/pages/timelog_info.py new file mode 100644 index 0000000000..7a3361c2ef --- /dev/null +++ b/erpnext/templates/pages/timelog_info.py @@ -0,0 +1,11 @@ +from __future__ import unicode_literals +import frappe + +from frappe import _ + +def get_context(context): + context.no_cache = 1 + + timelog = frappe.get_doc('Time Log', frappe.form_dict.timelog) + + context.doc = timelog \ No newline at end of file From 2ad801cfd8b517fc0e6b93cade5ef30b382053fd Mon Sep 17 00:00:00 2001 From: Kanchan Chauhan Date: Tue, 22 Mar 2016 16:00:41 +0530 Subject: [PATCH 2/2] Minor Updates --- erpnext/templates/includes/projects.css | 72 +++--- .../includes/projects/project_issues.html | 2 +- .../includes/projects/project_tasks.html | 2 +- .../templates/includes/projects/timeline.html | 57 ++--- erpnext/templates/pages/projects.html | 15 +- erpnext/templates/pages/projects.js | 224 ++++++------------ erpnext/templates/pages/projects.py | 58 ++--- 7 files changed, 172 insertions(+), 258 deletions(-) diff --git a/erpnext/templates/includes/projects.css b/erpnext/templates/includes/projects.css index e08088092f..d3f2e1786e 100644 --- a/erpnext/templates/includes/projects.css +++ b/erpnext/templates/includes/projects.css @@ -31,19 +31,19 @@ .timeline-centered { position: relative; - margin-bottom: 30px; + margin-bottom: 10px; } .timeline-centered:before { content: ''; position: absolute; display: block; - width: 4px; + width: 3px; background: #f5f5f6; /*left: 50%;*/ - top: 20px; - bottom: 20px; - margin-left: 30px; + top: 0px; + bottom: 0px; + margin-left: 10px; } .timeline-centered .timeline-entry { @@ -51,37 +51,25 @@ /*width: 50%; float: right;*/ margin-top: 5px; - margin-left: 30px; - margin-bottom: 10px; + margin-left: 10px; + margin-bottom: 5px; clear: both; } - -.timeline-centered .timeline-entry.left-aligned .timeline-entry-inner .timeline-label:after { - left: auto; - right: 0; - margin-left: 0; - margin-right: -9px; - -moz-transform: rotate(180deg); - -o-transform: rotate(180deg); - -webkit-transform: rotate(180deg); - -ms-transform: rotate(180deg); - transform: rotate(180deg); -} - .timeline-centered .timeline-entry .timeline-entry-inner { position: relative; - margin-left: -20px; + margin-left: -3px; } .timeline-centered .timeline-entry .timeline-entry-inner .timeline-icon { + margin-top:10px; background: #fff; color: #737881; display: block; - width: 40px; - height: 40px; + width: 10px; + height: 10px; -webkit-background-clip: padding-box; -moz-background-clip: padding; background-clip: padding-box; @@ -89,17 +77,41 @@ float: right;*/ -moz-border-radius: 20px; border-radius: 20px; text-align: center; - -moz-box-shadow: 0 0 0 5px #f5f5f6; - -webkit-box-shadow: 0 0 0 5px #f5f5f6; - box-shadow: 0 0 0 5px #f5f5f6; - line-height: 40px; - font-size: 15px; + -moz-box-shadow: 0 0 0 2px #f5f5f6; + -webkit-box-shadow: 0 0 0 2px #f5f5f6; + box-shadow: 0 0 0 2px #f5f5f6; + line-height: 30px; float: left; } +.timeline-centered .timeline-entry .timeline-entry-inner .timeline-icon.bg-primary { + background-color: #303641; + color: #fff; +} + +.timeline-centered .timeline-entry .timeline-entry-inner .timeline-icon.bg-secondary { + background-color: #ee4749; + color: #fff; +} + +.timeline-centered .timeline-entry .timeline-entry-inner .timeline-icon.bg-success { + background-color: #98d85b; + color: #fff; +} + +.timeline-centered .timeline-entry .timeline-entry-inner .timeline-icon.bg-info { + background-color: #21a9e1; + color: #fff; +} + .timeline-centered .timeline-entry .timeline-entry-inner .timeline-icon.bg-warning { - background-color: #fad839; + background-color: #ffa00a; + color: #fff; +} + +.timeline-centered .timeline-entry .timeline-entry-inner .timeline-icon.bg-danger { + background-color: #ff5858; color: #fff; } @@ -108,7 +120,7 @@ float: right;*/ position: relative; background: #f5f5f6; padding: 1em; - margin-left: 60px; + margin-left: 40px; -webkit-background-clip: padding-box; -moz-background-clip: padding; background-clip: padding-box; diff --git a/erpnext/templates/includes/projects/project_issues.html b/erpnext/templates/includes/projects/project_issues.html index 14ce70f1ad..34f6633af1 100644 --- a/erpnext/templates/includes/projects/project_issues.html +++ b/erpnext/templates/includes/projects/project_issues.html @@ -3,7 +3,7 @@
- + {% if issue.status == "Closed" %} {{ issue.subject }} resolved {{ frappe.utils.pretty_date(issue.resolution_date) }} {% else %} diff --git a/erpnext/templates/includes/projects/project_tasks.html b/erpnext/templates/includes/projects/project_tasks.html index 84de0e8914..b2be27babf 100644 --- a/erpnext/templates/includes/projects/project_tasks.html +++ b/erpnext/templates/includes/projects/project_tasks.html @@ -3,7 +3,7 @@
- + {% if task.status == "Closed" %} {{ task.subject }} completed on {{ task.closing_date }} {% else %} diff --git a/erpnext/templates/includes/projects/timeline.html b/erpnext/templates/includes/projects/timeline.html index 77b0c7609a..605404bb9f 100644 --- a/erpnext/templates/includes/projects/timeline.html +++ b/erpnext/templates/includes/projects/timeline.html @@ -1,44 +1,17 @@ {% for timeline in doc.timelines %} -
-
-
- - - {{timeline.reference_name}} {{timeline.subject }} - - - {{ frappe.utils.pretty_date(timeline.creation) }} - +
+
+
+
+
+ + + {{timeline.reference_name}} {{timeline.subject }} + + + {{ frappe.utils.pretty_date(timeline.creation) }} + +
-
-
-{% endfor %} - \ No newline at end of file + +{% endfor %} \ No newline at end of file diff --git a/erpnext/templates/pages/projects.html b/erpnext/templates/pages/projects.html index bbc5c6ebc8..c71cf2ec08 100644 --- a/erpnext/templates/pages/projects.html +++ b/erpnext/templates/pages/projects.html @@ -2,6 +2,17 @@ {% block title %}{{ doc.project_name }}{% endblock %} +{% block breadcrumbs %} +
+{% endblock %} + {% block header %}

{{ doc.project_name }} @@ -24,7 +35,7 @@ Filtered by "{{ frappe.form_dict.q }}" Clear

{% else %}

{{ _("Activity Feed") }}

-
+
{% include "erpnext/templates/includes/projects/timeline.html" %}
{% if doc.timelines|length > 9 %} @@ -40,7 +51,7 @@

{{ _("Tasks") }}

- +
diff --git a/erpnext/templates/pages/projects.js b/erpnext/templates/pages/projects.js index 87a1ab7b5a..b1468eba2f 100644 --- a/erpnext/templates/pages/projects.js +++ b/erpnext/templates/pages/projects.js @@ -1,172 +1,110 @@ frappe.ready(function() { - var reload_tasks = function(taskstatus) { - $.ajax({ - method: "GET", - url: "/", - dataType: "json", - data: { - cmd: "erpnext.templates.pages.projects.get_tasks_html", - project: '{{ doc.name }}', - taskstatus: taskstatus, - }, - dataType: "json", - success: function(data) { - $('.project-tasks').html(data.message); - - $('.project-tasks-section .btn-group .btn-primary').removeClass('btn-primary'); - $('.btn-'+ taskstatus +'-tasks').addClass( "btn-primary" ); - } - }); - - } + $( window ).load(function() { + $(".btn-open-tasks").click(); + $(".btn-open-issues").click(); + }); $('.btn-closed-tasks').click(function() { - reload_tasks('closed'); + reload_items('closed','tasks'); }); - $('.btn-open-tasks').click(function() { - reload_tasks('open'); - }); - var reload_issues = function(issuestatus) { + $('.btn-open-tasks').click(function() { + reload_items('open','tasks'); + }); + + $('.btn-closed-issues').click(function() { + reload_items('closed','issues'); + }); + + $('.btn-open-issues').click(function() { + reload_items('open','issues'); + }); + + var start = 10; + $(".more-tasks").click(function() { + more_items('tasks', true); + }); + + $(".more-issues").click(function() { + more_items('issues', true); + }); + + $(".more-timelogs").click(function() { + more_items('timelogs', false); + }); + + $(".more-timelines").click(function() { + more_items('timelines', false); + }); + + $( ".project-tasks" ).on('click', '.task-x', function() { + var item_name = $(this).attr('id'); + close_item('task', item_name); + }); + + $( ".project-issues" ).on('click', '.issue-x', function() { + var item_name = $(this).attr('id'); + close_item('issue', item_name); + }); + + var reload_items = function(item_status, item) { $.ajax({ method: "GET", url: "/", dataType: "json", data: { - cmd: "erpnext.templates.pages.projects.get_issues_html", + cmd: "erpnext.templates.pages.projects.get_"+ item +"_html", project: '{{ doc.name }}', - issuestatus: issuestatus, + item_status: item_status, }, dataType: "json", success: function(data) { - $('.project-issues').html(data.message); + $('.project-'+ item).html(data.message); - $('.project-issues-section .btn-group .btn-primary').removeClass('btn-primary'); - $('.btn-'+ issuestatus +'-issues').addClass( "btn-primary" ); + $('.project-'+ item +'-section .btn-group .btn-primary').removeClass('btn-primary'); + $('.btn-'+ item_status +'-'+ item).addClass( "btn-primary" ); + $(".more-"+ item).toggle(true); } }); } - $('.btn-closed-issues').click(function() { - reload_issues('closed'); - }); - $('.btn-open-issues').click(function() { - reload_issues('open'); - }); - - var taskstart = 5; - $(".more-tasks").click(function() { - var task_status = $('.project-tasks-section .btn-group .btn-primary').hasClass('btn-closed-tasks') - ? 'closed' : 'open'; - + var more_items = function(item, item_status){ + if(item_status) + { + var item_status = $('.project-'+ item +'-section .btn-group .btn-primary').hasClass('btn-closed-'+ item) + ? 'closed' : 'open'; + } $.ajax({ method: "GET", url: "/", dataType: "json", data: { - cmd: "erpnext.templates.pages.projects.get_tasks_html", + cmd: "erpnext.templates.pages.projects.get_"+ item +"_html", project: '{{ doc.name }}', - start: taskstart, - taskstatus: task_status, + start: start, + item_status: item_status, }, dataType: "json", success: function(data) { - $(data.message).appendTo('.project-tasks'); + $(data.message).appendTo('.project-'+ item); if(typeof data.message == 'undefined') { - $(".more-tasks").toggle(false); + $(".more-"+ item).toggle(false); } - taskstart = taskstart+5; + start = start+10; } - }); - - }); + }); + } - var issuestart = 2; - $(".more-issues").click(function() { - var issue_status = $('.project-issues-section .btn-group .btn-primary').hasClass('btn-closed-issues') - ? 'closed' : 'open'; - - $.ajax({ - method: "GET", - url: "/", - dataType: "json", - data: { - cmd: "erpnext.templates.pages.projects.get_issues_html", - project: '{{ doc.name }}', - start: issuestart, - issuestatus: issue_status, - }, - dataType: "json", - success: function(data) { - $(data.message).appendTo('.project-issues'); - if(typeof data.message == 'undefined') - { - $(".more-issues").toggle(false); - } - issuestart = issuestart+5; - } - }); - }); - - var timelogstart = 2; - $(".more-timelogs").click(function() { - $.ajax({ - method: "GET", - url: "/", - dataType: "json", - data: { - cmd: "erpnext.templates.pages.projects.get_timelogs_html", - project: '{{ doc.name }}', - start: timelogstart, - }, - dataType: "json", - success: function(data) { - $(data.message).appendTo('.project-timelogs'); - if(typeof data.message == 'undefined') - { - $(".more-timelogs").toggle(false); - } - timelogstart = timelogstart+2; - - } - }); - - }); - - var timelinestart = 10; - $(".more-timelines").click(function() { - $.ajax({ - method: "GET", - url: "/", - dataType: "json", - data: { - cmd: "erpnext.templates.pages.projects.get_timeline_html", - project: '{{ doc.name }}', - start: timelinestart, - - }, - dataType: "json", - success: function(data) { - $(data.message).appendTo('.project-timeline'); - if(typeof data.message == 'undefined') - { - $(".more-timelines").toggle(false); - } - timelinestart = timelinestart+10; - } - }); - }); - - $( ".project-tasks" ).on('click', '.task-x', function() { + var close_item = function(item, item_name){ var args = { project: '{{ doc.name }}', - task_name: $(this).attr('id'), - } + item_name: item_name, + } frappe.call({ btn: this, type: "POST", - method: "erpnext.templates.pages.projects.set_task_status", + method: "erpnext.templates.pages.projects.set_"+ item +"_status", args: args, callback: function(r) { if(r.exc) { @@ -178,27 +116,5 @@ frappe.ready(function() { } }) return false; - }); - - $( ".project-issues" ).on('click', '.issue-x', function() { - var args = { - project: '{{ doc.name }}', - issue_name: $(this).attr('id'), - } - frappe.call({ - btn: this, - type: "POST", - method: "erpnext.templates.pages.projects.set_issue_status", - args: args, - callback: function(r) { - if(r.exc) { - if(r._server_messages) - frappe.msgprint(r._server_messages); - } else { - $(this).remove(); - } - } - }) - return false; - }); + } }); diff --git a/erpnext/templates/pages/projects.py b/erpnext/templates/pages/projects.py index 7d0d2009fe..758113f660 100644 --- a/erpnext/templates/pages/projects.py +++ b/erpnext/templates/pages/projects.py @@ -32,39 +32,43 @@ def get_context(context): def get_timeline(project, start=10): issue_names = '({0})'.format(", ".join(["'{0}'".format(i.name) for i in get_issues(project)])) - print issue_names - timelines = frappe.db.sql("""select sender_full_name, - subject, communication_date, comment_type, name, creation, modified_by, reference_doctype, reference_name, - _liked_by, comment_type, _comments - from tabCommunication - where (reference_doctype='Project' and reference_name=%s) + timelines = frappe.db.sql(""" + select + sender_full_name, + subject, communication_date, comment_type, name, creation, modified_by, reference_doctype, reference_name, + _liked_by, comment_type, _comments + from + tabCommunication + where + (reference_doctype='Project' and reference_name=%s) or (timeline_doctype='Project' and timeline_name=%s) or (reference_doctype='Issue' and reference_name IN {issue_names}) - order by modified DESC limit {start}, {limit}""".format( + order by + modified DESC limit {start}, {limit}""".format( issue_names=issue_names, start=start, limit=10), - (project, project), as_dict=True); + (project, project), as_dict=True); for timeline in timelines: timeline.user_image = frappe.db.get_value('User', timeline.modified_by, 'user_image') return timelines @frappe.whitelist() -def get_timeline_html(project, start=0): +def get_timelines_html(project, start=0): return frappe.render_template("erpnext/templates/includes/projects/timeline.html", {"doc": {"timelines": get_timeline(project, start)}}, is_path=True) def get_issue_list(project): return [issue.name for issue in get_issues(project)] -def get_tasks(project, start=0, search=None, taskstatus=None): +def get_tasks(project, start=0, search=None, item_status=None): filters = {"project": project} if search: filters["subject"] = ("like", "%{0}%".format(search)) - if taskstatus: - filters = {"status": taskstatus} + if item_status: + filters = {"status": item_status} tasks = frappe.get_all("Task", filters=filters, fields=["name", "subject", "status", "exp_start_date", "exp_end_date", "priority"], - limit_start=start, limit_page_length=5) + limit_start=start, limit_page_length=10) for task in tasks: task.todo = frappe.get_all('ToDo',filters={'reference_name':task.name, 'reference_type':'Task'}, @@ -76,22 +80,21 @@ def get_tasks(project, start=0, search=None, taskstatus=None): return tasks @frappe.whitelist() -def get_tasks_html(project, start=0, taskstatus=None): +def get_tasks_html(project, start=0, item_status=None): return frappe.render_template("erpnext/templates/includes/projects/project_tasks.html", - {"doc": {"tasks": get_tasks(project, start, taskstatus=taskstatus)}}, is_path=True) + {"doc": {"tasks": get_tasks(project, start, item_status=item_status)}}, is_path=True) -def get_issues(project, start=0, search=None, issuestatus=None): - print issuestatus +def get_issues(project, start=0, search=None, item_status=None): filters = {"project": project} if search: filters["subject"] = ("like", "%{0}%".format(search)) - if issuestatus: - filters = {"status": issuestatus} + if item_status: + filters = {"status": item_status} issues = frappe.get_all("Issue", filters=filters, fields=["name", "subject", "status", "opening_date", "resolution_date", "resolution_details"], order_by='modified desc', - limit_start=start, limit_page_length=5) + limit_start=start, limit_page_length=10) for issue in issues: issue.todo = frappe.get_all('ToDo',filters={'reference_name':issue.name, 'reference_type':'Issue'}, @@ -103,10 +106,9 @@ def get_issues(project, start=0, search=None, issuestatus=None): return issues @frappe.whitelist() -def get_issues_html(project, start=0, issuestatus=None): - print issuestatus +def get_issues_html(project, start=0, item_status=None): return frappe.render_template("erpnext/templates/includes/projects/project_issues.html", - {"doc": {"issues": get_issues(project, start, issuestatus=issuestatus)}}, is_path=True) + {"doc": {"issues": get_issues(project, start, item_status=item_status)}}, is_path=True) def get_timelogs(project, start=0, search=None): filters = {"project": project} @@ -115,7 +117,7 @@ def get_timelogs(project, start=0, search=None): timelogs = frappe.get_all('Time Log', filters=filters, fields=['name','title','task','activity_type','from_time','to_time','hours','status','modified','modified_by'], - limit_start=start, limit_page_length=2) + limit_start=start, limit_page_length=10) for timelog in timelogs: timelog.user_image = frappe.db.get_value('User', timelog.modified_by, 'user_image') return timelogs @@ -126,14 +128,14 @@ def get_timelogs_html(project, start=0): {"doc": {"timelogs": get_timelogs(project, start)}}, is_path=True) @frappe.whitelist() -def set_task_status(project, task_name): - task = frappe.get_doc("Task", task_name) +def set_task_status(project, item_name): + task = frappe.get_doc("Task", item_name) task.status = 'Closed' task.save(ignore_permissions=True) @frappe.whitelist() -def set_issue_status(project, issue_name): - issue = frappe.get_doc("Issue", issue_name) +def set_issue_status(project, item_name): + issue = frappe.get_doc("Issue", item_name) issue.status = 'Closed' issue.save(ignore_permissions=True)