merge with latest trunk

bzr revid: ssu@tinyerp.com-20120509054553-e5mpyl997izy28nx
bzr revid: ssu@tinyerp.com-20120509124604-hv7x2zvq2gcxbjvl
This commit is contained in:
Saurang Suthar (OpenERP) 2012-05-09 18:16:04 +05:30
commit 0e6f4821c4
15 changed files with 675 additions and 43 deletions

View File

@ -96,6 +96,8 @@ class account_analytic_account(osv.osv):
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 @@ class account_analytic_account(osv.osv):
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:

View File

@ -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 @@ Dashboard for project members that includes:
'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:

View File

@ -155,6 +155,13 @@ class project(osv.osv):
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 @@ class project(osv.osv):
'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 @@ class project(osv.osv):
'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 ?

View File

@ -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>

View File

@ -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; }

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -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 );

View File

@ -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});
});
}
}
});
}

View File

@ -222,6 +222,8 @@ class project_issue(crm.crm_case, osv.osv):
}),
}
def on_change_project(self, cr, uid, ids, project_id, context=None):
return {}
_defaults = {
'active': 1,
@ -506,9 +508,23 @@ project_issue()
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):

View File

@ -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>

View File

@ -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>

View File

@ -215,9 +215,23 @@ project_user_allocation()
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,):

View File

@ -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
# ------------------------------------------------------

View File

@ -29,6 +29,36 @@ from tools.translate import _
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 @@ class project_project(osv.osv):
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()

View File

@ -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>