Commit 4ef035a4 authored by Kazuhiko Shiozaki's avatar Kazuhiko Shiozaki

initial implement of test() and explain() in FloatDivergenceTester.


git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@30527 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent 1bc37152
...@@ -62,3 +62,194 @@ class FloatDivergenceTester(Predicate): ...@@ -62,3 +62,194 @@ class FloatDivergenceTester(Predicate):
, PropertySheet.DivergenceTester , PropertySheet.DivergenceTester
, PropertySheet.SolverSelection , PropertySheet.SolverSelection
) )
def test(self, simulation_movement):
"""
Tests if simulation_movement is divergent. Returns False (0)
or True (1).
If decision_movement is a simulation movement, use
the recorded properties instead of the native ones.
simulation_movement -- a simulation movement
"""
return self.explain(simulation_movement) is not None
def explain(self, simulation_movement):
"""
Returns a single message which explain the nature of
the divergence of simulation_movement with its related
delivery movement.
If decision_movement is a simulation movement, use
the recorded properties instead of the native ones.
simulation_movement -- a simulation movement
NOTE: this approach is incompatible with previous
API which was returning a list.
NOTE: should we provide compatibility here ?
"""
tested_property = self.getTestedProperty()
delivery_mvt = simulation_movement.getDeliveryValue()
delivery_mvt_property = delivery_mvt.getProperty(tested_property)
simulation_mvt_property = simulation_movement.getProperty(tested_property)
def getErrorMessage(message, mapping):
return DivergenceMessage(
# XXX do we still need divergence_scope ?
divergence_scope='property',
object_relative_url=delivery_mvt.getRelativeUrl(),
simulation_movement=simulation_movement,
decision_value=delivery_mvt_property,
prevision_value=simulation_mvt_property,
tested_property=tested_property,
message=message,
mapping=mapping
)
delta = delivery_mvt_property - simulation_mvt_property
# XXX we should use appropriate property sheets and getter methods
# for these properties.
absolute_tolerance_min = self.getProperty('quantity_range_min') or \
self.getProperty('quantity')
if absolute_tolerance_min is not None and \
delta < absolute_tolerance_min:
return getErrorMessage(
'The difference of ${prperty_name} between decision and prevision is less than ${value}.',
dict(property_name=tested_property,
value=absolute_tolerance_min))
absolute_tolerance_max = self.getProperty('quantity_range_max') or \
self.getProperty('quantity')
if absolute_tolerance_max is not None and \
delta > absolute_tolerance_max:
return getErrorMessage(
'The difference of ${prperty_name} between decision and prevision is larger than ${value}.',
dict(property_name=tested_property,
value=absolute_tolerance_max))
tolerance_base = self.getProperty('tolerance_base')
if tolerance_base == 'currency_precision':
try:
precision = simulation_movement.getSectionValue().getPriceCurrencyValue().getQuantityPrecision()
base = 10 ** -precision
except AttributeError:
base = None
elif tolerance_base == 'quantity':
base = simulation_mvt_property
else:
base = None
if base is not None:
relative_tolerance_min = self.getProperty('tolerance_range_min') or \
self.getProperty('tolerance')
if relative_tolerance_min is not None and \
delta < relative_tolerance_min * base:
if tolerance_base == 'price_currency':
return getErrorMessage(
'The difference of ${prperty_name} between decision and prevision is less than ${value} times of the currency precision.',
dict(property_name=tested_property,
value=relative_tolerance_min))
else:
return getErrorMessage(
'The difference of ${prperty_name} between decision and prevision is less than ${value} times of the prevision value.',
dict(property_name=tested_property,
value=relative_tolerance_min))
relative_tolerance_max = self.getProperty('tolerance_range_max') or \
self.getProperty('tolerance')
if relative_tolerance_max is not None and \
delta < relative_tolerance_max * base:
if tolerance_base == 'price_currency':
return getErrorMessage(
'The difference of ${prperty_name} between decision and prevision is less than ${value} times of the currency precision.',
dict(property_name=tested_property,
value=relative_tolerance_max))
else:
return getErrorMessage(
'The difference of ${prperty_name} between decision and prevision is less than ${value} times of the prevision value.',
dict(property_name=tested_property,
value=relative_tolerance_max))
# XXX the followings are not treated yet:
# * decimal_alignment_enabled
# * decimal_rounding_option
# * 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):
"""
Updates decision_movement with properties from
prevision_movement so that next call to
compare returns True. This method is normally
invoked to copy properties from simulation movements
to delivery movements. It is also invoked to copy
properties from temp simulation movements of
Aggregated Amount Lists to pre-existing simulation
movements.
If decision_movement is a simulation movement, then
do not update recorded properties.
prevision_movement -- a simulation movement (prevision)
decision_movement -- a delivery movement (decision)
NOTE: recorded (forced) properties are not updated by
expand.
NOTE2: it is still unknown how to update properties from
a simulation movement to the relevant level of
delivery / line / cell.
"""
raise NotImplementedError
def accept(self, simulation_movement):
"""
Copies the properties handled by the divergence tester
from the related delivery movement to simulation_movement.
NOTE: the future existence of this method is still unknown
because it is likely to be implemented in TargetSolver
instead.
"""
raise NotImplementedError
def adopt(self, simulation_movement):
"""
Copies the properties handled by the divergence tester
from simulation_movement to the related delivery movement
NOTE: the future existence of this method is still unknown
because it is likely to be implemented in TargetSolver
instead.
"""
raise NotImplementedError
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