Приоритизация вычисляемых полей, которые зависят друг от друга - PullRequest
0 голосов
/ 13 февраля 2019

В моем экземпляре odoo у меня есть несколько вычисляемых полей в аналитическом объекте счета.Эти поля рассчитываются, чтобы гарантировать, что средство просмотра всегда имеет самый последний обзор.

Некоторые из этих полей зависят от других полей, которые сами по себе являются вычисляемыми полями.Сами расчеты довольно просты (поле A = поле B + поле C).Большинство полей также зависят от базовых дочерних идентификаторов.Например, поле A в верхнем объекте является сводкой всех значений поля A дочерних идентификаторов.Поле A для детей рассчитывается для их собственных полей B и C вместе взятых, как описано выше.

Ситуация, в которой я сейчас нахожусь, заключается в том, что по некоторым причинам поля, по-видимому, рассчитываются в случайном порядке.Я заметил это, потому что, когда я обновляюсь в быстрой последовательности, я получаю разные значения для одной и той же записи.

Пример: поля B и C равны 10. Я ожидаю, что A будет 20 (B + C), но в большинстве случаев это фактически 0, потому что вычисление поля для A происходит раньше, чем B и C. Иногда это 10, так какили B или C пробрались, прежде чем А смог закончить.В очень редких случаях это на самом деле 20 ....

Примечание: - Я не могу сделать поля сохраненными, потому что они будут зависеть от строк перемещения счета, которые создаются с невероятной скоростью, и база данных будет абсолютно чокнутой, пересчитывая всезаписи каждую минуту или около того.- Я уже добавил @ api.depends, но это полезно только в том случае, если вы используете сохраненные поля, чтобы определить, какие поля должны вызывать его, что неприменимо в моей ситуации.

Кто-нибудь знает решение этой проблемы?Или есть предложения по альтернативным способам расчета?

[РЕДАКТИРОВАТЬ] Добавлен код

Пример кода:

@api.multi
@api.depends('child_ids','costs_allowed','total_cost')
def _compute_production_result(self):
    for rec in self:
        rec_prod_cost = 0.0
        if rec.usage_type in ['contract','project']:
            for child in rec.child_ids:
                rec_prod_cost += child.production_result
        elif rec.usage_type in ['cost_control','planning']:
            rec_prod_cost = rec.costs_allowed - rec.total_cost
        rec.production_result = rec_prod_cost

Как видите, если у нас есть контракт илиВ рамках проекта нам нужно посмотреть на детей (учетные записи cost_control) на их результаты и ДОБАВИТЬ их вместе.Если мы на самом деле на счету cost_control, то мы можем получить действительные значения, взяв поля B и C и (в этом случае) вычтя их.

Проблема возникает, когда ДРУГИЕ записи контракта обрабатываются до того, как поля cost_control ИЛИ поля cost_allowed и total_cost равны 0,0 при оценке учетных записей cost_control.

Обратите внимание: оба поля cost_allowed и total_cost вычисляются всобственное уважение!

Ответы [ 3 ]

0 голосов
/ 13 февраля 2019

Вы можете сделать, как они сделали в Счет , многие вычисляемые поля зависят от многих других полей, и они устанавливают значение для каждого вычисляемого поля.

@api.one
@api.depends('X', 'Y', ...)
def _compute_amounts(self):
    self.A = ...
    self.B = ...
    self.C = self.A + self.B
0 голосов
/ 13 февраля 2019

Так что мне удалось найти коллегу, и мы выяснили это вместе.Как выясняется, когда вы определяете метод, который вычисляет поле как для своей собственной записи, так и для зависимости этого поля от дочерних записей, вам необходимо явно указать это в зависимостях.

Например:

@api.multi
@api.depends('a', 'b', 'c')
def _compute_a(self):
    for rec in self:
        if condition:
            rec.a = sum(child_ids.a)
        else:
            rec.a = rec.b + rec.c

В этом примере объект self содержит записи (1,2,3,4).Если вы включите зависимость, но в противном случае разрешите коду остаться прежним, например, так:

@api.multi
@api.depends('a', 'b', 'c', 'child_ids.a')
def _compute_a(self):
    for rec in self:
        if condition:
            rec.a = sum(child_ids.a)
        else:
            rec.a = rec.b + rec.c

запустит этот метод 4 раза, начиная с самого низкого / самого глубокого кандидата.Таким образом, в этом случае self будет (4), затем (3) и т. Д.

Слишком плохо, что эта логика, кажется, подразумевается и на самом деле нигде не описана (насколько я мог видеть).

0 голосов
/ 13 февраля 2019

Вы можете найти Python @properties полезным.Вместо того, чтобы просто использовать простые поля, это позволяет вам определить что-то, что выглядит как поле, но лениво оценивается - то есть рассчитывается по требованию, когда вы его «получаете».Таким образом, мы можем гарантировать его актуальность.Пример:

import datetime

class Person(object):

    def __init__(self):
        self._born = datetime.datetime.now()

    @property
    def age(self):
        return  datetime.datetime.now() - self._born


p = Person()

# do some stuff...

# We can 'get' age just like a field, but it is lazy evaluated
# i.e. calculated on demand
# This way we can guarantee it's up to date
print(p.age)

...