Exemplo n.º 1
0
    def generateMovementListForStockOptimisation(self, **kw):
        # XXX: unused
        from Products.ERP5Type.Document import newTempMovement

        movement_list = []
        for attribute, method in [("node_uid", "getDestinationUid"), ("section_uid", "getDestinationSectionUid")]:
            if getattr(self, method)() not in ("", None):
                kw[attribute] = getattr(self, method)()
        # We have to check the inventory for each stock movement date.
        # Inventory can be negative in some date, and positive in futur !!
        # This must be done by subclassing OrderBuilder with a new inventory
        # algorithm.
        sql_list = self.portal_simulation.getFutureInventoryList(
            group_by_variation=1, group_by_resource=1, group_by_node=1, group_by_section=0, **kw
        )
        id_count = 0
        for inventory_item in sql_list:
            # XXX FIXME SQL return None inventory...
            # It may be better to return always good values
            if inventory_item.inventory is not None:
                dumb_movement = inventory_item.getObject()
                # Create temporary movement
                movement = newTempMovement(self.getPortalObject(), str(id_count))
                id_count += 1
                movement.edit(
                    resource=inventory_item.resource_relative_url,
                    variation_category_list=dumb_movement.getVariationCategoryList(),
                    destination_value=self.getDestinationValue(),
                    destination_section_value=self.getDestinationSectionValue(),
                )
                # We can do other test on inventory here
                # XXX It is better if it can be sql parameters
                resource_portal_type = self.getResourcePortalType()
                resource = movement.getResourceValue()
                # FIXME: XXX Those properties are defined on a supply line !!
                # min_flow, max_delay
                min_flow = resource.getMinFlow(0)
                if (resource.getPortalType() == resource_portal_type) and (
                    round(inventory_item.inventory, 5) < min_flow
                ):
                    # FIXME XXX getNextNegativeInventoryDate must work
                    stop_date = DateTime() + 10
                    #         stop_date = resource.getNextNegativeInventoryDate(
                    #                               variation_text=movement.getVariationText(),
                    #                               from_date=DateTime(),
                    # #                             node_category=node_category,
                    # #                             section_category=section_category)
                    #                               node_uid=self.getDestinationUid(),
                    #                               section_uid=self.getDestinationSectionUid())
                    max_delay = resource.getMaxDelay(0)
                    movement.edit(
                        start_date=DateTime(((stop_date - max_delay).Date())),
                        stop_date=DateTime(stop_date.Date()),
                        quantity=min_flow - inventory_item.inventory,
                        quantity_unit=resource.getQuantityUnit()
                        # XXX FIXME define on a supply line
                        # quantity_unit
                    )
                    movement_list.append(movement)
        return movement_list
Exemplo n.º 2
0
 def test_PropertyCriterion(self):
     movement = newTempMovement(self.portal, 'tmp')
     predicate = self.createPredicate()
     predicate.setCriterionPropertyList(['quantity'])
     request = self.portal.REQUEST
     request.set(
         'listbox',
         {'quantity': {
             'max': '',
             'identity': [],
             'min': ''
         }},
     )
     predicate.Predicate_edit('Predicate_view')
     self.assertEqual(predicate._identity_criterion, {'quantity': []})
     self.assertEqual(predicate._range_criterion, {})
     self.assertTrue(predicate.test(movement))
     request.set(
         'listbox',
         {'quantity': {
             'max': '',
             'identity': [],
             'min': 1.0
         }},
     )
     predicate.Predicate_edit('Predicate_view')
     self.assertEqual(predicate._range_criterion, {'quantity': (1.0, None)})
     self.assertFalse(predicate.test(movement.asContext(quantity=0.5)))
     self.assertTrue(predicate.test(movement.asContext(quantity=1.0)))
     request.set(
         'listbox',
         {'quantity': {
             'max': 2.0,
             'identity': [],
             'min': ''
         }},
     )
     predicate.Predicate_edit('Predicate_view')
     self.assertEqual(predicate._range_criterion, {'quantity': (None, 2.0)})
     self.assertFalse(predicate.test(movement.asContext(quantity=2.0)))
     self.assertTrue(predicate.test(movement.asContext(quantity=1.5)))
     request.set(
         'listbox',
         {'quantity': {
             'max': 2.0,
             'identity': [],
             'min': 1.0
         }},
     )
     predicate.Predicate_edit('Predicate_view')
     self.assertEqual(predicate._range_criterion, {'quantity': (1.0, 2.0)})
     self.assertFalse(predicate.test(movement.asContext(quantity=0.5)))
     self.assertTrue(predicate.test(movement.asContext(quantity=1.0)))
     self.assertTrue(predicate.test(movement.asContext(quantity=1.5)))
     self.assertFalse(predicate.test(movement.asContext(quantity=2.0)))
Exemplo n.º 3
0
 def newMovement(inventory_item, resource):
   # Create temporary movement
   movement = newTempMovement(self.getPortalObject(), "temp")
   dumb_movement = inventory_item.getObject()
   resource_portal_type = resource.getPortalType()
   assert resource_portal_type in (resource_portal_type_list), \
     "Builder %r does not support resource of type : %r" % (
     self.getRelativeUrl(), resource_portal_type)
   movement.edit(
       resource=inventory_item.resource_relative_url,
       # XXX FIXME define on a supply line
       # quantity_unit
       quantity_unit=resource.getQuantityUnit(),
       variation_category_list=dumb_movement.getVariationCategoryList(),
       destination_value=self.getDestinationValue(),
       resource_portal_type=resource_portal_type,
       destination_section_value=self.getDestinationSectionValue())
   return movement
Exemplo n.º 4
0
 def newMovement(inventory_item, resource):
     # Create temporary movement
     movement = newTempMovement(self.getPortalObject(), "temp")
     dumb_movement = inventory_item.getObject()
     resource_portal_type = resource.getPortalType()
     assert resource_portal_type in resource_portal_type_list, \
       "Builder %r does not support resource of type : %r" % (
       self.getRelativeUrl(), resource_portal_type)
     movement.edit(
         resource=inventory_item.resource_relative_url,
         # XXX FIXME define on a supply line
         # quantity_unit
         quantity_unit=resource.getQuantityUnit(),
         destination_value=self.getDestinationValue(),
         resource_portal_type=resource_portal_type,
         destination_section_value=self.getDestinationSectionValue())
     # define variation after resource is set
     movement.edit(variation_text=inventory_item.variation_text)
     return movement
Exemplo n.º 5
0
 def generateMovementListForStockOptimisation(self, **kw):
     # XXX: unused
     from Products.ERP5Type.Document import newTempMovement
     movement_list = []
     for attribute, method in [('node_uid', 'getDestinationUid'),
                               ('section_uid', 'getDestinationSectionUid')]:
         if getattr(self, method)() not in ("", None):
             kw[attribute] = getattr(self, method)()
     # We have to check the inventory for each stock movement date.
     # Inventory can be negative in some date, and positive in futur !!
     # This must be done by subclassing OrderBuilder with a new inventory
     # algorithm.
     sql_list = self.portal_simulation.getFutureInventoryList(
         group_by_variation=1,
         group_by_resource=1,
         group_by_node=1,
         group_by_section=0,
         **kw)
     id_count = 0
     for inventory_item in sql_list:
         # XXX FIXME SQL return None inventory...
         # It may be better to return always good values
         if (inventory_item.inventory is not None):
             dumb_movement = inventory_item.getObject()
             # Create temporary movement
             movement = newTempMovement(self.getPortalObject(),
                                        str(id_count))
             id_count += 1
             movement.edit(resource=inventory_item.resource_relative_url,
                           variation_category_list=dumb_movement.
                           getVariationCategoryList(),
                           destination_value=self.getDestinationValue(),
                           destination_section_value=self.
                           getDestinationSectionValue())
             # We can do other test on inventory here
             # XXX It is better if it can be sql parameters
             resource_portal_type = self.getResourcePortalType()
             resource = movement.getResourceValue()
             # FIXME: XXX Those properties are defined on a supply line !!
             # min_flow, max_delay
             min_flow = resource.getMinFlow(0)
             if (resource.getPortalType() == resource_portal_type) and\
                (round(inventory_item.inventory, 5) < min_flow):
                 # FIXME XXX getNextNegativeInventoryDate must work
                 stop_date = DateTime() + 10
                 #         stop_date = resource.getNextNegativeInventoryDate(
                 #                               variation_text=movement.getVariationText(),
                 #                               from_date=DateTime(),
                 # #                             node_category=node_category,
                 # #                             section_category=section_category)
                 #                               node_uid=self.getDestinationUid(),
                 #                               section_uid=self.getDestinationSectionUid())
                 max_delay = resource.getMaxDelay(0)
                 movement.edit(
                     start_date=DateTime(((stop_date - max_delay).Date())),
                     stop_date=DateTime(stop_date.Date()),
                     quantity=min_flow - inventory_item.inventory,
                     quantity_unit=resource.getQuantityUnit()
                     # XXX FIXME define on a supply line
                     # quantity_unit
                 )
                 movement_list.append(movement)
     return movement_list
#   { id:resource_id,
#     variation_text: resource_variation_text,
#     row_dict_list: list of rows to insert; each row is represented as a dict.}
row_dict_dict_list = []

portal = context.getPortalObject()
for transformation_relative_url, variation_list_list in transformation_item_list:
  transformation = portal.restrictedTraverse(transformation_relative_url)
  resource = transformation.getResourceValue()

  if resource is None:
    continue
  for variation_list in variation_list_list:
    movement = newTempMovement(resource, 'temp',
                               specialise_value=transformation,
                               variation_category_list=variation_list,
                               resource_value=resource,
                               quantity=1.0)
    base_row = dict(uid=resource.getUid(), variation_text=movement.getVariationText())

    row_dict_list = []
    for amount in movement.getAggregatedAmountList():
      transformed_resource_uid = amount.getResourceUid()
      quantity = amount.getQuantity()
      if transformed_resource_uid is not None and quantity is not None:
        row_dict = base_row.copy()
        row_dict.update(transformed_uid=transformed_resource_uid,
                        transformed_variation_text=amount.getVariationText(),
                        quantity=quantity)
        row_dict_list.append(row_dict)
Exemplo n.º 7
0
  def _getInputMovementList(self, movement_list=None, rounding=None):
    """
      Generate the list of input movements by looking at all
      open order lines relating to this subscription item.

      TODO: clever handling of quantity (based on the nature
      of resource, ie. float or unit)
    """
    from Products.ERP5Type.Document import newTempMovement
    result = []
    catalog_tool = getToolByName(self, 'portal_catalog')

    # Try to find the source open order
    open_order_movement_list = self.getAggregateRelatedValueList(
                portal_type="Open Sale Order Line") # XXX-JPS Hard Coded    
    if not open_order_movement_list:
      return result

    # Find out which parent open orders
    explanation_uid_list = map(lambda x:x.getParentUid(), open_order_movement_list) # Instead, should call getDeliveryValue or equivalent
    open_order_list = catalog_tool.searchResults(uid = explanation_uid_list,
                                                 validation_state = 'validated') # XXX-JPS hard coding

    # Now generate movements for each valid open order
    for movement in open_order_movement_list:
      if movement.getParentValue().getValidationState() in ('open', 'validated'): # XXX-JPS hard coding
        resource = movement.getResource()
        start_date = movement.getStartDateRangeMin() # Is this appropriate ?
        stop_date = movement.getStartDateRangeMax() # Is this appropriate ?
        source = movement.getSource()
        source_section = movement.getSourceSection()
        destination = movement.getDestination()
        destination_section = movement.getDestinationSection() # XXX More arrows ? use context instead ?
        quantity = self.getQuantity() # Is it so ? XXX-JPS
        quantity_unit = movement.getQuantityUnit()
        price = movement.getPrice()
        specialise = movement.getSpecialise()
        current_date = self.getNextPeriodicalDate(start_date)
        id_index = 0
        while current_date < stop_date:
          next_date = self.getNextPeriodicalDate(current_date)
          generated_movement = newTempMovement(self, 'subscription_%s' % id_index)
          generated_movement._edit(  aggregate_value=self,
                                     resource=resource,
                                     quantity=quantity,
                                     quantity_unit=quantity_unit,
                                     price=price,
                                     start_date=current_date,
                                     stop_date=next_date,
                                     source=source,
                                     source_section=source_section,
                                     destination=destination,
                                     destination_section=destination_section,
                                     specialise=specialise,
                                #     delivery_value=movement # ??? to be confirmed - if we want order step or not
                                    )
          result.append(generated_movement)
          current_date = next_date
          id_index += 1

    # And now return result
    return result
Exemplo n.º 8
0
 def _getPriceContext(self, **kw):
     """Returns a temp movement that we can use for getPrice(context=
 """
     from Products.ERP5Type.Document import newTempMovement
     return newTempMovement(self.portal, 'tmp', **kw)
 def _getPriceContext(self, **kw):
   """Returns a temp movement that we can use for getPrice(context=
   """
   from Products.ERP5Type.Document import newTempMovement
   return newTempMovement(self.portal, 'tmp', **kw)
Exemplo n.º 10
0
  def _getInputMovementList(self, movement_list=None, rounding=None):
    """
      Generate the list of input movements by looking at all
      open order lines relating to this subscription item.

      TODO: clever handling of quantity (based on the nature
      of resource, ie. float or unit)
    """
    from Products.ERP5Type.Document import newTempMovement
    result = []

    # Try to find the source open order
    open_order_movement_list = self.getAggregateRelatedValueList(
                portal_type="Open Sale Order Line") # XXX-JPS Hard Coded
    if not open_order_movement_list:
      return result

    # Now generate movements for each valid open order
    for movement in open_order_movement_list: # YXU-Why we have a list here?
      if movement.getParentValue().getValidationState() in ('open', 'validated'): # XXX-JPS hard coding
        resource = movement.getResource()
        start_date = movement.getStartDate()
        stop_date = movement.getStopDate()
        source = movement.getSource()
        source_section = movement.getSourceSection()
        source_decision = movement.getSourceDecision()
        destination = movement.getDestination()
        destination_section = movement.getDestinationSection()
        destination_decision = movement.getDestinationDecision()
        quantity = movement.getQuantity()
        quantity_unit = movement.getQuantityUnit()
        price = movement.getPrice()
        price_currency = movement.getPriceCurrency()
        base_application_list = movement.getBaseApplicationList()
        base_contribution_list = movhement.getBaseContributionList()
        use_list = movement.getUseList()

        specialise = movement.getSpecialise()
        current_date = start_date
        id_index = 0
        while current_date < stop_date:
          next_date = self.getNextPeriodicalDate(current_date)
          if next_date > stop_date:
            next_date = stop_date
          generated_movement = newTempMovement(self, 'subscription_%s' % id_index)
          generated_movement._edit(  aggregate_value=self,
                                     resource=resource,
                                     quantity=quantity,
                                     quantity_unit=quantity_unit,
                                     price=price,
                                     price_currency=price_currency,
                                     start_date=current_date,
                                     stop_date=next_date,
                                     source=source,
                                     source_section=source_section,
                                     source_decision=source_decision,
                                     destination=destination,
                                     destination_section=destination_section,
                                     destination_decision=destination_decision,
                                     specialise=specialise,
                                     base_application_list=base_application_list,
                                     base_contribution_list=base_contribution_list,
                                     use_list=use_list
                                    )
          result.append(generated_movement)
          current_date = next_date
          id_index += 1

    return result
Exemplo n.º 11
0
 def generateMovementListForStockOptimisation(self, **kw):
   from Products.ERP5Type.Document import newTempMovement
   movement_list = []
   for attribute, method in [('node_uid', 'getDestinationUid'),
                             ('section_uid', 'getDestinationSectionUid')]:
     if getattr(self, method)() not in ("", None):
       kw[attribute] = getattr(self, method)()
   # We have to check the inventory for each stock movement date.
   # Inventory can be negative in some date, and positive in futur !!
   # This must be done by subclassing OrderBuilder with a new inventory
   # algorithm.
   sql_list = self.portal_simulation.getFutureInventoryList(
                                                  group_by_variation=1,
                                                  group_by_resource=1,
                                                  group_by_node=1,
                                                  group_by_section=0,
                                                  **kw)
   id_count = 0
   # min_flow and max_delay are stored on a supply line. By default
   # we can get them through a method having the right supply type prefix
   # like getPurchaseSupplyLineMinFlow. So we need to guess the supply prefix
   supply_prefix = ''
   delivery_type = self.getDeliveryPortalType()
   portal = self.getPortalObject()
   if delivery_type in portal.getPortalPurchaseTypeList():
     supply_prefix = 'purchase'
   elif delivery_type in portal.getPortalSaleTypeList():
     supply_prefix = 'sale'
   else:
     supply_prefix = 'internal'
   for inventory_item in sql_list:
     if (inventory_item.inventory is not None):
       dumb_movement = inventory_item.getObject()
       # Create temporary movement
       movement = newTempMovement(self.getPortalObject(),
                                  str(id_count))
       id_count += 1
       resource_portal_type_list = self.getResourcePortalTypeList()
       resource = portal.portal_catalog.getObject(inventory_item.resource_uid)
       resource_portal_type = resource.getPortalType()
       assert resource_portal_type in (resource_portal_type_list), \
         "Builder %r does not support resource of type : %r" % (
         self.getRelativeUrl(), resource_portal_type)
       movement.edit(
           resource=inventory_item.resource_relative_url,
           variation_category_list=dumb_movement.getVariationCategoryList(),
           destination_value=self.getDestinationValue(),
           resource_portal_type=resource_portal_type,
           destination_section_value=self.getDestinationSectionValue())
       # Get min_flow, max_delay on supply line
       min_flow = 0
       max_delay = 0
       min_stock = 0
       if supply_prefix:
         min_flow = resource.getProperty(supply_prefix + '_supply_line_min_flow', 0)
         max_delay = resource.getProperty(supply_prefix + '_supply_line_max_delay', 0)
         min_stock = resource.getProperty(supply_prefix + '_supply_line_min_stock', 0)
       if round(inventory_item.inventory, 5) < min_stock:
         stop_date = resource.getNextAlertInventoryDate(
                              reference_quantity=min_stock,
                              variation_text=movement.getVariationText(),
                              from_date=DateTime(),
                              **kw)
         if stop_date != None:
           max_delay = resource.getMaxDelay(0)
           movement.edit(
             start_date=DateTime(((stop_date-max_delay).Date())),
             stop_date=DateTime(stop_date.Date()),
             quantity=max(min_flow, -inventory_item.inventory),
             quantity_unit=resource.getQuantityUnit()
             # XXX FIXME define on a supply line
             # quantity_unit
           )
           movement_list.append(movement)
   return movement_list
Exemplo n.º 12
0
    def _getInputMovementList(self, movement_list=None, rounding=None):
        """
      Generate the list of input movements by looking at all
      open order lines relating to this subscription item.

      TODO: clever handling of quantity (based on the nature
      of resource, ie. float or unit)
    """
        from Products.ERP5Type.Document import newTempMovement
        result = []

        # Try to find the source open order
        open_order_movement_list = self.getAggregateRelatedValueList(
            portal_type="Open Sale Order Line")  # XXX-JPS Hard Coded
        if not open_order_movement_list:
            return result

        # Now generate movements for each valid open order
        for movement in open_order_movement_list:  # YXU-Why we have a list here?
            if movement.getParentValue().getValidationState() in (
                    'open', 'validated'):  # XXX-JPS hard coding
                resource = movement.getResource()
                start_date = movement.getStartDate()
                stop_date = movement.getStopDate()
                source = movement.getSource()
                source_section = movement.getSourceSection()
                source_decision = movement.getSourceDecision()
                destination = movement.getDestination()
                destination_section = movement.getDestinationSection()
                destination_decision = movement.getDestinationDecision()
                quantity = movement.getQuantity()
                quantity_unit = movement.getQuantityUnit()
                price = movement.getPrice()
                price_currency = movement.getPriceCurrency()
                base_application_list = movement.getBaseApplicationList()
                base_contribution_list = movhement.getBaseContributionList()
                use_list = movement.getUseList()

                specialise = movement.getSpecialise()
                current_date = start_date
                id_index = 0
                while current_date < stop_date:
                    next_date = self.getNextPeriodicalDate(current_date)
                    if next_date > stop_date:
                        next_date = stop_date
                    generated_movement = newTempMovement(
                        self, 'subscription_%s' % id_index)
                    generated_movement._edit(
                        aggregate_value=self,
                        resource=resource,
                        quantity=quantity,
                        quantity_unit=quantity_unit,
                        price=price,
                        price_currency=price_currency,
                        start_date=current_date,
                        stop_date=next_date,
                        source=source,
                        source_section=source_section,
                        source_decision=source_decision,
                        destination=destination,
                        destination_section=destination_section,
                        destination_decision=destination_decision,
                        specialise=specialise,
                        base_application_list=base_application_list,
                        base_contribution_list=base_contribution_list,
                        use_list=use_list)
                    result.append(generated_movement)
                    current_date = next_date
                    id_index += 1

        return result
Exemplo n.º 13
0
 def generateMovementListForStockOptimisation(self, **kw):
     from Products.ERP5Type.Document import newTempMovement
     movement_list = []
     for attribute, method in [('node_uid', 'getDestinationUid'),
                               ('section_uid', 'getDestinationSectionUid')]:
         if getattr(self, method)() not in ("", None):
             kw[attribute] = getattr(self, method)()
     # We have to check the inventory for each stock movement date.
     # Inventory can be negative in some date, and positive in futur !!
     # This must be done by subclassing OrderBuilder with a new inventory
     # algorithm.
     sql_list = self.portal_simulation.getFutureInventoryList(
         group_by_variation=1,
         group_by_resource=1,
         group_by_node=1,
         group_by_section=0,
         **kw)
     id_count = 0
     # min_flow and max_delay are stored on a supply line. By default
     # we can get them through a method having the right supply type prefix
     # like getPurchaseSupplyLineMinFlow. So we need to guess the supply prefix
     supply_prefix = ''
     delivery_type = self.getDeliveryPortalType()
     portal = self.getPortalObject()
     if delivery_type in portal.getPortalPurchaseTypeList():
         supply_prefix = 'purchase'
     elif delivery_type in portal.getPortalSaleTypeList():
         supply_prefix = 'sale'
     else:
         supply_prefix = 'internal'
     for inventory_item in sql_list:
         if (inventory_item.inventory is not None):
             dumb_movement = inventory_item.getObject()
             # Create temporary movement
             movement = newTempMovement(self.getPortalObject(),
                                        str(id_count))
             id_count += 1
             resource_portal_type_list = self.getResourcePortalTypeList()
             resource = portal.portal_catalog.getObject(
                 inventory_item.resource_uid)
             resource_portal_type = resource.getPortalType()
             assert resource_portal_type in (resource_portal_type_list), \
               "Builder %r does not support resource of type : %r" % (
               self.getRelativeUrl(), resource_portal_type)
             movement.edit(resource=inventory_item.resource_relative_url,
                           variation_category_list=dumb_movement.
                           getVariationCategoryList(),
                           destination_value=self.getDestinationValue(),
                           resource_portal_type=resource_portal_type,
                           destination_section_value=self.
                           getDestinationSectionValue())
             # Get min_flow, max_delay on supply line
             min_flow = 0
             max_delay = 0
             min_stock = 0
             if supply_prefix:
                 min_flow = resource.getProperty(
                     supply_prefix + '_supply_line_min_flow', 0)
                 max_delay = resource.getProperty(
                     supply_prefix + '_supply_line_max_delay', 0)
                 min_stock = resource.getProperty(
                     supply_prefix + '_supply_line_min_stock', 0)
             if round(inventory_item.inventory, 5) < min_stock:
                 stop_date = resource.getNextAlertInventoryDate(
                     reference_quantity=min_stock,
                     variation_text=movement.getVariationText(),
                     from_date=DateTime(),
                     **kw)
                 if stop_date != None:
                     max_delay = resource.getMaxDelay(0)
                     movement.edit(
                         start_date=DateTime(
                             ((stop_date - max_delay).Date())),
                         stop_date=DateTime(stop_date.Date()),
                         quantity=max(min_flow, -inventory_item.inventory),
                         quantity_unit=resource.getQuantityUnit()
                         # XXX FIXME define on a supply line
                         # quantity_unit
                     )
                     movement_list.append(movement)
     return movement_list