Resource.py 30.8 KB
Newer Older
Jean-Paul Smets's avatar
Jean-Paul Smets committed
1 2 3
##############################################################################
#
# Copyright (c) 2002 Nexedi SARL and Contributors. All Rights Reserved.
4
#                    Jean-Paul Smets-Solanes <jp@nexedi.com>
Jean-Paul Smets's avatar
Jean-Paul Smets committed
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
#
# 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 AccessControl import ClassSecurityInfo

from DateTime import DateTime

from Products.ERP5Type import Permissions, PropertySheet, Constraint, Interface
Jean-Paul Smets's avatar
Jean-Paul Smets committed
34
from Products.ERP5Type.XMLMatrix import XMLMatrix
Jean-Paul Smets's avatar
Jean-Paul Smets committed
35 36 37

from Products.ERP5.Variated import Variated
from Products.ERP5.Core.Resource import Resource as CoreResource
Jean-Paul Smets's avatar
Jean-Paul Smets committed
38
from Products.ERP5.Document.SupplyLine import SupplyLineMixin
Sebastien Robin's avatar
Sebastien Robin committed
39
from Products.CMFCore.WorkflowCore import WorkflowMethod
Jean-Paul Smets's avatar
Jean-Paul Smets committed
40 41 42

from zLOG import LOG

Jean-Paul Smets's avatar
Jean-Paul Smets committed
43
class Resource(XMLMatrix, CoreResource, Variated):
Jean-Paul Smets's avatar
Jean-Paul Smets committed
44 45 46 47 48 49
    """
      A Resource
    """

    meta_type = 'ERP5 Resource'
    portal_type = 'Resource'
50
    add_permission = Permissions.AddPortalContent
Jean-Paul Smets's avatar
Jean-Paul Smets committed
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
    isPortalContent = 1
    isRADContent = 1

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

    # Declarative interfaces
    __implements__ = ( Interface.Variated, )

    # Declarative properties
    property_sheets = ( PropertySheet.Base
                      , PropertySheet.XMLObject
                      , PropertySheet.CategoryCore
                      , PropertySheet.DublinCore
                      , PropertySheet.Price
                      , PropertySheet.Resource
                      , PropertySheet.Reference
69
                      , PropertySheet.FlowCapacity
Sebastien Robin's avatar
Sebastien Robin committed
70
                      , PropertySheet.VariationRange
Jean-Paul Smets's avatar
Jean-Paul Smets committed
71 72 73 74 75 76 77 78
                      )

    # Is it OK now ?
    # The same method is at about 3 different places
    # Some genericity is needed
    security.declareProtected(Permissions.AccessContentsInformation,
                                           'getVariationRangeCategoryItemList')
    def getVariationRangeCategoryItemList(self, base_category_list = (), base=1, root=1,
79
                                                display_id='getTitle', current_category=None):
Jean-Paul Smets's avatar
Jean-Paul Smets committed
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
        """
          Returns possible variations
        """
        if base_category_list is ():
          base_category_list = self.getVariationBaseCategoryList()
        elif type(base_category_list) is type('a'):
          base_category_list = (base_category_list,)
        result = []
        for c in base_category_list:
          c_range = self.getCategoryMembershipList(c, base=base)
          if len(c_range) > 0:
            result += list(map(lambda x: (x,x), c_range))
          else:
            if root:
              # XXX - no idea why we should keep this ? JPS
              result += self.portal_categories.unrestrictedTraverse(c).getBaseItemList(base=base)
        try:
97
          other_variations = self.searchFolder(portal_type = self.getPortalVariationTypeList())
Jean-Paul Smets's avatar
Jean-Paul Smets committed
98 99 100 101 102 103 104 105 106 107 108 109 110
        except:
          other_variations = []
        if len(other_variations) > 0:
          for o_brain in other_variations:
            o = o_brain.getObject()
            for v in o.getVariationBaseCategoryList():
              if base_category_list is () or v in base_category_list:
                if base:
                  result += [('%s/%s' % (v, o.getRelativeUrl()), '%s/%s' % (v, o.getRelativeUrl()))]
                else:
                  result += [(o.getRelativeUrl(),o.getRelativeUrl())]
        return result

Jean-Paul Smets's avatar
Jean-Paul Smets committed
111 112 113 114 115
    security.declareProtected(Permissions.AccessContentsInformation,
                                           'getVariationRangeCategoryList')
    def getVariationRangeCategoryList(self, base_category_list = (), base=1, root=1,
                                                display_id='getTitle', current_category=None):
        """
116 117
          Returns the range of acceptable categories
        """
Jean-Paul Smets's avatar
Jean-Paul Smets committed
118 119
        return map(lambda x: x[0], self.getVariationRangeCategoryItemList(base_category_list=base_category_list,
                                   base=base, root=root, display_id=display_id, current_category=current_category))
120 121


Jean-Paul Smets's avatar
Jean-Paul Smets committed
122 123 124
    security.declareProtected(Permissions.AccessContentsInformation,
                                           'getVariationCategoryItemList')
    def getVariationCategoryItemList(self, base_category_list = (),  base=1,
125
                                        display_id='getTitle',current_category=None):
Jean-Paul Smets's avatar
Jean-Paul Smets committed
126 127 128 129
        """
          Returns possible variations
        """
        result = Variated.getVariationCategoryItemList(self, base_category_list = base_category_list,
130
                                          display_id=display_id, base = base, current_category=None)
Jean-Paul Smets's avatar
Jean-Paul Smets committed
131
        try:
132
          other_variations = self.searchFolder(portal_type = self.getPortalVariationTypeList())
Jean-Paul Smets's avatar
Jean-Paul Smets committed
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
        except:
          other_variations = []
        if len(other_variations) > 0:
          for o_brain in other_variations:
            o = o_brain.getObject()
            if o is not None:
              for v in o.getVariationBaseCategoryList():
                if base_category_list is () or v in base_category_list:
                  if base:
                    result += [('%s/%s' % (v, o.getRelativeUrl()), '%s/%s' % (v, o.getRelativeUrl()))]
                  else:
                    result += [(o.getRelativeUrl(),o.getRelativeUrl())]
        return result

    # Unit conversion
    security.declareProtected(Permissions.AccessContentsInformation, 'convertQuantity')
    def convertQuantity(self, quantity, from_unit, to_unit):
      return quantity

    # Pricing
    security.declareProtected(Permissions.AccessContentsInformation, 'getTotalPrice')
    def getTotalPrice(self, quantity, unit=None, variation=None, REQUEST=None):
      return self.convertQuantity(quantity, unit, self.getDefaultQuantityUnit()) *\
156
                                                                  self.getBasePrice()
Jean-Paul Smets's avatar
Jean-Paul Smets committed
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191

    security.declareProtected(Permissions.AccessContentsInformation, 'getUnitPrice')
    def getUnitPrice(self, unit=None, variation=None, REQUEST=None):
      return self.getTotalPrice(1.0, unit, variation, REQUEST)


# This patch is temporary and allows to circumvent name conflict in ZSQLCatalog process for Coramy
    security.declareProtected(Permissions.AccessContentsInformation,
                                              'getDefaultDestinationAmountBis')
    def getDefaultDestinationAmountBis(self, unit=None, variation=None, REQUEST=None):
      try:
        return self.getDestinationReference()
      except:
        return None

# This patch is temporary and allows to circumvent name conflict in ZSQLCatalog process for Coramy
    security.declareProtected(Permissions.AccessContentsInformation,
                                              'getDefaultSourceAmountBis')
    def getDefaultSourceAmountBis(self, unit=None, variation=None, REQUEST=None):
      try:
        return self.getSourceReference()
      except:
        return None


    # This patch allows variations to find a resource
    security.declareProtected(Permissions.AccessContentsInformation,
                                              'getDefaultResourceValue')
    def getDefaultResourceValue(self):
      return self


    # Stock Management
    security.declareProtected(Permissions.AccessContentsInformation, 'getInventory')
    def getInventory(self, at_date = None, section = None, node = None,
192
            node_category=None, section_category=None, simulation_state=None, variation_text=None,
Jean-Paul Smets's avatar
Jean-Paul Smets committed
193
            ignore_variation=0, **kw):
194 195
      if section_category is None:
        section_category = self.getPortalDefaultSectionCategory()
Jean-Paul Smets's avatar
Jean-Paul Smets committed
196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
      if type(simulation_state) is type('a'):
        simulation_state = [simulation_state]
      result = self.Resource_zGetInventory(resource_uid = [self.getUid()],
                                             resource=None,
                                             to_date=at_date,
                                             section=section, node=node,
                                             node_category=node_category,
                                             section_category=section_category,
                                             simulation_state=simulation_state,
                                             variation_text=variation_text
                                             )
      if len(result) > 0:
        return result[0].inventory
      return 0.0

    security.declareProtected(Permissions.AccessContentsInformation, 'getFutureInventory')
    def getFutureInventory(self, section = None, node = None,
213
             node_category=None, section_category=None, simulation_state=None,
Jean-Paul Smets's avatar
Jean-Paul Smets committed
214 215 216 217
             ignore_variation=0, **kw):
      """
        Returns inventory at infinite
      """
218 219
      if section_category is None:
        section_category = self.getPortalDefaultSectionCategory()
Jean-Paul Smets's avatar
Jean-Paul Smets committed
220
      return self.getInventory(at_date=None, section=section, node=node,
221
        node_category=node_category, section_category=section_category,
222 223 224
                        simulation_state=list(self.getPortalFutureInventoryStateList())+ \
                          list(self.getPortalReservedInventoryStateList())+ \
                          list(self.getPortalCurrentInventoryStateList()),
225
                        **kw)
Jean-Paul Smets's avatar
Jean-Paul Smets committed
226 227 228

    security.declareProtected(Permissions.AccessContentsInformation, 'getCurrentInventory')
    def getCurrentInventory(self, section = None, node = None,
229
             node_category=None, section_category=None, ignore_variation=0, variation_text=None, **kw):
Jean-Paul Smets's avatar
Jean-Paul Smets committed
230 231 232 233 234
      """
        Returns current inventory
      """

      # Consider only delivered - forget date at this point
235 236 237 238 239
      if section_category is None:
        section_category = self.getPortalDefaultSectionCategory()
      return self.getInventory(simulation_state = self.getPortalCurrentInventoryStateList(),
                               section=section, node=node,
                               node_category=node_category, section_category=section_category, **kw)
Jean-Paul Smets's avatar
Jean-Paul Smets committed
240 241 242 243 244 245

      #return self.getInventory(at_date=DateTime(), section=section, node=node,
      #                       node_category=node_category, section_category=section_category, **kw)

    security.declareProtected(Permissions.AccessContentsInformation, 'getAvailableInventory')
    def getAvailableInventory(self, section = None, node = None,
246
               node_category=None, section_category=None,
Jean-Paul Smets's avatar
Jean-Paul Smets committed
247 248 249 250
               ignore_variation=0, **kw):
      """
        Returns available inventory, ie. current inventory - deliverable
      """
251 252
      if section_category is None:
        section_category = self.getPortalDefaultSectionCategory()
Jean-Paul Smets's avatar
Jean-Paul Smets committed
253 254 255 256 257
      return self.getInventory(at_date=DateTime(), section=section, node=node,
                             node_category=node_category, section_category=section_category, **kw)

    security.declareProtected(Permissions.AccessContentsInformation, 'getInventoryList')
    def getInventoryList(self, at_date = None, section = None, node = None,
258
              node_category=None, section_category=None, simulation_state=None,
Jean-Paul Smets's avatar
Jean-Paul Smets committed
259 260 261 262
              ignore_variation=0, **kw):
      """
        Returns list of inventory grouped by section or site
      """
263 264
      if section_category is None:
        section_category = self.getPortalDefaultSectionCategory()
Jean-Paul Smets's avatar
Jean-Paul Smets committed
265 266 267 268 269 270 271 272 273 274 275 276 277 278
      if type(simulation_state) is type('a'):
        simulation_state = [simulation_state]
      result = self.Resource_zGetInventoryList(resource_uid = [self.getUid()],
                                             resource=None,
                                             to_date=at_date,
                                             section=section, node=node,
                                             node_category=node_category,
                                             section_category=section_category,
                                             simulation_state=simulation_state,
                                              **kw)
      return result

    security.declareProtected(Permissions.AccessContentsInformation, 'getFutureInventoryList')
    def getFutureInventoryList(self, section = None, node = None,
279
             node_category=None, section_category=None,
280
             simulation_state=None, ignore_variation=0, **kw):
Jean-Paul Smets's avatar
Jean-Paul Smets committed
281 282 283
      """
        Returns list of future inventory grouped by section or site
      """
284 285
      if section_category is None:
        section_category = self.getPortalDefaultSectionCategory()
286
      LOG('getFutureInventoryList',0,str(kw))
Jean-Paul Smets's avatar
Jean-Paul Smets committed
287
      return self.getInventoryList(at_date=None, section=section, node=node,
288 289 290 291 292
                                   node_category=node_category, section_category=section_category,
                                   simulation_state=list(self.getPortalFutureInventoryStateList())+ \
                                                    list(self.getPortalReservedInventoryStateList())+ \
                                                    list(self.getPortalCurrentInventoryStateList()),
                                   **kw)
Jean-Paul Smets's avatar
Jean-Paul Smets committed
293 294 295

    security.declareProtected(Permissions.AccessContentsInformation, 'getCurrentInventoryList')
    def getCurrentInventoryList(self, section = None, node = None,
296
                            node_category=None, section_category=None,
Jean-Paul Smets's avatar
Jean-Paul Smets committed
297 298 299 300
                            ignore_variation=0, **kw):
      """
        Returns list of current inventory grouped by section or site
      """
301 302 303 304 305
      if section_category is None:
        section_category = self.getPortalDefaultSectionCategory()
      return self.getInventoryList(simulation_state=self.getPortalCurrentInventoryStateList(),
                                   section=section, node=node,
                                   node_category=node_category, section_category=section_category, **kw)
Jean-Paul Smets's avatar
Jean-Paul Smets committed
306 307 308 309 310
      #return self.getInventoryList(at_date=DateTime(), section=section, node=node,
      #                       node_category=node_category, section_category=section_category, **kw)

    security.declareProtected(Permissions.AccessContentsInformation, 'getInventoryStat')
    def getInventoryStat(self, at_date = None, section = None, node = None,
311
              node_category=None, section_category=None,
Jean-Paul Smets's avatar
Jean-Paul Smets committed
312 313 314 315
              simulation_state=None, ignore_variation=0, **kw):
      """
        Returns statistics of inventory list grouped by section or site
      """
316 317
      if section_category is None:
        section_category = self.getPortalDefaultSectionCategory()
Jean-Paul Smets's avatar
Jean-Paul Smets committed
318 319 320 321 322 323 324 325 326 327 328 329 330 331
      if type(simulation_state) is type('a'):
        simulation_state = [simulation_state]
      result = self.Resource_zGetInventory(resource_uid = [self.getUid()],
                                             resource=None,
                                             to_date=at_date,
                                             section=section, node=node,
                                             node_category=node_category,
                                             section_category=section_category,
                                             simulation_state=simulation_state,
                                             **kw)
      return result

    security.declareProtected(Permissions.AccessContentsInformation, 'getFutureInventoryStat')
    def getFutureInventoryStat(self, section = None, node = None,
332
             node_category=None, section_category=None,
333
             simulation_state=None, ignore_variation=0, **kw):
Jean-Paul Smets's avatar
Jean-Paul Smets committed
334 335 336
      """
        Returns statistics of future inventory list grouped by section or site
      """
337 338
      if section_category is None:
        section_category = self.getPortalDefaultSectionCategory()
Jean-Paul Smets's avatar
Jean-Paul Smets committed
339
      return self.getInventoryStat(at_date=None, section=section, node=node,
340 341 342 343 344
                                   node_category=node_category, section_category=section_category,
                                   simulation_state=list(self.getPortalFutureInventoryStateList())+ \
                                                    list(self.getPortalReservedInventoryStateList())+ \
                                                    list(self.getPortalCurrentInventoryStateList()),
                                   **kw)
Jean-Paul Smets's avatar
Jean-Paul Smets committed
345 346 347

    security.declareProtected(Permissions.AccessContentsInformation, 'getCurrentInventoryStat')
    def getCurrentInventoryStat(self, section = None, node = None,
348
                            node_category=None, section_category=None,
Jean-Paul Smets's avatar
Jean-Paul Smets committed
349 350 351 352
                            ignore_variation=0, **kw):
      """
        Returns statistics of current inventory list grouped by section or site
      """
353 354 355 356 357
      if section_category is None:
        section_category = self.getPortalDefaultSectionCategory()
      return self.getInventoryStat(simulation_state=self.getPortalCurrentInventoryStateList(),
                                   section=section, node=node,
                                   node_category=node_category, section_category=section_category, **kw)
Jean-Paul Smets's avatar
Jean-Paul Smets committed
358 359 360

    security.declareProtected(Permissions.AccessContentsInformation, 'getInventoryChart')
    def getInventoryChart(self, at_date = None, section = None, node = None,
361
              node_category=None, section_category=None, simulation_state=None,
Jean-Paul Smets's avatar
Jean-Paul Smets committed
362 363 364 365
              ignore_variation=0, **kw):
      """
        Returns list of inventory grouped by section or site
      """
366 367
      if section_category is None:
        section_category = self.getPortalDefaultSectionCategory()
Jean-Paul Smets's avatar
Jean-Paul Smets committed
368 369 370 371 372 373 374 375 376 377 378 379 380 381
      if type(simulation_state) is type('a'):
        simulation_state = [simulation_state]
      result = self.Resource_zGetInventoryList(resource_uid = [self.getUid()],
                                             resource=None,
                                             to_date=at_date,
                                             section=section, node=node,
                                             node_category=node_category,
                                             section_category=section_category,
                                             simulation_state=simulation_state,
                                             **kw)
      return map(lambda r: (r.node_title, r.inventory), result)

    security.declareProtected(Permissions.AccessContentsInformation, 'getFutureInventoryChart')
    def getFutureInventoryChart(self, section = None, node = None,
382
             node_category=None, section_category=None,
383
             simulation_state=None, ignore_variation=0, **kw):
Jean-Paul Smets's avatar
Jean-Paul Smets committed
384 385 386
      """
        Returns list of future inventory grouped by section or site
      """
387 388
      if section_category is None:
        section_category = self.getPortalDefaultSectionCategory()
Jean-Paul Smets's avatar
Jean-Paul Smets committed
389
      return self.getInventoryChart(at_date=None, section=section, node=node,
390 391 392 393 394
                                    node_category=node_category, section_category=section_category,
                                    simulation_state=list(self.getPortalFutureInventoryStateList())+ \
                                                     list(self.getPortalReservedInventoryStateList())+ \
                                                     list(self.getPortalCurrentInventoryStateList()),
                                    **kw)
Jean-Paul Smets's avatar
Jean-Paul Smets committed
395 396 397

    security.declareProtected(Permissions.AccessContentsInformation, 'getCurrentInventoryChart')
    def getCurrentInventoryChart(self, section = None, node = None,
398
                            node_category=None, section_category=None,
Jean-Paul Smets's avatar
Jean-Paul Smets committed
399 400 401 402
                            ignore_variation=0, **kw):
      """
        Returns list of current inventory grouped by section or site
      """
403 404 405 406 407
      if section_category is None:
        section_category = self.getPortalDefaultSectionCategory()
      return self.getInventoryChart(simulation_state=self.getPortalCurrentInventoryStateList(),
                                    section=section, node=node,
                                    node_category=node_category, section_category=section_category, **kw)
Jean-Paul Smets's avatar
Jean-Paul Smets committed
408 409 410 411 412 413
      #return self.getInventoryChart(at_date=DateTime(), section=section, node=node,
      #            node_category=node_category, section_category=section_category, **kw)


    security.declareProtected(Permissions.AccessContentsInformation, 'getMovementHistoryList')
    def getMovementHistoryList(self, from_date = None, to_date=None, section = None, node = None,
414
              node_category=None, section_category=None, simulation_state=None,
Jean-Paul Smets's avatar
Jean-Paul Smets committed
415 416 417 418
              ignore_variation=0, **kw):
      """
        Returns list of inventory grouped by section or site
      """
419 420
      if section_category is None:
        section_category = self.getPortalDefaultSectionCategory()
Jean-Paul Smets's avatar
Jean-Paul Smets committed
421 422 423 424 425 426 427
      result = self.Resource_zGetMovementHistoryList(resource_uid = [self.getUid()],
                                             resource=None,
                                             from_date=from_date,
                                             to_date=to_date,
                                             section=section,
                                             node=node,
                                             node_category=node_category,
428 429 430
                                             section_category=section_category,
                                             simulation_state=simulation_state,
                                             **kw)
Jean-Paul Smets's avatar
Jean-Paul Smets committed
431 432 433 434
      return result

    security.declareProtected(Permissions.AccessContentsInformation, 'getMovementHistoryStat')
    def getMovementHistoryStat(self, from_date = None, to_date=None, section = None, node = None,
435
              node_category=None, section_category=None, simulation_state=None,
Jean-Paul Smets's avatar
Jean-Paul Smets committed
436 437 438 439
              ignore_variation=0, **kw):
      """
        Returns list of inventory grouped by section or site
      """
440 441
      if section_category is None:
        section_category = self.getPortalDefaultSectionCategory()
Jean-Paul Smets's avatar
Jean-Paul Smets committed
442 443 444 445 446 447 448
      result = self.Resource_zGetInventory(resource_uid = [self.getUid()],
                                             resource=None,
                                             from_date=from_date,
                                             to_date=to_date,
                                             section=section,
                                             node=node,
                                             node_category=node_category,
449
                                             simulation_state=simulation_state,
Jean-Paul Smets's avatar
Jean-Paul Smets committed
450 451 452 453 454
                                             section_category=section_category, **kw)
      return result

    security.declareProtected(Permissions.AccessContentsInformation, 'getInventoryHistoryList')
    def getInventoryHistoryList(self, from_date = None, to_date=None, section = None, node = None,
455
              node_category=None, section_category=None, simulation_state=None,
Jean-Paul Smets's avatar
Jean-Paul Smets committed
456 457 458 459 460
              ignore_variation=0, **kw):
      """
        Returns list of inventory grouped by section or site
      """
      # Get Movement List
461 462
      if section_category is None:
        section_category = self.getPortalDefaultSectionCategory()
Jean-Paul Smets's avatar
Jean-Paul Smets committed
463 464 465 466 467 468 469 470 471 472 473 474 475 476 477
      result = self.Resource_getInventoryHistoryList(  resource_uid = [self.getUid()],
                                             resource=None,
                                             from_date=from_date,
                                             to_date=to_date,
                                             section=section,
                                             node=node,
                                             node_category=node_category,
                                             section_category=section_category,
                                             simulation_state = simulation_state,
                                              **kw)
      return result


    security.declareProtected(Permissions.AccessContentsInformation, 'getInventoryHistoryChart')
    def getInventoryHistoryChart(self, from_date = None, to_date=None, section = None, node = None,
478
              node_category=None, section_category=None, simulation_state=None,
Jean-Paul Smets's avatar
Jean-Paul Smets committed
479 480 481 482 483
              ignore_variation=0, **kw):
      """
        Returns list of inventory grouped by section or site
      """
      # Get Movement List
484 485
      if section_category is None:
        section_category = self.getPortalDefaultSectionCategory()
Jean-Paul Smets's avatar
Jean-Paul Smets committed
486 487 488 489 490 491 492 493 494 495 496 497 498 499
      result = self.Resource_getInventoryHistoryChart(  resource_uid = [self.getUid()],
                                             resource=None,
                                             from_date=from_date,
                                             to_date=to_date,
                                             section=section,
                                             node=node,
                                             node_category=node_category,
                                             section_category=section_category,
                                             simulation_state = simulation_state,
                                              **kw)
      return result


    security.declareProtected(Permissions.AccessContentsInformation, 'getNextNegativeInventoryDate')
500
    def getNextNegativeInventoryDate(self, from_date = None, section = None, node = None,
501
              node_category=None, section_category=None, simulation_state=None,
Jean-Paul Smets's avatar
Jean-Paul Smets committed
502 503 504 505 506
              variation_text = None,
              ignore_variation=0, **kw):
      """
        Returns list of inventory grouped by section or site
      """
507 508
      if section_category is None:
        section_category = self.getPortalDefaultSectionCategory()
509
      if from_date is None: from_date = DateTime()
Jean-Paul Smets's avatar
Jean-Paul Smets committed
510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527
      # Get Movement List
      result = self.Resource_getInventoryHistoryList(  resource_uid = [self.getUid()],
                                             resource=None,
                                             from_date=from_date,
                                             variation_text = variation_text,
                                             section=section,
                                             node=node,
                                             node_category=node_category,
                                             section_category=section_category,
                                             simulation_state = simulation_state,
                                              **kw)
      for inventory in result:
        if inventory['inventory'] < 0:
          return inventory['stop_date']

      return None


528 529 530 531 532 533 534 535 536
    # Industrial price API
    security.declareProtected(Permissions.AccessContentsInformation, 'getIndustrialPrice')
    def getIndustrialPrice(self, context=None, REQUEST=None, **kw):
      """
        Returns industrial price
      """
      context = self.asContext(context=context, REQUEST=REQUEST, **kw)
      result = self._getIndustrialPrice(context)
      if result is None:
537
        self._updateIndustrialPrice(context)
538
        result = self._getIndustrialPrice(context)
539
      return result
540 541 542 543 544 545 546 547

    def _getIndustrialPrice(self, context):
      # Default value is None
      return None

    def _updateIndustrialPrice(self, context):
      # Do nothing by default
      pass
Jean-Paul Smets's avatar
Jean-Paul Smets committed
548

Sebastien Robin's avatar
Sebastien Robin committed
549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564
    security.declareProtected( Permissions.ModifyPortalContent, 'validate' )
    def validate(self):
      """
      """
      pass

    validate = WorkflowMethod( validate )

    security.declareProtected( Permissions.ModifyPortalContent, 'invalidate' )
    def invalidate(self):
      """
      """
      pass

    invalidate = WorkflowMethod( invalidate )

565 566
    security.declareProtected( Permissions.ModifyPortalContent, 'updateSupplyMatrix' )
    def updateSupplyMatrix(self):
Jean-Paul Smets's avatar
Jean-Paul Smets committed
567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601
      """
          Define the indices provided
          one list per index (kw)

          Any number of list can be provided
      """
      # Update the cell range automatically
      # This is far from easy and requires some specific wizzardry
      base_id = 'path'
      kwd = {'base_id': base_id}
      new_range = self.SupplyLine_asCellRange() # This is a site dependent script
      self._setCellRange(*new_range, **kwd )
      cell_range_key_list = self.getCellRangeKeyList(base_id = base_id)
      if cell_range_key_list <> [[None, None]] :
        for k in cell_range_key_list:
          #LOG('new cell',0,str(k))
          c = self.newCell(*k, **kwd)
          c.edit( domain_base_category_list = self.getVariationBaseCategoryList(),
                  mapped_value_property_list = ( 'price',),
                  predicate_operator = 'SUPERSET_OF',
                  predicate_category_list = filter(lambda k_item: k_item is not None, k),
                  variation_category_list = filter(lambda k_item: k_item is not None, k),
                  force_update = 1
                ) # Make sure we do not take aquisition into account
      else:
        # If only one cell, delete it
        cell_range_id_list = self.getCellRangeIdList(base_id = base_id)
        for k in cell_range_id_list:
          if self.get(k) is not None:
            self[k].flushActivity(invoke=0)
            self[k].immediateReindexObject() # We are forced to do this is url is changed (not uid)
            self._delObject(k)

      # TO BE DONE XXX
      # reindex cells when price, quantity or source/dest changes
602

Jean-Paul Smets's avatar
Jean-Paul Smets committed
603 604
    # For generation of matrix lines
    security.declareProtected( Permissions.ModifyPortalContent, '_setQuantityStepList' )
605
    def _setQuantityStepList(self, value):
Jean-Paul Smets's avatar
Jean-Paul Smets committed
606 607 608 609 610
      self._baseSetQuantityStepList(value)
      value = self.getQuantityStepList()
      value.sort()
      for pid in self.contentIds(filter={'portal_type': 'Predicate'}):
        self.deleteContent(pid)
611 612 613 614 615
      if len(value) > 0:
        value = [None] + value + [None]
        for i in range(0, len(value) - 1):
          p = self.newContent(id = 'quantity_range_%s' % i, portal_type = 'Predicate')
          p.setCriterionPropertyList(('quantity', ))
616
          p.setCriterion('quantity', min=value[i], max=value[i+1])
617 618
          p.setTitle('%s <= quantity < %s' % (repr(value[i]),repr(value[i+1])))
      self.updateSupplyMatrix()
619 620

    # Predicate handling
Jean-Paul Smets's avatar
Jean-Paul Smets committed
621 622 623 624 625 626 627 628 629 630
    security.declareProtected(Permissions.AccessContentsInformation, 'asPredicate')
    def asPredicate(self):
      """
      Returns a temporary Predicate based on the Resource properties
      """
      from Products.ERP5 import newTempPredicateGroup as newTempPredicate
      p = newTempPredicate(self.getId(), uid = self.getUid())
      p.setMembershipCriterionBaseCategoryList(('resource',))
      p.setMembershipCriterionCategoryList(('resource/%s' % self.getRelativeUrl(),))
      return p
631 632

#monkeyPatch(SupplyLineMixin)
Jean-Paul Smets's avatar
Jean-Paul Smets committed
633 634 635 636
from types import FunctionType
for id, m in SupplyLineMixin.__dict__.items():
    if type(m) is FunctionType:
        setattr(Resource, id, m)