[Erp5-report] r41629 jm - in /erp5/trunk: bt5/erp5_base/PortalTypeTemplateItem/portal_types...
nobody at svn.erp5.org
nobody at svn.erp5.org
Tue Dec 21 19:23:37 CET 2010
Author: jm
Date: Tue Dec 21 19:23:36 2010
New Revision: 41629
URL: http://svn.erp5.org?rev=41629&view=rev
Log:
Use legacy OrderBuilder/DeliveryBuilder classes for legacy simulation
This fixes testLegacySimulationOrderBuilder
Added:
erp5/trunk/bt5/erp5_simulation_legacy/DocumentTemplateItem/OrderBuilder.py
erp5/trunk/bt5/erp5_simulation_legacy/DocumentTemplateItem/SimulatedDeliveryBuilder.py
erp5/trunk/products/ERP5/Document/OrderBuilder.py
erp5/trunk/products/ERP5Legacy/OrderBuilder.py
- copied, changed from r41628, erp5/trunk/products/ERP5Legacy/Document/OrderBuilder.py
Removed:
erp5/trunk/products/ERP5Legacy/Document/OrderBuilder.py
Modified:
erp5/trunk/bt5/erp5_base/PortalTypeTemplateItem/portal_types/Order%20Builder.xml
erp5/trunk/bt5/erp5_base/bt/revision
erp5/trunk/bt5/erp5_simulation_legacy/bt/revision
erp5/trunk/bt5/erp5_simulation_legacy/bt/template_document_id_list
erp5/trunk/products/ERP5Legacy/Document/DeliveryBuilder.py
Modified: erp5/trunk/bt5/erp5_base/PortalTypeTemplateItem/portal_types/Order%20Builder.xml
URL: http://svn.erp5.org/erp5/trunk/bt5/erp5_base/PortalTypeTemplateItem/portal_types/Order%2520Builder.xml?rev=41629&r1=41628&r2=41629&view=diff
==============================================================================
--- erp5/trunk/bt5/erp5_base/PortalTypeTemplateItem/portal_types/Order%20Builder.xml [utf8] (original)
+++ erp5/trunk/bt5/erp5_base/PortalTypeTemplateItem/portal_types/Order%20Builder.xml [utf8] Tue Dec 21 19:23:36 2010
@@ -58,7 +58,7 @@
</item>
<item>
<key> <string>factory</string> </key>
- <value> <string>addSimulatedDeliveryBuilder</string> </value>
+ <value> <string>addOrderBuilder</string> </value>
</item>
<item>
<key> <string>filter_content_types</string> </key>
Modified: erp5/trunk/bt5/erp5_base/bt/revision
URL: http://svn.erp5.org/erp5/trunk/bt5/erp5_base/bt/revision?rev=41629&r1=41628&r2=41629&view=diff
==============================================================================
--- erp5/trunk/bt5/erp5_base/bt/revision [utf8] (original)
+++ erp5/trunk/bt5/erp5_base/bt/revision [utf8] Tue Dec 21 19:23:36 2010
@@ -1 +1 @@
-916
\ No newline at end of file
+917
\ No newline at end of file
Added: erp5/trunk/bt5/erp5_simulation_legacy/DocumentTemplateItem/OrderBuilder.py
URL: http://svn.erp5.org/erp5/trunk/bt5/erp5_simulation_legacy/DocumentTemplateItem/OrderBuilder.py?rev=41629&view=auto
==============================================================================
--- erp5/trunk/bt5/erp5_simulation_legacy/DocumentTemplateItem/OrderBuilder.py (added)
+++ erp5/trunk/bt5/erp5_simulation_legacy/DocumentTemplateItem/OrderBuilder.py [utf8] Tue Dec 21 19:23:36 2010
@@ -0,0 +1,27 @@
+##############################################################################
+# Copyright (c) 2010 Nexedi SA and Contributors. All Rights Reserved.
+#
+# WARNING: This program as such is intended to be used by professional
+# programmers who take the whole responsibility 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
+# guarantees and support are strongly advised 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+##############################################################################
+
+from Products.ERP5Legacy.OrderBuilder import OrderBuilder
Added: erp5/trunk/bt5/erp5_simulation_legacy/DocumentTemplateItem/SimulatedDeliveryBuilder.py
URL: http://svn.erp5.org/erp5/trunk/bt5/erp5_simulation_legacy/DocumentTemplateItem/SimulatedDeliveryBuilder.py?rev=41629&view=auto
==============================================================================
--- erp5/trunk/bt5/erp5_simulation_legacy/DocumentTemplateItem/SimulatedDeliveryBuilder.py (added)
+++ erp5/trunk/bt5/erp5_simulation_legacy/DocumentTemplateItem/SimulatedDeliveryBuilder.py [utf8] Tue Dec 21 19:23:36 2010
@@ -0,0 +1,27 @@
+##############################################################################
+# Copyright (c) 2010 Nexedi SA and Contributors. All Rights Reserved.
+#
+# WARNING: This program as such is intended to be used by professional
+# programmers who take the whole responsibility 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
+# guarantees and support are strongly advised 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+##############################################################################
+
+from Products.ERP5Legacy.Document.DeliveryBuilder import DeliveryBuilder as SimulatedDeliveryBuilder
Modified: erp5/trunk/bt5/erp5_simulation_legacy/bt/revision
URL: http://svn.erp5.org/erp5/trunk/bt5/erp5_simulation_legacy/bt/revision?rev=41629&r1=41628&r2=41629&view=diff
==============================================================================
--- erp5/trunk/bt5/erp5_simulation_legacy/bt/revision [utf8] (original)
+++ erp5/trunk/bt5/erp5_simulation_legacy/bt/revision [utf8] Tue Dec 21 19:23:36 2010
@@ -1 +1 @@
-6
\ No newline at end of file
+7
\ No newline at end of file
Modified: erp5/trunk/bt5/erp5_simulation_legacy/bt/template_document_id_list
URL: http://svn.erp5.org/erp5/trunk/bt5/erp5_simulation_legacy/bt/template_document_id_list?rev=41629&r1=41628&r2=41629&view=diff
==============================================================================
--- erp5/trunk/bt5/erp5_simulation_legacy/bt/template_document_id_list [utf8] (original)
+++ erp5/trunk/bt5/erp5_simulation_legacy/bt/template_document_id_list [utf8] Tue Dec 21 19:23:36 2010
@@ -5,10 +5,12 @@ DeliverySimulationRule
InvoiceRootSimulationRule
InvoiceSimulationRule
InvoiceTransactionSimulationRule
+OrderBuilder
OrderRootSimulationRule
PaymentSimulationRule
ProductionOrderModelRootSimulationRule
ProductionOrderRootSimulationRule
RootAppliedRuleCausalityMovementGroup
+SimulatedDeliveryBuilder
SimulationLegacyPatches
TradeModelSimulationRule
\ No newline at end of file
Added: erp5/trunk/products/ERP5/Document/OrderBuilder.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/Document/OrderBuilder.py?rev=41629&view=auto
==============================================================================
--- erp5/trunk/products/ERP5/Document/OrderBuilder.py (added)
+++ erp5/trunk/products/ERP5/Document/OrderBuilder.py [utf8] Tue Dec 21 19:23:36 2010
@@ -0,0 +1,31 @@
+##############################################################################
+# Copyright (c) 2010 Nexedi SA and Contributors. All Rights Reserved.
+#
+# WARNING: This program as such is intended to be used by professional
+# programmers who take the whole responsibility 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
+# guarantees and support are strongly advised 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+##############################################################################
+
+# BACK: Temporary document so that legacy code can have its own set of classes
+# for builders, and still distinguish order builders from others
+# Once legacy simulation is dropped, "Order Builder" portal type should
+# should be changed to use SimulatedDeliveryBuilder class.
+from SimulatedDeliveryBuilder import SimulatedDeliveryBuilder as OrderBuilder
Modified: erp5/trunk/products/ERP5Legacy/Document/DeliveryBuilder.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5Legacy/Document/DeliveryBuilder.py?rev=41629&r1=41628&r2=41629&view=diff
==============================================================================
--- erp5/trunk/products/ERP5Legacy/Document/DeliveryBuilder.py [utf8] (original)
+++ erp5/trunk/products/ERP5Legacy/Document/DeliveryBuilder.py [utf8] Tue Dec 21 19:23:36 2010
@@ -29,8 +29,7 @@
from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet
-from Products.ERP5Legacy.Document.OrderBuilder import OrderBuilder, \
- SelectMethodError
+from Products.ERP5Legacy.OrderBuilder import OrderBuilder, SelectMethodError
from Products.ERP5Type.UnrestrictedMethod import UnrestrictedMethod
from Products.ERP5Type.CopySupport import CopyError, tryMethodCallWithTemporaryPermission
Removed: erp5/trunk/products/ERP5Legacy/Document/OrderBuilder.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5Legacy/Document/OrderBuilder.py?rev=41628&view=auto
==============================================================================
--- erp5/trunk/products/ERP5Legacy/Document/OrderBuilder.py [utf8] (original)
+++ erp5/trunk/products/ERP5Legacy/Document/OrderBuilder.py (removed)
@@ -1,844 +0,0 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# Copyright (c) 2005-2008 Nexedi SA and Contributors. All Rights Reserved.
-# Romain Courteaud <romain at nexedi.com>
-#
-# WARNING: This program as such is intended to be used by professional
-# programmers who take the whole responsibility 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
-# guarantees 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 Products.ERP5Type import Permissions, PropertySheet
-from Products.ERP5Type.XMLObject import XMLObject
-from Products.ERP5Type.Core.Predicate import Predicate
-from Products.ERP5.Document.Amount import Amount
-from Products.ERP5.MovementGroup import MovementGroupNode
-from Products.ERP5Type.TransactionalVariable import getTransactionalVariable
-from Products.ERP5Type.UnrestrictedMethod import UnrestrictedMethod
-from DateTime import DateTime
-from Acquisition import aq_parent, aq_inner, aq_base
-
-from zLOG import LOG
-
-class CollectError(Exception): pass
-class MatrixError(Exception): pass
-class DuplicatedPropertyDictKeysError(Exception): pass
-
-class SelectMethodError(Exception): pass
-class SelectMovementError(Exception): pass
-
-class OrderBuilder(XMLObject, Amount, Predicate):
- """
- Order Builder objects allow to gather multiple Simulation Movements
- into a single Delivery.
-
- The initial quantity property of the Delivery Line is calculated by
- summing quantities of related Simulation Movements.
-
- Order Builder objects are provided with a set a parameters to achieve
- their goal:
-
- A path definition: source, destination, etc. which defines the general
- kind of movements it applies.
-
- simulation_select_method which defines how to query all Simulation
- Movements which meet certain criteria (including the above path path
- definition).
-
- collect_order_list which defines how to group selected movements
- according to gathering rules.
-
- delivery_select_method which defines how to select existing Delivery
- which may eventually be updated with selected simulation movements.
-
- delivery_module, delivery_type and delivery_line_type which define the
- module and portal types for newly built Deliveries and Delivery Lines.
-
- Order Builders can also be provided with optional parameters to
- restrict selection to a given root Applied Rule caused by a single Order
- or to Simulation Movements related to a limited set of existing
- Deliveries.
- """
-
- # CMF Type Definition
- meta_type = 'ERP5 Order Builder'
- portal_type = 'Order Builder'
-
- # Declarative security
- security = ClassSecurityInfo()
- security.declareObjectProtected(Permissions.AccessContentsInformation)
-
- # Default Properties
- property_sheets = ( PropertySheet.Base
- , PropertySheet.XMLObject
- , PropertySheet.CategoryCore
- , PropertySheet.DublinCore
- , PropertySheet.Arrow
- , PropertySheet.Amount
- , PropertySheet.Comment
- , PropertySheet.DeliveryBuilder
- )
-
- # XXX it would be better to make the base id configurable at
- # each builder.
- matrix_base_id = 'movement'
-
- security.declarePublic('build')
- def build(self, applied_rule_uid=None, movement_relative_url_list=None,
- delivery_relative_url_list=None, movement_list=None, **kw):
- """
- Build deliveries from a list of movements
-
- Delivery Builders can also be provided with optional parameters to
- restrict selection to a given root Applied Rule caused by a single Order
- or to Simulation Movements related to a limited set of existing
- """
- # Parameter initialization
- if delivery_relative_url_list is None:
- delivery_relative_url_list = []
- # Call a script before building
- self.callBeforeBuildingScript() # XXX-JPS Used ?
- # Select
- if not movement_list:
- # XXX this code below has a problem of inconsistency in that
- # searchMovementList is unrestricted while passing a list of
- # movements is restricted.
- if not movement_relative_url_list:
- movement_list = self.searchMovementList(
- delivery_relative_url_list=delivery_relative_url_list,
- applied_rule_uid=applied_rule_uid,**kw)
- else:
- restrictedTraverse = self.getPortalObject().restrictedTraverse
- movement_list = [restrictedTraverse(relative_url) for relative_url \
- in movement_relative_url_list]
- LOG('movement_list', 0, repr(movement_list))
- if not movement_list:
- return []
- # Collect
- root_group_node = self.collectMovement(movement_list)
- # Build
- delivery_list = self.buildDeliveryList(
- root_group_node,
- delivery_relative_url_list=delivery_relative_url_list,
- movement_list=movement_list, **kw)
- # Call a script after building
- self.callAfterBuildingScript(delivery_list, movement_list, **kw)
- # XXX Returning the delivery list is probably not necessary
- return delivery_list
-
- def callBeforeBuildingScript(self):
- """
- Call a script on the module, for example, to remove some
- auto_planned Order.
- This part can only be done with a script, because user may want
- to keep existing auto_planned Order, and only update lines in
- them.
- No activities are used when deleting a object, so, current
- implementation should be OK.
- """
- delivery_module_before_building_script_id = \
- self.getDeliveryModuleBeforeBuildingScriptId()
- if delivery_module_before_building_script_id:
- delivery_module = getattr(self.getPortalObject(), self.getDeliveryModule())
- getattr(delivery_module, delivery_module_before_building_script_id)()
-
- 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
- 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
-
- @UnrestrictedMethod
- def searchMovementList(self, applied_rule_uid=None, **kw):
- """
- Returns a list of simulation movements (or something similar to
- simulation movements) to construct a new delivery.
-
- For compatibility, if a simulation select method id is not provided,
- a list of movements for predicting future supplies is returned.
- You should define a simulation select method id, then it will be used
- to calculate the result.
- """
- method_id = self.getSimulationSelectMethodId()
- if not method_id:
- # XXX compatibility
- return self.generateMovementListForStockOptimisation(**kw)
-
- select_method = getattr(self.getPortalObject(), method_id)
- movement_list = select_method(**kw)
-
- # Make sure that movements are not duplicated.
- movement_set = set()
- for movement in movement_list:
- if movement in movement_set:
- raise SelectMethodError('%s returned %s twice or more' % \
- (method_id, movement.getRelativeUrl()))
- else:
- movement_set.add(movement)
-
- return movement_list
-
- def collectMovement(self, movement_list):
- """
- group movements in the way we want. Thanks to this method, we are able
- to retrieve movement classed by order, resource, criterion,....
- movement_list : the list of movement wich we want to group
- class_list : the list of classes used to group movements. The order
- of the list is important and determines by what we will
- group movement first
- Typically, check_list is :
- [DateMovementGroup,PathMovementGroup,...]
- """
- movement_group_list = self.getMovementGroupList()
-
- # Need to find the last branch movement group for separate methods.
- last_line_movement_group = None
- previous_collect_order_group = None
- for movement_group in movement_group_list:
- collect_order_group = movement_group.getCollectOrderGroup()
- if collect_order_group == 'line':
- if previous_collect_order_group == 'delivery' \
- or movement_group.isBranch():
- last_line_movement_group = movement_group
- elif collect_order_group == 'cell':
- break
- previous_collect_order_group = collect_order_group
- if last_line_movement_group is None:
- # XXX I think this is an error, but there are many tests which
- # fail, so for now I permit falling back to the last one.
- #raise CollectError('No branch movement group found at %r' % (self,))
- last_line_movement_group = movement_group
-
- separate_method_name_list = self.getDeliveryCellSeparateOrderList([])
- root_group_node = MovementGroupNode(
- separate_method_name_list=separate_method_name_list,
- movement_group_list=movement_group_list,
- last_line_movement_group=last_line_movement_group)
- root_group_node.append(movement_list)
- return root_group_node
-
- def _test(self, instance, movement_group_node_list,
- divergence_list):
- result = True
- new_property_dict = {}
- for movement_group_node in movement_group_node_list:
- tmp_result, tmp_property_dict = movement_group_node.test(
- instance, divergence_list)
- if not tmp_result:
- result = tmp_result
- new_property_dict.update(tmp_property_dict)
- return result, new_property_dict
-
- def _findUpdatableObject(self, instance_list, current_movement_group_node,
- movement_group_node_list, divergence_list):
- # FIXME this code may generate inconsistent results, because
- # MovementGroupNode.test can return anything else but the
- # property dict. So it would be better to use the test method
- # in all cases. It is, however, not so easy to do, because
- # Movement Group classes might not be prepared for receiving
- # None instead of a real document object. So it would be safer
- # to pass a temp object, but generating a temp object is not
- # very fast.
- instance = None
- property_dict = {}
- if not instance_list:
- for movement_group_node in movement_group_node_list:
- for k, v in movement_group_node.getGroupEditDict().iteritems():
- if k in property_dict:
- raise DuplicatedPropertyDictKeysError(k)
- else:
- property_dict[k] = v
- else:
- # we want to check the original delivery first.
- movement = current_movement_group_node.getMovementList()[0]
- # XXX in the case of Order Builder, the movement is not always
- # related to simulation, thus it might not have the delivery category.
- # Possibly, this code should be overridden by DeliveryBuilder.
- if getattr(aq_base(movement), 'getDeliveryValue', None) is not None:
- delivery_movement = movement.getDeliveryValue()
- else:
- delivery_movement = None
- if delivery_movement is not None:
- delivery = delivery_movement.getRootDeliveryValue()
- try:
- instance_list.remove(delivery)
- except ValueError:
- pass
- else:
- instance_list.insert(0, delivery)
- for instance_to_update in instance_list:
- result, property_dict = self._test(
- instance_to_update, movement_group_node_list, divergence_list)
- if result:
- instance = instance_to_update
- break
- return instance, property_dict
-
- @UnrestrictedMethod
- def buildDeliveryList(self, movement_group_node,
- delivery_relative_url_list=None,
- movement_list=None, update=True, **kw):
- """
- Build deliveries from a list of movements
- """
- # Parameter initialization
- if delivery_relative_url_list is None:
- delivery_relative_url_list = []
- if movement_list is None:
- movement_list = []
- # Module where we can create new deliveries
- portal = self.getPortalObject()
- delivery_module = getattr(portal, self.getDeliveryModule())
- if update:
- unrestrictedTraverse = portal.unrestrictedTraverse
- delivery_to_update_list = [unrestrictedTraverse(relative_url) for \
- relative_url in delivery_relative_url_list]
- # Deliveries we are trying to update
- delivery_select_method_id = self.getDeliverySelectMethodId()
- if delivery_select_method_id:
- delivery_select_method = getattr(self, delivery_select_method_id)
- for brain in delivery_select_method(movement_list=movement_list):
- delivery_to_update_list.append(brain.getObject())
-
- # Make sure that the portal type is good.
- delivery_portal_type = self.getDeliveryPortalType()
- delivery_to_update_list = [x for x in delivery_to_update_list \
- if x.getPortalType() == delivery_portal_type]
- else:
- delivery_to_update_list = []
-
- delivery_list = self._processDeliveryGroup(
- delivery_module,
- movement_group_node,
- self.getDeliveryMovementGroupList(),
- delivery_to_update_list=delivery_to_update_list,
- **kw)
- return delivery_list
-
- def _createDelivery(self, delivery_module, movement_list, activate_kw):
- """
- Create a new delivery in case where a builder may not update
- an existing one.
- """
- new_delivery_id = str(delivery_module.generateNewId())
- delivery = delivery_module.newContent(
- portal_type=self.getDeliveryPortalType(),
- id=new_delivery_id,
- created_by_builder=1,
- activate_kw=activate_kw)
- return delivery
-
- def _processDeliveryGroup(self, delivery_module, movement_group_node,
- collect_order_list, movement_group_node_list=None,
- delivery_to_update_list=None,
- divergence_list=None,
- activate_kw=None, force_update=0, **kw):
- """
- Build delivery from a list of movement
- """
- if movement_group_node_list is None:
- movement_group_node_list = []
- if divergence_list is None:
- divergence_list = []
- # Parameter initialization
- if delivery_to_update_list is None:
- delivery_to_update_list = []
- delivery_list = []
-
- if collect_order_list:
- # Get sorted movement for each delivery
- for grouped_node in movement_group_node.getGroupList():
- # do not use 'append' or '+=' because they are destructive.
- new_movement_group_node_list = movement_group_node_list + [grouped_node]
- new_delivery_list = self._processDeliveryGroup(
- delivery_module,
- grouped_node,
- collect_order_list[1:],
- movement_group_node_list=new_movement_group_node_list,
- delivery_to_update_list=delivery_to_update_list,
- divergence_list=divergence_list,
- activate_kw=activate_kw,
- force_update=force_update)
- delivery_list.extend(new_delivery_list)
- force_update = 0
- else:
- # Test if we can update a existing delivery, or if we need to create
- # a new one
- delivery, property_dict = self._findUpdatableObject(
- delivery_to_update_list, movement_group_node, movement_group_node_list,
- divergence_list)
-
- # if all deliveries are rejected in case of update, we update the
- # first one.
- if force_update and delivery is None and delivery_to_update_list:
- delivery = delivery_to_update_list[0]
-
- if delivery is None:
- if not self.getDeliveryCreatable():
- raise SelectMethodError('No updatable delivery found with %s' \
- % (self.getPath(),))
- delivery = self._createDelivery(delivery_module,
- movement_group_node.getMovementList(),
- activate_kw)
- else:
- # The same delivery should not be updated more than once.
- # Note that it is important to use a destructive method here.
- delivery_to_update_list.remove(delivery)
-
- # Put properties on delivery
- if property_dict:
- property_dict.setdefault('edit_order', ('stop_date', 'start_date'))
- delivery.edit(activate_kw=activate_kw, **property_dict)
-
- # Then, create delivery lines
- delivery_line_portal_type = self.getDeliveryLinePortalType()
- delivery_line_to_update_list = []
- for line in delivery.contentValues(portal_type=delivery_line_portal_type):
- delivery_line_to_update_list.append(line)
- for grouped_node in movement_group_node.getGroupList():
- self._processDeliveryLineGroup(
- delivery,
- grouped_node,
- self.getDeliveryLineMovementGroupList()[1:],
- movement_group_node_list=[grouped_node],
- divergence_list=divergence_list,
- delivery_line_to_update_list=delivery_line_to_update_list,
- activate_kw=activate_kw,
- force_update=force_update)
- delivery_list.append(delivery)
- return delivery_list
-
- def _createDeliveryLine(self, delivery, movement_list, activate_kw):
- """
- Create a new delivery line in case where a builder may not update
- an existing one.
- """
- new_delivery_line_id = str(delivery.generateNewId())
- delivery_line = delivery.newContent(
- portal_type=self.getDeliveryLinePortalType(),
- id=new_delivery_line_id,
- created_by_builder=1,
- activate_kw=activate_kw)
- return delivery_line
-
- def _processDeliveryLineGroup(self, delivery, movement_group_node,
- collect_order_list, movement_group_node_list=None,
- divergence_list=None,
- delivery_line_to_update_list=None,
- activate_kw=None, force_update=0, **kw):
- """
- Build delivery line from a list of movement on a delivery
- """
- if movement_group_node_list is None:
- movement_group_node_list = []
- if divergence_list is None:
- divergence_list = []
- if delivery_line_to_update_list is None:
- delivery_line_to_update_list = []
-
- if collect_order_list and not movement_group_node.getCurrentMovementGroup().isBranch():
- # Get sorted movement for each delivery line
- for grouped_node in movement_group_node.getGroupList():
- # do not use 'append' or '+=' because they are destructive.
- new_movement_group_node_list = movement_group_node_list + [grouped_node]
- self._processDeliveryLineGroup(
- delivery,
- grouped_node,
- collect_order_list[1:],
- movement_group_node_list=new_movement_group_node_list,
- divergence_list=divergence_list,
- delivery_line_to_update_list=delivery_line_to_update_list,
- activate_kw=activate_kw,
- force_update=force_update)
- else:
- # Test if we can update an existing line, or if we need to create a new
- # one
- delivery_line, property_dict = self._findUpdatableObject(
- delivery_line_to_update_list, movement_group_node,
- movement_group_node_list, divergence_list)
- if delivery_line is not None:
- update_existing_line = 1
- delivery_line_to_update_list.remove(delivery_line)
- else:
- # Create delivery line
- update_existing_line = 0
- delivery_line = self._createDeliveryLine(
- delivery,
- movement_group_node.getMovementList(),
- activate_kw)
- # Put properties on delivery line
- if property_dict:
- property_dict.setdefault('edit_order', ('stop_date', 'start_date'))
- delivery_line.edit(force_update=1, activate_kw=activate_kw,
- **property_dict)
-
- if movement_group_node.getCurrentMovementGroup().isBranch():
- delivery_line_portal_type = self.getDeliveryLinePortalType()
- nested_delivery_line_to_update_list = []
- for line in delivery_line.contentValues(portal_type=delivery_line_portal_type):
- nested_delivery_line_to_update_list.append(line)
- for grouped_node in movement_group_node.getGroupList():
- self._processDeliveryLineGroup(
- delivery_line,
- grouped_node,
- collect_order_list[1:],
- movement_group_node_list=[grouped_node],
- divergence_list=divergence_list,
- delivery_line_to_update_list=nested_delivery_line_to_update_list,
- activate_kw=activate_kw,
- force_update=force_update)
- return
-
- # Update variation category list on line
- variation_category_set = set(delivery_line.getVariationCategoryList())
- for movement in movement_group_node.getMovementList():
- variation_category_set.update(movement.getVariationCategoryList())
- variation_category_list = sorted(variation_category_set)
- delivery_line.edit(variation_category_list=variation_category_list,
- activate_kw=activate_kw)
- # Then, create delivery movement (delivery cell or complete delivery
- # line)
- grouped_node_list = movement_group_node.getGroupList()
- # If no group is defined for cell, we need to continue, in order to
- # save the quantity value
- if grouped_node_list:
- base_id = self.matrix_base_id
- getCell = delivery_line.getCell
- delivery_movement_to_update_list = []
- cell_key_list = delivery_line.getCellKeyList(base_id=base_id)
- if cell_key_list:
- for cell_key in cell_key_list:
- cell = getCell(base_id=base_id, *cell_key)
- if cell is not None:
- delivery_movement_to_update_list.append(cell)
- else:
- delivery_movement_to_update_list.append(delivery_line)
- for grouped_node in grouped_node_list:
- self._processDeliveryCellGroup(
- delivery_line,
- grouped_node,
- self.getDeliveryCellMovementGroupList()[1:],
- movement_group_node_list=[grouped_node],
- update_existing_line=update_existing_line,
- divergence_list=divergence_list,
- delivery_movement_to_update_list=delivery_movement_to_update_list,
- activate_kw=activate_kw,
- force_update=force_update)
- else:
- self._processDeliveryCellGroup(
- delivery_line,
- movement_group_node,
- [],
- movement_group_node_list=[],
- update_existing_line=update_existing_line,
- divergence_list=divergence_list,
- delivery_movement_to_update_list=[delivery_line],
- activate_kw=activate_kw,
- force_update=force_update)
-
- def _createDeliveryCell(self, delivery_line, movement, activate_kw,
- base_id, cell_key):
- """
- Create a new delivery cell in case where a builder may not update
- an existing one.
- """
- cell = delivery_line.newCell(base_id=base_id,
- portal_type=self.getDeliveryCellPortalType(),
- activate_kw=activate_kw,
- *cell_key)
- return cell
-
- def _processDeliveryCellGroup(self, delivery_line, movement_group_node,
- collect_order_list, movement_group_node_list=None,
- update_existing_line=0,
- divergence_list=None,
- delivery_movement_to_update_list=None,
- activate_kw=None, force_update=0):
- """
- Build delivery cell from a list of movement on a delivery line
- or complete delivery line
- """
- if movement_group_node_list is None:
- movement_group_node_list = []
- if delivery_movement_to_update_list is None:
- delivery_movement_to_update_list = []
- if divergence_list is None:
- divergence_list = []
-
- if collect_order_list:
- # Get sorted movement for each delivery line
- for grouped_node in movement_group_node.getGroupList():
- new_movement_group_node_list = movement_group_node_list + [grouped_node]
- self._processDeliveryCellGroup(
- delivery_line,
- grouped_node,
- collect_order_list[1:],
- movement_group_node_list=new_movement_group_node_list,
- update_existing_line=update_existing_line,
- divergence_list=divergence_list,
- delivery_movement_to_update_list=delivery_movement_to_update_list,
- activate_kw=activate_kw,
- force_update=force_update)
- else:
- movement_list = movement_group_node.getMovementList()
- if len(movement_list) != 1:
- raise CollectError, "DeliveryBuilder: %s unable to distinct those\
- movements: %s" % (self.getId(), str(movement_list))
- else:
- base_id = self.matrix_base_id
- object_to_update = None
- # We need to initialize the cell
- update_existing_movement = 0
- movement = movement_list[0]
- # decide if we create a cell or if we update the line
- # Decision can only be made with line matrix range:
- # because matrix range can be empty even if line variation category
- # list is not empty
- property_dict = {}
- if not delivery_line.getCellKeyList(base_id=base_id):
- # update line
- dummy, property_dict = self._findUpdatableObject(
- delivery_movement_to_update_list, movement_group_node,
- movement_group_node_list, divergence_list)
- if delivery_movement_to_update_list:
- if update_existing_line:
- update_existing_movement = 1
- del delivery_movement_to_update_list[:]
- else:
- # XXX probably an exception should be raised here.
- pass
- object_to_update = delivery_line
- else:
- object_to_update, property_dict = self._findUpdatableObject(
- delivery_movement_to_update_list, movement_group_node,
- movement_group_node_list, divergence_list)
- if object_to_update is not None:
- # We update a existing cell
- # delivery_ratio of new related movement to this cell
- # must be updated to 0.
- update_existing_movement = 1
- delivery_movement_to_update_list.remove(object_to_update)
- else:
- # create a new cell
- cell_key = movement.getVariationCategoryList(
- omit_optional_variation=1)
- if not delivery_line.hasCell(base_id=base_id, *cell_key):
- cell = self._createDeliveryCell(delivery_line, movement,
- activate_kw, base_id, cell_key)
- vcl = movement.getVariationCategoryList()
- # _createDeliveryCell calls reindexObject, so no need to use
- # edit here.
- cell._edit(category_list=vcl,
- # XXX hardcoded value
- mapped_value_property_list=('quantity', 'price'),
- membership_criterion_category_list=vcl,
- membership_criterion_base_category_list=movement.\
- getVariationBaseCategoryList())
- else:
- raise MatrixError, 'Cell: %s already exists on %s' % \
- (str(cell_key), str(delivery_line))
- object_to_update = cell
-
- self._setDeliveryMovementProperties(
- object_to_update, movement, property_dict,
- update_existing_movement=update_existing_movement,
- force_update=force_update, activate_kw=activate_kw)
-
- def _setDeliveryMovementProperties(self, delivery_movement,
- simulation_movement, property_dict,
- update_existing_movement=0,
- force_update=0, activate_kw=None):
- """
- Initialize or update delivery movement properties.
- """
- if not update_existing_movement or force_update:
- # Now, only 1 movement is possible, so copy from this movement
- # XXX hardcoded value
- if getattr(simulation_movement, 'getMappedProperty', None) is not None:
- property_dict['quantity'] = simulation_movement.getMappedProperty('quantity')
- else:
- property_dict['quantity'] = simulation_movement.getQuantity()
- property_dict['price'] = simulation_movement.getPrice()
- # Update properties on object (quantity, price...)
- delivery_movement.edit(force_update=1, activate_kw=activate_kw,
- **property_dict)
-
- @UnrestrictedMethod
- def callAfterBuildingScript(self, delivery_list, movement_list=None, **kw):
- """
- Call script on each delivery built.
- """
- if not delivery_list:
- return
- # Parameter initialization
- if movement_list is None:
- movement_list = []
- delivery_after_generation_script_id = \
- self.getDeliveryAfterGenerationScriptId()
- related_simulation_movement_path_list = \
- [x.getPath() for x in movement_list]
- if delivery_after_generation_script_id:
- for delivery in delivery_list:
- script = getattr(delivery, delivery_after_generation_script_id)
- # BBB: Only Python Scripts were used in the past, and they might not
- # accept an arbitrary argument. So to keep compatibility,
- # check if it can take the new parameter safely, only when
- # the callable object is a Python Script.
- safe_to_pass_parameter = True
- meta_type = getattr(script, 'meta_type', None)
- if meta_type == 'Script (Python)':
- # check if the script accepts related_simulation_movement_path_list
- safe_to_pass_parameter = False
- for param in script.params().split(','):
- param = param.split('=', 1)[0].strip()
- if param == 'related_simulation_movement_path_list' \
- or param.startswith('**'):
- safe_to_pass_parameter = True
- break
-
- if safe_to_pass_parameter:
- script(related_simulation_movement_path_list=related_simulation_movement_path_list)
- else:
- script()
-
- security.declareProtected(Permissions.AccessContentsInformation,
- 'getMovementGroupList')
- def getMovementGroupList(self, portal_type=None, collect_order_group=None,
- **kw):
- """
- Return a list of movement groups sorted by collect order group and index.
- """
- portal = self.getPortalObject()
- if portal_type is None:
- portal_type = portal.getPortalMovementGroupTypeList()
-
- if collect_order_group is None:
- category_index_dict = {}
- for i in portal.portal_categories.collect_order_group.contentValues():
- category_index_dict[i.getId()] = i.getIntIndex()
-
- def getMovementGroupKey(movement_group):
- return (category_index_dict.get(movement_group.getCollectOrderGroup()),
- movement_group.getIntIndex())
-
- filter_dict = dict(portal_type=portal_type)
- movement_group_list = self.contentValues(filter=filter_dict)
- else:
- def getMovementGroupKey(movement_group):
- return movement_group.getIntIndex()
-
- filter_dict = dict(portal_type=portal_type)
- movement_group_list = []
- for movement_group in self.contentValues(filter=filter_dict):
- if movement_group.getCollectOrderGroup() == collect_order_group:
- movement_group_list.append(movement_group)
-
- return sorted(movement_group_list, key=getMovementGroupKey)
-
- # XXX category name is hardcoded.
- def getDeliveryMovementGroupList(self, **kw):
- return self.getMovementGroupList(collect_order_group='delivery')
-
- # XXX category name is hardcoded.
- def getDeliveryLineMovementGroupList(self, **kw):
- return self.getMovementGroupList(collect_order_group='line')
-
- # XXX category name is hardcoded.
- def getDeliveryCellMovementGroupList(self, **kw):
- return self.getMovementGroupList(collect_order_group='cell')
-
- # XXX this method is not used in OrderBuilder but in DeliveryBuilder.
- # So it should perhaps be moved to DeliveryBuilder.
- def _searchUpByPortalType(self, obj, portal_type):
- limit_portal_type = self.getPortalObject().getPortalType()
- while obj is not None:
- obj_portal_type = obj.getPortalType()
- if obj_portal_type == portal_type:
- break
- elif obj_portal_type == limit_portal_type:
- obj = None
- break
- else:
- obj = aq_parent(aq_inner(obj))
- return obj
-
- # for backward compatibilities.
- _deliveryGroupProcessing = _processDeliveryGroup
- _deliveryLineGroupProcessing = _processDeliveryLineGroup
- _deliveryCellGroupProcessing = _processDeliveryCellGroup
Copied: erp5/trunk/products/ERP5Legacy/OrderBuilder.py (from r41628, erp5/trunk/products/ERP5Legacy/Document/OrderBuilder.py)
URL: http://svn.erp5.org/erp5/trunk/products/ERP5Legacy/OrderBuilder.py?p2=erp5/trunk/products/ERP5Legacy/OrderBuilder.py&p1=erp5/trunk/products/ERP5Legacy/Document/OrderBuilder.py&r1=41628&r2=41629&rev=41629&view=diff
==============================================================================
(empty)
More information about the Erp5-report
mailing list