class HrEmployee(models.Model): _inherit = "hr.employee" goal_ids = fields.One2many('gamification.goal', string='Employee HR Goals', compute='_compute_employee_goals') badge_ids = fields.One2many( 'gamification.badge.user', string='Employee Badges', compute='_compute_employee_badges', help="All employee badges, linked to the employee either directly or through the user" ) has_badges = fields.Boolean(compute='_compute_employee_badges') # necessary for correct dependencies of badge_ids and has_badges direct_badge_ids = fields.One2many( 'gamification.badge.user', 'employee_id', help="Badges directly linked to the employee") @api.depends('user_id.goal_ids.challenge_id.category') def _compute_employee_goals(self): for employee in self: employee.goal_ids = self.env['gamification.goal'].search([ ('user_id', '=', employee.user_id.id), ('challenge_id.category', '=', 'hr'), ]) @api.depends('direct_badge_ids', 'user_id.badge_ids.employee_id') def _compute_employee_badges(self): for employee in self: badge_ids = self.env['gamification.badge.user'].search([ '|', ('employee_id', '=', employee.id), '&', ('employee_id', '=', False), ('user_id', '=', employee.user_id.id) ]) employee.has_badges = bool(badge_ids) employee.badge_ids = badge_ids
class ProductTemplate(models.Model): _inherit = "product.template" bom_line_ids = fields.One2many('mrp.bom.line', 'product_tmpl_id', 'BoM Components') bom_ids = fields.One2many('mrp.bom', 'product_tmpl_id', 'Bill of Materials') bom_count = fields.Integer('# Bill of Material', compute='_compute_bom_count') used_in_bom_count = fields.Integer('# of BoM Where is Used', compute='_compute_used_in_bom_count') mrp_product_qty = fields.Float('Manufactured', compute='_compute_mrp_product_qty') produce_delay = fields.Float( 'Manufacturing Lead Time', default=0.0, help= "Average lead time in days to manufacture this product. In the case of multi-level BOM, the manufacturing lead times of the components will be added." ) def _compute_bom_count(self): for product in self: product.bom_count = self.env['mrp.bom'].search_count([ ('product_tmpl_id', '=', product.id) ]) @api.multi def _compute_used_in_bom_count(self): for template in self: template.used_in_bom_count = self.env['mrp.bom'].search_count([ ('bom_line_ids.product_id', 'in', template.product_variant_ids.ids) ]) @api.multi def action_used_in_bom(self): self.ensure_one() action = self.env.ref('mrp.mrp_bom_form_action').read()[0] action['domain'] = [('bom_line_ids.product_id', 'in', self.product_variant_ids.ids)] return action @api.one def _compute_mrp_product_qty(self): self.mrp_product_qty = float_round( sum(self.mapped('product_variant_ids').mapped('mrp_product_qty')), precision_rounding=self.uom_id.rounding) @api.multi def action_view_mos(self): action = self.env.ref('mrp.mrp_production_report').read()[0] action['domain'] = [('state', '=', 'done'), ('product_tmpl_id', 'in', self.ids)] action['context'] = { 'search_default_last_year_mo_order': 1, 'search_default_status': 1, 'search_default_scheduled_month': 1, 'graph_measure': 'product_uom_qty', } return action
class MaintenanceTeam(models.Model): _name = 'maintenance.team' _description = 'Maintenance Teams' name = fields.Char(required=True, translate=True) active = fields.Boolean(default=True) company_id = fields.Many2one('res.company', string='Company', default=lambda self: self.env.user.company_id) member_ids = fields.Many2many('res.users', 'maintenance_team_users_rel', string="Team Members") color = fields.Integer("Color Index", default=0) request_ids = fields.One2many('maintenance.request', 'maintenance_team_id', copy=False) equipment_ids = fields.One2many('maintenance.equipment', 'maintenance_team_id', copy=False) # For the dashboard only todo_request_ids = fields.One2many('maintenance.request', string="Requests", copy=False, compute='_compute_todo_requests') todo_request_count = fields.Integer(string="Number of Requests", compute='_compute_todo_requests') todo_request_count_date = fields.Integer(string="Number of Requests Scheduled", compute='_compute_todo_requests') todo_request_count_high_priority = fields.Integer(string="Number of Requests in High Priority", compute='_compute_todo_requests') todo_request_count_block = fields.Integer(string="Number of Requests Blocked", compute='_compute_todo_requests') todo_request_count_unscheduled = fields.Integer(string="Number of Requests Unscheduled", compute='_compute_todo_requests') @api.one @api.depends('request_ids.stage_id.done') def _compute_todo_requests(self): self.todo_request_ids = self.request_ids.filtered(lambda e: e.stage_id.done==False) self.todo_request_count = len(self.todo_request_ids) self.todo_request_count_date = len(self.todo_request_ids.filtered(lambda e: e.schedule_date != False)) self.todo_request_count_high_priority = len(self.todo_request_ids.filtered(lambda e: e.priority == '3')) self.todo_request_count_block = len(self.todo_request_ids.filtered(lambda e: e.kanban_state == 'blocked')) self.todo_request_count_unscheduled = len(self.todo_request_ids.filtered(lambda e: not e.schedule_date)) @api.one @api.depends('equipment_ids') def _compute_equipment(self): self.equipment_count = len(self.equipment_ids)
class Event(models.Model): _inherit = 'event.event' event_ticket_ids = fields.One2many( 'event.event.ticket', 'event_id', string='Event Ticket', copy=True) @api.onchange('event_type_id') def _onchange_type(self): super(Event, self)._onchange_type() if self.event_type_id.use_ticketing: self.event_ticket_ids = [(5, 0, 0)] + [ (0, 0, { 'name': self.name and _('Registration for %s') % self.name or ticket.name, 'product_id': ticket.product_id.id, 'price': ticket.price, }) for ticket in self.event_type_id.event_ticket_ids] @api.multi def _is_event_registrable(self): self.ensure_one() if not self.event_ticket_ids: return True return bool( self.event_ticket_ids.with_context(active_test=False).filtered( lambda t: t.product_id.active and not t.is_expired and (not t.seats_max or t.seats_available) ) )
class EventType(models.Model): _inherit = 'event.type' @api.model def _get_default_event_ticket_ids(self): product = self.env.ref('event_sale.product_product_event', raise_if_not_found=False) if not product: return False return [(0, 0, { 'name': _('Registration'), 'product_id': product.id, 'price': 0, })] use_ticketing = fields.Boolean('Ticketing') event_ticket_ids = fields.One2many( 'event.event.ticket', 'event_type_id', string='Tickets', default=_get_default_event_ticket_ids) @api.onchange('name') def _onchange_name(self): if self.name: self.event_ticket_ids.filtered(lambda ticket: ticket.name == _('Registration')).update({ 'name': _('Registration for %s') % self.name })
class HrPayslipRun(models.Model): _name = 'hr.payslip.run' _description = 'Payslip Batches' name = fields.Char(required=True, readonly=True, states={'draft': [('readonly', False)]}) slip_ids = fields.One2many('hr.payslip', 'payslip_run_id', string='Payslips', readonly=True, states={'draft': [('readonly', False)]}) state = fields.Selection([ ('draft', 'Draft'), ('close', 'Close'), ], string='Status', index=True, readonly=True, copy=False, default='draft') date_start = fields.Date(string='Date From', required=True, readonly=True, states={'draft': [('readonly', False)]}, default=lambda self: fields.Date.to_string(date.today().replace(day=1))) date_end = fields.Date(string='Date To', required=True, readonly=True, states={'draft': [('readonly', False)]}, default=lambda self: fields.Date.to_string((datetime.now() + relativedelta(months=+1, day=1, days=-1)).date())) credit_note = fields.Boolean(string='Credit Note', readonly=True, states={'draft': [('readonly', False)]}, help="If its checked, indicates that all payslips generated from here are refund payslips.") @api.multi def draft_payslip_run(self): return self.write({'state': 'draft'}) @api.multi def close_payslip_run(self): return self.write({'state': 'close'}) @api.multi def unlink(self): if any(self.filtered(lambda payslip_run: payslip_run.state not in ('draft'))): raise UserError(_('You cannot delete a payslip batch which is not draft!')) if any(self.mapped('slip_ids').filtered(lambda payslip: payslip.state not in ('draft','cancel'))): raise UserError(_('You cannot delete a payslip which is not draft or cancelled!')) return super(HrPayslipRun, self).unlink()
class RestaurantFloor(models.Model): _name = 'restaurant.floor' _description = 'Restaurant Floor' name = fields.Char( 'Floor Name', required=True, help='An internal identification of the restaurant floor') pos_config_id = fields.Many2one('pos.config', string='Point of Sale') background_image = fields.Binary( 'Background Image', attachment=True, help= 'A background image used to display a floor layout in the point of sale interface' ) background_color = fields.Char( 'Background Color', help= 'The background color of the floor layout, (must be specified in a html-compatible format)', default='rgb(210, 210, 210)') table_ids = fields.One2many('restaurant.table', 'floor_id', string='Tables', help='The list of tables in this floor') sequence = fields.Integer('Sequence', help='Used to sort Floors', default=1)
class AccountBankStmtCashWizard(models.Model): """ Account Bank Statement popup that allows entering cash details. """ _name = 'account.bank.statement.cashbox' _description = 'Bank Statement Cashbox' cashbox_lines_ids = fields.One2many('account.cashbox.line', 'cashbox_id', string='Cashbox Lines') @api.multi def validate(self): bnk_stmt_id = self.env.context.get('bank_statement_id', False) or self.env.context.get( 'active_id', False) bnk_stmt = self.env['account.bank.statement'].browse(bnk_stmt_id) total = 0.0 for lines in self.cashbox_lines_ids: total += lines.subtotal if self.env.context.get('balance', False) == 'start': #starting balance bnk_stmt.write({ 'balance_start': total, 'cashbox_start_id': self.id }) else: #closing balance bnk_stmt.write({ 'balance_end_real': total, 'cashbox_end_id': self.id }) return {'type': 'ir.actions.act_window_close'}
class EventType(models.Model): _inherit = 'event.type' use_questions = fields.Boolean('Questions to Attendees') question_ids = fields.One2many( 'event.question', 'event_type_id', string='Questions', copy=True)
class EventQuestion(models.Model): _name = 'event.question' _rec_name = 'title' _order = 'sequence,id' _description = 'Event Question' title = fields.Char(required=True, translate=True) event_type_id = fields.Many2one('event.type', 'Event Type', ondelete='cascade') event_id = fields.Many2one('event.event', 'Event', ondelete='cascade') answer_ids = fields.One2many('event.answer', 'question_id', "Answers", required=True, copy=True) sequence = fields.Integer(default=10) is_individual = fields.Boolean('Ask each attendee', help="If True, this question will be asked for every attendee of a reservation. If " "not it will be asked only once and its value propagated to every attendees.") @api.constrains('event_type_id', 'event_id') def _constrains_event(self): if any(question.event_type_id and question.event_id for question in self): raise UserError(_('Question cannot belong to both the event category and itself.')) @api.model def create(self, vals): event_id = vals.get('event_id', False) if event_id: event = self.env['event.event'].browse([event_id]) if event.event_type_id.use_questions and event.event_type_id.question_ids and not vals.get('answer_ids'): vals['answer_ids'] = [(0, 0, { 'name': answer.name, 'sequence': answer.sequence, }) for answer in event.event_type_id.question_ids.filtered(lambda question: question.title == vals.get('title')).mapped('answer_ids')] return super(EventQuestion, self).create(vals)
class ThemeAttachment(models.Model): _name = 'theme.ir.attachment' _description = 'Theme Attachments' name = fields.Char(required=True) key = fields.Char(required=True) url = fields.Char() copy_ids = fields.One2many('ir.attachment', 'theme_template_id', 'Attachment using a copy of me', copy=False, readonly=True) # TODO in master: add missing field: datas_fname @api.multi def _convert_to_base_model(self, website, **kwargs): self.ensure_one() new_attach = { 'key': self.key, 'public': True, 'res_model': 'ir.ui.view', 'type': 'url', 'name': self.name, 'url': self.url, 'website_id': website.id, 'theme_template_id': self.id, } return new_attach
class ThemePage(models.Model): _name = 'theme.website.page' _description = 'Website Theme Page' url = fields.Char() view_id = fields.Many2one('theme.ir.ui.view', required=True, ondelete="cascade") website_indexed = fields.Boolean('Page Indexed', default=True) copy_ids = fields.One2many('website.page', 'theme_template_id', 'Page using a copy of me', copy=False, readonly=True) @api.multi def _convert_to_base_model(self, website, **kwargs): self.ensure_one() view_id = self.view_id.copy_ids.filtered( lambda x: x.website_id == website) if not view_id: # inherit_id not yet created, add to the queue return False new_page = { 'url': self.url, 'view_id': view_id.id, 'website_indexed': self.website_indexed, 'theme_template_id': self.id, } return new_page
class ThemeMenu(models.Model): _name = 'theme.website.menu' _description = 'Website Theme Menu' name = fields.Char(required=True, translate=True) url = fields.Char(default='') page_id = fields.Many2one('theme.website.page', ondelete='cascade') new_window = fields.Boolean('New Window') sequence = fields.Integer() parent_id = fields.Many2one('theme.website.menu', index=True, ondelete="cascade") copy_ids = fields.One2many('website.menu', 'theme_template_id', 'Menu using a copy of me', copy=False, readonly=True) @api.multi def _convert_to_base_model(self, website, **kwargs): self.ensure_one() page_id = self.page_id.copy_ids.filtered( lambda x: x.website_id == website) parent_id = self.copy_ids.filtered(lambda x: x.website_id == website) new_menu = { 'name': self.name, 'url': self.url, 'page_id': page_id and page_id.id or False, 'new_window': self.new_window, 'sequence': self.sequence, 'parent_id': parent_id and parent_id.id or False, 'theme_template_id': self.id, } return new_menu
class LeadTest(models.Model): _name = "base.automation.lead.test" _description = "Automated Rule Test" name = fields.Char(string='Subject', required=True, index=True) user_id = fields.Many2one('res.users', string='Responsible') state = fields.Selection([('draft', 'New'), ('cancel', 'Cancelled'), ('open', 'In Progress'), ('pending', 'Pending'), ('done', 'Closed')], string="Status", readonly=True, default='draft') active = fields.Boolean(default=True) partner_id = fields.Many2one('res.partner', string='Partner') date_action_last = fields.Datetime(string='Last Action', readonly=True) customer = fields.Boolean(related='partner_id.customer', readonly=True, store=True) line_ids = fields.One2many('base.automation.line.test', 'lead_id') priority = fields.Boolean() deadline = fields.Boolean(compute='_compute_deadline', store=True) is_assigned_to_admin = fields.Boolean(string='Assigned to admin user') @api.depends('priority') def _compute_deadline(self): for record in self: if not record.priority: record.deadline = False else: record.deadline = fields.Datetime.from_string(record.create_date) + relativedelta.relativedelta(days=3)
class HrSalaryRuleCategory(models.Model): _name = 'hr.salary.rule.category' _description = 'Salary Rule Category' name = fields.Char(required=True, translate=True) code = fields.Char(required=True) parent_id = fields.Many2one( 'hr.salary.rule.category', string='Parent', help= "Linking a salary category to its parent is used only for the reporting purpose." ) children_ids = fields.One2many('hr.salary.rule.category', 'parent_id', string='Children') note = fields.Text(string='Description') company_id = fields.Many2one( 'res.company', string='Company', default=lambda self: self.env['res.company']._company_default_get()) @api.constrains('parent_id') def _check_parent_id(self): if not self._check_recursion(): raise ValidationError( _('Error! You cannot create recursive hierarchy of Salary Rule Category.' ))
class ResCompany(models.Model): _inherit = 'res.company' resource_calendar_ids = fields.One2many( 'resource.calendar', 'company_id', 'Working Hours') resource_calendar_id = fields.Many2one( 'resource.calendar', 'Default Working Hours', ondelete='restrict') @api.model def _init_data_resource_calendar(self): self.search([('resource_calendar_id', '=', False)])._create_resource_calendar() def _create_resource_calendar(self): for company in self: company.resource_calendar_id = self.env['resource.calendar'].create({ 'name': _('Standard 40 hours/week'), 'company_id': company.id }).id @api.model def create(self, values): company = super(ResCompany, self).create(values) if not company.resource_calendar_id: company.sudo()._create_resource_calendar() # calendar created from form view: no company_id set because record was still not created if not company.resource_calendar_id.company_id: company.resource_calendar_id.company_id = company.id return company
class AccountAnalyticGroup(models.Model): _name = 'account.analytic.group' _description = 'Analytic Categories' _parent_store = True _rec_name = 'complete_name' name = fields.Char(required=True) description = fields.Text(string='Description') parent_id = fields.Many2one('account.analytic.group', string="Parent", ondelete='cascade') parent_path = fields.Char(index=True) children_ids = fields.One2many('account.analytic.group', 'parent_id', string="Childrens") complete_name = fields.Char('Complete Name', compute='_compute_complete_name', store=True) company_id = fields.Many2one('res.company', string='Company') @api.depends('name', 'parent_id.complete_name') def _compute_complete_name(self): for group in self: if group.parent_id: group.complete_name = '%s / %s' % ( group.parent_id.complete_name, group.name) else: group.complete_name = group.name
class MailThread(models.AbstractModel): _inherit = 'mail.thread' _mail_post_token_field = 'access_token' # token field for external posts, to be overridden website_message_ids = fields.One2many('mail.message', 'res_id', string='Website Messages', domain=lambda self: [('model', '=', self._name), '|', ('message_type', '=', 'comment'), ('message_type', '=', 'email')], auto_join=True, help="Website communication history")
class ResUsers(models.Model): _inherit = 'res.users' resource_ids = fields.One2many('resource.resource', 'user_id', 'Resources') resource_calendar_id = fields.Many2one('resource.calendar', 'Default Working Hours', related='resource_ids.calendar_id', readonly=False)
class ResCompany(models.Model): _inherit = "res.company" ldaps = fields.One2many('res.company.ldap', 'company', string='LDAP Parameters', copy=True, groups="base.group_system")
class AccountInvoice(models.Model): _inherit = "account.invoice" timesheet_ids = fields.One2many('account.analytic.line', 'timesheet_invoice_id', string='Timesheets', readonly=True, copy=False) timesheet_count = fields.Integer("Number of timesheets", compute='_compute_timesheet_count') @api.multi @api.depends('timesheet_ids') def _compute_timesheet_count(self): timesheet_data = self.env['account.analytic.line'].read_group( [('timesheet_invoice_id', 'in', self.ids)], ['timesheet_invoice_id'], ['timesheet_invoice_id']) mapped_data = dict([(t['timesheet_invoice_id'][0], t['timesheet_invoice_id_count']) for t in timesheet_data]) for invoice in self: invoice.timesheet_count = mapped_data.get(invoice.id, 0) def action_view_timesheet(self): self.ensure_one() return { 'type': 'ir.actions.act_window', 'name': _('Timesheets'), 'domain': [('project_id', '!=', False)], 'res_model': 'account.analytic.line', 'view_id': False, 'view_mode': 'tree,form', 'view_type': 'form', 'help': _(""" <p class="o_view_nocontent_smiling_face"> Record timesheets </p><p> You can register and track your workings hours by project every day. Every time spent on a project will become a cost and can be re-invoiced to customers if required. </p> """), 'limit': 80, 'context': { 'default_project_id': self.id, 'search_default_project_id': [self.id] } }
class StockTrackConfirmation(models.TransientModel): _name = 'stock.track.confirmation' _description = 'Stock Track Confirmation' tracking_line_ids = fields.One2many('stock.track.line', 'wizard_id') inventory_id = fields.Many2one('stock.inventory', 'Inventory') @api.one def action_confirm(self): return self.inventory_id._action_done()
class IrExports(models.Model): _name = "ir.exports" _description = 'Exports' _order = 'name' name = fields.Char(string='Export Name') resource = fields.Char(index=True) export_fields = fields.One2many('ir.exports.line', 'export_id', string='Export ID', copy=True)
class PosConfig(models.Model): _inherit = 'pos.config' iface_splitbill = fields.Boolean( string='Bill Splitting', help='Enables Bill Splitting in the Point of Sale.') iface_printbill = fields.Boolean( string='Bill Printing', help='Allows to print the Bill before payment.') iface_orderline_notes = fields.Boolean( string='Orderline Notes', help='Allow custom notes on Orderlines.') floor_ids = fields.One2many( 'restaurant.floor', 'pos_config_id', string='Restaurant Floors', help='The restaurant floors served by this point of sale.') printer_ids = fields.Many2many('restaurant.printer', 'pos_config_printer_rel', 'config_id', 'printer_id', string='Order Printers') is_table_management = fields.Boolean('Table Management') is_order_printer = fields.Boolean('Order Printer') module_pos_restaurant = fields.Boolean(default=True) @api.onchange('iface_tipproduct') def _onchange_tipproduct(self): if self.iface_tipproduct: self.tip_product_id = self.env.ref( 'point_of_sale.product_product_tip', False) else: self.tip_product_id = False @api.onchange('module_pos_restaurant') def _onchange_module_pos_restaurant(self): if not self.module_pos_restaurant: self.update({ 'iface_printbill': False, 'iface_splitbill': False, 'iface_tipproduct': False, 'is_order_printer': False, 'is_table_management': False, 'iface_orderline_notes': False }) @api.onchange('is_table_management') def _onchange_is_table_management(self): if not self.is_table_management: self.floor_ids = [(5, 0, 0)] @api.onchange('is_order_printer') def _onchange_is_order_printer(self): if not self.is_order_printer: self.printer_ids = [(5, 0, 0)]
class BlogTagCategory(models.Model): _name = 'blog.tag.category' _description = 'Blog Tag Category' _order = 'name' name = fields.Char('Name', required=True, translate=True) tag_ids = fields.One2many('blog.tag', 'category_id', string='Tags') _sql_constraints = [ ('name_uniq', 'unique (name)', "Tag category already exists !"), ]
class ProductTemplateAttributeValue(models.Model): """Materialized relationship between attribute values and product template generated by the product.template.attribute.line""" _name = "product.template.attribute.value" _order = 'product_attribute_value_id, id' _description = 'Product Attribute Value' name = fields.Char('Value', related="product_attribute_value_id.name") product_attribute_value_id = fields.Many2one('product.attribute.value', string='Attribute Value', required=True, ondelete='cascade', index=True) product_tmpl_id = fields.Many2one('product.template', string='Product Template', required=True, ondelete='cascade', index=True) attribute_id = fields.Many2one( 'product.attribute', string='Attribute', related="product_attribute_value_id.attribute_id") sequence = fields.Integer('Sequence', related="product_attribute_value_id.sequence") price_extra = fields.Float( string='Attribute Price Extra', default=0.0, digits=dp.get_precision('Product Price'), help="""Price Extra: Extra price for the variant with this attribute value on sale price. eg. 200 price extra, 1000 + 200 = 1200.""" ) exclude_for = fields.One2many( 'product.template.attribute.exclusion', 'product_template_attribute_value_id', string="Exclude for", relation="product_template_attribute_exclusion", help="""Make this attribute value not compatible with other values of the product or some attribute values of optional and accessory products.""" ) @api.multi def name_get(self): if not self._context.get('show_attribute', True): # TDE FIXME: not used return super(ProductTemplateAttributeValue, self).name_get() return [(value.id, "%s: %s" % (value.attribute_id.name, value.name)) for value in self] @api.multi def _without_no_variant_attributes(self): return self.filtered( lambda ptav: ptav.attribute_id.create_variant != 'no_variant')
class Product(models.Model): _inherit = 'product.product' event_ticket_ids = fields.One2many('event.event.ticket', 'product_id', string='Event Tickets') @api.onchange('event_ok') def _onchange_event_ok(self): """ Redirection, inheritance mechanism hides the method on the model """ if self.event_ok: self.type = 'service'
class PutAwayStrategy(models.Model): _name = 'product.putaway' _description = 'Put Away Strategy' name = fields.Char('Name', required=True) fixed_location_ids = fields.One2many( 'stock.fixed.putaway.strat', 'putaway_id', 'Fixed Locations Per Product Category', domain=[('category_id', '!=', False)], copy=True) product_location_ids = fields.One2many('stock.fixed.putaway.strat', 'putaway_id', 'Fixed Locations Per Product', domain=[('product_id', '!=', False) ], copy=True) def putaway_apply(self, product): put_away = self._get_putaway_rule(product) if put_away: return put_away.fixed_location_id return self.env['stock.location'] def _get_putaway_rule(self, product): if self.product_location_ids: put_away = self.product_location_ids.filtered( lambda x: x.product_id == product) if put_away: return put_away[0] if self.fixed_location_ids: categ = product.categ_id while categ: put_away = self.fixed_location_ids.filtered( lambda x: x.category_id == categ) if put_away: return put_away[0] categ = categ.parent_id return self.env['stock.location']
class ModuleCategory(models.Model): _name = "ir.module.category" _description = "Application" _order = 'name' @api.depends('module_ids') def _compute_module_nr(self): cr = self._cr cr.execute('SELECT category_id, COUNT(*) \ FROM ir_module_module \ WHERE category_id IN %(ids)s \ OR category_id IN (SELECT id \ FROM ir_module_category \ WHERE parent_id IN %(ids)s) \ GROUP BY category_id', {'ids': tuple(self.ids)} ) result = dict(cr.fetchall()) for cat in self.filtered('id'): cr.execute('SELECT id FROM ir_module_category WHERE parent_id=%s', (cat.id,)) cat.module_nr = sum([result.get(c, 0) for (c,) in cr.fetchall()], result.get(cat.id, 0)) name = fields.Char(string='Name', required=True, translate=True, index=True) parent_id = fields.Many2one('ir.module.category', string='Parent Application', index=True) child_ids = fields.One2many('ir.module.category', 'parent_id', string='Child Applications') module_nr = fields.Integer(string='Number of Apps', compute='_compute_module_nr') module_ids = fields.One2many('ir.module.module', 'category_id', string='Modules') description = fields.Text(string='Description', translate=True) sequence = fields.Integer(string='Sequence') visible = fields.Boolean(string='Visible', default=True) exclusive = fields.Boolean(string='Exclusive') xml_id = fields.Char(string='External ID', compute='_compute_xml_id') def _compute_xml_id(self): xml_ids = defaultdict(list) domain = [('model', '=', self._name), ('res_id', 'in', self.ids)] for data in self.env['ir.model.data'].sudo().search_read(domain, ['module', 'name', 'res_id']): xml_ids[data['res_id']].append("%s.%s" % (data['module'], data['name'])) for cat in self: cat.xml_id = xml_ids.get(cat.id, [''])[0]
class AccountAnalyticTag(models.Model): _name = 'account.analytic.tag' _description = 'Analytic Tags' name = fields.Char(string='Analytic Tag', index=True, required=True) color = fields.Integer('Color Index') active = fields.Boolean( default=True, help="Set active to false to hide the Analytic Tag without removing it." ) active_analytic_distribution = fields.Boolean('Analytic Distribution') analytic_distribution_ids = fields.One2many( 'account.analytic.distribution', 'tag_id', string="Analytic Accounts") company_id = fields.Many2one('res.company', string='Company')