Transformation.py 12.8 KB
Newer Older
Jean-Paul Smets's avatar
Jean-Paul Smets committed
1 2 3 4
##############################################################################
#
# Copyright (c) 2002 Coramy SAS and Contributors. All Rights Reserved.
#                    Thierry_Faucher <Thierry_Faucher@coramy.com>
5 6
# Copyright (c) 2004 Nexedi SARL and Contributors. All Rights Reserved.
#                    Romain Courteaud <romain@nexedi.com>
Jean-Paul Smets's avatar
Jean-Paul Smets committed
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
#
# 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.
#
##############################################################################

from Globals import InitializeClass, PersistentMapping
from AccessControl import ClassSecurityInfo

from Products.ERP5Type import Permissions, PropertySheet, Constraint, Interface
from Products.ERP5Type.XMLObject import XMLObject
from Products.ERP5Type.Utils import asList, keepIn, rejectIn

from Products.ERP5.Variated import Variated

40
from Products.ERP5.Document.Domain import Domain
Jean-Paul Smets's avatar
Jean-Paul Smets committed
41

42 43 44
from Globals import InitializeClass
from Products.PythonScripts.Utility import allow_class

45
import string
46
from Products.CMFCategory.Renderer import Renderer
Jean-Paul Smets's avatar
Jean-Paul Smets committed
47 48 49 50 51 52 53 54 55
from zLOG import LOG

class Transformation(XMLObject, Domain, Variated):
    """
      Build of material - contains a list of transformed resources

      Use of default_resource... (to define the variation range,
      to ...)

56 57
      XXX Transformation works only for a miximum of 3 variation base category...
      Matrixbox must be rewrite for a clean implementation of n base category
Jean-Paul Smets's avatar
Jean-Paul Smets committed
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74

    """

    meta_type = 'ERP5 Transformation'
    portal_type = 'Transformation'

    # Declarative security
    security = ClassSecurityInfo()
    security.declareObjectProtected(Permissions.View)

    # Declarative properties
    property_sheets = ( PropertySheet.Base
                      , PropertySheet.XMLObject
                      , PropertySheet.CategoryCore
                      , PropertySheet.DublinCore
                      , PropertySheet.VariationRange
                      , PropertySheet.Domain
75 76 77
                      #, PropertySheet.Resource
                      , PropertySheet.TransformedResource
                      , PropertySheet.Path
Jean-Paul Smets's avatar
Jean-Paul Smets committed
78 79 80 81 82 83
                      , PropertySheet.Transformation
                      )

    # Declarative interfaces
    __implements__ = ( Interface.Variated, )

84 85 86 87 88 89 90

    security.declareProtected(Permissions.AccessContentsInformation, 'updateVariationCategoryList')
    def updateVariationCategoryList(self):
      """
        Check if variation category list of the resource changed and update transformation
        and transformation line
      """
91
      self.setVariationBaseCategoryList(self.getVariationBaseCategoryList())
92 93 94 95 96
      transformation_line_list = self.contentValues()
      for transformation_line in transformation_line_list:
        transformation_line.updateVariationCategoryList()

    security.declareProtected(Permissions.AccessContentsInformation, 'getVariationRangeBaseCategoryList')
Jean-Paul Smets's avatar
Jean-Paul Smets committed
97 98 99
    def getVariationRangeBaseCategoryList(self):
        """
          Returns possible variation base_category ids of the
100 101
          default resource which can be used a variation axis
          in the transformation. 
Jean-Paul Smets's avatar
Jean-Paul Smets committed
102
        """
103
        resource = self.getResourceValue()
Jean-Paul Smets's avatar
Jean-Paul Smets committed
104 105 106
        if resource is not None:
          result = resource.getVariationBaseCategoryList()
        else:
107 108 109 110
          # XXX result = self.getBaseCategoryIds()
          # Why calling this method ?
          # Get a global variable which define a list of variation base category
          result = self.getPortalVariationBaseCategoryList()
Jean-Paul Smets's avatar
Jean-Paul Smets committed
111 112
        return result

113
    security.declareProtected(Permissions.AccessContentsInformation, 'getVariationRangeBaseCategoryItemList')
Jean-Paul Smets's avatar
Jean-Paul Smets committed
114 115
    def getVariationRangeBaseCategoryItemList(self):
        """
116
          Returns possible variations of the transformation
Jean-Paul Smets's avatar
Jean-Paul Smets committed
117 118 119 120
          as a list of tuples (id, title). This is mostly
          useful in ERP5Form instances to generate selection
          menus.
        """
121 122
        return self.portal_categories.getItemList( self.getVariationRangeBaseCategoryList() )

Jean-Paul Smets's avatar
Jean-Paul Smets committed
123

124
    security.declareProtected(Permissions.AccessContentsInformation,'getVariationRangeCategoryList')
125
    def getVariationRangeCategoryList(self, base_category_list=()):
Jean-Paul Smets's avatar
Jean-Paul Smets committed
126
        """
127 128 129 130 131 132 133
          Returns possible variation category values for the
          transformation according to the default resource.
          Possible category values is provided as a list of
          id.
          User may want to define generic transformation without
          any resource define.
          Result is left display.
Jean-Paul Smets's avatar
Jean-Paul Smets committed
134
        """
135 136 137 138 139
        if base_category_list is ():
          base_category_list = self.getVariationBaseCategoryList()

        resource = self.getResourceValue()
        if resource != None:
140 141 142
          result = resource.getVariationCategoryList(
                                        base_category_list=base_category_list,
                                        omit_individual_variation=0)
143 144 145 146
        else:
          # No resource is define on transformation. We want to display content of base categories
          result = self.portal_categories.getCategoryChildList(base_category_list, base=1)
        return result
Jean-Paul Smets's avatar
Jean-Paul Smets committed
147

148
    security.declareProtected(Permissions.AccessContentsInformation,'getVariationRangeCategoryItemList')
149 150
    def getVariationRangeCategoryItemList(self, base_category_list=(),
                                          display_base_category=1):
Jean-Paul Smets's avatar
Jean-Paul Smets committed
151 152 153 154 155 156 157
        """
          Returns possible variation category values for the
          transformation according to the default resource.
          Possible category values is provided as a list of
          tuples (id, title). This is mostly
          useful in ERP5Form instances to generate selection
          menus.
158 159
          User may want to define generic transformation without
          any resource define.
Jean-Paul Smets's avatar
Jean-Paul Smets committed
160 161 162
        """
        if base_category_list is ():
          base_category_list = self.getVariationBaseCategoryList()
163 164 165

        resource = self.getResourceValue()
        if resource != None:
166 167 168 169
          result = resource.getVariationCategoryItemList(
                                  base_category_list=base_category_list,
                                  omit_individual_variation=0,
                                  display_base_category=display_base_category)
170 171 172
        else:
          # No resource is define on transformation. We want to display content of base categories
          result = self.portal_categories.getCategoryChildTitleItemList(base_category_list, base=1, display_none_category=0)
Jean-Paul Smets's avatar
Jean-Paul Smets committed
173 174
        return result

175 176
    security.declareProtected(Permissions.AccessContentsInformation, 'getVariationBaseCategoryItemList')
    def getVariationBaseCategoryItemList(self):
Jean-Paul Smets's avatar
Jean-Paul Smets committed
177
      """
178
        Returns a list of base_category tuples for this tranformation
Jean-Paul Smets's avatar
Jean-Paul Smets committed
179
      """
180
      return self.portal_categories.getItemList(self.getVariationBaseCategoryList())
Jean-Paul Smets's avatar
Jean-Paul Smets committed
181

182 183 184

    security.declareProtected(Permissions.AccessContentsInformation, '_setVariationBaseCategoryList')
    def _setVariationBaseCategoryList(self, value):
Jean-Paul Smets's avatar
Jean-Paul Smets committed
185
      """
186
        Define the possible base categories
Jean-Paul Smets's avatar
Jean-Paul Smets committed
187
      """
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
#      XXX TransformedResource works only for a maximum of 3 variation base category...
#      Matrixbox must be rewrite for a clean implementation of n base category
      if len(value) <= 3:
        self._baseSetVariationBaseCategoryList(value)
      else:
        raise MoreThan3VariationBaseCategory

      # create relations between resource variation and transformation
      self._setVariationCategoryList( self.getVariationRangeCategoryList() )

    security.declareProtected(Permissions.AccessContentsInformation, 'setVariationBaseCategoryList')
    def setVariationBaseCategoryList(self, value):
      """
        Define the possible base categories and reindex object
      """
      self._setVariationBaseCategoryList(value)
      self.reindexObject()

    security.declareProtected(Permissions.AccessContentsInformation, 'getVariationCategoryItemList')
207 208 209
    def getVariationCategoryItemList(self, base_category_list=(), base=1, 
                                     display_id='title', 
                                     current_category=None):
210 211 212 213 214 215 216 217 218
      """
        Returns the list of possible variations
        XXX Copied and modified from Variated
        Result is left display.
      """
      variation_category_item_list = []
      if base_category_list == ():
        base_category_list = self.getVariationBaseCategoryList()

219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243
      for base_category in base_category_list:
        variation_category_list = self.getVariationCategoryList(
                                            base_category_list=[base_category])

        resource_list = [self.portal_categories.resolveCategory(x) for x in\
                         variation_category_list]
        category_list = [x for x in resource_list \
                         if x.getPortalType() == 'Category']
        variation_category_item_list.extend(Renderer(
                               is_right_display=0,
                               display_base_category=1,
                               display_none_category=0, base=base,
                               current_category=current_category,
                               display_id='logical_path').\
                                                 render(category_list))
        object_list = [x for x in resource_list \
                         if x.getPortalType() != 'Category']
        variation_category_item_list.extend(Renderer(
                               is_right_display=0,
                               display_base_category=1,
                               base_category=base_category, 
                               display_none_category=0, base=base,
                               current_category=current_category,
                               display_id=display_id).\
                                                 render(object_list))
244 245
      return variation_category_item_list

Jean-Paul Smets's avatar
Jean-Paul Smets committed
246 247 248
    security.declareProtected(Permissions.AccessContentsInformation, 'getAggregatedAmountList')
    def getAggregatedAmountList(self, context=None, REQUEST=None, **kw):
      """
249
        getAggregatedAmountList returns a AggregatedAmountList which can be used
Jean-Paul Smets's avatar
Jean-Paul Smets committed
250 251 252
        either to do some calculation (ex. price, BOM) or to display
        a detailed view of a transformation.
      """
253
      context = self.asContext(context=context, REQUEST=REQUEST, **kw)
Jean-Paul Smets's avatar
Jean-Paul Smets committed
254
      # First we need to get the list of transformations which this transformation depends on
255 256 257
      # XXX At this moment, we only consider 1 dependency
      template_transformation_list = self.getSpecialiseValueList()

258
      result = AggregatedAmountList()
Jean-Paul Smets's avatar
Jean-Paul Smets committed
259 260 261 262

      # Browse all involved transformations and create one line per line of transformation
      # Currently, we do not consider abstractions, we just add whatever we find in all
      # transformations
263
      for transformation in [self] + template_transformation_list:
264
        # Browse each transformed or assorted resource of the current transformation
265
        for transformation_line in transformation.objectValues():
266

267
          result.extend( transformation_line.getAggregatedAmountList(context) )
268 269 270

      return result

271 272 273
# XXX subclassing directly list would be better, but does not work yet (error with class and security)
from UserList import UserList
class AggregatedAmountList(UserList):
274 275 276 277 278 279
  """
    Temporary object needed to aggregate Amount value
    And to calculate some report or total value
  """
  meta_type = "AggregatedAmountList"
  security = ClassSecurityInfo()
280
#  security.declareObjectPublic()
281

282 283
  security.declarePublic('getTotalPrice')
  def getTotalPrice(self):
284 285 286
    """
      Return total bas price of the transformation
    """
287
    result = sum( filter(lambda y: y is not None  ,map( lambda x: x.getTotalPrice(), self)) )
288 289 290 291 292 293 294 295 296 297 298 299
    return result

  security.declarePublic('getTotalDuration')
  def getTotalDuration(self):
    """
      Return total duration of the transformation
    """
    result = sum( filter(lambda y: y is not None  ,map( lambda x: x.getDuration(), self) ))
    return result
  
InitializeClass(AggregatedAmountList)
allow_class(AggregatedAmountList)