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
Пример #2
0
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
Пример #3
0
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
Пример #4
0
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
Пример #5
0
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:])]
Пример #6
0
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'))
Пример #7
0
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
Пример #8
0
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)
Пример #9
0
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')
Пример #10
0
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))
Пример #11
0
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
Пример #12
0
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'])
Пример #13
0
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
Пример #14
0
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)
Пример #15
0
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
Пример #16
0
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']
Пример #17
0
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
Пример #18
0
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,
                })
Пример #19
0
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()
Пример #20
0
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)
Пример #21
0
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),
                ],
            ])
Пример #22
0
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')
Пример #23
0
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
Пример #24
0
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:])]
Пример #25
0
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)
Пример #26
0
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)
Пример #27
0
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
Пример #28
0
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')
Пример #29
0
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')
Пример #30
0
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:])]