testResource.py 40.3 KB
Newer Older
Romain Courteaud's avatar
Romain Courteaud committed
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
##############################################################################
#
# Copyright (c) 2005 Nexedi SARL and Contributors. All Rights Reserved.
#          Romain Courteaud <romain@nexedi.com>
#
# 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.
#
##############################################################################

29
import unittest
Romain Courteaud's avatar
Romain Courteaud committed
30 31 32

from Testing import ZopeTestCase
from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase
33
from AccessControl.SecurityManagement import newSecurityManager
Romain Courteaud's avatar
Romain Courteaud committed
34
from zLOG import LOG
35
from Products.ERP5Type.tests.Sequence import SequenceList
36
from DateTime import DateTime
37

Romain Courteaud's avatar
Romain Courteaud committed
38 39 40 41 42 43

class TestResource(ERP5TypeTestCase):
  """
    Test ERP5 document Resource
  """
  run_all_test = 1
44
  quiet = 0
Romain Courteaud's avatar
Romain Courteaud committed
45 46 47

  # Global variables
  resource_portal_type = 'Apparel Model'
48
  product_portal_type = 'Product'
49
  node_portal_type = 'Organisation'
50 51
  sale_supply_portal_type = 'Sale Supply'
  sale_supply_line_portal_type = 'Sale Supply Line'
52
  purchase_supply_line_portal_type = 'Purchase Supply Line'
53
  sale_supply_cell_portal_type = 'Sale Supply Cell'
Kevin Deldycke's avatar
Kevin Deldycke committed
54
  variation_base_category_list = ['colour', 'size', 'morphology',
55
                                  'industrial_phase']
Kevin Deldycke's avatar
Kevin Deldycke committed
56
  size_list = ['size/Child','size/Man']
57
  variation_property_list = []
Romain Courteaud's avatar
Romain Courteaud committed
58 59 60 61 62

  def getBusinessTemplateList(self):
    """
      Install needed business template
    """
63
    # Trade is needeed for pricing
64
    return ('erp5_base', 'erp5_pdm', 'erp5_trade', 'erp5_apparel', )
Romain Courteaud's avatar
Romain Courteaud committed
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80

  def getTitle(self):
    return "Resource"

  def login(self):
    uf = self.getPortal().acl_users
    uf._doAddUser('rc', '', ['Manager'], [])
    user = uf.getUserById('rc').__of__(uf)
    newSecurityManager(None, user)

  def afterSetUp(self):
    self.login()
    self.portal = self.getPortal()
    self.category_tool = self.getCategoryTool()
    self.createCategories()

Jérome Perrin's avatar
Jérome Perrin committed
81 82 83 84 85 86 87 88 89 90 91 92 93
  def beforeTearDown(self):
    get_transaction().abort()
    for folder in (
          self.portal.getDefaultModule(self.resource_portal_type),
          self.portal.getDefaultModule(self.sale_supply_portal_type),
          self.portal.getDefaultModule("Currency"),
          self.portal.getDefaultModule(self.node_portal_type),
          self.portal.getDefaultModule("Sale Order"),
          self.portal.getDefaultModule("Purchase Order"),):
      folder.manage_delObjects([i for i in folder.objectIds()])
    get_transaction().commit()
    self.tic()

Romain Courteaud's avatar
Romain Courteaud committed
94
  def createCategories(self):
Kevin Deldycke's avatar
Kevin Deldycke committed
95 96
    """
      Light install create only base categories, so we create
Romain Courteaud's avatar
Romain Courteaud committed
97 98 99 100 101 102 103
      some categories for testing them
    """
    size_category_list = ['Baby', 'Child', 'Man', 'Woman']
    if len(self.category_tool.size.contentValues()) == 0 :
      for category_id in size_category_list:
        o = self.category_tool.size.newContent(portal_type='Category',
                                               id=category_id)
Kevin Deldycke's avatar
Kevin Deldycke committed
104
    self.size_category_list = map(lambda x: 'size/%s' % x,
Romain Courteaud's avatar
Romain Courteaud committed
105 106 107 108 109 110 111
                                  size_category_list)

    colour_category_list = ['blue', 'green']
    if len(self.category_tool.colour.contentValues()) == 0 :
      for category_id in colour_category_list:
        o = self.category_tool.colour.newContent(portal_type='Category',
                                               id=category_id)
Kevin Deldycke's avatar
Kevin Deldycke committed
112
    self.colour_category_list = map(lambda x: 'colour/%s' % x,
Romain Courteaud's avatar
Romain Courteaud committed
113 114
                                    colour_category_list)

115 116 117 118 119 120 121
    ind_phase_category_list = ['phase1', 'phase2']
    if len(self.category_tool.industrial_phase.contentValues()) == 0:
      for category_id in ind_phase_category_list:
        o = self.category_tool.industrial_phase.newContent(
                                               portal_type='Category',
                                               id=category_id)
    self.industrial_phase_category_list = map(
Kevin Deldycke's avatar
Kevin Deldycke committed
122
                                    lambda x: 'industrial_phase/%s' % x,
123 124
                                    ind_phase_category_list)

Romain Courteaud's avatar
Romain Courteaud committed
125 126 127 128
    self.morphology_category_list = []
    self.base_category_content_list = {
      'size':self.size_category_list,
      'colour':self.colour_category_list,
129
      'morphology':self.morphology_category_list,
130
      'industrial_phase':self.industrial_phase_category_list
Romain Courteaud's avatar
Romain Courteaud committed
131 132
    }

133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
    quantity_unit_weight = self.portal.portal_categories.quantity_unit._getOb(
                                        'weight', None)
    if quantity_unit_weight is None:
      quantity_unit_weight = self.portal.portal_categories.quantity_unit\
                                  .newContent(id='weight',
                                              portal_type='Category')
    self.quantity_unit_gram = quantity_unit_weight._getOb('gram', None)
    if self.quantity_unit_gram is None:
      self.quantity_unit_gram = quantity_unit_weight.newContent(
                                      portal_type='Category',
                                      quantity=0.001,
                                      id='gram')
    self.quantity_unit_kilo = quantity_unit_weight._getOb('kilo', None)
    if self.quantity_unit_kilo is None:
      self.quantity_unit_kilo = quantity_unit_weight.newContent(
                                      portal_type='Category',
                                      quantity=1,
                                      id='kilo')


Romain Courteaud's avatar
Romain Courteaud committed
153 154 155 156 157 158 159 160 161 162 163 164 165
  def stepTic(self,**kw):
    self.tic()

  def stepCreateResource(self, sequence=None, sequence_list=None, **kw):
    """
      Create a resource without variation
    """
    resource_module = self.portal.getDefaultModule(self.resource_portal_type)
    resource = resource_module.newContent( \
                                 portal_type=self.resource_portal_type)
    resource.edit(
      title = "Resource"
    )
166 167
    sequence.edit(resource=resource,
                  variation_property_list=[])
Romain Courteaud's avatar
Romain Courteaud committed
168 169 170 171 172
    self.category_list = []
    # Actually, resource has no individual variation
    for base_category in resource.getVariationBaseCategoryList():
      sequence.edit(**{base_category:None})

Kevin Deldycke's avatar
Kevin Deldycke committed
173
  def stepCheckGetVariationBaseCategoryList(self, sequence=None,
Romain Courteaud's avatar
Romain Courteaud committed
174 175 176 177 178 179 180 181
                                             sequence_list=None, **kw):
    """
      Check if getVariationBaseCategoryList returns the good result
    """
    resource = sequence.get('resource')
    vbcl = resource.getVariationBaseCategoryList()
    self.failIfDifferentSet(self.variation_base_category_list, vbcl)

Kevin Deldycke's avatar
Kevin Deldycke committed
182
  def stepCheckGetVariationRangeCategoryList(self, sequence=None,
Romain Courteaud's avatar
Romain Courteaud committed
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
                                             sequence_list=None, **kw):
    """
      Check if getVariationRangeCategoryList returns the good result
    """
    resource = sequence.get('resource')
    vbcl = resource.getVariationBaseCategoryList()
    correct_variation_range_category_list = []
    for base_category in vbcl:
      # Check if resource has individual variations
      individual_variation_list = sequence.get(base_category)
      if individual_variation_list is None:
        correct_variation_range_category_list.extend(
                               self.base_category_content_list[base_category])
      else:
        correct_variation_range_category_list.extend(individual_variation_list)

    vrcl = resource.getVariationRangeCategoryList()
    self.failIfDifferentSet(correct_variation_range_category_list, vrcl)

  def stepSetCategoryVariation(self, sequence=None, sequence_list=None, **kw):
    """
      Set category variation to current resource
    """
    resource = sequence.get('resource')
    size_list = map(lambda x: x[len('size/'):], self.size_list)
Kevin Deldycke's avatar
Kevin Deldycke committed
208
    resource.setSizeList(size_list)
Romain Courteaud's avatar
Romain Courteaud committed
209 210
    self.category_list = self.size_list[:]

Kevin Deldycke's avatar
Kevin Deldycke committed
211
  def stepSetIndividualVariationWithEmptyBase(self, sequence=None,
Romain Courteaud's avatar
Romain Courteaud committed
212 213
                                              sequence_list=None, **kw):
    """
Alexandre Boeglin's avatar
Alexandre Boeglin committed
214 215
    Set the individual variation of the current resource to a base category
    that contains no subobjects.
Romain Courteaud's avatar
Romain Courteaud committed
216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
    """
    resource = sequence.get('resource')
    morphology_list = []
    morphology_variation_count = 2
    for i in range(morphology_variation_count) :
      variation_portal_type = 'Apparel Model Morphology Variation'
      variation = resource.newContent(portal_type=variation_portal_type)
      variation.edit(
        title = 'MorphologyVariation%s' % str(i)
      )
      morphology_list.append('morphology/%s' %
                                        variation.getRelativeUrl())
    # store individual resource
    sequence.edit(morphology=morphology_list)

Kevin Deldycke's avatar
Kevin Deldycke committed
231
  def stepSetIndividualVariationWithFillBase(self, sequence=None,
Romain Courteaud's avatar
Romain Courteaud committed
232 233
                                              sequence_list=None, **kw):
    """
Alexandre Boeglin's avatar
Alexandre Boeglin committed
234 235
    Set the individual variation of the current resource to a base category
    that contains some subobjects.
Romain Courteaud's avatar
Romain Courteaud committed
236 237 238
    """
    resource = sequence.get('resource')
    colour_list = []
Kevin Deldycke's avatar
Kevin Deldycke committed
239
    colour_variation_count = 1
Romain Courteaud's avatar
Romain Courteaud committed
240 241 242 243 244 245 246 247 248 249
    for i in range(colour_variation_count) :
      variation_portal_type = 'Apparel Model Colour Variation'
      variation = resource.newContent(portal_type=variation_portal_type)
      variation.edit(
        title = 'ColourVariation%s' % str(i)
      )
      colour_list.append('colour/%s' % variation.getRelativeUrl())
    # store individual resource
    sequence.edit(colour=colour_list)

250
  def test_01_getVariationBaseCategoryList(self, quiet=quiet, run=run_all_test):
Romain Courteaud's avatar
Romain Courteaud committed
251 252 253 254 255 256 257 258 259 260 261
    """
      Test the method getVariationBaseCategoryList on a resource.
    """
    if not run: return
    sequence_list = SequenceList()
    # Test when resource has no variation
    sequence_string = '\
                      CreateResource \
                      CheckGetVariationBaseCategoryList \
                      '
    sequence_list.addSequenceString(sequence_string)
262
    sequence_list.play(self, quiet=quiet)
Romain Courteaud's avatar
Romain Courteaud committed
263

264
  def genericTest(self, test_method_name, quiet=quiet):
Romain Courteaud's avatar
Romain Courteaud committed
265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309
    """
      Generic test on a resource.
    """
    sequence_list = SequenceList()
    # Test when resource has no variation
    sequence_string = '\
                      CreateResource \
                      %s \
                      ' % test_method_name
    sequence_list.addSequenceString(sequence_string)
    # Test when resource has category variations
    sequence_string = '\
                      CreateResource \
                      SetCategoryVariation \
                      %s \
                      ' % test_method_name
    sequence_list.addSequenceString(sequence_string)
    # Test when resource has individual variation and base category
    # has no content
    sequence_string = '\
                      CreateResource \
                      SetIndividualVariationWithEmptyBase \
                      Tic \
                      %s \
                      ' % test_method_name
    sequence_list.addSequenceString(sequence_string)
    # Test when resource has individual variation and base category
    # has category content
    sequence_string = '\
                      CreateResource \
                      SetIndividualVariationWithFillBase \
                      Tic \
                      %s \
                      ' % test_method_name
    sequence_list.addSequenceString(sequence_string)
    # Test with all cases
    sequence_string = '\
                      CreateResource \
                      SetCategoryVariation \
                      SetIndividualVariationWithEmptyBase \
                      SetIndividualVariationWithFillBase \
                      Tic \
                      %s \
                      ' % test_method_name
    sequence_list.addSequenceString(sequence_string)
310
    sequence_list.play(self, quiet=quiet)
Romain Courteaud's avatar
Romain Courteaud committed
311

312
  def test_02_getVariationRangeCategoryList(self, quiet=quiet, run=run_all_test):
Romain Courteaud's avatar
Romain Courteaud committed
313 314 315 316
    """
      Test the method getVariationRangeCategoryList on a resource.
    """
    if not run: return
317
    self.genericTest('CheckGetVariationRangeCategoryList', quiet=quiet)
Romain Courteaud's avatar
Romain Courteaud committed
318

Kevin Deldycke's avatar
Kevin Deldycke committed
319
  def stepCheckGetVariationRangeCategoryItemList(self, sequence=None,
Romain Courteaud's avatar
Romain Courteaud committed
320 321 322 323 324 325 326 327 328 329 330
                                                 sequence_list=None, **kw):
    """
      Check if getVariationRangeCategoryItemList returns the good result.
      Does not test display...
      Item are left display.
    """
    resource = sequence.get('resource')
    vrcl = resource.getVariationRangeCategoryList()
    vrcil = resource.getVariationRangeCategoryItemList()
    self.failIfDifferentSet(vrcl, map(lambda x: x[1], vrcil))

331
  def test_03_getVariationRangeCategoryItemList(self, quiet=quiet,
Romain Courteaud's avatar
Romain Courteaud committed
332 333 334 335 336
                                                run=run_all_test):
    """
      Test the method getVariationRangeCategoryItemList on a resource.
    """
    if not run: return
337
    self.genericTest('CheckGetVariationRangeCategoryItemList', quiet=quiet)
Romain Courteaud's avatar
Romain Courteaud committed
338

Kevin Deldycke's avatar
Kevin Deldycke committed
339
  def stepCheckGetVariationCategoryList(self, sequence=None,
Romain Courteaud's avatar
Romain Courteaud committed
340 341
                                                 sequence_list=None, **kw):
    """
Alexandre Boeglin's avatar
Alexandre Boeglin committed
342 343
    Check if getVariationCategoryList returns the good result, with default
    value for omit_individual_variation parameter
Romain Courteaud's avatar
Romain Courteaud committed
344 345 346 347 348
    """
    resource = sequence.get('resource')
    vcl = resource.getVariationCategoryList()
    self.failIfDifferentSet(self.category_list, vcl)

349
  def test_04_getVariationCategoryList(self, quiet=quiet, run=run_all_test):
Romain Courteaud's avatar
Romain Courteaud committed
350 351 352 353
    """
      Test the method getVariationCategoryList on a resource.
    """
    if not run: return
354
    self.genericTest('CheckGetVariationCategoryList', quiet=quiet)
Romain Courteaud's avatar
Romain Courteaud committed
355

Kevin Deldycke's avatar
Kevin Deldycke committed
356
  def stepCheckGetVariationCategoryListWithoutOmit(self, sequence=None,
Romain Courteaud's avatar
Romain Courteaud committed
357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372
                                                 sequence_list=None, **kw):
    """
      Check if getVariationCategoryList returns the good result,
      with parameter omit_individual_variation=0.
    """
    resource = sequence.get('resource')
    vcl = resource.getVariationCategoryList(omit_individual_variation=0)
    correct_vcl = self.category_list[:]

    for base_category in resource.getVariationBaseCategoryList():
      # Check if resource has individual variations
      individual_variation_list = sequence.get(base_category)
      if individual_variation_list is not None:
        correct_vcl.extend(individual_variation_list)
    self.failIfDifferentSet(correct_vcl, vcl)

373
  def test_05_getVariationCategoryList(self, quiet=quiet, run=run_all_test):
Romain Courteaud's avatar
Romain Courteaud committed
374 375 376 377 378
    """
      Test the method getVariationCategoryList on a resource
      with parameter omit_individual_variation=0.
    """
    if not run: return
379
    self.genericTest('CheckGetVariationCategoryListWithoutOmit', quiet)
Romain Courteaud's avatar
Romain Courteaud committed
380

Kevin Deldycke's avatar
Kevin Deldycke committed
381
  def stepCheckGetVariationCategoryItemList(self, sequence=None,
Romain Courteaud's avatar
Romain Courteaud committed
382 383 384 385 386 387 388 389 390 391
                                                 sequence_list=None, **kw):
    """
      Check if getVariationCategoryItemList returns the good result,
      with parameter omit_individual_variation=1.
    """
    resource = sequence.get('resource')
    vcl = resource.getVariationCategoryList()
    vcil = resource.getVariationCategoryItemList()
    self.failIfDifferentSet(vcl, map(lambda x: x[1], vcil))

392
  def test_06_getVariationCategoryItemList(self, quiet=quiet, run=run_all_test):
Romain Courteaud's avatar
Romain Courteaud committed
393 394 395 396
    """
      Test the method getVariationCategoryItemList on a resource.
    """
    if not run: return
397
    self.genericTest('CheckGetVariationCategoryItemList', quiet)
Romain Courteaud's avatar
Romain Courteaud committed
398

Kevin Deldycke's avatar
Kevin Deldycke committed
399
  def stepCheckGetVariationCategoryItemListWithoutOmit(self, sequence=None,
Romain Courteaud's avatar
Romain Courteaud committed
400 401 402 403 404 405 406 407 408 409
                                                 sequence_list=None, **kw):
    """
      Check if getVariationCategoryItemList returns the good result,
      with parameter omit_individual_variation=0.
    """
    resource = sequence.get('resource')
    vcl = resource.getVariationCategoryList(omit_individual_variation=0)
    vcil = resource.getVariationCategoryItemList(omit_individual_variation=0)
    self.failIfDifferentSet(vcl, map(lambda x: x[1], vcil))

410
  def test_07_getVariationCategoryItemList(self, quiet=quiet, run=run_all_test):
Romain Courteaud's avatar
Romain Courteaud committed
411 412 413 414 415
    """
      Test the method getVariationCategoryItemList on a resource
      with parameter omit_individual_variation=0.
    """
    if not run: return
416 417
    self.genericTest('CheckGetVariationCategoryItemListWithoutOmit',
        quiet=quiet)
Romain Courteaud's avatar
Romain Courteaud committed
418

Kevin Deldycke's avatar
Kevin Deldycke committed
419
  def stepCheckGetVariationPropertyList(self, sequence=None,
420 421 422 423 424 425 426 427 428
                                        sequence_list=None, **kw):
    """
      Check if GetVariationPropertyList exists on a resource.
    """
    resource = sequence.get('resource')
    vpl = sequence.get('variation_property_list')
    self.failIfDifferentSet(resource.getVariationPropertyList(),
                            vpl)

Kevin Deldycke's avatar
Kevin Deldycke committed
429
  def stepCheckSetVariationPropertyList(self, sequence=None,
430 431 432 433 434 435 436 437 438 439 440 441
                                        sequence_list=None, **kw):
    """
      Check if SetVariationPropertyList exists on a resource.
      And test it.
    """
    resource = sequence.get('resource')
    vpl = ['prop1', 'prop2']
    sequence.edit(variation_property_list=vpl)
    resource.setVariationPropertyList(vpl)
    self.failIfDifferentSet(resource.variation_property_list,
                            vpl)

442
  def test_08_variationPropertyList(self, quiet=quiet, run=run_all_test):
443 444 445 446 447 448 449 450 451 452 453 454 455
    """
      Simply test if method are well generated by the property sheet.
    """
    if not run: return
    sequence_list = SequenceList()
    # Test when resource has no variation
    sequence_string = '\
                      CreateResource \
                      CheckGetVariationPropertyList \
                      CheckSetVariationPropertyList \
                      CheckGetVariationPropertyList \
                      '
    sequence_list.addSequenceString(sequence_string)
456
    sequence_list.play(self, quiet=quiet)
457

458 459 460 461 462 463 464
  def getPriceConfig(self):
    """
    Define somes cases of pricing configuration to test.
    """
    config = [
      {
        'base_price': None,
465 466 467
        'additional_price': None,
        'surcharge_ratio': None,
        'discount_ratio': None,
468 469 470 471
        'exclusive_discount_ratio': None,
        'price': None,
      },{
        'base_price': 5,
472 473 474
        'additional_price': None,
        'surcharge_ratio': None,
        'discount_ratio': None,
475 476 477 478
        'exclusive_discount_ratio': None,
        'price': 5,
      },{
        'base_price': 5,
479 480 481
        'additional_price': 1,
        'surcharge_ratio': None,
        'discount_ratio': None,
482 483 484 485
        'exclusive_discount_ratio': None,
        'price': 6,
      },{
        'base_price': 5,
486 487 488
        'additional_price': 3,
        'surcharge_ratio': 0.5,
        'discount_ratio': None,
489 490 491 492
        'exclusive_discount_ratio': None,
        'price': 12,
      },{
        'base_price': 5,
493 494 495
        'additional_price': 3,
        'surcharge_ratio': None,
        'discount_ratio': 0.25,
496 497 498 499
        'exclusive_discount_ratio': None,
        'price': 6,
      },{
        'base_price': 5,
500 501 502
        'additional_price': 3,
        'surcharge_ratio': None,
        'discount_ratio': None,
503 504 505 506
        'exclusive_discount_ratio': 0.5,
        'price': 4,
      },{
        'base_price': 5,
507 508 509
        'additional_price': 3,
        'surcharge_ratio': None,
        'discount_ratio': 0.5,
510 511 512 513
        'exclusive_discount_ratio': 0.75,
        'price': 2,
      },{
        'base_price': 5,
514 515 516
        'additional_price': 3,
        'surcharge_ratio': None,
        'discount_ratio': 0.75,
517 518 519 520
        'exclusive_discount_ratio': 0.25,
        'price': 2,
      },{
        'base_price': 5,
521 522 523
        'additional_price': 3,
        'surcharge_ratio': 1,
        'discount_ratio': 0.75,
524
        'exclusive_discount_ratio': 0.25,
525
        'price': 4,
526 527
      },{
        'base_price': None,
528 529 530
        'additional_price': 3,
        'surcharge_ratio': 1,
        'discount_ratio': 0.75,
531 532 533 534 535 536 537 538 539 540
        'exclusive_discount_ratio': 0.25,
        'price': None,
      }
    ]
    return config

  def logMessage(self, msg, tab=0):
    """
    Log a message.
    """
541 542
    if self.quiet:
      return
543 544 545 546 547
    if tab:
      msg = '  %s' % msg
    ZopeTestCase._print('\n%s' % msg)
    LOG('testResource.play', 0, msg)

548
  def test_09_getPrice(self, quiet=quiet, run=run_all_test):
549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574
    """
    Test the pricing model.
    """
    if not run: return
    config_list = self.getPriceConfig()
    for i in range(0, len(config_list)):
      self.logMessage("Starting New Pricing Case %i..." % i)
      config = config_list[i]
      # Create product
      self.logMessage("Creating product...", tab=1)
      product_module = self.portal.getDefaultModule(self.product_portal_type)
      product = product_module.newContent( \
                                   portal_type=self.product_portal_type,
                                   title='Product%i' % i)
      # Configure pricing parameters
      for key, value in config.items():
        if key != 'price':
          if value not in [None, []]:
            if type(value) != type([]):
              value_list = [value]
            else:
              value_list = value
            # Create requested supply line
            for pricing_param in value_list:
              self.logMessage("Creating supply line...", tab=1)
              supply_line = product.newContent(
575
                    portal_type=self.sale_supply_line_portal_type)
576
              # Set pricing parameter
577 578
              self.logMessage("Set %s on supply line with value %s..." % \
                              (key, str(pricing_param)), tab=1)
579 580 581 582 583 584 585 586 587 588 589
              supply_line.setProperty(key, pricing_param)
      # Commit transaction
      self.logMessage("Commit transaction...", tab=1)
      get_transaction().commit()
      # Tic
      self.logMessage("Tic...", tab=1)
      self.tic()
      # Check resource price
      self.logMessage("Check product price...", tab=1)
      self.assertEquals(config['price'], product.getPrice())

590
  def test_10_getPriceWithOptions(self, quiet=quiet, run=run_all_test):
591 592 593 594 595 596
    """
    Test the pricing model on a resource with options.
    """
    if not run: return
    i = 1
    self.logMessage("Starting New Option Pricing Case %i..." % i)
597 598 599 600 601 602
    # Fill the PDM preferences
    preference = self.portal.portal_preferences.default_site_preference
    preference.setPreferredProductOptionalVariationBaseCategoryList(['industrial_phase'])
    preference.enable()
    get_transaction().commit()
    self.tic()
Kevin Deldycke's avatar
Kevin Deldycke committed
603
    # Create another product/supply, in order to be sure that the
604 605 606 607 608 609 610 611 612
    # nothing will be generated from this supply!
    self.logMessage("Creating fake product...", tab=1)
    product_module = self.portal.getDefaultModule(self.product_portal_type)
    product = product_module.newContent( \
                                 portal_type=self.product_portal_type,
                                 title='FakeProduct%i' % i)
    product.setVariationCategoryList(self.industrial_phase_category_list)
    self.logMessage("Creating supply line...", tab=1)
    supply_line = product.newContent(
613
          portal_type=self.sale_supply_line_portal_type)
614 615 616 617
    supply_line.setProperty('base_price', 100)
    supply_line.setSurchargeRatioQuantityStepList([])
    supply_line.getCellKeyList(base_id='path_optional_surcharge_ratio')
    cell1 = supply_line.newCell('industrial_phase/phase1',
618
        base_id='path_optional_surcharge_ratio', 
619
        portal_type=self.sale_supply_cell_portal_type)
620 621 622 623
    cell1.setSurchargeRatio(20)
    cell1.setMappedValuePropertyList(["surcharge_ratio"])
    cell1.setMembershipCriterionBaseCategory('industrial_phase')
    cell1.setMembershipCriterionCategory('industrial_phase/phase1')
624 625 626 627 628 629 630 631 632 633 634
    # Create product
    self.logMessage("Creating product...", tab=1)
    product_module = self.portal.getDefaultModule(self.product_portal_type)
    product = product_module.newContent( \
                                 portal_type=self.product_portal_type,
                                 title='Product%i' % i)
    # Select some options on the resource
    product.setVariationCategoryList(self.industrial_phase_category_list)
    # Create requested supply line
    self.logMessage("Creating supply line...", tab=1)
    supply_line = product.newContent(
635
          portal_type=self.sale_supply_line_portal_type)
636 637 638 639 640 641
    # Set pricing parameter
    supply_line.setProperty('base_price', 1)
    # Define the additional price matrix range
    supply_line.setAdditionalPriceQuantityStepList([])
    supply_line.getCellKeyList(base_id='path_optional_additional_price')
    cell1 = supply_line.newCell('industrial_phase/phase1',
642
        base_id='path_optional_additional_price', 
643
        portal_type=self.sale_supply_cell_portal_type)
644
    cell1.setAdditionalPrice(2)
645 646 647
    cell1.setMappedValuePropertyList(["additional_price"])
    cell1.setMembershipCriterionBaseCategory('industrial_phase')
    cell1.setMembershipCriterionCategory('industrial_phase/phase1')
648
    cell2 = supply_line.newCell('industrial_phase/phase2',
649
        base_id='path_optional_additional_price', 
650
        portal_type=self.sale_supply_cell_portal_type)
651
    cell2.setAdditionalPrice(7)
652 653 654
    cell2.setMappedValuePropertyList(["additional_price"])
    cell2.setMembershipCriterionBaseCategory('industrial_phase')
    cell2.setMembershipCriterionCategory('industrial_phase/phase2')
655 656 657 658 659 660 661
    # Commit transaction
    self.logMessage("Commit transaction...", tab=1)
    get_transaction().commit()
    # Tic
    self.logMessage("Tic...", tab=1)
    self.tic()
    # Check resource price
662
    self.logMessage("Check product price without option...", tab=1)
663 664
    self.assertEquals(1, product.getPrice(context=supply_line))
    # Check resource option price
665 666
    self.logMessage("Check product price with option: %s..." % \
                    'industrial_phase/phase1', tab=1)
667 668
    self.assertEquals(3, product.getPrice(
                                   categories=['industrial_phase/phase1']))
669 670
    self.logMessage("Check product price with option: %s..." % \
                    'industrial_phase/phase2', tab=1)
671 672
    self.assertEquals(8, product.getPrice(
                                   categories=['industrial_phase/phase2']))
673 674 675 676 677
    self.logMessage("Check product price with options: %s..." % \
                    'industrial_phase/phase1 industrial_phase/phase2', tab=1)
    self.assertEquals(10, product.getPrice(
                                   categories=['industrial_phase/phase1',
                                               'industrial_phase/phase2']))
678

679
  def test_11_getPriceWithDestinationSection(self, quiet=quiet, run=run_all_test):
680 681
    """
    Test the pricing model with multiple price for 
682
    differents destination sections.
683 684 685 686 687 688
    """
    if not run: return
    # Initialize variables
    test_case_list = []
    # Create product
    product_module = self.portal.getDefaultModule(self.product_portal_type)
689
    supply_module = self.portal.getDefaultModule(self.sale_supply_portal_type)
690
    currency_module = self.portal.getDefaultModule("Currency")
691
    currency = currency_module.newContent(
692 693 694 695 696
                     portal_type="Currency",
                     title='A great currency')
    # Create generic supply
    self.logMessage("Creating generic fake supply ...", tab=1)
    generic_supply = supply_module.newContent(
697
                     portal_type=self.sale_supply_portal_type,
698 699 700 701
                     title='FakeGenericSupply',
                     price_currency_value=currency)
    # Create empty supply line
    supply_line = generic_supply.newContent(
702
          portal_type=self.sale_supply_line_portal_type)
703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718
    supply_line.setProperty('base_price', 0)
    for j in range(33, 35):
      self.logMessage("Creating fake product %s..." % j, tab=1)
      product = product_module.newContent(
                           portal_type=self.product_portal_type,
                           title='AnotherFakeProduct%s' % j)
      # Create some nodes
      node_module = self.portal.getDefaultModule(self.node_portal_type)
      for i in range(11, 14):
        self.logMessage("Creating fake node %s..." % i, tab=1)
        node = node_module.newContent(
                       portal_type=self.node_portal_type,
                       title='FakeNode%s%s' % (j, i))
        # Create a supply
        self.logMessage("Creating fake supply %s..." % i, tab=1)
        supply = supply_module.newContent(
719
                                     portal_type=self.sale_supply_portal_type,
720
                                     title='FakeSupply%s' % i,
721
                                     price_currency_value=currency,
722
                                     destination_section_value=node)
723 724
        self.logMessage("Creating fake supply line %s..." % i, tab=1)
        supply_line = supply.newContent(
725
              portal_type=self.sale_supply_line_portal_type,
726 727 728 729 730 731 732 733 734
              resource_value=product)
        # Set pricing parameter
        base_price = i*j
        supply_line.setProperty('base_price', base_price)
        # Register the case
        test_case_list.append((product, node, base_price))
      # Create generic supply line
      self.logMessage("Creating generic fake supply line ...", tab=1)
      supply_line = generic_supply.newContent(
735
            portal_type=self.sale_supply_line_portal_type,
736 737 738 739 740 741 742 743 744 745 746 747
            resource_value=product)
      supply_line.setProperty('base_price', j)
      test_case_list.append((product, None, j))
    # Commit transaction
    self.logMessage("Commit transaction...", tab=1)
    get_transaction().commit()
    # Tic
    self.logMessage("Tic...", tab=1)
    self.tic()
    # Test the cases
    for product, node, base_price in test_case_list:
      if node is not None:
748
        self.logMessage("Check product %s with destination section %s" % \
749 750 751 752
                        (product.getTitle(), node.getTitle()),
                        tab=1)
        self.assertEquals(base_price, 
                          product.getPrice(
753
                    categories=['destination_section/%s' % node.getRelativeUrl()]))
754
      else:
755
        self.logMessage("Check product %s without destination section" % \
756 757 758 759
                        product.getTitle(),
                        tab=1)
        self.assertEquals(base_price, 
                          product.getPrice())
760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879

  def test_11b_getPriceWithCells(self, quiet=quiet, run=run_all_test):
    """
    Test the pricing model with multiple price for 
    differents destination sections, using supply cells
    """
    if not run: return
    # Initialize variables
    test_case_list = []
    # Create product
    product_module = self.portal.getDefaultModule(self.product_portal_type)
    supply_module = self.portal.getDefaultModule(self.sale_supply_portal_type)
    currency_module = self.portal.getDefaultModule("Currency")
    currency = currency_module.newContent(
                     portal_type="Currency",
                     title='A great currency')
    # Create generic supply
    self.logMessage("Creating generic fake supply ...", tab=1)
    generic_supply = supply_module.newContent(
                     portal_type=self.sale_supply_portal_type,
                     title='FakeGenericSupply',
                     price_currency_value=currency)
    # Create empty supply line
    supply_line = generic_supply.newContent(
          portal_type=self.sale_supply_line_portal_type)
    supply_line.setProperty('base_price', 0)
    for j in range(33, 35):
      self.logMessage("Creating fake product %s..." % j, tab=1)
      product = product_module.newContent(
                           portal_type=self.product_portal_type,
                           title='AnotherFakeProduct%s' % j)
      product.setVariationBaseCategoryList(['size'])
      product.setVariationCategoryList(['size/Baby', 'size/Man'])
      # Create some nodes
      node_module = self.portal.getDefaultModule(self.node_portal_type)
      for i in range(11, 14):
        self.logMessage("Creating fake node %s..." % i, tab=1)
        node = node_module.newContent(
                       portal_type=self.node_portal_type,
                       title='FakeNode%s%s' % (j, i))
        # Create a supply
        self.logMessage("Creating fake supply %s..." % i, tab=1)
        supply = supply_module.newContent(
                                     portal_type=self.sale_supply_portal_type,
                                     title='FakeSupply%s' % i,
                                     price_currency_value=currency,
                                     destination_section_value=node)

        if 0:
          # XXX if both a supply line for the resource and a supply cell for
          # the resource with the exact variation can be applied, one of them
          # is choosen randomly. It looks like a bug, but I'm not sure we
          # should handle such situation.
          self.logMessage("Creating wrong supply line %s..." % i, tab=1)
          wrong_supply_line = supply.newContent(
                portal_type=self.sale_supply_line_portal_type,
                resource_value=product)
          wrong_supply_line.setBasePrice(12454326)

        self.logMessage("Creating fake supply line %s..." % i, tab=1)
        supply_line = supply.newContent(
              portal_type=self.sale_supply_line_portal_type,
              resource_value=product)
        supply_line.setPVariationBaseCategoryList(['size'])
        supply_line.updateCellRange(base_id='path')

        baby_cell = supply_line.newCell('size/Baby',
                           portal_type=self.sale_supply_cell_portal_type)
        baby_cell.setVariationCategoryList(['size/Baby'])
        baby_cell.setPredicateCategoryList(['size/Baby'])
        baby_cell.setMappedValuePropertyList(['base_price'])
        baby_cell.setMembershipCriterionBaseCategory('size')
        baby_cell.setMembershipCriterionCategory('size/Baby')
        base_price = i*j
        baby_cell.setProperty('base_price', base_price)
        # Register the case
        test_case_list.append((product, 'size/Baby', node, base_price))

        man_cell = supply_line.newCell('size/Man',
                        portal_type=self.sale_supply_cell_portal_type)
        man_cell.setVariationCategoryList(['size/Man'])
        man_cell.setPredicateCategoryList(['size/Man'])
        man_cell.setMappedValuePropertyList(['base_price'])
        man_cell.setMembershipCriterionBaseCategory('size')
        man_cell.setMembershipCriterionCategory('size/Man')
        base_price = i*j+3
        man_cell.setProperty('base_price', base_price)
        # Register the case
        test_case_list.append((product, 'size/Man', node, base_price))

      # Create generic supply line
      self.logMessage("Creating generic fake supply line ...", tab=1)
      supply_line = generic_supply.newContent(
            portal_type=self.sale_supply_line_portal_type,
            resource_value=product)
      supply_line.setProperty('base_price', j)
      test_case_list.append((product, None, None, j))

    # Commit transaction
    self.logMessage("Commit transaction...", tab=1)
    get_transaction().commit()
    # Tic
    self.logMessage("Tic...", tab=1)
    self.tic()
    # Test the cases
    for product, variation, node, base_price in test_case_list:
      if node is not None:
        self.logMessage("Check product %s with destination section %s" % \
                        (product.getTitle(), node.getTitle()),
                        tab=1)
        self.assertEquals(base_price,
             product.getPrice(
               categories=['destination_section/%s' % node.getRelativeUrl(),
                           variation]))
      else:
        self.logMessage("Check product %s without destination section" % \
                        product.getTitle(),
                        tab=1)
        self.assertEquals(base_price,
                          product.getPrice(categories=[variation]))
880
  
881

882
  def test_12_getPurchaseVsSalePrice(self, quiet=quiet, run=run_all_test):
883 884
    """
    Test the pricing model with purchase and sale supply lines, and with
885
    source_section/destination_section.
886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911
    """
    if not run: return
    # Initialize variables
    product_module = self.portal.getDefaultModule(self.product_portal_type)
    organisation_module = self.getOrganisationModule()
    currency_module = self.getCurrencyModule()
    sale_order_module = self.portal.getDefaultModule("Sale Order")
    purchase_order_module = self.portal.getDefaultModule("Purchase Order")
    # Create currency and product
    currency = currency_module.newContent(
                     portal_type="Currency",
                     title='A great currency')
    product = product_module.newContent(
        portal_type=self.product_portal_type,
        title="yet another product")
    # Create organisations
    orga1 = organisation_module.newContent(
        portal_type="Organisation",
        title="orga1")
    orga2 = organisation_module.newContent(
        portal_type="Organisation",
        title="orga2")
    # Create sale supply lines
    product.newContent(
        portal_type=self.sale_supply_line_portal_type,
        base_price=100.0,
912
        destination_section_value=orga1)
913 914 915
    product.newContent(
        portal_type=self.sale_supply_line_portal_type,
        base_price=200.0,
916
        destination_section_value=orga2)
917 918 919 920 921 922 923
    product.newContent(
        portal_type=self.sale_supply_line_portal_type,
        base_price=400.0)
    # Create purchase supply lines
    product.newContent(
        portal_type=self.purchase_supply_line_portal_type,
        base_price=10.0,
924
        source_section_value=orga1)
925 926 927
    product.newContent(
        portal_type=self.purchase_supply_line_portal_type,
        base_price=20.0,
928
        source_section_value=orga2)
929 930 931 932 933 934 935 936 937 938 939 940 941 942
    product.newContent(
        portal_type=self.purchase_supply_line_portal_type,
        base_price=40.0)
    # Create sale order and check price
    sale_order = sale_order_module.newContent(
        portal_type="Sale Order",
        start_date=DateTime(),
        stop_date=DateTime())
    sale_order_line = sale_order.newContent(
        portal_type="Sale Order Line",
        resource_value=product)
    get_transaction().commit()
    self.tic()
    self.assertEquals(sale_order_line.getPrice(), 400.0)
943
    sale_order.setDestinationSectionValue(orga2)
944 945 946 947 948 949 950 951 952 953 954 955 956 957 958
    get_transaction().commit()
    self.tic()
    sale_order_line.setPrice(None)
    self.assertEquals(sale_order_line.getPrice(), 200.0)
    # Create purchase order and check price
    purchase_order = purchase_order_module.newContent(
        portal_type="Purchase Order",
        start_date=DateTime(),
        stop_date=DateTime())
    purchase_order_line = purchase_order.newContent(
        portal_type="Purchase Order Line",
        resource_value=product)
    get_transaction().commit()
    self.tic()
    self.assertEquals(purchase_order_line.getPrice(), 40.0)
959
    purchase_order.setSourceSectionValue(orga2)
960 961 962 963 964
    get_transaction().commit()
    self.tic()
    purchase_order_line.setPrice(None)
    self.assertEquals(purchase_order_line.getPrice(), 20.0)
  
965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989
  def testGetPriceWithQuantityUnit(self):
    resource = self.portal.getDefaultModule(self.product_portal_type)\
                .newContent(portal_type=self.product_portal_type)
    resource.setDefaultQuantityUnitValue(self.quantity_unit_kilo)
    supply_line = resource.newContent(
                    portal_type=self.sale_supply_line_portal_type)
    supply_line.setBasePrice(1000)
    get_transaction().commit()
    self.tic()
    sale_order = self.portal.getDefaultModule("Sale Order").newContent(
                              portal_type='Sale Order',)
    sale_order_line = sale_order.newContent(
                          resource_value=resource,
                          quantity=5)
    self.assertEquals(1000, sale_order_line.getPrice())
    self.assertEquals(5000, sale_order_line.getTotalPrice())
    
    # if we give the quantity unit in grams
    sale_order_line = sale_order.newContent(
                          resource_value=resource,
                          quantity=5000,
                          quantity_unit_value=self.quantity_unit_gram)
    self.assertEquals(1, sale_order_line.getPrice())
    self.assertEquals(5000, sale_order_line.getTotalPrice())

990 991 992 993 994 995 996 997 998 999 1000
  def testQuantityPrecision(self):
    """test how to define quantity precision on resources.
    """
    resource = self.portal.getDefaultModule(self.product_portal_type)\
                .newContent(portal_type=self.product_portal_type)
    # default is 1
    self.assertEquals(1, resource.getBaseUnitQuantity())
    self.assertEquals(0, resource.getQuantityPrecision())
    # quantity precision is calculated using base quantity unit
    resource.setBaseUnitQuantity(0.001)
    self.assertEquals(3, resource.getQuantityPrecision())
1001

1002 1003 1004 1005 1006

def test_suite():
  suite = unittest.TestSuite()
  suite.addTest(unittest.makeSuite(TestResource))
  return suite