Example #1
0
class base_module_update(models.TransientModel):
    _name = "base.module.update"
    _description = "Update Module"

    updated = fields.Integer('Number of modules updated', readonly=True)
    added = fields.Integer('Number of modules added', readonly=True)
    state = fields.Selection([('init', 'init'), ('done', 'done')],
                             'Status',
                             readonly=True,
                             default='init')

    @api.one
    def update_module(self):
        self.updated, self.added = self.env['ir.module.module'].update_list()
        self.state = 'done'
        return False

    @api.multi
    def action_module_open(self):
        res = {
            'domain': str([]),
            'name': 'Modules',
            'view_type': 'form',
            'view_mode': 'tree,form',
            'res_model': 'ir.module.module',
            'view_id': False,
            'type': 'ir.actions.act_window',
        }
        return res
Example #2
0
class HrDepartment(models.Model):
    _inherit = 'hr.department'

    new_applicant_count = fields.Integer(
        compute='_compute_new_applicant_count', string='New Applicant')
    new_hired_employee = fields.Integer(compute='_compute_recruitment_stats',
                                        string='New Hired Employee')
    expected_employee = fields.Integer(compute='_compute_recruitment_stats',
                                       string='Expected Employee')

    @api.multi
    def _compute_new_applicant_count(self):
        applicant_data = self.env['hr.applicant'].read_group(
            [('department_id', 'in', self.ids),
             ('stage_id.sequence', '<=', '1')], ['department_id'],
            ['department_id'])
        result = dict((data['department_id'][0], data['department_id_count'])
                      for data in applicant_data)
        for department in self:
            department.new_applicant_count = result.get(department.id, 0)

    @api.multi
    def _compute_recruitment_stats(self):
        job_data = self.env['hr.job'].read_group(
            [('department_id', 'in', self.ids)],
            ['no_of_hired_employee', 'no_of_recruitment', 'department_id'],
            ['department_id'])
        new_emp = dict((data['department_id'][0], data['no_of_hired_employee'])
                       for data in job_data)
        expected_emp = dict(
            (data['department_id'][0], data['no_of_recruitment'])
            for data in job_data)
        for department in self:
            department.new_hired_employee = new_emp.get(department.id, 0)
            department.expected_employee = expected_emp.get(department.id, 0)
Example #3
0
class AccountAssetCategory(models.Model):
    _name = 'account.asset.category'
    _description = 'Asset category'

    active = fields.Boolean(default=True)
    name = fields.Char(required=True, index=True, string="Asset Type")
    account_analytic_id = fields.Many2one('account.analytic.account', string='Analytic Account')
    account_asset_id = fields.Many2one('account.account', string='Asset Account', required=True, domain=[('internal_type','=','other'), ('deprecated', '=', False)])
    account_income_recognition_id = fields.Many2one('account.account', string='Recognition Income Account', domain=[('internal_type','=','other'), ('deprecated', '=', False)], oldname='account_expense_depreciation_id')
    account_depreciation_id = fields.Many2one('account.account', string='Depreciation Account', required=True, domain=[('internal_type','=','other'), ('deprecated', '=', False)])
    journal_id = fields.Many2one('account.journal', string='Journal', required=True)
    company_id = fields.Many2one('res.company', string='Company', required=True, default=lambda self: self.env['res.company']._company_default_get('account.asset.category'))
    method = fields.Selection([('linear', 'Linear'), ('degressive', 'Degressive')], string='Computation Method', required=True, default='linear',
        help="Choose the method to use to compute the amount of depreciation lines.\n"
            "  * Linear: Calculated on basis of: Gross Value / Number of Depreciations\n"
            "  * Degressive: Calculated on basis of: Residual Value * Degressive Factor")
    method_number = fields.Integer(string='Number of Depreciations', default=5, help="The number of depreciations needed to depreciate your asset")
    method_period = fields.Integer(string='Period Length', default=1, help="State here the time between 2 depreciations, in months", required=True)
    method_progress_factor = fields.Float('Degressive Factor', default=0.3)
    method_time = fields.Selection([('number', 'Number of Depreciations'), ('end', 'Ending Date')], string='Time Method', required=True, default='number',
        help="Choose the method to use to compute the dates and number of depreciation lines.\n"
           "  * Number of Depreciations: Fix the number of depreciation lines and the time between 2 depreciations.\n"
           "  * Ending Date: Choose the time between 2 depreciations and the date the depreciations won't go beyond.")
    method_end = fields.Date('Ending date')
    prorata = fields.Boolean(string='Prorata Temporis', help='Indicates that the first depreciation entry for this asset have to be done from the purchase date instead of the first of January')
    open_asset = fields.Boolean(string='Post Journal Entries', help="Check this if you want to automatically confirm the assets of this category when created by invoices.")
    type = fields.Selection([('sale', 'Sale: Revenue Recognition'), ('purchase', 'Purchase: Asset')], required=True, index=True, default='purchase')

    @api.onchange('type')
    def onchange_type(self):
        if self.type == 'sale':
            self.prorata = True
            self.method_period = 1
        else:
            self.method_period = 12
Example #4
0
class SaasClient(models.AbstractModel):
    _name = 'saas_base.client'
    
    users_len = fields.Integer('Count users', readonly=True)
    max_users = fields.Char('Max users allowed', readonly=True)
    file_storage = fields.Integer('File storage (MB)', readonly=True)
    db_storage = fields.Integer('DB storage (MB)', readonly=True)
    total_storage_limit = fields.Integer('Total storage limit (MB)', readonly=True, default=0)
    expiration_datetime = fields.Datetime('Expiration', track_visibility='onchange')
    trial = fields.Boolean('Trial', help='indication of trial clients', default=False, readonly=True)
Example #5
0
class HrEquipmentCategory(models.Model):
    _name = 'hr.equipment.category'
    _inherits = {"mail.alias": "alias_id"}
    _inherit = ['mail.thread']
    _description = 'Asset Category'

    @api.one
    @api.depends('equipment_ids')
    def _compute_fold(self):
        self.fold = False if self.equipment_count else True

    name = fields.Char('Category Name', required=True, translate=True)
    user_id = fields.Many2one('res.users', 'Responsible', track_visibility='onchange', default=lambda self: self.env.uid)
    color = fields.Integer('Color Index')
    note = fields.Text('Comments', translate=True)
    equipment_ids = fields.One2many('hr.equipment', 'category_id', string='Equipments', copy=False)
    equipment_count = fields.Integer(string="Equipment", compute='_compute_equipment_count')
    maintenance_ids = fields.One2many('hr.equipment.request', 'category_id', copy=False)
    maintenance_count = fields.Integer(string="Maintenance", compute='_compute_maintenance_count')
    alias_id = fields.Many2one(
        'mail.alias', 'Alias', ondelete='cascade', required=True,
        help="Email alias for this equipment category. New emails will automatically "
        "create new maintenance request for this equipment category.")
    fold = fields.Boolean(string='Folded in Maintenance Pipe', compute='_compute_fold', store=True)

    @api.multi
    def _compute_equipment_count(self):
        equipment_data = self.env['hr.equipment'].read_group([('category_id', 'in', self.ids)], ['category_id'], ['category_id'])
        mapped_data = dict([(m['category_id'][0], m['category_id_count']) for m in equipment_data])
        for category in self:
            category.equipment_count = mapped_data.get(category.id, 0)

    @api.multi
    def _compute_maintenance_count(self):
        maintenance_data = self.env['hr.equipment.request'].read_group([('category_id', 'in', self.ids)], ['category_id'], ['category_id'])
        mapped_data = dict([(m['category_id'][0], m['category_id_count']) for m in maintenance_data])
        for category in self:
            category.maintenance_count = mapped_data.get(category.id, 0)

    @api.model
    def create(self, vals):
        self = self.with_context(alias_model_name='hr.equipment.request', alias_parent_model_name=self._name)
        category_id = super(HrEquipmentCategory, self).create(vals)
        category_id.alias_id.write({'alias_parent_thread_id': category_id.id, 'alias_defaults': {'category_id': category_id.id}})
        return category_id

    @api.multi
    def unlink(self):
        for category in self:
            if category.equipment_ids or category.maintenance_ids:
                raise UserError(_("You cannot delete an equipment category containing equipments or maintenance requests."))
        res = super(HrEquipmentCategory, self).unlink()
        return res
Example #6
0
class DateRangeGenerator(models.TransientModel):
    _name = 'date.range.generator'

    @api.model
    def _default_company(self):
        return self.env['res.company']._company_default_get('date.range')

    name_prefix = fields.Char('Range name prefix', required=True)
    date_start = fields.Date(strint='Start date', required=True)
    type_id = fields.Many2one(comodel_name='date.range.type',
                              string='Type',
                              required=True,
                              ondelete='cascade')
    company_id = fields.Many2one(comodel_name='res.company',
                                 string='Company',
                                 default=_default_company)
    unit_of_time = fields.Selection([(YEARLY, 'years'), (MONTHLY, 'months'),
                                     (WEEKLY, 'weeks'), (DAILY, 'days')],
                                    required=True)
    duration_count = fields.Integer('Duration', required=True)
    count = fields.Integer(string="Number of ranges to generate",
                           required=True)

    @api.multi
    def _compute_date_ranges(self):
        self.ensure_one()
        vals = rrule(freq=self.unit_of_time,
                     interval=self.duration_count,
                     dtstart=fields.Date.from_string(self.date_start),
                     count=self.count + 1)
        vals = list(vals)
        date_ranges = []
        for idx, dt_start in enumerate(vals[:-1]):
            date_start = fields.Date.to_string(dt_start.date())
            dt_end = vals[idx + 1].date() - relativedelta(days=1)
            date_end = fields.Date.to_string(dt_end)
            date_ranges.append({
                'name': '%s-%d' % (self.name_prefix, idx + 1),
                'date_start': date_start,
                'date_end': date_end,
                'type_id': self.type_id.id,
                'company_id': self.company_id.id
            })
        return date_ranges

    @api.multi
    def action_apply(self):
        date_ranges = self._compute_date_ranges()
        if date_ranges:
            for dr in date_ranges:
                self.env['date.range'].create(dr)
        return self.env['ir.actions.act_window'].for_xml_id(
            module='date_range', xml_id='date_range_action')
Example #7
0
class ImLivechatChannelRule(models.Model):
    """ Channel Rules
        Rules defining access to the channel (countries, and url matching). It also provide the 'auto pop'
        option to open automatically the conversation.
    """

    _name = 'im_livechat.channel.rule'
    _description = 'Channel Rules'
    _order = 'sequence asc'


    regex_url = fields.Char('URL Regex',
        help="Regular expression identifying the web page on which the rules will be applied.")
    action = fields.Selection([('display_button', 'Display the button'), ('auto_popup', 'Auto popup'), ('hide_button', 'Hide the button')],
        string='Action', required=True, default='display_button',
        help="* Select 'Display the button' to simply display the chat button on the pages.\n"\
             "* Select 'Auto popup' for to display the button, and automatically open the conversation window.\n"\
             "* Select 'Hide the button' to hide the chat button on the pages.")
    auto_popup_timer = fields.Integer('Auto popup timer', default=0,
        help="Delay (in seconds) to automatically open the converssation window. Note : the selected action must be 'Auto popup', otherwise this parameter will not be take into account.")
    channel_id = fields.Many2one('im_livechat.channel', 'Channel',
        help="The channel of the rule")
    country_ids = fields.Many2many('res.country', 'im_livechat_channel_country_rel', 'channel_id', 'country_id', 'Country',
        help="The actual rule will match only for this country. So if you set select 'Belgium' and 'France' and you set the action to 'Hide Buttun', this 2 country will not be see the support button for the specified URL. This feature requires GeoIP installed on your server.")
    sequence = fields.Integer('Matching order', default=10,
        help="Given the order to find a matching rule. If 2 rules are matching for the given url/country, the one with the lowest sequence will be chosen.")

    def match_rule(self, channel_id, url, country_id=False):
        """ determine if a rule of the given channel match with the given url
            :param channel_id : the identifier of the channel_id
            :param url : the url to match with a rule
            :param country_id : the identifier of the country
            :returns the rule that match the given condition. False otherwise.
            :rtype : im_livechat.channel.rule
        """
        def _match(rules):
            for rule in rules:
                if re.search(rule.regex_url, url):
                    return rule
            return False
        # first, search the country specific rules (the first match is returned)
        if country_id: # don't include the country in the research if geoIP is not installed
            domain = [('country_ids', 'in', [country_id]), ('channel_id', '=', channel_id)]
            rule = _match(self.search(domain))
            if rule:
                return rule
        # second, fallback on the rules without country
        domain = [('country_ids', '=', False), ('channel_id', '=', channel_id)]
        return _match(self.search(domain))
Example #8
0
class CrmActivity(models.Model):
    ''' CrmActivity is a model introduced in eCore v9 that models activities
    performed in CRM, like phonecalls, sending emails, making demonstrations,
    ... Users are able to configure their custom activities.

    Each activity has up to three next activities. This allows to model light
    custom workflows. This way sales manager can configure their crm workflow
    that salepersons will use in their daily job.

    CrmActivity inherits from mail.message.subtype. This allows users to follow
    some activities through subtypes. Each activity will generate messages with
    the matching subtypes, allowing reporting and statistics computation based
    on mail.message.subtype model. '''

    _name = 'crm.activity'
    _description = 'CRM Activity'
    _inherits = {'mail.message.subtype': 'subtype_id'}
    _rec_name = 'name'
    _order = "sequence"

    days = fields.Integer(
        'Number of days',
        default=0,
        help=
        'Number of days before executing the action, allowing you to plan the date of the action.'
    )
    sequence = fields.Integer('Sequence', default=0)
    team_id = fields.Many2one('crm.team', string='Sales Team')
    subtype_id = fields.Many2one('mail.message.subtype',
                                 string='Message Subtype',
                                 required=True,
                                 ondelete='cascade')
    activity_1_id = fields.Many2one('crm.activity', string="Next Activity 1")
    activity_2_id = fields.Many2one('crm.activity', string="Next Activity 2")
    activity_3_id = fields.Many2one('crm.activity', string="Next Activity 3")

    @api.model
    def create(self, values):
        ''' Override to set the res_model of inherited subtype to crm.lead.
        This cannot be achieved using a default on res_model field because
        of the inherits. Indeed a new field would be created. However the
        field on the subtype would still exist. Being void, the subtype
        will be present for every model in eCore. That's quite an issue. '''
        if not values.get(
                'res_model') and 'default_res_model' not in self._context:
            values['res_model'] = 'crm.lead'
        if 'internal' not in values and 'default_internal' not in self._context:
            values['internal'] = True
        return super(CrmActivity, self).create(values)
Example #9
0
class PriceRule(models.Model):
    _name = "delivery.price.rule"
    _description = "Delivery Price Rules"
    _order = 'sequence, list_price'

    @api.depends('variable', 'operator', 'max_value', 'list_base_price', 'list_price', 'variable_factor')
    def _get_name(self):
        for rule in self:
            name = 'if %s %s %s then' % (rule.variable, rule.operator, rule.max_value)
            if rule.list_base_price and not rule.list_price:
                name = '%s fixed price %s' % (name, rule.list_base_price)
            elif rule.list_price and not rule.list_base_price:
                name = '%s %s times %s' % (name, rule.list_price, rule.variable_factor)
            else:
                name = '%s fixed price %s and %s times %s Extra' % (name, rule.list_base_price, rule.list_price, rule.variable_factor)
            rule.name = name

    name = fields.Char(compute='_get_name')
    sequence = fields.Integer(required=True, help="Gives the sequence order when calculating delivery carrier.", default=10)
    carrier_id = fields.Many2one('delivery.carrier', 'Carrier', required=True, ondelete='cascade')
    variable = fields.Selection([('weight', 'Weight'), ('volume', 'Volume'), ('wv', 'Weight * Volume'), ('price', 'Price'), ('quantity', 'Quantity')], 'Variable', required=True, default='weight')
    operator = fields.Selection([('==', '='), ('<=', '<='), ('<', '<'), ('>=', '>='), ('>', '>')], 'Operator', required=True, default='<=')
    max_value = fields.Float('Maximum Value', required=True)
    variable_factor = fields.Selection([('weight', 'Weight'), ('volume', 'Volume'), ('wv', 'Weight * Volume'), ('price', 'Price'), ('quantity', 'Quantity')], 'Variable Factor', required=True, default='weight')
    list_base_price = fields.Float(string='Sale Base Price', digits=dp.get_precision('Product Price'), required=True, default=0.0)
    list_price = fields.Float('Sale Price', digits=dp.get_precision('Product Price'), required=True, default=0.0)
    standard_price = fields.Float('Cost Price', digits=dp.get_precision('Product Price'), required=True, default=0.0)
Example #10
0
class account_bank_statement_line(models.Model):
    _inherit = "account.bank.statement.line"

    mercury_card_number = fields.Char(
        string='Card Number',
        help='The last 4 numbers of the card used to pay')
    mercury_prefixed_card_number = fields.Char(
        string='Card Number',
        compute='_compute_prefixed_card_number',
        help='The card number used for the payment.')
    mercury_card_brand = fields.Char(
        string='Card Brand',
        help='The brand of the payment card (e.g. Visa, AMEX, ...)')
    mercury_card_owner_name = fields.Char(string='Card Owner Name',
                                          help='The name of the card owner')
    mercury_ref_no = fields.Char(
        string='Mercury reference number',
        help='Payment reference number from Mercury Pay')
    mercury_record_no = fields.Char(
        string='Mercury record number',
        help='Payment record number from Mercury Pay')
    mercury_invoice_no = fields.Integer(string='Mercury invoice number',
                                        help='Invoice number from Mercury Pay')

    @api.one
    def _compute_prefixed_card_number(self):
        if self.mercury_card_number:
            self.mercury_prefixed_card_number = "********" + self.mercury_card_number
        else:
            self.mercury_prefixed_card_number = ""
Example #11
0
class EmbeddedSlide(models.Model):
    """ Embedding in third party websites. Track view count, generate statistics. """
    _name = 'slide.embed'
    _description = 'Embedded Slides View Counter'
    _rec_name = 'slide_id'

    slide_id = fields.Many2one('slide.slide',
                               string="Presentation",
                               required=True,
                               select=1)
    url = fields.Char('Third Party Website URL', required=True)
    count_views = fields.Integer('# Views', default=1)

    def add_embed_url(self, slide_id, url):
        schema = urlparse(url)
        baseurl = schema.netloc
        embeds = self.search([('url', '=', baseurl),
                              ('slide_id', '=', int(slide_id))],
                             limit=1)
        if embeds:
            embeds.count_views += 1
        else:
            embeds = self.create({
                'slide_id': slide_id,
                'url': baseurl,
            })
        return embeds.count_views
Example #12
0
class RecruitmentStage(models.Model):
    _name = "hr.recruitment.stage"
    _description = "Stage of Recruitment"
    _order = 'sequence'

    name = fields.Char("Stage name", required=True, translate=True)
    sequence = fields.Integer(
        "Sequence",
        default=1,
        help="Gives the sequence order when displaying a list of stages.")
    job_ids = fields.Many2many(
        'hr.job',
        'job_stage_rel',
        'stage_id',
        'job_id',
        string='Job Stages',
        default=lambda self: [(4, self._context['default_job_id'])]
        if self._context.get('default_job_id') else None)
    requirements = fields.Text("Requirements")
    template_id = fields.Many2one(
        'mail.template',
        "Use template",
        help=
        "If set, a message is posted on the applicant using the template when the applicant is set to the stage."
    )
    fold = fields.Boolean(
        "Folded in Recruitment Pipe",
        help=
        "This stage is folded in the kanban view when there are no records in that stage to display."
    )
Example #13
0
class product_product(models.Model):
    _inherit = 'product.product'

    attachment_count = fields.Integer(compute='_compute_attachment_count',
                                      string="File")

    @api.multi
    def _compute_attachment_count(self):
        IrAttachment = self.env['ir.attachment']
        for product in self:
            product.attachment_count = IrAttachment.search_count([
                ('res_model', '=', product._name),
                ('res_id', 'in', product.ids)
            ])

    @api.multi
    def action_open_attachments(self):
        self.ensure_one()
        return {
            'name':
            _('Digital Attachments'),
            'domain': [('res_model', '=', self._name),
                       ('res_id', '=', self.id)],
            'res_model':
            'ir.attachment',
            'type':
            'ir.actions.act_window',
            'view_mode':
            'kanban,form',
            'view_type':
            'form',
            'context':
            "{'default_res_model': '%s','default_res_id': %d}" %
            (self._name, self.id),
        }
Example #14
0
class Tags(models.Model):
    _name = "forum.tag"
    _description = "Forum Tag"
    _inherit = ['website.seo.metadata']

    name = fields.Char('Name', required=True)
    create_uid = fields.Many2one('res.users',
                                 string='Created by',
                                 readonly=True)
    forum_id = fields.Many2one('forum.forum', string='Forum', required=True)
    post_ids = fields.Many2many('forum.post',
                                'forum_tag_rel',
                                'forum_tag_id',
                                'forum_id',
                                string='Posts')
    posts_count = fields.Integer('Number of Posts',
                                 compute='_get_posts_count',
                                 store=True)

    _sql_constraints = [
        ('name_uniq', 'unique (name, forum_id)', "Tag name already exists !"),
    ]

    @api.multi
    @api.depends("post_ids.tag_ids")
    def _get_posts_count(self):
        for tag in self:
            tag.posts_count = len(tag.post_ids)
class ImLivechatReportChannel(models.Model):
    """ Livechat Support Report on the Channels """

    _name = "im_livechat.report.channel"
    _description = "Livechat Support Report"
    _order = 'start_date, technical_name'
    _auto = False

    uuid = fields.Char('UUID', readonly=True)
    channel_id = fields.Many2one('mail.channel', 'Conversation', readonly=True)
    channel_name = fields.Char('Channel Name', readonly=True)
    technical_name = fields.Char('Code', readonly=True)
    livechat_channel_id = fields.Many2one('im_livechat.channel', 'Channel', readonly=True)
    start_date = fields.Datetime('Start Date of session', readonly=True, help="Start date of the conversation")
    start_date_hour = fields.Char('Hour of start Date of session', readonly=True)
    duration = fields.Float('Average duration', digits=(16, 2), readonly=True, group_operator="avg", help="Duration of the conversation (in seconds)")
    nbr_speaker = fields.Integer('# of speakers', readonly=True, group_operator="avg", help="Number of different speakers")
    nbr_message = fields.Integer('Average message', readonly=True, group_operator="avg", help="Number of message in the conversation")
    partner_id = fields.Many2one('res.partner', 'Opertor', readonly=True)

    def init(self, cr):
        # Note : start_date_hour must be remove when the read_group will allow grouping on the hour of a datetime. Don't forget to change the view !
        tools.drop_view_if_exists(cr, 'im_livechat_report_channel')
        cr.execute("""
            CREATE OR REPLACE VIEW im_livechat_report_channel AS (
                SELECT
                    C.id as id,
                    C.uuid as uuid,
                    C.id as channel_id,
                    C.name as channel_name,
                    CONCAT(L.name, ' / ', C.id) as technical_name,
                    C.livechat_channel_id as livechat_channel_id,
                    C.create_date as start_date,
                    to_char(date_trunc('hour', C.create_date), 'YYYY-MM-DD HH24:MI:SS') as start_date_hour,
                    EXTRACT('epoch' FROM (max((SELECT (max(M.create_date)) FROM mail_message M JOIN mail_message_mail_channel_rel R ON (R.mail_message_id = M.id) WHERE R.mail_channel_id = C.id))-C.create_date)) as duration,
                    count(distinct P.id) as nbr_speaker,
                    count(distinct M.id) as nbr_message,
                    MAX(S.partner_id) as partner_id
                FROM mail_channel C
                    JOIN mail_message_mail_channel_rel R ON (C.id = R.mail_channel_id)
                    JOIN mail_message M ON (M.id = R.mail_message_id)
                    JOIN mail_channel_partner S ON (S.channel_id = C.id)
                    JOIN im_livechat_channel L ON (L.id = C.livechat_channel_id)
                    LEFT JOIN res_partner P ON (M.author_id = P.id)
                GROUP BY C.id, C.name, C.livechat_channel_id, L.name, C.create_date, C.uuid
            )
        """)
Example #16
0
class Project(models.Model):

    _inherit = "project.project"

    @api.one
    @api.depends('percentage_satisfaction_task')
    def _compute_percentage_satisfaction_project(self):
        self.percentage_satisfaction_project = self.percentage_satisfaction_task

    @api.one
    @api.depends('tasks.rating_ids.rating')
    def _compute_percentage_satisfaction_task(self):
        activity = self.tasks.rating_get_grades()
        self.percentage_satisfaction_task = activity['great'] * 100 / sum(
            activity.values()) if sum(activity.values()) else -1

    percentage_satisfaction_task = fields.Integer(
        compute='_compute_percentage_satisfaction_task',
        string='% Happy',
        store=True,
        default=-1)
    percentage_satisfaction_project = fields.Integer(
        compute="_compute_percentage_satisfaction_project",
        string="% Happy",
        store=True,
        default=-1)
    is_visible_happy_customer = fields.Boolean(
        string="Customer Satisfaction",
        default=False,
        help=
        "Display informations about rating of the project on kanban and form view. This buttons will only be displayed if at least a rating exists."
    )

    @api.multi
    def action_view_task_rating(self):
        """ return the action to see all the rating about the tasks of the project """
        action = self.env['ir.actions.act_window'].for_xml_id(
            'rating', 'action_view_rating')
        return dict(action,
                    domain=[('rating', '!=', -1),
                            ('res_id', 'in', self.tasks.ids),
                            ('res_model', '=', 'project.task')])

    @api.multi
    def action_view_all_rating(self):
        """ return the action to see all the rating about the all sort of activity of the project (tasks, issues, ...) """
        return self.action_view_task_rating()
Example #17
0
class Invite(models.TransientModel):
    """ Wizard to invite partners (or channels) and make them followers. """
    _name = 'mail.wizard.invite'
    _description = 'Invite wizard'

    @api.model
    def default_get(self, fields):
        result = super(Invite, self).default_get(fields)
        user_name = self.env.user.name_get()[0][1]
        model = result.get('res_model')
        res_id = result.get('res_id')
        if self._context.get('mail_invite_follower_channel_only'):
            result['send_mail'] = False
        if 'message' in fields and model and res_id:
            model_name = self.env['ir.model'].search([('model', '=', self.pool[model]._name)]).name_get()[0][1]
            document_name = self.env[model].browse(res_id).name_get()[0][1]
            message = _('<div><p>Hello,</p><p>%s invited you to follow %s document: %s.</p></div>') % (user_name, model_name, document_name)
            result['message'] = message
        elif 'message' in fields:
            result['message'] = _('<div><p>Hello,</p><p>%s invited you to follow a new document.</p></div>') % user_name
        return result

    res_model = fields.Char('Related Document Model', required=True, select=1, help='Model of the followed resource')
    res_id = fields.Integer('Related Document ID', select=1, help='Id of the followed resource')
    partner_ids = fields.Many2many('res.partner', string='Recipients', help="List of partners that will be added as follower of the current document.")
    channel_ids = fields.Many2many('mail.channel', string='Channels', help='List of channels that will be added as listeners of the current document.',
                                   domain=[('channel_type', '=', 'channel')])
    message = fields.Html('Message')
    send_mail = fields.Boolean('Send Email', default=True, help="If checked, the partners will receive an email warning they have been added in the document's followers.")

    @api.multi
    def add_followers(self):
        email_from = self.env['mail.message']._get_default_from()
        for wizard in self:
            Model = self.env[wizard.res_model]
            document = Model.browse(wizard.res_id)

            # filter partner_ids to get the new followers, to avoid sending email to already following partners
            new_partners = wizard.partner_ids - document.message_partner_ids
            new_channels = wizard.channel_ids - document.message_channel_ids
            document.message_subscribe(new_partners.ids, new_channels.ids)

            model_ids = self.env['ir.model'].search([('model', '=', wizard.res_model)])
            model_name = model_ids.name_get()[0][1]
            # send an email if option checked and if a message exists (do not send void emails)
            if wizard.send_mail and wizard.message and not wizard.message == '<br>':  # when deleting the message, cleditor keeps a <br>
                message = self.env['mail.message'].create({
                    'subject': _('Invitation to follow %s: %s') % (model_name, document.name_get()[0][1]),
                    'body': wizard.message,
                    'record_name': document.name_get()[0][1],
                    'email_from': email_from,
                    'reply_to': email_from,
                    'model': wizard.res_model,
                    'res_id': wizard.res_id,
                    'no_auto_thread': True,
                })
                new_partners.with_context(auto_delete=True)._notify(message, force_send=True, user_signature=True)
                message.unlink()
        return {'type': 'ir.actions.act_window_close'}
Example #18
0
File: event.py Project: ecoreos/hz
class EventAnswer(models.Model):
    _name = 'event.answer'
    _order = 'sequence,id'

    name = fields.Char('Answer', required=True, translate=True)
    question_id = fields.Many2one('event.question',
                                  required=True,
                                  ondelete='cascade')
    sequence = fields.Integer(default=10)
Example #19
0
class AccountAccountTag(models.Model):
    _name = 'account.account.tag'
    _description = 'Account Tag'

    name = fields.Char(required=True)
    applicability = fields.Selection([('accounts', 'Accounts'),
                                      ('taxes', 'Taxes')],
                                     required=True,
                                     default='accounts')
    color = fields.Integer('Color Index')
Example #20
0
class HtmlFormField(models.Model):

    _name = "html.form.field"
    _description = "HTML Form Field"
    _order = "sequence asc"

    sequence = fields.Integer(string="Sequence")
    html_id = fields.Many2one('html.form',
                              ondelete='cascade',
                              string="HTML Form")
    model_id = fields.Many2one('ir.model', string="Model", readonly=True)
    model = fields.Char(related="model_id.model",
                        string="Model Name",
                        readonly=True)
    field_id = fields.Many2one(
        'ir.model.fields',
        domain=
        "[('name','!=','create_date'),('name','!=','create_uid'),('name','!=','id'),('name','!=','write_date'),('name','!=','write_uid')]",
        string="Form Field")
    field_type = fields.Many2one('html.form.field.type', string="Field Type")
    field_label = fields.Char(string="Field Label")
    html_name = fields.Char(string="HTML Name")
    validation_format = fields.Char(string="Validation Format")
    setting_general_required = fields.Boolean(string="Required")
    setting_binary_file_type_filter = fields.Selection(
        [('image', 'Image'), ('audio', 'Audio')], string="File Type Filter")
    character_limit = fields.Integer(string="Character Limit", default="100")

    @api.model
    def create(self, values):
        sequence = self.env['ir.sequence'].get('sequence')
        values['sequence'] = sequence
        return super(HtmlFormField, self).create(values)

    @api.onchange('field_id')
    def _onchange_field_id(self):
        """Set the default field type, html_name and field label"""
        if self.field_id:
            self.field_type = self.env['html.form.field.type'].search([
                ('data_type', '=', self.field_id.ttype), ('default', '=', True)
            ])[0].id
            self.html_name = self.field_id.name
            self.field_label = self.field_id.field_description
Example #21
0
class AccountMoveLineReconcile(models.TransientModel):
    """
    Account move line reconcile wizard, it checks for the write off the reconcile entry or directly reconcile.
    """
    _name = 'account.move.line.reconcile'
    _description = 'Account move line reconcile'

    trans_nbr = fields.Integer(string='# of Transaction', readonly=True)
    credit = fields.Float(string='Credit amount', readonly=True, digits=0)
    debit = fields.Float(string='Debit amount', readonly=True, digits=0)
    writeoff = fields.Float(string='Write-Off amount', readonly=True, digits=0)
    company_id = fields.Many2one('res.company', string='Company', required=True, default=lambda self: self.env.user.company_id)

    @api.model
    def default_get(self, fields):
        res = super(AccountMoveLineReconcile, self).default_get(fields)
        data = self.trans_rec_get()
        if 'trans_nbr' in fields:
            res.update({'trans_nbr': data['trans_nbr']})
        if 'credit' in fields:
            res.update({'credit': data['credit']})
        if 'debit' in fields:
            res.update({'debit': data['debit']})
        if 'writeoff' in fields:
            res.update({'writeoff': data['writeoff']})
        return res

    @api.multi
    def trans_rec_get(self):
        context = self._context or {}
        credit = debit = 0
        lines = self.env['account.move.line'].browse(context.get('active_ids', []))
        for line in lines:
            if not line.reconciled:
                credit += line.credit
                debit += line.debit
        precision = self.company_id.currency_id.decimal_places
        writeoff = float_round(debit - credit, precision_digits=precision)
        credit = float_round(credit, precision_digits=precision)
        debit = float_round(debit, precision_digits=precision)
        return {'trans_nbr': len(lines), 'credit': credit, 'debit': debit, 'writeoff': writeoff}

    @api.multi
    def trans_rec_addendum_writeoff(self):
        return self.env['account.move.line.reconcile.writeoff'].trans_rec_addendum()

    @api.multi
    def trans_rec_reconcile_partial_reconcile(self):
        return self.env['account.move.line.reconcile.writeoff'].trans_rec_reconcile_partial()

    @api.multi
    def trans_rec_reconcile_full(self):
        move_lines = self.env['account.move.line'].browse(self._context.get('active_ids', []))
        move_lines.reconcile()
        return {'type': 'ir.actions.act_window_close'}
Example #22
0
class MailMessageSubtype(models.Model):
    """ Class holding subtype definition for messages. Subtypes allow to tune
        the follower subscription, allowing only some subtypes to be pushed
        on the Wall. """
    _name = 'mail.message.subtype'
    _description = 'Message subtypes'
    _order = 'sequence, id'

    name = fields.Char(
        'Message Type',
        required=True,
        translate=True,
        help='Message subtype gives a more precise type on the message, '
        'especially for system notifications. For example, it can be '
        'a notification related to a new record (New), or to a stage '
        'change in a process (Stage change). Message subtypes allow to '
        'precisely tune the notifications the user want to receive on its wall.'
    )
    description = fields.Text(
        'Description',
        translate=True,
        help='Description that will be added in the message posted for this '
        'subtype. If void, the name will be added instead.')
    internal = fields.Boolean(
        'Internal Only',
        help=
        'Messages with internal subtypes will be visible only by employees, aka members of base_user group'
    )
    parent_id = fields.Many2one(
        'mail.message.subtype',
        string='Parent',
        ondelete='set null',
        help=
        'Parent subtype, used for automatic subscription. This field is not '
        'correctly named. For example on a project, the parent_id of project '
        'subtypes refers to task-related subtypes.')
    relation_field = fields.Char(
        'Relation field',
        help='Field used to link the related model to the subtype model when '
        'using automatic subscription on a related document. The field '
        'is used to compute getattr(related_document.relation_field).')
    res_model = fields.Char(
        'Model',
        help=
        "Model the subtype applies to. If False, this subtype applies to all models."
    )
    default = fields.Boolean('Default',
                             default=True,
                             help="Activated by default when subscribing.")
    sequence = fields.Integer('Sequence',
                              default=1,
                              help="Used to order subtypes.")
    hidden = fields.Boolean('Hidden',
                            help="Hide the subtype in the follower options")
Example #23
0
class HrEquipmentStage(models.Model):
    """ Model for case stages. This models the main stages of a Maintenance Request management flow. """

    _name = 'hr.equipment.stage'
    _description = 'Maintenance Stage'
    _order = 'sequence, id'

    name = fields.Char('Name', required=True, translate=True)
    sequence = fields.Integer('Sequence', default=20)
    fold = fields.Boolean('Folded in Recruitment Pipe')
    done = fields.Boolean('Request Done')
class ImLivechatReportOperator(models.Model):
    """ Livechat Support Report on the Operator """

    _name = "im_livechat.report.operator"
    _description = "Livechat Support Report"
    _order = 'livechat_channel_id, partner_id'
    _auto = False

    partner_id = fields.Many2one('res.partner', 'Operator', readonly=True)
    livechat_channel_id = fields.Many2one('im_livechat.channel',
                                          'Channel',
                                          readonly=True)
    nbr_channel = fields.Integer('# of channel',
                                 readonly=True,
                                 group_operator="sum",
                                 help="Number of conversation")
    channel_id = fields.Many2one('mail.channel', 'Conversation', readonly=True)
    start_date = fields.Datetime('Start Date of session',
                                 readonly=True,
                                 help="Start date of the conversation")
    time_to_answer = fields.Float(
        'Time to answer',
        digits=(16, 2),
        readonly=True,
        group_operator="avg",
        help="Average time to give the first answer to the visitor")
    duration = fields.Float('Average duration',
                            digits=(16, 2),
                            readonly=True,
                            group_operator="avg",
                            help="Duration of the conversation (in seconds)")

    def init(self, cr):
        # Note : start_date_hour must be remove when the read_group will allow grouping on the hour of a datetime. Don't forget to change the view !
        tools.drop_view_if_exists(cr, 'im_livechat_report_operator')
        cr.execute("""
            CREATE OR REPLACE VIEW im_livechat_report_operator AS (
                SELECT
                    row_number() OVER () AS id,
                    P.id as partner_id,
                    L.id as livechat_channel_id,
                    count(C.id) as nbr_channel,
                    C.id as channel_id,
                    C.create_date as start_date,
                    EXTRACT('epoch' FROM (max((SELECT (max(M.create_date)) FROM mail_message M JOIN mail_message_mail_channel_rel R ON (R.mail_message_id = M.id) WHERE R.mail_channel_id = C.id))-C.create_date)) as duration,
                    EXTRACT('epoch' from ((SELECT min(M.create_date) FROM mail_message M, mail_message_mail_channel_rel R WHERE M.author_id=P.id AND R.mail_channel_id = C.id AND R.mail_message_id = M.id)-(SELECT min(M.create_date) FROM mail_message M, mail_message_mail_channel_rel R WHERE M.author_id IS NULL AND R.mail_channel_id = C.id AND R.mail_message_id = M.id))) as time_to_answer
                FROM im_livechat_channel_im_user O
                    JOIN res_users U ON (O.user_id = U.id)
                    JOIN res_partner P ON (U.partner_id = P.id)
                    LEFT JOIN im_livechat_channel L ON (L.id = O.channel_id)
                    LEFT JOIN mail_channel C ON (C.livechat_channel_id = L.id)
                GROUP BY P.id, L.id, C.id, C.create_date
            )
        """)
Example #25
0
class res_partner(models.Model):
    _name = 'res.partner'
    _inherit = 'res.partner'

    @api.multi
    def _purchase_invoice_count(self):
        PurchaseOrder = self.env['purchase.order']
        Invoice = self.env['account.invoice']
        for partner in self:
            partner.purchase_order_count = PurchaseOrder.search_count([('partner_id', 'child_of', partner.id)])
            partner.supplier_invoice_count = Invoice.search_count([('partner_id', 'child_of', partner.id), ('type', '=', 'in_invoice')])

    @api.model
    def _commercial_fields(self):
        return super(res_partner, self)._commercial_fields()

    property_purchase_currency_id = fields.Many2one(
        'res.currency', string="Supplier Currency", company_dependent=True,
        help="This currency will be used, instead of the default one, for purchases from the current partner")
    purchase_order_count = fields.Integer(compute='_purchase_invoice_count', string='# of Purchase Order')
    supplier_invoice_count = fields.Integer(compute='_purchase_invoice_count', string='# Vendor Bills')
Example #26
0
class RecruitmentDegree(models.Model):
    _name = "hr.recruitment.degree"
    _description = "Degree of Recruitment"
    _sql_constraints = [
        ('name_uniq', 'unique (name)',
         'The name of the Degree of Recruitment must be unique!')
    ]

    name = fields.Char("Degree", required=True, translate=True)
    sequence = fields.Integer(
        "Sequence",
        default=1,
        help="Gives the sequence order when displaying a list of degrees.")
Example #27
0
class SaleOrder(models.Model):
    _inherit = 'sale.order'

    tasks_ids = fields.Many2many('project.task',
                                 compute='_compute_tasks_ids',
                                 string='Tasks associated to this sale')
    tasks_count = fields.Integer(string='Tasks', compute='_compute_tasks_ids')

    @api.multi
    @api.depends('order_line.product_id.project_id')
    def _compute_tasks_ids(self):
        for order in self:
            order.tasks_ids = self.env['project.task'].search([
                ('sale_line_id', 'in', order.order_line.ids)
            ])
            order.tasks_count = len(order.tasks_ids)

    @api.multi
    def action_view_task(self):
        self.ensure_one()
        imd = self.env['ir.model.data']
        action = imd.xmlid_to_object('project.action_view_task')
        list_view_id = imd.xmlid_to_res_id('project.view_task_tree2')
        form_view_id = imd.xmlid_to_res_id('project.view_task_form2')

        result = {
            'name':
            action.name,
            'help':
            action.help,
            'type':
            action.type,
            'views': [[list_view_id, 'tree'], [False, 'kanban'],
                      [form_view_id, 'form'], [False, 'graph'],
                      [False, 'calendar'], [False, 'pivot'], [False, 'graph']],
            'target':
            action.target,
            'context':
            action.context,
            'res_model':
            action.res_model,
        }
        if len(self.tasks_ids) > 1:
            result['domain'] = "[('id','in',%s)]" % self.tasks_ids.ids
        elif len(self.tasks_ids) == 1:
            result['views'] = [(form_view_id, 'form')]
            result['res_id'] = self.tasks_ids.id
        else:
            result = {'type': 'ir.actions.act_window_close'}
        return result
Example #28
0
class HrDepartment(models.Model):
    _inherit = 'hr.department'

    def _compute_expense_to_approve(self):
        expense_data = self.env['hr.expense'].read_group(
            [('department_id', 'in', self.ids),
             ('state', '=', 'submit')], ['department_id'], ['department_id'])
        result = dict((data['department_id'][0], data['department_id_count'])
                      for data in expense_data)
        for department in self:
            department.expense_to_approve_count = result.get(department.id, 0)

    expense_to_approve_count = fields.Integer(
        compute='_compute_expense_to_approve', string='Expenses to Approve')
Example #29
0
class AccountingAssertTest(models.Model):
    _name = "accounting.assert.test"
    _order = "sequence"

    name = fields.Char(string='Test Name',
                       required=True,
                       index=True,
                       translate=True)
    desc = fields.Text(string='Test Description', index=True, translate=True)
    code_exec = fields.Text(string='Python code',
                            required=True,
                            default=CODE_EXEC_DEFAULT)
    active = fields.Boolean(default=True)
    sequence = fields.Integer(default=10)
Example #30
0
class product_template(models.Model):
    _inherit = ['product.template']

    attachment_count = fields.Integer(compute='_compute_attachment_count',
                                      string="File")

    @api.multi
    def _compute_attachment_count(self):
        IrAttachment = self.env['ir.attachment']
        for ptemplate in self:
            prod_tmpl_attach_count = IrAttachment.search_count([
                ('res_model', '=', 'product.template'),
                ('res_id', 'in', ptemplate.ids)
            ])
            prod_attach_count = IrAttachment.search_count([
                ('res_model', '=', 'product.product'),
                ('res_id', 'in', ptemplate.product_variant_ids.ids)
            ])
            ptemplate.attachment_count = prod_tmpl_attach_count + prod_attach_count

    @api.model
    def _get_product_template_type(self):
        res = super(product_template, self)._get_product_template_type()
        if 'digital' not in [item[0] for item in res]:
            res.append(('digital', 'Digital Content'))
        return res

    @api.multi
    def action_open_attachments(self):
        self.ensure_one()
        return {
            'name':
            _('Digital Attachments'),
            'domain': [
                '|', '&', ('res_model', '=', 'product.product'),
                ('res_id', 'in', self.product_variant_ids.ids), '&',
                ('res_model', '=', self._name), ('res_id', '=', self.id)
            ],
            'res_model':
            'ir.attachment',
            'type':
            'ir.actions.act_window',
            'view_mode':
            'kanban,form',
            'view_type':
            'form',
            'context':
            "{'default_res_model': '%s','default_res_id': %d}" %
            (self._name, self.id),
        }