Amit Patel (OpenERP) has proposed merging
lp:~openerp-dev/openobject-addons/trunk-project-gallery-apa into
lp:openobject-addons.
Requested reviews:
Raphael Collet (OpenERP) (rco-openerp)
For more details, see:
https://code.launchpad.net/~openerp-dev/openobject-addons/trunk-project-gallery-apa/+merge/104092
Hello,
[ADD]:Added kanban view for project.
more detail in this pad :
http://pad.openerp.com/rd-v62-project-task-227-HGIX0GS8
Thanks,
Amit
--
https://code.launchpad.net/~openerp-dev/openobject-addons/trunk-project-gallery-apa/+merge/104092
Your team OpenERP R&D Team is subscribed to branch
lp:~openerp-dev/openobject-addons/trunk-project-gallery-apa.
=== modified file 'analytic/analytic.py'
--- analytic/analytic.py 2012-03-30 09:08:37 +0000
+++ analytic/analytic.py 2012-05-09 08:27:20 +0000
@@ -96,6 +96,8 @@
return self._compute_level_tree(cr, uid, ids, child_ids, res, fields, context)
def name_get(self, cr, uid, ids, context=None):
+ if isinstance(ids, (int, long)):
+ ids=[ids]
if not ids:
return []
res = []
@@ -132,7 +134,7 @@
return accounts
def _set_company_currency(self, cr, uid, ids, name, value, arg, context=None):
- if type(ids) != type([]):
+ if isinstance(ids, (int, long)):
ids=[ids]
for account in self.browse(cr, uid, ids, context=context):
if account.company_id:
=== modified file 'project/__openerp__.py'
--- project/__openerp__.py 2012-04-10 12:09:38 +0000
+++ project/__openerp__.py 2012-05-09 08:27:20 +0000
@@ -29,7 +29,7 @@
"sequence": 8,
'complexity': "easy",
"images": ["images/gantt.png", "images/project_dashboard.jpeg","images/project_task_tree.jpeg","images/project_task.jpeg","images/project.jpeg","images/task_analysis.jpeg"],
- "depends": ["base_setup", "product", "analytic", "board", "mail", "resource"],
+ "depends": ["base_setup", "product", "analytic", "board", "mail", "resource","web_kanban"],
"description": """
Project management module tracks multi-level projects, tasks, work done on tasks, eso.
======================================================================================
@@ -70,6 +70,8 @@
'installable': True,
'auto_install': False,
'application': True,
+ 'css': ['static/src/css/project.css'],
+ 'js': ['static/src/js/dropdown.js','static/src/js/project.js'],
'certificate': '0075116868317',
}
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
=== modified file 'project/project.py'
--- project/project.py 2012-04-03 17:21:08 +0000
+++ project/project.py 2012-05-09 08:27:20 +0000
@@ -155,6 +155,13 @@
raise osv.except_osv(_('Operation Not Permitted !'), _('You cannot delete a project containing tasks. I suggest you to desactivate it.'))
return super(project, self).unlink(cr, uid, ids, *args, **kwargs)
+ def _task_count(self, cr, uid, ids, field_name, arg, context=None):
+ res = dict.fromkeys(ids, 0)
+ task_ids = self.pool.get('project.task').search(cr, uid, [('project_id', 'in', ids)])
+ for task in self.pool.get('project.task').browse(cr, uid, task_ids, context):
+ res[task.project_id.id] += 1
+ return res
+
_columns = {
'complete_name': fields.function(_complete_name, string="Project Name", type='char', size=250),
'active': fields.boolean('Active', help="If the active field is set to False, it will allow you to hide the project without removing it."),
@@ -191,7 +198,15 @@
'warn_header': fields.text('Mail Header', help="Header added at the beginning of the email for the warning message sent to the customer when a task is closed.", states={'close':[('readonly',True)], 'cancelled':[('readonly',True)]}),
'warn_footer': fields.text('Mail Footer', help="Footer added at the beginning of the email for the warning message sent to the customer when a task is closed.", states={'close':[('readonly',True)], 'cancelled':[('readonly',True)]}),
'type_ids': fields.many2many('project.task.type', 'project_task_type_rel', 'project_id', 'type_id', 'Tasks Stages', states={'close':[('readonly',True)], 'cancelled':[('readonly',True)]}),
+ 'use_tasks': fields.boolean('Use Tasks', help="Check this field if this project is aimed at managing tasks"),
+ 'task_count': fields.function(_task_count, type='integer', string="Open Tasks"),
+ 'color': fields.integer('Color Index'),
+ 'company_uom_id': fields.related('company_id', 'project_time_mode_id', type='many2one', relation='product.uom'),
}
+
+ def dummy(self, cr, uid, ids, context):
+ return True
+
def _get_type_common(self, cr, uid, context):
ids = self.pool.get('project.task.type').search(cr, uid, [('project_default','=',1)], context=context)
return ids
@@ -201,7 +216,8 @@
'active': True,
'priority': 1,
'sequence': 10,
- 'type_ids': _get_type_common
+ 'type_ids': _get_type_common,
+ 'use_tasks': True,
}
# TODO: Why not using a SQL contraints ?
=== modified file 'project/project_view.xml'
--- project/project_view.xml 2012-04-25 14:02:12 +0000
+++ project/project_view.xml 2012-05-09 08:27:20 +0000
@@ -43,12 +43,17 @@
</group>
<notebook colspan="4">
<page string="Administration">
+ <group col="2" colspan="2" name="kanban">
+ <separator colspan="2" string="Project Management"/>
+ <field name="use_tasks"/>
+ </group>
<group col="2" colspan="2">
- <separator colspan="2" string="Performance"/>
+ <separator colspan="4" string="Performance"/>
<field name="planned_hours" widget="float_time"/>
<field name="effective_hours" widget="float_time" />
<field name="resource_calendar_id"/>
</group>
+ <newline/>
<group col="2" colspan="2" name="misc">
<separator colspan="4" string="Miscelleanous"/>
<field name="company_id" select="1" groups="base.group_multi_company" widget="selection" required="1"/>
@@ -155,6 +160,94 @@
</tree>
</field>
</record>
+
+ <act_window
+ context="{'search_default_project_id': [active_id], 'default_project_id': active_id}"
+ id="act_project_project_2_project_task_all"
+ name="Tasks"
+ res_model="project.task"
+ src_model="project.project"
+ view_mode="kanban,tree,form,calendar,graph"
+ view_type="form"/>
+
+
+ <record model="ir.ui.view" id="view_project_kanban">
+ <field name="name">project.project.kanban</field>
+ <field name="model">project.project</field>
+ <field name="type">kanban</field>
+ <field name="arch" type="xml">
+ <kanban>
+ <field name="effective_hours"/>
+ <field name="planned_hours"/>
+ <field name="name"/>
+ <field name="members"/>
+ <field name="use_tasks"/>
+ <field name="user_id"/>
+ <field name="date"/>
+ <field name="color"/>
+ <field name="task_count"/>
+ <templates>
+ <t t-name="kanban-box">
+ <div class="project_vignettes">
+ <li t-attf-class="#{kanban_color(record.color.raw_value)} oe_project_kanban_vignette" id="oe_project_kanban_vignette">
+ <a href="#" class="oe_project_kanban_action dropdown-toggle"><span class="oe_i">B</span></a>
+ <ul class="dropdown-menu">
+ <li ><a type="edit" >Edit...</a></li>
+ <li ><a type="delete">Delete</a></li>
+ <li>
+ <ul class="color-chooser">
+ <li><a t-att-id="record.id.value" class="bgcolor"><span class="oe_kanban_color_0 square"></span></a></li>
+ <li><a t-att-id="record.id.value" class="bgcolor"><span class="oe_kanban_color_1 square"></span></a></li>
+ <li><a t-att-id="record.id.value" class="bgcolor"><span class="oe_kanban_color_2 square"></span></a></li>
+ <li><a t-att-id="record.id.value" class="bgcolor"><span class="oe_kanban_color_3 square"></span></a></li>
+ <li><a t-att-id="record.id.value" class="bgcolor"><span class="oe_kanban_color_4 square"></span></a></li>
+ <li><a t-att-id="record.id.value" class="bgcolor"><span class="oe_kanban_color_5 square"></span></a></li>
+ </ul>
+ </li>
+ </ul>
+ <h4><t t-esc="record.name.value.substr(0,33)"/><t t-if="record.name.value.length > 33">...</t></h4>
+ <div id="list">
+ <a t-if="record.use_tasks.raw_value" class="oe_project_buttons"
+ id="1" name="%(act_project_project_2_project_task_all)d" type="action">
+ Tasks(<field name="task_count"/>)</a>
+ </div>
+ <br/>
+ <button class="click_button" name="dummy" type="object">
+ <table class="project_fields">
+ <tr id="deadline" t-if="record.date.raw_value">
+ <th align="left">Deadline</th>
+ <td align="left"><field name="date"/></td>
+ </tr>
+ <tr>
+ <th align="left" width="70px">Progress</th>
+ <td align="left">
+ <t t-esc="Math.round(record.effective_hours.raw_value)"/> / <t t-esc="Math.round(record.planned_hours.raw_value)"/> <field name="company_uom_id"/>
+ </td>
+ </tr>
+ </table>
+ <br/>
+ <t t-foreach="record.members.raw_value" t-as="member">
+ <img t-att-src="kanban_image('res.users', 'avatar', member)" t-att-id="member" class="project_avatar"/>
+ </t>
+ </button>
+ </li>
+ </div>
+ <script type="text/javascript">
+ //open dropdwon when click on the icon.
+ $('.dropdown-toggle').dropdown();
+
+ //show and hide the dropdown icon when mouseover and mouseour.
+ $('.oe_project_kanban_vignette').mouseover(function() {
+ return $(this).find('.oe_project_kanban_action').show();
+ }).mouseout(function() {
+ return $(this).find('.oe_project_kanban_action').hide();
+ });
+ </script>
+ </t>
+ </templates>
+ </kanban>
+ </field>
+ </record>
<record id="view_project_project_gantt" model="ir.ui.view">
<field name="name">project.project.gantt</field>
@@ -171,8 +264,8 @@
<field name="res_model">project.project</field>
<field name="view_type">form</field>
<field name="domain">[]</field>
- <field name="view_mode">tree,form,gantt</field>
- <field name="view_id" ref="view_project"/>
+ <field name="view_mode">kanban,tree,form,gantt</field>
+ <field name="view_id" ref="view_project_kanban"/>
<field name="search_view_id" ref="view_project_project_filter"/>
<field name="context">{}</field>
<field name="help">A project contains a set of tasks or issues that will be performed by your resources assigned to it. A project can be hierarchically structured, as a child of a Parent Project. This allows you to design large project structures with different phases spread over the project duration cycle. Each user can set his default project in his own preferences to automatically filter the tasks or issues he usually works on. If you choose to invoice the time spent on a project task, you can find project tasks to be invoiced in the billing section.</field>
@@ -314,8 +407,7 @@
</form>
</field>
</record>
-
-
+
<!-- Project Task Kanban View -->
<record model="ir.ui.view" id="view_task_kanban">
<field name="name">project.task.kanban</field>
@@ -627,22 +719,13 @@
<menuitem id="menu_tasks_config" name="GTD" parent="project.menu_definitions" sequence="1"/>
- <menuitem id="menu_project_config_project" name="Projects and Stages" parent="menu_definitions" sequence="1"/>
+ <menuitem id="menu_project_config_project" name="Stages" parent="menu_definitions" sequence="1"/>
<menuitem action="open_task_type_form" id="menu_task_types_view" parent="menu_project_config_project" sequence="2" groups="base.group_no_one"/>
- <menuitem action="open_view_project_all" id="menu_open_view_project_all" parent="menu_project_config_project" sequence="1" groups="base.group_no_one"/>
+ <menuitem action="open_view_project_all" id="menu_projects" name="Projects" parent="menu_project_management" sequence="1"/>
<act_window context="{'search_default_user_id': [active_id], 'default_user_id': active_id}" id="act_res_users_2_project_project" name="User's projects" res_model="project.project" src_model="res.users" view_mode="tree,form" view_type="form"/>
- <act_window
- context="{'search_default_project_id': [active_id], 'default_project_id': active_id}"
- id="act_project_project_2_project_task_all"
- name="Tasks"
- res_model="project.task"
- src_model="project.project"
- view_mode="tree,form,calendar,graph"
- view_type="form"/>
-
<record id="task_company" model="ir.ui.view">
<field name="name">res.company.task.config</field>
<field name="model">res.company</field>
=== added directory 'project/static/src/css'
=== added file 'project/static/src/css/project.css'
--- project/static/src/css/project.css 1970-01-01 00:00:00 +0000
+++ project/static/src/css/project.css 2012-05-09 08:27:20 +0000
@@ -0,0 +1,220 @@
+.project_fields {
+ margin-top: 1px;
+ margin-bottom: 1px;
+ font-size: 11px;
+ padding-left: 0px;
+ }
+.project_fields td {
+ border: none;
+ padding: 2px 0 2px 8px; }
+.project_fields th {
+ padding: 0;
+ border-right: 1px solid #dddddd;
+ vertical-align: top;
+ margin-right: 8px; }
+.project_vignettes{
+ padding: 4px !important }
+ .project_vignettes li {
+ float: left;
+ }
+ .project_vignettes .project_avatar {
+ width: 30px;
+ height: 30px;
+ padding-left: 0px; }
+ .project_vignettes .project_fields {
+ width: 100%; }
+ .project_vignettes .project_fields th {
+ width: 120px;
+ font-weight: normal; }
+ .project_vignettes .project_fields td {
+ color: #888888; }
+ .project_vignettes h4 a {
+ color: #4c4c4c; }
+ .project_vignettes > li h4 {
+ margin-bottom: 2px;
+ padding-left: 2px; }
+
+.oe_project_buttons {
+ padding: 2px 2px !important;
+ background: none !important;
+ background-color: transparent !important;
+ border: hidden !important;
+ color: #8A89BA !important;
+}
+.oe_project_buttons:hover {
+ cursor: pointer;
+ color: #0000FF;
+}
+.project_avatar {
+ -moz-border-radius: 4px;
+ -webkit-border-radius: 4px;
+ border-radius: 4px;
+ -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
+ -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
+ -box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
+ }
+.click_button {
+ background: none !important;
+ background-color: transparent !important;
+ border: hidden !important;
+ min-height: 155px;
+ min-width: 265px;
+ border: hidden;
+ /*margin-left: 6px !important;*/
+ margin-top: 3px !important;
+ text-align: left;
+ vertical-align: super;
+ font-size: 11px;
+ -webkit-box-align: baseline;
+}
+
+
+.click_button:hover {
+ cursor: default !important;
+}
+.dropdown-menu {
+ display: none;
+ position: absolute; }
+.dropdown {
+ position: relative; }
+.dropdown-toggle:after {
+ width: 0;
+ height: 0;
+ display: inline-block;
+ content: "&darr";
+ text-indent: -99999px;
+ vertical-align: top;
+ margin-top: 8px;
+ margin-left: 4px;
+ border-left: 4px solid transparent;
+ border-right: 4px solid transparent;
+ border-top: 4px solid white;
+ filter: alpha(opacity=50);
+ -khtml-opacity: 0.5;
+ -moz-opacity: 0.5;
+ opacity: 0.5; }
+ .oe_project_kanban_vignette .dropdown-menu .color-chooser {
+ padding: 0 3px; }
+ .oe_project_kanban_vignette .dropdown-menu .color-chooser li {
+ float: left; }
+ .oe_project_kanban_vignette .dropdown-menu .color-chooser li a {
+ padding: 2px; }
+a.oe_project_kanban_action {
+ position: absolute;
+ right: 0;
+ display: none;
+ }
+ a.oe_project_kanban_action:hover {
+ text-decoration: none; }
+ a.oe_project_kanban_action .oe_i {
+ color: #4c4c4c; }
+
+.square {
+ display: inline-block;
+ width: 18px;
+ height: 18px;
+ border:1px solid grey;
+ }
+
+.oe_kanban_color_0 {
+ background: white;
+}
+.oe_kanban_color_1 {
+ background: #B1DCFE;
+}
+.oe_kanban_color_2 {
+ background: #FF8E8E;
+}
+.oe_kanban_color_3 {
+ background: khaki;
+}
+.oe_kanban_color_4 {
+ background: thistle;
+}
+.oe_kanban_color_5 {
+ background: orange;
+}
+
+.open {
+ display: block;
+ }
+ .open .dropdown-menu {
+ display: block; }
+
+a.oe_project_kanban_action {
+ position: absolute;
+ right: 0;
+ }
+ a.oe_project_kanban_action:hover {
+ text-decoration: none;
+ }
+ a.oe_project_kanban_action .eo_i {
+ color: #4c4c4c; }
+
+.oe_project_kanban_vignette {
+ position: relative;
+ min-height: 50px;
+ /*background: white;*/
+ border: 1px solid #d8d8d8;
+ border-bottom-color: #b9b9b9;
+ padding: 6px;
+ margin: 6px 0;
+ display: inline-block;
+ -moz-border-radius: 4px;
+ -webkit-border-radius: 4px;
+ border-radius: 4px;
+
+}
+ .oe_project_kanban_vignette:last-child {
+ margin-bottom: 0; }
+ .oe_project_kanban_vignette:hover {
+ -moz-box-shadow: 0 0 3px rgba(0, 0, 0, 0.6);
+ -webkit-box-shadow: 0 0 3px rgba(0, 0, 0, 0.6);
+ -box-shadow: 0 0 3px rgba(0, 0, 0, 0.6); }
+ .oe_project_kanban_vignette h4 {
+ margin: 0 0 2px; }
+
+.oe_project_kanban_vignette .dropdown-menu {
+ top: 30px;
+ right: -140px;
+ padding: 4px;
+ border: 1px solid #afafb6;
+ width: 160px;
+ overflow-x: hidden;
+ z-index: 900;
+ background: white;
+ -moz-border-radius: 3px;
+ -webkit-border-radius: 3px;
+ border-radius: 3px;
+ -moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
+ -webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
+ -box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3); }
+ .oe_project_kanban_vignette .dropdown-menu p {
+ margin-left: 12px; }
+ .oe_project_kanban_vignette .dropdown-menu li {
+ float: none;
+ display: block;
+ background-color: none; }
+ .oe_project_kanban_vignette .dropdown-menu li a {
+ display: block;
+ padding: 3px 6px;
+ clear: both;
+ font-weight: normal;
+ line-height: 14px;
+ color: #4c4c4c;
+ text-decoration: none; }
+ .oe_project_kanban_vignette .dropdown-menu li a:hover {
+ background: #f0f0fa;
+ background: -moz-linear-gradient(#f0f0fa, #eeeef6);
+ background: -webkit-gradient(linear, left top, left bottom, from(#f0f0fa), to(#eeeef6));
+ background: -webkit-linear-gradient(#f0f0fa, #eeeef6);
+ -moz-box-shadow: none;
+ -webkit-box-shadow: none;
+ -box-shadow: none; }
+
+.oe_project_kanban_vignette .dropdown-menu .color-chooser {
+ padding: 0 3px; }
+ .oe_project_kanban_vignette .dropdown-menu .color-chooser li {
+ float: left; }
+ .oe_project_kanban_vignette .dropdown-menu .color-chooser li a {
+ padding: 2px; }
=== added file 'project/static/src/img/tasks_icon.png'
Binary files project/static/src/img/tasks_icon.png 1970-01-01 00:00:00 +0000 and project/static/src/img/tasks_icon.png 2012-05-09 08:27:20 +0000 differ
=== added directory 'project/static/src/js'
=== added file 'project/static/src/js/dropdown.js'
--- project/static/src/js/dropdown.js 1970-01-01 00:00:00 +0000
+++ project/static/src/js/dropdown.js 2012-05-09 08:27:20 +0000
@@ -0,0 +1,92 @@
+/* ============================================================
+ * bootstrap-dropdown.js v2.0.2
+ * http://twitter.github.com/bootstrap/javascript.html#dropdowns
+ * ============================================================
+ * Copyright 2012 Twitter, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============================================================ */
+
+
+!function( $ ){
+
+ "use strict"
+
+ /* DROPDOWN CLASS DEFINITION
+ * ========================= */
+
+ var toggle = '[data-toggle="dropdown"]'
+ , Dropdown = function ( element ) {
+ var $el = $(element).on('click.dropdown.data-api', this.toggle)
+ $('html').on('click.dropdown.data-api', function () {
+ $el.parent().removeClass('open')
+ })
+ }
+
+ Dropdown.prototype = {
+
+ constructor: Dropdown
+
+ , toggle: function ( e ) {
+ var $this = $(this)
+ , selector = $this.attr('data-target')
+ , $parent
+ , isActive
+
+ if (!selector) {
+ selector = $this.attr('href')
+ selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
+ }
+
+ $parent = $(selector)
+ $parent.length || ($parent = $this.parent())
+
+ isActive = $parent.hasClass('open')
+
+ clearMenus()
+ !isActive && $parent.toggleClass('open')
+
+ return false
+ }
+
+ }
+
+ function clearMenus() {
+ $(toggle).parent().removeClass('open')
+ }
+
+
+ /* DROPDOWN PLUGIN DEFINITION
+ * ========================== */
+
+ $.fn.dropdown = function ( option ) {
+ return this.each(function () {
+ var $this = $(this)
+ , data = $this.data('dropdown')
+ if (!data) $this.data('dropdown', (data = new Dropdown(this)))
+ if (typeof option == 'string') data[option].call($this)
+ })
+ }
+
+ $.fn.dropdown.Constructor = Dropdown
+
+
+ /* APPLY TO STANDARD DROPDOWN ELEMENTS
+ * =================================== */
+
+ $(function () {
+ $('html').on('click.dropdown.data-api', clearMenus)
+ $('body').on('click.dropdown.data-api', toggle, Dropdown.prototype.toggle)
+ })
+
+}( window.jQuery );
\ No newline at end of file
=== added file 'project/static/src/js/project.js'
--- project/static/src/js/project.js 1970-01-01 00:00:00 +0000
+++ project/static/src/js/project.js 2012-05-09 08:27:20 +0000
@@ -0,0 +1,48 @@
+openerp.project = function(openerp) {
+ openerp.web_kanban.ProjectKanban = openerp.web_kanban.KanbanRecord.include({
+ bind_events: function() {
+ var self = this;
+ self._super();
+ if(this.view.dataset.model == 'project.project') {
+
+ /*set avatar title for members.
+ In many2many fields, returns only list of ids.
+ we can implement return value of m2m fields like [(1,"Adminstration"),...].
+ */
+ _.each($(this.$element).find('.project_avatar'),function(avatar){
+ var dataset = new openerp.web.DataSetSearch(this, 'res.users', self.session.context, [['id','=',avatar.id]]);
+ dataset.read_slice(['name']).then(function(result){
+ avatar.setAttribute("title",result[0].name)
+ });
+ });
+
+ // set sequence like Tasks,Issues,Timesheets and Phases
+ var my_list = $("#list a")
+ my_list.sort(function (a, b) {
+ var aValue = parseInt(a.id);
+ var bValue = parseInt(b.id);
+ return aValue == bValue ? 0 : aValue < bValue ? -1 : 1;
+ });
+ $('#list').replaceWith(my_list);
+
+ // when vignette is clicked, it opens the first action in sequence
+ if (my_list.length != 0) {
+ var click_button = $(this.$element).find('.click_button')
+ click_button.attr('data-name', my_list[0].getAttribute('data-name'));
+ click_button.attr('data-type', "action");
+ }
+
+ /* set background color.
+ we can do other way to implement new widget.
+ because we need to rpc call for that.
+ */
+ this.$element.find('.bgcolor').click(function(){
+ var color = parseInt($(this).find('span').attr('class').split(' ')[0].substring(16))
+ var color_class = $(this).find('span').attr('class').split(' ')[0]
+ $(this).closest('#oe_project_kanban_vignette').removeClass().addClass(color_class + ' oe_project_kanban_vignette');
+ self.view.dataset.write(parseInt(this.id), {color:color});
+ });
+ }
+ }
+ });
+}
=== modified file 'project_issue/project_issue.py'
--- project_issue/project_issue.py 2012-04-03 17:21:08 +0000
+++ project_issue/project_issue.py 2012-05-09 08:27:20 +0000
@@ -222,6 +222,8 @@
}),
}
+ def on_change_project(self, cr, uid, ids, project_id, context=None):
+ return {}
_defaults = {
'active': 1,
@@ -506,9 +508,23 @@
class project(osv.osv):
_inherit = "project.project"
+
+ def _issue_count(self, cr, uid, ids, field_name, arg, context=None):
+ res = dict.fromkeys(ids, 0)
+ issue_ids = self.pool.get('project.issue').search(cr, uid, [('project_id', 'in', ids)])
+ for issue in self.pool.get('project.issue').browse(cr, uid, issue_ids, context):
+ res[issue.project_id.id] += 1
+ return res
+
_columns = {
'project_escalation_id' : fields.many2one('project.project','Project Escalation', help='If any issue is escalated from the current Project, it will be listed under the project selected here.', states={'close':[('readonly',True)], 'cancelled':[('readonly',True)]}),
- 'reply_to' : fields.char('Reply-To Email Address', size=256)
+ 'reply_to' : fields.char('Reply-To Email Address', size=256),
+ 'use_issues' : fields.boolean('Use Issues', help="Check this field if this project manages issues"),
+ 'issue_count': fields.function(_issue_count, type='integer'),
+ }
+
+ _defaults = {
+ 'use_issues': True,
}
def _check_escalation(self, cr, uid, ids, context=None):
=== modified file 'project_issue/project_issue_menu.xml'
--- project_issue/project_issue_menu.xml 2012-04-05 16:55:29 +0000
+++ project_issue/project_issue_menu.xml 2012-05-09 08:27:20 +0000
@@ -45,15 +45,6 @@
<field name="act_window_id" ref="project_issue_categ_act0"/>
</record>
- <act_window
- context="{'search_default_project_id': [active_id], 'default_project_id': active_id}"
- id="act_project_project_2_project_issue_all"
- name="Issues"
- res_model="project.issue"
- src_model="project.project"
- view_mode="tree,form,calendar,graph"
- view_type="form"/>
-
<menuitem name="Issues" id="menu_project_issue_track" parent="project.menu_project_management"
action="project_issue_categ_act0" sequence="15"/>
</data>
=== modified file 'project_issue/project_issue_view.xml'
--- project_issue/project_issue_view.xml 2012-04-25 14:02:12 +0000
+++ project_issue/project_issue_view.xml 2012-05-09 08:27:20 +0000
@@ -334,6 +334,14 @@
</search>
</field>
</record>
+
+ <act_window id="act_project_project_2_project_issue_all"
+ name="Issues"
+ src_model="project.project"
+ res_model="project.issue"
+ view_type="form"
+ view_mode="kanban,tree,form,calendar,graph"
+ context="{'search_default_project_id': [active_id], 'default_project_id': active_id}"/>
# ------------------------------------------------------
# Project
@@ -345,12 +353,32 @@
<field name="type">form</field>
<field name="inherit_id" ref="project.edit_project"/>
<field name="arch" type="xml">
+ <field name="use_tasks" position="after">
+ <field name="use_issues"/>
+ </field>
<field name="priority" position="before">
<field name="project_escalation_id"/>
<field name="reply_to"/>
</field>
</field>
</record>
-
+
+ <record id="view_project_kanban_inherited" model="ir.ui.view">
+ <field name="name">project.project.kanban.inherited</field>
+ <field name="model">project.project</field>
+ <field name="type">kanban</field>
+ <field name="inherit_id" ref="project.view_project_kanban"/>
+ <field name="arch" type="xml">
+ <field name="use_tasks" position="after">
+ <field name="use_issues"/>
+ <field name="issue_count" invisible="1"/>
+ </field>
+ <xpath expr="//div[@id='list']" position="inside">
+ <a t-if="record.use_issues.raw_value" class="oe_project_buttons"
+ id="2" name="%(act_project_project_2_project_issue_all)d" type="action">
+ Issues(<field name="issue_count"/>)</a>
+ </xpath>
+ </field>
+ </record>
</data>
</openerp>
=== modified file 'project_long_term/project_long_term.py'
--- project_long_term/project_long_term.py 2012-01-31 13:36:57 +0000
+++ project_long_term/project_long_term.py 2012-05-09 08:27:20 +0000
@@ -123,6 +123,7 @@
_defaults = {
'state': 'draft',
'sequence': 10,
+ 'project_id':lambda self, cr, uid, context: context.get('active_id',False),
'product_uom': lambda self,cr,uid,c: self.pool.get('product.uom').search(cr, uid, [('name', '=', _('Day'))], context=c)[0]
}
_order = "project_id, date_start, sequence"
@@ -215,9 +216,23 @@
class project(osv.osv):
_inherit = "project.project"
+
+ def _phase_count(self, cr, uid, ids, field_name, arg, context=None):
+ res = dict.fromkeys(ids, 0)
+ phase_ids = self.pool.get('project.phase').search(cr, uid, [('project_id', 'in', ids)])
+ for phase in self.pool.get('project.phase').browse(cr, uid, phase_ids, context):
+ res[phase.project_id.id] += 1
+ return res
+
_columns = {
'phase_ids': fields.one2many('project.phase', 'project_id', "Project Phases"),
- }
+ 'use_phases': fields.boolean('Use Phases', help="Check this field if project manages phases"),
+ 'phase_count': fields.function(_phase_count, type='integer', string="Open Phases"),
+ }
+ _defaults = {
+ 'use_phases': True,
+ }
+
def schedule_phases(self, cr, uid, ids, context=None):
context = context or {}
if type(ids) in (long, int,):
=== modified file 'project_long_term/project_long_term_view.xml'
--- project_long_term/project_long_term_view.xml 2012-04-25 14:02:12 +0000
+++ project_long_term/project_long_term_view.xml 2012-05-09 08:27:20 +0000
@@ -84,12 +84,12 @@
</search>
</field>
</record>
- <record id="act_resouce_allocation" model="ir.actions.act_window">
+ <record id="act_resouce_allocation" model="ir.actions.act_window">
<field name="name">Planning of Users</field>
<field name="res_model">project.user.allocation</field>
<field name="view_type">form</field>
<field name="view_mode">gantt,tree,form,calendar</field>
- <field name="context">{}</field>
+ <field name="context">{}</field>
<field name="search_view_id" ref="view_project_user_allocation_search"/>
</record>
@@ -98,6 +98,44 @@
# Project Phase
# ------------------------------------------------------
+ <record id="project_phase_form" model="ir.ui.view">
+ <field name="name">Inherit project form : Phase</field>
+ <field name="model">project.project</field>
+ <field name="type">form</field>
+ <field name="inherit_id" ref="project.edit_project"/>
+ <field name="arch" type="xml">
+ <field name="use_tasks" position="after">
+ <field name="use_phases"/>
+ </field>
+ </field>
+ </record>
+
+ <act_window id="act_project_phases"
+ name="Phases"
+ src_model="project.project"
+ res_model="project.phase"
+ view_type="form"
+ view_mode="tree,form"
+ context="{'search_default_project_id': [active_id], 'default_project_id': active_id}"
+ />
+
+ <record id="view_project_kanban_phase" model="ir.ui.view">
+ <field name="name">project.project.kanban.inherited</field>
+ <field name="model">project.project</field>
+ <field name="type">kanban</field>
+ <field name="inherit_id" ref="project.view_project_kanban"/>
+ <field name="arch" type="xml">
+ <field name="use_tasks" position="after">
+ <field name="use_phases"/>
+ <field name="phase_count"/>
+ </field>
+ <xpath expr="//div[@id='list']" position="inside">
+ <a t-if="record.use_phases.raw_value" class="oe_project_buttons"
+ id="4" name="%(act_project_phases)d" type="action">Phases(<field name="phase_count"/>)</a>
+ </xpath>
+ </field>
+ </record>
+
<record id="view_project_phase_form" model="ir.ui.view">
<field name="name">project.phase.form</field>
<field name="model">project.phase</field>
@@ -278,7 +316,7 @@
<field name="inherit_id" ref="project.view_task_form2"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='effective_hours']" position="after">
- <field name="phase_id"/>
+ <field name="phase_id" context="{'default_project_id' : project_id}"/>
</xpath>
</field>
</record>
@@ -327,16 +365,6 @@
view_mode="tree,form"
/>
- <act_window
- context="{'search_default_project_id': active_id, 'default_project_id': active_id}"
- id="act_project_phases"
- name="Phases"
- res_model="project.phase"
- src_model="project.project"
- view_mode="tree,form"
- view_type="form"
- />
-
# ------------------------------------------------------
# Menu Items
# ------------------------------------------------------
=== modified file 'project_timesheet/project_timesheet.py'
--- project_timesheet/project_timesheet.py 2012-01-31 13:36:57 +0000
+++ project_timesheet/project_timesheet.py 2012-05-09 08:27:20 +0000
@@ -29,6 +29,36 @@
class project_project(osv.osv):
_inherit = 'project.project'
+ def _to_invoice(self, cr, uid, ids, field_name, arg, context=None):
+ account_analytic_line = self.pool.get("account.analytic.line")
+ res = {}
+ for project in self.browse(cr,uid,ids,context=context):
+ line_ids = account_analytic_line.search(cr, uid, [('account_id', '=', project.analytic_account_id.id), ('to_invoice','=',1), ('invoice_id','=',False)])
+ lines = account_analytic_line.browse(cr, uid, line_ids, context)
+ res[project.id] = {
+ 'amount_to_invoice': sum(line.amount for line in lines),
+ 'time_to_invoice': sum(line.unit_amount for line in lines),
+ }
+ return res
+
+ def _timesheet_count(self, cr, uid, ids, field_name, arg, context=None):
+ account_analytic_line = self.pool.get('account.analytic.line')
+ res = {}
+ for project in self.browse(cr, uid, ids, context):
+ line_ids = account_analytic_line.search(cr, uid, [('account_id', '=', project.analytic_account_id.id)])
+ res[project.id] = len(line_ids)
+ return res
+
+ _columns = {
+ 'use_timesheets': fields.boolean('Timesheets', help="Check this field if this project manages timesheets"),
+ 'amount_to_invoice': fields.function(_to_invoice, string="Amount to Invoice", multi="sums"),
+ 'time_to_invoice': fields.function(_to_invoice, string="Time to Invoice", multi="sums"),
+ 'timesheet_count': fields.function(_timesheet_count, type='integer', string="Issue"),
+ }
+ _defaults = {
+ 'use_timesheets': True,
+ }
+
def onchange_partner_id(self, cr, uid, ids, part=False, context=None):
res = super(project_project, self).onchange_partner_id(cr, uid, ids, part, context)
if part and res and ('value' in res):
@@ -39,6 +69,28 @@
factor_id = data_obj.browse(cr, uid, data_id).res_id
res['value'].update({'to_invoice': factor_id})
return res
+
+ def open_timesheets(self, cr, uid, ids, context=None):
+ """ open Timesheets view """
+ project = self.browse(cr, uid, ids[0], context)
+ try:
+ journal_id = self.pool.get('ir.model.data').get_object(cr, uid, 'hr_timesheet', 'analytic_journal').id
+ except ValueError:
+ journal_id = False
+ view_context = {
+ 'search_default_account_id': [project.analytic_account_id.id],
+ 'default_account_id': project.analytic_account_id.id,
+ 'default_journal_id': journal_id,
+ }
+ return {
+ 'type': 'ir.actions.act_window',
+ 'name': _('Bill Tasks Works'),
+ 'res_model': 'account.analytic.line',
+ 'view_type': 'form',
+ 'view_mode': 'tree,form',
+ 'context': view_context,
+ 'nodestroy': True,
+ }
project_project()
=== modified file 'project_timesheet/project_timesheet_view.xml'
--- project_timesheet/project_timesheet_view.xml 2012-04-25 14:02:12 +0000
+++ project_timesheet/project_timesheet_view.xml 2012-05-09 08:27:20 +0000
@@ -7,6 +7,11 @@
<field name="type">form</field>
<field name="inherit_id" ref="project.edit_project"/>
<field name="arch" type="xml">
+ <field name="use_tasks" position='after'>
+ <field name="use_timesheets"/>
+ <field name="amount_to_invoice" invisible="True"/>
+ <field name="time_to_invoice" invisible="True"/>
+ </field>
<field name="warn_customer" position="after">
<group colspan="4" col="4">
<separator colspan="4" string="Invoicing Data"/>
@@ -19,6 +24,41 @@
</field>
</record>
+ <record id="view_project_kanban_inherited" model="ir.ui.view">
+ <field name="name">project.project.kanban.inherited</field>
+ <field name="model">project.project</field>
+ <field name="type">kanban</field>
+ <field name="inherit_id" ref="project.view_project_kanban"/>
+ <field name="arch" type="xml">
+ <field name="use_tasks" position="after">
+ <field name="use_timesheets"/>
+ <field name="timesheet_count"/>
+ <field name="currency_id"/>
+ <field name="partner_id"/>
+ </field>
+ <xpath expr="//div[@id='list']" position="inside">
+ <a t-if="record.use_timesheets.raw_value" class="oe_project_buttons"
+ id="3" name="open_timesheets" type="object">Timesheets(<field name="timesheet_count"/>)</a>
+ </xpath>
+ <xpath expr="//tr[@id='deadline']" position="before">
+ <t t-if="record.partner_id.raw_value">
+ <tr>
+ <th align="left">Amount to invoice</th>
+ <td align="left">
+ <field name="amount_to_invoice"/> <t t-esc="record.currency_id.raw_value[1].split(' ')[1][1]"/>
+ </td>
+ </tr>
+ <tr>
+ <th align="left">Time to Invoice</th>
+ <td align="left">
+ <field name="time_to_invoice"/> <field name="company_uom_id"/>
+ </td>
+ </tr>
+ </t>
+ </xpath>
+ </field>
+ </record>
+
<record id="project_invoice_form_cutomer" model="ir.ui.view">
<field name="name">Inherit project form : Customer</field>
<field name="model">project.project</field>
_______________________________________________
Mailing list: https://launchpad.net/~openerp-dev-gtk
Post to : [email protected]
Unsubscribe : https://launchpad.net/~openerp-dev-gtk
More help : https://help.launchpad.net/ListHelp