[MIG] project_issue: migration to new api
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import models
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
{
|
||||
@@ -19,18 +19,18 @@ It allows the manager to quickly check the issues, assign them and decide on the
|
||||
'project',
|
||||
],
|
||||
'data': [
|
||||
'data/mail_message_subtype_data.xml',
|
||||
'report/project_issue_report_view.xml',
|
||||
'security/project_issue_security.xml',
|
||||
'security/ir.model.access.csv',
|
||||
'views/project_issue_view.xml',
|
||||
'views/project_issue_config_settings_views.xml',
|
||||
'views/account_analytic_account_view.xml',
|
||||
'views/project_project_view.xml',
|
||||
'views/res_partner_view.xml',
|
||||
'views/project_issue_menu.xml',
|
||||
'report/project_issue_report_view.xml',
|
||||
'security/project_issue_security.xml',
|
||||
'security/ir.model.access.csv',
|
||||
'data/mail_message_subtype_data.xml',
|
||||
'views/project_dashboard.xml',
|
||||
],
|
||||
],
|
||||
'demo': ['data/project_issue_demo.xml'],
|
||||
'test': [
|
||||
'test/issue_users.yml',
|
||||
@@ -38,7 +38,5 @@ It allows the manager to quickly check the issues, assign them and decide on the
|
||||
'test/issue_process.yml',
|
||||
'test/issue_demo.yml'
|
||||
],
|
||||
'installable': True,
|
||||
'auto_install': False,
|
||||
'application': True,
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<?xml version="1.0"?>
|
||||
<openerp>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data noupdate="1">
|
||||
|
||||
<!-- notify all employees of module installation -->
|
||||
<record model="mail.message" id="module_install_notification">
|
||||
<record id="module_install_notification" model="mail.message">
|
||||
<field name="model">mail.channel</field>
|
||||
<field name="res_id" ref="mail.channel_all_employees"/>
|
||||
<field name="message_type">notification</field>
|
||||
@@ -73,6 +73,5 @@ Access all issues from the top Project menu, and access the issues of a specific
|
||||
<field name="parent_id" eval="ref('mt_issue_stage')"/>
|
||||
<field name="relation_field">project_id</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
</odoo>
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
<?xml version="1.0"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="project.project_project_1" model="project.project">
|
||||
<field name="use_issues" eval="True"/>
|
||||
</record>
|
||||
@@ -21,7 +19,6 @@
|
||||
<field name="use_issues" eval="True"/>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
<data noupdate="1">
|
||||
|
||||
<!-- Categories -->
|
||||
@@ -37,13 +34,11 @@
|
||||
|
||||
<!-- Issues -->
|
||||
<record id="crm_case_buginaccountsmodule0" model="project.issue">
|
||||
<field eval="time.strftime('%Y-%m-08 10:15:00')" name="date"/>
|
||||
<field name="priority">0</field>
|
||||
<field name="date" eval="time.strftime('%Y-%m-08 10:15:00')"/>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field name="partner_id" ref="portal.partner_demo_portal"/>
|
||||
<field eval="1" name="active"/>
|
||||
<field name="project_id" ref="project.project_project_1"/>
|
||||
<field eval="15.0" name="duration"/>
|
||||
<field name="duration" eval="15.0"/>
|
||||
<field name="name">Bug in Accounts module</field>
|
||||
<field name="email_from">agr@agrolait.com</field>
|
||||
<field name="stage_id" ref="project.project_stage_1"/>
|
||||
@@ -52,23 +47,20 @@
|
||||
</record>
|
||||
|
||||
<record id="crm_case_programnotgivingproperoutput0" model="project.issue">
|
||||
<field eval="time.strftime('%Y-%m-15 12:50:00')" name="date"/>
|
||||
<field name="date" eval="time.strftime('%Y-%m-15 12:50:00')"/>
|
||||
<field name="priority">1</field>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field name="partner_id" ref="base.res_partner_1"/>
|
||||
<field eval="1" name="active"/>
|
||||
<field eval="3.5" name="duration"/>
|
||||
<field name="duration" eval="3.5"/>
|
||||
<field name="name">Program not giving proper output</field>
|
||||
<field name="project_id" ref="project.project_project_4"/>
|
||||
<field name="stage_id" ref="project.project_stage_1"/>
|
||||
</record>
|
||||
|
||||
<record id="crm_case_outputincorrect0" model="project.issue">
|
||||
<field eval="time.strftime('%Y-%m-18 14:30:00')" name="date"/>
|
||||
<field name="priority">0</field>
|
||||
<field name="date" eval="time.strftime('%Y-%m-18 14:30:00')"/>
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field eval="1" name="active"/>
|
||||
<field eval="2.3" name="duration"/>
|
||||
<field name="duration" eval="2.3"/>
|
||||
<field name="project_id" ref="project.project_project_5"/>
|
||||
<field name="name">Output incorrect</field>
|
||||
<field name="stage_id" ref="project.project_stage_2"/>
|
||||
@@ -78,36 +70,33 @@
|
||||
</record>
|
||||
|
||||
<record id="crm_case_problemloadingpage0" model="project.issue">
|
||||
<field eval="time.strftime('%Y-%m-20 15:25:05')" name="date"/>
|
||||
<field name="date" eval="time.strftime('%Y-%m-20 15:25:05')"/>
|
||||
<field name="priority">1</field>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field name="partner_id" ref="base.res_partner_4"/>
|
||||
<field eval="1" name="active"/>
|
||||
<field eval="4.0" name="duration"/>
|
||||
<field name="duration" eval="4.0"/>
|
||||
<field name="project_id" ref="project.project_project_4"/>
|
||||
<field name="name">Problem loading page</field>
|
||||
<field name="stage_id" ref="project.project_stage_0"/>
|
||||
</record>
|
||||
|
||||
<record id="crm_case_pagenotfound0" model="project.issue">
|
||||
<field eval="time.strftime('%Y-%m-22 18:15:00')" name="date"/>
|
||||
<field name="date" eval="time.strftime('%Y-%m-22 18:15:00')"/>
|
||||
<field name="priority">1</field>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field name="partner_id" ref="base.res_partner_2"/>
|
||||
<field eval="1" name="active"/>
|
||||
<field eval="1.0" name="duration"/>
|
||||
<field name="duration" eval="1.0"/>
|
||||
<field name="project_id" ref="project.project_project_4"/>
|
||||
<field name="name">Page not Found</field>
|
||||
<field name="stage_id" ref="project.project_stage_0"/>
|
||||
</record>
|
||||
|
||||
<record id="crm_case_programmingerror0" model="project.issue">
|
||||
<field eval="time.strftime('%Y-%m-24 09:45:00')" name="date"/>
|
||||
<field name="date" eval="time.strftime('%Y-%m-24 09:45:00')"/>
|
||||
<field name="priority">1</field>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field name="partner_id" ref="base.res_partner_3"/>
|
||||
<field eval="1" name="active"/>
|
||||
<field eval="4.0" name="duration"/>
|
||||
<field name="duration" eval="4.0"/>
|
||||
<field name="project_id" ref="project.project_project_4"/>
|
||||
<field name="name">Programming Error</field>
|
||||
<field name="stage_id" ref="project.project_stage_0"/>
|
||||
@@ -117,72 +106,65 @@
|
||||
</record>
|
||||
|
||||
<record id="crm_case_logicalerrorinprogram0" model="project.issue">
|
||||
<field eval="time.strftime('%Y-%m-26 11:10:00')" name="date"/>
|
||||
<field name="date" eval="time.strftime('%Y-%m-26 11:10:00')"/>
|
||||
<field name="priority">2</field>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field name="partner_id" ref="base.res_partner_1"/>
|
||||
<field eval="1" name="active"/>
|
||||
<field eval="2.0" name="duration"/>
|
||||
<field name="duration" eval="2.0"/>
|
||||
<field name="project_id" ref="project.project_project_2"/>
|
||||
<field name="name">Logical Error in Program</field>
|
||||
<field name="stage_id" ref="project.project_stage_3"/>
|
||||
</record>
|
||||
|
||||
<record id="crm_case_constrainterror0" model="project.issue">
|
||||
<field eval="time.strftime('%Y-%m-25 13:35:00')" name="date"/>
|
||||
<field name="date" eval="time.strftime('%Y-%m-25 13:35:00')"/>
|
||||
<field name="priority">2</field>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field name="partner_id" ref="base.res_partner_1"/>
|
||||
<field eval="1" name="active"/>
|
||||
<field eval="7.3" name="duration"/>
|
||||
<field name="duration" eval="7.3"/>
|
||||
<field name="project_id" ref="project.project_project_2"/>
|
||||
<field name="name">Constraint Error</field>
|
||||
<field name="stage_id" ref="project.project_stage_1"/>
|
||||
</record>
|
||||
|
||||
<record id="crm_case_errorinprogram0" model="project.issue">
|
||||
<field eval="time.strftime('%Y-%m-28 15:40:00')" name="date"/>
|
||||
<field name="date" eval="time.strftime('%Y-%m-28 15:40:00')"/>
|
||||
<field name="priority">2</field>
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field name="partner_id" ref="base.res_partner_3"/>
|
||||
<field eval="1" name="active"/>
|
||||
<field eval="1.3" name="duration"/>
|
||||
<field name="duration" eval="1.3"/>
|
||||
<field name="project_id" ref="project.project_project_4"/>
|
||||
<field name="name">Error in Program</field>
|
||||
<field name="stage_id" ref="project.project_stage_1"/>
|
||||
</record>
|
||||
|
||||
<record id="crm_case_patcheserrorinprogram0" model="project.issue">
|
||||
<field eval="time.strftime('%Y-%m-28 16:30:00')" name="date"/>
|
||||
<field name="date" eval="time.strftime('%Y-%m-28 16:30:00')"/>
|
||||
<field name="priority">2</field>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field name="partner_id" ref="base.res_partner_2"/>
|
||||
<field eval="1" name="active"/>
|
||||
<field eval="13.0" name="duration"/>
|
||||
<field name="duration" eval="13.0"/>
|
||||
<field name="project_id" ref="project.project_project_2"/>
|
||||
<field name="name">Patches Error in Program</field>
|
||||
<field name="stage_id" ref="project.project_stage_1"/>
|
||||
</record>
|
||||
|
||||
<record id="crm_case_newfeaturestobeadded0" model="project.issue">
|
||||
<field eval="time.strftime('%Y-%m-01 12:15:10')" name="date"/>
|
||||
<field name="priority">0</field>
|
||||
<field name="date" eval="time.strftime('%Y-%m-01 12:15:10')"/>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field name="partner_id" ref="base.res_partner_12"/>
|
||||
<field eval="1" name="active"/>
|
||||
<field eval="3.2" name="duration"/>
|
||||
<field name="duration" eval="3.2"/>
|
||||
<field name="project_id" ref="project.project_project_3"/>
|
||||
<field name="name">New Features To Be Added</field>
|
||||
<field name="stage_id" ref="project.project_stage_1"/>
|
||||
</record>
|
||||
|
||||
<record id="crm_case_addmenustothemodule0" model="project.issue">
|
||||
<field eval="time.strftime('%Y-%m-05 18:00:00')" name="date"/>
|
||||
<field name="date" eval="time.strftime('%Y-%m-05 18:00:00')"/>
|
||||
<field name="priority">1</field>
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field name="partner_id" ref="base.res_partner_12"/>
|
||||
<field eval="1" name="active"/>
|
||||
<field eval="3.0" name="duration"/>
|
||||
<field name="duration" eval="3.0"/>
|
||||
<field name="project_id" ref="project.project_project_3"/>
|
||||
<field name="name">Add menus to the module</field>
|
||||
<field name="email_from">info@opensides.be</field>
|
||||
@@ -190,12 +172,11 @@
|
||||
</record>
|
||||
|
||||
<record id="crm_case_includeattendancesheetinproject0" model="project.issue">
|
||||
<field eval="time.strftime('%Y-%m-10 17:05:30')" name="date"/>
|
||||
<field name="date" eval="time.strftime('%Y-%m-10 17:05:30')"/>
|
||||
<field name="priority">1</field>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field name="partner_id" ref="base.res_partner_10"/>
|
||||
<field eval="1" name="active"/>
|
||||
<field eval="2.0" name="duration"/>
|
||||
<field name="duration" eval="2.0"/>
|
||||
<field name="project_id" ref="project.project_project_2"/>
|
||||
<field name="name">Include Attendance sheet in Project</field>
|
||||
<field name="email_from">contact@tecsas.fr</field>
|
||||
@@ -203,44 +184,41 @@
|
||||
</record>
|
||||
|
||||
<record id="crm_case_createnewobject0" model="project.issue">
|
||||
<field eval="time.strftime('%Y-%m-15 10:35:15')" name="date"/>
|
||||
<field name="date" eval="time.strftime('%Y-%m-15 10:35:15')"/>
|
||||
<field name="priority">1</field>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field name="partner_id" ref="base.res_partner_1"/>
|
||||
<field eval="1" name="active"/>
|
||||
<field eval="2.45" name="duration"/>
|
||||
<field name="duration" eval="2.45"/>
|
||||
<field name="project_id" ref="project.project_project_4"/>
|
||||
<field name="name">Create new object</field>
|
||||
<field name="stage_id" ref="project.project_stage_0"/>
|
||||
</record>
|
||||
|
||||
<record id="crm_case_improvereportsinhrms0" model="project.issue">
|
||||
<field eval="time.strftime('%Y-%m-19 12:15:00')" name="date"/>
|
||||
<field name="priority">0</field>
|
||||
<field name="date" eval="time.strftime('%Y-%m-19 12:15:00')"/>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field name="partner_id" ref="base.res_partner_3"/>
|
||||
<field eval="1" name="active"/>
|
||||
<field eval="15.0" name="duration"/>
|
||||
<field name="duration" eval="15.0"/>
|
||||
<field name="project_id" ref="project.project_project_4"/>
|
||||
<field name="name">Improve Reports in HRMS</field>
|
||||
<field name="stage_id" ref="project.project_stage_2"/>
|
||||
</record>
|
||||
|
||||
<record id="crm_case_improvereportsinpms0" model="project.issue">
|
||||
<field eval="time.strftime('%Y-%m-21 14:30:00')" name="date"/>
|
||||
<field name="date" eval="time.strftime('%Y-%m-21 14:30:00')"/>
|
||||
<field name="priority">2</field>
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field name="partner_id" ref="base.res_partner_3"/>
|
||||
<field eval="1" name="active"/>
|
||||
<field eval="06.15" name="duration"/>
|
||||
<field name="duration" eval="06.15"/>
|
||||
<field name="project_id" ref="project.project_project_4"/>
|
||||
<field name="name">Improve Reports in PMS</field>
|
||||
<field name="stage_id" ref="project.project_stage_1"/>
|
||||
</record>
|
||||
|
||||
<!-- Call function to set some issues as 'unread' -->
|
||||
|
||||
<!-- <function model="project.issue" name="message_mark_as_unread"
|
||||
eval="[ ref('crm_case_improvereportsinhrms0'), ref('crm_case_createnewobject0')], {}"/> -->
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
</odoo>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import project_issue
|
||||
|
||||
@@ -1,35 +1,30 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from openerp.osv import fields, osv
|
||||
from openerp.tools.translate import _
|
||||
from openerp.exceptions import UserError
|
||||
from odoo import api, fields, models, _
|
||||
from odoo.exceptions import UserError
|
||||
|
||||
|
||||
class account_analytic_account(osv.Model):
|
||||
class AccountAnalyticAccount(models.Model):
|
||||
_inherit = 'account.analytic.account'
|
||||
_description = 'Analytic Account'
|
||||
|
||||
_columns = {
|
||||
'use_issues': fields.boolean('Use Issues', help="Check this box to manage customer activities through this project"),
|
||||
}
|
||||
use_issues = fields.Boolean(string='Use Issues', help="Check this box to manage customer activities through this project")
|
||||
|
||||
def on_change_template(self, cr, uid, ids, template_id, date_start=False, context=None):
|
||||
res = super(account_analytic_account, self).on_change_template(cr, uid, ids, template_id, date_start=date_start, context=context)
|
||||
@api.multi
|
||||
def on_change_template(self, template_id, date_start=False):
|
||||
res = super(AccountAnalyticAccount, self).on_change_template(template_id, date_start=date_start)
|
||||
if template_id and 'value' in res:
|
||||
template = self.browse(cr, uid, template_id, context=context)
|
||||
res['value']['use_issues'] = template.use_issues
|
||||
account_analytic_account = self.browse(template_id)
|
||||
res['value']['use_issues'] = account_analytic_account.use_issues
|
||||
return res
|
||||
|
||||
def _trigger_project_creation(self, cr, uid, vals, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
res = super(account_analytic_account, self)._trigger_project_creation(cr, uid, vals, context=context)
|
||||
return res or (vals.get('use_issues') and not 'project_creation_in_progress' in context)
|
||||
|
||||
def unlink(self, cr, uid, ids, context=None):
|
||||
proj_ids = self.pool['project.project'].search(cr, uid, [('analytic_account_id', 'in', ids)])
|
||||
has_issues = self.pool['project.issue'].search(cr, uid, [('project_id', 'in', proj_ids)], count=True, context=context)
|
||||
if has_issues:
|
||||
@api.multi
|
||||
def unlink(self):
|
||||
if self.env['project.issue'].search_count([('project_id.analytic_account_id', 'in', self.ids)]):
|
||||
raise UserError(_('Please remove existing issues in the project linked to the accounts you want to delete.'))
|
||||
return super(account_analytic_account, self).unlink(cr, uid, ids, context=context)
|
||||
return super(AccountAnalyticAccount, self).unlink()
|
||||
|
||||
@api.model
|
||||
def _trigger_project_creation(self, vals):
|
||||
res = super(AccountAnalyticAccount, self)._trigger_project_creation(vals)
|
||||
return res or (vals.get('use_issues') and not 'project_creation_in_progress' in self.env.context)
|
||||
|
||||
@@ -1,304 +1,223 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from openerp import api
|
||||
from openerp import SUPERUSER_ID
|
||||
from openerp import tools
|
||||
from openerp.exceptions import UserError, AccessError
|
||||
from openerp.osv import fields, osv
|
||||
from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT
|
||||
from openerp.tools.safe_eval import safe_eval as eval
|
||||
from openerp.tools.translate import _
|
||||
from odoo import api, fields, models, tools, _
|
||||
from odoo.exceptions import AccessError
|
||||
from odoo.tools.safe_eval import safe_eval as eval
|
||||
|
||||
|
||||
class project_issue(osv.Model):
|
||||
class ProjectIssue(models.Model):
|
||||
_name = "project.issue"
|
||||
_description = "Project Issue"
|
||||
_order = "priority desc, create_date desc"
|
||||
_inherit = ['mail.thread', 'ir.needaction_mixin']
|
||||
_order = "priority desc, create_date desc"
|
||||
_mail_post_access = 'read'
|
||||
|
||||
def _get_default_partner(self, cr, uid, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
if 'default_project_id' in context:
|
||||
project = self.pool.get('project.project').browse(cr, uid, context['default_project_id'], context=context)
|
||||
if project and project.partner_id:
|
||||
return project.partner_id.id
|
||||
return False
|
||||
@api.model
|
||||
def _get_default_stage_id(self):
|
||||
return self.stage_find(self.env.context.get('default_project_id'), [('fold', '=', False)])
|
||||
|
||||
def _get_default_stage_id(self, cr, uid, context=None):
|
||||
""" Gives default stage_id """
|
||||
if context is None:
|
||||
context = {}
|
||||
return self.stage_find(cr, uid, [], context.get('default_project_id'), [('fold', '=', False)], context=context)
|
||||
name = fields.Char(string='Issue', required=True)
|
||||
active = fields.Boolean(default=True)
|
||||
days_since_creation = fields.Integer(compute='_compute_inactivity_days', string='Days since creation date',
|
||||
help="Difference in days between creation date and current date")
|
||||
date_deadline = fields.Date(string='Deadline')
|
||||
partner_id = fields.Many2one('res.partner', string='Contact', index=True)
|
||||
company_id = fields.Many2one('res.company', string='Company', default=lambda self: self.env.user.company_id)
|
||||
description = fields.Text('Private Note')
|
||||
kanban_state = fields.Selection([('normal', 'Normal'), ('blocked', 'Blocked'), ('done', 'Ready for next stage')], string='Kanban State',
|
||||
track_visibility='onchange', required=True, default='normal',
|
||||
help="""An Issue's kanban state indicates special situations affecting it:\n
|
||||
* Normal is the default situation\n
|
||||
* Blocked indicates something is preventing the progress of this issue\n
|
||||
* Ready for next stage indicates the issue is ready to be pulled to the next stage""")
|
||||
email_from = fields.Char(string='Email', help="These people will receive email.", index=True)
|
||||
email_cc = fields.Char(string='Watchers Emails', help="""These email addresses will be added to the CC field of all inbound
|
||||
and outbound emails for this record before being sent. Separate multiple email addresses with a comma""")
|
||||
date_open = fields.Datetime(string='Assigned', readonly=True, index=True)
|
||||
date_closed = fields.Datetime(string='Closed', readonly=True, index=True)
|
||||
date = fields.Datetime('Date')
|
||||
date_last_stage_update = fields.Datetime(string='Last Stage Update', index=True, default=fields.Datetime.now)
|
||||
channel = fields.Char(string='Channel', help="Communication channel.")
|
||||
tag_ids = fields.Many2many('project.tags', string='Tags')
|
||||
priority = fields.Selection([('0', 'Low'), ('1', 'Normal'), ('2', 'High')], 'Priority', index=True, default='0')
|
||||
stage_id = fields.Many2one('project.task.type', string='Stage', track_visibility='onchange', index=True,
|
||||
domain="[('project_ids', '=', project_id)]", copy=False,
|
||||
default=_get_default_stage_id)
|
||||
project_id = fields.Many2one('project.project', string='Project', track_visibility='onchange', index=True)
|
||||
duration = fields.Float('Duration')
|
||||
task_id = fields.Many2one('project.task', string='Task', domain="[('project_id','=',project_id)]",
|
||||
help="You can link this issue to an existing task or directly create a new one from here")
|
||||
day_open = fields.Float(compute='_compute_day', string='Days to Assign', store=True)
|
||||
day_close = fields.Float(compute='_compute_day', string='Days to Close', store=True)
|
||||
|
||||
def _read_group_stage_ids(self, cr, uid, ids, domain, read_group_order=None, access_rights_uid=None, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
access_rights_uid = access_rights_uid or uid
|
||||
stage_obj = self.pool.get('project.task.type')
|
||||
order = stage_obj._order
|
||||
user_id = fields.Many2one('res.users', string='Assigned to', index=True, track_visibility='onchange', default=lambda self: self.env.uid)
|
||||
working_hours_open = fields.Float(compute='_compute_day', string='Working Hours to assign the Issue', store=True)
|
||||
working_hours_close = fields.Float(compute='_compute_day', string='Working Hours to close the Issue', store=True)
|
||||
inactivity_days = fields.Integer(compute='_compute_inactivity_days', string='Days since last action',
|
||||
help="Difference in days between last action and current date")
|
||||
color = fields.Integer('Color Index')
|
||||
user_email = fields.Char(related='user_id.email', string='User Email', readonly=True)
|
||||
date_action_last = fields.Datetime(string='Last Action', readonly=True)
|
||||
date_action_next = fields.Datetime(string='Next Action', readonly=True)
|
||||
legend_blocked = fields.Char(related="stage_id.legend_blocked", string='Kanban Blocked Explanation')
|
||||
legend_done = fields.Char(related="stage_id.legend_done", string='Kanban Valid Explanation')
|
||||
legend_normal = fields.Char(related="stage_id.legend_normal", string='Kanban Ongoing Explanation')
|
||||
|
||||
@api.multi
|
||||
def _read_group_stage_ids(self, domain, read_group_order=None, access_rights_uid=None):
|
||||
access_rights_uid = access_rights_uid or self.env.uid
|
||||
ProjectTaskType = self.env['project.task.type']
|
||||
order = ProjectTaskType._order
|
||||
# lame hack to allow reverting search, should just work in the trivial case
|
||||
if read_group_order == 'stage_id desc':
|
||||
order = "%s desc" % order
|
||||
# retrieve project_id from the context, add them to already fetched columns (ids)
|
||||
if 'default_project_id' in context:
|
||||
search_domain = ['|', ('project_ids', '=', context['default_project_id']), ('id', 'in', ids)]
|
||||
if 'default_project_id' in self.env.context:
|
||||
search_domain = ['|', ('project_ids', '=', self.env.context['default_project_id']), ('id', 'in', self.ids)]
|
||||
else:
|
||||
search_domain = [('id', 'in', ids)]
|
||||
search_domain = [('id', 'in', self.ids)]
|
||||
# perform search
|
||||
stage_ids = stage_obj._search(cr, uid, search_domain, order=order, access_rights_uid=access_rights_uid, context=context)
|
||||
result = stage_obj.name_get(cr, access_rights_uid, stage_ids, context=context)
|
||||
project_task_types = ProjectTaskType.sudo(access_rights_uid).search(search_domain, order=order)
|
||||
result = project_task_types.sudo(access_rights_uid).name_get()
|
||||
# restore order of the search
|
||||
result.sort(lambda x, y: cmp(stage_ids.index(x[0]), stage_ids.index(y[0])))
|
||||
|
||||
fold = {}
|
||||
for stage in stage_obj.browse(cr, access_rights_uid, stage_ids, context=context):
|
||||
fold[stage.id] = stage.fold or False
|
||||
project_task_type_ids = project_task_types.mapped('id')
|
||||
result.sort(lambda x, y: cmp(project_task_type_ids.index(x[0]), project_task_type_ids.index(y[0])))
|
||||
fold = {project_task_type.id: project_task_type.fold for project_task_type in project_task_types}
|
||||
return result, fold
|
||||
|
||||
def _compute_day(self, cr, uid, ids, fields, args, context=None):
|
||||
"""
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param ids: List of Openday’s IDs
|
||||
@return: difference between current date and log date
|
||||
@param context: A standard dictionary for contextual values
|
||||
"""
|
||||
Calendar = self.pool['resource.calendar']
|
||||
|
||||
res = dict((res_id, {}) for res_id in ids)
|
||||
for issue in self.browse(cr, uid, ids, context=context):
|
||||
values = {
|
||||
'day_open': 0.0, 'day_close': 0.0,
|
||||
'working_hours_open': 0.0, 'working_hours_close': 0.0,
|
||||
'days_since_creation': 0.0, 'inactivity_days': 0.0,
|
||||
}
|
||||
# if the working hours on the project are not defined, use default ones (8 -> 12 and 13 -> 17 * 5), represented by None
|
||||
calendar_id = None
|
||||
if issue.project_id and issue.project_id.resource_calendar_id:
|
||||
calendar_id = issue.project_id.resource_calendar_id.id
|
||||
|
||||
dt_create_date = datetime.strptime(issue.create_date, DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
|
||||
if issue.date_open:
|
||||
dt_date_open = datetime.strptime(issue.date_open, DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
values['day_open'] = (dt_date_open - dt_create_date).total_seconds() / (24.0 * 3600)
|
||||
values['working_hours_open'] = Calendar._interval_hours_get(
|
||||
cr, uid, calendar_id, dt_create_date, dt_date_open,
|
||||
timezone_from_uid=issue.user_id.id or uid,
|
||||
exclude_leaves=False, context=context)
|
||||
|
||||
if issue.date_closed:
|
||||
dt_date_closed = datetime.strptime(issue.date_closed, DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
values['day_close'] = (dt_date_closed - dt_create_date).total_seconds() / (24.0 * 3600)
|
||||
values['working_hours_close'] = Calendar._interval_hours_get(
|
||||
cr, uid, calendar_id, dt_create_date, dt_date_closed,
|
||||
timezone_from_uid=issue.user_id.id or uid,
|
||||
exclude_leaves=False, context=context)
|
||||
|
||||
days_since_creation = datetime.today() - dt_create_date
|
||||
values['days_since_creation'] = days_since_creation.days
|
||||
if issue.date_action_last:
|
||||
inactive_days = datetime.today() - datetime.strptime(issue.date_action_last, DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
elif issue.date_last_stage_update:
|
||||
inactive_days = datetime.today() - datetime.strptime(issue.date_last_stage_update, DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
else:
|
||||
inactive_days = datetime.today() - datetime.strptime(issue.create_date, DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
values['inactivity_days'] = inactive_days.days
|
||||
|
||||
# filter only required values
|
||||
for field in fields:
|
||||
res[issue.id][field] = values[field]
|
||||
|
||||
return res
|
||||
|
||||
def on_change_project(self, cr, uid, ids, project_id, context=None):
|
||||
if project_id:
|
||||
project = self.pool.get('project.project').browse(cr, uid, project_id, context=context)
|
||||
if project and project.partner_id:
|
||||
return {'value': {'partner_id': project.partner_id.id, 'email_from': project.partner_id.email}}
|
||||
return {}
|
||||
|
||||
_columns = {
|
||||
'id': fields.integer('ID', readonly=True),
|
||||
'name': fields.char('Issue', required=True),
|
||||
'active': fields.boolean('Active', required=False),
|
||||
'create_date': fields.datetime('Creation Date', readonly=True, select=True),
|
||||
'write_date': fields.datetime('Update Date', readonly=True),
|
||||
'days_since_creation': fields.function(_compute_day, string='Days since creation date', \
|
||||
multi='compute_day', type="integer", help="Difference in days between creation date and current date",
|
||||
groups='base.group_user'),
|
||||
'date_deadline': fields.date('Deadline'),
|
||||
'partner_id': fields.many2one('res.partner', 'Contact', select=1),
|
||||
'company_id': fields.many2one('res.company', 'Company'),
|
||||
'description': fields.text('Private Note'),
|
||||
'kanban_state': fields.selection([('normal', 'Normal'),('blocked', 'Blocked'),('done', 'Ready for next stage')], 'Kanban State',
|
||||
track_visibility='onchange',
|
||||
help="A Issue's kanban state indicates special situations affecting it:\n"
|
||||
" * Normal is the default situation\n"
|
||||
" * Blocked indicates something is preventing the progress of this issue\n"
|
||||
" * Ready for next stage indicates the issue is ready to be pulled to the next stage",
|
||||
required=True),
|
||||
'email_from': fields.char('Email', size=128, help="These people will receive email.", select=1),
|
||||
'email_cc': fields.char('Watchers Emails', size=256, help="These email addresses will be added to the CC field of all inbound and outbound emails for this record before being sent. Separate multiple email addresses with a comma"),
|
||||
'date_open': fields.datetime('Assigned', readonly=True, select=True),
|
||||
# Project Issue fields
|
||||
'date_closed': fields.datetime('Closed', readonly=True, select=True),
|
||||
'date': fields.datetime('Date'),
|
||||
'date_last_stage_update': fields.datetime('Last Stage Update', select=True),
|
||||
'channel': fields.char('Channel', help="Communication channel."),
|
||||
'tag_ids': fields.many2many('project.tags', string='Tags'),
|
||||
'priority': fields.selection([('0','Low'), ('1','Normal'), ('2','High')], 'Priority', select=True),
|
||||
'stage_id': fields.many2one ('project.task.type', 'Stage',
|
||||
track_visibility='onchange', select=True,
|
||||
domain="[('project_ids', '=', project_id)]", copy=False),
|
||||
'project_id': fields.many2one('project.project', 'Project', track_visibility='onchange', select=True),
|
||||
'duration': fields.float('Duration'),
|
||||
'task_id': fields.many2one('project.task', 'Task', domain="[('project_id','=',project_id)]",
|
||||
help="You can link this issue to an existing task or directly create a new one from here"),
|
||||
'day_open': fields.function(_compute_day, string='Days to Assign',
|
||||
multi='compute_day', type="float",
|
||||
store={'project.issue': (lambda self, cr, uid, ids, c={}: ids, ['date_open'], 10)},
|
||||
groups='base.group_user'),
|
||||
'day_close': fields.function(_compute_day, string='Days to Close',
|
||||
multi='compute_day', type="float",
|
||||
store={'project.issue': (lambda self, cr, uid, ids, c={}: ids, ['date_closed'], 10)},
|
||||
groups='base.group_user'),
|
||||
'user_id': fields.many2one('res.users', 'Assigned to', required=False, select=1, track_visibility='onchange'),
|
||||
'working_hours_open': fields.function(_compute_day, string='Working Hours to assign the Issue',
|
||||
multi='compute_day', type="float",
|
||||
store={'project.issue': (lambda self, cr, uid, ids, c={}: ids, ['date_open'], 10)},
|
||||
groups='base.group_user'),
|
||||
'working_hours_close': fields.function(_compute_day, string='Working Hours to close the Issue',
|
||||
multi='compute_day', type="float",
|
||||
store={'project.issue': (lambda self, cr, uid, ids, c={}: ids, ['date_closed'], 10)},
|
||||
groups='base.group_user'),
|
||||
'inactivity_days': fields.function(_compute_day, string='Days since last action',
|
||||
multi='compute_day', type="integer", help="Difference in days between last action and current date",
|
||||
groups='base.group_user'),
|
||||
'color': fields.integer('Color Index'),
|
||||
'user_email': fields.related('user_id', 'email', type='char', string='User Email', readonly=True),
|
||||
'date_action_last': fields.datetime('Last Action', readonly=1),
|
||||
'date_action_next': fields.datetime('Next Action', readonly=1),
|
||||
'legend_blocked': fields.related("stage_id", "legend_blocked", type="char", string='Kanban Blocked Explanation'),
|
||||
'legend_done': fields.related("stage_id", "legend_done", type="char", string='Kanban Valid Explanation'),
|
||||
'legend_normal': fields.related("stage_id", "legend_normal", type="char", string='Kanban Ongoing Explanation'),
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
'active': 1,
|
||||
'stage_id': lambda s, cr, uid, c: s._get_default_stage_id(cr, uid, c),
|
||||
'company_id': lambda s, cr, uid, c: s.pool['res.users']._get_company(cr, uid, context=c),
|
||||
'priority': '0',
|
||||
'kanban_state': 'normal',
|
||||
'date_last_stage_update': fields.datetime.now,
|
||||
'user_id': lambda obj, cr, uid, context: uid,
|
||||
}
|
||||
|
||||
_group_by_full = {
|
||||
'stage_id': _read_group_stage_ids
|
||||
}
|
||||
|
||||
def copy(self, cr, uid, id, default=None, context=None):
|
||||
issue = self.read(cr, uid, [id], ['name'], context=context)[0]
|
||||
if not default:
|
||||
default = {}
|
||||
default = default.copy()
|
||||
default.update(name=_('%s (copy)') % (issue['name']))
|
||||
return super(project_issue, self).copy(cr, uid, id, default=default, context=context)
|
||||
@api.multi
|
||||
@api.depends('create_date', 'date_closed', 'date_open')
|
||||
def _compute_day(self):
|
||||
for issue in self:
|
||||
# if the working hours on the project are not defined, use default ones (8 -> 12 and 13 -> 17 * 5), represented by None
|
||||
calendar_id = None
|
||||
if issue.project_id and issue.project_id.resource_calendar_id:
|
||||
calendar_id = issue.project_id.resource_calendar_id.id
|
||||
|
||||
def create(self, cr, uid, vals, context=None):
|
||||
context = dict(context or {})
|
||||
if vals.get('project_id') and not context.get('default_project_id'):
|
||||
dt_create_date = fields.Datetime.from_string(issue.create_date)
|
||||
if issue.date_open:
|
||||
dt_date_open = fields.Datetime.from_string(issue.date_open)
|
||||
issue.day_open = (dt_date_open - dt_create_date).total_seconds() / (24.0 * 3600)
|
||||
# FIXME when resource.calendar is migrated to new api
|
||||
# Old api call because get_working_hours uses get_weekdays
|
||||
# which has a different behavior if the given id is None.
|
||||
issue.working_hours_open = self.pool['resource.calendar'].get_working_hours(
|
||||
self.env.cr, self.env.uid, calendar_id, dt_create_date, dt_date_open,
|
||||
compute_leaves=True, resource_id=False, default_interval=(8, 16),
|
||||
context=self.env.context
|
||||
)
|
||||
|
||||
if issue.date_closed:
|
||||
dt_date_closed = fields.Datetime.from_string(issue.date_closed)
|
||||
issue.day_close = (dt_date_closed - dt_create_date).total_seconds() / (24.0 * 3600)
|
||||
# FIXME when resource.calendar is migrated to new api
|
||||
# Old api call because get_working_hours uses get_weekdays
|
||||
# which has a different behavior if the given id is None.
|
||||
issue.working_hours_close = self.pool['resource.calendar'].get_working_hours(
|
||||
self.env.cr, self.env.uid, calendar_id, dt_create_date, dt_date_closed,
|
||||
compute_leaves=True, resource_id=False, default_interval=(8, 16),
|
||||
context=self.env.context
|
||||
)
|
||||
|
||||
@api.multi
|
||||
@api.depends('create_date', 'date_action_last', 'date_last_stage_update')
|
||||
def _compute_inactivity_days(self):
|
||||
current_datetime = fields.Datetime.from_string(fields.Datetime.now())
|
||||
for issue in self:
|
||||
dt_create_date = fields.Datetime.from_string(issue.create_date)
|
||||
issue.days_since_creation = (current_datetime - dt_create_date).days
|
||||
|
||||
if issue.date_action_last:
|
||||
issue.inactivity_days = (current_datetime - fields.Datetime.from_string(issue.date_action_last)).days
|
||||
elif issue.date_last_stage_update:
|
||||
issue.inactivity_days = (current_datetime - fields.Datetime.from_string(issue.date_last_stage_update)).days
|
||||
else:
|
||||
issue.inactivity_days = (current_datetime - dt_create_date).days
|
||||
|
||||
@api.onchange('partner_id')
|
||||
def _onchange_partner_id(self):
|
||||
""" This function sets partner email address based on partner
|
||||
"""
|
||||
self.email_from = self.partner_id.email
|
||||
|
||||
@api.onchange('project_id')
|
||||
def _onchange_project_id(self):
|
||||
if self.project_id:
|
||||
self.partner_id = self.project_id.partner_id.id
|
||||
self.email_from = self.project_id.partner_id.email
|
||||
|
||||
@api.onchange('task_id')
|
||||
def _onchange_task_id(self):
|
||||
self.user_id = self.task_id.user_id
|
||||
|
||||
@api.one
|
||||
def copy(self, default=None):
|
||||
if default is None:
|
||||
default = {}
|
||||
default.update(name=_('%s (copy)') % (self.name))
|
||||
return super(ProjectIssue, self).copy(default=default)
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
context = dict(self.env.context)
|
||||
if vals.get('project_id') and not self.env.context.get('default_project_id'):
|
||||
context['default_project_id'] = vals.get('project_id')
|
||||
if vals.get('user_id') and not vals.get('date_open'):
|
||||
vals['date_open'] = fields.datetime.now()
|
||||
vals['date_open'] = fields.Datetime.now()
|
||||
if 'stage_id' in vals:
|
||||
vals.update(self.onchange_stage_id(cr, uid, None, vals.get('stage_id'), context=context)['value'])
|
||||
vals.update(self.update_date_closed(vals['stage_id']))
|
||||
|
||||
# context: no_log, because subtype already handle this
|
||||
create_context = dict(context, mail_create_nolog=True)
|
||||
return super(project_issue, self).create(cr, uid, vals, context=create_context)
|
||||
context['mail_create_nolog'] = True
|
||||
return super(ProjectIssue, self.with_context(context)).create(vals)
|
||||
|
||||
def write(self, cr, uid, ids, vals, context=None):
|
||||
@api.multi
|
||||
def write(self, vals):
|
||||
# stage change: update date_last_stage_update
|
||||
if 'stage_id' in vals:
|
||||
vals.update(self.onchange_stage_id(cr, uid, ids, vals.get('stage_id'), context=context)['value'])
|
||||
vals['date_last_stage_update'] = fields.datetime.now()
|
||||
vals.update(self.update_date_closed(vals['stage_id']))
|
||||
vals['date_last_stage_update'] = fields.Datetime.now()
|
||||
if 'kanban_state' not in vals:
|
||||
vals['kanban_state'] = 'normal'
|
||||
# user_id change: update date_open
|
||||
if vals.get('user_id') and 'date_open' not in vals:
|
||||
vals['date_open'] = fields.datetime.now()
|
||||
vals['date_open'] = fields.Datetime.now()
|
||||
return super(ProjectIssue, self).write(vals)
|
||||
|
||||
return super(project_issue, self).write(cr, uid, ids, vals, context)
|
||||
|
||||
def onchange_task_id(self, cr, uid, ids, task_id, context=None):
|
||||
if not task_id:
|
||||
return {'value': {}}
|
||||
task = self.pool.get('project.task').browse(cr, uid, task_id, context=context)
|
||||
return {'value': {'user_id': task.user_id.id, }}
|
||||
|
||||
def onchange_partner_id(self, cr, uid, ids, partner_id, context=None):
|
||||
""" This function returns value of partner email address based on partner
|
||||
:param part: Partner's id
|
||||
"""
|
||||
if partner_id:
|
||||
partner = self.pool['res.partner'].browse(cr, uid, partner_id, context)
|
||||
return {'value': {'email_from': partner.email}}
|
||||
return {'value': {'email_from': False}}
|
||||
|
||||
def get_empty_list_help(self, cr, uid, help, context=None):
|
||||
context = dict(context or {})
|
||||
context['empty_list_help_model'] = 'project.project'
|
||||
context['empty_list_help_id'] = context.get('default_project_id')
|
||||
context['empty_list_help_document_name'] = _("issues")
|
||||
return super(project_issue, self).get_empty_list_help(cr, uid, help, context=context)
|
||||
@api.model
|
||||
def get_empty_list_help(self, help):
|
||||
return super(ProjectIssue, self.with_context(
|
||||
empty_list_help_model='project.project',
|
||||
empty_list_help_id=self.env.context.get('default_project_id'),
|
||||
empty_list_help_document_name=_("issues")
|
||||
)).get_empty_list_help(help)
|
||||
|
||||
# -------------------------------------------------------
|
||||
# Stage management
|
||||
# -------------------------------------------------------
|
||||
|
||||
def onchange_stage_id(self, cr, uid, ids, stage_id, context=None):
|
||||
if not stage_id:
|
||||
return {'value': {}}
|
||||
stage = self.pool['project.task.type'].browse(cr, uid, stage_id, context=context)
|
||||
if stage.fold:
|
||||
return {'value': {'date_closed': fields.datetime.now()}}
|
||||
return {'value': {'date_closed': False}}
|
||||
def update_date_closed(self, stage_id):
|
||||
project_task_type = self.env['project.task.type'].browse(stage_id)
|
||||
if project_task_type.fold:
|
||||
return {'date_closed': fields.Datetime.now()}
|
||||
return {'date_closed': False}
|
||||
|
||||
def stage_find(self, cr, uid, cases, project_id, domain=[], order='sequence', context=None):
|
||||
def stage_find(self, project_id, domain=None, order='sequence'):
|
||||
""" Override of the base.stage method
|
||||
Parameter of the stage search taken from the issue:
|
||||
- type: stage type must be the same or 'both'
|
||||
- project_id: if set, stages must belong to this project or
|
||||
be a default case
|
||||
"""
|
||||
if isinstance(cases, (int, long)):
|
||||
cases = self.browse(cr, uid, cases, context=context)
|
||||
# collect all project_ids
|
||||
project_ids = []
|
||||
search_domain = list(domain) if domain else []
|
||||
if project_id:
|
||||
project_ids.append(project_id)
|
||||
for task in cases:
|
||||
if task.project_id:
|
||||
project_ids.append(task.project_id.id)
|
||||
# OR all project_ids and OR with case_default
|
||||
search_domain = []
|
||||
if project_ids:
|
||||
search_domain += [('|')] * (len(project_ids) - 1)
|
||||
for project_id in project_ids:
|
||||
search_domain.append(('project_ids', '=', project_id))
|
||||
search_domain += list(domain)
|
||||
# perform search, return the first found
|
||||
stage_ids = self.pool.get('project.task.type').search(cr, uid, search_domain, order=order, context=context)
|
||||
if stage_ids:
|
||||
return stage_ids[0]
|
||||
return False
|
||||
search_domain += [('project_ids', '=', project_id)]
|
||||
project_task_type = self.env['project.task.type'].search(search_domain, order=order, limit=1)
|
||||
return project_task_type.id
|
||||
|
||||
# -------------------------------------------------------
|
||||
# Mail gateway
|
||||
@@ -306,57 +225,57 @@ class project_issue(osv.Model):
|
||||
|
||||
@api.multi
|
||||
def _track_template(self, tracking):
|
||||
res = super(project_issue, self)._track_template(tracking)
|
||||
test_issue = self[0]
|
||||
changes, dummy = tracking[test_issue.id]
|
||||
if 'stage_id' in changes and test_issue.stage_id.mail_template_id:
|
||||
res['stage_id'] = (test_issue.stage_id.mail_template_id, {'composition_mode': 'mass_mail'})
|
||||
self.ensure_one()
|
||||
res = super(ProjectIssue, self)._track_template(tracking)
|
||||
changes, dummy = tracking[self.id]
|
||||
if 'stage_id' in changes and self.stage_id.mail_template_id:
|
||||
res['stage_id'] = (self.stage_id.mail_template_id, {'composition_mode': 'mass_mail'})
|
||||
return res
|
||||
|
||||
def _track_subtype(self, cr, uid, ids, init_values, context=None):
|
||||
record = self.browse(cr, uid, ids[0], context=context)
|
||||
if 'kanban_state' in init_values and record.kanban_state == 'blocked':
|
||||
def _track_subtype(self, init_values):
|
||||
self.ensure_one()
|
||||
if 'kanban_state' in init_values and self.kanban_state == 'blocked':
|
||||
return 'project_issue.mt_issue_blocked'
|
||||
elif 'kanban_state' in init_values and record.kanban_state == 'done':
|
||||
elif 'kanban_state' in init_values and self.kanban_state == 'done':
|
||||
return 'project_issue.mt_issue_ready'
|
||||
elif 'user_id' in init_values and record.user_id: # assigned -> new
|
||||
elif 'user_id' in init_values and self.user_id: # assigned -> new
|
||||
return 'project_issue.mt_issue_new'
|
||||
elif 'stage_id' in init_values and record.stage_id and record.stage_id.sequence <= 1: # start stage -> new
|
||||
elif 'stage_id' in init_values and self.stage_id and self.stage_id.sequence <= 1: # start stage -> new
|
||||
return 'project_issue.mt_issue_new'
|
||||
elif 'stage_id' in init_values:
|
||||
return 'project_issue.mt_issue_stage'
|
||||
return super(project_issue, self)._track_subtype(cr, uid, ids, init_values, context=context)
|
||||
return super(ProjectIssue, self)._track_subtype(init_values)
|
||||
|
||||
def _notification_group_recipients(self, cr, uid, ids, message, recipients, done_ids, group_data, context=None):
|
||||
@api.multi
|
||||
def _notification_group_recipients(self, message, recipients, done_ids, group_data):
|
||||
""" Override the mail.thread method to handle project users and officers
|
||||
recipients. Indeed those will have specific action in their notification
|
||||
emails: creating tasks, assigning it. """
|
||||
group_project_user = self.pool['ir.model.data'].xmlid_to_res_id(cr, uid, 'project.group_project_user')
|
||||
group_user = self.pool['ir.model.data'].xmlid_to_res_id(cr, uid, 'base.group_user')
|
||||
group_project_user_id = self.env.ref('project.group_project_user').id
|
||||
for recipient in recipients:
|
||||
if recipient.id in done_ids:
|
||||
continue
|
||||
if recipient.user_ids and group_project_user in recipient.user_ids[0].groups_id.ids:
|
||||
if recipient.user_ids and group_project_user_id in recipient.user_ids[0].groups_id.ids:
|
||||
group_data['group_project_user'] |= recipient
|
||||
elif not recipient.user_ids:
|
||||
group_data['partner'] |= recipient
|
||||
else:
|
||||
group_data['user'] |= recipient
|
||||
done_ids.add(recipient.id)
|
||||
return super(project_issue, self)._notification_group_recipients(cr, uid, ids, message, recipients, done_ids, group_data, context=context)
|
||||
return super(ProjectIssue, self)._notification_group_recipients(message, recipients, done_ids, group_data)
|
||||
|
||||
def _notification_get_recipient_groups(self, cr, uid, ids, message, recipients, context=None):
|
||||
res = super(project_issue, self)._notification_get_recipient_groups(cr, uid, ids, message, recipients, context=context)
|
||||
@api.multi
|
||||
def _notification_get_recipient_groups(self, message, recipients):
|
||||
self.ensure_one()
|
||||
res = super(ProjectIssue, self)._notification_get_recipient_groups(message, recipients)
|
||||
|
||||
new_action_id = self.pool['ir.model.data'].xmlid_to_res_id(cr, uid, 'project_issue.project_issue_categ_act0')
|
||||
take_action = self._notification_link_helper(cr, uid, ids, 'assign', context=context)
|
||||
new_action = self._notification_link_helper(cr, uid, ids, 'new', context=context, action_id=new_action_id)
|
||||
|
||||
task_record = self.browse(cr, uid, ids[0], context=context)
|
||||
actions = []
|
||||
if not task_record.user_id:
|
||||
if not self.user_id:
|
||||
take_action = self._notification_link_helper('assign')
|
||||
actions.append({'url': take_action, 'title': _('I take it')})
|
||||
else:
|
||||
new_action_id = self.env.ref('project_issue.project_issue_categ_act0').id
|
||||
new_action = self._notification_link_helper('new', action_id=new_action_id)
|
||||
actions.append({'url': new_action, 'title': _('New Issue')})
|
||||
|
||||
res['group_project_user'] = {
|
||||
@@ -364,18 +283,19 @@ class project_issue(osv.Model):
|
||||
}
|
||||
return res
|
||||
|
||||
@api.cr_uid_context
|
||||
def message_get_reply_to(self, cr, uid, ids, default=None, context=None):
|
||||
@api.model
|
||||
def message_get_reply_to(self, res_ids, default=None):
|
||||
""" Override to get the reply_to of the parent project. """
|
||||
issues = self.browse(cr, SUPERUSER_ID, ids, context=context)
|
||||
project_ids = set([issue.project_id.id for issue in issues if issue.project_id])
|
||||
aliases = self.pool['project.project'].message_get_reply_to(cr, uid, list(project_ids), default=default, context=context)
|
||||
issues = self.browse(res_ids)
|
||||
project_ids = set(issues.mapped('project_id').ids)
|
||||
aliases = self.env['project.project'].message_get_reply_to(list(project_ids), default=default)
|
||||
return dict((issue.id, aliases.get(issue.project_id and issue.project_id.id or 0, False)) for issue in issues)
|
||||
|
||||
def message_get_suggested_recipients(self, cr, uid, ids, context=None):
|
||||
recipients = super(project_issue, self).message_get_suggested_recipients(cr, uid, ids, context=context)
|
||||
@api.multi
|
||||
def message_get_suggested_recipients(self):
|
||||
recipients = super(ProjectIssue, self).message_get_suggested_recipients()
|
||||
try:
|
||||
for issue in self.browse(cr, uid, ids, context=context):
|
||||
for issue in self:
|
||||
if issue.partner_id:
|
||||
issue._message_add_suggested_recipient(recipients, partner=issue.partner_id, reason=_('Customer'))
|
||||
elif issue.email_from:
|
||||
@@ -384,14 +304,14 @@ class project_issue(osv.Model):
|
||||
pass
|
||||
return recipients
|
||||
|
||||
def email_split(self, cr, uid, ids, msg, context=None):
|
||||
@api.multi
|
||||
def email_split(self, msg):
|
||||
email_list = tools.email_split((msg.get('to') or '') + ',' + (msg.get('cc') or ''))
|
||||
# check left-part is not already an alias
|
||||
issue_ids = self.browse(cr, uid, ids, context=context)
|
||||
aliases = [issue.project_id.alias_name for issue in issue_ids if issue.project_id]
|
||||
return filter(lambda x: x.split('@')[0] not in aliases, email_list)
|
||||
return filter(lambda x: x.split('@')[0] not in self.mapped('project_id.alias_name'), email_list)
|
||||
|
||||
def message_new(self, cr, uid, msg, custom_values=None, context=None):
|
||||
@api.model
|
||||
def message_new(self, msg, custom_values=None):
|
||||
""" Overrides mail_thread message_new that is called by the mailgateway
|
||||
through message_process.
|
||||
This override updates the document according to the email.
|
||||
@@ -400,60 +320,59 @@ class project_issue(osv.Model):
|
||||
# do not want to explicitly set user_id to False; however we do not
|
||||
# want the gateway user to be responsible if no other responsible is
|
||||
# found.
|
||||
create_context = dict(context or {})
|
||||
create_context = dict(self.env.context or {})
|
||||
create_context['default_user_id'] = False
|
||||
if custom_values is None:
|
||||
custom_values = {}
|
||||
context = dict(context or {}, state_to='draft')
|
||||
defaults = {
|
||||
'name': msg.get('subject') or _("No Subject"),
|
||||
'email_from': msg.get('from'),
|
||||
'email_cc': msg.get('cc'),
|
||||
'partner_id': msg.get('author_id', False),
|
||||
}
|
||||
defaults.update(custom_values)
|
||||
if custom_values:
|
||||
defaults.update(custom_values)
|
||||
|
||||
res_id = super(project_issue, self).message_new(cr, uid, msg, custom_values=defaults, context=create_context)
|
||||
email_list = self.email_split(cr, uid, [res_id], msg, context=context)
|
||||
partner_ids = filter(None, self._find_partner_from_emails(cr, uid, [res_id], email_list, force_create=False, context=context))
|
||||
self.message_subscribe(cr, uid, [res_id], partner_ids, context=context)
|
||||
res_id = super(ProjectIssue, self.with_context(create_context)).message_new(msg, custom_values=defaults)
|
||||
issue = self.browse(res_id)
|
||||
email_list = issue.email_split(msg)
|
||||
partner_ids = filter(None, issue._find_partner_from_emails(email_list))
|
||||
issue.message_subscribe(partner_ids)
|
||||
return res_id
|
||||
|
||||
def message_update(self, cr, uid, ids, msg, update_vals=None, context=None):
|
||||
@api.multi
|
||||
def message_update(self, msg, update_vals=None):
|
||||
""" Override to update the issue according to the email. """
|
||||
email_list = self.email_split(msg)
|
||||
partner_ids = filter(None, self._find_partner_from_emails(email_list))
|
||||
self.message_subscribe(partner_ids)
|
||||
return super(ProjectIssue, self).message_update(msg, update_vals=update_vals)
|
||||
|
||||
email_list = self.email_split(cr, uid, ids, msg, context=context)
|
||||
partner_ids = filter(None, self._find_partner_from_emails(cr, uid, ids, email_list, force_create=False, context=context))
|
||||
self.message_subscribe(cr, uid, ids, partner_ids, context=context)
|
||||
return super(project_issue, self).message_update(cr, uid, ids, msg, update_vals=update_vals, context=context)
|
||||
|
||||
@api.cr_uid_ids_context
|
||||
@api.multi
|
||||
@api.returns('mail.message', lambda value: value.id)
|
||||
def message_post(self, cr, uid, thread_id, subtype=None, context=None, **kwargs):
|
||||
def message_post(self, subtype=None, **kwargs):
|
||||
""" Overrides mail_thread message_post so that we can set the date of last action field when
|
||||
a new message is posted on the issue.
|
||||
"""
|
||||
if context is None:
|
||||
context = {}
|
||||
res = super(project_issue, self).message_post(cr, uid, thread_id, subtype=subtype, context=context, **kwargs)
|
||||
if thread_id and subtype:
|
||||
self.write(cr, SUPERUSER_ID, thread_id, {'date_action_last': fields.datetime.now()}, context=context)
|
||||
return res
|
||||
self.ensure_one()
|
||||
mail_message = super(ProjectIssue, self).message_post(subtype=subtype, **kwargs)
|
||||
if subtype:
|
||||
self.sudo().write({'date_action_last': fields.Datetime.now()})
|
||||
return mail_message
|
||||
|
||||
def message_get_email_values(self, cr, uid, ids, notif_mail=None, context=None):
|
||||
res = super(project_issue, self).message_get_email_values(cr, uid, ids, notif_mail=notif_mail, context=context)
|
||||
current_issue = self.browse(cr, uid, ids[0], context=context)
|
||||
@api.multi
|
||||
def message_get_email_values(self, notif_mail=None):
|
||||
self.ensure_one()
|
||||
res = super(ProjectIssue, self).message_get_email_values(notif_mail=notif_mail)
|
||||
headers = {}
|
||||
if res.get('headers'):
|
||||
try:
|
||||
headers.update(eval(res['headers']))
|
||||
except Exception:
|
||||
pass
|
||||
if current_issue.project_id:
|
||||
if self.project_id:
|
||||
current_objects = filter(None, headers.get('X-Odoo-Objects', '').split(','))
|
||||
current_objects.insert(0, 'project.project-%s, ' % current_issue.project_id.id)
|
||||
current_objects.insert(0, 'project.project-%s, ' % self.project_id.id)
|
||||
headers['X-Odoo-Objects'] = ','.join(current_objects)
|
||||
if current_issue.tag_ids:
|
||||
headers['X-Odoo-Tags'] = ','.join([tag.name for tag in current_issue.tag_ids])
|
||||
if self.tag_ids:
|
||||
headers['X-Odoo-Tags'] = ','.join(self.tag_ids.mapped('name'))
|
||||
res['headers'] = repr(headers)
|
||||
return res
|
||||
|
||||
@@ -1,70 +1,43 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from openerp.osv import fields, osv
|
||||
from openerp import api
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class project_project(osv.Model):
|
||||
class Project(models.Model):
|
||||
_inherit = 'project.project'
|
||||
|
||||
def _get_alias_models(self, cr, uid, context=None):
|
||||
res = super(project, self)._get_alias_models(cr, uid, context=context)
|
||||
issue_count = fields.Integer(compute='_compute_issue_count', string="Issues")
|
||||
issue_ids = fields.One2many('project.issue', 'project_id', string="Issues", domain=['|', ('stage_id.fold', '=', False), ('stage_id', '=', False)])
|
||||
label_issues = fields.Char(string='Use Issues as', help="Customize the issues label, for example to call them cases.", default='Issues')
|
||||
use_issues = fields.Boolean(related="analytic_account_id.use_issues", default=True)
|
||||
issue_needaction_count = fields.Integer(compute="_issue_needaction_count", string="Issues")
|
||||
|
||||
@api.model
|
||||
def _get_alias_models(self):
|
||||
res = super(Project, self)._get_alias_models()
|
||||
res.append(("project.issue", "Issues"))
|
||||
return res
|
||||
|
||||
def _compute_issue_count(self):
|
||||
self.issue_count = self.env['project.issue'].search_count([('project_id', '=', self.id), '|', ('stage_id.fold', '=', False), ('stage_id', '=', False)])
|
||||
|
||||
def _issue_count(self, cr, uid, ids, field_name, arg, context=None):
|
||||
Issue = self.pool['project.issue']
|
||||
return {
|
||||
project_id: Issue.search_count(cr,uid, [('project_id', '=', project_id), '|', ('stage_id.fold', '=', False), ('stage_id', '=', False)], context=context)
|
||||
for project_id in ids
|
||||
}
|
||||
def _issue_needaction_count(self):
|
||||
issue_data = self.env['project.issue'].read_group([('project_id', 'in', self.ids), ('message_needaction', '=', True)], ['project_id'], ['project_id'])
|
||||
result = dict((data['project_id'][0], data['project_id_count']) for data in issue_data)
|
||||
for project in self:
|
||||
project.issue_needaction_count = int(result.get(project.id, 0))
|
||||
|
||||
def _issue_needaction_count(self, cr, uid, ids, field_name, arg, context=None):
|
||||
Issue = self.pool['project.issue']
|
||||
res = dict.fromkeys(ids, 0)
|
||||
projects = Issue.read_group(cr, uid, [('project_id', 'in', ids), ('message_needaction', '=', True)], ['project_id'], ['project_id'], context=context)
|
||||
res.update({project['project_id'][0]: int(project['project_id_count']) for project in projects})
|
||||
return res
|
||||
|
||||
_columns = {
|
||||
'issue_count': fields.function(_issue_count, type='integer', string="Issues",),
|
||||
'issue_ids': fields.one2many('project.issue', 'project_id', string="Issues",
|
||||
domain=['|', ('stage_id.fold', '=', False), ('stage_id', '=', False)]),
|
||||
'issue_needaction_count': fields.function(_issue_needaction_count, type='integer', string="Issues",),
|
||||
'label_issues': fields.char('Use Issues as', help="Customize the issues label, for example to call them cases."),
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
'use_issues': True,
|
||||
'label_issues': 'Issues',
|
||||
}
|
||||
|
||||
def _check_create_write_values(self, cr, uid, vals, context=None):
|
||||
""" Perform some check on values given to create or write. """
|
||||
# Handle use_tasks / use_issues: if only one is checked, alias should take the same model
|
||||
if vals.get('use_tasks') and not vals.get('use_issues'):
|
||||
vals['alias_model'] = 'project.task'
|
||||
elif vals.get('use_issues') and not vals.get('use_tasks'):
|
||||
vals['alias_model'] = 'project.issue'
|
||||
|
||||
def on_change_use_tasks_or_issues(self, cr, uid, ids, use_tasks, use_issues, context=None):
|
||||
values = {}
|
||||
if use_tasks and not use_issues:
|
||||
values['alias_model'] = 'project.task'
|
||||
elif not use_tasks and use_issues:
|
||||
values['alias_model'] = 'project.issue'
|
||||
return {'value': values}
|
||||
|
||||
def create(self, cr, uid, vals, context=None):
|
||||
self._check_create_write_values(cr, uid, vals, context=context)
|
||||
return super(project_project, self).create(cr, uid, vals, context=context)
|
||||
@api.onchange('use_issues', 'use_tasks')
|
||||
def _on_change_use_tasks_or_issues(self):
|
||||
if self.use_tasks and not self.use_issues:
|
||||
self.alias_model = 'project.task'
|
||||
elif not self.use_tasks and self.use_issues:
|
||||
self.alias_model = 'project.issue'
|
||||
|
||||
@api.multi
|
||||
def write(self, vals):
|
||||
self._check_create_write_values(vals)
|
||||
res = super(project_project, self).write(vals)
|
||||
res = super(Project, self).write(vals)
|
||||
if 'active' in vals:
|
||||
# archiving/unarchiving a project does it on its issues, too
|
||||
issues = self.with_context(active_test=False).mapped('issue_ids')
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from openerp import models
|
||||
from odoo import models
|
||||
|
||||
|
||||
class ProjectStage(models.Model):
|
||||
_name = "project.task.type"
|
||||
_inherit = ['project.task.type']
|
||||
|
||||
def _get_mail_template_id_domain(self):
|
||||
|
||||
@@ -1,21 +1,16 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from openerp.osv import fields, osv
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class res_partner(osv.osv):
|
||||
""" Inherits partner and adds Issue information in the partner form """
|
||||
class ResPartner(models.Model):
|
||||
_inherit = 'res.partner'
|
||||
|
||||
def _issue_count(self, cr, uid, ids, field_name, arg, context=None):
|
||||
Issue = self.pool['project.issue']
|
||||
partners = {id: self.search(cr, uid, [('id', 'child_of', ids)]) for id in ids}
|
||||
return {
|
||||
partner_id: Issue.search_count(cr, uid, [('partner_id', 'in', partners[partner_id])])
|
||||
for partner_id in partners.keys()
|
||||
}
|
||||
issue_count = fields.Integer(compute='_compute_issue_count', string='# Issues')
|
||||
|
||||
_columns = {
|
||||
'issue_count': fields.function(_issue_count, string='# Issues', type='integer'),
|
||||
}
|
||||
def _compute_issue_count(self):
|
||||
Issue = self.pool['project.issue']
|
||||
partners = {id: self.search([('id', 'child_of', self.ids)]) for id in self.ids}
|
||||
for partner_id in partners.keys():
|
||||
partner.issue_count = Issue.search_count([('partner_id', 'in', partners[partner_id])])
|
||||
|
||||
@@ -1,38 +1,33 @@
|
||||
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from openerp.osv import fields, osv
|
||||
from openerp import tools
|
||||
from odoo import fields, models, tools
|
||||
|
||||
|
||||
class project_issue_report(osv.osv):
|
||||
class ProjectIssueReport(models.Model):
|
||||
_name = "project.issue.report"
|
||||
_auto = False
|
||||
|
||||
_columns = {
|
||||
'company_id': fields.many2one('res.company', 'Company', readonly=True),
|
||||
'opening_date': fields.datetime('Date of Opening', readonly=True),
|
||||
'create_date': fields.datetime('Create Date', readonly=True),
|
||||
'date_closed': fields.datetime('Date of Closing', readonly=True),
|
||||
'date_last_stage_update': fields.datetime('Last Stage Update', readonly=True),
|
||||
'stage_id': fields.many2one('project.task.type', 'Stage'),
|
||||
'nbr': fields.integer('# of Issues', readonly=True), # TDE FIXME master: rename into nbr_issues
|
||||
'working_hours_open': fields.float('Avg. Working Hours to Open', readonly=True, group_operator="avg"),
|
||||
'working_hours_close': fields.float('Avg. Working Hours to Close', readonly=True, group_operator="avg"),
|
||||
'delay_open': fields.float('Avg. Delay to Open', digits=(16,2), readonly=True, group_operator="avg",
|
||||
help="Number of Days to open the project issue."),
|
||||
'delay_close': fields.float('Avg. Delay to Close', digits=(16,2), readonly=True, group_operator="avg",
|
||||
help="Number of Days to close the project issue"),
|
||||
'company_id' : fields.many2one('res.company', 'Company'),
|
||||
'priority': fields.selection([('0','Low'), ('1','Normal'), ('2','High')], 'Priority'),
|
||||
'project_id':fields.many2one('project.project', 'Project',readonly=True),
|
||||
'user_id' : fields.many2one('res.users', 'Assigned to',readonly=True),
|
||||
'partner_id': fields.many2one('res.partner','Contact'),
|
||||
'channel': fields.char('Channel', readonly=True, help="Communication Channel."),
|
||||
'task_id': fields.many2one('project.task', 'Task'),
|
||||
'email': fields.integer('# Emails', size=128, readonly=True),
|
||||
}
|
||||
company_id = fields.Many2one('res.company', 'Company', readonly=True)
|
||||
opening_date = fields.Datetime('Date of Opening', readonly=True)
|
||||
create_date = fields.Datetime('Create Date', readonly=True)
|
||||
date_closed = fields.Datetime('Date of Closing', readonly=True)
|
||||
date_last_stage_update = fields.Datetime('Last Stage Update', readonly=True)
|
||||
stage_id = fields.Many2one('project.task.type', 'Stage')
|
||||
nbr = fields.Integer('# of Issues', readonly=True) # TDE FIXME master: rename into nbr_issues
|
||||
working_hours_open = fields.Float('Avg. Working Hours to Open', readonly=True, group_operator="avg")
|
||||
working_hours_close = fields.Float('Avg. Working Hours to Close', readonly=True, group_operator="avg")
|
||||
delay_open = fields.Float('Avg. Delay to Open', digits=(16, 2), readonly=True, group_operator="avg",
|
||||
help="Number of Days to open the project issue.")
|
||||
delay_close = fields.Float('Avg. Delay to Close', digits=(16, 2), readonly=True, group_operator="avg",
|
||||
help="Number of Days to close the project issue")
|
||||
priority = fields.Selection([('0', 'Low'), ('1', 'Normal'), ('2', 'High')])
|
||||
project_id = fields.Many2one('project.project', 'Project', readonly=True)
|
||||
user_id = fields.Many2one('res.users', 'Assigned to', readonly=True)
|
||||
partner_id = fields.Many2one('res.partner', 'Contact')
|
||||
channel = fields.Char('Channel', readonly=True, help="Communication Channel.")
|
||||
task_id = fields.Many2one('project.task', 'Task')
|
||||
email = fields.Integer('# Emails', readonly=True)
|
||||
|
||||
def init(self, cr):
|
||||
tools.drop_view_if_exists(cr, 'project_issue_report')
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<odoo>
|
||||
<record id="view_project_issue_report_pivot" model="ir.ui.view">
|
||||
<field name="name">project.issue.report.pivot</field>
|
||||
<field name="model">project.issue.report</field>
|
||||
@@ -93,9 +92,6 @@
|
||||
<field name="help">This report on the project issues allows you to analyse the quality of your support or after-sales services. You can track the issues per age. You can analyse the time required to open or close an issue, the number of email to exchange and the time spent on average by issues.</field>
|
||||
</record>
|
||||
|
||||
<menuitem action="action_project_issue_report" id="menu_project_issue_report_tree"
|
||||
<menuitem id="menu_project_issue_report_tree" action="action_project_issue_report"
|
||||
parent="base.menu_project_report"/>
|
||||
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
</odoo>
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<odoo>
|
||||
<data noupdate="1">
|
||||
|
||||
<record model="ir.rule" id="issue_project_manager_rule">
|
||||
<record id="issue_project_manager_rule" model="ir.rule">
|
||||
<field name="name">Project/Issue: project manager: see all</field>
|
||||
<field name="model_id" ref="model_project_issue"/>
|
||||
<field name="domain_force">[(1, '=', 1)]</field>
|
||||
<field name="groups" eval="[(4,ref('project.group_project_manager'))]"/>
|
||||
</record>
|
||||
|
||||
<record model="ir.rule" id="issue_user_rule">
|
||||
<record id="issue_user_rule" model="ir.rule">
|
||||
<field name="name">Project/Issue: employees: employee or (followers and following)</field>
|
||||
<field name="model_id" ref="model_project_issue"/>
|
||||
<field name="domain_force">['|',
|
||||
@@ -46,4 +46,4 @@
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
</odoo>
|
||||
|
||||
@@ -1,17 +1,15 @@
|
||||
<?xml version="1.0"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<record id="analytic_account_inherited_issue_form" model="ir.ui.view">
|
||||
<field name="name">account.analytic.account.issue.form.inherit</field>
|
||||
<field name="model">account.analytic.account</field>
|
||||
<field name="inherit_id" ref="project.analytic_account_inherited_form"/>
|
||||
<field eval="18" name="priority"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr='//div[@name="project"]' position='inside'>
|
||||
<field name="use_issues" groups="base.group_no_one"/>
|
||||
<label for="use_issues" groups="base.group_no_one"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="analytic_account_inherited_issue_form" model="ir.ui.view">
|
||||
<field name="name">account.analytic.account.issue.form.inherit</field>
|
||||
<field name="model">account.analytic.account</field>
|
||||
<field name="inherit_id" ref="project.analytic_account_inherited_form"/>
|
||||
<field name="priority" eval="18"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr='//div[@name="project"]' position='inside'>
|
||||
<field name="use_issues" groups="base.group_no_one"/>
|
||||
<label for="use_issues" groups="base.group_no_one"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="view_project_kanban_inherited" model="ir.ui.view">
|
||||
<field name="name">project.project.kanban.inherited</field>
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
<?xml version="1.0"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<!--
|
||||
ALL BUGS
|
||||
-->
|
||||
<record model="ir.actions.act_window" id="project_issue_categ_act0">
|
||||
<record id="project_issue_categ_act0" model="ir.actions.act_window">
|
||||
<field name="name">Issues</field>
|
||||
<field name="res_model">project.issue</field>
|
||||
<field name="view_type">form</field>
|
||||
@@ -16,49 +14,48 @@
|
||||
<field name="search_view_id" ref="view_project_issue_filter"/>
|
||||
<field name="help" type="html">
|
||||
<p>
|
||||
The Odoo issues tacker allows you to efficiently manage things
|
||||
The Odoo issues tracker allows you to efficiently manage things
|
||||
like internal requests, software development bugs, customer
|
||||
complaints, project troubles, material breakdowns, etc.
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.actions.act_window.view" id="action_crm_tag_kanban_view0">
|
||||
<record id="action_crm_tag_kanban_view0" model="ir.actions.act_window.view">
|
||||
<field name="sequence" eval="0"/>
|
||||
<field name="view_mode">kanban</field>
|
||||
<field name="view_id" ref="project_issue_kanban_view"/>
|
||||
<field name="act_window_id" ref="project_issue_categ_act0"/>
|
||||
</record>
|
||||
|
||||
<record model="ir.actions.act_window.view" id="action_crm_tag_tree_view0">
|
||||
<record id="action_crm_tag_tree_view0" model="ir.actions.act_window.view">
|
||||
<field name="sequence" eval="1"/>
|
||||
<field name="view_mode">tree</field>
|
||||
<field name="view_id" ref="project_issue_tree_view"/>
|
||||
<field name="act_window_id" ref="project_issue_categ_act0"/>
|
||||
</record>
|
||||
|
||||
<record model="ir.actions.act_window.view" id="action_crm_tag_calendar_view0">
|
||||
<record id="action_crm_tag_calendar_view0" model="ir.actions.act_window.view">
|
||||
<field name="sequence" eval="2"/>
|
||||
<field name="view_mode">calendar</field>
|
||||
<field name="view_id" ref="project_issue_calendar_view"/>
|
||||
<field name="act_window_id" ref="project_issue_categ_act0"/>
|
||||
</record>
|
||||
|
||||
<record model="ir.actions.act_window.view" id="action_crm_tag_form_view0">
|
||||
<record id="action_crm_tag_form_view0" model="ir.actions.act_window.view">
|
||||
<field name="sequence" eval="3"/>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="view_id" ref="project_issue_form_view"/>
|
||||
<field name="act_window_id" ref="project_issue_categ_act0"/>
|
||||
</record>
|
||||
|
||||
<record model="ir.actions.act_window.view" id="action_crm_tag_graph_view0">
|
||||
<record id="action_crm_tag_graph_view0" model="ir.actions.act_window.view">
|
||||
<field name="sequence" eval="4"/>
|
||||
<field name="view_mode">graph</field>
|
||||
<field name="view_id" ref="project_issue_graph_view"/>
|
||||
<field name="act_window_id" ref="project_issue_categ_act0"/>
|
||||
</record>
|
||||
|
||||
<menuitem name="Issues" id="menu_project_issue_track" parent="project.menu_project_management"
|
||||
<menuitem id="menu_project_issue_track" name="Issues" parent="project.menu_project_management"
|
||||
action="project_issue_categ_act0" sequence="15"/>
|
||||
</data>
|
||||
</openerp>
|
||||
</odoo>
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
<?xml version="1.0"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<record model="ir.ui.view" id="project_issue_form_view">
|
||||
<field name="name">Project Issue Tracker Form</field>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="project_issue_form_view" model="ir.ui.view">
|
||||
<field name="name">project.issue.form.view</field>
|
||||
<field name="model">project.issue</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
@@ -30,11 +28,10 @@
|
||||
<field name="tag_ids" widget="many2many_tags"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="partner_id" on_change="onchange_partner_id(partner_id)"/>
|
||||
<field name="partner_id"/>
|
||||
<field name="email_from"/>
|
||||
<field name="project_id" on_change="on_change_project(project_id)" context="{'default_use_issues':1}"
|
||||
groups="base.group_user"/>
|
||||
<field name="task_id" groups="base.group_no_one" on_change="onchange_task_id(task_id)" context="{'default_project_id':project_id}"/>
|
||||
<field name="project_id" context="{'default_use_issues':1}" groups="base.group_user"/>
|
||||
<field name="task_id" groups="base.group_no_one" context="{'default_project_id':project_id}"/>
|
||||
</group>
|
||||
</group>
|
||||
<notebook>
|
||||
@@ -67,8 +64,8 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="project_issue_tree_view">
|
||||
<field name="name">Project Issue Tracker Tree</field>
|
||||
<record id="project_issue_tree_view" model="ir.ui.view">
|
||||
<field name="name">project.issue.tree.view</field>
|
||||
<field name="model">project.issue</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Issue Tracker Tree" decoration-bf="message_needaction==True">
|
||||
@@ -78,7 +75,7 @@
|
||||
<field name="partner_id"/>
|
||||
<field name="project_id" groups="base.group_user"/>
|
||||
<field name="priority" string="Priority" groups="base.group_user"/>
|
||||
<field name="create_date"/>
|
||||
<field name="create_date" string="Creation Date"/>
|
||||
<field name="user_id"/>
|
||||
<field name="stage_id" widget="selection" readonly="1"/>
|
||||
<field name="tag_ids" invisible="1"/>
|
||||
@@ -88,7 +85,7 @@
|
||||
</record>
|
||||
|
||||
<record id="view_project_issue_filter" model="ir.ui.view">
|
||||
<field name="name">Project Issue Tracker Search</field>
|
||||
<field name="name">project.issue.search.view</field>
|
||||
<field name="model">project.issue</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Issue Tracker Search">
|
||||
@@ -121,8 +118,8 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="project_issue_calendar_view">
|
||||
<field name="name">Project Issue Tracker Calendar</field>
|
||||
<record id="project_issue_calendar_view" model="ir.ui.view">
|
||||
<field name="name">project.issue.calendar.view</field>
|
||||
<field name="model">project.issue</field>
|
||||
<field name="priority" eval="2"/>
|
||||
<field name="arch" type="xml">
|
||||
@@ -136,8 +133,8 @@
|
||||
|
||||
<!-- Project Issue Karban View-->
|
||||
|
||||
<record model="ir.ui.view" id="project_issue_kanban_view">
|
||||
<field name="name">Project Issue Kanban</field>
|
||||
<record id="project_issue_kanban_view" model="ir.ui.view">
|
||||
<field name="name">project.issue.kanban.view</field>
|
||||
<field name="model">project.issue</field>
|
||||
<field name="arch" type="xml">
|
||||
<kanban default_group_by="stage_id" class="o_kanban_small_column">
|
||||
@@ -198,8 +195,8 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="project_issue_pivot_view">
|
||||
<field name="name">Project Issue Tracker Pivot</field>
|
||||
<record id="project_issue_pivot_view" model="ir.ui.view">
|
||||
<field name="name">project.issue.pivot.view</field>
|
||||
<field name="model">project.issue</field>
|
||||
<field name="arch" type="xml">
|
||||
<pivot string="Project Issues">
|
||||
@@ -209,8 +206,8 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="project_issue_graph_view">
|
||||
<field name="name">Project Issue Tracker Graph</field>
|
||||
<record id="project_issue_graph_view" model="ir.ui.view">
|
||||
<field name="name">project.issue.graph.view</field>
|
||||
<field name="model">project.issue</field>
|
||||
<field name="arch" type="xml">
|
||||
<graph string="Project Issues" type="bar">
|
||||
@@ -222,8 +219,8 @@
|
||||
|
||||
|
||||
<!-- Feature Requests -->
|
||||
<record model="ir.ui.view" id="project_feature_tree_view">
|
||||
<field name="name">Project Issue- Feature Tracker Tree</field>
|
||||
<record id="project_feature_tree_view" model="ir.ui.view">
|
||||
<field name="name">project.issue.tree.view.featured</field>
|
||||
<field name="model">project.issue</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Feature Tracker Tree" decoration-bf="message_needaction==True">
|
||||
@@ -250,7 +247,7 @@
|
||||
</field>
|
||||
<field name="help" type="html">
|
||||
<p>
|
||||
The Odoo issues tacker allows you to efficiently manage things
|
||||
The Odoo issues tracker allows you to efficiently manage things
|
||||
like internal requests, software development bugs, customer
|
||||
complaints, project troubles, material breakdowns, etc.
|
||||
</p>
|
||||
@@ -264,7 +261,7 @@
|
||||
<field name="view_mode">kanban,tree,form,calendar,graph</field>
|
||||
<field name="help" type="html">
|
||||
<p>
|
||||
The Odoo issues tacker allows you to efficiently manage things
|
||||
The Odoo issues tracker allows you to efficiently manage things
|
||||
like internal requests, software development bugs, customer
|
||||
complaints, project troubles, material breakdowns, etc.
|
||||
</p>
|
||||
@@ -286,14 +283,10 @@
|
||||
<p class="oe_view_nocontent_create">
|
||||
Click to create an issue.
|
||||
</p><p>
|
||||
You can track your issues from this menu and the action we
|
||||
will take.
|
||||
You can track your issues from this menu and the action we will take.
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<menuitem name="Issues" id="portal_services_issues" parent="portal.portal_projects"
|
||||
action="open_view_issue" sequence="10"/>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
<menuitem id="portal_services_issues" name="Issues" parent="portal.portal_projects"
|
||||
action="open_view_issue" sequence="10"/>
|
||||
</odoo>
|
||||
|
||||
@@ -1,36 +1,28 @@
|
||||
<?xml version="1.0"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<record id="view_project_form_inherited" model="ir.ui.view">
|
||||
<field name="name">project.project.form.inherited</field>
|
||||
<field name="model">project.project</field>
|
||||
<field name="inherit_id" ref="project.edit_project"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr='//field[@name="use_tasks"]' position='attributes'>
|
||||
<attribute name="on_change">on_change_use_tasks_or_issues(use_tasks, use_issues)</attribute>
|
||||
</xpath>
|
||||
<xpath expr='//div[@name="options_active"]' position="attributes">
|
||||
<attribute name="invisible">0</attribute>
|
||||
</xpath>
|
||||
<xpath expr='//div[@name="options_active"]' position='inside'>
|
||||
<div>
|
||||
<field name="use_issues" class="oe_inline"
|
||||
on_change="on_change_use_tasks_or_issues(use_tasks, use_issues)"/>
|
||||
<label for="use_issues" class="oe_inline" string="Issues"/>
|
||||
<span attrs="{'invisible':[('use_issues', '=', False)]}">as </span>
|
||||
<field name="label_issues" class="oe_inline oe_input_align" attrs="{'invisible': [('use_issues', '=', False)]}"/>
|
||||
</div>
|
||||
</xpath>
|
||||
<div name="button_box" position="inside">
|
||||
<button class="oe_stat_button" type="action" attrs="{'invisible':[('use_issues','=', False)]}"
|
||||
name="%(act_project_project_2_project_issue_all)d" icon="fa-bug">
|
||||
<field string="Issues" name="issue_count" widget="statinfo" options="{'label_field': 'label_issues'}"/>
|
||||
</button>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<!-- Project -->
|
||||
<record id="view_project_form_inherited" model="ir.ui.view">
|
||||
<field name="name">project.project.form.inherited</field>
|
||||
<field name="model">project.project</field>
|
||||
<field name="inherit_id" ref="project.edit_project"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr='//div[@name="options_active"]' position="attributes">
|
||||
<attribute name="invisible">0</attribute>
|
||||
</xpath>
|
||||
<xpath expr='//div[@name="options_active"]' position='inside'>
|
||||
<div>
|
||||
<field name="use_issues" class="oe_inline"/>
|
||||
<label for="use_issues" class="oe_inline" string="Issues"/>
|
||||
<span attrs="{'invisible':[('use_issues', '=', False)]}">as </span>
|
||||
<field name="label_issues" class="oe_inline oe_input_align" attrs="{'invisible': [('use_issues', '=', False)]}"/>
|
||||
</div>
|
||||
<xpath expr='//field[@name="use_tasks"]' position="attributes">
|
||||
<attribute name="attrs">{'on_change': 'on_change_use_tasks_or_issues(use_tasks, use_issues)'}</attribute>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
</xpath>
|
||||
<div name="button_box" position="inside">
|
||||
<button class="oe_stat_button" type="action" attrs="{'invisible':[('use_issues','=', False)]}"
|
||||
name="%(act_project_project_2_project_issue_all)d" icon="fa-bug">
|
||||
<field string="Issues" name="issue_count" widget="statinfo" options="{'label_field': 'label_issues'}"/>
|
||||
</button>
|
||||
</div>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
|
||||
@@ -1,24 +1,21 @@
|
||||
<?xml version="1.0"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<!-- res.partner -->
|
||||
<record model="ir.ui.view" id="res_partner_issues_button_view">
|
||||
<field name="name">res.partner.issues.button.view</field>
|
||||
<field name="model">res.partner</field>
|
||||
<field name="inherit_id" ref="base.view_partner_form" />
|
||||
<field name="priority" eval="50"/>
|
||||
<field name="groups_id" eval="[(4, ref('project.group_project_user'))]"/>
|
||||
<field name="arch" type="xml">
|
||||
<div name="button_box" position="inside">
|
||||
<button class="oe_stat_button" type="action" name="%(action_view_issues)d"
|
||||
context="{'search_default_partner_id': active_id, 'default_partner_id': active_id}"
|
||||
attrs="{'invisible': [('customer', '=', False)]}"
|
||||
icon="fa-bug">
|
||||
<field string="Issues" name="issue_count" widget="statinfo"/>
|
||||
</button>
|
||||
</div>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<!-- res.partner -->
|
||||
<record id="res_partner_issues_button_view" model="ir.ui.view">
|
||||
<field name="name">res.partner.issues.button.view.inherit</field>
|
||||
<field name="model">res.partner</field>
|
||||
<field name="inherit_id" ref="base.view_partner_form" />
|
||||
<field name="priority" eval="50"/>
|
||||
<field name="groups_id" eval="[(4, ref('project.group_project_user'))]"/>
|
||||
<field name="arch" type="xml">
|
||||
<div name="button_box" position="inside">
|
||||
<button class="oe_stat_button" type="action" name="%(action_view_issues)d"
|
||||
context="{'search_default_partner_id': active_id, 'default_partner_id': active_id}"
|
||||
attrs="{'invisible': [('customer', '=', False)]}"
|
||||
icon="fa-bug">
|
||||
<field name="issue_count" string="Issues" widget="statinfo"/>
|
||||
</button>
|
||||
</div>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
|
||||
Reference in New Issue
Block a user