<commit_before># -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.

from datetime import datetime, date
from lxml import etree
import time

from openerp import api
from openerp import SUPERUSER_ID
from openerp import tools
from openerp.osv import fields, osv
from openerp.tools.safe_eval import safe_eval as eval
from openerp.tools.translate import _
from openerp.exceptions import UserError


class project_task_type(osv.osv):
    _name = 'project.task.type'
    _description = 'Task Stage'
    _order = 'sequence'

    def _get_mail_template_id_domain(self):
        return [('model', '=', 'project.task')]

    _columns = {
        'name': fields.char('Stage Name', required=True, translate=True),
        'description': fields.text('Description', translate=True),
        'sequence': fields.integer('Sequence'),
        'project_ids': fields.many2many('project.project', 'project_task_type_rel', 'type_id', 'project_id', 'Projects'),
        'legend_priority': fields.char(
            'Priority Management Explanation', translate=True,
            help='Explanation text to help users using the star and priority mechanism on stages or issues that are in this stage.'),
        'legend_blocked': fields.char(
            'Kanban Blocked Explanation', translate=True,
            help='Override the default value displayed for the blocked state for kanban selection, when the task or issue is in that stage.'),
        'legend_done': fields.char(
            'Kanban Valid Explanation', translate=True,
            help='Override the default value displayed for the done state for kanban selection, when the task or issue is in that stage.'),
        'legend_normal': fields.char(
            'Kanban Ongoing Explanation', translate=True,
            help='Override the default value displayed for the normal state for kanban selection, when the task or issue is in that stage.'),
        'mail_template_id': fields.many2one(
            'mail.template',
            string='Email Template',
            domain=lambda self: self._get_mail_template_id_domain(),
            help="If set an email will be sent to the customer when the task or issue reaches this step."),
        'fold': fields.boolean('Folded in Tasks Pipeline',
                               help='This stage is folded in the kanban view when '
                               'there are no records in that stage to display.'),
    }

    def _get_default_project_ids(self, cr, uid, ctx=None):
        if ctx is None:
            ctx = {}
        default_project_id = ctx.get('default_project_id')
        return [default_project_id] if default_project_id else None

    _defaults = {
        'sequence': 1,
        'project_ids': _get_default_project_ids,
    }


class project(osv.osv):
    _name = "project.project"
    _description = "Project"
    _inherit = ['mail.alias.mixin', 'mail.thread', 'ir.needaction_mixin']
    _inherits = {'account.analytic.account': "analytic_account_id"}
    _period_number = 5

    def get_alias_model_name(self, vals):
        return vals.get('alias_model', 'project.task')

    def get_alias_values(self):
        values = super(project, self).get_alias_values()
        values['alias_defaults'] = {'project_id': self.id}
        return values

    def onchange_partner_id(self, cr, uid, ids, part=False, context=None):
        partner_obj = self.pool.get('res.partner')
        val = {}
        if not part:
            return {'value': val}
        if 'pricelist_id' in self.fields_get(cr, uid, context=context):
            pricelist = partner_obj.read(cr, uid, part, ['property_product_pricelist'], context=context)
            pricelist_id = pricelist.get('property_product_pricelist', False) and pricelist.get('property_product_pricelist')[0] or False
            val['pricelist_id'] = pricelist_id
        return {'value': val}

    def unlink(self, cr, uid, ids, context=None):
        analytic_account_to_delete = set()
        for proj in self.browse(cr, uid, ids, context=context):
            if proj.tasks:
                raise UserError(_('You cannot delete a project containing tasks. You can either delete all the project\'s tasks and then delete the project or simply deactivate the project.'))
            if proj.analytic_account_id and not proj.analytic_account_id.line_ids:
                analytic_account_to_delete.add(proj.analytic_account_id.id)
        res = super(project, self).unlink(cr, uid, ids, context=context)
        self.pool['account.analytic.account'].unlink(cr, uid, list(analytic_account_to_delete), context=context)
        return res

    def _get_attached_docs(self, cr, uid, ids, field_name, arg, context):
        res = {}
        attachment = self.pool.get('ir.attachment')
        task = self.pool.get('project.task')
        for id in ids:
            project_attachments = attachment.search(cr, uid, [('res_model', '=', 'project.project'), ('res_id', '=', id)], context=context, count=True)
            task_ids = task.search(cr, uid, [('project_id', '=', id)], context=context)
            task_attachments = attachment.search(cr, uid, [('res_model', '=', 'project.task'), ('res_id', 'in', task_ids)], context=context, count=True)
            res[id] = (project_attachments or 0) + (task_attachments or 0)
        return res
    def _task_count(self, cr, uid, ids, field_name, arg, context=None):
        if context is None:
            context = {}
        res={}
        for project in self.browse(cr, uid, ids, context=context):
            res[project.id] = len(project.task_ids)
        return res

    def _task_needaction_count(self, cr, uid, ids, field_name, arg, context=None):
        Task = self.pool['project.task']
        res = dict.fromkeys(ids, 0)
        projects = Task.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

    def _get_alias_models(self, cr, uid, context=None):
        """ Overriden in project_issue to offer more options """
        return [('project.task', "Tasks")]

    def _get_visibility_selection(self, cr, uid, context=None):
        """ Overriden in portal_project to offer more options """
        return [('portal', _('Customer Project: visible in portal if the customer is a follower')),
                ('employees', _('All Employees Project: all employees can access')),
                ('followers', _('Private Project: followers only'))]

    def attachment_tree_view(self, cr, uid, ids, context):
        task_ids = self.pool.get('project.task').search(cr, uid, [('project_id', 'in', ids)])
        domain = [
             '|',
             '&', ('res_model', '=', 'project.project'), ('res_id', 'in', ids),
             '&', ('res_model', '=', 'project.task'), ('res_id', 'in', task_ids)]
        res_id = ids and ids[0] or False
        return {
            'name': _('Attachments'),
            'domain': domain,
            'res_model': 'ir.attachment',
            'type': 'ir.actions.act_window',
            'view_id': False,
            'view_mode': 'kanban,tree,form',
            'view_type': 'form',
            'help': _('''<p class="oe_view_nocontent_create">
                        Documents are attached to the tasks and issues of your project.</p><p><commit_msg>[IMP] project: Wording of project privacy field<commit_after># -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.

from datetime import datetime, date
from lxml import etree
import time

from openerp import api
from openerp import SUPERUSER_ID
from openerp import tools
from openerp.osv import fields, osv
from openerp.tools.safe_eval import safe_eval as eval
from openerp.tools.translate import _
from openerp.exceptions import UserError


class project_task_type(osv.osv):
    _name = 'project.task.type'
    _description = 'Task Stage'
    _order = 'sequence'

    def _get_mail_template_id_domain(self):
        return [('model', '=', 'project.task')]

    _columns = {
        'name': fields.char('Stage Name', required=True, translate=True),
        'description': fields.text('Description', translate=True),
        'sequence': fields.integer('Sequence'),
        'project_ids': fields.many2many('project.project', 'project_task_type_rel', 'type_id', 'project_id', 'Projects'),
        'legend_priority': fields.char(
            'Priority Management Explanation', translate=True,
            help='Explanation text to help users using the star and priority mechanism on stages or issues that are in this stage.'),
        'legend_blocked': fields.char(
            'Kanban Blocked Explanation', translate=True,
            help='Override the default value displayed for the blocked state for kanban selection, when the task or issue is in that stage.'),
        'legend_done': fields.char(
            'Kanban Valid Explanation', translate=True,
            help='Override the default value displayed for the done state for kanban selection, when the task or issue is in that stage.'),
        'legend_normal': fields.char(
            'Kanban Ongoing Explanation', translate=True,
            help='Override the default value displayed for the normal state for kanban selection, when the task or issue is in that stage.'),
        'mail_template_id': fields.many2one(
            'mail.template',
            string='Email Template',
            domain=lambda self: self._get_mail_template_id_domain(),
            help="If set an email will be sent to the customer when the task or issue reaches this step."),
        'fold': fields.boolean('Folded in Tasks Pipeline',
                               help='This stage is folded in the kanban view when '
                               'there are no records in that stage to display.'),
    }

    def _get_default_project_ids(self, cr, uid, ctx=None):
        if ctx is None:
            ctx = {}
        default_project_id = ctx.get('default_project_id')
        return [default_project_id] if default_project_id else None

    _defaults = {
        'sequence': 1,
        'project_ids': _get_default_project_ids,
    }


class project(osv.osv):
    _name = "project.project"
    _description = "Project"
    _inherit = ['mail.alias.mixin', 'mail.thread', 'ir.needaction_mixin']
    _inherits = {'account.analytic.account': "analytic_account_id"}
    _period_number = 5

    def get_alias_model_name(self, vals):
        return vals.get('alias_model', 'project.task')

    def get_alias_values(self):
        values = super(project, self).get_alias_values()
        values['alias_defaults'] = {'project_id': self.id}
        return values

    def onchange_partner_id(self, cr, uid, ids, part=False, context=None):
        partner_obj = self.pool.get('res.partner')
        val = {}
        if not part:
            return {'value': val}
        if 'pricelist_id' in self.fields_get(cr, uid, context=context):
            pricelist = partner_obj.read(cr, uid, part, ['property_product_pricelist'], context=context)
            pricelist_id = pricelist.get('property_product_pricelist', False) and pricelist.get('property_product_pricelist')[0] or False
            val['pricelist_id'] = pricelist_id
        return {'value': val}

    def unlink(self, cr, uid, ids, context=None):
        analytic_account_to_delete = set()
        for proj in self.browse(cr, uid, ids, context=context):
            if proj.tasks:
                raise UserError(_('You cannot delete a project containing tasks. You can either delete all the project\'s tasks and then delete the project or simply deactivate the project.'))
            if proj.analytic_account_id and not proj.analytic_account_id.line_ids:
                analytic_account_to_delete.add(proj.analytic_account_id.id)
        res = super(project, self).unlink(cr, uid, ids, context=context)
        self.pool['account.analytic.account'].unlink(cr, uid, list(analytic_account_to_delete), context=context)
        return res

    def _get_attached_docs(self, cr, uid, ids, field_name, arg, context):
        res = {}
        attachment = self.pool.get('ir.attachment')
        task = self.pool.get('project.task')
        for id in ids:
            project_attachments = attachment.search(cr, uid, [('res_model', '=', 'project.project'), ('res_id', '=', id)], context=context, count=True)
            task_ids = task.search(cr, uid, [('project_id', '=', id)], context=context)
            task_attachments = attachment.search(cr, uid, [('res_model', '=', 'project.task'), ('res_id', 'in', task_ids)], context=context, count=True)
            res[id] = (project_attachments or 0) + (task_attachments or 0)
        return res
    def _task_count(self, cr, uid, ids, field_name, arg, context=None):
        if context is None:
            context = {}
        res={}
        for project in self.browse(cr, uid, ids, context=context):
            res[project.id] = len(project.task_ids)
        return res

    def _task_needaction_count(self, cr, uid, ids, field_name, arg, context=None):
        Task = self.pool['project.task']
        res = dict.fromkeys(ids, 0)
        projects = Task.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

    def _get_alias_models(self, cr, uid, context=None):
        """ Overriden in project_issue to offer more options """
        return [('project.task', "Tasks")]

    def _get_visibility_selection(self, cr, uid, context=None):
        """ Overriden in portal_project to offer more options """
        return [('portal', _('Customer project')),
                ('employees', _('All employees')),
                ('followers', _('Private: followers only'))]

    def attachment_tree_view(self, cr, uid, ids, context):
        task_ids = self.pool.get('project.task').search(cr, uid, [('project_id', 'in', ids)])
        domain = [
             '|',
             '&', ('res_model', '=', 'project.project'), ('res_id', 'in', ids),
             '&', ('res_model', '=', 'project.task'), ('res_id', 'in', task_ids)]
        res_id = ids and ids[0] or False
        return {
            'name': _('Attachments'),
            'domain': domain,
            'res_model': 'ir.attachment',
            'type': 'ir.actions.act_window',
            'view_id': False,
            'view_mode': 'kanban,tree,form',
            'view_type': 'form',
            'help': _('''<p class="oe_view_nocontent_create">
                        Documents are attached to the tasks and issues of your project.</p><p>
{'fraction_non_alphanumeric': 0.1241486276889878, 'fraction_numerical': 0.0014835794726549328, 'mean_word_length': 2.9067439409905163, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 2}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4479175', 'n_tokens_mistral': 4411, 'n_tokens_neox': 4235, 'n_words': 1226}