Transformation.py 13 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
    isMovement = 1 # XXX very stupid, but for doing a test on catalog
Jean-Paul Smets's avatar
Jean-Paul Smets committed
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75

    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
76 77 78
                      #, PropertySheet.Resource
                      , PropertySheet.TransformedResource
                      , PropertySheet.Path
Jean-Paul Smets's avatar
Jean-Paul Smets committed
79 80 81 82 83 84
                      , PropertySheet.Transformation
                      )

    # Declarative interfaces
    __implements__ = ( Interface.Variated, )

85 86 87 88 89 90 91

    security.declareProtected(Permissions.AccessContentsInformation, 'updateVariationCategoryList')
    def updateVariationCategoryList(self):
      """
        Check if variation category list of the resource changed and update transformation
        and transformation line
      """
92
      self.setVariationBaseCategoryList(self.getVariationBaseCategoryList())
93 94 95 96 97
      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
98 99 100
    def getVariationRangeBaseCategoryList(self):
        """
          Returns possible variation base_category ids of the
101 102
          default resource which can be used a variation axis
          in the transformation. 
Jean-Paul Smets's avatar
Jean-Paul Smets committed
103
        """
104
        resource = self.getResourceValue()
Jean-Paul Smets's avatar
Jean-Paul Smets committed
105 106 107
        if resource is not None:
          result = resource.getVariationBaseCategoryList()
        else:
108 109 110 111
          # 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
112 113
        return result

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

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

126
    security.declareProtected(Permissions.AccessContentsInformation,'getVariationRangeCategoryList')
127
    def getVariationRangeCategoryList(self, base_category_list=()):
Jean-Paul Smets's avatar
Jean-Paul Smets committed
128
        """
129 130 131 132 133 134 135
          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
136
        """
137 138 139 140 141
        if base_category_list is ():
          base_category_list = self.getVariationBaseCategoryList()

        resource = self.getResourceValue()
        if resource != None:
142 143 144
          result = resource.getVariationCategoryList(
                                        base_category_list=base_category_list,
                                        omit_individual_variation=0)
145 146 147 148
        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
149

150
    security.declareProtected(Permissions.AccessContentsInformation,'getVariationRangeCategoryItemList')
151 152
    def getVariationRangeCategoryItemList(self, base_category_list=(),
                                          display_base_category=1):
Jean-Paul Smets's avatar
Jean-Paul Smets committed
153 154 155 156 157 158 159
        """
          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.
160 161
          User may want to define generic transformation without
          any resource define.
Jean-Paul Smets's avatar
Jean-Paul Smets committed
162 163 164
        """
        if base_category_list is ():
          base_category_list = self.getVariationBaseCategoryList()
165 166 167

        resource = self.getResourceValue()
        if resource != None:
168 169 170 171
          result = resource.getVariationCategoryItemList(
                                  base_category_list=base_category_list,
                                  omit_individual_variation=0,
                                  display_base_category=display_base_category)
172 173 174
        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
175 176
        return result

177
    security.declareProtected(Permissions.AccessContentsInformation, 'getVariationBaseCategoryItemList')
178
    def getVariationBaseCategoryItemList(self,display_id='title_or_id',**kw):
Jean-Paul Smets's avatar
Jean-Paul Smets committed
179
      """
180
        Returns a list of base_category tuples for this tranformation
Jean-Paul Smets's avatar
Jean-Paul Smets committed
181
      """
182 183
      return self.portal_categories.getItemList(self.getVariationBaseCategoryList(),
                                                display_id=display_id,**kw)
Jean-Paul Smets's avatar
Jean-Paul Smets committed
184

185 186 187

    security.declareProtected(Permissions.AccessContentsInformation, '_setVariationBaseCategoryList')
    def _setVariationBaseCategoryList(self, value):
Jean-Paul Smets's avatar
Jean-Paul Smets committed
188
      """
189
        Define the possible base categories
Jean-Paul Smets's avatar
Jean-Paul Smets committed
190
      """
191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
#      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')
210 211
    def getVariationCategoryItemList(self, base_category_list=(), base=1, 
                                     display_id='title', 
212 213
                                     current_category=None,
                                     **kw):
214 215 216 217 218 219 220 221 222
      """
        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()

223 224 225 226 227 228 229 230 231 232 233 234
      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_none_category=0, base=base,
                               current_category=current_category,
235
                               display_id='logical_path',**kw).\
236 237 238 239 240 241 242 243
                                                 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,
                               base_category=base_category, 
                               display_none_category=0, base=base,
                               current_category=current_category,
244
                               display_id=display_id,**kw).\
245
                                                 render(object_list))
246 247
      return variation_category_item_list

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

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

      # 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
265
      for transformation in [self] + template_transformation_list:
266
        # Browse each transformed or assorted resource of the current transformation
267
        for transformation_line in transformation.objectValues():
268

269
          result.extend( transformation_line.getAggregatedAmountList(context) )
270 271 272

      return result

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

284 285
  security.declarePublic('getTotalPrice')
  def getTotalPrice(self):
286 287 288
    """
      Return total bas price of the transformation
    """
289
    result = sum( filter(lambda y: y is not None  ,map( lambda x: x.getTotalPrice(), self)) )
290 291 292 293 294 295 296 297 298 299 300 301
    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)