Commit 5b7eeb7f authored by Yusei Tahara's avatar Yusei Tahara

Fix a typo.

Add precision property to make rounding system compatible with float
field. So, decimal exponent property is no longer required.
Add a basic test case.


git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@34256 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent 13b8b932
...@@ -53,9 +53,8 @@ class RoundingModel(Predicate): ...@@ -53,9 +53,8 @@ class RoundingModel(Predicate):
security.declareProtected(Permissions.AccessContentsInformation, 'roundValue') security.declareProtected(Permissions.AccessContentsInformation, 'roundValue')
def roundValue(self, value): def roundValue(self, value):
""" if not value:
Return rounded value. return value
"""
if self.getRoundingMethodId() is not None: if self.getRoundingMethodId() is not None:
rounding_method = getattr(self, self.getRoundingMethodId(), None) rounding_method = getattr(self, self.getRoundingMethodId(), None)
if rounding_method is None: if rounding_method is None:
...@@ -67,10 +66,21 @@ class RoundingModel(Predicate): ...@@ -67,10 +66,21 @@ class RoundingModel(Predicate):
if (decimal_rounding_option is None or if (decimal_rounding_option is None or
decimal_rounding_option not in ROUNDING_OPTION_DICT): decimal_rounding_option not in ROUNDING_OPTION_DICT):
raise ValueError, 'Decimal rounding option must be selected.' raise ValueError, 'Decimal rounding option must be selected.'
def rounding_method(value, decimal_exponent): def rounding_method(value, decimal_exponent, precision):
return float(Decimal(str(value)).quantize(Decimal(decimal_exponent), if decimal_exponent is None and precision is not None:
rounding=decimal_rounding_option)) if precision > 0:
return rounding_method(value, self.getDecimalExponent()) decimal_exponent = '1.' + '0' * precision
else:
decimal_exponent = '1'
result = float(
Decimal(str(value)).quantize(Decimal(decimal_exponent),
rounding=decimal_rounding_option))
if precision < 0:
# FIXME!!!!!
result = round(result, precision)
return result
return rounding_method(value, self.getDecimalExponent(), self.getPrecision())
security.declareProtected(Permissions.AccessContentsInformation, 'getRoundingProxy') security.declareProtected(Permissions.AccessContentsInformation, 'getRoundingProxy')
def getRoundingProxy(self, document): def getRoundingProxy(self, document):
...@@ -115,10 +125,22 @@ class RoundingModel(Predicate): ...@@ -115,10 +125,22 @@ class RoundingModel(Predicate):
def _getOriginalDocument(self): def _getOriginalDocument(self):
if isinstance(original_document, RoundingProxy): if isinstance(original_document, RoundingProxy):
return original_document._editOriginalDocument() return original_document._getOriginalDocument()
else: else:
return original_document return original_document
def getRoundingModelPrecision(self, property_id):
"""
Return precision value of rounding model. This is useful for
float field.
"""
if property_id in rounding_model.getRoundedPropertyIdList():
return rounding_model.getPrecision()
elif isinstance(original_document, RoundingProxy):
return original_document.getRoundingModelPrecision(property_id)
else:
return None
def __getattr__(self, name): def __getattr__(self, name):
attribute = getattr(original_document, name) attribute = getattr(original_document, name)
if getattr(attribute, 'DUMMY_ROUNDING_METHOD_MARK', None) is DUMMY_ROUNDING_METHOD_MARK: if getattr(attribute, 'DUMMY_ROUNDING_METHOD_MARK', None) is DUMMY_ROUNDING_METHOD_MARK:
......
...@@ -46,4 +46,10 @@ class RoundingModel(DecimalOption): ...@@ -46,4 +46,10 @@ class RoundingModel(DecimalOption):
'mode' : 'w', 'mode' : 'w',
'default' : None, 'default' : None,
}, },
{ 'id' : 'precision',
'description' : 'Precision value to be used for rounding. Rounding model accepts negative precision value as same as built-in round function.',
'type' : 'int',
'mode' : 'w',
'default' : None,
},
) )
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (c) 2010 Nexedi KK, Nexedi SA and Contributors. All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
import unittest
from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase
import transaction
class TestRoundingTool(ERP5TypeTestCase):
"""
Rounding Tool Test
"""
def getTitle(self):
return 'Rounding Tool Test'
def getBusinessTemplateList(self):
return ('erp5_base',
'erp5_pdm',
'erp5_trade',
)
def afterSetUp(self):
if getattr(self.portal, '_run_after_setup', None) is not None:
return
self.portal._run_after_setup = True
user_folder = self.portal.acl_users
user_folder._doAddUser('developer', '', ['Manager'], [])
user_folder._doAddUser('assignor', '', ['Auditor', 'Author', 'Assignor'], [])
transaction.commit()
self.tic()
def testBasicRounding(self):
"""
Test basic features of rounding tool
"""
rounding_tool = self.portal.portal_roundings
self.login('assignor')
sale_order = self.portal.sale_order_module.newContent(portal_type='Sale Order')
sale_order_line = sale_order.newContent(portal_type='Sale Order Line')
transaction.commit()
self.tic()
# check values of empty line
self.assertEqual(sale_order_line.getPrice(), None)
self.assertEqual(sale_order_line.getQuantity(), 0.0)
self.assertEqual(sale_order_line.getTotalPrice(), 0.0)
self.login('developer')
# rounding model dummy never match to sale order line
rounding_model_dummy= rounding_tool.newContent(portal_type='Rounding Model')
rounding_model_dummy.edit(decimal_rounding_option='ROUND_DOWN',
precision=2,
rounded_property_id_list=['price',
'quantity',
'total_price'])
rounding_model_dummy.setCriterionProperty('portal_type')
rounding_model_dummy.setCriterion('portal_type', identity=['Web Page'],
min='', max='')
# add a rounding model for price of sale order line
rounding_model_1 = rounding_tool.newContent(portal_type='Rounding Model')
rounding_model_1.edit(decimal_rounding_option='ROUND_DOWN',
precision=2,
rounded_property_id_list=['price'])
rounding_model_1.setCriterionProperty('portal_type')
rounding_model_1.setCriterion('portal_type', identity=['Sale Order Line'],
min='', max='')
self.login('assignor')
rounding_model_dummy.validate()
rounding_model_1.validate()
transaction.commit()
self.tic()
# rounding model does not do anything to empty values like None
wrapped_line = rounding_tool.getRoundingProxy(sale_order_line, sale_order_line)
self.assertEqual(wrapped_line.getPrice(), None)
self.assertEqual(wrapped_line.getQuantity(), 0.0)
self.assertEqual(wrapped_line.getTotalPrice(), 0.0)
self.assertEqual(wrapped_line.getRoundingModelPrecision('price'), 2)
self.assertEqual(wrapped_line.getRoundingModelPrecision('quantity'), None)
self.assertEqual(wrapped_line.getRoundingModelPrecision('total_price'), None)
transaction.commit()
self.tic()
# set values
sale_order_line.edit(price=123.456, quantity=78.91)
transaction.commit()
self.tic()
self.assertEqual(sale_order_line.getPrice(), 123.456)
self.assertEqual(sale_order_line.getQuantity(), 78.91)
self.assertEqual(sale_order_line.getTotalPrice(), 123.456*78.91)
# check if price is rounded
wrapped_line = rounding_tool.getRoundingProxy(sale_order_line, sale_order_line)
self.assertEqual(wrapped_line.getPrice(), 123.45)
self.assertEqual(wrapped_line.getQuantity(), 78.91)
self.assertEqual(wrapped_line.getTotalPrice(), 123.45*78.91)
self.assertEqual(wrapped_line.getRoundingModelPrecision('price'), 2)
self.assertEqual(wrapped_line.getRoundingModelPrecision('quantity'), None)
self.assertEqual(wrapped_line.getRoundingModelPrecision('total_price'), None)
# add a rounding model for quantity of any portal type
self.login('developer')
rounding_model_2 = rounding_tool.newContent(portal_type='Rounding Model')
rounding_model_2.edit(decimal_rounding_option='ROUND_UP',
precision=1,
rounded_property_id_list=['quantity'])
transaction.commit()
self.tic()
self.login('assignor')
# check if price and quantity are rounded
# if rounding model is not validated, then it is not applied
wrapped_line = rounding_tool.getRoundingProxy(sale_order_line, sale_order_line)
self.assertEqual(wrapped_line.getPrice(), 123.45)
self.assertEqual(wrapped_line.getQuantity(), 78.91)
self.assertEqual(wrapped_line.getTotalPrice(), 123.45*78.91)
self.assertEqual(wrapped_line.getRoundingModelPrecision('price'), 2)
self.assertEqual(wrapped_line.getRoundingModelPrecision('quantity'), None)
self.assertEqual(wrapped_line.getRoundingModelPrecision('total_price'), None)
# validate
rounding_model_2.validate()
transaction.commit()
self.tic()
# check if price and quantity are rounded
# now, rounding model is validated, so it is applied
wrapped_line = rounding_tool.getRoundingProxy(sale_order_line, sale_order_line)
self.assertEqual(wrapped_line.getPrice(), 123.45)
self.assertEqual(wrapped_line.getQuantity(), 79.0)
self.assertEqual(wrapped_line.getTotalPrice(), 123.45*79.0)
self.assertEqual(wrapped_line.getRoundingModelPrecision('price'), 2)
self.assertEqual(wrapped_line.getRoundingModelPrecision('quantity'), 1)
self.assertEqual(wrapped_line.getRoundingModelPrecision('total_price'), None)
# add a rounding model for total price of any portal type
self.login('developer')
rounding_model_3 = rounding_tool.newContent(portal_type='Rounding Model')
rounding_model_3.edit(decimal_rounding_option='ROUND_UP',
precision=-1,
rounded_property_id_list=['total_price'])
self.login('assignor')
rounding_model_3.validate()
transaction.commit()
self.tic()
# check if price and quantity and total price are rounded
wrapped_line = rounding_tool.getRoundingProxy(sale_order_line, sale_order_line)
self.assertEqual(wrapped_line.getPrice(), 123.45)
self.assertEqual(wrapped_line.getQuantity(), 79.0)
self.assertEqual(wrapped_line.getTotalPrice(), 9750.0)
self.assertEqual(wrapped_line.getRoundingModelPrecision('price'), 2)
self.assertEqual(wrapped_line.getRoundingModelPrecision('quantity'), 1)
self.assertEqual(wrapped_line.getRoundingModelPrecision('total_price'), -1)
def test_suite():
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestRoundingTool))
return suite
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment