diff --git a/babi_multiprocess.diff b/babi_multiprocess.diff
new file mode 100644
index 0000000..30bc38c
--- /dev/null
+++ b/babi_multiprocess.diff
@@ -0,0 +1,25 @@
+ diff -r cc988ec8da34 trytond/trytond/protocols/dispatcher.py
+ --- a/trytond/trytond/protocols/dispatcher.py Mon Apr 23 17:12:37 2018 +0200
+ +++ b/trytond/trytond/protocols/dispatcher.py Fri May 11 12:53:17 2018 +0200
+ @@ -122,8 +122,19 @@
+ type, _ = method.split('.', 1)
+ name = '.'.join(method.split('.')[1:-1])
+ method = method.split('.')[-1]
+ - return pool.get(name, type=type), method
+ -
+ + try:
+ + obj = pool.get(name, type=type)
+ + except KeyError:
+ + if name[:15] == 'babi_execution_':
+ + with Transaction().start(pool.database_name, request.user_id,
+ + readonly=False):
+ + Execution = pool.get('babi.report.execution')
+ + execution = Execution(int(name[15:]))
+ + execution.validate_model()
+ + obj = pool.get(name, type=type)
+ + else:
+ + raise
+ + return obj, method
+
+ @app.auth_required
+ @with_pool
diff --git a/domain_validation_warning.diff b/domain_validation_warning.diff
new file mode 100644
index 0000000..0166fd9
--- /dev/null
+++ b/domain_validation_warning.diff
@@ -0,0 +1,414 @@
+Index: b/trytond/trytond/model/modelstorage.py
+===================================================================
+--- a/trytond/trytond/model/modelstorage.py
++++ b/trytond/trytond/model/modelstorage.py
+@@ -5,6 +5,7 @@ import datetime
+ import time
+ import csv
+ import warnings
++import logging
+
+ from decimal import Decimal
+ from itertools import islice, ifilter, chain, izip
+@@ -27,6 +28,7 @@ from .modelview import ModelView
+ from .descriptors import dualmethod
+
+ __all__ = ['ModelStorage', 'EvalEnvironment']
++logger = logging.getLogger(__name__)
+
+
+ def without_check_access(func):
+@@ -1009,8 +1011,27 @@ class ModelStorage(Model):
+ domain,
+ ])
+ if sub_relations != set(finds):
++ fail_field_value = sub_relations.difference(
++ set(finds)).pop()
++ error_args = cls._get_error_args(field.name)
++ error_args.update({
++ 'value': fail_field_value.rec_name if
++ isinstance(fail_field_value, Model)
++ else fail_field_value,
++ 'domain': getattr(cls, field_name).domain
++ })
++ msg = cls.raise_user_error('domain_validation_record',
++ error_args=error_args, raise_exception=False)
++ msg += ' Records: ' + ', '.join(
++ [str(r.id) for r in records])
++ msg += ' Domain: %s' % (domain,)
++ msg += ' Relations: ' + ', '.join(
++ [str(r.id) for r in list(sub_relations)])
++ msg += ' Finds: ' + ', '.join(
++ [str(r.id) for r in finds])
++ logger.warn(msg)
+ cls.raise_user_error('domain_validation_record',
+- error_args=cls._get_error_args(field.name))
++ error_args=error_args)
+
+ field_names = set(field_names or [])
+ function_fields = {name for name, field in cls._fields.iteritems()
+Index: b/trytond/trytond/ir/translation.xml
+===================================================================
+--- a/trytond/trytond/ir/translation.xml
++++ b/trytond/trytond/ir/translation.xml
+@@ -129,8 +129,8 @@ this repository contains the full copyri
+ domain_validation_record
+ en
+ error
+- The value of the field "%(field)s" on "%(model)s" is not valid according to its domain.
+- The value of the field "%(field)s" on "%(model)s" is not valid according to its domain.
++ The value "%(value)s" of the field "%(field)s" on "%(model)s" is not valid according to its domain "%(domain)s".
++ The value "%(value)s" of the field "%(field)s" on "%(model)s" is not valid according to its domain "%(domain)s".
+ ir
+
+
+Index: b/trytond/trytond/ir/locale/bg.po
+===================================================================
+--- a/trytond/trytond/ir/locale/bg.po
++++ b/trytond/trytond/ir/locale/bg.po
+@@ -26,11 +26,11 @@ msgstr ""
+
+ msgctxt "error:domain_validation_record:"
+ msgid ""
+-"The value of the field \"%(field)s\" on \"%(model)s\" is not valid according"
+-" to its domain."
++"The value \"%(value)s\" of the field \"%(field)s\" on \"%(model)s\" is not "
++"valid according to its domain \"%(domain)s\"."
+ msgstr ""
+-"The value of the field \"%(field)s\" on \"%(model)s\" is not valid according"
+-" to its domain."
++"The value \"%(value)s\" of the field \"%(field)s\" on \"%(model)s\" is not "
++"valid according to its domain \"%(domain)s\"."
+
+ msgctxt "error:foreign_model_exist:"
+ msgid ""
+Index: b/trytond/trytond/ir/locale/ca.po
+===================================================================
+--- a/trytond/trytond/ir/locale/ca.po
++++ b/trytond/trytond/ir/locale/ca.po
+@@ -24,11 +24,11 @@ msgstr ""
+
+ msgctxt "error:domain_validation_record:"
+ msgid ""
+-"The value of the field \"%(field)s\" on \"%(model)s\" is not valid according"
+-" to its domain."
++"The value \"%(value)s\" of the field \"%(field)s\" on \"%(model)s\" is not "
++"valid according to its domain \"%(domain)s\"."
+ msgstr ""
+-"El valor del camp \"%(field)s\" de \"%(model)s\" no és correcte segons "
+-"aquest domini."
++"El valor \"%(field)s\" del camp \"%(field)s\" de \"%(model)s\" no és correcte segons "
++"aquest domini \"%(domain)s\"."
+
+ msgctxt "error:foreign_model_exist:"
+ msgid ""
+Index: b/trytond/trytond/ir/locale/cs.po
+===================================================================
+--- a/trytond/trytond/ir/locale/cs.po
++++ b/trytond/trytond/ir/locale/cs.po
+@@ -24,11 +24,11 @@ msgstr ""
+
+ msgctxt "error:domain_validation_record:"
+ msgid ""
+-"The value of the field \"%(field)s\" on \"%(model)s\" is not valid according"
+-" to its domain."
++"The value \"%(value)s\" of the field \"%(field)s\" on \"%(model)s\" is not "
++"valid according to its domain \"%(domain)s\"."
+ msgstr ""
+-"The value of the field \"%(field)s\" on \"%(model)s\" is not valid according"
+-" to its domain."
++"The value \"%(value)s\" of the field \"%(field)s\" on \"%(model)s\" is not "
++"valid according to its domain \"%(domain)s\"."
+
+ msgctxt "error:foreign_model_exist:"
+ msgid ""
+Index: b/trytond/trytond/ir/locale/de.po
+===================================================================
+--- a/trytond/trytond/ir/locale/de.po
++++ b/trytond/trytond/ir/locale/de.po
+@@ -23,11 +23,11 @@ msgstr ""
+
+ msgctxt "error:domain_validation_record:"
+ msgid ""
+-"The value of the field \"%(field)s\" on \"%(model)s\" is not valid according"
+-" to its domain."
++"The value \"%(value)s\" of the field \"%(field)s\" on \"%(model)s\" is not "
++"valid according to its domain \"%(domain)s\"."
+ msgstr ""
+-"Der Wert des Feldes \"%(field)s\" in \"%(model)s\" liegt nicht im gültigen "
+-"Wertebereich (Domain)."
++"Der Wert \"%(value)s\" des Feldes \"%(field)s\" in \"%(model)s\" liegt nicht im gültigen "
++"Wertebereich (Domain) \"%(domain)s\"."
+
+ msgctxt "error:foreign_model_exist:"
+ msgid ""
+Index: b/trytond/trytond/ir/locale/es.po
+===================================================================
+--- a/trytond/trytond/ir/locale/es.po
++++ b/trytond/trytond/ir/locale/es.po
+@@ -22,11 +22,11 @@ msgstr ""
+
+ msgctxt "error:domain_validation_record:"
+ msgid ""
+-"The value of the field \"%(field)s\" on \"%(model)s\" is not valid according"
+-" to its domain."
++"The value \"%(value)s\" of the field \"%(field)s\" on \"%(model)s\" is not "
++"valid according to its domain \"%(domain)s\"."
+ msgstr ""
+-"El valor del campo \"%(field)s\" de \"%(model)s\" no es correcto según su "
+-"dominio."
++"El valor \"%(value)s\" del campo \"%(field)s\" de \"%(model)s\" no es correcto según su "
++"dominio \"%(domain)s\"."
+
+ msgctxt "error:foreign_model_exist:"
+ msgid ""
+Index: b/trytond/trytond/ir/locale/es_419.po
+===================================================================
+--- a/trytond/trytond/ir/locale/es_419.po
++++ b/trytond/trytond/ir/locale/es_419.po
+@@ -20,8 +20,8 @@ msgstr ""
+
+ msgctxt "error:domain_validation_record:"
+ msgid ""
+-"The value of the field \"%(field)s\" on \"%(model)s\" is not valid according"
+-" to its domain."
++"The value \"%(value)s\" of the field \"%(field)s\" on \"%(model)s\" is not "
++"valid according to its domain \"%(domain)s\"."
+ msgstr ""
+
+ msgctxt "error:foreign_model_exist:"
+Index: b/trytond/trytond/ir/locale/fa.po
+===================================================================
+--- a/trytond/trytond/ir/locale/fa.po
++++ b/trytond/trytond/ir/locale/fa.po
+@@ -24,8 +24,8 @@ msgstr ""
+
+ msgctxt "error:domain_validation_record:"
+ msgid ""
+-"The value of the field \"%(field)s\" on \"%(model)s\" is not valid according"
+-" to its domain."
++"The value \"%(value)s\" of the field \"%(field)s\" on \"%(model)s\" is not "
++"valid according to its domain \"%(domain)s\"."
+ msgstr "مقدار فیلد: \"%s\" در مدل: \"%s\" باتوجه به دامنه آن معتبر نیست."
+
+ msgctxt "error:foreign_model_exist:"
+Index: b/trytond/trytond/ir/locale/fr.po
+===================================================================
+--- a/trytond/trytond/ir/locale/fr.po
++++ b/trytond/trytond/ir/locale/fr.po
+@@ -24,11 +24,11 @@ msgstr ""
+
+ msgctxt "error:domain_validation_record:"
+ msgid ""
+-"The value of the field \"%(field)s\" on \"%(model)s\" is not valid according"
+-" to its domain."
++"The value \"%(value)s\" of the field \"%(field)s\" on \"%(model)s\" is not "
++"valid according to its domain \"%(domain)s\"."
+ msgstr ""
+-"La valeur du champ « %(field)s » sur « %(model)s » n'est pas valide selon "
+-"son domaine."
++"La valeur \"%(value)s\" du champ « %(field)s » sur « %(model)s » n'est pas valide selon "
++"son domaine \"%(domain)s\"."
+
+ msgctxt "error:foreign_model_exist:"
+ msgid ""
+Index: b/trytond/trytond/ir/locale/hu_HU.po
+===================================================================
+--- a/trytond/trytond/ir/locale/hu_HU.po
++++ b/trytond/trytond/ir/locale/hu_HU.po
+@@ -27,11 +27,11 @@ msgstr ""
+ #, fuzzy
+ msgctxt "error:domain_validation_record:"
+ msgid ""
+-"The value of the field \"%(field)s\" on \"%(model)s\" is not valid according"
+-" to its domain."
++"The value \"%(value)s\" of the field \"%(field)s\" on \"%(model)s\" is not "
++"valid according to its domain \"%(domain)s\"."
+ msgstr ""
+-"The value of the field \"%(field)s\" on \"%(model)s\" is not valid according"
+-" to its domain."
++"The value \"%(value)s\" of the field \"%(field)s\" on \"%(model)s\" is not "
++"valid according to its domain \"%(domain)s\"."
+
+ #, fuzzy
+ msgctxt "error:foreign_model_exist:"
+Index: b/trytond/trytond/ir/locale/it_IT.po
+===================================================================
+--- a/trytond/trytond/ir/locale/it_IT.po
++++ b/trytond/trytond/ir/locale/it_IT.po
+@@ -27,11 +27,11 @@ msgstr ""
+ #, fuzzy
+ msgctxt "error:domain_validation_record:"
+ msgid ""
+-"The value of the field \"%(field)s\" on \"%(model)s\" is not valid according"
+-" to its domain."
++"The value \"%(value)s\" of the field \"%(field)s\" on \"%(model)s\" is not "
++"valid according to its domain \"%(domain)s\"."
+ msgstr ""
+-"The value of the field \"%(field)s\" on \"%(model)s\" is not valid according"
+-" to its domain."
++"The value \"%(value)s\" of the field \"%(field)s\" on \"%(model)s\" is not "
++"valid according to its domain \"%(domain)s\"."
+
+ #, fuzzy
+ msgctxt "error:foreign_model_exist:"
+Index: b/trytond/trytond/ir/locale/ja_JP.po
+===================================================================
+--- a/trytond/trytond/ir/locale/ja_JP.po
++++ b/trytond/trytond/ir/locale/ja_JP.po
+@@ -24,11 +24,11 @@ msgstr ""
+
+ msgctxt "error:domain_validation_record:"
+ msgid ""
+-"The value of the field \"%(field)s\" on \"%(model)s\" is not valid according"
+-" to its domain."
++"The value \"%(value)s\" of the field \"%(field)s\" on \"%(model)s\" is not "
++"valid according to its domain \"%(domain)s\"."
+ msgstr ""
+-"The value of the field \"%(field)s\" on \"%(model)s\" is not valid according"
+-" to its domain."
++"The value \"%(value)s\" of the field \"%(field)s\" on \"%(model)s\" is not "
++"valid according to its domain \"%(domain)s\"."
+
+ msgctxt "error:foreign_model_exist:"
+ msgid ""
+Index: b/trytond/trytond/ir/locale/lo.po
+===================================================================
+--- a/trytond/trytond/ir/locale/lo.po
++++ b/trytond/trytond/ir/locale/lo.po
+@@ -24,11 +24,11 @@ msgstr ""
+
+ msgctxt "error:domain_validation_record:"
+ msgid ""
+-"The value of the field \"%(field)s\" on \"%(model)s\" is not valid according"
+-" to its domain."
++"The value \"%(value)s\" of the field \"%(field)s\" on \"%(model)s\" is not "
++"valid according to its domain \"%(domain)s\"."
+ msgstr ""
+-"The value of the field \"%(field)s\" on \"%(model)s\" is not valid according"
+-" to its domain."
++"The value \"%(value)s\" of the field \"%(field)s\" on \"%(model)s\" is not "
++"valid according to its domain \"%(domain)s\"."
+
+ msgctxt "error:foreign_model_exist:"
+ msgid ""
+Index: b/trytond/trytond/ir/locale/nl.po
+===================================================================
+--- a/trytond/trytond/ir/locale/nl.po
++++ b/trytond/trytond/ir/locale/nl.po
+@@ -26,11 +26,11 @@ msgstr ""
+
+ msgctxt "error:domain_validation_record:"
+ msgid ""
+-"The value of the field \"%(field)s\" on \"%(model)s\" is not valid according"
+-" to its domain."
++"The value \"%(value)s\" of the field \"%(field)s\" on \"%(model)s\" is not "
++"valid according to its domain \"%(domain)s\"."
+ msgstr ""
+-"The value of the field \"%(field)s\" on \"%(model)s\" is not valid according"
+-" to its domain."
++"The value \"%(value)s\" of the field \"%(field)s\" on \"%(model)s\" is not "
++"valid according to its domain \"%(domain)s\"."
+
+ msgctxt "error:foreign_model_exist:"
+ msgid ""
+Index: b/trytond/trytond/ir/locale/pl.po
+===================================================================
+--- a/trytond/trytond/ir/locale/pl.po
++++ b/trytond/trytond/ir/locale/pl.po
+@@ -24,11 +24,11 @@ msgstr ""
+
+ msgctxt "error:domain_validation_record:"
+ msgid ""
+-"The value of the field \"%(field)s\" on \"%(model)s\" is not valid according"
+-" to its domain."
++"The value \"%(value)s\" of the field \"%(field)s\" on \"%(model)s\" is not "
++"valid according to its domain \"%(domain)s\"."
+ msgstr ""
+-"Wartość w polu \"%(field)s\" dla \"%(model)s\" jest nieprawidłowa względem "
+-"swojej domeny."
++"Wartość \"%(value)s\" w polu \"%(field)s\" dla \"%(model)s\" jest "
++"nieprawidłowa względem swojej domeny\"%(domain)s\"."
+
+ msgctxt "error:foreign_model_exist:"
+ msgid ""
+Index: b/trytond/trytond/ir/locale/pt_BR.po
+===================================================================
+--- a/trytond/trytond/ir/locale/pt_BR.po
++++ b/trytond/trytond/ir/locale/pt_BR.po
+@@ -27,11 +27,11 @@ msgstr ""
+ #, fuzzy
+ msgctxt "error:domain_validation_record:"
+ msgid ""
+-"The value of the field \"%(field)s\" on \"%(model)s\" is not valid according"
+-" to its domain."
++"The value \"%(value)s\" of the field \"%(field)s\" on \"%(model)s\" is not "
++"valid according to its domain \"%(domain)s\"."
+ msgstr ""
+-"The value of the field \"%(field)s\" on \"%(model)s\" is not valid according"
+-" to its domain."
++"The value \"%(value)s\" of the field \"%(field)s\" on \"%(model)s\" is not "
++"valid according to its domain \"%(domain)s\"."
+
+ #, fuzzy
+ msgctxt "error:foreign_model_exist:"
+Index: b/trytond/trytond/ir/locale/ru.po
+===================================================================
+--- a/trytond/trytond/ir/locale/ru.po
++++ b/trytond/trytond/ir/locale/ru.po
+@@ -26,11 +26,11 @@ msgstr ""
+
+ msgctxt "error:domain_validation_record:"
+ msgid ""
+-"The value of the field \"%(field)s\" on \"%(model)s\" is not valid according"
+-" to its domain."
++"The value \"%(value)s\" of the field \"%(field)s\" on \"%(model)s\" is not "
++"valid according to its domain \"%(domain)s\"."
+ msgstr ""
+-"The value of the field \"%(field)s\" on \"%(model)s\" is not valid according"
+-" to its domain."
++"The value \"%(value)s\" of the field \"%(field)s\" on \"%(model)s\" is not "
++"valid according to its domain \"%(domain)s\".""
+
+ msgctxt "error:foreign_model_exist:"
+ msgid ""
+Index: b/trytond/trytond/ir/locale/sl.po
+===================================================================
+--- a/trytond/trytond/ir/locale/sl.po
++++ b/trytond/trytond/ir/locale/sl.po
+@@ -27,11 +27,11 @@ msgstr ""
+ #, fuzzy
+ msgctxt "error:domain_validation_record:"
+ msgid ""
+-"The value of the field \"%(field)s\" on \"%(model)s\" is not valid according"
+-" to its domain."
++"The value \"%(value)s\" of the field \"%(field)s\" on \"%(model)s\" is not "
++"valid according to its domain \"%(domain)s\"."
+ msgstr ""
+-"The value of the field \"%(field)s\" on \"%(model)s\" is not valid according"
+-" to its domain."
++"The value \"%(value)s\" of the field \"%(field)s\" on \"%(model)s\" is not "
++"valid according to its domain \"%(domain)s\"."
+
+ #, fuzzy
+ msgctxt "error:foreign_model_exist:"
+Index: b/trytond/trytond/ir/locale/zh_CN.po
+===================================================================
+--- a/trytond/trytond/ir/locale/zh_CN.po
++++ b/trytond/trytond/ir/locale/zh_CN.po
+@@ -27,11 +27,11 @@ msgstr ""
+ #, fuzzy
+ msgctxt "error:domain_validation_record:"
+ msgid ""
+-"The value of the field \"%(field)s\" on \"%(model)s\" is not valid according"
+-" to its domain."
++"The value \"%(value)s\" of the field \"%(field)s\" on \"%(model)s\" is not "
++"valid according to its domain \"%(domain)s\"."
+ msgstr ""
+-"The value of the field \"%(field)s\" on \"%(model)s\" is not valid according"
+-" to its domain."
++"The value \"%(value)s\" of the field \"%(field)s\" on \"%(model)s\" is not "
++"valid according to its domain \"%(domain)s\"."
+
+ #, fuzzy
+ msgctxt "error:foreign_model_exist:"
diff --git a/improve_performance_on_try_assign.diff b/improve_performance_on_try_assign.diff
new file mode 100644
index 0000000..d2245fe
--- /dev/null
+++ b/improve_performance_on_try_assign.diff
@@ -0,0 +1,43 @@
+diff -r 3239605d105d move.py
+--- a/trytond/trytond/modules/stock/move.py Mon May 21 20:17:34 2018 +0200
++++ b/trytond/trytond/modules/stock/move.py Fri Jul 20 12:16:25 2018 +0200
+@@ -850,6 +850,7 @@
+ ])
+ else:
+ locations = list(set((m.from_location for m in moves)))
++
+ location_ids = [l.id for l in locations]
+ product_ids = list(set((m.product.id for m in moves)))
+ stock_date_end = Date.today()
+@@ -1446,12 +1447,27 @@
+ if location not in location_ids:
+ del quantities[key]
+
+- # Round quantities
+- default_uom = dict((p.id, p.default_uom) for p in
+- Model.browse(list(ids)))
++ Uom = Pool().get('product.uom')
++ ttemplate = Template.__table__()
++ table = Model.__table__()
++ cursor = Transaction().connection.cursor()
++
++ if Model == Template:
++ cursor.execute(*ttemplate.select(ttemplate.id,
++ ttemplate.default_uom,
++ where=reduce_ids(ttemplate.id, ids)))
++ else:
++ cursor.execute(*ttemplate.join(table,
++ condition=table.template == ttemplate.id).select(
++ table.id, ttemplate.default_uom,
++ where=reduce_ids(table.id, ids)))
++
++ default_uom = dict((x[0], x[1]) for x in
++ cursor.fetchall())
++
+ for key, quantity in quantities.iteritems():
+ location = key[0]
+- uom = default_uom[id_getter(key)]
++ uom = Uom(default_uom[id_getter(key)])
+ quantities[key] = uom.round(quantity)
+
+ return quantities
diff --git a/issue10467.diff b/issue10467.diff
new file mode 100644
index 0000000..249aa91
--- /dev/null
+++ b/issue10467.diff
@@ -0,0 +1,24 @@
+diff -r 8a6a82c717d6 stock.py
+--- a/trytond/trytond/modules/stock_lot/stock.py Tue Jul 10 12:57:12 2018 +0200
++++ b/trytond/trytond/modules/stock_lot/stock.py Tue Jul 10 12:58:45 2018 +0200
+@@ -159,6 +159,20 @@
+ 'lot_required': 'Lot is required for move of product "%s".',
+ })
+
++ @classmethod
++ def assign_try(cls, moves, with_childs=True, grouping=('product',)):
++ lot_moves = []
++ product_moves = []
++ for move in moves:
++ if move.lot:
++ lot_moves.append(move)
++ else:
++ product_moves.append(move)
++ return (super(Move, cls).assign_try(lot_moves,
++ with_childs=with_childs, grouping=('product', 'lot'))
++ & super(Move, cls).assign_try(product_moves,
++ with_childs=with_childs, grouping=grouping))
++
+ def check_lot(self):
+ "Check if lot is required"
+ if (self.state == 'done'
diff --git a/issue240_631.diff b/issue240_631.diff
new file mode 100644
index 0000000..f14a5b0
--- /dev/null
+++ b/issue240_631.diff
@@ -0,0 +1,323 @@
+diff -r d1102046dce6 __init__.py
+--- a/trytond/trytond/modules/stock_lot/__init__.py Mon Apr 23 17:32:23 2018 +0200
++++ b/trytond/trytond/modules/stock_lot/__init__.py Thu Jun 14 14:59:26 2018 +0200
+@@ -2,24 +2,29 @@
+ # this repository contains the full copyright notices and license terms.
+
+ from trytond.pool import Pool
+-from .stock import *
+-from .product import *
++from . import stock
++from . import product
+
+
+ def register():
+ Pool.register(
+- Lot,
+- LotByLocationContext,
+- LotType,
+- Move,
+- ShipmentIn,
+- ShipmentOut,
+- ShipmentOutReturn,
+- Period,
+- PeriodCacheLot,
+- Inventory,
+- InventoryLine,
+- Template,
+- Product,
+- TemplateLotType,
++ stock.Lot,
++ stock.LotByLocationContext,
++ stock.LotType,
++ stock.Move,
++ stock.ShipmentIn,
++ stock.ShipmentOut,
++ stock.ShipmentOutReturn,
++ stock.Period,
++ stock.PeriodCacheLot,
++ stock.Inventory,
++ stock.InventoryLine,
++ product.Template,
++ product.Product,
++ product.TemplateLotType,
++ stock.Location,
++ stock.LotByLocationStart,
+ module='stock_lot', type_='model')
++ Pool.register(
++ stock.LotByLocation,
++ module='stock_lot', type_='wizard')
+diff -r d1102046dce6 stock.py
+--- a/trytond/trytond/modules/stock_lot/stock.py Mon Apr 23 17:32:23 2018 +0200
++++ b/trytond/trytond/modules/stock_lot/stock.py Thu Jun 14 14:59:26 2018 +0200
+@@ -4,16 +4,86 @@
+ from collections import defaultdict
+
+ from trytond.model import ModelView, ModelSQL, fields
+-from trytond.pyson import Eval
++from trytond.pyson import PYSONEncoder, Eval
+ from trytond.pool import Pool, PoolMeta
+ from trytond.transaction import Transaction
+ from trytond.modules.stock import StockMixin
++from trytond.wizard import Wizard, StateView, StateAction, Button
+
+-__all__ = ['Lot', 'LotType', 'Move', 'ShipmentIn', 'ShipmentOut',
++_all__ = ['Lot', 'LotType', 'Move', 'ShipmentIn', 'ShipmentOut',
+ 'LotByLocationContext', 'ShipmentOutReturn',
+ 'Period', 'PeriodCacheLot',
+- 'Inventory', 'InventoryLine', 'LotByLocationContext']
++ 'Inventory', 'InventoryLine', 'LotByLocationContext',
++ 'Location', 'LotByLocation', 'LotByLocationStart']
++
++
++class Location:
++ __name__ = 'stock.location'
++ __metaclass__ = PoolMeta
++
++ @classmethod
++ def _quantity_grouping_and_key(cls):
++ if Transaction().context.get('lot'):
++ lot_id = Transaction().context['lot']
++ product_id = Transaction().context['product']
++ return ('product', 'lot'), (product_id, lot_id)
++ return super(Location, cls)._quantity_grouping_and_key()
++
++
++class LotByLocationStart(ModelView):
++ 'Lot by Location'
++ __name__ = 'stock.lot.by_location.start'
++ forecast_date = fields.Date(
++ 'At Date', help=('Allow to compute expected '
++ 'stock quantities for this date.\n'
++ '* An empty value is an infinite date in the future.\n'
++ '* A date in the past will provide historical values.'))
++
++ @staticmethod
++ def default_forecast_date():
++ Date = Pool().get('ir.date')
++ return Date.today()
++
+
++class LotByLocation(Wizard):
++ 'Lot by Location'
++ __name__ = 'stock.lot.by_location'
++ start = StateView('stock.lot.by_location.start',
++ 'stock_lot.lot_by_location_start_view_form', [
++ Button('Cancel', 'end', 'tryton-cancel'),
++ Button('Open', 'open', 'tryton-ok', default=True),
++ ])
++ open = StateAction('stock.act_location_quantity_tree')
++
++ def do_open(self, action):
++ pool = Pool()
++ Lot = pool.get('stock.lot')
++ Lang = pool.get('ir.lang')
++
++ context = {}
++ lot_id = Transaction().context['active_id']
++ context['lot'] = lot_id
++
++ lot = Lot(lot_id)
++ context['product'] = lot.product.id
++
++ if self.start.forecast_date:
++ context['stock_date_end'] = self.start.forecast_date
++ else:
++ context['stock_date_end'] = datetime.date.max
++ action['pyson_context'] = PYSONEncoder().encode(context)
++
++ for code in [Transaction().language, 'en_US']:
++ langs = Lang.search([
++ ('code', '=', code),
++ ])
++ if langs:
++ break
++ lang, = langs
++ date = lang.strftime(context['stock_date_end'])
++ action['name'] += ' - %s (%s) @ %s' % (lot.rec_name,
++ lot.product.default_uom.rec_name, date)
++ return action, {}
+
+ class Lot(ModelSQL, ModelView, StockMixin):
+ "Stock Lot"
+diff -r d1102046dce6 stock.xml
+--- a/trytond/trytond/modules/stock_lot/stock.xml Mon Apr 23 17:32:23 2018 +0200
++++ b/trytond/trytond/modules/stock_lot/stock.xml Thu Jun 14 14:59:26 2018 +0200
+@@ -112,6 +112,28 @@
+
+
+
++
++
++ Lot by Locations
++ stock.lot.by_location
++ stock.lot
++
++
++ form_relate
++ stock.lot,-1
++
++
++
++
++
++
++
++ stock.lot.by_location.start
++ form
++ lot_by_location_start_form
++
++
+
+ supplier
+ Supplier
+diff -r d1102046dce6 view/lot_by_location_start_form.xml
+--- /dev/null Thu Jan 01 00:00:00 1970 +0000
++++ b/trytond/trytond/modules/stock_lot/view/lot_by_location_start_form.xml Thu Jun 14 14:59:26 2018 +0200
+@@ -0,0 +1,7 @@
++
++
++
+diff -r d1102046dce6 locale/ca.po
+--- a/trytond/trytond/modules/stock_lot/locale/ca.po Mon Apr 23 17:32:23 2018 +0200
++++ b/trytond/trytond/modules/stock_lot/locale/ca.po Wed Jun 27 12:46:43 2018 +0200
+@@ -90,6 +90,14 @@
+ msgid "Write User"
+ msgstr "Usuari de modificació"
+
++msgctxt "field:stock.lot.by_location.start,forecast_date:"
++msgid "At Date"
++msgstr "A data"
++
++msgctxt "field:stock.lot.by_location.start,id:"
++msgid "ID"
++msgstr "ID"
++
+ msgctxt "field:stock.lot.type,code:"
+ msgid "Code"
+ msgstr "Codi"
+@@ -194,6 +202,16 @@
+ msgid "The type of location for which lot is required"
+ msgstr "Tipus d'ubicació per la qual el lot és obligatori."
+
++msgctxt "help:stock.lot.by_location.start,forecast_date:"
++msgid ""
++"Allow to compute expected stock quantities for this date.\n"
++"* An empty value is an infinite date in the future.\n"
++"* A date in the past will provide historical values."
++msgstr ""
++"Permet calcular les quantitats previstes per a aquesta data.\n"
++"* Un valor buit és un data infinita en el futur.\n"
++"* Una data en el passat proporcionarà valors històrics. "
++
+ msgctxt "help:stock.lots_by_location.context,forecast_date:"
+ msgid ""
+ "Allow to compute expected stock quantities for this date.\n"
+@@ -216,6 +234,10 @@
+ msgid "Moves"
+ msgstr "Moviments"
+
++msgctxt "model:ir.action,name:wizard_lot_by_location"
++msgid "Lot by Locations"
++msgstr "Lot per ubicació"
++
+ msgctxt "model:ir.ui.menu,name:menu_lot_form"
+ msgid "Lots"
+ msgstr "Lots"
+@@ -228,6 +250,10 @@
+ msgid "Stock Lot"
+ msgstr "Lot"
+
++msgctxt "model:stock.lot.by_location.start,name:"
++msgid "Lot by Location"
++msgstr "Lot per ubicació"
++
+ msgctxt "model:stock.lot.type,name:"
+ msgid "Stock Lot Type"
+ msgstr "Tipus de lot"
+@@ -279,3 +305,11 @@
+ msgctxt "view:stock.period.cache.lot:"
+ msgid "Period Lot Caches"
+ msgstr "Períodes d'existències precalculat"
++
++msgctxt "wizard_button:stock.lot.by_location,start,end:"
++msgid "Cancel"
++msgstr "Cancel·la"
++
++msgctxt "wizard_button:stock.lot.by_location,start,open:"
++msgid "Open"
++msgstr "Pendent"
+diff -r d1102046dce6 locale/es.po
+--- a/trytond/trytond/modules/stock_lot/locale/es.po Mon Apr 23 17:32:23 2018 +0200
++++ b/trytond/trytond/modules/stock_lot/locale/es.po Wed Jun 27 12:46:43 2018 +0200
+@@ -90,6 +90,14 @@
+ msgid "Write User"
+ msgstr "Usuario de modificación"
+
++msgctxt "field:stock.lot.by_location.start,forecast_date:"
++msgid "At Date"
++msgstr "A la fecha"
++
++msgctxt "field:stock.lot.by_location.start,id:"
++msgid "ID"
++msgstr "ID"
++
+ msgctxt "field:stock.lot.type,code:"
+ msgid "Code"
+ msgstr "Código"
+@@ -194,6 +202,16 @@
+ msgid "The type of location for which lot is required"
+ msgstr "El tipo de ubicación en la que el lote es obligatorio."
+
++msgctxt "help:stock.lot.by_location.start,forecast_date:"
++msgid ""
++"Allow to compute expected stock quantities for this date.\n"
++"* An empty value is an infinite date in the future.\n"
++"* A date in the past will provide historical values."
++msgstr ""
++"Permite calcular las cantidades previstas para esta fecha.\n"
++"* Un valor vacío es una fecha infinita en el futuro.\n"
++"* Una fecha en el pasado proporcionará valores históricos. "
++
+ msgctxt "help:stock.lots_by_location.context,forecast_date:"
+ msgid ""
+ "Allow to compute expected stock quantities for this date.\n"
+@@ -216,6 +234,10 @@
+ msgid "Moves"
+ msgstr "Movimientos"
+
++msgctxt "model:ir.action,name:wizard_lot_by_location"
++msgid "Lot by Locations"
++msgstr "Lotes por ubicaciones"
++
+ msgctxt "model:ir.ui.menu,name:menu_lot_form"
+ msgid "Lots"
+ msgstr "Lotes"
+@@ -228,6 +250,10 @@
+ msgid "Stock Lot"
+ msgstr "Lote"
+
++msgctxt "model:stock.lot.by_location.start,name:"
++msgid "Lot by Location"
++msgstr "Lote por ubicación"
++
+ msgctxt "model:stock.lot.type,name:"
+ msgid "Stock Lot Type"
+ msgstr "Tipo lote"
+@@ -279,3 +305,11 @@
+ msgctxt "view:stock.period.cache.lot:"
+ msgid "Period Lot Caches"
+ msgstr "Período lote precalculados"
++
++msgctxt "wizard_button:stock.lot.by_location,start,end:"
++msgid "Cancel"
++msgstr "Cancelar"
++
++msgctxt "wizard_button:stock.lot.by_location,start,open:"
++msgid "Open"
++msgstr "Pendiente"
diff --git a/issue3932.diff b/issue3932.diff
new file mode 100644
index 0000000..cff5490
--- /dev/null
+++ b/issue3932.diff
@@ -0,0 +1,32 @@
+ diff -r e978ecc8f044 trytond/trytond/modules/account/move.xml
+ --- a/trytond/trytond/modules/account/move.xml Mon Apr 23 17:24:11 2018 +0200
+ +++ b/trytond/trytond/modules/account/move.xml Fri May 11 12:49:37 2018 +0200
+ @@ -367,5 +367,28 @@
+ account.move.general_journal
+ account/general_journal.fodt
+
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+
+
diff --git a/issue4030.diff b/issue4030.diff
new file mode 100644
index 0000000..d752df5
--- /dev/null
+++ b/issue4030.diff
@@ -0,0 +1,12 @@
+diff -r 1329bfa523a8 trytond/trytond/modules/analytic_account/line.py
+--- a/trytond/trytond/modules/analytic_account/line.py Mon Apr 23 17:28:19 2018 +0200
++++ b/trytond/trytond/modules/analytic_account/line.py Fri May 11 13:16:07 2018 +0200
+@@ -28,7 +28,7 @@
+ 'on_change_with_company', searcher='search_company')
+ account = fields.Many2One('analytic_account.account', 'Account',
+ required=True, select=True, domain=[
+- ('type', 'not in', ['view', 'distribution']),
++ ('type', 'not in', ['view', 'distribution', 'root']),
+ ['OR',
+ ('company', '=', None),
+ ('company', '=', Eval('company', -1)),
diff --git a/issue4341.diff b/issue4341.diff
new file mode 100644
index 0000000..a1e7df0
--- /dev/null
+++ b/issue4341.diff
@@ -0,0 +1,72 @@
+diff -r e978ecc8f044 trytond/trytond/modules/account/view/account_list.xml
+--- a/trytond/trytond/modules/account/view/account_list.xml Mon Apr 23 17:24:11 2018 +0200
++++ b/trytond/trytond/modules/account/view/account_list.xml Fri May 11 14:15:10 2018 +0200
+@@ -5,4 +5,5 @@
+
+
+
++
+
+diff -r e978ecc8f044 trytond/trytond/modules/account/view/account_tree.xml
+--- a/trytond/trytond/modules/account/view/account_tree.xml Mon Apr 23 17:24:11 2018 +0200
++++ b/trytond/trytond/modules/account/view/account_tree.xml Fri May 11 14:15:10 2018 +0200
+@@ -7,4 +7,5 @@
+
+
+
++
+
+diff -r e978ecc8f044 trytond/trytond/modules/account/view/journal_period_tree.xml
+--- a/trytond/trytond/modules/account/view/journal_period_tree.xml Mon Apr 23 17:24:11 2018 +0200
++++ b/trytond/trytond/modules/account/view/journal_period_tree.xml Fri May 11 14:15:10 2018 +0200
+@@ -5,4 +5,5 @@
+
+
+
++
+
+diff -r e978ecc8f044 trytond/trytond/modules/account/view/journal_tree.xml
+--- a/trytond/trytond/modules/account/view/journal_tree.xml Mon Apr 23 17:24:11 2018 +0200
++++ b/trytond/trytond/modules/account/view/journal_tree.xml Fri May 11 14:15:10 2018 +0200
+@@ -5,4 +5,5 @@
+
+
+
++
+
+diff -r e978ecc8f044 trytond/trytond/modules/account/view/move_template_list.xml
+--- a/trytond/trytond/modules/account/view/move_template_list.xml Mon Apr 23 17:24:11 2018 +0200
++++ b/trytond/trytond/modules/account/view/move_template_list.xml Fri May 11 14:15:10 2018 +0200
+@@ -3,4 +3,5 @@
+ this repository contains the full copyright notices and license terms. -->
+
+
++
+
+diff -r e978ecc8f044 trytond/trytond/modules/account/view/tax_code_list.xml
+--- a/trytond/trytond/modules/account/view/tax_code_list.xml Mon Apr 23 17:24:11 2018 +0200
++++ b/trytond/trytond/modules/account/view/tax_code_list.xml Fri May 11 14:15:10 2018 +0200
+@@ -5,4 +5,5 @@
+
+
+
++
+
+diff -r e978ecc8f044 trytond/trytond/modules/account/view/tax_code_tree.xml
+--- a/trytond/trytond/modules/account/view/tax_code_tree.xml Mon Apr 23 17:24:11 2018 +0200
++++ b/trytond/trytond/modules/account/view/tax_code_tree.xml Fri May 11 14:15:10 2018 +0200
+@@ -7,4 +7,5 @@
+
+
+
++
+
+diff -r e978ecc8f044 trytond/trytond/modules/account/view/tax_list.xml
+--- a/trytond/trytond/modules/account/view/tax_list.xml Mon Apr 23 17:24:11 2018 +0200
++++ b/trytond/trytond/modules/account/view/tax_list.xml Fri May 11 14:15:10 2018 +0200
+@@ -5,4 +5,5 @@
+
+
+
++
+
diff --git a/issue4482.diff b/issue4482.diff
new file mode 100644
index 0000000..b071370
--- /dev/null
+++ b/issue4482.diff
@@ -0,0 +1,19 @@
+diff -r 98c229b8cb4a trytond/trytond/modules/stock/inventory.xml
+--- a/trytond/trytond/modules/stock/inventory.xml Mon Apr 23 17:29:56 2018 +0200
++++ b/trytond/trytond/modules/stock/inventory.xml Fri May 11 13:46:51 2018 +0200
+@@ -60,6 +60,15 @@
+ inventory_line_tree
+
+
++
++
++
++
++
++
++
++
++
+
+
+
diff --git a/issue4506.diff b/issue4506.diff
new file mode 100644
index 0000000..37e2d6a
--- /dev/null
+++ b/issue4506.diff
@@ -0,0 +1,49 @@
+diff -r 9cd9f1c27fdd trytond/trytond/modules/account_invoice/invoice.xml
+--- a/trytond/trytond/modules/account_invoice/invoice.xml Mon Apr 23 17:32:58 2018 +0200
++++ b/trytond/trytond/modules/account_invoice/invoice.xml Fri May 11 13:11:48 2018 +0200
+@@ -132,6 +132,17 @@
+
+
++
++ Credit Notes
++ account.invoice
++
++
++
++ form_relate
++ account.invoice,-1
++
++
++
+
+
+
+diff -r 9cd9f1c27fdd trytond/trytond/modules/account_invoice/locale/ca.po
+--- a/trytond/trytond/modules/account_invoice/locale/ca.po Mon Apr 23 17:32:58 2018 +0200
++++ b/trytond/trytond/modules/account_invoice/locale/ca.po Fri May 11 13:11:48 2018 +0200
+@@ -1127,6 +1127,10 @@
+ msgid "Invoice Tax"
+ msgstr "Impost de factura"
+
++msgctxt "model:ir.action,name:act_credit_notes_form"
++msgid "Credit Notes"
++msgstr "Abonaments"
++
+ msgctxt "model:ir.action,name:act_invoice_form"
+ msgid "Invoices"
+ msgstr "Factures"
+diff -r 9cd9f1c27fdd trytond/trytond/modules/account_invoice/locale/es.po
+--- a/trytond/trytond/modules/account_invoice/locale/es.po Mon Apr 23 17:32:58 2018 +0200
++++ b/trytond/trytond/modules/account_invoice/locale/es.po Fri May 11 13:11:48 2018 +0200
+@@ -1123,6 +1123,10 @@
+ msgid "Invoice Tax"
+ msgstr "Impuesto de factura"
+
++msgctxt "model:ir.action,name:act_credit_notes_form"
++msgid "Credit Notes"
++msgstr "Abonos"
++
+ msgctxt "model:ir.action,name:act_invoice_form"
+ msgid "Invoices"
+ msgstr "Facturas"
diff --git a/issue53451002_1_10001.diff b/issue53451002_1_10001.diff
new file mode 100644
index 0000000..9bcfec6
--- /dev/null
+++ b/issue53451002_1_10001.diff
@@ -0,0 +1,93 @@
+diff -r 29eb0f164bcb move.py
+--- a/trytond/trytond/modules/stock/move.py Tue Oct 30 12:37:21 2018 +0100
++++ b/trytond/trytond/modules/stock/move.py Tue Oct 30 12:41:42 2018 +0100
+@@ -850,7 +850,6 @@
+ ])
+ else:
+ locations = list(set((m.from_location for m in moves)))
+-
+ location_ids = [l.id for l in locations]
+ product_ids = list(set((m.product.id for m in moves)))
+ stock_date_end = Date.today()
+@@ -967,7 +966,8 @@
+
+ @classmethod
+ def compute_quantities_query(cls, location_ids, with_childs=False,
+- grouping=('product',), grouping_filter=None):
++ grouping=('product',), grouping_filter=None,
++ quantity_field='internal_quantity'):
+ """
+ Prepare a query object to compute for each location and product the
+ stock quantity in the default uom of the product.
+@@ -985,6 +985,8 @@
+ stock_skip_warehouse: if set, quantities on a warehouse are no more
+ quantities of all child locations but quantities of the storage
+ zone.
++ quantity_field is the name of the field containing the quantity to be
++ aggregated
+ If with_childs, it computes also for child locations.
+ grouping is a tuple of Move (or Product if prefixed by 'product.')
+ field names and defines how stock moves are grouped.
+@@ -1037,7 +1039,7 @@
+ if use_product:
+ product = Product.__table__()
+ columns = ['id', 'state', 'effective_date', 'planned_date',
+- 'internal_quantity', 'from_location', 'to_location']
++ quantity_field, 'from_location', 'to_location']
+ columns += list(grouping)
+ columns = [get_column(c, move, product) for c in columns]
+ move = (move
+@@ -1050,7 +1052,7 @@
+ period_cache = PeriodCache.__table__()
+ if use_product:
+ product_cache = Product.__table__()
+- columns = ['internal_quantity', 'period', 'location']
++ columns = [quantity_field, 'period', 'location']
+ columns += list(grouping)
+ columns = [get_column(c, period_cache, product_cache)
+ for c in columns]
+@@ -1067,7 +1069,7 @@
+ to_location = Location.__table__()
+ to_parent_location = Location.__table__()
+ columns = ['id', 'state', 'effective_date', 'planned_date',
+- 'internal_quantity'] + list(grouping)
++ quantity_field] + list(grouping)
+ columns = [Column(move, c).as_(c) for c in columns]
+
+ move_with_parent = (move
+@@ -1121,7 +1123,7 @@
+ if PeriodCache:
+ location = Location.__table__()
+ parent_location = Location.__table__()
+- columns = ['internal_quantity', 'period'] + list(grouping)
++ columns = [quantity_field, 'period'] + list(grouping)
+ columns = [Column(period_cache, c).as_(c) for c in columns]
+ period_cache = Union(
+ period_cache.select(
+@@ -1319,7 +1321,7 @@
+ move_keys_alias = [Column(move, key).as_(key) for key in grouping]
+ move_keys = [Column(move, key) for key in grouping]
+ query = move.select(move.to_location.as_('location'),
+- Sum(move.internal_quantity).as_('quantity'),
++ Sum(getattr(move, quantity_field)).as_('quantity'),
+ *move_keys_alias,
+ where=state_date_clause_in
+ & where
+@@ -1329,7 +1331,7 @@
+ & dest_clause_from,
+ group_by=[move.to_location] + move_keys)
+ query = Union(query, move.select(move.from_location.as_('location'),
+- (-Sum(move.internal_quantity)).as_('quantity'),
++ (-Sum(getattr(move, quantity_field))).as_('quantity'),
+ *move_keys_alias,
+ where=state_date_clause_out
+ & where
+@@ -1344,7 +1346,7 @@
+ for key in grouping]
+ query = Union(query, from_period.select(
+ period_cache.location.as_('location'),
+- period_cache.internal_quantity.as_('quantity'),
++ getattr(period_cache, quantity_field).as_('quantity'),
+ *period_keys,
+ where=(period_cache.period
+ == (period.id if period else None))
diff --git a/issue7276.diff b/issue7276.diff
new file mode 100644
index 0000000..7e365cf
--- /dev/null
+++ b/issue7276.diff
@@ -0,0 +1,21 @@
+diff -r 0447f28ab266 trytond/trytond/modules/account/move.py
+--- a/trytond/trytond/modules/account/move.py Wed Sep 12 15:56:58 2018 +0200
++++ b/trytond/trytond/modules/account/move.py Wed Sep 12 16:09:55 2018 +0200
+@@ -635,7 +635,6 @@
+ party_required = fields.Function(fields.Boolean('Party Required'),
+ 'on_change_with_party_required')
+ maturity_date = fields.Date('Maturity Date',
+- states=_states, depends=_depends,
+ help='This field is used for payable and receivable lines. \n'
+ 'You can put the limit date for the payment.')
+ state = fields.Selection([
+@@ -668,7 +667,8 @@
+ @classmethod
+ def __setup__(cls):
+ super(Line, cls).__setup__()
+- cls._check_modify_exclude = {'reconciliation'}
++ cls._check_modify_exclude = {
++ 'maturity_date', 'reconciliation', 'tax_lines'}
+ cls._reconciliation_modify_disallow = {
+ 'account', 'debit', 'credit', 'party',
+ }
diff --git a/issue7826.diff b/issue7826.diff
new file mode 100644
index 0000000..0775218
--- /dev/null
+++ b/issue7826.diff
@@ -0,0 +1,13 @@
+diff -r 4c5abccfccf2 trytond/trytond/modules/stock_package/stock.py
+--- a/trytond/trytond/modules/stock_package/stock.py Mon Apr 23 17:36:31 2018 +0200
++++ b/trytond/trytond/modules/stock_package/stock.py Tue Oct 30 12:45:02 2018 +0100
+@@ -212,7 +212,8 @@
+
+ @property
+ def packages_moves(self):
+- return (m for m in self.outgoing_moves if m.state != 'cancel')
++ return (m for m in self.outgoing_moves
++ if m.state != 'cancel' and m.quantity != 0.0)
+
+
+ class ShipmentInReturn(PackageMixin, object):
diff --git a/issue7856.diff b/issue7856.diff
new file mode 100644
index 0000000..2a10b63
--- /dev/null
+++ b/issue7856.diff
@@ -0,0 +1,20 @@
+diff -r 10d517bd46f1 trytond/trytond/modules/stock/move.py
+--- a/trytond/trytond/modules/stock/move.py Wed Nov 14 09:54:25 2018 +0100
++++ b/trytond/trytond/modules/stock/move.py Wed Nov 14 09:55:39 2018 +0100
+@@ -907,6 +907,7 @@
+ if move.state == 'staging':
+ success = False
+ continue
++ to_location = move.to_location
+ # Keep location order for pick_product
+ location_qties = OrderedDict()
+ if with_childs:
+@@ -919,6 +920,8 @@
+ else:
+ childs = [move.from_location]
+ for location in childs:
++ if location.id == to_location.id:
++ continue
+ key = get_key(move, location)
+ if key in pbl:
+ location_qties[location] = Uom.compute_qty(
diff --git a/logging_jsonrpc_exeption.diff b/logging_jsonrpc_exeption.diff
new file mode 100644
index 0000000..d3f9e31
--- /dev/null
+++ b/logging_jsonrpc_exeption.diff
@@ -0,0 +1,31 @@
+diff -r 7ed03689fe01 trytond/trytond/protocols/dispatcher.py
+--- a/trytond/trytond/protocols/dispatcher.py Fri May 11 13:52:50 2018 +0200
++++ b/trytond/trytond/protocols/dispatcher.py Fri May 11 13:56:27 2018 +0200
+@@ -192,7 +192,7 @@
+ raise
+ except (ConcurrencyException, UserError, UserWarning,
+ LoginException):
+- logger.debug(log_message, *log_args, exc_info=True)
++ logger.warning(log_message, *log_args, exc_info=True)
+ raise
+ except Exception:
+ logger.error(log_message, *log_args, exc_info=True)
+diff -r 7ed03689fe01 trytond/trytond/protocols/jsonrpc.py
+--- a/trytond/trytond/protocols/jsonrpc.py Fri May 11 13:52:50 2018 +0200
++++ b/trytond/trytond/protocols/jsonrpc.py Fri May 11 13:56:27 2018 +0200
+@@ -4,6 +4,7 @@
+ from decimal import Decimal
+ import json
+ import base64
++import logging
+
+ from werkzeug.wrappers import Response
+ from werkzeug.utils import cached_property
+@@ -12,6 +13,8 @@
+ from trytond.protocols.wrappers import Request
+ from trytond.exceptions import TrytonException
+
++logger = logging.getLogger(__name__)
++
+
+ class JSONDecoder(object):
diff --git a/match.diff b/match.diff
new file mode 100644
index 0000000..7663ad5
--- /dev/null
+++ b/match.diff
@@ -0,0 +1,12 @@
+diff -r 5b4101d67bb7 trytond/model/match.py
+--- a/trytond/trytond/model/match.py Mon Oct 15 22:49:51 2018 +0200
++++ b/trytond/trytond/model/match.py Sat Nov 03 18:21:44 2018 +0100
+@@ -10,6 +10,8 @@
+ and matching value as value'''
+ for field, pattern_value in pattern.iteritems():
+ value = getattr(self, field)
++ if self._fields[field]._type in ('char', 'text') and value == "":
++ value = None
+ if not match_none and value is None:
+ continue
+ if self._fields[field]._type == 'many2one':
diff --git a/purchase_request.diff b/purchase_request.diff
new file mode 100644
index 0000000..47e6309
--- /dev/null
+++ b/purchase_request.diff
@@ -0,0 +1,12 @@
+diff -r a4d9a0d5ca24 purchase_request.py
+--- a/trytond/trytond/modules/purchase_request/purchase_request.py Mon May 21 20:13:25 2018 +0200
++++ b/trytond/trytond/modules/purchase_request/purchase_request.py Tue Jul 24 15:56:01 2018 +0200
+@@ -276,6 +276,8 @@
+
+ supplier = None
+ today = Date.today()
++ if not date:
++ date = today
+ for product_supplier in product.product_suppliers:
+ supply_date = product_supplier.compute_supply_date(date=today)
+ timedelta = date - supply_date
diff --git a/sale_number_of_packages.diff b/sale_number_of_packages.diff
new file mode 100644
index 0000000..c04ebd4
--- /dev/null
+++ b/sale_number_of_packages.diff
@@ -0,0 +1,32 @@
+diff -r 8eadb6e76468 trytond/trytond/modules/sale_number_of_packages/stock.py
+--- a/trytond/trytond/modules/sale_number_of_packages/stock.py Mon Dec 03 16:38:23 2018 +0100
++++ b/trytond/trytond/modules/sale_number_of_packages/stock.py Wed Dec 12 14:45:49 2018 +0100
+@@ -179,7 +179,8 @@
+
+ @classmethod
+ def compute_quantities_query(cls, location_ids, with_childs=False,
+- grouping=('product',), grouping_filter=None):
++ grouping=('product',), grouping_filter=None,
++ quantity_field='internal_quantity'):
+ pool = Pool()
+ Lot = pool.get('stock.lot')
+ lot = Lot.__table__()
+@@ -187,7 +188,8 @@
+ if not Transaction().context.get('normalized_number_of_packages'):
+ return super(Move, cls).compute_quantities_query(
+ location_ids, with_childs=with_childs, grouping=grouping,
+- grouping_filter=grouping_filter)
++ grouping_filter=grouping_filter,
++ quantity_field=quantity_field)
+
+ new_grouping = grouping[:]
+ new_grouping_filter = (grouping_filter[:] if grouping_filter != None
+@@ -199,7 +201,8 @@
+
+ query = super(Move, cls).compute_quantities_query(
+ location_ids, with_childs=with_childs, grouping=new_grouping,
+- grouping_filter=new_grouping_filter)
++ grouping_filter=new_grouping_filter,
++ quantity_field=quantity_field)
+ if not query:
+ return query
diff --git a/search_warehouse.diff b/search_warehouse.diff
new file mode 100644
index 0000000..9765a54
--- /dev/null
+++ b/search_warehouse.diff
@@ -0,0 +1,40 @@
+diff -r 78ac887c5b7f location.py
+--- a/trytond/trytond/modules/stock/location.py Tue Jun 12 16:16:43 2018 +0200
++++ b/trytond/trytond/modules/stock/location.py Tue Jun 12 16:19:53 2018 +0200
+@@ -59,7 +59,7 @@
+ "Flat Children",
+ help="Check to restrict to one level of children.")
+ warehouse = fields.Function(fields.Many2One('stock.location', 'Warehouse'),
+- 'get_warehouse')
++ 'get_warehouse', searcher='search_warehouse')
+ input_location = fields.Many2One(
+ "stock.location", "Input", states={
+ 'invisible': Eval('type') != 'warehouse',
+@@ -195,6 +195,27 @@
+ inactives.append(location)
+ cls.check_inactive(inactives)
+
++ @classmethod
++ def search_warehouse(cls, name, clause):
++ warehouse_child_locations = cls.search([
++ ('parent.type', '=', 'warehouse'),
++ ('type', '=', 'storage'),
++ ('parent', clause[1], clause[2]),
++ ])
++ found_warehouse_ids = []
++ storage_location_ids = []
++ for location in warehouse_child_locations:
++ storage_location_ids.append(location.id)
++ found_warehouse_ids.append(location.parent.id)
++ warehouse_location_ids = []
++ for location in cls.search([
++ ('parent', 'child_of', storage_location_ids),
++ ]):
++ if (location.warehouse and location.warehouse.id in
++ found_warehouse_ids):
++ warehouse_location_ids.append(location.id)
++ return [('id', 'in', warehouse_location_ids)]
++
+ def check_type_for_moves(self):
+ """ Check locations with moves have types compatible with moves. """
+ invalid_move_types = ['warehouse', 'view']
diff --git a/series b/series
index 6863b34..8cf2e55 100644
--- a/series
+++ b/series
@@ -1,2 +1,26 @@
-issue6253.diff # add invoice type criteria
-lock_stock_move.diff # stock
+babi_multiprocess.diff # [trytond] babi multiprocess
+logging_jsonrpc_exeption.diff # [trytond] logging JSONRPC Exception
+match.diff # [trytond] Control when tje filed is a Char o Text and the value is not none but it's an empty string
+issue3932.diff # [account] rule account move and account move line by company
+issue6253.diff # [account_invoice] add invoice type criteria
+issue4506.diff # [account_invoice] Add credit invoices keyword from account.invoice
+issue4030.diff # [analytic_account] Not selected root accounts in analytic account lines
+purchase_request.diff # [purchase_request] as shippment_date it's not required we need to ensure operation could be done
+
+issue4482.diff # [stock] stock inventory misses company access rule
+search_warehouse.diff #[stock] search function for warehouse.
+
+# TODO: improve_performance_on_try_assign.diff # [stock] change browse of product to get default_uom to pysql
+
+issue240_631.diff # [stock_lot] stock_by_locations get all locations with that lot.
+issue10467.diff # stock_lot: add lot to grouping if lot it's required on product
+
+issue53451002_1_10001.diff # [stock] Allow configuring which quantity is grouped in compute_quantities_query() needed by stock_number_of_packages
+sale_number_of_packages.diff # [sale_number_of_packages] Allow configuring which quantity is grouped in compute_quantities_query() needed by stock_number_of_packages
+stock_external_party.diff # [stock_external_party] Allow configuring which quantity is grouped in compute_quantities_query() needed by stock_number_of_packages
+stock_lot_deactivatable.diff # [stock_lot_deactivatable] Allow configuring which quantity is grouped in compute_quantities_query() needed by stock_number_of_packages
+stock_lot_sled.diff # [stock_lot_sled] Allow configuring which quantity is grouped in compute_quantities_query() needed by stock_number_of_packages
+
+issue7826.diff # [stock_package] Total packages moves are all
+lock_stock_move.diff # [stock] Function to overwrite if lock table or not
+issue7856.diff # [stock] Can't move qty from a parent location to child location
diff --git a/stock_external_party.diff b/stock_external_party.diff
new file mode 100644
index 0000000..27bdc8f
--- /dev/null
+++ b/stock_external_party.diff
@@ -0,0 +1,22 @@
+diff -r f7f8e7da9dd8 trytond/trytond/modules/stock_external_party/stock.py
+--- a/trytond/trytond/modules/stock_external_party/stock.py Tue Dec 04 13:36:33 2018 +0100
++++ b/trytond/trytond/modules/stock_external_party/stock.py Wed Dec 05 16:24:09 2018 +0100
+@@ -155,7 +155,8 @@
+
+ @classmethod
+ def compute_quantities_query(cls, location_ids, with_childs=False,
+- grouping=('product',), grouping_filter=None):
++ grouping=('product',), grouping_filter=None,
++ quantity_field='internal_quantity'):
+ context = Transaction().context
+
+ new_grouping = grouping[:]
+@@ -168,7 +169,7 @@
+
+ query = super(Move, cls).compute_quantities_query(
+ location_ids, with_childs=with_childs, grouping=new_grouping,
+- grouping_filter=new_grouping_filter)
++ grouping_filter=new_grouping_filter, quantity_field=quantity_field)
+ return query
+
+ @classmethod
diff --git a/stock_lot_deactivatable.diff b/stock_lot_deactivatable.diff
new file mode 100644
index 0000000..d66ed34
--- /dev/null
+++ b/stock_lot_deactivatable.diff
@@ -0,0 +1,20 @@
+diff -r c8f4cfc59666 trytond/trytond/modules/stock_lot_deactivatable/stock.py
+--- a/trytond/trytond/modules/stock_lot_deactivatable/stock.py Wed Dec 12 15:46:19 2018 +0100
++++ b/trytond/trytond/modules/stock_lot_deactivatable/stock.py Wed Dec 12 15:50:28 2018 +0100
+@@ -82,13 +82,14 @@
+
+ @classmethod
+ def compute_quantities_query(cls, location_ids, with_childs=False,
+- grouping=('product',), grouping_filter=None):
++ grouping=('product',), grouping_filter=None,
++ quantity_field='internal_quantity'):
+ pool = Pool()
+ Lot = pool.get('stock.lot')
+ Period = pool.get('stock.period')
+ query = super(Move, cls).compute_quantities_query(
+ location_ids, with_childs=with_childs, grouping=grouping,
+- grouping_filter=grouping_filter)
++ grouping_filter=grouping_filter, quantity_field=quantity_field)
+
+ if not query or 'lot' not in grouping:
+ return query
diff --git a/stock_lot_sled.diff b/stock_lot_sled.diff
new file mode 100644
index 0000000..cc9ff0e
--- /dev/null
+++ b/stock_lot_sled.diff
@@ -0,0 +1,39 @@
+diff -r fb7f3b05e343 stock.py
+--- a/trytond/trytond/modules/stock_lot_sled/stock.py Mon Apr 23 17:44:40 2018 +0200
++++ b/trytond/trytond/modules/stock_lot_sled/stock.py Tue Nov 27 11:21:59 2018 +0100
+@@ -229,7 +229,8 @@
+
+ @classmethod
+ def compute_quantities_query(cls, location_ids, with_childs=False,
+- grouping=('product',), grouping_filter=None):
++ grouping=('product',), grouping_filter=None,
++ quantity_field='internal_quantity'):
+ pool = Pool()
+ Date = pool.get('ir.date')
+ Lot = pool.get('stock.lot')
+@@ -237,7 +238,24 @@
+
+ query = super(Move, cls).compute_quantities_query(
+ location_ids, with_childs=with_childs, grouping=grouping,
+- grouping_filter=grouping_filter)
++ grouping_filter=grouping_filter, quantity_field=quantity_field)
++
++
++ return query
++
++ # We avoid this part of code, and pass responsability to user to
++ # remove expired products from stock locations.
++ # This code had several problems and add inconsitence what you get
++ # in client and what you get in code
++ # In client you get all stock
++ # In code you get all stock without quanities expired
++ # Code tries to remove all quantities from expired products but
++ # introduces some issues on stock_supply procedure.
++ # - he substract all quantities from beginning to start_day,
++ # every day of planning
++ # - Even If you do not configure expired quantity, has anormal
++ # results in stock.
++
+
+ context = Transaction().context
+ today = Date.today()