Esempio n. 1
0
class Origin(origin_mixin(_states, _depends), ModelSQL, ModelView):
    "Account Statement Origin"
    __name__ = 'account.statement.origin'
    _rec_name = 'number'

    lines = fields.One2Many(
        'account.statement.line',
        'origin',
        "Lines",
        states={
            'readonly':
            ((Eval('statement_id', -1) < 0)
             | ~Eval('statement_state').in_(['draft', 'validated'])),
        },
        domain=[
            ('statement', '=', Eval('statement')),
            ('date', '=', Eval('date')),
        ],
        depends=['statement', 'date', 'statement_id'])
    statement_id = fields.Function(fields.Integer("Statement ID"),
                                   'on_change_with_statement_id')
    pending_amount = fields.Function(fields.Numeric(
        "Pending Amount",
        digits=(16, Eval('_parent_statement', {}).get('currency_digits', 2))),
                                     'on_change_with_pending_amount',
                                     searcher='search_pending_amount')
    informations = fields.Dict('account.statement.origin.information',
                               "Informations",
                               readonly=True)

    @fields.depends('statement')
    def on_change_with_statement_id(self, name=None):
        if self.statement:
            return self.statement.id
        return -1

    @fields.depends('lines', 'amount')
    def on_change_with_pending_amount(self, name=None):
        lines_amount = sum(
            getattr(l, 'amount') or Decimal(0) for l in self.lines)
        return (self.amount or Decimal(0)) - lines_amount

    @classmethod
    def search_pending_amount(cls, name, clause):
        pool = Pool()
        Line = pool.get('account.statement.line')
        table = cls.__table__()
        line = Line.__table__()

        _, operator, value = clause
        Operator = fields.SQL_OPERATORS[operator]

        query = (table.join(
            line, 'LEFT', condition=line.origin == table.id).select(
                table.id,
                having=Operator(table.amount - Coalesce(Sum(line.amount), 0),
                                value),
                group_by=table.id))
        return [('id', 'in', query)]
Esempio n. 2
0
class DictDefault(ModelSQL):
    'Dict Default'
    __name__ = 'test.dict_default'
    dico = fields.Dict(None, 'Test Dict')

    @staticmethod
    def default_dico():
        return dict(a=1)
Esempio n. 3
0
class DictUnaccentedOff(ModelSQL):
    "Dict Unaccented Off"
    __name__ = 'test.dict_unaccented_off'
    dico = fields.Dict(None, "Dict")

    @classmethod
    def __setup__(cls):
        super().__setup__()
        cls.dico.search_unaccented = False
Esempio n. 4
0
class TestAccess(ModelSQL):
    'Test Access'
    __name__ = 'test.access'
    field1 = fields.Char('Field 1')
    field2 = fields.Char('Field 2')
    relate = fields.Many2One('test.access.relate', "Relate")
    reference = fields.Reference("Reference", [
        (None, ""),
        ('test.access.relate', "Reference"),
    ])
    dict_ = fields.Dict(None, "Dict")
Esempio n. 5
0
class TakeSampleStart(ModelView):
    'Take Sample Start'
    __name__ = 'lims.take.sample.start'

    date = fields.Date('Date', required=True)
    label = fields.Char('Label', required=True)
    attributes = fields.Dict('lims.sample.attribute', 'Attributes')
    sample = fields.Many2One('lims.sample', 'Sample')

    @staticmethod
    def default_date():
        Date = Pool().get('ir.date')
        return Date.today()
Esempio n. 6
0
class Product:
    __metaclass__ = PoolMeta
    __name__ = 'product.product'
    attributes = fields.Dict(
        'product.attribute',
        'Attributes',
        domain=[
            ('sets', '=', Eval('_parent_template',
                               {}).get('attribute_set',
                                       Eval('attribute_set', -1))),
        ],
        states={
            'readonly': (~Eval('attribute_set')
                         & ~Eval('_parent_template', {}).get('attribute_set')),
        },
        depends=['attribute_set'])
Esempio n. 7
0
class Product(metaclass=PoolMeta):
    __name__ = 'product.product'
    attributes = fields.Dict(
        'product.attribute',
        'Attributes',
        domain=[
            ('sets', '=', Eval('_parent_template',
                               {}).get('attribute_set',
                                       Eval('attribute_set', -1))),
        ],
        states={
            'readonly': (~Eval('attribute_set')
                         & ~Eval('_parent_template', {}).get('attribute_set')),
        },
        depends=['attribute_set'],
        help="Add attributes to the variant.")
Esempio n. 8
0
class ModelViewChangedValues(ModelView):
    'ModelView Changed Values'
    __name__ = 'test.modelview.changed_values'
    name = fields.Char('Name')
    target = fields.Many2One('test.modelview.changed_values.target', 'Target')
    stored_target = fields.Many2One(
        'test.modelview.changed_values.stored_target', "Stored Target")
    ref_target = fields.Reference('Target Reference', [
        ('test.modelview.changed_values.target', 'Target'),
    ])
    targets = fields.One2Many('test.modelview.changed_values.target', 'parent',
                              'Targets')
    m2m_targets = fields.Many2Many('test.modelview.changed_values.target',
                                   None, None, 'Targets')
    multiselection = fields.MultiSelection([
        ('a', 'A'),
        ('b', 'B'),
    ], "MultiSelection")
    dictionary = fields.Dict('test.modelview.changed_values.dictionary',
                             "Dictionary")
Esempio n. 9
0
class Lot(metaclass=PoolMeta):
    __name__ = 'stock.lot'

    attributes = fields.Dict('stock.lot.attribute',
                             'Attributes',
                             domain=[('type', 'in',
                                      Eval('attribute_types_domain'))],
                             depends=['attribute_types_domain'])
    attributes_string = attributes.translated('attributes')
    attribute_types_domain = fields.Function(
        fields.Many2Many('stock.lot.attribute.type', None, None,
                         'Attribute Types domain'),
        'on_change_with_attribute_types_domain')

    @fields.depends('product', '_parent_product.template')
    def on_change_with_attribute_types_domain(self, name=None):
        a_types = []
        if self.product and self.product.template.categories:
            for cat in self.product.template.categories:
                for a_type in cat.lot_attribute_types:
                    a_types.append(a_type.id)
        return a_types
Esempio n. 10
0
class Product(metaclass=PoolMeta):
    __name__ = 'product.product'
    attributes = fields.Dict(
        'product.attribute',
        'Attributes',
        domain=[
            ('sets', '=', Eval('_parent_template',
                               {}).get('attribute_set',
                                       Eval('attribute_set', -1))),
        ],
        states={
            'readonly': (~Eval('attribute_set')
                         & ~Eval('_parent_template', {}).get('attribute_set')),
        },
        depends={'template'},
        help="Add attributes to the variant.")
    attributes_name = fields.Function(
        fields.Char("Attributes Name",
                    states={
                        'invisible': ~Eval('attribute_set'),
                    }), 'on_change_with_attributes_name')

    @fields.depends('attribute_set', 'attributes')
    def on_change_with_attributes_name(self, name=None):
        if not self.attribute_set or not self.attributes:
            return

        def key(attribute):
            return getattr(attribute, 'sequence', attribute.name)

        values = []
        for attribute in sorted(self.attribute_set.attributes, key=key):
            if attribute.name in self.attributes:
                value = self.attributes[attribute.name]
                values.append(
                    gettext('product_attribute.msg_label_value',
                            label=attribute.string,
                            value=attribute.format(value)))
        return " | ".join(filter(None, values))
Esempio n. 11
0
class Product:
    __name__ = 'product.product'
    attributes = fields.Dict(
        'product.attribute',
        'Attributes',
        domain=[
            ('sets', '=', Eval('_parent_template',
                               {}).get('attribute_set',
                                       Eval('attribute_set', -1))),
        ],
        states={
            'readonly': (~Eval('attribute_set')
                         & ~Eval('_parent_template', {}).get('attribute_set')),
        },
        depends=['attribute_set'])
    attribute_set = fields.Function(
        fields.Many2One('product.attribute.set', 'Set'),
        'on_change_with_attribute_set')

    @fields.depends('template')
    def on_change_with_attribute_set(self, name=None):
        if self.template and getattr(self.template, 'attribute_set', None):
            return self.template.attribute_set.id
Esempio n. 12
0
class Queue(ModelSQL):
    "Queue"
    __name__ = 'ir.queue'
    name = fields.Char("Name", required=True)

    data = fields.Dict(None, "Data")

    enqueued_at = fields.Timestamp("Enqueued at", required=True)
    dequeued_at = fields.Timestamp("Dequeued at")
    finished_at = fields.Timestamp("Finished at")

    scheduled_at = fields.Timestamp("Scheduled at",
        help="When the task can start.")
    expected_at = fields.Timestamp("Expected at",
        help="When the task should be done.")

    @classmethod
    def __register__(cls, module_name):
        queue = cls.__table__()
        super().__register__(module_name)
        table_h = cls.__table_handler__(module_name)

        # Add index for candidates
        table_h.index_action([
                queue.scheduled_at.nulls_first,
                queue.expected_at.nulls_first,
                queue.dequeued_at,
                queue.name,
                ], action='add')

    @classmethod
    def default_enqueued_at(cls):
        return datetime.datetime.now()

    @classmethod
    def copy(cls, records, default=None):
        if default is None:
            default = {}
        else:
            default = default.copy()
        default.setdefault('enqueued_at')
        default.setdefault('dequeued_at')
        default.setdefault('finished_at')
        return super(Queue, cls).copy(records, default=default)

    @classmethod
    def push(cls, name, data, scheduled_at=None, expected_at=None):
        transaction = Transaction()
        database = transaction.database
        cursor = transaction.connection.cursor()
        with transaction.set_user(0):
            record, = cls.create([{
                        'name': name,
                        'data': data,
                        'scheduled_at': scheduled_at,
                        'expected_at': expected_at,
                        }])
        if database.has_channel():
            cursor.execute('NOTIFY "%s"', (cls.__name__,))
        if not has_worker:
            transaction.tasks.append(record.id)
        return record.id

    @classmethod
    def pull(cls, database, connection, name=None):
        cursor = connection.cursor()
        queue = cls.__table__()

        candidates = With('id', 'scheduled_at', 'expected_at',
            query=queue.select(
                queue.id,
                queue.scheduled_at,
                queue.expected_at,
                where=((queue.name == name) if name else Literal(True))
                & (queue.dequeued_at == Null),
                order_by=[
                    queue.scheduled_at.nulls_first,
                    queue.expected_at.nulls_first]))
        selected = With('id', query=candidates.select(
                candidates.id,
                where=((candidates.scheduled_at <= CurrentTimestamp())
                    | (candidates.scheduled_at == Null))
                & database.lock_id(candidates.id),
                order_by=[
                    candidates.scheduled_at.nulls_first,
                    candidates.expected_at.nulls_first],
                limit=1))
        next_timeout = With('seconds', query=candidates.select(
                Min(Extract('second',
                        candidates.scheduled_at - CurrentTimestamp())
                    ),
                where=candidates.scheduled_at >= CurrentTimestamp()))

        task_id, seconds = None, None
        if database.has_returning():
            query = queue.update([queue.dequeued_at], [CurrentTimestamp()],
                where=queue.id == selected.select(selected.id),
                with_=[candidates, selected, next_timeout],
                returning=[
                    queue.id, next_timeout.select(next_timeout.seconds)])
            cursor.execute(*query)
            row = cursor.fetchone()
            if row:
                task_id, seconds = row
        else:
            query = queue.select(queue.id,
                where=queue.id == selected.select(selected.id),
                with_=[candidates, selected])
            cursor.execute(*query)
            row = cursor.fetchone()
            if row:
                task_id, = row
                query = queue.update([queue.dequeued_at], [CurrentTimestamp()],
                    where=queue.id == task_id)
                cursor.execute(*query)
            query = next_timeout.select(next_timeout.seconds)
            cursor.execute(*query)
            row = cursor.fetchone()
            if row:
                seconds, = row

        if not task_id and database.has_channel():
            cursor.execute('LISTEN "%s"', (cls.__name__,))
        return task_id, seconds

    def run(self):
        transaction = Transaction()
        Model = Pool().get(self.data['model'])
        with transaction.set_user(self.data['user']), \
                transaction.set_context(self.data['context']):
            instances = self.data['instances']
            # Ensure record ids still exist
            if isinstance(instances, int):
                with transaction.set_context(active_test=False):
                    if Model.search([('id', '=', instances)]):
                        instances = Model(instances)
                    else:
                        instances = None
            else:
                ids = set()
                with transaction.set_context(active_test=False):
                    for sub_ids in grouped_slice(instances):
                        records = Model.search([('id', 'in', list(sub_ids))])
                        ids.update(map(int, records))
                if ids:
                    instances = Model.browse(
                        [i for i in instances if i in ids])
                else:
                    instances = None
            if instances is not None:
                getattr(Model, self.data['method'])(
                    instances, *self.data['args'], **self.data['kwargs'])
        if not self.dequeued_at:
            self.dequeued_at = datetime.datetime.now()
        self.finished_at = datetime.datetime.now()
        self.save()

    @classmethod
    def caller(cls, model):
        return _Model(cls, model)
Esempio n. 13
0
class DictUnaccentedOn(ModelSQL):
    "Dict Unaccented On"
    __name__ = 'test.dict_unaccented_on'
    dico = fields.Dict(None, "Dict")
Esempio n. 14
0
class DictNoSchema(ModelSQL):
    "Dict No Schema"
    __name__ = 'test.dict_noschema'
    dico = fields.Dict(None, "Dict")
Esempio n. 15
0
class DictText(ModelSQL):
    'Dict TEXT'
    __name__ = 'test.dict_text'
    dico = fields.Dict('test.dict.schema', 'Test Dict')
    dico._sql_type = 'TEXT'
Esempio n. 16
0
class ResultsReportVersionDetailSample(metaclass=PoolMeta):
    __name__ = 'lims.results_report.version.detail.sample'

    diagnosis = fields.Text('Diagnosis')
    diagnosis_plain = fields.Function(fields.Text('Diagnosis'),
                                      'get_diagnosis_plain',
                                      setter='set_diagnosis_plain')
    diagnosis_states = fields.Dict('lims.diagnosis.state',
                                   'States',
                                   domain=[('id', 'in',
                                            Eval('diagnosis_states_domain'))],
                                   depends=['diagnosis_states_domain'])
    diagnosis_states_string = diagnosis_states.translated('diagnosis_states')
    diagnosis_states_domain = fields.Function(
        fields.Many2Many('lims.diagnosis.state', None, None, 'States domain'),
        'on_change_with_diagnosis_states_domain')
    diagnosis_warning = fields.Function(fields.Boolean('Diagnosis Warning'),
                                        'get_notebook_field')
    template_type = fields.Function(
        fields.Selection([
            (None, ''),
            ('base', 'HTML'),
            ('header', 'HTML - Header'),
            ('footer', 'HTML - Footer'),
        ], 'Report Template Type'), 'get_template_type')

    @classmethod
    def view_attributes(cls):
        return super().view_attributes() + [
            ('//page[@id="diagnosis"]', 'states', {
                'invisible': Not(Bool(Eval('template_type'))),
            }),
            ('//page[@id="diagnosis_plain"]', 'states', {
                'invisible': Eval('template_type') == 'base',
            }),
        ]

    def get_diagnosis_plain(self, name):
        return self.diagnosis

    @classmethod
    def set_diagnosis_plain(cls, records, name, value):
        cls.write(records, {'diagnosis': value})

    def get_template_type(self, name):
        return (self.version_detail.template
                and self.version_detail.template.type or None)

    @classmethod
    def create(cls, vlist):
        samples = super().create(vlist)
        for sample in samples:
            diagnosis_template = None
            report = sample.version_detail
            if report.diagnosis_template:
                diagnosis_template = report.diagnosis_template
            elif report.template and report.template.diagnosis_template:
                diagnosis_template = report.template.diagnosis_template
            if not diagnosis_template:
                continue
            save = False
            if not sample.diagnosis:
                content = diagnosis_template.content
                sample.diagnosis = content
                save = True
            if not sample.diagnosis_states:
                states = {}
                for state in diagnosis_template.diagnosis_states:
                    states[state.name] = cls.get_default_diagnosis_state(
                        sample, state.name)
                sample.diagnosis_states = states
                save = True
            if save:
                sample.save()
        return samples

    @fields.depends('version_detail',
                    '_parent_version_detail.diagnosis_template')
    def on_change_with_diagnosis_states_domain(self, name=None):
        if (self.version_detail and self.version_detail.diagnosis_template
                and self.version_detail.diagnosis_template.diagnosis_states):
            return [
                s.id for s in
                self.version_detail.diagnosis_template.diagnosis_states
            ]
        return []

    @classmethod
    def _get_fields_from_sample(cls, sample, only_accepted=True):
        sample_default = super()._get_fields_from_sample(sample, only_accepted)
        sample_default['diagnosis'] = sample.diagnosis
        sample_default['diagnosis_states'] = sample.diagnosis_states
        return sample_default

    @classmethod
    def get_default_diagnosis_state(cls, sample, state_name):
        return '*'
Esempio n. 17
0
class ResultsReportVersionDetailSample(metaclass=PoolMeta):
    __name__ = 'lims.results_report.version.detail.sample'

    plant = fields.Function(fields.Many2One('lims.plant', 'Plant'),
                            'get_notebook_field')
    equipment = fields.Function(fields.Many2One('lims.equipment', 'Equipment'),
                                'get_notebook_field')
    equipment_template = fields.Function(
        fields.Many2One('lims.equipment.template', 'Equipment Template'),
        'get_notebook_field')
    equipment_model = fields.Function(fields.Char('Equipment Model'),
                                      'get_notebook_field')
    equipment_serial_number = fields.Function(
        fields.Char('Equipment Serial Number'), 'get_notebook_field')
    equipment_name = fields.Function(fields.Char('Equipment Name'),
                                     'get_notebook_field')
    component = fields.Function(fields.Many2One('lims.component', 'Component'),
                                'get_notebook_field')
    comercial_product = fields.Function(
        fields.Many2One('lims.comercial.product', 'Comercial Product'),
        'get_notebook_field')
    precedent1 = fields.Many2One(
        'lims.notebook',
        'Precedent 1',
        domain=[
            If(~Eval('free_precedents'),
               [('component', '=', Eval('component')),
                ('fraction.sample.state', '!=', 'annulled')],
               [('fraction.sample.state', '!=', 'annulled')])
        ],
        depends=['free_precedents', 'component'])
    precedent2 = fields.Many2One(
        'lims.notebook',
        'Precedent 2',
        domain=[
            If(~Eval('free_precedents'),
               [('component', '=', Eval('component')),
                ('fraction.sample.state', '!=', 'annulled')],
               [('fraction.sample.state', '!=', 'annulled')])
        ],
        depends=['free_precedents', 'component'])
    precedent3 = fields.Many2One(
        'lims.notebook',
        'Precedent 3',
        domain=[
            If(~Eval('free_precedents'),
               [('component', '=', Eval('component')),
                ('fraction.sample.state', '!=', 'annulled')],
               [('fraction.sample.state', '!=', 'annulled')])
        ],
        depends=['free_precedents', 'component'])
    precedent4 = fields.Many2One(
        'lims.notebook',
        'Precedent 4',
        domain=[
            If(~Eval('free_precedents'),
               [('component', '=', Eval('component')),
                ('fraction.sample.state', '!=', 'annulled')],
               [('fraction.sample.state', '!=', 'annulled')])
        ],
        depends=['free_precedents', 'component'])
    precedent5 = fields.Many2One(
        'lims.notebook',
        'Precedent 5',
        domain=[
            If(~Eval('free_precedents'),
               [('component', '=', Eval('component')),
                ('fraction.sample.state', '!=', 'annulled')],
               [('fraction.sample.state', '!=', 'annulled')])
        ],
        depends=['free_precedents', 'component'])
    precedent6 = fields.Many2One(
        'lims.notebook',
        'Precedent 6',
        domain=[
            If(~Eval('free_precedents'),
               [('component', '=', Eval('component')),
                ('fraction.sample.state', '!=', 'annulled')],
               [('fraction.sample.state', '!=', 'annulled')])
        ],
        depends=['free_precedents', 'component'])
    precedent7 = fields.Many2One(
        'lims.notebook',
        'Precedent 7',
        domain=[
            If(~Eval('free_precedents'),
               [('component', '=', Eval('component')),
                ('fraction.sample.state', '!=', 'annulled')],
               [('fraction.sample.state', '!=', 'annulled')])
        ],
        depends=['free_precedents', 'component'])
    precedent8 = fields.Many2One(
        'lims.notebook',
        'Precedent 8',
        domain=[
            If(~Eval('free_precedents'),
               [('component', '=', Eval('component')),
                ('fraction.sample.state', '!=', 'annulled')],
               [('fraction.sample.state', '!=', 'annulled')])
        ],
        depends=['free_precedents', 'component'])
    free_precedents = fields.Boolean('Free precedents')
    precedent1_diagnosis = fields.Function(
        fields.Text('Diagnosis Precedent 1'),
        'on_change_with_precedent1_diagnosis')
    precedent2_diagnosis = fields.Function(
        fields.Text('Diagnosis Precedent 2'),
        'on_change_with_precedent2_diagnosis')
    precedent3_diagnosis = fields.Function(
        fields.Text('Diagnosis Precedent 3'),
        'on_change_with_precedent3_diagnosis')
    precedent1_diagnosis_states = fields.Function(
        fields.Dict('lims.diagnosis.state', 'Diagnosis States Precedent 1'),
        'get_precedent_diagnosis')
    precedent2_diagnosis_states = fields.Function(
        fields.Dict('lims.diagnosis.state', 'Diagnosis States Precedent 2'),
        'get_precedent_diagnosis')
    precedent3_diagnosis_states = fields.Function(
        fields.Dict('lims.diagnosis.state', 'Diagnosis States Precedent 3'),
        'get_precedent_diagnosis')

    @staticmethod
    def default_free_precedents():
        return False

    @classmethod
    def view_attributes(cls):
        missing_diagnosis = True if 'diagnosis' not in cls._fields else False
        return super().view_attributes() + [
            ('//group[@id="diagnosis"]', 'states', {
                'invisible': missing_diagnosis,
            }),
        ]

    @fields.depends('precedent1')
    def on_change_with_precedent1_diagnosis(self, name=None):
        if self.precedent1:
            result = self.get_precedent_diagnosis((self, ),
                                                  ('precedent1_diagnosis', ))
            return result['precedent1_diagnosis'][self.id]
        return None

    @fields.depends('precedent2')
    def on_change_with_precedent2_diagnosis(self, name=None):
        if self.precedent2:
            result = self.get_precedent_diagnosis((self, ),
                                                  ('precedent2_diagnosis', ))
            return result['precedent2_diagnosis'][self.id]
        return None

    @fields.depends('precedent3')
    def on_change_with_precedent3_diagnosis(self, name=None):
        if self.precedent3:
            result = self.get_precedent_diagnosis((self, ),
                                                  ('precedent3_diagnosis', ))
            return result['precedent3_diagnosis'][self.id]
        return None

    @classmethod
    def get_precedent_diagnosis(cls, samples, names):
        result = {}
        missing_diagnosis = True if 'diagnosis' not in cls._fields else False
        if missing_diagnosis:
            for name in names:
                result[name] = {}
                for s in samples:
                    result[name][s.id] = None
        else:
            for name in names:
                result[name] = {}
                if 'precedent1' in name:
                    for s in samples:
                        result[name][s.id] = cls._get_precedent_diagnosis(
                            s.precedent1, name)
                elif 'precedent2' in name:
                    for s in samples:
                        result[name][s.id] = cls._get_precedent_diagnosis(
                            s.precedent2, name)
                else:  # name == 'precedent3_diagnosis':
                    for s in samples:
                        result[name][s.id] = cls._get_precedent_diagnosis(
                            s.precedent3, name)
        return result

    @classmethod
    def _get_precedent_diagnosis(cls, precedent, name):
        if not precedent:
            return None
        precedent_sample = cls.search([
            ('notebook', '=', precedent),
        ])
        if not precedent_sample:
            return None
        return (precedent_sample[0].diagnosis_states
                if 'states' in name else precedent_sample[0].diagnosis)

    @classmethod
    def _get_fields_from_sample(cls, sample, only_accepted=True):
        sample_default = super()._get_fields_from_sample(sample, only_accepted)
        sample_default['precedent1'] = (sample.precedent1 and sample.precedent1
                                        or None)
        sample_default['precedent2'] = (sample.precedent2 and sample.precedent2
                                        or None)
        sample_default['precedent3'] = (sample.precedent3 and sample.precedent3
                                        or None)
        sample_default['precedent4'] = (sample.precedent4 and sample.precedent4
                                        or None)
        sample_default['precedent5'] = (sample.precedent5 and sample.precedent5
                                        or None)
        sample_default['precedent6'] = (sample.precedent6 and sample.precedent6
                                        or None)
        sample_default['precedent7'] = (sample.precedent7 and sample.precedent7
                                        or None)
        sample_default['precedent8'] = (sample.precedent8 and sample.precedent8
                                        or None)
        return sample_default

    @classmethod
    def create(cls, vlist):
        samples = super().create(vlist)
        for sample in samples:
            if not sample.precedent1:
                precedents = cls.get_default_precedents(sample)
                if not precedents:
                    continue
                for i in range(0, min(3, len(precedents))):
                    setattr(sample, 'precedent%s' % str(i + 1), precedents[i])
                sample.save()
                cls.update_precedent_lines(sample)
        return samples

    @classmethod
    def write(cls, *args):
        super().write(*args)
        update_precedent_lines = False
        if not update_precedent_lines:
            return
        actions = iter(args)
        for samples, vals in zip(actions, actions):
            change_precedents = False
            for field in [
                    'precedent1', 'precedent2', 'precedent3', 'precedent4',
                    'precedent5', 'precedent6', 'precedent7', 'precedent8'
            ]:
                if field in vals:
                    change_precedents = True
            if change_precedents:
                for sample in samples:
                    cls.update_precedent_lines(sample)

    @staticmethod
    def get_default_precedents(sample):
        pool = Pool()
        Notebook = pool.get('lims.notebook')
        if not sample.component:
            return []
        precedents = Notebook.search([
            ('id', '!=', sample.notebook.id),
            ('component', '=', sample.component),
            ('fraction.sample.state', '!=', 'annulled'),
            ('invoice_party', '=', sample.notebook.invoice_party),
        ],
                                     order=[
                                         ('fraction.sample.number', 'DESC'),
                                     ],
                                     limit=3)
        return precedents

    @classmethod
    def update_precedent_lines(cls, sample):
        pool = Pool()
        ResultsLine = pool.get('lims.results_report.version.detail.line')
        NotebookLine = pool.get('lims.notebook.line')

        precedent_lines = ResultsLine.search([
            ('detail_sample', '=', sample.id),
            ('notebook_line', '=', None),
        ])
        if precedent_lines:
            ResultsLine.delete(precedent_lines)

        result_lines = ResultsLine.search([
            ('detail_sample', '=', sample.id),
        ])
        analysis = [rl.notebook_line.analysis.id for rl in result_lines]

        lines_to_create = []
        for precedent in [
                sample.precedent1, sample.precedent2, sample.precedent3
        ]:
            if not precedent:
                continue
            precedent_lines = NotebookLine.search([
                ('notebook', '=', precedent),
                ('analysis', 'not in', analysis),
                ('accepted', '=', True),
            ])
            for line in precedent_lines:
                lines_to_create.append({
                    'detail_sample': sample.id,
                    'precedent_analysis': line.analysis.id,
                })
                analysis.append(line.analysis.id)

        if lines_to_create:
            ResultsLine.create(lines_to_create)
Esempio n. 18
0
class DictJSONB(ModelSQL):
    'Dict JSONB'
    __name__ = 'test.dict_jsonb'
    dico = fields.Dict('test.dict.schema', 'Test Dict')
Esempio n. 19
0
class StatementOrigin(metaclass=PoolMeta):
    __name__ = 'account.statement.origin'

    keywords = fields.Dict(None, "Keywords")
Esempio n. 20
0
class Dict(ModelSQL):
    'Dict'
    __name__ = 'test.dict'
    dico = fields.Dict('test.dict.schema', 'Test Dict')
    dico_string = dico.translated('dico')
    dico_string_keys = dico.translated('dico', 'keys')
Esempio n. 21
0
class Origin(origin_mixin(_states), ModelSQL, ModelView):
    "Account Statement Origin"
    __name__ = 'account.statement.origin'
    _rec_name = 'number'

    lines = fields.One2Many(
        'account.statement.line', 'origin', "Lines",
        states={
            'readonly': ((Eval('statement_id', -1) < 0)
                | ~Eval('statement_state').in_(['draft', 'validated'])),
            },
        domain=[
            ('statement', '=', Eval('statement', -1)),
            ('date', '=', Eval('date', None)),
            ])
    statement_id = fields.Function(
        fields.Integer("Statement ID"), 'on_change_with_statement_id')
    pending_amount = fields.Function(Monetary(
            "Pending Amount", currency='currency', digits='currency'),
        'on_change_with_pending_amount', searcher='search_pending_amount')
    information = fields.Dict(
        'account.statement.origin.information', "Information", readonly=True)

    @classmethod
    def __register__(cls, module_name):
        table = cls.__table_handler__(module_name)

        # Migration from 5.0: rename informations into information
        table.column_rename('informations', 'information')

        super(Origin, cls).__register__(module_name)

    @fields.depends('statement', '_parent_statement.id')
    def on_change_with_statement_id(self, name=None):
        if self.statement:
            return self.statement.id
        return -1

    @fields.depends('lines', 'amount')
    def on_change_with_pending_amount(self, name=None):
        lines_amount = sum(
            getattr(l, 'amount') or Decimal(0) for l in self.lines)
        return (self.amount or Decimal(0)) - lines_amount

    @classmethod
    def search_pending_amount(cls, name, clause):
        pool = Pool()
        Line = pool.get('account.statement.line')
        table = cls.__table__()
        line = Line.__table__()

        _, operator, value = clause
        Operator = fields.SQL_OPERATORS[operator]

        query = (table.join(line, 'LEFT', condition=line.origin == table.id)
            .select(table.id,
                having=Operator(
                    table.amount - Coalesce(Sum(line.amount), 0), value),
                group_by=table.id))
        return [('id', 'in', query)]

    @classmethod
    def copy(cls, origins, default=None):
        default = default.copy() if default is not None else {}
        default.setdefault('lines')
        return super().copy(origins, default=default)
Esempio n. 22
0
class DictRequired(ModelSQL):
    'Dict Required'
    __name__ = 'test.dict_required'
    dico = fields.Dict(None, 'Test Dict', required=True)
Esempio n. 23
0
class LandedCost(Workflow, ModelSQL, ModelView, MatchMixin):
    'Landed Cost'
    __name__ = 'account.landed_cost'
    _rec_name = 'number'
    number = fields.Char('Number', select=True, readonly=True)
    company = fields.Many2One('company.company',
                              'Company',
                              required=True,
                              states={
                                  'readonly': Eval('state') != 'draft',
                              },
                              depends=['state'])
    shipments = fields.Many2Many('account.landed_cost-stock.shipment.in',
                                 'landed_cost',
                                 'shipment',
                                 'Shipments',
                                 states={
                                     'readonly': Eval('state') != 'draft',
                                 },
                                 domain=[
                                     ('company', '=', Eval('company')),
                                     ('state', 'in', ['received', 'done']),
                                 ],
                                 depends=['company', 'state'])
    invoice_lines = fields.One2Many('account.invoice.line',
                                    'landed_cost',
                                    'Invoice Lines',
                                    states={
                                        'readonly': Eval('state') != 'draft',
                                    },
                                    add_remove=[
                                        ('landed_cost', '=', None),
                                    ],
                                    domain=[
                                        ('company', '=', Eval('company', -1)),
                                        ('invoice.state', 'in',
                                         ['posted', 'paid']),
                                        ('invoice.type', '=', 'in'),
                                        ('product.landed_cost', '=', True),
                                        ('type', '=', 'line'),
                                    ],
                                    depends=['state', 'company'])
    allocation_method = fields.Selection([
        ('value', 'By Value'),
    ],
                                         'Allocation Method',
                                         required=True,
                                         states={
                                             'readonly':
                                             Eval('state') != 'draft',
                                         },
                                         depends=['state'])

    categories = fields.Many2Many(
        'account.landed_cost-product.category',
        'landed_cost',
        'category',
        "Categories",
        states={
            'readonly': Eval('state') != 'draft',
        },
        depends=['state'],
        help="Apply only to products of these categories.")
    products = fields.Many2Many('account.landed_cost-product.product',
                                'landed_cost',
                                'product',
                                "Products",
                                states={
                                    'readonly': Eval('state') != 'draft',
                                },
                                depends=['state'],
                                help="Apply only to these products.")

    posted_date = fields.Date('Posted Date', readonly=True)
    state = fields.Selection([
        ('draft', 'Draft'),
        ('posted', 'Posted'),
        ('cancelled', 'Cancelled'),
    ],
                             "State",
                             readonly=True,
                             sort=False)

    factors = fields.Dict(None, "Factors", readonly=True)

    @classmethod
    def __setup__(cls):
        super(LandedCost, cls).__setup__()

        cls._order = [
            ('number', 'DESC'),
            ('id', 'DESC'),
        ]
        cls._transitions |= set((
            ('draft', 'posted'),
            ('draft', 'cancelled'),
            ('posted', 'cancelled'),
            ('cancelled', 'draft'),
        ))
        cls._buttons.update({
            'cancel': {
                'invisible': Eval('state') == 'cancelled',
                'depends': ['state'],
            },
            'draft': {
                'invisible': Eval('state') != 'cancelled',
                'depends': ['state'],
            },
            'post': {
                'invisible': Eval('state') != 'draft',
                'depends': ['state'],
            },
        })

    @classmethod
    def __register__(cls, module_name):
        cursor = Transaction().connection.cursor()
        table_h = cls.__table_handler__(module_name)
        sql_table = cls.__table__()

        # Migration from 3.8: rename code into number
        if table_h.column_exist('code'):
            table_h.column_rename('code', 'number')

        super(LandedCost, cls).__register__(module_name)

        # Migration from 5.6: rename state cancel to cancelled
        cursor.execute(*sql_table.update([sql_table.state], ['cancelled'],
                                         where=sql_table.state == 'cancel'))

    @staticmethod
    def default_company():
        return Transaction().context.get('company')

    @staticmethod
    def default_allocation_method():
        return 'value'

    @staticmethod
    def default_state():
        return 'draft'

    @classmethod
    @ModelView.button
    @Workflow.transition('cancelled')
    def cancel(cls, landed_costs):
        for landed_cost in landed_costs:
            if landed_cost.state == 'posted':
                getattr(
                    landed_cost,
                    'unallocate_cost_by_%s' % landed_cost.allocation_method)()
        cls.write(landed_costs, {
            'posted_date': None,
            'factors': None,
            'state': 'cancelled',
        })

    @classmethod
    @ModelView.button
    @Workflow.transition('draft')
    def draft(cls, landed_costs):
        pass

    @property
    def cost(self):
        pool = Pool()
        Currency = pool.get('currency.currency')

        currency = self.company.currency
        cost = Decimal(0)

        for line in self.invoice_lines:
            with Transaction().set_context(date=line.invoice.currency_date):
                cost += Currency.compute(line.invoice.currency,
                                         line.amount,
                                         currency,
                                         round=False)
        return cost

    def stock_moves(self):
        moves = []
        for shipment in self.shipments:
            for move in shipment.incoming_moves:
                if move.state == 'cancelled':
                    continue
                if self._stock_move_filter(move):
                    moves.append(move)
        return moves

    def _stock_move_filter(self, move):
        if not self.categories and not self.products:
            return True
        result = False
        if self.categories:
            result |= bool(
                set(self.categories)
                & set(_parents(move.product.categories_all)))
        if self.products:
            result |= bool(move.product in self.products)
        return result

    def _stock_move_filter_unused(self, moves):
        pool = Pool()
        Warning = pool.get('res.user.warning')

        categories = {
            c
            for m in moves for c in _parents(m.product.categories_all)
        }
        for category in self.categories:
            if category not in categories:
                key = '%s - %s' % (self, category)
                if Warning.check(key):
                    raise FilterUnusedWarning(
                        key,
                        gettext(
                            'account_stock_landed_cost'
                            '.msg_landed_cost_unused_category',
                            landed_cost=self.rec_name,
                            category=category.rec_name))

        products = {m.product for m in moves}
        for product in self.products:
            if product not in products:
                key = '%s - %s' % (self, product)
                if Warning.check(key):
                    raise FilterUnusedWarning(
                        key,
                        gettext(
                            'account_stock_landed_cost'
                            '.msg_landed_cost_unused_product',
                            landed_cost=self.rec_name,
                            product=product.rec_name))

    def allocate_cost_by_value(self):
        self.factors = self._get_value_factors()
        self._allocate_cost(self.factors)

    def unallocate_cost_by_value(self):
        factors = self.factors or self._get_value_factors()
        self._allocate_cost(factors, sign=-1)

    def _get_value_factors(self):
        "Return the factor for each move based on value"
        pool = Pool()
        Currency = pool.get('currency.currency')

        currency = self.company.currency
        moves = self.stock_moves()

        sum_value = 0
        unit_prices = {}
        for move in moves:
            with Transaction().set_context(date=move.effective_date):
                unit_price = Currency.compute(move.currency,
                                              move.unit_price,
                                              currency,
                                              round=False)
            unit_prices[move.id] = unit_price
            sum_value += unit_price * Decimal(str(move.quantity))

        factors = {}
        length = Decimal(len(moves))
        for move in moves:
            quantity = Decimal(str(move.quantity))
            if not sum_value:
                factors[str(move.id)] = 1 / length
            else:
                factors[str(move.id)] = (quantity * unit_prices[move.id] /
                                         sum_value)
        return factors

    def _allocate_cost(self, factors, sign=1):
        "Allocate cost on moves using factors"
        pool = Pool()
        Move = pool.get('stock.move')
        Currency = pool.get('currency.currency')
        assert sign in {1, -1}

        cost = self.cost
        currency = self.company.currency
        moves = [m for m in self.stock_moves() if m.quantity]

        costs = []
        digit = Move.unit_price.digits[1]
        exp = Decimal(str(10.0**-digit))
        difference = cost
        for move in moves:
            quantity = Decimal(str(move.quantity))
            move_cost = cost * factors[str(move.id)]
            unit_landed_cost = round_price(move_cost / quantity,
                                           rounding=ROUND_DOWN)
            costs.append({
                'unit_landed_cost':
                unit_landed_cost,
                'difference':
                move_cost - (unit_landed_cost * quantity),
                'move':
                move,
            })
            difference -= unit_landed_cost * quantity
        costs.sort(key=itemgetter('difference'), reverse=True)
        for cost in costs:
            move = cost['move']
            quantity = Decimal(str(move.quantity))
            if exp * quantity <= difference:
                cost['unit_landed_cost'] += exp
                difference -= exp * quantity
            if difference < exp:
                break

        for cost in costs:
            move = cost['move']
            with Transaction().set_context(date=move.effective_date):
                unit_landed_cost = Currency.compute(currency,
                                                    cost['unit_landed_cost'],
                                                    move.currency,
                                                    round=False)
            unit_landed_cost = round_price(unit_landed_cost,
                                           rounding=ROUND_HALF_EVEN)
            if move.unit_landed_cost is None:
                move.unit_landed_cost = 0
            move.unit_price += unit_landed_cost * sign
            move.unit_landed_cost += unit_landed_cost * sign
        Move.save(moves)

    @classmethod
    @ModelView.button
    @Workflow.transition('posted')
    def post(cls, landed_costs):
        pool = Pool()
        Date = pool.get('ir.date')
        Warning = pool.get('res.user.warning')
        today = Date.today()

        for landed_cost in landed_costs:
            stock_moves = landed_cost.stock_moves()
            if not stock_moves:
                key = '%s post no move' % landed_cost
                if Warning.check(key):
                    raise NoMoveWarning(
                        key,
                        gettext(
                            'account_stock_landed_cost'
                            '.msg_landed_cost_post_no_stock_move',
                            landed_cost=landed_cost.rec_name))
            landed_cost._stock_move_filter_unused(stock_moves)
            getattr(landed_cost,
                    'allocate_cost_by_%s' % landed_cost.allocation_method)()
        for company, c_landed_costs in groupby(landed_costs,
                                               key=lambda l: l.company):
            with Transaction().set_context(company=company.id):
                today = Date.today()
            for landed_cost in c_landed_costs:
                landed_cost.posted_date = today
            landed_cost.posted_date = today
        # Use save as allocate methods may modify the records
        cls.save(landed_costs)

    @classmethod
    def create(cls, vlist):
        pool = Pool()
        Config = pool.get('account.configuration')

        vlist = [v.copy() for v in vlist]
        config = Config(1)
        default_company = cls.default_company()
        for values in vlist:
            if values.get('number') is None:
                values['number'] = config.get_multivalue(
                    'landed_cost_sequence',
                    company=values.get('company', default_company)).get()
        return super(LandedCost, cls).create(vlist)