account_invoice
module raises a warning if the user tries to post an invoice and any due date is in the past.
Several customers didn’t want that warning and we created a small module that simply overrides the get_move()
method and calls the super with _skip_warnings=True
This worked flawlessly in 6.0 but in 6.4 came out as the culprit of a strange error which took quite some time to track down.
When the invoice is posted we get the following backtrace:
....
File "/trytond/modules/sale/invoice.py", line 83, in _post
super()._post(invoices)
File "/trytond/modules/purchase/invoice.py", line 22, in wrapper
func(cls, invoices)
File "/trytond/modules/purchase/invoice.py", line 96, in _post
super()._post(invoices)
File "/trytond/modules/account_invoice_stock/account.py", line 26, in _post
super()._post(invoices)
File "/trytond/modules/account_invoice/invoice.py", line 1594, in _post
Move.post([i.move for i in invoices if i.move.state != 'posted'])
File "/trytond/modules/account_invoice/invoice.py", line 1594, in <listcomp>
Move.post([i.move for i in invoices if i.move.state != 'posted'])
AttributeError: 'NoneType' object has no attribute 'state'
In order to understand what piece of code was setting move=None
after being written correctly to the database, I had to add some instrumentation which eventually showed that the value was set to None by the following line of code:
and more precisely with this backtrace:
File "/trytond/trytond/modules/sale/invoice.py", line 83, in _post
super()._post(invoices)
File "/trytond/trytond/modules/purchase/invoice.py", line 22, in wrapper
func(cls, invoices)
File "/trytond/trytond/modules/purchase/invoice.py", line 96, in _post
super()._post(invoices)
File "/trytond/trytond/modules/account_invoice_stock/account.py", line 26, in _post
super()._post(invoices)
File "/trytond/trytond/modules/account_invoice/invoice.py", line 1585, in _post
move = invoice.get_move()
File "/trytond/trytond/modules/account_prevent_due_date_warning/invoice.py", line 10, in get_move
return super().get_move()
File "/trytond/trytond/modules/account_payment_days/invoice.py", line 82, in get_move
return super(Invoice, self).get_move()
File "/trytond/trytond/modules/account_invoice/invoice.py", line 996, in get_move
if self.move:
File "/trytond/trytond/model/fields/field.py", line 365, in __get__
return inst.__getattr__(self.name)
File "/trytond/trytond/model/modelstorage.py", line 1806, in __getattr__
self._cache[id_]._update(
File "/trytond/trytond/model/model.py", line 520, in _update
.... some instrumentation code ...
It looks like the fact that the Move assigned to the field move of invoice, is causing issues if instantiated with different context as the one of the invoice, or at least with skip_warnings=True
. That sounds strange given that it looks like the cache should ignore that key.
All of this looks like a bug to me, it should either work or raise an error when we try to assign a move with a context different from the one of the invoice but I may be missing something.
Thoughts?