movement_generator.py 5.38 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (c) 2010 Nexedi SA and Contributors. All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility 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
# guarantees 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
##############################################################################

from Products.ERP5.MovementCollectionDiff import _getPropertyAndCategoryList

class MovementGeneratorMixin:
  """Movement Generator interface specification

  Documents which implement IMovementGenerator
  can be used to generate an IMovementList from
  an existing IMovementCollection, IMovementList or
  IMovement. Typical IMovementGenerator are Rules
  and Trade Conditions.
  """

  # Implementation of IMovementGenerator
  def getGeneratedMovementList(context, movement_list=None, rounding=False):
    """
    Returns an IMovementList generated by a model applied to the context

    context - an IMovementCollection, an IMovementList or an IMovement

    movement_list - optional IMovementList which can be passed explicitely
                    whenever context is an IMovementCollection and whenever
                    we want to filter context.getMovementList

    rounding - boolean argument, which controls if rounding shall be applied on
               generated movements or not

    NOTE:
      - implement rounding appropriately (True or False seems
        simplistic)
    """
    raise NotImplementedError

  def _getInputMovementAndPathTupleList(self, context):
    """Returns list of tuples (movement, business_path)"""
    input_movement_list = self._getInputMovementList(context)
    business_process = context.getBusinessProcessValue()
65
    trade_phase_list = context.getSpecialiseValue().getTradePhaseList()
66 67

    # In non-BPM case, we have no business path.
68
    if business_process is None or len(trade_phase_list) == 0:
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
      return [(input_movement, None) for input_movement in input_movement_list]

    input_movement_and_path_list = []
    business_path_list = []
    for input_movement in input_movement_list:
      for business_path in business_process.getPathValueList(
                          trade_phase_list,
                          input_movement):
        input_movement_and_path_list.append((input_movement, business_path))
        business_path not in business_path_list and business_path_list \
            .append(business_path)

    return input_movement_and_path_list

  def _getInputMovementList(self, context):
    raise NotImplementedError

86 87 88 89 90
  def _getPropertyAndCategoryList(self, movement, business_path, rule=None):
    if rule is None:
      property_dict = _getPropertyAndCategoryList(movement)
    else:
      property_dict = {}
91
      for tester in rule._getUpdatingTesterList(exclude_quantity=False):
92 93
        property_dict.update(tester.getUpdatablePropertyDict(
          movement, None))
94 95 96 97 98

    if business_path is None:
      return property_dict

    # Arrow
99 100 101 102
    for base_category, category_url_list in \
            business_path.getArrowCategoryDict(context=movement).iteritems():
      property_dict[base_category] = category_url_list

103 104 105 106 107 108 109 110 111
    # Amount
    if business_path.getQuantity():
      property_dict['quantity'] = business_path.getQuantity()
    elif business_path.getEfficiency():
      property_dict['quantity'] = movement.getQuantity() *\
        business_path.getEfficiency()
    else:
      property_dict['quantity'] = movement.getQuantity()

112 113 114
    movement_start_date = movement.getStartDate()
    movement_stop_date = movement.getStopDate()
    if movement_start_date == movement_stop_date:
115 116 117 118 119 120 121
      property_dict['start_date'] = business_path.getExpectedStartDate(
          movement)
      property_dict['stop_date'] = business_path.getExpectedStopDate(movement)
      # in case of not fully working BPM get dates from movement
      # XXX: as soon as BPM will be fully operational this hack will not be
      #      needed anymore
      if property_dict['start_date'] is None:
122
        property_dict['start_date'] = movement_start_date
123
      if property_dict['stop_date'] is None:
124
        property_dict['stop_date'] = movement_stop_date
125 126
    else: # XXX shall not be used, but business_path.getExpectedStart/StopDate
          # do not works on second path...
127 128
      property_dict['start_date'] = movement_start_date
      property_dict['stop_date'] = movement_stop_date
129 130

    # save a relation to business path
131
    property_dict['causality'] = [business_path.getRelativeUrl()]
132 133

    return property_dict