Odoo 14,在 stock.quant.write() 上触发一个函数,但只触发一次
Odoo 14, triggering a function upon stock.quant.write(), but only once
我想在写入 stock.quant 时触发一个动作,即当产品的总库存发生变化时。我目前的做法是:
class StockQuantInherit(models.Model):
_inherit = "stock.quant"
def write(self, vals):
res = super(StockQuantInherit, self).write(vals)
available = self.product_id.product_tmpl_id.mapped('virtual_available')[0]
log(available) # see result below
api_call_to_external_site(self.product_id.default_code, available)
return res
当产品库存发生变化时,这会导致 stock.quant 被写入 三 次,如下所示。 (显示为错误,因此我可以轻松地在信息流中发现它)
2021-08-08 12:25:44,278 11335 ERROR odoo odoo.addons.stock_enhanced.models.stock_move: 87.0
2021-08-08 12:25:44,281 11335 ERROR odoo odoo.addons.stock_enhanced.models.stock_move: 87.0
2021-08-08 12:25:44,299 11335 ERROR odoo odoo.addons.stock_enhanced.models.stock_move: 96.0
或者也可能是这样的:
2021-08-08 12:32:43,987 11335 ERROR odoo odoo.addons.stock_enhanced.models.stock_move: 100.0
2021-08-08 12:32:43,990 11335 ERROR odoo odoo.addons.stock_enhanced.models.stock_move: 100.0
2021-08-08 12:32:44,009 11335 ERROR odoo odoo.addons.stock_enhanced.models.stock_move: 100.0
我对前两个值不感兴趣,因为它们可能正确也可能不正确。只有最后一个是有趣的。因此,以效率的名义而不是调用同一个函数,这将在一瞬间调用外部 API 三次,我想仅在最后一次写入事件后触发该函数。
现在我的问题来了,我该怎么做?只触发第一次就够简单了,但我不知道如何只在最后一次触发它。
好的,我设法解决了问题。我要找的是“事件去抖动”。
我试图复制粘贴这个装饰器:https://gist.github.com/walkermatt/2871026
然而,这并没有奏效,因为显然每次都会创建一个新的去抖函数实例(?),导致三个线程都成功等待 1 秒通过。
所以我在我的模块中实现了这个函数,以确保它总是被调用的那个。如果我对装饰器为什么不工作的解释不正确,我深表歉意。
无论如何,这个解决方案现在解决了我的问题:
from threading import Timer
def call_api(sku, quantity_available):
def call_it():
log(quantity_available)
try:
call_api.t.cancel()
except(AttributeError):
pass
call_api.t = Timer(1, call_it)
call_api.t.start()
class StockQuantInherit(models.Model):
_inherit = "stock.quant"
def write(self, vals):
res = super(StockQuantInherit, self).write(vals)
if self.product_id.default_code:
available = self.product_id.product_tmpl_id.mapped('virtual_available')[0]
call_api(self.product_id.default_code, available)
return res
我想在写入 stock.quant 时触发一个动作,即当产品的总库存发生变化时。我目前的做法是:
class StockQuantInherit(models.Model):
_inherit = "stock.quant"
def write(self, vals):
res = super(StockQuantInherit, self).write(vals)
available = self.product_id.product_tmpl_id.mapped('virtual_available')[0]
log(available) # see result below
api_call_to_external_site(self.product_id.default_code, available)
return res
当产品库存发生变化时,这会导致 stock.quant 被写入 三 次,如下所示。 (显示为错误,因此我可以轻松地在信息流中发现它)
2021-08-08 12:25:44,278 11335 ERROR odoo odoo.addons.stock_enhanced.models.stock_move: 87.0
2021-08-08 12:25:44,281 11335 ERROR odoo odoo.addons.stock_enhanced.models.stock_move: 87.0
2021-08-08 12:25:44,299 11335 ERROR odoo odoo.addons.stock_enhanced.models.stock_move: 96.0
或者也可能是这样的:
2021-08-08 12:32:43,987 11335 ERROR odoo odoo.addons.stock_enhanced.models.stock_move: 100.0
2021-08-08 12:32:43,990 11335 ERROR odoo odoo.addons.stock_enhanced.models.stock_move: 100.0
2021-08-08 12:32:44,009 11335 ERROR odoo odoo.addons.stock_enhanced.models.stock_move: 100.0
我对前两个值不感兴趣,因为它们可能正确也可能不正确。只有最后一个是有趣的。因此,以效率的名义而不是调用同一个函数,这将在一瞬间调用外部 API 三次,我想仅在最后一次写入事件后触发该函数。
现在我的问题来了,我该怎么做?只触发第一次就够简单了,但我不知道如何只在最后一次触发它。
好的,我设法解决了问题。我要找的是“事件去抖动”。
我试图复制粘贴这个装饰器:https://gist.github.com/walkermatt/2871026
然而,这并没有奏效,因为显然每次都会创建一个新的去抖函数实例(?),导致三个线程都成功等待 1 秒通过。
所以我在我的模块中实现了这个函数,以确保它总是被调用的那个。如果我对装饰器为什么不工作的解释不正确,我深表歉意。
无论如何,这个解决方案现在解决了我的问题:
from threading import Timer
def call_api(sku, quantity_available):
def call_it():
log(quantity_available)
try:
call_api.t.cancel()
except(AttributeError):
pass
call_api.t = Timer(1, call_it)
call_api.t.start()
class StockQuantInherit(models.Model):
_inherit = "stock.quant"
def write(self, vals):
res = super(StockQuantInherit, self).write(vals)
if self.product_id.default_code:
available = self.product_id.product_tmpl_id.mapped('virtual_available')[0]
call_api(self.product_id.default_code, available)
return res