diff --git a/CHANGELOG b/CHANGELOG index 6989d998a4..963d634e94 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,4 @@ +* Apply factor on domain parser * Use tab name in CSV Export/Import * Add bus management * Use CSS to style label diff --git a/tryton/common/domain_parser.py b/tryton/common/domain_parser.py index 55673f00b7..ff33f8f19e 100644 --- a/tryton/common/domain_parser.py +++ b/tryton/common/domain_parser.py @@ -241,20 +241,23 @@ def convert_value(field, value, context=None): return bool(value) def convert_float(): + factor = float(field.get('factor', 1)) try: - return locale.atof(value) + return locale.atof(value) / factor except (ValueError, AttributeError): return def convert_integer(): + factor = float(field.get('factor', 1)) try: - return int(locale.atof(value)) + return int(locale.atof(value) / factor) except (ValueError, AttributeError): return def convert_numeric(): + factor = Decimal(field.get('factor', 1)) try: - return locale.atof(value, Decimal) + return locale.atof(value, Decimal) / factor except (decimal.InvalidOperation, AttributeError): return @@ -348,6 +351,14 @@ def test_convert_float(): assert convert_value(field, value) == result +def test_convert_float_factor(): + field = { + 'type': 'float', + 'factor': '100', + } + assert convert_value(field, '42') == 0.42 + + def test_convert_integer(): field = { 'type': 'integer', @@ -362,6 +373,14 @@ def test_convert_integer(): assert convert_value(field, value) == result +def test_convert_integer_factor(): + field = { + 'type': 'integer', + 'factor': '2', + } + assert convert_value(field, '6') == 3 + + def test_convert_numeric(): field = { 'type': 'numeric', @@ -376,6 +395,14 @@ def test_convert_numeric(): assert convert_value(field, value) == result +def test_convert_numeric_factor(): + field = { + 'type': 'numeric', + 'factor': '5', + } + assert convert_value(field, '1') == Decimal('0.2') + + def test_convert_selection(): field = { 'type': 'selection', @@ -463,8 +490,9 @@ def format_value(field, value, target=None, context=None): return _('True') if value else _('False') def format_integer(): + factor = float(field.get('factor', 1)) if value or value is 0 or isinstance(value, float): - return str(int(value)) + return str(int(value * factor)) return '' def format_float(): @@ -472,11 +500,16 @@ def format_value(field, value, target=None, context=None): and value is not 0 and not isinstance(value, (float, Decimal))): return '' + if isinstance(value, Decimal): + cast = Decimal + else: + cast = float + factor = cast(field.get('factor', 1)) try: - digit = len(str(value).split('.')[1]) + digit = len(str(value * factor).rstrip('0').split('.')[1]) except IndexError: digit = 0 - return locale.format('%.*f', (digit, value or 0), True) + return locale.format('%.*f', (digit, value * factor or 0), True) def format_selection(): selections = dict(field['selection']) @@ -567,6 +600,14 @@ def test_format_integer(): assert format_value(field, value) == result +def test_format_integer_factor(): + field = { + 'type': 'integer', + 'factor': '2', + } + assert format_value(field, 3) == '6' + + def test_format_float(): field = { 'type': 'float', @@ -577,13 +618,21 @@ def test_format_float(): (1.50, '1.5'), (150.79, '150.79'), (0, '0'), - (0.0, '0.0'), + (0.0, '0'), (False, ''), (None, ''), ): assert format_value(field, value) == result +def test_format_float_factor(): + field = { + 'type': 'float', + 'factor': '100', + } + assert format_value(field, 0.42) == '42' + + def test_format_numeric(): field = { 'type': 'numeric', @@ -591,16 +640,24 @@ def test_format_numeric(): for value, result in ( (Decimal(1), '1'), (Decimal('1.5'), '1.5'), - (Decimal('1.50'), '1.50'), + (Decimal('1.50'), '1.5'), (Decimal('150.79'), '150.79'), (Decimal(0), '0'), - (Decimal('0.0'), '0.0'), + (Decimal('0.0'), '0'), (False, ''), (None, ''), ): assert format_value(field, value) == result +def test_format_numeric_factor(): + field = { + 'type': 'numeric', + 'factor': '5', + } + assert format_value(field, Decimal('0.2')) == '1' + + def test_format_selection(): field = { 'type': 'selection', @@ -1510,3 +1567,10 @@ def test_completion(): assert list(dom.completion('Name: !=foo')) == [] assert list(dom.completion('')) == ['Name: '] assert list(dom.completion(' ')) == ['', 'Name: '] + + +if __name__ == '__main__': + for name in list(globals()): + if name.startswith('test_'): + func = globals()[name] + func() diff --git a/tryton/gui/window/view_form/screen/screen.py b/tryton/gui/window/view_form/screen/screen.py index 3efdf36fe5..40db87e11e 100644 --- a/tryton/gui/window/view_form/screen/screen.py +++ b/tryton/gui/window/view_form/screen/screen.py @@ -180,11 +180,21 @@ class Screen(SignalEvent): # Filter only fields in XML view xml_dom = xml.dom.minidom.parseString(view_tree['arch']) root_node, = xml_dom.childNodes - xml_fields = [node_attributes(node).get('name') - for node in root_node.childNodes - if node.nodeName == 'field'] - fields = collections.OrderedDict( - (name, fields[name]) for name in xml_fields) + ofields = collections.OrderedDict() + for node in root_node.childNodes: + if node.nodeName != 'field': + continue + attributes = node_attributes(node) + name = attributes['name'] + # If a field is defined multiple times in the XML, + # take only the first definition + if name in ofields: + continue + ofields[name] = fields[name] + for attr in ['string', 'factor']: + if attributes.get(attr): + ofields[name][attr] = attributes[attr] + fields = ofields if 'active' in view_tree['fields']: self.screen_container.but_active.show()