Commit 34e52cbd authored by Kazuhiko Shiozaki's avatar Kazuhiko Shiozaki

move comparison part to _compare() and use it in both explain() and compare().


git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@30690 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent a80a5c22
...@@ -91,37 +91,76 @@ class FloatDivergenceTester(Predicate): ...@@ -91,37 +91,76 @@ class FloatDivergenceTester(Predicate):
NOTE: should we provide compatibility here ? NOTE: should we provide compatibility here ?
""" """
tested_property = self.getTestedProperty() delivery_movement = simulation_movement.getDeliveryValue()
delivery_mvt = simulation_movement.getDeliveryValue() compare_result = self._compare(simulation_movement, delivery_movement)
delivery_mvt_property = delivery_mvt.getProperty(tested_property) if compare_result is None:
if simulation_movement.isPropertyRecorded(tested_property): return None
simulation_mvt_property = simulation_movement.getRecordedProperty(tested_property)
if isinstance(simulation_mvt_property, (list, tuple)):
simulation_mvt_property = simulation_mvt_property[0]
else: else:
simulation_mvt_property = simulation_movement.getProperty(tested_property) prevision_value, decision_value, message, mapping = compare_result
def getErrorMessage(message, mapping):
return DivergenceMessage( return DivergenceMessage(
# XXX do we still need divergence_scope ? object_relative_url=delivery_movement.getRelativeUrl(),
divergence_scope='property',
object_relative_url=delivery_mvt.getRelativeUrl(),
simulation_movement=simulation_movement, simulation_movement=simulation_movement,
decision_value=delivery_mvt_property, decision_value=decision_value,
prevision_value=simulation_mvt_property, prevision_value=prevision_value,
tested_property=tested_property, tested_property=self.getTestedProperty(),
message=message, message=message,
mapping=mapping mapping=mapping
) )
delta = delivery_mvt_property - simulation_mvt_property def generateHashKey(self, movement):
"""
Returns a hash key which can be used to optimise the
matching algorithm between movements. The purpose
of this hash key is to reduce the size of lists of
movements which need to be compared using the compare
method (quadratic complexity).
If decision_movement is a simulation movement, use
the recorded properties instead of the native ones.
"""
raise NotImplementedError
def compare(self, prevision_movement, decision_movement):
"""
Returns True if simulation_movement and delivery_movement
match. Returns False else. The method is asymmetric and
the order of parameter matters. For example, a sourcing
rule may use a tester which makes sure that movements are
delivered no sooner than 2 weeks before production but
no later than the production date.
If decision_movement is a simulation movement, use
the recorded properties instead of the native ones.
prevision_movement -- a simulation movement (prevision)
decision_movement -- a delivery movement (decision)
"""
return (self._compare(prevision_movement, decision_movement) is None)
def _compare(self, prevision_movement, decision_movement):
"""
If prevision_movement and decision_movement dont match, it returns a
list : (prevision_value, decision_value, message, mapping)
"""
tested_property = self.getTestedProperty()
decision_value = decision_movement.getProperty(tested_property)
if prevision_movement.isPropertyRecorded(tested_property):
prevision_value = prevision_movement.getRecordedProperty(tested_property)
if isinstance(prevision_value, (list, tuple)):
prevision_value = prevision_value[0]
else:
prevision_value = prevision_movement.getProperty(tested_property)
delta = decision_value - prevision_value
# XXX we should use appropriate property sheets and getter methods # XXX we should use appropriate property sheets and getter methods
# for these properties. # for these properties.
absolute_tolerance_min = self.getProperty('quantity_range_min') or \ absolute_tolerance_min = self.getProperty('quantity_range_min') or \
self.getProperty('quantity') self.getProperty('quantity')
if absolute_tolerance_min is not None and \ if absolute_tolerance_min is not None and \
delta < absolute_tolerance_min: delta < absolute_tolerance_min:
return getErrorMessage( return (
prevision_value, decision_value,
'The difference of ${prperty_name} between decision and prevision is less than ${value}.', 'The difference of ${prperty_name} between decision and prevision is less than ${value}.',
dict(property_name=tested_property, dict(property_name=tested_property,
value=absolute_tolerance_min)) value=absolute_tolerance_min))
...@@ -129,7 +168,8 @@ class FloatDivergenceTester(Predicate): ...@@ -129,7 +168,8 @@ class FloatDivergenceTester(Predicate):
self.getProperty('quantity') self.getProperty('quantity')
if absolute_tolerance_max is not None and \ if absolute_tolerance_max is not None and \
delta > absolute_tolerance_max: delta > absolute_tolerance_max:
return getErrorMessage( return (
prevision_value, decision_value,
'The difference of ${prperty_name} between decision and prevision is larger than ${value}.', 'The difference of ${prperty_name} between decision and prevision is larger than ${value}.',
dict(property_name=tested_property, dict(property_name=tested_property,
value=absolute_tolerance_max)) value=absolute_tolerance_max))
...@@ -137,12 +177,12 @@ class FloatDivergenceTester(Predicate): ...@@ -137,12 +177,12 @@ class FloatDivergenceTester(Predicate):
tolerance_base = self.getProperty('tolerance_base') tolerance_base = self.getProperty('tolerance_base')
if tolerance_base == 'currency_precision': if tolerance_base == 'currency_precision':
try: try:
precision = simulation_movement.getSectionValue().getPriceCurrencyValue().getQuantityPrecision() precision = prevision_movement.getSectionValue().getPriceCurrencyValue().getQuantityPrecision()
base = 10 ** -precision base = 10 ** -precision
except AttributeError: except AttributeError:
base = None base = None
elif tolerance_base == 'quantity': elif tolerance_base == 'quantity':
base = simulation_mvt_property base = prevision_value
else: else:
base = None base = None
if base is not None: if base is not None:
...@@ -151,12 +191,14 @@ class FloatDivergenceTester(Predicate): ...@@ -151,12 +191,14 @@ class FloatDivergenceTester(Predicate):
if relative_tolerance_min is not None and \ if relative_tolerance_min is not None and \
delta < relative_tolerance_min * base: delta < relative_tolerance_min * base:
if tolerance_base == 'price_currency': if tolerance_base == 'price_currency':
return getErrorMessage( return (
prevision_value, decision_value,
'The difference of ${prperty_name} between decision and prevision is less than ${value} times of the currency precision.', 'The difference of ${prperty_name} between decision and prevision is less than ${value} times of the currency precision.',
dict(property_name=tested_property, dict(property_name=tested_property,
value=relative_tolerance_min)) value=relative_tolerance_min))
else: else:
return getErrorMessage( return (
prevision_value, decision_value,
'The difference of ${prperty_name} between decision and prevision is less than ${value} times of the prevision value.', 'The difference of ${prperty_name} between decision and prevision is less than ${value} times of the prevision value.',
dict(property_name=tested_property, dict(property_name=tested_property,
value=relative_tolerance_min)) value=relative_tolerance_min))
...@@ -165,51 +207,23 @@ class FloatDivergenceTester(Predicate): ...@@ -165,51 +207,23 @@ class FloatDivergenceTester(Predicate):
if relative_tolerance_max is not None and \ if relative_tolerance_max is not None and \
delta < relative_tolerance_max * base: delta < relative_tolerance_max * base:
if tolerance_base == 'price_currency': if tolerance_base == 'price_currency':
return getErrorMessage( return (
prevision_value, decision_value,
'The difference of ${prperty_name} between decision and prevision is less than ${value} times of the currency precision.', 'The difference of ${prperty_name} between decision and prevision is less than ${value} times of the currency precision.',
dict(property_name=tested_property, dict(property_name=tested_property,
value=relative_tolerance_max)) value=relative_tolerance_max))
else: else:
return getErrorMessage( return (
prevision_value, decision_value,
'The difference of ${prperty_name} between decision and prevision is less than ${value} times of the prevision value.', 'The difference of ${prperty_name} between decision and prevision is less than ${value} times of the prevision value.',
dict(property_name=tested_property, dict(property_name=tested_property,
value=relative_tolerance_max)) value=relative_tolerance_max))
return None
# XXX the followings are not treated yet: # XXX the followings are not treated yet:
# * decimal_alignment_enabled # * decimal_alignment_enabled
# * decimal_rounding_option # * decimal_rounding_option
# * decimal_exponent # * decimal_exponent
def generateHashKey(self, movement):
"""
Returns a hash key which can be used to optimise the
matching algorithm between movements. The purpose
of this hash key is to reduce the size of lists of
movements which need to be compared using the compare
method (quadratic complexity).
If decision_movement is a simulation movement, use
the recorded properties instead of the native ones.
"""
raise NotImplementedError
def compare(self, prevision_movement, decision_movement):
"""
Returns True if simulation_movement and delivery_movement
match. Returns False else. The method is asymmetric and
the order of parameter matters. For example, a sourcing
rule may use a tester which makes sure that movements are
delivered no sooner than 2 weeks before production but
no later than the production date.
If decision_movement is a simulation movement, use
the recorded properties instead of the native ones.
prevision_movement -- a simulation movement (prevision)
decision_movement -- a delivery movement (decision)
"""
raise NotImplementedError
def update(self, prevision_movement, decision_movement): def update(self, prevision_movement, decision_movement):
""" """
Updates decision_movement with properties from Updates decision_movement with properties from
......
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