def web_login(self, *args, **kw): ensure_db() if request.httprequest.method == 'GET' and request.session.uid and request.params.get( 'redirect'): # Redirect if already logged in and redirect param is present return http.redirect_with_hash(request.params.get('redirect')) providers = self.list_providers() response = super(OAuthLogin, self).web_login(*args, **kw) if response.is_qweb: error = request.params.get('oauth_error') if error == '1': error = _("Sign up is not allowed on this database.") elif error == '2': error = _("Access Denied") elif error == '3': error = _( "You do not have access to this database or your invitation has expired. Please ask for an invitation and be sure to follow the link in your invitation email." ) else: error = None response.qcontext['providers'] = providers if error: response.qcontext['error'] = error return response
def _onchange_product_id_check_availability(self): if not self.product_id or not self.product_uom_qty or not self.product_uom: self.product_packaging = False return {} if self.product_id.type == 'product': precision = self.env['decimal.precision'].precision_get( 'Product Unit of Measure') product = self.product_id.with_context( warehouse=self.order_id.warehouse_id.id, lang=self.order_id.partner_id.lang or self.env.user.lang or 'en_US') product_qty = self.product_uom._compute_quantity( self.product_uom_qty, self.product_id.uom_id) if float_compare(product.virtual_available, product_qty, precision_digits=precision) == -1: is_available = self._check_routing() if not is_available: message = _('You plan to sell %s %s but you only have %s %s available in %s warehouse.') % \ (self.product_uom_qty, self.product_uom.name, product.virtual_available, product.uom_id.name, self.order_id.warehouse_id.name) # We check if some products are available in other warehouses. if float_compare(product.virtual_available, self.product_id.virtual_available, precision_digits=precision) == -1: message += _('\nThere are %s %s available accross all warehouses.') % \ (self.product_id.virtual_available, product.uom_id.name) warning_mess = { 'title': _('Not enough inventory!'), 'message': message } return {'warning': warning_mess} return {}
def get_abandoned_carts(self): self.ensure_one() return { 'name': _('Abandoned Carts'), 'type': 'ir.actions.act_window', 'view_type': 'form', 'view_mode': 'tree,form', 'domain': [('is_abandoned_cart', '=', True)], 'search_view_id': self.env.ref('sale.sale_order_view_search_inherit_sale').id, 'context': { 'search_default_team_id': self.id, 'default_team_id': self.id, 'search_default_recovery_email': 1, 'create': False }, 'res_model': 'sale.order', 'help': _('''<p class="oe_view_nocontent_create"> You can find all abandoned carts here, i.e. the carts generated by your website's visitors from over an hour ago that haven't been confirmed yet.</p> <p>You should send an email to the customers to encourage them!</p> '''), }
def onchange_serial_number(self): """ When the user is encoding a move line for a tracked product, we apply some logic to help him. This includes: - automatically switch `qty_done` to 1.0 - warn if he has already encoded `lot_name` in another move line """ res = {} if self.product_id.tracking == 'serial': if not self.qty_done: self.qty_done = 1 message = None if self.lot_name or self.lot_id: move_lines_to_check = self._get_similar_move_lines() - self if self.lot_name: counter = Counter(move_lines_to_check.mapped('lot_name')) if counter.get( self.lot_name) and counter[self.lot_name] > 1: message = _( 'You cannot use the same serial number twice. Please correct the serial numbers encoded.' ) elif self.lot_id: counter = Counter(move_lines_to_check.mapped('lot_id.id')) if counter.get( self.lot_id.id) and counter[self.lot_id.id] > 1: message = _( 'You cannot use the same serial number twice. Please correct the serial numbers encoded.' ) if message: res['warning'] = {'title': _('Warning'), 'message': message} return res
def _do_payment(self): if self.payment_token_id.acquirer_id.capture_manually: raise ValidationError( _('This feature is not available for payment acquirers set to the "Authorize" mode.\n' 'Please use a token from another provider than %s.') % self.payment_token_id.acquirer_id.name) reference = "P-%s-%s" % ( self.id, datetime.datetime.now().strftime('%y%m%d_%H%M%S')) tx = self.env['payment.transaction'].create({ 'amount': self.amount, 'acquirer_id': self.payment_token_id.acquirer_id.id, 'type': 'server2server', 'currency_id': self.currency_id.id, 'reference': reference, 'payment_token_id': self.payment_token_id.id, 'partner_id': self.partner_id.id, 'partner_country_id': self.partner_id.country_id.id, }) s2s_result = tx.s2s_do_transaction() if not s2s_result or tx.state != 'done': raise ValidationError( _("Payment transaction failed (%s)") % tx.state_message) self.payment_transaction_id = tx
def asset_compute(self): self.ensure_one() context = self._context created_move_ids = self.env[ 'account.asset.asset'].compute_generated_entries( self.date, asset_type=context.get('asset_type')) return { 'name': _('Created Asset Moves') if context.get('asset_type') == 'purchase' else _('Created Revenue Moves'), 'view_type': 'form', 'view_mode': 'tree,form', 'res_model': 'account.move', 'view_id': False, 'domain': "[('id','in',[" + ','.join(str(id) for id in created_move_ids) + "])]", 'type': 'ir.actions.act_window', }
def print_checks(self): """ Check that the recordset is valid, set the payments state to sent and call print_checks() """ # Since this method can be called via a client_action_multi, we need to make sure the received records are what we expect self = self.filtered(lambda r: r.payment_method_id.code == 'check_printing' and r.state != 'reconciled') if len(self) == 0: raise UserError(_("Payments to print as a checks must have 'Check' selected as payment method and " "not have already been reconciled")) if any(payment.journal_id != self[0].journal_id for payment in self): raise UserError(_("In order to print multiple checks at once, they must belong to the same bank journal.")) if not self[0].journal_id.check_manual_sequencing: # The wizard asks for the number printed on the first pre-printed check # so payments are attributed the number of the check the'll be printed on. last_printed_check = self.search([ ('journal_id', '=', self[0].journal_id.id), ('check_number', '!=', 0)], order="check_number desc", limit=1) next_check_number = last_printed_check and last_printed_check.check_number + 1 or 1 return { 'name': _('Print Pre-numbered Checks'), 'type': 'ir.actions.act_window', 'res_model': 'print.prenumbered.checks', 'view_type': 'form', 'view_mode': 'form', 'target': 'new', 'context': { 'payment_ids': self.ids, 'default_next_check_number': next_check_number, } } else: self.filtered(lambda r: r.state == 'draft').post() return self.do_print_checks()
def web_auth_reset_password(self, *args, **kw): qcontext = self.get_auth_signup_qcontext() if not qcontext.get('token') and not qcontext.get( 'reset_password_enabled'): raise werkzeug.exceptions.NotFound() if 'error' not in qcontext and request.httprequest.method == 'POST': try: if qcontext.get('token'): self.do_signup(qcontext) return super(AuthSignupHome, self).web_login(*args, **kw) else: login = qcontext.get('login') assert login, _("No login provided.") _logger.info( "Password reset attempt for <%s> by user <%s> from %s", login, request.env.user.login, request.httprequest.remote_addr) request.env['res.users'].sudo().reset_password(login) qcontext['message'] = _( "An email has been sent with credentials to reset your password" ) except UserError as e: qcontext['error'] = e.name or e.value except SignupError: qcontext['error'] = _("Could not reset your password") _logger.exception('error when resetting password') except Exception as e: qcontext['error'] = str(e) response = request.render('auth_signup.reset_password', qcontext) response.headers['X-Frame-Options'] = 'DENY' return response
def _print_report(self, data): res = {} data = self.pre_print_report(data) data['form'].update(self.read(['period_length'])[0]) period_length = data['form']['period_length'] if period_length <= 0: raise UserError(_('You must set a period length greater than 0.')) if not data['form']['date_from']: raise UserError(_('You must set a start date.')) start = datetime.strptime(data['form']['date_from'], "%Y-%m-%d") for i in range(5)[::-1]: stop = start - relativedelta(days=period_length - 1) res[str(i)] = { 'name': (i != 0 and (str( (5 - (i + 1)) * period_length) + '-' + str( (5 - i) * period_length)) or ('+' + str(4 * period_length))), 'stop': start.strftime('%Y-%m-%d'), 'start': (i != 0 and stop.strftime('%Y-%m-%d') or False), } start = stop - relativedelta(days=1) data['form'].update(res) return self.env.ref( 'account.action_report_aged_partner_balance').with_context( landscape=True).report_action(self, data=data)
def _confirm_so(self): """ Check tx state, confirm the potential SO """ self.ensure_one() if self.sale_order_id.state not in ['draft', 'sent', 'sale']: _logger.warning( '<%s> transaction STATE INCORRECT for order %s (ID %s, state %s)', self.acquirer_id.provider, self.sale_order_id.name, self.sale_order_id.id, self.sale_order_id.state) return 'pay_sale_invalid_doc_state' if not float_compare(self.amount, self.sale_order_id.amount_total, 2) == 0: _logger.warning( '<%s> transaction AMOUNT MISMATCH for order %s (ID %s): expected %r, got %r', self.acquirer_id.provider, self.sale_order_id.name, self.sale_order_id.id, self.sale_order_id.amount_total, self.amount, ) self.sale_order_id.message_post( subject=_("Amount Mismatch (%s)") % self.acquirer_id.provider, body= _("The sale order was not confirmed despite response from the acquirer (%s): SO amount is %r but acquirer replied with %r." ) % ( self.acquirer_id.provider, self.sale_order_id.amount_total, self.amount, )) return 'pay_sale_tx_amount' if self.state == 'authorized' and self.acquirer_id.capture_manually: _logger.info( '<%s> transaction authorized, auto-confirming order %s (ID %s)', self.acquirer_id.provider, self.sale_order_id.name, self.sale_order_id.id) if self.sale_order_id.state in ('draft', 'sent'): self.sale_order_id.with_context( send_email=True).action_confirm() elif self.state == 'done': _logger.info( '<%s> transaction completed, auto-confirming order %s (ID %s)', self.acquirer_id.provider, self.sale_order_id.name, self.sale_order_id.id) if self.sale_order_id.state in ('draft', 'sent'): self.sale_order_id.with_context( send_email=True).action_confirm() elif self.state not in ['cancel', 'error' ] and self.sale_order_id.state == 'draft': _logger.info( '<%s> transaction pending/to confirm manually, sending quote email for order %s (ID %s)', self.acquirer_id.provider, self.sale_order_id.name, self.sale_order_id.id) self.sale_order_id.force_quotation_send() else: _logger.warning('<%s> transaction MISMATCH for order %s (ID %s)', self.acquirer_id.provider, self.sale_order_id.name, self.sale_order_id.id) return 'pay_sale_tx_state' return True
def onchange_product_uom(self): res = {} if not self.product_id or not self.product_uom: return res if self.product_uom.category_id != self.product_id.uom_id.category_id: res['warning'] = {'title': _('Warning'), 'message': _('The Product Unit of Measure you chose has a different category than in the product form.')} self.product_uom = self.product_id.uom_id.id return res
def _ogone_form_get_tx_from_data(self, data): """ Given a data dict coming from ogone, verify it and find the related transaction record. Create a payment token if an alias is returned.""" reference, pay_id, shasign, alias = data.get('orderID'), data.get( 'PAYID'), data.get('SHASIGN'), data.get('ALIAS') if not reference or not pay_id or not shasign: error_msg = _( 'Ogone: received data with missing reference (%s) or pay_id (%s) or shasign (%s)' ) % (reference, pay_id, shasign) _logger.info(error_msg) raise ValidationError(error_msg) # find tx -> @TDENOTE use paytid ? tx = self.search([('reference', '=', reference)]) if not tx or len(tx) > 1: error_msg = _('Ogone: received data for reference %s') % ( reference) if not tx: error_msg += _('; no order found') else: error_msg += _('; multiple order found') _logger.info(error_msg) raise ValidationError(error_msg) # verify shasign shasign_check = tx.acquirer_id._ogone_generate_shasign('out', data) if shasign_check.upper() != shasign.upper(): error_msg = _( 'Ogone: invalid shasign, received %s, computed %s, for data %s' ) % (shasign, shasign_check, data) _logger.info(error_msg) raise ValidationError(error_msg) if not tx.acquirer_reference: tx.acquirer_reference = pay_id # alias was created on ogone server, store it if alias and tx.type == 'form_save': Token = self.env['payment.token'] domain = [('acquirer_ref', '=', alias)] cardholder = data.get('CN') if not Token.search_count(domain): _logger.info('Ogone: saving alias %s for partner %s' % (data.get('CARDNO'), tx.partner_id)) ref = Token.create({ 'name': data.get('CARDNO') + (' - ' + cardholder if cardholder else ''), 'partner_id': tx.partner_id.id, 'acquirer_id': tx.acquirer_id.id, 'acquirer_ref': alias }) tx.write({'payment_token_id': ref.id}) return tx
def _graph_title_and_key(self): if self.type == 'sale': return ['', _('Sales: Untaxed Total')] elif self.type == 'purchase': return ['', _('Purchase: Untaxed Total')] elif self.type == 'cash': return ['', _('Cash: Balance')] elif self.type == 'bank': return ['', _('Bank: Balance')]
def unlink(self): for record in self: if record.move_check: if record.asset_id.category_id.type == 'purchase': msg = _("You cannot delete posted depreciation lines.") else: msg = _("You cannot delete posted installment lines.") raise UserError(msg) return super(AccountAssetDepreciationLine, self).unlink()
def _run(self, records): for box in self: for record in records: if not record.journal_id: raise UserError(_("Please check that the field 'Journal' is set on the Bank Statement")) if not record.journal_id.company_id.transfer_account_id: raise UserError(_("Please check that the field 'Transfer Account' is set on the company.")) box._create_bank_statement_line(record) return {}
def unlink(self): if any(bool(rec.move_line_ids) for rec in self): raise UserError( _("You can not delete a payment that is already posted")) if any(rec.move_name for rec in self): raise UserError( _('It is not allowed to delete a payment that already created a journal entry since it would create a gap in the numbering. You should create the journal entry again and cancel it thanks to a regular revert.' )) return super(account_payment, self).unlink()
def _get_menu_entries(self): """ Method returning menu entries to display on the website view of the event, possibly depending on some options in inheriting modules. """ self.ensure_one() return [ (_('Introduction'), False, 'website_event.template_intro'), (_('Location'), False, 'website_event.template_location'), (_('Register'), '/event/%s/register' % slug(self), False), ]
def button_reg_close(self): """ Close Registration """ today = fields.Datetime.now() if self.event_id.date_begin <= today and self.event_id.state == 'confirm': self.write({'state': 'done', 'date_closed': today}) elif self.event_id.state == 'draft': raise UserError(_("You must wait the event confirmation before doing this action.")) else: raise UserError(_("You must wait the event starting day before doing this action."))
def done(self): pickings = self.mapped('picking_ids').filtered( lambda picking: picking.state not in ('cancel', 'done')) if any(picking.state not in ('assigned') for picking in pickings): raise UserError( _('Some pickings are still waiting for goods. Please check or force their availability before setting this batch to done.' )) for picking in pickings: picking.message_post( body= "<b>%s:</b> %s <a href=#id=%s&view_type=form&model=stock.picking.batch>%s</a>" % (_("Transferred by"), _("Batch Picking"), picking.batch_id.id, picking.batch_id.name)) picking_to_backorder = self.env['stock.picking'] picking_without_qty_done = self.env['stock.picking'] for picking in pickings: if all([x.qty_done == 0.0 for x in picking.move_line_ids]): # If no lots when needed, raise error picking_type = picking.picking_type_id if (picking_type.use_create_lots or picking_type.use_existing_lots): for ml in picking.move_line_ids: if ml.product_id.tracking != 'none': raise UserError( _('Some products require lots/serial numbers, so you need to specify those first!' )) # Check if we need to set some qty done. picking_without_qty_done |= picking elif picking._check_backorder(): picking_to_backorder |= picking else: picking.action_done() self.write({'state': 'done'}) if picking_without_qty_done: view = self.env.ref('stock.view_immediate_transfer') wiz = self.env['stock.immediate.transfer'].create({ 'pick_ids': [(4, p.id) for p in picking_without_qty_done], 'pick_to_backorder_ids': [(4, p.id) for p in picking_to_backorder], }) return { 'name': _('Immediate Transfer?'), 'type': 'ir.actions.act_window', 'view_type': 'form', 'view_mode': 'form', 'res_model': 'stock.immediate.transfer', 'views': [(view.id, 'form')], 'view_id': view.id, 'target': 'new', 'res_id': wiz.id, 'context': self.env.context, } if picking_to_backorder: return picking_to_backorder.action_generate_backorder_wizard() return True
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) move_dest_exists = False product_return_moves = [] picking = self.env['stock.picking'].browse( self.env.context.get('active_id')) if picking: res.update({'picking_id': picking.id}) if picking.state != 'done': raise UserError(_("You may only return Done pickings")) for move in picking.move_lines: if move.scrapped: continue if move.move_dest_ids: move_dest_exists = True quantity = move.product_qty - sum(move.move_dest_ids.filtered(lambda m: m.state in ['partially_available', 'assigned', 'done']).\ mapped('move_line_ids').mapped('product_qty')) quantity = float_round( quantity, precision_rounding=move.product_uom.rounding) product_return_moves.append((0, 0, { 'product_id': move.product_id.id, 'quantity': quantity, 'move_id': move.id, 'uom_id': move.product_id.uom_id.id })) if not product_return_moves: raise UserError( _("No products to return (only lines in Done state and not fully returned yet can be returned)!" )) if 'product_return_moves' in fields: res.update({'product_return_moves': product_return_moves}) if 'move_dest_exists' in fields: res.update({'move_dest_exists': move_dest_exists}) if 'parent_location_id' in fields and picking.location_id.usage == 'internal': res.update({ 'parent_location_id': picking.picking_type_id.warehouse_id and picking.picking_type_id.warehouse_id.view_location_id.id or picking.location_id.location_id.id }) if 'original_location_id' in fields: res.update({'original_location_id': picking.location_id.id}) if 'location_id' in fields: location_id = picking.location_id.id if picking.picking_type_id.return_picking_type_id.default_location_dest_id.return_location: location_id = picking.picking_type_id.return_picking_type_id.default_location_dest_id.id res['location_id'] = location_id return res
def _get_menu_entries(self): self.ensure_one() res = super(Event, self)._get_menu_entries() if self.website_track: res += [(_('Talks'), '/event/%s/track' % slug(self), False), (_('Agenda'), '/event/%s/agenda' % slug(self), False)] if self.website_track_proposal: res += [(_('Talk Proposals'), '/event/%s/track_proposal' % slug(self), False)] return res
def _get_manufacture_route_id(self): manufacture_route = self.env.ref('mrp.route_warehouse0_manufacture', raise_if_not_found=False) if not manufacture_route: manufacture_route = self.env['stock.location.route'].search( [('name', 'like', _('Manufacture'))], limit=1) if not manufacture_route: raise exceptions.UserError( _('Can\'t find any generic Manufacture route.')) return manufacture_route.id
def _onchange_qty_done(self): """ When the user is encoding a produce line for a tracked product, we apply some logic to help him. This onchange will warn him if he set `qty_done` to a non-supported value. """ res = {} if self.product_id.tracking == 'serial': if float_compare(self.qty_done, 1.0, precision_rounding=self.move_id.product_id.uom_id.rounding) != 0: message = _('You can only process 1.0 %s for products with unique serial number.') % self.product_id.uom_id.name res['warning'] = {'title': _('Warning'), 'message': message} return res
def sale_pay_form(self, acquirer_id, order_id, save_token=False, access_token=None, **kwargs): """ Json method that creates a payment.transaction, used to create a transaction when the user clicks on 'pay now' button on the payment form. :return html: form containing all values related to the acquirer to redirect customers to the acquirer website """ success_url = kwargs.get('success_url', '/my') order_sudo = request.env['sale.order'].sudo().browse(order_id) if not order_sudo: return False try: acquirer = request.env['payment.acquirer'].browse(int(acquirer_id)) except: return False # we check if the order need to create a payment token save_token = save_token or order_sudo._get_payment_type( ) == "form_save" if request.env.user._is_public(): save_token = False token = request.env['payment.token'].sudo( ) # currently no support of payment tokens tx = request.env['payment.transaction'].sudo( )._check_or_create_sale_tx( order_sudo, acquirer, payment_token=token, tx_type='form_save' if save_token else 'form', ) # set the transaction id into the session request.session['portal_sale_%s_transaction_id' % order_sudo.id] = tx.id return tx.render_sale_button( order_sudo, success_url, submit_txt=_('Pay'), render_values={ 'type': 'form_save' if save_token else 'form', 'alias_usage': _('If we store your payment information on our server, subscription payments will be made automatically.' ), })
def _check_write(self): """check that the field is created from the menu and not from an database update otherwise the database update can crash:""" if self.env.context.get('manual'): global_state = self._get_global_state() if global_state == 'anonymized': raise UserError(_("The database is currently anonymized, you cannot create, modify or delete fields.")) elif global_state == 'unstable': raise UserError(_("The database anonymization is currently in an unstable state. Some fields are anonymized," " while some fields are not anonymized. You should try to solve this problem before trying to create, write or delete fields.")) return True
def post(self): """ Create the journal items for the payment and update the payment's state to 'posted'. A journal entry is created containing an item in the source liquidity account (selected journal's default_debit or default_credit) and another in the destination reconciliable account (see _compute_destination_account_id). If invoice_ids is not empty, there will be one reconciliable move line per invoice to reconcile with. If the payment is a transfer, a second journal entry is created in the destination journal to receive money from the transfer account. """ for rec in self: if rec.state != 'draft': raise UserError(_("Only a draft payment can be posted.")) if any(inv.state != 'open' for inv in rec.invoice_ids): raise ValidationError( _("The payment cannot be processed because the invoice is not open!" )) # Use the right sequence to set the name if rec.payment_type == 'transfer': sequence_code = 'account.payment.transfer' else: if rec.partner_type == 'customer': if rec.payment_type == 'inbound': sequence_code = 'account.payment.customer.invoice' if rec.payment_type == 'outbound': sequence_code = 'account.payment.customer.refund' if rec.partner_type == 'supplier': if rec.payment_type == 'inbound': sequence_code = 'account.payment.supplier.refund' if rec.payment_type == 'outbound': sequence_code = 'account.payment.supplier.invoice' rec.name = self.env['ir.sequence'].with_context( ir_sequence_date=rec.payment_date).next_by_code(sequence_code) if not rec.name and rec.payment_type != 'transfer': raise UserError( _("You have to define a sequence for %s in your company.") % (sequence_code, )) # Create the journal entry amount = rec.amount * (rec.payment_type in ('outbound', 'transfer') and 1 or -1) move = rec._create_payment_entry(amount) # In case of a transfer, the first journal entry created debited the source liquidity account and credited # the transfer account. Now we debit the transfer account and credit the destination liquidity account. if rec.payment_type == 'transfer': transfer_credit_aml = move.line_ids.filtered( lambda r: r.account_id == rec.company_id. transfer_account_id) transfer_debit_aml = rec._create_transfer_entry(amount) (transfer_credit_aml + transfer_debit_aml).reconcile() rec.write({'state': 'posted', 'move_name': move.name}) return True
def _construct_constraint_msg(self, country_code): self.ensure_one() vat_no = "'CC##' (CC=Country Code, ##=VAT Number)" vat_no = _ref_vat.get(country_code) or vat_no if self.env.context.get('company_id'): company = self.env['res.company'].browse(self.env.context['company_id']) else: company = self.env.user.company_id if company.vat_check_vies: return '\n' + _('The VAT number [%s] for partner [%s] either failed the VIES VAT validation check or did not respect the expected format %s.') % (self.vat, self.name, vat_no) return '\n' + _('The VAT number [%s] for partner [%s] does not seem to be valid. \nNote: the expected format is %s') % (self.vat, self.name, vat_no)
def _compute_last_done_picking(self): # TDE TODO: true multi tristates = [] for picking in self.env['stock.picking'].search([('picking_type_id', '=', self.id), ('state', '=', 'done')], order='date_done desc', limit=10): if picking.date_done > picking.date: tristates.insert(0, {'tooltip': picking.name or '' + ": " + _('Late'), 'value': -1}) elif picking.backorder_id: tristates.insert(0, {'tooltip': picking.name or '' + ": " + _('Backorder exists'), 'value': 0}) else: tristates.insert(0, {'tooltip': picking.name or '' + ": " + _('OK'), 'value': 1}) self.last_done_picking = json.dumps(tristates)
def _check_pattern(self): p = self.pattern.replace("\\\\", "X").replace("\{", "X").replace("\}", "X") findall = re.findall("[{]|[}]", p) # p does not contain escaped { or } if len(findall) == 2: if not re.search("[{][N]*[D]*[}]", p): raise ValidationError(_("There is a syntax error in the barcode pattern ") + self.pattern + _(": braces can only contain N's followed by D's.")) elif re.search("[{][}]", p): raise ValidationError(_("There is a syntax error in the barcode pattern ") + self.pattern + _(": empty braces.")) elif len(findall) != 0: raise ValidationError(_("There is a syntax error in the barcode pattern ") + self.pattern + _(": a rule can only contain one pair of braces.")) elif p == '*': raise ValidationError(_(" '*' is not a valid Regex Barcode Pattern. Did you mean '.*' ?"))
def _get_default_category_id(self): if self._context.get('categ_id') or self._context.get('default_categ_id'): return self._context.get('categ_id') or self._context.get('default_categ_id') category = self.env.ref('product.product_category_all', raise_if_not_found=False) if not category: category = self.env['product.category'].search([], limit=1) if category: return category.id else: err_msg = _('You must define at least one product category in order to be able to create products.') redir_msg = _('Go to Internal Categories') raise RedirectWarning(err_msg, self.env.ref('product.product_category_action_form').id, redir_msg)