class calendar_event_category(osv.osv): _inherit = 'calendar.event.category' is_worklog = Boolean( string='Is Worklog', help='Default Is Worklog setting for meetings with this category', default=False) is_attendance = Boolean( string='Is Attendance', help='Default Is-Attendance setting for meetings with this category', default=False)
class calendar_event(osv.osv): _inherit = 'calendar.event' # If we do not want to set a default value for category_id but still be able to install this addon in an existing # Database we could use the _auto_init or even better the init method to execute an SQL query and prepopulate the # table - see addon website_sale_categories for an example # https://www.odoo.com/es_ES/forum/help-1/question/is-there-a-way-to-set-a-value-for-a-field-for-all-existing-records-in-the-database-at-addon-installation-only-89400 # https://gist.github.com/lepistone/3ca65107fc7344440777 @api.model def _get_category(self): category = self.env.ref("calendar_category.category_generalactivity", raise_if_not_found=False) if not category: category = self.env['calendar.event.category'].search([], limit=1, order='id') return category no_invitations = Boolean(string='No invitation e-mails!', help='Do not send invitation e-mails!', default=True) odometer_start = Integer(string='Odometer at start') odometer_finish = Integer(string='Odometer at finish') category_id = Many2one('calendar.event.category', string='Category', required=True, default=lambda self: self._get_category()) meeting_minutes = Text('Internal Meeting Minutes') mainpartner_id = Many2one('res.partner', string='Main Partner') @api.onchange('mainpartner_id') def _add_attendee(self): if self.mainpartner_id: # http://odoo-new-api-guide-line.readthedocs.org/en/latest/environment.html#the-ids-attribute # http://www.mindissoftware.com/2014/11/07/Understand-Odoo-Model-Part1 # https://github.com/odoo/odoo/issues/2693 # https://www.odoo.com/fr_FR/forum/help-1/question/how-to-add-records-in-many2many-field-82878 # https://www.odoo.com/fr_FR/forum/help-1/question/how-to-insert-value-to-a-one2many-field-in-table-with-create-method-28714 # https://www.odoo.com/fr_FR/forum/help-1/question/insert-new-record-into-one2many-field-20931 self.partner_ids = [(4, self.mainpartner_id.id)]
class ResPartner(Model): _inherit = 'res.partner' @api.multi def get_object_activity(self, object_name, partner_field_name, nb_month=24): """ Returns a dictionary containing the active status of the partner concerning the object :param nb_month: number of month the partner activity must be checked :returns: a dictionary containing the active status of the partner concerning the object """ res = {} obj = self.env[object_name] start_date = datetime.now() - timedelta(nb_month * 365 / 12) for partner in self: res.update({partner.id: False}) lead_recs = obj.search([(partner_field_name, '=', partner.id), ('create_date', '>=', datetime.strftime(start_date, "%Y-%m-%d 00:00:00"))]) ## If a child is active than the parent partner must be active too active_child = False child_recs = self.search([('parent_id', '=', partner.id)]) res_children = child_recs.get_object_activity( object_name, partner_field_name) for res_child in res_children: if res_children.get(res_child, False): active_child = True if len(lead_recs) or active_child: res.update({partner.id: True}) return res @api.multi @api.depends('opportunity_count') def _get_activity_status(self): """ Returns a dictionary containing the active status in last 24 month """ lead_res = self.get_object_activity('crm.lead', 'partner_id', 24) for partner in self: if lead_res.get(partner.id): partner.is_active = True else: partner.is_active = False is_active = Boolean('Active during last 2 years', compute=_get_activity_status)
class IrActionsReportXML(Model): _inherit = "ir.actions.report.xml" add_terms_conditions = Boolean(string='add Terms and Conditions', default=False) terms_conditions_language_field = Char('Language field')
class calendar_event(osv.osv): _inherit = 'calendar.event' is_worklog = Boolean(string='Is Worklog', help='Create a Work-Log Entry', default=False) project_id = Many2one('project.project', string='Project') task_id = Many2one('project.task', string='Task') worklog_text = Char('Work-Log', size=128) task_work_id = Many2one('project.task.work', string='Task Worklog ID') analytic_time_id = Many2one('hr.analytic.timesheet', string='HR Analytic Timesheet ID') # DISABLED FOR NOW Update the field event_category_id at installation or update # def init(self, cr, context=None): # print "INIT OF calendar_log_project" # events = self.browse(cr, SUPERUSER_ID, self.search(cr, SUPERUSER_ID, [])) # for event in events: # # We trigger the write method at install or update time for all events to update the event_category_id # event.write({"name": event.name or None}) @api.onchange('category_id') def _set_worklog(self): if self.category_id: self.is_worklog = self.category_id.is_worklog @api.onchange('task_id') def _set_project(self): if self.task_id: # Set the Project to the project_id of the Task if self.project_id != self.task_id.project_id: self.project_id = self.task_id.project_id # Set the Main Partner to the task or project partner if not self.mainpartner_id: if self.task_id.partner_id: self.mainpartner_id = self.task_id.partner_id elif self.project_id.partner_id: self.mainpartner_id = self.project_id.partner_id @api.onchange('project_id') def _set_task(self): # https://github.com/odoo/odoo/issues/4574 if self.project_id: # Clear the Task if it has a different project_id if self.task_id: if self.task_id.project_id != self.project_id: self.task_id = False # Try to set the Main Partner if not self.mainpartner_id: if self.task_id and self.task_id.partner_id: self.mainpartner_id = self.task_id.partner_id elif self.project_id.partner_id: self.mainpartner_id = self.project_id.partner_id # Set a domain for the task list to only show tasks that belong to this project return {'domain': {'task_id': [('project_id', '=', self.project_id.id)]}} else: # Clear the Domain for Tasks if no Project is selected return {'domain': {'task_id': []}} @api.multi def write(self, values): # Unlink any existing task_work_id if task has changed # So we force a task_work_id create which will create a new task_work_id.hr_analytic_timesheet_id! if 'task_id' in values and self.task_work_id and self.ensure_one(): self.task_work_id.hr_analytic_timesheet_id.unlink() self.task_work_id.unlink() res = super(calendar_event, self).write(values) if res and self.ensure_one(): # Create or Update related hr.analytic.timesheet entries if self.is_worklog and (self.task_id or self.project_id): if self.task_id: # Create or update Task Work Log values_worklog = { 'name': self.worklog_text or self.name, 'user_id': self.user_id.id, 'date': self.start_datetime, 'hours': self.duration, 'task_id': self.task_id.id, } # UNLINK hr.analytic.timesheet if self.analytic_time_id: self.analytic_time_id.unlink() # CREATE (No Worklog exists) if not self.task_work_id: self.task_work_id = self.task_id.work_ids.create(values_worklog) # UPDATE (Worklog exists - relinks to new task if changed) else: self.task_work_id.write(values_worklog) # Update the related hr.analytic.timesheet of the task_work_id with event_category_id self.task_work_id.hr_analytic_timesheet_id.write({'event_category_id': self.category_id.id, }) elif self.project_id: # Get the Values for hr.analytic.timesheet time_obj = self.env['hr.analytic.timesheet'] values_hr_line = { 'name': self.worklog_text or self.name, 'user_id': self.user_id.id, 'date': self.start_datetime, 'unit_amount': self.duration, 'account_id': self.project_id.analytic_account_id.id, 'journal_id': time_obj._getAnalyticJournal(context={'user_id': self.user_id.id}), 'product_id': time_obj._getEmployeeProduct(context={'user_id': self.user_id.id}), 'product_uom_id': time_obj._getEmployeeUnit(context={'user_id': self.user_id.id}), 'general_account_id': time_obj._getGeneralAccount(context={'user_id': self.user_id.id}), 'event_category_id': self.category_id.id, } # Recheck the UOM and recalculate if needed default_uom = self.env['res.users'].browse(self.user_id.id).company_id.project_time_mode_id.id if values_hr_line['product_uom_id'] != default_uom: values_hr_line['unit_amount'] = self.pool['product.uom']._compute_qty(default_uom, values_hr_line['unit_amount'], values_hr_line['product_uom_id']) if self.task_work_id: # Unlink task worklog self.task_work_id.unlink() if not self.analytic_time_id: # Create analytic timeline entry self.analytic_time_id = self.analytic_time_id.create(values_hr_line) else: # Update analytic timeline entry self.analytic_time_id.write(values_hr_line) else: # UNLINK Work Logs if self.task_work_id: self.task_work_id.unlink() if self.analytic_time_id: self.analytic_time_id.unlink() return res @api.multi def unlink(self): for event in self: if event.task_work_id: event.task_work_id.unlink() if event.analytic_time_id: event.analytic_time_id.unlink() return super(calendar_event, self).unlink()
class CrmLead(Model): _inherit = 'crm.lead' def compute_lost_visible(self): for rec in self: if rec.stage_id.name == 'Lost': rec.lost_visible = True @api.multi def action_set_lost(self): """ Lost semantic: probability = 0, active = False """ lost_stage = self.env['crm.stage'].search([('name','=','Lost')])[0] return self.write({'probability': 0,'stage_id':lost_stage.id}) @api.multi def open_form_view(self): if self[0].type == 'lead': name = _('Leads') res = self.env.ref('crm.crm_case_form_view_leads') else: name = _('Opportunities') res = self.env.ref('crm.crm_case_form_view_oppor') return { 'name': name or '', 'view_type': 'form', 'view_mode': 'form', 'view_id': [res.id], 'res_model': 'crm.lead', 'context': "{}", 'type': 'ir.actions.act_window', 'nodestroy': True, 'res_id': self[0].id or False } @api.onchange('partner_id') def on_change_partner_id(self): result = super(CrmLead, self)._onchange_partner_id_values(self.partner_id.id if self.partner_id else False) if not self.partner_id: return result partner = self.env['res.partner'].browse(self.partner_id.id) result.update({'website': partner.website}) return result @api.model def _lead_create_contact(self, name, is_company, parent_id=False): partner_id = super(CrmLead, self)._lead_create_contact(name, is_company, parent_id) self.env['res.partner'].browse(partner_id.id).write({'website': self.website}) return partner_id @api.model def create(self, values): if values.get('stage_id'): crm_stage_rec = self.env['crm.case.stage'].browse(values.get('stage_id')) values.update({'probability': crm_stage_rec.probability}) return super(CrmLead, self).create(values) website = Char('Website', size=64, help="Website of Partner or Company") lost_visible = Boolean(default=False ,compute='compute_lost_visible',store=False)
class calendar_event(osv.osv): _inherit = 'calendar.event' is_worklog = Boolean(string='Is Worklog', help='Create a Work-Log Entry', default=False) project_id = Many2one('project.project', string='Project') task_id = Many2one('project.task', string='Task') worklog_text = Char('Work-Log', size=128) task_work_id = Many2one('project.task.work', string='Task Worklog ID') analytic_time_id = Many2one('hr.analytic.timesheet', string='HR Analytic Timesheet ID') @api.onchange('task_id') def _set_project(self): if self.task_id: # Set the Project to the project_id of the Task if self.project_id != self.task_id.project_id: self.project_id = self.task_id.project_id # Set the Main Partner to the task or project partner if not self.mainpartner_id: if self.task_id.partner_id: self.mainpartner_id = self.task_id.partner_id elif self.project_id.partner_id: self.mainpartner_id = self.project_id.partner_id @api.onchange('project_id') def _set_task(self): # https://github.com/odoo/odoo/issues/4574 if self.project_id: # Clear the Task if it has a different project_id if self.task_id: if self.task_id.project_id != self.project_id: self.task_id = False # Try to set the Main Partner if not self.mainpartner_id: if self.task_id and self.task_id.partner_id: self.mainpartner_id = self.task_id.partner_id elif self.project_id.partner_id: self.mainpartner_id = self.project_id.partner_id # Set a domain for the task list to only show tasks that belong to this project return { 'domain': { 'task_id': [('project_id', '=', self.project_id.id)] } } else: # Clear the Domain for Tasks if no Project is selected return {'domain': {'task_id': []}} @api.multi def write(self, values): print 'Test' res = super(calendar_event, self).write(values) if res and self.ensure_one(): # Create or Update related hr.analytic.timesheet entries if self.is_worklog and (self.task_id or self.project_id): if self.task_id: # Create or update Task Work Log values_worklog = { 'name': self.worklog_text or self.name, 'user_id': self.user_id.id, 'date': self.start_datetime, 'hours': self.duration, 'task_id': self.task_id.id, } # UNLINK hr.analytic.timesheet if self.analytic_time_id: self.analytic_time_id.unlink() # CREATE (No Worklog exists) if not self.task_work_id: self.task_work_id = self.task_id.work_ids.create( values_worklog) # UPDATE (Worklog exists - relinks to new task if changed) else: self.task_work_id.write(values_worklog) elif self.project_id: # Get the Values for hr.analytic.timesheet time_obj = self.env['hr.analytic.timesheet'] values_hr_line = { 'name': self.worklog_text or self.name, 'user_id': self.user_id.id, 'date': self.start_datetime, 'unit_amount': self.duration, 'account_id': self.project_id.analytic_account_id.id, 'journal_id': time_obj._getAnalyticJournal( context={'user_id': self.user_id.id}), 'product_id': time_obj._getEmployeeProduct( context={'user_id': self.user_id.id}), 'product_uom_id': time_obj._getEmployeeUnit( context={'user_id': self.user_id.id}), 'general_account_id': time_obj._getGeneralAccount( context={'user_id': self.user_id.id}), } # Recheck the UOM and recalculate if needed default_uom = self.env['res.users'].browse( self.user_id.id).company_id.project_time_mode_id.id if values_hr_line['product_uom_id'] != default_uom: values_hr_line['unit_amount'] = self.pool[ 'product.uom']._compute_qty( default_uom, values_hr_line['unit_amount'], values_hr_line['product_uom_id']) if self.task_work_id: # Unlink task worklog self.task_work_id.unlink() if not self.analytic_time_id: # Create analytic timeline entry self.analytic_time_id = self.analytic_time_id.create( values_hr_line) else: # Update analytic timeline entry self.analytic_time_id.write(values_hr_line) else: # UNLINK Work Logs if self.task_work_id: self.task_work_id.unlink() if self.analytic_time_id: self.analytic_time_id.unlink() return res
class calendar_event(osv.osv): _inherit = 'calendar.event' is_worklog = Boolean(string='Is Worklog', help='Create a Work-Log Entry', default=False) is_attendance = Boolean(string='Is Attendance', help='Create Attendance Entry (Sing In/Out)', default=False) project_id = Many2one('project.project', string='Project') task_id = Many2one('project.task', string='Task') worklog_text = Char('Work-Log', size=128) task_work_id = Many2one('project.task.work', string='Task Worklog ID') # These are the worklog lines NOT the timesheet itself analytic_time_id = Many2one('hr.analytic.timesheet', string='HR Analytic Timesheet ID') sign_in_id = Many2one('hr.attendance', string='Sign In') sign_out_id = Many2one('hr.attendance', string='Sign Out') to_invoice = Many2one( 'hr_timesheet_invoice.factor', 'Invoiceable', help="It allows to set the discount while making invoice, " "keep empty if the activities should not be invoiced.") # DISABLED FOR NOW Update the field event_category_id at installation or update # def init(self, cr, context=None): # print "INIT OF calendar_log_project" # events = self.browse(cr, SUPERUSER_ID, self.search(cr, SUPERUSER_ID, [])) # for event in events: # # We trigger the write method at install or update time for all events to update the event_category_id # event.write({"name": event.name or None}) @api.constrains('is_worklog', 'is_attendance') def _constraint_user_partner_id_in_event_partner_ids(self): for r in self: if (r.is_worklog or r.is_attendance) and r.user_id.partner_id: assert r.user_id.partner_id in r.partner_ids, _( "You must be a participant if is_worklog or is_attendance is set!" ) @api.onchange('category_id') def _oc_category_id(self): # Only update if a category was set if self.category_id: # Set boolean field is_worklog to category setting self.is_worklog = self.category_id.is_worklog # Set boolean field is attendance to category setting self.is_attendance = self.category_id.is_attendance @api.onchange('task_id') def _set_project(self): if self.task_id: # Set the Project to the project_id of the Task if self.project_id != self.task_id.project_id: self.project_id = self.task_id.project_id # Set the Main Partner to the task or project partner if not self.mainpartner_id: if self.task_id.partner_id: self.mainpartner_id = self.task_id.partner_id elif self.project_id.partner_id: self.mainpartner_id = self.project_id.partner_id @api.onchange('project_id') def _set_task(self): # https://github.com/odoo/odoo/issues/4574 if self.project_id: # Clear the Task if it has a different project_id if self.task_id: if self.task_id.project_id != self.project_id: self.task_id = False # Try to set the Main Partner if not self.mainpartner_id: if self.task_id and self.task_id.partner_id: self.mainpartner_id = self.task_id.partner_id elif self.project_id.partner_id: self.mainpartner_id = self.project_id.partner_id # Make sure we are still a participant if self.is_worklog or self.is_attendance: if self.user_id and self.user_id.partner_id not in self.partner_ids: self.partner_ids = [(4, self.user_id.partner_id.id, '')] # Set a domain for the task list to only show tasks that belong to this project return { 'domain': { 'task_id': [('project_id', '=', self.project_id.id)] } } else: # Clear the Domain for Tasks if no Project is selected return {'domain': {'task_id': []}} @api.onchange('is_worklog', 'is_attendance') def _onchange_set_user_id_partner_id_as_participant(self): if self.is_worklog or self.is_attendance: if self.user_id and self.user_id.partner_id not in self.partner_ids: self.partner_ids = [(4, self.user_id.partner_id.id, '')] # Clear to_invoice of not worklog if self.to_invoice and not self.is_worklog: self.to_invoice = False # @api.multi # def create(self, values, context=None): # return super(calendar_event, self).create(values, context=context) @api.multi def write(self, values): # WARNING: Check that NO defaults are set for is_worklog and is_attendance fields cause this will make it # impossible for other code to create events. MUST BE FALSE BY DEFAULT! assert not self.env['ir.values'].sudo().search([ '&', ('name', '=', 'is_worklog'), ('model', '=', 'calendar.event') ]), _( 'Remove any Default for calendar.event.is_worklog field! Settings > Technical > Actions > User Defaults' ) assert not self.env['ir.values'].sudo().search([ '&', ('name', '=', 'is_attendance'), ('model', '=', 'calendar.event') ]), _( 'Remove any Default for calendar.event.is_attendance field! Settings > Technical > Actions > User Defaults' ) # Create or update hr.timesheet worklog and attendance records # ------------------------------------------------------------ if values.get( 'active', '' ) is not False and 'skipp_calendar_log_project' not in values: # Loop through the records for r in self: rec_values = dict() # HINT: A event creation will also call the write method because of the "message_last_post" field # Therefore we do not have to extend the create method also. # WARNING: Do nothing if record gets unlinked (there is {'active': False} included in vals on unlink) # Prepare variables # HINT: r.task_id.id will return FALSE if r.task_id is empty (no assertion will be thrown!) name = values.get('name') if 'name' in values else r.name start = values.get('start') if 'start' in values else \ values.get('start_datetime') if 'start_datetime' in values \ else r.start stop = values.get('stop') if 'stop' in values else \ values.get('stop_datetime') if 'stop_datetime' in values \ else r.stop duration = values.get( 'duration') if 'duration' in values else r.duration is_worklog = values.get( 'is_worklog') if 'is_worklog' in values else r.is_worklog worklog_text = values.get( 'worklog_text' ) if 'worklog_text' in values else r.worklog_text is_attendance = values.get( 'is_attendance' ) if 'is_attendance' in values else r.is_attendance user_id = values.get( 'user_id') if 'user_id' in values else r.user_id.id category_id = values.get( 'category_id' ) if 'category_id' in values else r.category_id.id project_id = values.get( 'project_id' ) if 'project_id' in values else r.project_id.id task_id = values.get( 'task_id') if 'task_id' in values else r.task_id.id to_invoice = values.get( 'to_invoice', r.to_invoice.id if r.to_invoice else False) _logger.info( "Create or update worklog and attendance records for calendar.event %s with user %s" % (r.id, user_id)) # ======= # WORKLOG # ======= # Unlink task worklog if task_id != r.task_id.id or not is_worklog: # Unlink task worklog and related analytic timesheet worklog if r.task_work_id: if r.task_work_id.hr_analytic_timesheet_id: r.task_work_id.hr_analytic_timesheet_id.unlink() r.task_work_id.unlink() # Unlink project worklog # ATTENTION: Unlink any existing project worklog also if a task is available if project_id != r.project_id.id or task_id or not is_worklog: if r.analytic_time_id: r.analytic_time_id.unlink() # Create or update worklog if is_worklog: assert project_id, _( 'You have to choose a project if Is Worklog is checked!' ) # TASK WORKLOG # ------------ # HINT: You can add bool in but it's not necessary, because bool is a subclass of int. if task_id: task_worklog_values = { 'name': worklog_text or name, 'user_id': user_id, 'date': start, 'hours': duration, 'task_id': task_id, } # Update an existing task worklog # HINT: If the task changed the task worklog would already be deleted before we reach this point. if r.task_work_id: r.task_work_id.write(task_worklog_values) # Create a new task worklog # HINT: We did not write the event so need to create the worklog without r.task_work_id else: task_obj = r.env['project.task'] task = task_obj.browse([task_id]) task_work_id = task.work_ids.create( task_worklog_values) # HINT: task.work_ids will create a related hr_analytic_timesheet entry on creation task_work_id.hr_analytic_timesheet_id.event_category_id = category_id rec_values['task_work_id'] = task_work_id.id # PROJECT WORKLOG # --------------- else: # Prepare values ts_obj = r.env['hr.analytic.timesheet'] prj_obj = r.env['project.project'] project = prj_obj.browse([project_id]) account_id = project.analytic_account_id.id unit_amount = duration company_time_unit_id = r.env['res.users'].browse( [user_id]).company_id.project_time_mode_id.id employee_time_unit_id = ts_obj._getEmployeeUnit( context={'user_id': user_id}) # If the company has a different time unit than the employee we need to recalculate unit_amount if company_time_unit_id != employee_time_unit_id: unit_amount = r.env['product.uom']._compute_qty( company_time_unit_id, unit_amount, employee_time_unit_id) ts_values = { 'name': worklog_text or name, 'user_id': user_id, 'date': start, 'unit_amount': unit_amount, 'account_id': account_id, 'journal_id': ts_obj._getAnalyticJournal( context={'user_id': user_id}), 'product_id': ts_obj._getEmployeeProduct( context={'user_id': user_id}), 'product_uom_id': employee_time_unit_id, 'general_account_id': ts_obj._getGeneralAccount( context={'user_id': user_id}), 'event_category_id': category_id, 'to_invoice': to_invoice, } # Update an existing project worklog # HINT: If the project changed the project worklog would already be deleted # So an update id only possible if the project exists and stayed the same. if r.analytic_time_id: r.analytic_time_id.write(ts_values) # Create a project worklog # HINT: We did not write the event so need to create the worklog without r.analytic_time_id else: project_worklog = ts_obj.create(ts_values) rec_values['analytic_time_id'] = project_worklog.id # ========== # ATTENDANCE # ========== # Unlink attendance if not is_attendance: if r.sign_in_id: r.sign_in_id.unlink() if r.sign_out_id: r.sign_out_id.unlink() # Create or Update Attendance if is_attendance: attendance_obj = r.env['hr.attendance'] # Get the employee id employee_obj = r.env['hr.employee'] employee_id = employee_obj.search( [('user_id', '=', r.user_id.id)], limit=1).id assert employee_id, _( 'No employee found for current user!') # SIGN_IN attendance sign_in_values = { 'employee_id': employee_id, 'name': start, 'action': 'sign_in', } # Update existing sign-in attendance if r.sign_in_id: r.sign_in_id.write(sign_in_values) # Create new sign-in attendance else: sign_in = attendance_obj.create(sign_in_values) rec_values['sign_in_id'] = sign_in.id # SIGN_OUT attendance sign_out_values = { 'employee_id': employee_id, 'name': stop, 'action': 'sign_out', } # Update existing sign-out attendance if r.sign_out_id: r.sign_out_id.write(sign_out_values) # Create new sign-out attendance else: sign_out = attendance_obj.create(sign_out_values) rec_values['sign_out_id'] = sign_out.id # UPDATE RECORD VALUES if rec_values: # Make sure "Create or update hr.timesheet worklog and attendance records" is only run once! rec_values['skipp_calendar_log_project'] = True # Call write again with updated values and 'skipp_calendar_log_project' only for this single record r.write(rec_values) # END Create or update hr.timesheet worklog and attendance records # ---------------------------------------------------------------- # Remove 'skipp_calendar_log_project' for the rec_values write if 'skipp_calendar_log_project' in values: values.pop('skipp_calendar_log_project') return super(calendar_event, self).write(values) @api.multi def unlink(self): for event in self: if event.task_work_id: event.task_work_id.unlink() if event.analytic_time_id: event.analytic_time_id.unlink() if event.sign_in_id: event.sign_in_id.unlink() if event.sign_out_id: event.sign_out_id.unlink() return super(calendar_event, self).unlink()