It's essential to be clear about why you want to use Odoo Project and what your goals are.
Indeed, there are many ways to manage a project, to find the best one for you, you need to know exactly what you want to achieve. And later on, we will hopefully transform your objectives into real improvements for your company.
@@ -83,7 +83,7 @@
The Odoo Project app can be used to manage many activities, from the development of a new product to the daily operations of a customer support. With some creativity, it can even be used to manage your marketing communications or personal projects. But just because it can be done doesn't mean it's always a good idea: let's start by helping you understand what can be a good project. Depending on what you need and how you want to operate, there are several ways to work with Odoo. First, decide if you want to think in terms of tasks or issues. Then, activate the Timesheets app if you need it.
A good inventory management aims to optimize stock levels: not too low (or
you may find yourself out of stock) and not too high (your products occupy
diff --git a/addons/stock/models/product.py b/addons/stock/models/product.py
index f7f0ab75d32..c0094aea3c3 100644
--- a/addons/stock/models/product.py
+++ b/addons/stock/models/product.py
@@ -507,6 +507,8 @@ class ProductTemplate(models.Model):
done_moves = self.env['stock.move'].search([('product_id', 'in', updated.mapped('product_variant_ids').ids)], limit=1)
if done_moves:
raise UserError(_("You can not change the unit of measure of a product that has already been used in a done stock move. If you need to change the unit of measure, you may deactivate this product."))
+ if 'type' in vals and vals['type'] != 'product' and sum(self.mapped('nbr_reordering_rules')) != 0:
+ raise UserError(_('You still have some active reordering rules on this product. Please archive or delete them first.'))
return super(ProductTemplate, self).write(vals)
@api.multi
diff --git a/odoo/addons/test_impex/tests/test_export.py b/odoo/addons/test_impex/tests/test_export.py
index 861e7dd1661..226ba9943f6 100644
--- a/odoo/addons/test_impex/tests/test_export.py
+++ b/odoo/addons/test_impex/tests/test_export.py
@@ -304,12 +304,13 @@ class test_m2o(CreatorCase):
[[False]])
def test_basic(self):
- """ Exported value is empty
+ """ Exported value is the name_get of the related object
"""
record = self.env['export.integer'].create({'value': 42})
+ name = dict(record.name_get())[record.id]
self.assertEqual(
self.export(record.id),
- [['']])
+ [[name]])
def test_path(self):
""" Can recursively export fields of m2o via path
@@ -351,13 +352,14 @@ class test_o2m(CreatorCase):
def test_single(self):
self.assertEqual(
self.export([(0, False, {'value': 42})]),
- [['']])
+ # name_get result
+ [[u'export.one2many.child:42']])
def test_single_subfield(self):
self.assertEqual(
self.export([(0, False, {'value': 42})],
fields=['value', 'value/value']),
- [['', u'42']])
+ [[u'export.one2many.child:42', u'42']])
def test_integrate_one_in_parent(self):
self.assertEqual(
@@ -379,13 +381,9 @@ class test_o2m(CreatorCase):
def test_multiple_records_name(self):
self.assertEqual(
self.export(self.commands, fields=['const', 'value']),
- [
- [u'4', ''],
- ['', ''],
- ['', ''],
- ['', ''],
- ['', ''],
- ])
+ [[
+ u'4', u','.join(self.names)
+ ]])
def test_multiple_records_id(self):
export = self.export(self.commands, fields=['const', 'value/.id'])
@@ -403,18 +401,14 @@ class test_o2m(CreatorCase):
def test_multiple_records_with_name_before(self):
self.assertEqual(
self.export(self.commands, fields=['const', 'value', 'value/value']),
- [
- [u'4', '', u'4'],
- ['', '', u'42'],
- ['', '', u'36'],
- ['', '', u'4'],
- ['', '', u'13'],
- ])
+ [[ # exports sub-fields of very first o2m
+ u'4', u','.join(self.names), u'4'
+ ]])
def test_multiple_records_with_name_after(self):
self.assertEqual(
self.export(self.commands, fields=['const', 'value/value', 'value']),
- [
+ [ # completely ignores name_get request
[u'4', u'4', ''],
['', u'42', ''],
['', u'36', ''],
@@ -465,16 +459,16 @@ class test_o2m_multiple(CreatorCase):
def test_single_per_side(self):
self.assertEqual(
self.export(child1=False, child2=[(0, False, {'value': 42})]),
- [[False, '']])
+ [[False, u'export.one2many.child.2:42']])
self.assertEqual(
self.export(child1=[(0, False, {'value': 43})], child2=False),
- [['', False]])
+ [[u'export.one2many.child.1:43', False]])
self.assertEqual(
self.export(child1=[(0, False, {'value': 43})],
child2=[(0, False, {'value': 42})]),
- [['', '']])
+ [[u'export.one2many.child.1:43', u'export.one2many.child.2:42']])
def test_single_integrate_subfield(self):
fields = ['const', 'child1/value', 'child2/value']
@@ -561,13 +555,14 @@ class test_m2m(CreatorCase):
def test_single(self):
self.assertEqual(
self.export([(0, False, {'value': 42})]),
- [['']])
+ # name_get result
+ [[u'export.many2many.other:42']])
def test_single_subfield(self):
self.assertEqual(
self.export([(0, False, {'value': 42})],
fields=['value', 'value/value']),
- [['', u'42']])
+ [[u'export.many2many.other:42', u'42']])
def test_integrate_one_in_parent(self):
self.assertEqual(
@@ -589,13 +584,10 @@ class test_m2m(CreatorCase):
def test_multiple_records_name(self):
self.assertEqual(
self.export(self.commands, fields=['const', 'value']),
- [
- [u'4', ''],
- ['', ''],
- ['', ''],
- ['', ''],
- ['', ''],
- ])
+ [[ # FIXME: hardcoded comma, import uses config.csv_internal_sep
+ # resolution: remove configurable csv_internal_sep
+ u'4', u','.join(self.names)
+ ]])
# essentially same as o2m, so boring
diff --git a/odoo/models.py b/odoo/models.py
index 1796f74725e..b46e3e255f4 100644
--- a/odoo/models.py
+++ b/odoo/models.py
@@ -805,8 +805,14 @@ class BaseModel(object):
for j, val in enumerate(lines2[0]):
if val or isinstance(val, bool):
current[j] = val
- # append the other lines at the end
- lines += lines2[1:]
+ # check value of current field
+ if not current[i] and not isinstance(current[i], bool):
+ # assign xml_ids, and forget about remaining lines
+ xml_ids = [item[1] for item in value.name_get()]
+ current[i] = ','.join(xml_ids)
+ else:
+ # append the other lines at the end
+ lines += lines2[1:]
else:
current[i] = False
1. Learn about Tasks, Issues and Timesheets.