def update_status(self, new_status): if new_status == self.status: return transition = (self.status, new_status) if transition not in self.__class__._transitions: raise BadRequest( gettext('electronic_signature.msg_unauthorized_transition', provider_id=self.provider_id, provider=self.provider_credential.provider if self.provider_credential else '', status=new_status)) if self.status != new_status: # the transition writes the status on the signature getattr(self.__class__, 'set_status_%s' % new_status)([self]) # now that the status is updated in database, we can notify if new_status in ('expired', 'canceled'): self.notify_signature_failed() elif new_status == 'completed': self.notify_signature_completed()
def get(self, _lock=False): ''' Return the next sequence value ''' cls = self.__class__ # bypass rules on sequences with Transaction().set_context(user=False, _check_access=False): with Transaction().set_user(0): try: sequence = cls(self.id) except TypeError: raise MissingError(gettext('ir.msg_sequence_missing')) if _lock: self.lock() date = Transaction().context.get('date') return '%s%s%s' % ( cls._process(sequence.prefix, date=date), cls._get_sequence(sequence), cls._process(sequence.suffix, date=date), )
def find(cls, date=None, exception=True): pool = Pool() Lang = pool.get('ir.lang') Date = pool.get('ir.date') if not date: date = Date.today() workyears = cls.search([ ('start_date', '<=', date), ('end_date', '>=', date), ], order=[('start_date', 'DESC')], limit=1) if not workyears: if exception: lang = Lang.get() formatted = lang.strftime(date) raise UserError(gettext( 'lims.msg_no_workyear_date', date=formatted)) else: return None return workyears[0].id
def write(cls, *args): pool = Pool() Warning = pool.get('res.user.warning') actions = iter(args) for templates, values in zip(actions, actions): if not values.get("purchase_uom"): continue for template in templates: if not template.purchase_uom: continue if template.purchase_uom.id == values["purchase_uom"]: continue for product in template.products: if not product.product_suppliers: continue name = '%s@product_template' % template.id if Warning.check(name): raise PurchaseUOMWarning( name, gettext('purchase.msg_change_purchase_uom')) super(Template, cls).write(*args)
def encode(element): for attr in ('states', 'domain', 'spell'): if not element.get(attr): continue try: value = PYSONDecoder().decode(element.get(attr)) validates.get(attr, lambda a: True)(value) except Exception as e: error_log = '%s: <%s %s="%s"/>' % ( e, element.get('id') or element.get('name'), attr, element.get(attr)) logger.error( 'Invalid XML view %s:\n%s\n%s', view.rec_name, error_log, xml) raise XMLError( gettext( 'ir.msg_view_invalid_xml', name=view.rec_name), error_log) from e for child in element: encode(child)
def check_deposit(cls, invoices): to_check = set() for invoice in invoices: for line in invoice.lines: if line.type != 'line': continue if line.account.type.deposit: if ((invoice.type.endswith('invoice') and line.amount < 0) or (invoice.type.endswith('credit_note') and line.amount > 0)): sign = 1 if invoice.type.startswith('in') else -1 to_check.add((invoice.party, line.account, sign)) for party, account, sign in to_check: if not party.check_deposit(account, sign): raise DepositError( gettext('account_deposit.msg_deposit_not_enough', account=account.rec_name, party=party.rec_name))
def post(cls, statements): pool = Pool() Lang = pool.get('ir.lang') StatementLine = pool.get('account.statement.line') for statement in statements: for origin in statement.origins: if origin.pending_amount: lang = Lang.get() amount = lang.currency( origin.pending_amount, statement.journal.currency) raise StatementPostError( gettext('account_statement' '.msg_statement_post_pending_amount', statement=statement.rec_name, amount=amount, origin=origin.rec_name)) # Write state to skip statement test on Move.post cls.write(statements, {'state': 'posted'}) lines = [l for s in statements for l in s.lines] StatementLine.post_move(lines)
def _login_password(cls, login, parameters): if 'password' not in parameters: msg = gettext('res.msg_user_password', login=login) raise LoginException('password', msg, type='password') user_id, password_hash, password_reset = cls._get_login(login) if user_id and password_hash: password = parameters['password'] valid, new_hash = cls.check_password(password, password_hash) if valid: if new_hash: logger.info("Update password hash for %s", user_id) with Transaction().new_transaction() as transaction: with transaction.set_user(0): cls.write([cls(user_id)], { 'password_hash': new_hash, }) return user_id elif user_id and password_reset: if password_reset == parameters['password']: return user_id
def check_identifier_types(self, field_names=None): pool = Pool() Identifier = pool.get('party.identifier') if field_names and 'identifier_types' not in field_names: return if self.identifier_types: identifier_types = [None, ''] + list(self.identifier_types) identifiers = Identifier.search([ ('type', 'not in', identifier_types), ], limit=1, order=[]) if identifiers: identifier, = identifiers selection = self.fields_get( ['identifier_types'])['identifier_types']['selection'] selection = dict(selection) raise AccessError(gettext( 'party.msg_identifier_type_remove', type=selection.get(identifier.type, identifier.type), identifier=identifier.rec_name, ))
def check_uniqueness(cls, orders): """ Ensure uniqueness of order points. I.E that there is no several order point for the same location, the same product and the same company. """ query = ['OR'] for op in orders: field = cls._type2field(op.type) arg = [ 'AND', ('product', '=', op.product.id), (field, '=', getattr(op, field).id), ('id', '!=', op.id), ('company', '=', op.company.id), ] query.append(arg) if cls.search(query): raise OrderPointValidationError( gettext('stock_supply.msg_order_point_unique'))
def deactivate(cls, modules): pool = Pool() Module = pool.get('ir.module') Dependency = pool.get('ir.module.dependency') module_table = Module.__table__() dep_table = Dependency.__table__() cursor = Transaction().connection.cursor() for module in modules: cursor.execute(*dep_table.join(module_table, condition=(dep_table.module == module_table.id) ).select(module_table.state, module_table.name, where=(dep_table.name == module.name) & NotIn( module_table.state, ['not activated', 'to remove']))) res = cursor.fetchall() if res: raise DeactivateDependencyError( gettext('ir.msg_module_deactivate_dependency'), '\n'.join('\t%s: %s' % (x[0], x[1]) for x in res)) cls.write(modules, {'state': 'to remove'})
def transition_start(self): pool = Pool() Request = pool.get('purchase.request') Warning = pool.get('res.user.warning') requests = Request.browse(Transaction().context['active_ids']) reqs = [r for r in requests if r.state in {'draft', 'quotation'}] if reqs: for r in reqs: if r.state == 'quotation': if Warning.check(str(r)): raise PreviousQuotation( str(r), gettext( 'purchase_request_quotation' '.msg_previous_quotation', request=r.rec_name)) return 'ask_suppliers' return 'end'
def write(cls, *args): pool = Pool() Move = pool.get('account.move') actions = iter(args) for fiscalyears, values in zip(actions, actions): if values.get('post_move_sequence'): for fiscalyear in fiscalyears: if (fiscalyear.post_move_sequence and fiscalyear.post_move_sequence.id != values['post_move_sequence']): if Move.search([ ('period.fiscalyear', '=', fiscalyear.id), ('state', '=', 'posted'), ]): raise AccessError( gettext( 'account.' 'msg_change_fiscalyear_post_move_sequence', fiscalyear=fiscalyear.rec_name)) super(FiscalYear, cls).write(*args)
def check_type_for_moves(self): """ Check locations with moves have types compatible with moves. """ invalid_move_types = ['warehouse', 'view'] Move = Pool().get('stock.move') if self.type in invalid_move_types: # Use root to compute for all companies with Transaction().set_user(0): moves = Move.search([ [ 'OR', ('to_location', '=', self.id), ('from_location', '=', self.id), ], ('state', 'not in', ['staging', 'draft']), ]) if moves: raise LocationValidationError( gettext('stock.msg_location_invalid_type_for_moves', location=self.rec_name, type=self.type_string))
def reopen(cls, fiscalyears): ''' Re-open a fiscal year ''' Deferral = Pool().get('account.account.deferral') for fiscalyear in fiscalyears: if cls.search([ ('start_date', '>=', fiscalyear.end_date), ('state', '!=', 'open'), ('company', '=', fiscalyear.company.id), ]): raise FiscalYearReOpenError( gettext('account.msg_reopen_fiscalyear_later', fiscalyear=fiscalyear.rec_name)) deferrals = Deferral.search([ ('fiscalyear', '=', fiscalyear.id), ]) Deferral.delete(deferrals)
def wrapper(cls, records, *args, **kwargs): pool = Pool() ModelAccess = pool.get('ir.model.access') Button = pool.get('ir.model.button') ButtonClick = pool.get('ir.model.button.click') User = pool.get('res.user') transaction = Transaction() check_access = transaction.context.get('_check_access') assert len(records) == len(set(records)), "Duplicate records" if (transaction.user != 0) and check_access: ModelAccess.check(cls.__name__, 'read') groups = set(User.get_groups()) button_groups = Button.get_groups(cls.__name__, func.__name__) if button_groups: if not groups & button_groups: raise AccessButtonError( gettext('ir.msg_access_button_error', button=func.__name__, model=cls.__name__)) else: ModelAccess.check(cls.__name__, 'write') with Transaction().set_context(_check_access=False): if (transaction.user != 0) and check_access: button_rules = Button.get_rules( cls.__name__, func.__name__) if button_rules: clicks = ButtonClick.register( cls.__name__, func.__name__, records) records = [r for r in records if all(br.test(r, clicks.get(r.id, [])) for br in button_rules)] # Reset click after filtering in case the button also has rules names = Button.get_reset(cls.__name__, func.__name__) if names: ButtonClick.reset(cls.__name__, names, records) return func(cls, records, *args, **kwargs)
def close(cls, fiscalyears): ''' Close a fiscal year ''' pool = Pool() Period = pool.get('account.period') Account = pool.get('account.account') Deferral = pool.get('account.account.deferral') # Prevent create new fiscal year or period cls.lock() Period.lock() deferrals = [] for fiscalyear in fiscalyears: if cls.search([ ('end_date', '<=', fiscalyear.start_date), ('state', '=', 'open'), ('company', '=', fiscalyear.company.id), ]): raise FiscalYearCloseError( gettext('account.msg_close_fiscalyear_earlier', fiscalyear=fiscalyear.rec_name)) periods = Period.search([ ('fiscalyear', '=', fiscalyear.id), ]) Period.close(periods) with Transaction().set_context(fiscalyear=fiscalyear.id, date=None, cumulate=True, journal=None): accounts = Account.search([ ('company', '=', fiscalyear.company.id), ]) for account in accounts: deferral = fiscalyear.get_deferral(account) if deferral: deferrals.append(deferral) Deferral.save(deferrals)
def check_dates(self): cursor = Transaction().connection.cursor() table = self.__table__() cursor.execute( *table.select(table.id, where=(((table.start_date <= self.start_date) & (table.end_date >= self.start_date)) | ( (table.start_date <= self.end_date) & (table.end_date >= self.end_date)) | ( (table.start_date >= self.start_date) & (table.end_date <= self.end_date))) & (table.id != self.id))) second_id = cursor.fetchone() if second_id: second = self.__class__(second_id[0]) raise UserError( gettext( 'lims.msg_workyear_overlaps', first=self.rec_name, second=second.rec_name, ))
def check_unique(cls, numbers, field_names=None): if field_names and not (field_names & {'number', 'coupon'}): return duplicates = [] for sub_numbers in grouped_slice(numbers): domain = ['OR'] for number in sub_numbers: domain.append([ ('number', '=', number.number), ('id', '!=', number.id), ('coupon.promotion.company', '=', number.coupon.promotion.company.id), ]) duplicates.extend(cls.search(domain)) if duplicates: numbers = ', '.join(n.number for n in duplicates[:5]) if len(duplicates) > 5: numbers += '...' raise DuplicateError( gettext('sale_promotion_coupon.msg_duplicate_numbers', numbers=numbers))
def check_over_shipment(self): pool = Pool() Configuration = pool.get('sale.configuration') Warning = pool.get('res.user.warning') config = Configuration(1) if self.quantity >= 0: shipment_type = 'out' else: shipment_type = 'in' shipped_quantity = self._get_shipped_quantity(shipment_type) tolerance = config.sale_over_shipment_tolerance if tolerance is not None: maximal_quantity = abs(self.quantity * tolerance) if shipped_quantity > maximal_quantity: name = 'over_shipment_sale_line_%d' % self.id if Warning.check(name): raise OverShipmentWarning( name, gettext('sale_shipment_tolerance.msg_over_shipment', line=self.rec_name))
def done(cls, productions): pool = Pool() Warning = pool.get('res.user.warning') def pending_purchase(production): return any(l.purchase_state in {'draft', 'quotation'} for l in production.purchase_lines) pendings = list(filter(pending_purchase, productions)) if pendings: names = ', '.join(p.rec_name for p in productions[:5]) if len(pendings) > 5: names += '...' warning_name = '%s.pending_purchase.done' % hashlib.md5( str(pendings).encode('utf-8')).hexdigest() if Warning.check(warning_name): raise PurchaseWarning( warning_name, gettext('production_outsourcing.msg_pending_purchase_done', productions=names)) super(Production, cls).done(productions)
def wrapper(self): account = func(self) if not account: account = self.get_account(field_name + '_used') # Allow empty values on on_change if not account and not Transaction().readonly: Model = self.__class__ field = field_name if field_string: if getattr(self, field_string, None): Model = getattr(self, field_string).__class__ else: field = field_string field = ( Model.fields_get([field])[field]['string']) raise AccountError( gettext('account_product.msg_missing_account', field=field, name=self.rec_name)) if account: return account.current()
def default_start(self, fields): pool = Pool() Sale = pool.get('sale.sale') User = pool.get('res.user') sale = Sale(Transaction().context['active_id']) user = User(Transaction().user) sale_device = sale.sale_device or user.sale_device or False if user.id != 0 and not sale_device: raise UserError(gettext('sale_payment.not_sale_device')) return { 'journal': sale_device.journal.id if sale_device.journal else None, 'journals': [j.id for j in sale_device.journals], 'payment_amount': sale.total_amount - sale.paid_amount if sale.paid_amount else sale.total_amount, 'currency_digits': sale.currency_digits, 'party': sale.party.id, }
def generate_edi_file(cls, shipments): pool = Pool() Configuration = pool.get('stock.configuration') Warning = pool.get('res.user.warning') done_edi_shipment = Transaction().context.get( 'done_edi_shipment', False) if done_edi_shipment: configuration = Configuration(1) if not configuration.automatic_edi_shipment_out: return for shipment in shipments: if shipment.is_edi: if done_edi_shipment: warning_name = '%s.send_edi_shipment' % shipment if Warning.check(warning_name): raise UserWarning(warning_name, gettext( 'stock_shipment_out_edi.msg_send_edi_shipment', shipment=shipment.number)) shipment.generate_edi()
def post(cls, moves): pool = Pool() BankReconciliation = pool.get('cash_bank.reconciliation') reconciliations = {} # Key: account, value: last reconc. date for move in moves: for line in move.lines: if line.account.id not in reconciliations: last_date = \ BankReconciliation.last_cash_bank_reconciliation_date( line.account) if last_date is None: continue reconciliations[line.account.id] = last_date last_date = reconciliations[line.account.id] if last_date and move.date <= last_date: raise UserError( gettext('cash_bank_reconciliation.acc_invalid_move', account=line.account.rec_name)) super(Move, cls).post(moves)
def get_move(self): ''' Return Move instance for the inventory line ''' pool = Pool() Move = pool.get('stock.move') Uom = pool.get('product.uom') qty = self.quantity if qty is None: if self.inventory.empty_quantity is None: raise InventoryValidationError( gettext('stock.msg_inventory_missing_empty_quantity', inventory=self.inventory.rec_name)) if self.inventory.empty_quantity == 'keep': return else: qty = 0.0 delta_qty = Uom.compute_qty(self.uom, self.expected_quantity - qty, self.uom) if delta_qty == 0.0: return from_location = self.inventory.location to_location = self.inventory.lost_found if delta_qty < 0: (from_location, to_location, delta_qty) = \ (to_location, from_location, -delta_qty) return Move( from_location=from_location, to_location=to_location, quantity=delta_qty, product=self.product, uom=self.uom, company=self.inventory.company, effective_date=self.inventory.date, origin=self, )
def create_moves(cls, shipments): pool = Pool() Move = pool.get('stock.move') CatalogLine = pool.get('stock.shipment.internal.catalog_line') to_create = [] to_delete = [] same_from_to_locations = set() for shipment in shipments: if shipment.state != 'draft' or not shipment.catalog_lines: continue to_delete += [m for m in shipment.moves if (m.state in ('draft', 'cancel') and (m.origin and m.origin.__name__ == CatalogLine.__name__))] move_lines_with_quantity = [line for line in shipment.catalog_lines if line.quantity > 0] for line in move_lines_with_quantity: move = Move() move.shipment = shipment move.company = shipment.company move.from_location = line.catalogue.location move.to_location = shipment.to_location if move.from_location == move.to_location: same_from_to_locations.add(move.from_location.rec_name) break move.product = line.product move.on_change_product() move.quantity = line.quantity move.origin = line to_create.append(move) if same_from_to_locations: raise UserError(gettext('intern_catalogue.msg_same_from_to_locations', locations=','.join(list(same_from_to_locations)))) if to_delete: Move.draft(to_delete) Move.delete(to_delete) if to_create: Move.create([x._save_values for x in to_create])
def test_gettext_with_translation(self): "gettext returns the translated text" pool = Pool() Lang = pool.get('ir.lang') Translation = pool.get('ir.translation') ModelData = pool.get('ir.model.data') lang, = Lang.search([('code', '!=', 'en')], limit=1) Translation.create([{ 'name': 'ir.message,text', 'lang': lang.code, 'type': 'model', 'res_id': ModelData.get_id('tests', 'msg_test'), 'src': 'Message', 'value': 'Translated Message', 'module': 'tests', 'fuzzy': False, }]) message = gettext('tests.msg_test', lang.code) self.assertEqual(message, 'Translated Message')
def parseVariable(self): self.skipWhitespace() var = '' while self.hasNext(): char = self.peek() if char.lower() in '_abcdefghijklmnopqrstuvwxyz0123456789': var += char self._index += 1 else: break value = self._vars.get(var, None) if value is None: raise UserError( gettext('lims.msg_unrecognized_variable', variable=var)) if value == '': return float(0) try: value = float(value) except (ValueError): return float(0) return value
def post(cls, invoices): ''' Check up invoices that requires bank account because its payment type, has one ''' to_save = [] for invoice in invoices: account_bank = (invoice.payment_type and invoice.payment_type.account_bank or 'none') if (invoice.payment_type and account_bank != 'none' and not invoice.bank_account): invoice._get_bank_account() if not invoice.bank_account: raise UserError( gettext('account_bank.invoice_without_bank_account', invoice=invoice.rec_name, payment_type=invoice.payment_type.rec_name)) to_save.append(invoice) if to_save: cls.save(to_save) super(Invoice, cls).post(invoices)