class ProductImages(sequence_ordered('sequence', 'Orden de Listado'), ModelView, ModelSQL): 'Product Images' __name__ = 'product.images' name = fields.Many2One('product.product', 'Producto') image_name = fields.Function(fields.Char('File Name'), 'get_image_name') image_id = fields.Char('File ID', readonly=True, states={'invisible': True}) image = fields.Binary('Imagen', filename='image_name', file_id=file_id, store_prefix=None) def get_img(self): foto = None if self.image_id: return '/static/img2/' + self.image_id[:2] + '/' + self.image_id[ 2:4] + '/' + self.image_id if self.image: import base64 foto = base64.b64encode(self.image).decode() return "data:image/JPEG;base64," + foto return None def get_image_name(self, name): file_name = '' if self.name.rec_name: file_name = self.name.rec_name + ".jpg" return file_name
class SaleOpportunityLine(sequence_ordered(), ModelSQL, ModelView): 'Sale Opportunity Line' __name__ = "sale.opportunity.line" service = fields.Many2One( 'sale.subscription.service', "Service", required=True, ) @fields.depends('service', 'product', 'unit', 'quantity') def on_change_service(self): if self.service: self.product = self.service.product.id self.product = self.service.product.id self.unit = self.service.product.sale_uom.id self.quantity = 1 def get_sale_line(self, sale): ''' Return sale line for opportunity line ''' SaleLine = Pool().get('sale.subscription.line') sale_line = SaleLine( subscription=sale, quantity=self.quantity, unit=self.unit, service=self.service, ) sale_line.on_change_service() return sale_line
class Level(sequence_ordered(), ModelSQL, ModelView): 'Account Dunning Level' __name__ = 'account.dunning.level' procedure = fields.Many2One('account.dunning.procedure', 'Procedure', required=True, select=True) overdue = fields.TimeDelta('Overdue', help="When the level should be applied.") @classmethod def __register__(cls, module_name): cursor = Transaction().connection.cursor() table = cls.__table_handler__(module_name) sql_table = cls.__table__() super(Level, cls).__register__(module_name) # Migration from 4.0: change days into timedelta overdue if table.column_exist('days'): cursor.execute(*sql_table.select( sql_table.id, sql_table.days, where=sql_table.days != Null)) for id_, days in cursor.fetchall(): overdue = datetime.timedelta(days) cursor.execute(*sql_table.update( [sql_table.overdue], [overdue], where=sql_table.id == id_)) table.drop_column('days') def get_rec_name(self, name): return '%s@%s' % (self.procedure.levels.index(self), self.procedure.rec_name) def test(self, line, date): if self.overdue is not None: return (date - line.maturity_date) >= self.overdue
class ViewConfiguratorLineField(sequence_ordered(), ModelSQL, ModelView): '''View Configurator Line Field''' __name__ = 'view.configurator.line.field' view = fields.Many2One('view.configurator', 'View Configurator', required=True) field = fields.Many2One('ir.model.field', 'Field', domain=[ ('model', '=', Eval('parent_model')), ], depends=['parent_model']) expand = fields.Integer('Expand') searchable = fields.Boolean('Searchable') type = fields.Selection([ ('ir.model.field', 'Field'), ], 'Type') parent_model = fields.Function(fields.Many2One('ir.model', 'Model'), 'on_change_with_parent_model') @staticmethod def default_type(): return 'ir.model.field' @fields.depends('view', '_parent_view.model') def on_change_with_parent_model(self, name=None): return self.view.model.id if self.view else None
class ProductBom(sequence_ordered(), ModelSQL, ModelView): 'Product - BOM' __name__ = 'product.product-production.bom' product = fields.Many2One('product.product', 'Product', ondelete='CASCADE', select=1, required=True, domain=[ ('producible', '=', True), ]) bom = fields.Many2One('production.bom', 'BOM', ondelete='CASCADE', select=1, required=True, domain=[ ('output_products', '=', If(Bool(Eval('product')), Eval('product', 0), Get(Eval('_parent_product', {}), 'id', 0))), ], depends=['product']) def get_rec_name(self, name): return self.bom.rec_name @classmethod def search_rec_name(cls, name, clause): return [('bom.rec_name', ) + tuple(clause[1:])]
class ProductionLeadTime(sequence_ordered(), ModelSQL, ModelView, MatchMixin): 'Production Lead Time' __name__ = 'production.lead_time' product = fields.Many2One('product.product', 'Product', ondelete='CASCADE', select=True, required=True, domain=[ ('type', '!=', 'service'), ]) bom = fields.Many2One('production.bom', 'BOM', ondelete='CASCADE', domain=[ ('output_products', '=', If(Bool(Eval('product')), Eval('product', -1), Get(Eval('_parent_product', {}), 'id', 0))), ], depends=['product']) lead_time = fields.TimeDelta('Lead Time') @classmethod def __setup__(cls): super(ProductionLeadTime, cls).__setup__() cls._order.insert(0, ('product', 'ASC'))
class LocationLeadTime(sequence_ordered(), ModelSQL, ModelView, MatchMixin): 'Location Lead Time' __name__ = 'stock.location.lead_time' warehouse_from = fields.Many2One('stock.location', 'Warehouse From', ondelete='CASCADE', domain=[ ('type', '=', 'warehouse'), ]) warehouse_to = fields.Many2One('stock.location', 'Warehouse To', ondelete='CASCADE', domain=[ ('type', '=', 'warehouse'), ]) lead_time = fields.TimeDelta( 'Lead Time', help="The time it takes to move stock between the warehouses.") @classmethod def get_lead_time(cls, pattern): for record in cls.search([]): if record.match(pattern): return record.lead_time
class PlanLines(sequence_ordered(), ModelSQL, ModelView, MatchMixin): 'Commission Plan Line' __name__ = 'commission.plan.line' plan = fields.Many2One('commission.plan', 'Plan', required=True, ondelete='CASCADE', help="The plan to which the line belongs.") category = fields.Many2One('product.category', "Category", ondelete='CASCADE', help="Apply only to products in the category.") product = fields.Many2One('product.product', "Product", ondelete='CASCADE', help="Apply only to the product.") formula = fields.Char( 'Formula', required=True, help="The python expression used to calculate the amount of " "commission for the line.\n" "It is evaluated with:\n" "- amount: the original amount") @staticmethod def default_formula(): return 'amount' @classmethod def validate(cls, lines): super(PlanLines, cls).validate(lines) for line in lines: line.check_formula() def check_formula(self): context = self.plan.get_context_formula(Decimal(0), None) try: if not isinstance(self.get_amount(**context), Decimal): raise ValueError except Exception as exception: raise FormulaError( gettext('commission.msg_plan_line_invalid_formula', formula=self.formula, line=self.rec_name, exception=exception)) from exception def get_amount(self, **context): 'Return amount (as Decimal)' context.setdefault('functions', {})['Decimal'] = Decimal return simple_eval(decistmt(self.formula), **context) def match(self, pattern): if 'categories' in pattern: pattern = pattern.copy() categories = pattern.pop('categories') if (self.category is not None and self.category.id not in categories): return False return super(PlanLines, self).match(pattern)
class DashboardAction(sequence_ordered(), ModelSQL, ModelView): "Dashboard Action" __name__ = "dashboard.action" user = fields.Many2One('res.user', 'User', required=True, select=True) act_window = fields.Many2One('ir.action.act_window', 'Action', required=True, ondelete='CASCADE', domain=[ ('res_model', '!=', None), ('res_model', '!=', ''), ('usage', '=', 'dashboard'), # XXX copy ir.action rule to prevent access rule error ['OR', ('groups', 'in', Eval('context', {}).get('groups', [])), ('groups', '=', None), ], ]) @classmethod def __register__(cls, module_name): TableHandler = backend.get('TableHandler') table = TableHandler(cls, module_name) super(DashboardAction, cls).__register__(module_name) # Migration from 2.4: drop required on sequence table.not_null_action('sequence', action='remove')
class ProductIdentifier(sequence_ordered(), ModelSQL, ModelView): "Product Identifier" __name__ = 'product.identifier' _rec_name = 'code' product = fields.Many2One('product.product', "Product", ondelete='CASCADE', required=True, select=True, help="The product identified by the code.") type = fields.Selection([ (None, ''), ('ean', "International Article Number"), ('isan', "International Standard Audiovisual Number"), ('isbn', "International Standard Book Number"), ('isil', "International Standard Identifier for Libraries"), ('isin', "International Securities Identification Number"), ('ismn', "International Standard Music Number"), ], "Type") type_string = type.translated('type') code = fields.Char("Code", required=True) @classmethod def __setup__(cls): super().__setup__() cls.__access__.add('product') @fields.depends('type', 'code') def on_change_with_code(self): if self.type and self.type != 'other': try: module = import_module('stdnum.%s' % self.type) return module.compact(self.code) except ImportError: pass except stdnum.exceptions.ValidationError: pass return self.code def pre_validate(self): super().pre_validate() self.check_code() @fields.depends('type', 'product', 'code') def check_code(self): if self.type: try: module = import_module('stdnum.%s' % self.type) except ModuleNotFoundError: return if not module.is_valid(self.code): if self.product and self.product.id > 0: product = self.product.rec_name else: product = '' raise InvalidIdentifierCode( gettext('product.msg_invalid_code', type=self.type_string, code=self.code, product=product))
class Rule(sequence_ordered(), MatchMixin, AnalyticMixin, ModelSQL, ModelView): "Analytic Rule" __name__ = 'analytic_account.rule' company = fields.Many2One('company.company', "Company", required=True) account = fields.Many2One('account.account', "Account", domain=[ ('company', '=', Eval('company', -1)), ('type', '!=', 'view'), ], depends=['company']) party = fields.Many2One('party.party', "Party", states={ 'invisible': ~Eval('party_visible'), }, depends=['party_visible']) party_visible = fields.Function(fields.Boolean("Party Visible"), 'on_change_with_party_visible') journal = fields.Many2One('account.journal', "Journal") @classmethod def default_company(cls): return Transaction().context.get('company') @fields.depends('account') def on_change_with_party_visible(self, name=None): if self.account: return self.account.party_required return False
class ProductLocation(sequence_ordered(), ModelSQL, ModelView, MatchMixin): ''' Product Location It defines the default storage location by warehouse for a product. ''' __name__ = 'stock.product.location' product = fields.Many2One('product.product', 'Product', required=True, select=True, ondelete='CASCADE') warehouse = fields.Many2One('stock.location', 'Warehouse', required=True, domain=[('type', '=', 'warehouse')], ondelete='CASCADE') location = fields.Many2One('stock.location', 'Storage Location', required=True, ondelete='CASCADE', domain=[ ('type', '=', 'storage'), ('parent', 'child_of', If(Bool(Eval('warehouse')), [Eval('warehouse')], [])), ], depends=['warehouse'])
class CarrierSelection(sequence_ordered(), MatchMixin, ModelSQL, ModelView): 'Carrier Selection' __name__ = 'carrier.selection' _get_carriers_cache = Cache('carrier.selection.get_carriers') active = fields.Boolean('Active') from_country = fields.Many2One('country.country', 'From Country', ondelete='RESTRICT') to_country = fields.Many2One('country.country', 'To Country', ondelete='RESTRICT') carrier = fields.Many2One('carrier', 'Carrier', required=True, ondelete='CASCADE') @staticmethod def default_active(): return True @classmethod def create(cls, *args, **kwargs): selections = super(CarrierSelection, cls).create(*args, **kwargs) cls._get_carriers_cache.clear() return selections @classmethod def write(cls, *args, **kwargs): super(CarrierSelection, cls).write(*args, **kwargs) cls._get_carriers_cache.clear() @classmethod def delete(cls, *args, **kwargs): super(CarrierSelection, cls).delete(*args, **kwargs) cls._get_carriers_cache.clear() @classmethod def get_carriers(cls, pattern): pool = Pool() Carrier = pool.get('carrier') key = tuple(sorted(pattern.iteritems())) carriers = cls._get_carriers_cache.get(key) if carriers is not None: return Carrier.browse(carriers) carriers = [] selections = cls.search([]) if not selections: with Transaction().set_context(active_test=False): carriers = Carrier.search([]) else: for selection in selections: if selection.match(pattern): carriers.append(selection.carrier) cls._get_carriers_cache.set(key, map(int, carriers)) return carriers
class InvoiceLine(sequence_ordered(), ModelSQL, ModelView): 'Invoice Line' __name__ = 'account.invoice.line' @classmethod def __setup__(cls): super(InvoiceLine, cls).__setup__() cls.unit_price.digits = (16, 2)
class Selection( DeactivableMixin, sequence_ordered(), MatchMixin, ModelSQL, ModelView): 'Carrier Selection' __name__ = 'carrier.selection' _get_carriers_cache = Cache( 'carrier.selection.get_carriers', context=False) from_country = fields.Many2One('country.country', 'From Country', ondelete='RESTRICT', help="Apply only when shipping from this country.\n" "Leave empty for any countries.") to_country = fields.Many2One('country.country', 'To Country', ondelete='RESTRICT', help="Apply only when shipping to this country.\n" "Leave empty for any countries.") carrier = fields.Many2One('carrier', 'Carrier', required=True, ondelete='CASCADE', help="The selected carrier.") @classmethod def create(cls, *args, **kwargs): selections = super().create(*args, **kwargs) cls._get_carriers_cache.clear() return selections @classmethod def write(cls, *args, **kwargs): super().write(*args, **kwargs) cls._get_carriers_cache.clear() @classmethod def delete(cls, *args, **kwargs): super().delete(*args, **kwargs) cls._get_carriers_cache.clear() @classmethod def get_carriers(cls, pattern): pool = Pool() Carrier = pool.get('carrier') key = tuple(sorted(pattern.items())) carriers = cls._get_carriers_cache.get(key) if carriers is not None: return Carrier.browse(carriers) carriers = [] selections = cls.search([]) if not selections: with Transaction().set_context(active_test=False): carriers = Carrier.search([]) else: for selection in selections: if (selection.match(pattern) and selection.carrier not in carriers): carriers.append(selection.carrier) cls._get_carriers_cache.set(key, list(map(int, carriers))) return carriers
class Location(sequence_ordered(), metaclass=PoolMeta): "Stock Location" __name__ = 'stock.location' @classmethod def __setup__(cls): super(Location, cls).__setup__() previous_readonly = cls.sequence.states.get('readonly', Bool(False)) cls.sequence.states['readonly'] = previous_readonly | ~Eval('active') cls.sequence.depends = ['active']
class ActivityType(sequence_ordered(), ModelSQL, ModelView): 'Activity Type' __name__ = "activity.type" name = fields.Char('Name', required=True, translate=True) active = fields.Boolean('Active') color = fields.Char('Color') default_duration = fields.TimeDelta('Default Duration') @staticmethod def default_active(): return True
class PlanLines(sequence_ordered(), ModelSQL, ModelView, MatchMixin): 'Commission Plan Line' __name__ = 'commission.plan.line' plan = fields.Many2One('commission.plan', 'Plan', required=True, ondelete='CASCADE') category = fields.Many2One('product.category', "Category", ondelete='CASCADE') product = fields.Many2One('product.product', 'Product', ondelete='CASCADE') formula = fields.Char( 'Formula', required=True, help=('Python expression that will be evaluated with:\n' '- amount: the original amount')) @classmethod def __setup__(cls): super(PlanLines, cls).__setup__() cls._error_messages.update({ 'invalid_formula': ('Invalid formula "%(formula)s" in ' 'commission plan line "%(line)s" with exception ' '"%(exception)s".'), }) @staticmethod def default_formula(): return 'amount' @classmethod def validate(cls, lines): super(PlanLines, cls).validate(lines) for line in lines: line.check_formula() def check_formula(self): context = self.plan.get_context_formula(Decimal(0), None) try: if not isinstance(self.get_amount(**context), Decimal): raise ValueError except ValueError, exception: self.raise_user_error( 'invalid_formula', { 'formula': self.formula, 'line': self.rec_name, 'exception': exception, })
class Icon(sequence_ordered(), ModelSQL, ModelView): 'Icon' __name__ = 'ir.ui.icon' name = fields.Char('Name', required=True, select=True) module = fields.Char('Module', readonly=True, required=True) path = fields.Char('SVG Path', readonly=True, required=True) icon = fields.Function(fields.Char('Icon', depends=['path']), 'get_icon') @classmethod def __setup__(cls): super(Icon, cls).__setup__() cls.__rpc__.update({ 'list_icons': RPC(), }) @classmethod def __register__(cls, module_name): super().__register__(module_name) table = cls.__table_handler__(module_name) # Migration from 5.0: remove required on sequence table.not_null_action('sequence', 'remove') @staticmethod def default_module(): return Transaction().context.get('module') or '' @staticmethod def default_sequence(): return 10 @classmethod def list_icons(cls): icons = {} for icon in cls.browse( cls.search([], order=[('sequence', 'ASC'), ('id', 'ASC')])): if icon.name not in icons: icons[icon.name] = icon.id return sorted((icon_id, name) for name, icon_id in icons.items()) def get_icon(self, name): path = os.path.join(self.module, self.path.replace('/', os.sep)) with file_open( path, subdir='modules' if self.module not in {'ir', 'res'} else '', mode='r', encoding='utf-8') as fp: return fp.read()
class UIMenuFavorite(sequence_ordered(), ModelSQL, ModelView): "Menu Favorite" __name__ = 'ir.ui.menu.favorite' menu = fields.Many2One('ir.ui.menu', 'Menu', required=True, ondelete='CASCADE') user = fields.Many2One('res.user', 'User', required=True, ondelete='CASCADE') @classmethod def __setup__(cls): super(UIMenuFavorite, cls).__setup__() cls.__rpc__.update({ 'get': RPC(), 'set': RPC(readonly=False), 'unset': RPC(readonly=False), }) @staticmethod def default_user(): return Transaction().user @classmethod def get(cls): user = Transaction().user favorites = cls.search([ ('user', '=', user), ]) return [(f.menu.id, f.menu.rec_name, f.menu.icon) for f in favorites] @classmethod def set(cls, menu_id): user = Transaction().user cls.create([{ 'menu': menu_id, 'user': user, }]) @classmethod def unset(cls, menu_id): user = Transaction().user favorites = cls.search([ ('menu', '=', menu_id), ('user', '=', user), ]) cls.delete(favorites)
class Action(sequence_ordered(), ModelSQL, ModelView): "Dashboard Action" __name__ = "dashboard.action" user = fields.Many2One('res.user', 'User', required=True, select=True) act_window = fields.Many2One('ir.action.act_window', 'Action', required=True, ondelete='CASCADE', domain=[ ('res_model', '!=', None), ('res_model', '!=', ''), ('usage', '=', 'dashboard'), # XXX copy ir.action rule to prevent access rule error ['OR', ('groups', 'in', Eval('context', {}).get('groups', [])), ('groups', '=', None), ], ])
class ViewTableFormula(sequence_ordered(), ModelSQL, ModelView): 'Shine View Table Formula' __name__ = 'shine.view.table.formula' view = fields.Many2One('shine.view', 'View', required=True, ondelete='CASCADE') formula = fields.Many2One('shine.formula', 'Formula', domain=[ ('sheet', '=', Eval('_parent_view', {}).get('sheet')), ], required=True, ondelete='CASCADE')
class ModuleConfigWizardItem(sequence_ordered(), ModelSQL, ModelView): "Config wizard to run after activating a module" __name__ = 'ir.module.config_wizard.item' action = fields.Many2One('ir.action', 'Action', required=True, readonly=True) state = fields.Selection([ ('open', 'Open'), ('done', 'Done'), ], string='State', required=True, select=True) @classmethod def __register__(cls, module_name): TableHandler = backend.get('TableHandler') cursor = Transaction().connection.cursor() pool = Pool() ModelData = pool.get('ir.model.data') model_data = ModelData.__table__() # Migration from 3.6: remove double module old_table = 'ir_module_module_config_wizard_item' if TableHandler.table_exist(old_table): TableHandler.table_rename(old_table, cls._table) cursor.execute(*model_data.update( columns=[model_data.model], values=[cls.__name__], where=(model_data.model == 'ir.module.module.config_wizard.item'))) super(ModuleConfigWizardItem, cls).__register__(module_name) table = cls.__table_handler__(module_name) # Migration from 5.0: remove required on sequence table.not_null_action('sequence', 'remove') @staticmethod def default_state(): return 'open' @staticmethod def default_sequence(): return 10
class RoutingStep(sequence_ordered(), ModelSQL, ModelView): 'Route' __name__ = 'production.routing.step' operation = fields.Many2One('production.routing.operation', 'Operation', required=True) routing = fields.Many2One('production.routing', 'Routing', required=True, ondelete='CASCADE') def get_rec_name(self, name): return self.operation.rec_name @classmethod def search_rec_name(cls, name, clause): return [('operation.rec_name', ) + tuple(clause[1:])]
class ProductSupplierPrice(sequence_ordered(), ModelSQL, ModelView, MatchMixin): 'Product Supplier Price' __name__ = 'purchase.product_supplier.price' product_supplier = fields.Many2One('purchase.product_supplier', 'Supplier', required=True, ondelete='CASCADE') quantity = fields.Float('Quantity', required=True, help='Minimal quantity') unit_price = fields.Numeric('Unit Price', required=True, digits=price_digits) @classmethod def __register__(cls, module_name): TableHandler = backend.get('TableHandler') cursor = Transaction().connection.cursor() table = TableHandler(cls, module_name) sql_table = cls.__table__() fill_sequence = not table.column_exist('sequence') super(ProductSupplierPrice, cls).__register__(module_name) # Migration from 3.2: replace quantity by sequence for order if fill_sequence: cursor.execute( *sql_table.update([sql_table.sequence], [sql_table.quantity])) @staticmethod def default_quantity(): return 0.0 @staticmethod def get_pattern(): return {} def match(self, quantity, uom, pattern): pool = Pool() Uom = pool.get('product.uom') test_quantity = Uom.compute_qty(self.product_supplier.uom, self.quantity, uom) if test_quantity > quantity: return False return super(ProductSupplierPrice, self).match(pattern)
class AgentSelection(sequence_ordered(), MatchMixin, ModelSQL, ModelView): "Agent Selection" __name__ = 'commission.agent.selection' agent = fields.Many2One('commission.agent', "Agent", required=True) start_date = fields.Date( "Start Date", domain=[ If( Eval('start_date') & Eval('end_date'), ('start_date', '<=', Eval('end_date')), ()), ], depends=['end_date'], help="The first date that the agent will be considered for selection.") end_date = fields.Date( "End Date", domain=[ If( Eval('start_date') & Eval('end_date'), ('end_date', '>=', Eval('start_date')), ()), ], depends=['start_date'], help="The last date that the agent will be considered for selection.") party = fields.Many2One('party.party', "Party", ondelete='CASCADE', select=True) @classmethod def __setup__(cls): super().__setup__() cls._order.insert(0, ('party', 'ASC NULLS LAST')) def match(self, pattern): pool = Pool() Date = pool.get('ir.date') pattern = pattern.copy() if 'company' in pattern: pattern.pop('company') date = pattern.pop('date', None) or Date.today() if self.start_date and self.start_date > date: return False if self.end_date and self.end_date < date: return False return super().match(pattern)
class ProductLocation(sequence_ordered(), ModelSQL, ModelView, MatchMixin): ''' Product Location It defines the default storage location by warehouse for a product. ''' __name__ = 'stock.product.location' template = fields.Many2One( 'product.template', "Product", required=True, ondelete='CASCADE', select=True, domain=[ If(Bool(Eval('product')), ('products', '=', Eval('product')), ()), ]) product = fields.Many2One( 'product.product', "Variant", ondelete='CASCADE', select=True, domain=[ If(Bool(Eval('template')), ('template', '=', Eval('template')), ()), ]) warehouse = fields.Many2One('stock.location', 'Warehouse', required=True, domain=[('type', '=', 'warehouse')], ondelete='CASCADE') location = fields.Many2One('stock.location', 'Storage Location', required=True, ondelete='CASCADE', domain=[ ('type', '=', 'storage'), ('parent', 'child_of', If(Bool(Eval('warehouse')), [Eval('warehouse')], [])), ]) @classmethod def __register__(cls, module_name): table = cls.__table_handler__(module_name) super().__register__(module_name) # Migration from 5.6: Add template on locations table.not_null_action('product', 'remove') @fields.depends('product', '_parent_product.template') def on_change_product(self): if self.product: self.template = self.product.template
class UserViewField(sequence_ordered(), ModelSQL, ModelView): 'User View Field' __name__ = 'user.view.field' name = fields.Char('Field Name') field = fields.Many2One('ir.model.field', 'Field', domain=[ ('model', '=', Eval('_parent_user_view', {}).get('view_model')), ]) width = fields.Float('Width') height = fields.Float('Height') expression = fields.Char('Expression') user_view = fields.Many2One('user.view', 'User View', ondelete='CASCADE') # to save from original view field_widget = fields.Char('Widget') visual = fields.Char('Visual') # type means field or button and will be written from the view type = fields.Char('Type') description = fields.Char('Description')
class Location(sequence_ordered()): "Stock Location" __metaclass__ = PoolMeta __name__ = 'stock.location' @classmethod def __setup__(cls): super(Location, cls).__setup__() previous_readonly = cls.sequence.states.get('readonly', Bool(False)) cls.sequence.states['readonly'] = previous_readonly | ~Eval('active') cls.sequence.depends = ['active'] @classmethod def __register__(cls, module_name): TableHandler = backend.get('TableHandler') table = TableHandler(cls, module_name) super(Location, cls).__register__(module_name) # Migration from 2.4: drop required on sequence table.not_null_action('sequence', action='remove')
class Product_TariffCode(sequence_ordered(), ModelSQL, ModelView): 'Product - Tariff Code' __name__ = 'product-customs.tariff.code' product = fields.Reference('Product', selection=[ ('product.template', 'Template'), ('product.category', 'Category'), ], required=True, select=True) tariff_code = fields.Many2One('customs.tariff.code', 'Tariff Code', required=True, ondelete='CASCADE') def get_rec_name(self, name): return self.tariff_code.rec_name @classmethod def search_rec_name(cls, name, clause): return [('tariff_code.rec_name', ) + tuple(clause[1:])]