def unlink(self): projects = self.env['project.project'].search([('analytic_account_id', 'in', self.ids)]) has_tasks = self.env['project.task'].search_count([('project_id', 'in', projects.ids)]) if has_tasks: raise UserError( _('Please remove existing tasks in the project linked to the accounts you want to delete.' )) return super(AccountAnalyticAccount, self).unlink()
def _check_dates(self): ''' Check interleaving between fiscal years. There are 3 cases to consider: s1 s2 e1 e2 ( [----)----] s2 s1 e2 e1 [----(----] ) s1 s2 e2 e1 ( [----] ) ''' for fy in self: # Starting date must be prior to the ending date date_from = fy.date_from date_to = fy.date_to if date_to < date_from: raise ValidationError( _('The ending date must not be prior to the starting date.' )) domain = [ ('id', '!=', fy.id), ('company_id', '=', fy.company_id.id), '|', '|', '&', ('date_from', '<=', fy.date_from), ('date_to', '>=', fy.date_from), '&', ('date_from', '<=', fy.date_to), ('date_to', '>=', fy.date_to), '&', ('date_from', '<=', fy.date_from), ('date_to', '>=', fy.date_to), ] if self.search_count(domain) > 0: raise ValidationError( _('You can not have an overlap between two fiscal years, please correct the start and/or end dates of your fiscal years.' ))
def assign_responsible(self): self.ensure_one() pickings = self.env['stock.picking'].browse( self.env.context.get('active_ids')) restricted_companies = pickings.company_id - self.user_id.company_ids if restricted_companies: raise UserError( _('%s has a restricted access to %s') % (self.user_id.name, restricted_companies.mapped('name'))) pickings.write({'user_id': self.user_id.id})
def _check_main_currency_rounding(self): if any(precision.name == 'Account' and tools.float_compare(self.env.company.currency_id.rounding, 10**-precision.digits, precision_digits=6) == -1 for precision in self): raise ValidationError( _("You cannot define the decimal precision of 'Account' as greater than the rounding factor of the company's main currency" )) return True
def blacklist_remove(self, mailing_id, res_id, email, token): if not self._valid_unsubscribe_token(mailing_id, res_id, email, token): return 'unauthorized' if email: blacklist_rec = request.env['mail.blacklist'].sudo()._remove(email) self._log_blacklist_action( blacklist_rec, mailing_id, _("""Requested de-blacklisting via unsubscription page.""")) return True return 'error'
def _check_attendance_ids(self): for resource in self: if (resource.two_weeks_calendar and resource.attendance_ids.filtered( lambda a: a.display_type == 'line_section') and not resource.attendance_ids.sorted( 'sequence')[0].display_type): raise ValidationError( _("In a calendar with 2 weeks mode, all periods need to be in the sections." ))
def check_quantity(self): for quant in self: if float_compare( quant.quantity, 1, precision_rounding=quant.product_uom_id.rounding ) > 0 and quant.lot_id and quant.product_id.tracking == 'serial': raise ValidationError( _('A serial number should only be linked to a single product.' ))
def _check_product_id(self): """ As no quants are created for consumable products, it should not be possible do adjust their quantity. """ for line in self: if line.product_id.type != 'product': raise ValidationError( _("You can only adjust storable products.") + '\n\n%s -> %s' % (line.product_id.display_name, line.product_id.type))
def action_validate(self): if not self.exists(): return self.ensure_one() if not self.user_has_groups('stock.group_stock_manager'): raise UserError( _("Only a stock manager can validate an inventory adjustment.") ) if self.state != 'confirm': raise UserError( _("You can't validate the inventory '%s', maybe this inventory " + "has been already validated or isn't ready.") % (self.name)) inventory_lines = self.line_ids.filtered( lambda l: l.product_id.tracking in ['lot', 'serial'] and not l. prod_lot_id and l.theoretical_qty != l.product_qty) lines = self.line_ids.filtered(lambda l: float_compare( l.product_qty, 1, precision_rounding=l.product_uom_id.rounding ) > 0 and l.product_id.tracking == 'serial' and l.prod_lot_id) if inventory_lines and not lines: wiz_lines = [(0, 0, { 'product_id': product.id, 'tracking': product.tracking }) for product in inventory_lines.mapped('product_id')] wiz = self.env['stock.track.confirmation'].create({ 'inventory_id': self.id, 'tracking_line_ids': wiz_lines }) return { 'name': _('Tracked Products in Inventory Adjustment'), 'type': 'ir.actions.act_window', 'view_mode': 'form', 'views': [(False, 'form')], 'res_model': 'stock.track.confirmation', 'target': 'new', 'res_id': wiz.id, } self._action_done() self.line_ids._check_company() self._check_company() return True
def poll(self, channels, last, options=None): if options is None: options = {} if not dispatch: raise Exception("bus.Bus unavailable") if [c for c in channels if not isinstance(c, str)]: raise Exception("bus.Bus only string channels are allowed.") if request.registry.in_test_mode(): raise exceptions.UserError(_("bus.Bus not available in test mode")) return self._poll(request.db, channels, last, options)
def _purchase_service_create(self, quantity=False): """ On Sales Order confirmation, some lines (services ones) can create a purchase order line and maybe a purchase order. If a line should create a RFQ, it will check for existing PO. If no one is find, the SO line will create one, then adds a new PO line. The created purchase order line will be linked to the SO line. :param quantity: the quantity to force on the PO line, expressed in SO line UoM """ PurchaseOrder = self.env['purchase.order'] supplier_po_map = {} sale_line_purchase_map = {} for line in self: line = line.with_context(force_company=line.company_id.id) # determine vendor of the order (take the first matching company and product) suppliers = line.product_id.with_context( force_company=line.company_id.id)._select_seller( quantity=line.product_uom_qty, uom_id=line.product_uom) if not suppliers: raise UserError( _("There is no vendor associated to the product %s. Please define a vendor for this product." ) % (line.product_id.display_name, )) supplierinfo = suppliers[0] partner_supplier = supplierinfo.name # yes, this field is not explicit .... it is a res.partner ! # determine (or create) PO purchase_order = supplier_po_map.get(partner_supplier.id) if not purchase_order: purchase_order = PurchaseOrder.search([ ('partner_id', '=', partner_supplier.id), ('state', '=', 'draft'), ('company_id', '=', line.company_id.id), ], limit=1) if not purchase_order: values = line._purchase_service_prepare_order_values( supplierinfo) purchase_order = PurchaseOrder.create(values) else: # update origin of existing PO so_name = line.order_id.name origins = [] if purchase_order.origin: origins = purchase_order.origin.split(', ') + origins if so_name not in origins: origins += [so_name] purchase_order.write({'origin': ', '.join(origins)}) supplier_po_map[partner_supplier.id] = purchase_order # add a PO line to the PO values = line._purchase_service_prepare_line_values( purchase_order, quantity=quantity) purchase_line = line.env['purchase.order.line'].create(values) # link the generated purchase to the SO line sale_line_purchase_map.setdefault(line, line.env['purchase.order.line']) sale_line_purchase_map[line] |= purchase_line return sale_line_purchase_map
def _create_or_update_picking(self): for line in self: if line.product_id and line.product_id.type in ('product', 'consu'): # Prevent decreasing below received quantity if float_compare(line.product_qty, line.qty_received, line.product_uom.rounding) < 0: raise UserError( _('You cannot decrease the ordered quantity below the received quantity.\n' 'Create a return first.')) if float_compare(line.product_qty, line.qty_invoiced, line.product_uom.rounding) == -1: # If the quantity is now below the invoiced quantity, create an activity on the vendor bill # inviting the user to create a refund. activity = self.env['mail.activity'].sudo().create({ 'activity_type_id': self.env.ref('mail.mail_activity_data_warning').id, 'note': _('The quantities on your purchase order indicate less than billed. You should ask for a refund. ' ), 'res_id': line.invoice_lines[0].move_id.id, 'res_model_id': self.env.ref('account.model_account_move').id, }) activity._onchange_activity_type_id() # If the user increased quantity of existing line or created a new line pickings = line.order_id.picking_ids.filtered( lambda x: x.state not in ('done', 'cancel') and x. location_dest_id.usage in ('internal', 'transit')) picking = pickings and pickings[0] or False if not picking: res = line.order_id._prepare_picking() picking = self.env['stock.picking'].create(res) move_vals = line._prepare_stock_moves(picking) for move_val in move_vals: self.env['stock.move']\ .create(move_val)\ ._action_confirm()\ ._action_assign()
def web_auth_signup(self, *args, **kw): qcontext = self.get_auth_signup_qcontext() if not qcontext.get('token') and not qcontext.get('signup_enabled'): raise werkzeug.exceptions.NotFound() if 'error' not in qcontext and request.httprequest.method == 'POST': try: self.do_signup(qcontext) # Send an account creation confirmation email if qcontext.get('token'): User = request.env['res.users'] user_sudo = User.sudo().search( User._get_login_domain(qcontext.get('login')), order=User._get_login_order(), limit=1) template = request.env.ref( 'auth_signup.mail_template_user_signup_account_created', raise_if_not_found=False) if user_sudo and template: template.sudo().with_context( lang=user_sudo.lang, auth_login=werkzeug.url_encode( {'auth_login': user_sudo.email}), ).send_mail(user_sudo.id, force_send=True) return self.web_login(*args, **kw) except UserError as e: qcontext['error'] = e.name or e.value except (SignupError, AssertionError) as e: if request.env["res.users"].sudo().search([ ("login", "=", qcontext.get("login")) ]): qcontext["error"] = _( "Another user is already registered using this email address." ) else: _logger.error("%s", e) qcontext['error'] = _("Could not create a new account.") response = request.render('auth_signup.signup', qcontext) response.headers['X-Frame-Options'] = 'DENY' return response
def convert_comment_to_answer(self, message_id, default=None): """ Tool to convert a comment (mail.message) into an answer (forum.post). The original comment is unlinked and a new answer from the comment's author is created. Nothing is done if the comment's author already answered the question. """ comment = self.env['mail.message'].sudo().browse(message_id) post = self.browse(comment.res_id) if not comment.author_id or not comment.author_id.user_ids: # only comment posted by users can be converted return False # karma-based action check: must check the message's author to know if own / all is_author = comment.author_id.id == self.env.user.partner_id.id karma_own = post.forum_id.karma_comment_convert_own karma_all = post.forum_id.karma_comment_convert_all karma_convert = is_author and karma_own or karma_all can_convert = self.env.user.karma >= karma_convert if not can_convert: if is_author and karma_own < karma_all: raise AccessError(_('%d karma required to convert your comment to an answer.') % karma_own) else: raise AccessError(_('%d karma required to convert a comment to an answer.') % karma_all) # check the message's author has not already an answer question = post.parent_id if post.parent_id else post post_create_uid = comment.author_id.user_ids[0] if any(answer.create_uid.id == post_create_uid.id for answer in question.child_ids): return False # create the new post post_values = { 'forum_id': question.forum_id.id, 'content': comment.body, 'parent_id': question.id, 'name': _('Re: %s') % (question.name or ''), } # done with the author user to have create_uid correctly set new_post = self.with_user(post_create_uid).create(post_values) # delete comment comment.unlink() return new_post
def test_smtp_connection(self): for server in self: smtp = False try: smtp = self.connect(mail_server_id=server.id) # simulate sending an email from current user's address - without sending it! email_from, email_to = self.env.user.email, '*****@*****.**' if not email_from: raise UserError( _('Please configure an email on the current user to simulate ' 'sending an email message via this outgoing server')) # Testing the MAIL FROM step should detect sender filter problems (code, repl) = smtp.mail(email_from) if code != 250: raise UserError( _('The server refused the sender address (%(email_from)s) ' 'with error %(repl)s') % locals()) # Testing the RCPT TO step should detect most relaying problems (code, repl) = smtp.rcpt(email_to) if code not in (250, 251): raise UserError( _('The server refused the test recipient (%(email_to)s) ' 'with error %(repl)s') % locals()) # Beginning the DATA step should detect some deferred rejections # Can't use self.data() as it would actually send the mail! smtp.putcmd("data") (code, repl) = smtp.getreply() if code != 354: raise UserError( _('The server refused the test connection ' 'with error %(repl)s') % locals()) except UserError as e: # let UserErrors (messages) bubble up raise e except Exception as e: raise UserError( _("Connection Test Failed! Here is what we got instead:\n %s" ) % ustr(e)) finally: try: if smtp: smtp.close() except Exception: # ignored, just a consequence of the previous exception pass title = _("Connection Test Succeeded!") message = _("Everything seems properly set up!") return { 'type': 'ir.actions.client', 'tag': 'display_notification', 'params': { 'title': title, 'message': message, 'sticky': False, } }
def create(self, vals_list): """ If it is product slider then slider_filter_ids is required else raise warning :param vals_list: :return: """ res = super(Slider, self).create(vals_list) if not res.slider_filter_ids: raise UserError(_('Sorry! Please set product filters first')) else: return res
def write(self, values): if values.get('publisher_comment'): if not self.env.user.has_group("website.group_website_publisher"): raise exceptions.AccessError( _("Only the publisher of the website can change the rating comment" )) if not values.get('publisher_datetime'): values['publisher_datetime'] = fields.Datetime.now() if not values.get('publisher_id'): values['publisher_id'] = self.env.user.partner_id.id return super(Rating, self).write(values)
def _onchange_partner_ids(self): if self.survey_users_login_required and self.partner_ids: if not self.survey_id.users_can_signup: invalid_partners = self.env['res.partner'].search([ ('user_ids', '=', False), ('id', 'in', self.partner_ids.ids) ]) if invalid_partners: raise UserError( _('The following recipients have no user account: %s. You should create user accounts for them or allow external signup in configuration.' % (','.join(invalid_partners.mapped('name')))))
def default_get(self, fields): if len(self.env.context.get('active_ids', list())) > 1: raise UserError(_("You may only return one picking at a time.")) res = super(ReturnPicking, self).default_get(fields) if self.env.context.get('active_id') and self.env.context.get( 'active_model') == 'stock.picking': picking = self.env['stock.picking'].browse( self.env.context.get('active_id')) if picking.exists(): res.update({'picking_id': picking.id}) return res
def action_send_sms(self, res_ids=None): for mailing in self: if not res_ids: res_ids = mailing._get_remaining_recipients() if not res_ids: raise UserError(_('There are no recipients selected.')) composer = self.env['sms.composer'].with_context(active_id=False).create(mailing._send_sms_get_composer_values(res_ids)) composer._action_send_sms() mailing.write({'state': 'done', 'sent_date': fields.Datetime.now()}) return True
def _compute_project_task_opened_value(self): if not self.env.user.has_group('project.group_project_user'): raise AccessError(_("Do not have access, skip this data for user's digest email")) for record in self: start, end, company = record._get_kpi_compute_parameters() record.kpi_project_task_opened_value = self.env['project.task'].search_count([ ('stage_id.fold', '=', False), ('create_date', '>=', start), ('create_date', '<', end), ('company_id', '=', company.id) ])
def _get_sequence_values(self): sequence_values = super(Warehouse, self)._get_sequence_values() sequence_values.update({ 'pos_type_id': { 'name': self.name + ' ' + _('Picking POS'), 'prefix': self.code + '/POS/', 'padding': 5, 'company_id': self.company_id.id, } }) return sequence_values
def action_send_mail(self, res_ids=None): author_id = self.env.user.partner_id.id for mailing in self: if not res_ids: res_ids = mailing._get_remaining_recipients() if not res_ids: raise UserError(_('There are no recipients selected.')) composer_values = { 'author_id': author_id, 'attachment_ids': [(4, attachment.id) for attachment in mailing.attachment_ids], 'body': mailing.body_html, 'subject': mailing.subject, 'model': mailing.mailing_model_real, 'email_from': mailing.email_from, 'record_name': False, 'composition_mode': 'mass_mail', 'mass_mailing_id': mailing.id, 'mailing_list_ids': [(4, l.id) for l in mailing.contact_list_ids], 'no_auto_thread': mailing.reply_to_mode != 'thread', 'template_id': None, 'mail_server_id': mailing.mail_server_id.id, } if mailing.reply_to_mode == 'email': composer_values['reply_to'] = mailing.reply_to composer = self.env['mail.compose.message'].with_context( active_ids=res_ids).create(composer_values) extra_context = self._get_mass_mailing_context() composer = composer.with_context(active_ids=res_ids, **extra_context) # auto-commit except in testing mode auto_commit = not getattr(threading.currentThread(), 'testing', False) composer.send_mail(auto_commit=auto_commit) mailing.write({ 'state': 'done', 'sent_date': fields.Datetime.now() }) return True
def action_test(self): self.ensure_one() ctx = dict(self.env.context, default_mass_mailing_id=self.id) return { 'name': _('Test Mailing'), 'type': 'ir.actions.act_window', 'view_mode': 'form', 'res_model': 'mailing.mailing.test', 'target': 'new', 'context': ctx, }
def check_granting(self): """Check the user 'uid' can grant the badge 'badge_id' and raise the appropriate exception if not Do not check for SUPERUSER_ID """ status_code = self._can_grant_badge() if status_code == self.CAN_GRANT: return True elif status_code == self.NOBODY_CAN_GRANT: raise exceptions.UserError(_('This badge can not be sent by users.')) elif status_code == self.USER_NOT_VIP: raise exceptions.UserError(_('You are not in the user allowed list.')) elif status_code == self.BADGE_REQUIRED: raise exceptions.UserError(_('You do not have the required badges.')) elif status_code == self.TOO_MANY: raise exceptions.UserError(_('You have already sent this badge too many time this month.')) else: _logger.error("Unknown badge status code: %s" % status_code) return False
def _compute_kpi_crm_lead_created_value(self): if not self.env.user.has_group('sales_team.group_sale_salesman'): raise AccessError( _("Do not have access, skip this data for user's digest email") ) for record in self: start, end, company = record._get_kpi_compute_parameters() record.kpi_crm_lead_created_value = self.env[ 'crm.lead'].search_count([('create_date', '>=', start), ('create_date', '<', end), ('company_id', '=', company.id)])
def button_done(self): if any([x.state in ('done', 'cancel') for x in self]): raise UserError( _('A Manufacturing Order is already done or cancelled.')) self.end_all() end_date = datetime.now() return self.write({ 'state': 'done', 'date_finished': end_date, 'date_planned_finished': end_date, })
def default_get(self, fields): result = super(Opportunity2Quotation, self).default_get(fields) active_model = self._context.get('active_model') if active_model != 'crm.lead': raise UserError(_('You can only apply this action from a lead.')) active_id = self._context.get('active_id') if 'lead_id' in fields and active_id: result['lead_id'] = active_id return result
def write(self, values): if 'ptav_product_variant_ids' in values: # Force write on this relation from `product.product` to properly # trigger `_compute_combination_indices`. raise UserError(_("You cannot update related variants from the values. Please update related values from the variants.")) pav_in_values = 'product_attribute_value_id' in values product_in_values = 'product_tmpl_id' in values if pav_in_values or product_in_values: for ptav in self: if pav_in_values and ptav.product_attribute_value_id.id != values['product_attribute_value_id']: raise UserError( _("You cannot change the value of the value %s set on product %s.") % (ptav.display_name, ptav.product_tmpl_id.display_name) ) if product_in_values and ptav.product_tmpl_id.id != values['product_tmpl_id']: raise UserError( _("You cannot change the product of the value %s set on product %s.") % (ptav.display_name, ptav.product_tmpl_id.display_name) ) return super(ProductTemplateAttributeValue, self).write(values)
def launch_payment(self): return { 'name': _('Payment'), 'view_mode': 'form', 'res_model': 'pos.make.payment', 'view_id': False, 'target': 'new', 'views': False, 'type': 'ir.actions.act_window', 'context': self.env.context, }