Commit 4ee585d8 authored by Arnaud Fontaine's avatar Arnaud Fontaine

ERP5/Document: Fix pylint warnings.

parent d672defe
...@@ -35,187 +35,183 @@ from AccessControl.PermissionRole import PermissionRole ...@@ -35,187 +35,183 @@ from AccessControl.PermissionRole import PermissionRole
from Products.ERP5Type import Permissions, PropertySheet, interfaces from Products.ERP5Type import Permissions, PropertySheet, interfaces
from Products.ERP5.Document.OrderLine import OrderLine
from Products.ERP5.Document.Movement import Movement from Products.ERP5.Document.Movement import Movement
from Products.ERP5.Document.MappedValue import MappedValue from Products.ERP5.Document.MappedValue import MappedValue
from Products.ERP5.Document.ImmobilisationMovement import ImmobilisationMovement from Products.ERP5.Document.ImmobilisationMovement import ImmobilisationMovement
class DeliveryCell(MappedValue, Movement, ImmobilisationMovement): class DeliveryCell(MappedValue, Movement, ImmobilisationMovement):
"""
A DeliveryCell allows to define specific quantities
for each variation of a resource in a delivery line.
"""
meta_type = 'ERP5 Delivery Cell'
portal_type = 'Delivery Cell'
isCell = 1
# Declarative security
security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation)
# Declarative properties
property_sheets = ( PropertySheet.Base
, PropertySheet.CategoryCore
, PropertySheet.Arrow
, PropertySheet.Amount
, PropertySheet.Task
, PropertySheet.Movement
, PropertySheet.Price
, PropertySheet.Predicate
, PropertySheet.MappedValue
, PropertySheet.ItemAggregation
)
# Declarative interfaces
zope.interface.implements(interfaces.IDivergenceController,)
security.declareProtected(Permissions.AccessContentsInformation, 'isPredicate')
def isPredicate(self):
"""Movements are not predicates.
""" """
A DeliveryCell allows to define specific quantities return False
for each variation of a resource in a delivery line.
""" # MatrixBox methods
security.declareProtected( Permissions.AccessContentsInformation,
meta_type = 'ERP5 Delivery Cell' 'hasCellContent' )
portal_type = 'Delivery Cell' def hasCellContent(self, base_id='movement'):
isCell = 1 """A cell cannot have cell content itself.
"""
# Declarative security return 0
security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation) security.declareProtected(Permissions.AccessContentsInformation, 'isAccountable')
def isAccountable(self):
# Declarative properties """
property_sheets = ( PropertySheet.Base Returns 1 if this needs to be accounted
, PropertySheet.CategoryCore Only account movements which are not associated to a delivery
, PropertySheet.Arrow Whenever delivery is there, delivery has priority
, PropertySheet.Amount """
, PropertySheet.Task return self.getParentValue().getParentValue().isAccountable()
, PropertySheet.Movement
, PropertySheet.Price security.declareProtected(Permissions.AccessContentsInformation, 'getPrice')
, PropertySheet.Predicate def getPrice(self, *args, **kw):
, PropertySheet.MappedValue """
, PropertySheet.ItemAggregation call Movement.getPrice
) """
return Movement.getPrice(self, *args, **kw)
# Declarative interfaces
zope.interface.implements(interfaces.IDivergenceController,) security.declareProtected(Permissions.AccessContentsInformation, 'getTotalPrice')
def getTotalPrice(self, default=0.0, *args, **kw):
security.declareProtected(Permissions.AccessContentsInformation, 'isPredicate') """
def isPredicate(self): call Movement.getTotalPrice
"""Movements are not predicates. """
""" return Movement.getTotalPrice(self, default=default, *args, **kw)
return False
security.declareProtected(Permissions.AccessContentsInformation,
# MatrixBox methods 'getRootDeliveryValue')
security.declareProtected( Permissions.AccessContentsInformation, def getRootDeliveryValue(self):
'hasCellContent' ) """
def hasCellContent(self, base_id='movement'): Returns the root delivery responsible of this cell
"""A cell cannot have cell content itself. """
""" return self.getParentValue().getRootDeliveryValue()
return 0
security.declareProtected( Permissions.ModifyPortalContent,
security.declareProtected(Permissions.AccessContentsInformation, 'isAccountable') 'notifyAfterUpdateRelatedContent' )
def isAccountable(self): def notifyAfterUpdateRelatedContent(self, previous_category_url, new_category_url):
""" """
Returns 1 if this needs to be accounted Membership Crirerions and Category List are same in DeliveryCell
Only account movements which are not associated to a delivery Must update it (or change implementation to remove data duplication)
Whenever delivery is there, delivery has priority """
""" update_method = self.portal_categories.updateRelatedCategory
return self.getParentValue().getParentValue().isAccountable() new_predicate_value = [update_method(c, previous_category_url, new_category_url)
for c in self.getPredicateValueList()]
security.declareProtected(Permissions.AccessContentsInformation, 'getPrice') self._setPredicateValueList(new_predicate_value)
def getPrice(self, *args, **kw): # No reindex needed since uid stable
"""
call Movement.getPrice # XXX FIXME: option variation are today not well implemented
""" # This little hack is needed to make the matrixbox working
return Movement.getPrice(self, *args, **kw) # in DeliveryLine_viewIndustrialPhase
# Generic form (DeliveryLine_viewOption) is required
security.declareProtected(Permissions.AccessContentsInformation, 'getTotalPrice') def _edit(self, **kw):
def getTotalPrice(self, default=0.0, *args, **kw): """
""" Store variation_category_list, in order to store new value of
call Movement.getTotalPrice industrial_phase after.
""" """
return Movement.getTotalPrice(self, default=default, *args, **kw) edit_order = ['variation_category_list', # edit this one first
'item_id_list'] # this one must be the last
security.declareProtected(Permissions.AccessContentsInformation, edit_order[1:1] = [x for x in kw.pop('edit_order', ())
'getRootDeliveryValue') if x not in edit_order]
def getRootDeliveryValue(self): # Base._edit updates unordered properties first
""" edit_order[1:1] = [x for x in kw if x not in edit_order]
Returns the root delivery responsible of this cell MappedValue._edit(self, edit_order=edit_order, **kw)
"""
return self.getParentValue().getRootDeliveryValue()
security.declareProtected( Permissions.ModifyPortalContent,
'notifyAfterUpdateRelatedContent' )
def notifyAfterUpdateRelatedContent(self, previous_category_url,
new_category_url):
"""
Membership Crirerions and Category List are same in DeliveryCell
Must update it (or change implementation to remove data duplication)
"""
update_method = self.portal_categories.updateRelatedCategory
predicate_value = self.getPredicateValueList()
new_predicate_value = map(lambda c: update_method(c,
previous_category_url, new_category_url), predicate_value)
self._setPredicateValueList(new_predicate_value)
# No reindex needed since uid stable
# XXX FIXME: option variation are today not well implemented
# This little hack is needed to make the matrixbox working
# in DeliveryLine_viewIndustrialPhase
# Generic form (DeliveryLine_viewOption) is required
def _edit(self, **kw):
"""
Store variation_category_list, in order to store new value of
industrial_phase after.
"""
edit_order = ['variation_category_list', # edit this one first
'item_id_list'] # this one must be the last
edit_order[1:1] = [x for x in kw.pop('edit_order', ())
if x not in edit_order]
# Base._edit updates unordered properties first
edit_order[1:1] = [x for x in kw if x not in edit_order]
MappedValue._edit(self, edit_order=edit_order, **kw)
# if self.isSimulated(): # if self.isSimulated():
# self.getRootDeliveryValue().activate().propagateResourceToSimulation() # self.getRootDeliveryValue().activate().propagateResourceToSimulation()
security.declareProtected(Permissions.ModifyPortalContent, security.declareProtected(Permissions.ModifyPortalContent,
'updateSimulationDeliveryProperties') 'updateSimulationDeliveryProperties')
def updateSimulationDeliveryProperties(self, movement_list = None): def updateSimulationDeliveryProperties(self, movement_list = None):
""" """
Set properties delivery_ratio and delivery_error for each Set properties delivery_ratio and delivery_error for each
simulation movement in movement_list (all movements by default), simulation movement in movement_list (all movements by default),
according to this delivery calculated quantity according to this delivery calculated quantity
""" """
parent = self.getParentValue() parent = self.getParentValue()
if parent is not None:
parent = parent.getParentValue()
if parent is not None: if parent is not None:
parent = parent.getParentValue() parent.updateSimulationDeliveryProperties(movement_list, self)
if parent is not None:
parent.updateSimulationDeliveryProperties(movement_list, self) security.declareProtected(Permissions.AccessContentsInformation, 'isMovement')
def isMovement(self):
security.declareProtected(Permissions.AccessContentsInformation, 'isMovement') return 1
def isMovement(self):
return 1 security.declareProtected(Permissions.AccessContentsInformation,
'isMovingItem')
security.declareProtected(Permissions.AccessContentsInformation, def isMovingItem(self, item):
'isMovingItem') type_based_script = self._getTypeBasedMethod('isMovingItem')
def isMovingItem(self, item): if type_based_script:
type_based_script = self._getTypeBasedMethod('isMovingItem') return type_based_script(item)
if type_based_script: return self.isAccountable()
return type_based_script(item)
return self.isAccountable() # Override getQuantityUnitXXX to negate same methods defined in
# Amount class. Because cell must acquire quantity unit from line
# Override getQuantityUnitXXX to negate same methods defined in # not from resource.
# Amount class. Because cell must acquire quantity unit from line security.declareProtected( Permissions.AccessContentsInformation,
# not from resource. 'getQuantityUnitValue')
security.declareProtected( Permissions.AccessContentsInformation, def getQuantityUnitValue(self):
'getQuantityUnitValue') return self.getParentValue().getQuantityUnitValue()
def getQuantityUnitValue(self):
return self.getParentValue().getQuantityUnitValue() security.declareProtected( Permissions.AccessContentsInformation,
'getQuantityUnit')
security.declareProtected( Permissions.AccessContentsInformation, def getQuantityUnit(self, checked_permission=None):
'getQuantityUnit') return self.getParentValue().getQuantityUnit(checked_permission=checked_permission)
def getQuantityUnit(self, checked_permission=None):
return self.getParentValue().getQuantityUnit(checked_permission=checked_permission) # XXX: Dirty but required for erp5_banking_core
### Acquire Baobab source / destination uids from parent line
# XXX: Dirty but required for erp5_banking_core getBaobabSourceUid = lambda x: x.getSourceUid()
### Acquire Baobab source / destination uids from parent line getBaobabSourceUid__roles__ = PermissionRole(Permissions.View)
getBaobabSourceUid = lambda x: x.getSourceUid()
getBaobabSourceUid__roles__ = PermissionRole(Permissions.View) getBaobabDestinationUid = lambda x: x.getDestinationUid()
getBaobabDestinationUid__roles__ = PermissionRole(Permissions.View)
getBaobabDestinationUid = lambda x: x.getDestinationUid()
getBaobabDestinationUid__roles__ = PermissionRole(Permissions.View) getBaobabSourceSectionUid = lambda x: x.getSourceSectionUid()
getBaobabSourceSectionUid__roles__ = PermissionRole(Permissions.View)
getBaobabSourceSectionUid = lambda x: x.getSourceSectionUid()
getBaobabSourceSectionUid__roles__ = PermissionRole(Permissions.View) getBaobabDestinationSectionUid = lambda x: x.getDestinationSectionUid()
getBaobabDestinationSectionUid__roles__ = PermissionRole(Permissions.View)
getBaobabDestinationSectionUid = lambda x: x.getDestinationSectionUid()
getBaobabDestinationSectionUid__roles__ = PermissionRole(Permissions.View) getBaobabSourcePaymentUid = lambda x: x.getSourcePaymentUid()
getBaobabSourcePaymentUid__roles__ = PermissionRole(Permissions.View)
getBaobabSourcePaymentUid = lambda x: x.getSourcePaymentUid()
getBaobabSourcePaymentUid__roles__ = PermissionRole(Permissions.View) getBaobabDestinationPaymentUid = lambda x: x.getDestinationPaymentUid()
getBaobabDestinationPaymentUid__roles__ = PermissionRole(Permissions.View)
getBaobabDestinationPaymentUid = lambda x: x.getDestinationPaymentUid()
getBaobabDestinationPaymentUid__roles__ = PermissionRole(Permissions.View) getBaobabSourceFunctionUid = lambda x: x.getSourceFunctionUid()
getBaobabSourceFunctionUid__roles__ = PermissionRole(Permissions.View)
getBaobabSourceFunctionUid = lambda x: x.getSourceFunctionUid()
getBaobabSourceFunctionUid__roles__ = PermissionRole(Permissions.View) getBaobabDestinationFunctionUid = lambda x: x.getDestinationFunctionUid()
getBaobabDestinationFunctionUid__roles__ = PermissionRole(Permissions.View)
getBaobabDestinationFunctionUid = lambda x: x.getDestinationFunctionUid()
getBaobabDestinationFunctionUid__roles__ = PermissionRole(Permissions.View) getBaobabSourceProjectUid = lambda x: x.getSourceProjectUid()
getBaobabSourceProjectUid__roles__ = PermissionRole(Permissions.View)
getBaobabSourceProjectUid = lambda x: x.getSourceProjectUid()
getBaobabSourceProjectUid__roles__ = PermissionRole(Permissions.View) getBaobabDestinationProjectUid = lambda x: x.getDestinationProjectUid()
getBaobabDestinationProjectUid__roles__ = PermissionRole(Permissions.View)
getBaobabDestinationProjectUid = lambda x: x.getDestinationProjectUid() \ No newline at end of file
getBaobabDestinationProjectUid__roles__ = PermissionRole(Permissions.View)
...@@ -41,240 +41,238 @@ from Products.ERP5Type.Base import Base ...@@ -41,240 +41,238 @@ from Products.ERP5Type.Base import Base
edit_args_list = getargspec(Base._edit).args edit_args_list = getargspec(Base._edit).args
class DeliveryLine(Movement, XMLMatrix, ImmobilisationMovement): class DeliveryLine(Movement, XMLMatrix, ImmobilisationMovement):
"""
A DeliveryLine object allows to implement lines in
Deliveries (packing list, order, invoice, etc.)
It may include a price (for insurance, for customs, for invoices,
for orders)
"""
meta_type = 'ERP5 Delivery Line'
portal_type = 'Delivery Line'
# Declarative security
security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation)
# Declarative properties
property_sheets = ( PropertySheet.Base
, PropertySheet.XMLObject
, PropertySheet.CategoryCore
, PropertySheet.Amount
, PropertySheet.Task
, PropertySheet.Arrow
, PropertySheet.Movement
, PropertySheet.Price
, PropertySheet.VariationRange
, PropertySheet.ItemAggregation
, PropertySheet.SortIndex
)
# Declarative interfaces
zope.interface.implements(interfaces.IDivergenceController,)
# Multiple inheritance definition
updateRelatedContent = XMLMatrix.updateRelatedContent
# Force in _edit to modify variation_base_category_list first
def _edit(self, edit_order=(), **kw):
# XXX FIXME For now, special cases are handled in _edit methods in many
# documents : DeliveryLine, DeliveryCell ... Ideally, to prevent code
# duplication, it should be handled in a _edit method present only in
# Amount.py
# If variations and resources are set at the same time, resource must be
# set before any variation.
before_order = ('resource', 'resource_value',
'variation_base_category_list',
'variation_category_list')
before_kw = {k: kw.pop(k) for k in before_order if k in kw}
if before_kw:
before_kw.update((k, kw[k]) for k in edit_args_list if k in kw)
Base._edit(self, edit_order=before_order, **before_kw)
if kw:
Movement._edit(self, edit_order=edit_order, **kw)
# We must check if the user has changed the resource of particular line
security.declareProtected( Permissions.ModifyPortalContent, 'edit' )
def edit(self, REQUEST=None, force_update = 0, reindex_object=1, **kw):
return self._edit(REQUEST=REQUEST, force_update=force_update, reindex_object=reindex_object, **kw)
security.declareProtected(Permissions.AccessContentsInformation,
'isAccountable')
def isAccountable(self):
"""To avoid duplicate docstring. Please read movement interface."""
return self.getParentValue().isAccountable() and (not self.hasCellContent())
security.declareProtected(Permissions.AccessContentsInformation,
'isMovingItem')
def isMovingItem(self, item):
type_based_script = self._getTypeBasedMethod('isMovingItem')
if type_based_script:
return type_based_script(item)
return self.isAccountable()
def _getTotalPrice(self, default=0.0, context=None, fast=0):
""" """
A DeliveryLine object allows to implement lines in Returns the total price for this line, this line contains, or the cells it contains.
Deliveries (packing list, order, invoice, etc.)
It may include a price (for insurance, for customs, for invoices, if hasLineContent: return sum of lines total price
for orders) if hasCellContent: return sum of cells total price
else: return quantity * price
if fast argument is true, inventory API will be used.
""" """
if fast:
kw = {}
kw['section_uid'] = self.getDestinationSectionUid()
kw['stock.explanation_uid'] = self.getExplanationUid()
kw['relative_url'] = ( '%s/%%' % (
self.getRelativeUrl().replace('_', '\\_')),
self.getRelativeUrl() )
kw['only_accountable'] = False
return self.getPortalObject().portal_simulation.getInventoryAssetPrice(**kw)
if self.hasLineContent():
meta_type = self.meta_type
return sum(l.getTotalPrice(context=context)
for l in self.objectValues() if l.meta_type==meta_type)
elif not self.hasCellContent(base_id='movement'):
return Movement._getTotalPrice(self, default=default, context=context)
return sum(cell.getTotalPrice(default=0.0, context=context)
for cell in self.getCellValueList())
security.declareProtected( Permissions.AccessContentsInformation,
'getTotalQuantity')
def getTotalQuantity(self, fast=0):
"""
Returns the quantity if no cell or the total quantity if cells
meta_type = 'ERP5 Delivery Line' if hasLineContent: return sum of lines total quantity
portal_type = 'Delivery Line' if hasCellContent: return sum of cells total quantity
else: return quantity
# Declarative security if fast argument is true, inventory API will be used.
security = ClassSecurityInfo() """
security.declareObjectProtected(Permissions.AccessContentsInformation) if fast:
kw = {}
# Declarative properties kw['section_uid'] = self.getDestinationSectionUid()
property_sheets = ( PropertySheet.Base kw['stock.explanation_uid'] = self.getExplanationUid()
, PropertySheet.XMLObject kw['relative_url'] = ( '%s/%%' % (
, PropertySheet.CategoryCore self.getRelativeUrl().replace('_', '\\_')),
, PropertySheet.Amount self.getRelativeUrl() )
, PropertySheet.Task kw['only_accountable'] = False
, PropertySheet.Arrow return self.getPortalObject().portal_simulation.getInventory(**kw)
, PropertySheet.Movement
, PropertySheet.Price base_id = 'movement'
, PropertySheet.VariationRange if self.hasLineContent():
, PropertySheet.ItemAggregation meta_type = self.meta_type
, PropertySheet.SortIndex return sum(l.getTotalQuantity() for l in
) self.objectValues() if l.meta_type==meta_type)
elif self.hasCellContent(base_id=base_id):
# Declarative interfaces return sum([cell.getQuantity() for cell in self.getCellValueList()])
zope.interface.implements(interfaces.IDivergenceController,) return self.getQuantity()
# Multiple inheritance definition security.declareProtected(Permissions.AccessContentsInformation,
updateRelatedContent = XMLMatrix.updateRelatedContent 'hasLineContent')
def hasLineContent(self):
# Force in _edit to modify variation_base_category_list first """Return true if the object contains lines.
def _edit(self, edit_order=(), **kw):
# XXX FIXME For now, special cases are handled in _edit methods in many
# documents : DeliveryLine, DeliveryCell ... Ideally, to prevent code
# duplication, it should be handled in a _edit method present only in
# Amount.py
# If variations and resources are set at the same time, resource must be
# set before any variation.
before_order = ('resource', 'resource_value',
'variation_base_category_list',
'variation_category_list')
before_kw = {k: kw.pop(k) for k in before_order if k in kw}
if before_kw:
before_kw.update((k, kw[k]) for k in edit_args_list if k in kw)
Base._edit(self, edit_order=before_order, **before_kw)
if kw:
Movement._edit(self, edit_order=edit_order, **kw)
# We must check if the user has changed the resource of particular line
security.declareProtected( Permissions.ModifyPortalContent, 'edit' )
def edit(self, REQUEST=None, force_update = 0, reindex_object=1, **kw):
return self._edit(REQUEST=REQUEST, force_update=force_update, reindex_object=reindex_object, **kw)
security.declareProtected(Permissions.AccessContentsInformation,
'isAccountable')
def isAccountable(self):
"""To avoid duplicate docstring. Please read movement interface."""
return self.getParentValue().isAccountable() and (not self.hasCellContent())
security.declareProtected(Permissions.AccessContentsInformation,
'isMovingItem')
def isMovingItem(self, item):
type_based_script = self._getTypeBasedMethod('isMovingItem')
if type_based_script:
return type_based_script(item)
return self.isAccountable()
def _getTotalPrice(self, default=0.0, context=None, fast=0):
"""
Returns the total price for this line, this line contains, or the cells it contains.
if hasLineContent: return sum of lines total price
if hasCellContent: return sum of cells total price
else: return quantity * price
if fast argument is true, inventory API will be used.
"""
if fast:
kw = {}
kw['section_uid'] = self.getDestinationSectionUid()
kw['stock.explanation_uid'] = self.getExplanationUid()
kw['relative_url'] = ( '%s/%%' % (
self.getRelativeUrl().replace('_', '\\_')),
self.getRelativeUrl() )
kw['only_accountable'] = False
return self.getPortalObject().portal_simulation.getInventoryAssetPrice(**kw)
if self.hasLineContent():
meta_type = self.meta_type
return sum(l.getTotalPrice(context=context)
for l in self.objectValues() if l.meta_type==meta_type)
elif not self.hasCellContent(base_id='movement'):
return Movement._getTotalPrice(self, default=default, context=context)
return sum(cell.getTotalPrice(default=0.0, context=context)
for cell in self.getCellValueList())
security.declareProtected( Permissions.AccessContentsInformation,
'getTotalQuantity')
def getTotalQuantity(self, fast=0):
"""
Returns the quantity if no cell or the total quantity if cells
if hasLineContent: return sum of lines total quantity
if hasCellContent: return sum of cells total quantity
else: return quantity
if fast argument is true, inventory API will be used.
"""
if fast:
kw = {}
kw['section_uid'] = self.getDestinationSectionUid()
kw['stock.explanation_uid'] = self.getExplanationUid()
kw['relative_url'] = ( '%s/%%' % (
self.getRelativeUrl().replace('_', '\\_')),
self.getRelativeUrl() )
kw['only_accountable'] = False
return self.getPortalObject().portal_simulation.getInventory(**kw)
base_id = 'movement'
if self.hasLineContent():
meta_type = self.meta_type
return sum(l.getTotalQuantity() for l in
self.objectValues() if l.meta_type==meta_type)
elif self.hasCellContent(base_id=base_id):
return sum([cell.getQuantity() for cell in self.getCellValueList()])
return self.getQuantity()
security.declareProtected(Permissions.AccessContentsInformation,
'hasLineContent')
def hasLineContent(self):
"""Return true if the object contains lines.
This method only checks the first sub line because all sub This method only checks the first sub line because all sub
lines should be same meta type in reality if we have line lines should be same meta type in reality if we have line
inside line. inside line.
""" """
return len(self) != 0 and self.objectValues()[0].meta_type == self.meta_type return len(self) != 0 and self.objectValues()[0].meta_type == self.meta_type
security.declareProtected(Permissions.AccessContentsInformation, security.declareProtected(Permissions.AccessContentsInformation,
'hasCellContent') 'hasCellContent')
def hasCellContent(self, base_id='movement'): def hasCellContent(self, base_id='movement'):
"""Return true if the object contains cells. """Return true if the object contains cells.
""" """
# Do not use XMLMatrix.hasCellContent, because it can generate # Do not use XMLMatrix.hasCellContent, because it can generate
# inconsistency in catalog # inconsistency in catalog
# Exemple: define a line and set the matrix cell range, but do not create # Exemple: define a line and set the matrix cell range, but do not create
# cell. # cell.
# Line was in this case consider like a movement, and was catalogued. # Line was in this case consider like a movement, and was catalogued.
# But, getVariationText of the line was not empty. # But, getVariationText of the line was not empty.
# So, in ZODB, resource as without variation, but in catalog, this was # So, in ZODB, resource as without variation, but in catalog, this was
# the contrary... # the contrary...
cell_range = XMLMatrix.getCellRange(self, base_id=base_id) cell_range = XMLMatrix.getCellRange(self, base_id=base_id)
return (cell_range is not None and len(cell_range) > 0) return (cell_range is not None and len(cell_range) > 0)
# DeliveryLine can be a movement when it does not content any cell and # DeliveryLine can be a movement when it does not content any cell and
# matrix cell range is not empty. # matrix cell range is not empty.
# Better implementation is needed. # Better implementation is needed.
# We want to define a line without cell, defining a variated resource. # We want to define a line without cell, defining a variated resource.
# If we modify the cell range, we need to move the quantity to a new # If we modify the cell range, we need to move the quantity to a new
# cell, which define the same variated resource. # cell, which define the same variated resource.
# return XMLMatrix.hasCellContent(self, base_id=base_id) # return XMLMatrix.hasCellContent(self, base_id=base_id)
security.declareProtected( Permissions.AccessContentsInformation, security.declareProtected( Permissions.AccessContentsInformation,
'isMovement' ) 'isMovement' )
def isMovement(self): def isMovement(self):
""" """
returns true is the object contains no submovement (line or cell) returns true is the object contains no submovement (line or cell)
""" """
object_list = self.objectValues() object_list = self.objectValues()
if object_list: if object_list:
portal_type = self.getPortalObject().getPortalMovementTypeList() portal_type = self.getPortalObject().getPortalMovementTypeList()
for ob in object_list: for ob in object_list:
if ob.getPortalType() in portal_type: if ob.getPortalType() in portal_type:
return False return False
return True return True
security.declareProtected(Permissions.AccessContentsInformation, 'getMovedItemUidList') security.declareProtected(Permissions.AccessContentsInformation, 'getMovedItemUidList')
def getMovedItemUidList(self): def getMovedItemUidList(self):
"""This method returns an uid list of items """This method returns an uid list of items
""" """
return [item.getUid() for item in self.getAggregateValueList() \ return [item.getUid() for item in self.getAggregateValueList() \
if self.isMovingItem(item)] if self.isMovingItem(item)]
security.declareProtected( Permissions.AccessContentsInformation, 'getCellValueList' ) security.declareProtected( Permissions.AccessContentsInformation, 'getCellValueList' )
def getCellValueList(self, base_id='movement'): def getCellValueList(self, base_id='movement'):
""" """
This method can be overriden This method can be overriden
""" """
return XMLMatrix.getCellValueList(self, base_id=base_id) return XMLMatrix.getCellValueList(self, base_id=base_id)
security.declareProtected( Permissions.AccessContentsInformation, 'getCell' ) security.declareProtected( Permissions.AccessContentsInformation, 'getCell' )
def getCell(self, *kw , **kwd): def getCell(self, *kw , **kwd):
""" """
This method can be overriden This method can be overriden
""" """
if 'base_id' not in kwd: if 'base_id' not in kwd:
kwd['base_id'] = 'movement' kwd['base_id'] = 'movement'
return XMLMatrix.getCell(self, *kw, **kwd) return XMLMatrix.getCell(self, *kw, **kwd)
security.declareProtected( Permissions.ModifyPortalContent, 'newCell' ) security.declareProtected( Permissions.ModifyPortalContent, 'newCell' )
def newCell(self, *kw, **kwd): def newCell(self, *kw, **kwd):
""" """
This method creates a new cell This method creates a new cell
""" """
if 'base_id' not in kwd: if 'base_id' not in kwd:
kwd['base_id'] = 'movement' kwd['base_id'] = 'movement'
return XMLMatrix.newCell(self, *kw, **kwd) return XMLMatrix.newCell(self, *kw, **kwd)
def applyToDeliveryLineRelatedMovement(self, portal_type='Simulation Movement', method_id = 'expand'): def applyToDeliveryLineRelatedMovement(self, portal_type='Simulation Movement', method_id = 'expand'):
# Find related in simulation # Find related in simulation
for my_simulation_movement in self.getDeliveryRelatedValueList( for my_simulation_movement in self.getDeliveryRelatedValueList(
portal_type = 'Simulation Movement'): portal_type = 'Simulation Movement'):
# And apply
getattr(my_simulation_movement.getObject(), method_id)()
for c in self.objectValues(portal_type='Delivery Cell'):
for my_simulation_movement in c.getDeliveryRelatedValueList(
portal_type = 'Simulation Movement'):
# And apply # And apply
getattr(my_simulation_movement.getObject(), method_id)() getattr(my_simulation_movement.getObject(), method_id)()
for c in self.objectValues(portal_type='Delivery Cell'):
for my_simulation_movement in c.getDeliveryRelatedValueList( def reindexObject(self, *k, **kw):
portal_type = 'Simulation Movement'): """Reindex children"""
# And apply self.recursiveReindexObject(*k, **kw)
getattr(my_simulation_movement.getObject(), method_id)()
security.declareProtected(Permissions.AccessContentsInformation, 'getInventoriatedQuantity')
def reindexObject(self, *k, **kw): def getInventoriatedQuantity(self):
"""Reindex children""" """
self.recursiveReindexObject(*k, **kw) """
return Movement.getInventoriatedQuantity(self)
security.declareProtected(Permissions.AccessContentsInformation, 'getInventoriatedQuantity')
def getInventoriatedQuantity(self):
"""
"""
return Movement.getInventoriatedQuantity(self)
# security.declarePrivate('_checkConsistency') # security.declarePrivate('_checkConsistency')
# def _checkConsistency(self, fixit=0, mapped_value_property_list = ('quantity', 'price')): # def _checkConsistency(self, fixit=0, mapped_value_property_list = ('quantity', 'price')):
...@@ -311,188 +309,185 @@ class DeliveryLine(Movement, XMLMatrix, ImmobilisationMovement): ...@@ -311,188 +309,185 @@ class DeliveryLine(Movement, XMLMatrix, ImmobilisationMovement):
# #
# return error_list # return error_list
security.declareProtected(Permissions.AccessContentsInformation, security.declareProtected(Permissions.AccessContentsInformation,
'getRootDeliveryValue') 'getRootDeliveryValue')
def getRootDeliveryValue(self): def getRootDeliveryValue(self):
""" """
Returns the root delivery responsible of this line Returns the root delivery responsible of this line
""" """
return self.getParentValue().getRootDeliveryValue() return self.getParentValue().getRootDeliveryValue()
security.declareProtected(Permissions.ModifyPortalContent, security.declareProtected(Permissions.ModifyPortalContent,
'updateSimulationDeliveryProperties') 'updateSimulationDeliveryProperties')
def updateSimulationDeliveryProperties(self, movement_list = None): def updateSimulationDeliveryProperties(self, movement_list = None):
""" """
Set properties delivery_ratio and delivery_error for each Set properties delivery_ratio and delivery_error for each
simulation movement in movement_list (all movements by default), simulation movement in movement_list (all movements by default),
according to this delivery calculated quantity according to this delivery calculated quantity
""" """
parent = self.getParentValue() parent = self.getParentValue()
if parent is not None: if parent is not None:
parent.updateSimulationDeliveryProperties(movement_list, self) parent.updateSimulationDeliveryProperties(movement_list, self)
security.declarePrivate('manage_afterAdd') security.declarePrivate('manage_afterAdd')
def manage_afterAdd(self, item, container): def manage_afterAdd(self, item, container):
"if the container is a line too, reindex it" "if the container is a line too, reindex it"
if self.meta_type == container.meta_type: if self.meta_type == container.meta_type:
container.reindexObject() container.reindexObject()
return Movement.manage_afterAdd(self, item, container) return Movement.manage_afterAdd(self, item, container)
security.declarePrivate('manage_beforeDelete') security.declarePrivate('manage_beforeDelete')
def manage_beforeDelete(self, item, container): def manage_beforeDelete(self, item, container):
"if the container is a line too, reindex it" "if the container is a line too, reindex it"
if self.meta_type == container.meta_type: if self.meta_type == container.meta_type:
container.reindexObject() container.reindexObject()
return Movement.manage_beforeDelete(self, item, container) return Movement.manage_beforeDelete(self, item, container)
# divergence support with solving # divergence support with solving
security.declareProtected(Permissions.AccessContentsInformation, 'isDivergent') security.declareProtected(Permissions.AccessContentsInformation, 'isDivergent')
def isDivergent(self): def isDivergent(self):
"""Returns true if the delivery line is divergent, or if any contained """Returns true if the delivery line is divergent, or if any contained
cell is divergent. cell is divergent.
""" """
return bool(self.getDivergenceList()) return bool(self.getDivergenceList())
security.declareProtected(Permissions.AccessContentsInformation, 'getDivergenceList') security.declareProtected(Permissions.AccessContentsInformation, 'getDivergenceList')
def getDivergenceList(self): def getDivergenceList(self):
"""Returns a list of messages that contains the divergences for that line """Returns a list of messages that contains the divergences for that line
and the cells it may contain. and the cells it may contain.
""" """
if self.hasCellContent(): if self.hasCellContent():
divergence_list = [] divergence_list = []
for cell in self.objectValues(portal_type=self.getPortalObject() for cell in self.objectValues(portal_type=self.getPortalObject()
.getPortalDeliveryMovementTypeList()): .getPortalDeliveryMovementTypeList()):
divergence_list += cell.getDivergenceList() divergence_list += cell.getDivergenceList()
return divergence_list return divergence_list
else: else:
return Movement.getDivergenceList(self) return Movement.getDivergenceList(self)
def _distributePropertyToSimulation(self, decision): def _distributePropertyToSimulation(self, decision):
"""Distributes property from self to all related simulation movements """Distributes property from self to all related simulation movements
AKA - accept decision""" AKA - accept decision"""
for simulation_movement in self.getDeliveryRelatedValueList( for simulation_movement in self.getDeliveryRelatedValueList(
portal_type='Simulation Movement'): portal_type='Simulation Movement'):
simulation_movement.edit(**{ simulation_movement.edit(**{
decision.divergence.tested_property: decision.divergence.tested_property:
self.getProperty(decision.divergence.tested_property) self.getProperty(decision.divergence.tested_property)
}) })
def _updatePropertyFromSimulation(self, decision_list): def _updatePropertyFromSimulation(self, decision_list):
"""Update property from simulation """Update property from simulation
'Stolen' from Products.ERP5.Document.DeliveryBuilder._solveDivergence 'Stolen' from Products.ERP5.Document.DeliveryBuilder._solveDivergence
Another possibility is to just simply copy properties or, in case of Another possibility is to just simply copy properties or, in case of
quantity, add from all simulation movements. quantity, add from all simulation movements.
""" """
simulation_movement_list = self.getDeliveryRelatedValueList( simulation_movement_list = self.getDeliveryRelatedValueList(
portal_type="Simulation Movement") portal_type="Simulation Movement")
business_link = simulation_movement_list[0].getCausalityValue() business_link = simulation_movement_list[0].getCausalityValue()
delivery = self.getExplanationValue() delivery = self.getExplanationValue()
delivery_portal_type = delivery.getPortalType() delivery_portal_type = delivery.getPortalType()
delivery_line_portal_type = self.getPortalType() delivery_line_portal_type = self.getPortalType()
# we need to find only one matching delivery builder # we need to find only one matching delivery builder
for delivery_builder in business_link.getDeliveryBuilderValueList(): for delivery_builder in business_link.getDeliveryBuilderValueList():
if delivery_builder.getDeliveryPortalType() == \ if delivery_builder.getDeliveryPortalType() == \
delivery_portal_type and \ delivery_portal_type and \
delivery_builder.getDeliveryLinePortalType() == \ delivery_builder.getDeliveryLinePortalType() == \
delivery_line_portal_type: delivery_line_portal_type:
break break
else:
raise ValueError('No builder found')
self.edit(quantity=0) # adoption have to 'rebuild' delivery line
# Collect
root_group_node = delivery_builder.collectMovement(
simulation_movement_list)
divergence_list = [decision.divergence for decision in decision_list]
# Build
portal = self.getPortalObject()
delivery_module = getattr(portal, delivery_builder.getDeliveryModule())
delivery_to_update_list = [delivery]
delivery_list = delivery_builder._processDeliveryGroup(
delivery_module,
root_group_node,
delivery_builder.getDeliveryMovementGroupList(),
delivery_to_update_list=delivery_to_update_list,
divergence_list=divergence_list,
force_update=1)
new_delivery_list = [x for x in delivery_list if x != delivery]
if new_delivery_list:
raise ValueError('No new deliveries shall be created')
# Then, we should re-apply quantity divergence according to 'Do
# nothing' quantity divergence list because all quantity are already
# calculated in adopt prevision phase.
quantity_dict = {}
for divergence in self.getDivergenceList():
if divergence.getProperty('divergence_scope') != 'quantity' or \
divergence in divergence_list:
continue
s_m = divergence.getProperty('simulation_movement')
delivery_movement = s_m.getDeliveryValue()
assert delivery_movement == self
quantity_gap = divergence.getProperty('decision_value') - \
divergence.getProperty('prevision_value')
delivery_movement.setQuantity(delivery_movement.getQuantity() + \
quantity_gap)
quantity_dict[s_m] = \
divergence.getProperty('decision_value')
# Finally, recalculate delivery_ratio
#
# Here, created/updated movements are not indexed yet. So we try to
# gather delivery relations from simulation movements.
delivery_dict = {}
for s_m in simulation_movement_list:
delivery_path = s_m.getDelivery()
delivery_dict[delivery_path] = \
delivery_dict.get(delivery_path, []) + \
[s_m]
for s_m_list_per_movement in delivery_dict.values():
total_quantity = sum([quantity_dict.get(s_m, s_m.getQuantity()) \
for s_m in s_m_list_per_movement])
if total_quantity != 0.0:
for s_m in s_m_list_per_movement:
delivery_ratio = quantity_dict.get(s_m, s_m.getQuantity()) \
/ total_quantity
s_m.edit(delivery_ratio=delivery_ratio)
else: else:
raise ValueError('No builder found') for s_m in s_m_list_per_movement:
delivery_ratio = 1.0 / len(s_m_list_per_movement)
self.edit(quantity=0) # adoption have to 'rebuild' delivery line s_m.edit(delivery_ratio=delivery_ratio)
movement_type_list = (delivery_builder.getDeliveryLinePortalType(),
delivery_builder.getDeliveryCellPortalType()) security.declareProtected(Permissions.ModifyPortalContent, 'solve')
# Collect def solve(self, decision_list):
root_group_node = delivery_builder.collectMovement( """Solves line according to decision list
simulation_movement_list) """
simulation_tool = self.getPortalObject().portal_simulation
divergence_list = [decision.divergence for decision in decision_list] solveMovement = simulation_tool.solveMovement
# accept + split
# Build for decision in [q for q in decision_list if q.decision != 'adopt']:
portal = self.getPortalObject() if decision.decision == 'accept':
delivery_module = getattr(portal, delivery_builder.getDeliveryModule()) # accepting - in case of passed DeliverySolver use it, otherwise
delivery_to_update_list = [delivery] # simply copy values to simulation
delivery_list = delivery_builder._processDeliveryGroup( if not decision.delivery_solver_name:
delivery_module, self._distributePropertyToSimulation(decision)
root_group_node, solveMovement(self, decision.delivery_solver_name,
delivery_builder.getDeliveryMovementGroupList(), decision.target_solver_name, divergence_list = [decision.divergence])
delivery_to_update_list=delivery_to_update_list, elif decision.decision == 'split':
divergence_list=divergence_list, solveMovement(self, decision.delivery_solver_name,
force_update=1) decision.target_solver_name, **decision.split_kw)
else: # aka - do nothing
new_delivery_list = [x for x in delivery_list if x != delivery] pass
if new_delivery_list: # adopt
raise ValueError('No new deliveries shall be created') adopt_decision_list = [q for q in decision_list \
if q.decision == 'adopt']
# Then, we should re-apply quantity divergence according to 'Do if adopt_decision_list:
# nothing' quantity divergence list because all quantity are already self._updatePropertyFromSimulation(adopt_decision_list)
# calculated in adopt prevision phase. \ No newline at end of file
quantity_dict = {}
for divergence in self.getDivergenceList():
if divergence.getProperty('divergence_scope') != 'quantity' or \
divergence in divergence_list:
continue
s_m = divergence.getProperty('simulation_movement')
delivery_movement = s_m.getDeliveryValue()
assert delivery_movement == self
quantity_gap = divergence.getProperty('decision_value') - \
divergence.getProperty('prevision_value')
delivery_movement.setQuantity(delivery_movement.getQuantity() + \
quantity_gap)
quantity_dict[s_m] = \
divergence.getProperty('decision_value')
# Finally, recalculate delivery_ratio
#
# Here, created/updated movements are not indexed yet. So we try to
# gather delivery relations from simulation movements.
delivery_dict = {}
for s_m in simulation_movement_list:
delivery_path = s_m.getDelivery()
delivery_dict[delivery_path] = \
delivery_dict.get(delivery_path, []) + \
[s_m]
for s_m_list_per_movement in delivery_dict.values():
total_quantity = sum([quantity_dict.get(s_m, s_m.getQuantity()) \
for s_m in s_m_list_per_movement])
if total_quantity != 0.0:
for s_m in s_m_list_per_movement:
delivery_ratio = quantity_dict.get(s_m, s_m.getQuantity()) \
/ total_quantity
s_m.edit(delivery_ratio=delivery_ratio)
else:
for s_m in s_m_list_per_movement:
delivery_ratio = 1.0 / len(s_m_list_per_movement)
s_m.edit(delivery_ratio=delivery_ratio)
security.declareProtected(Permissions.ModifyPortalContent, 'solve')
def solve(self, decision_list):
"""Solves line according to decision list
"""
simulation_tool = self.getPortalObject().portal_simulation
solveMovement = simulation_tool.solveMovement
solve_result_list = []
# accept + split
for decision in [q for q in decision_list if q.decision != 'adopt']:
if decision.decision == 'accept':
# accepting - in case of passed DeliverySolver use it, otherwise
# simply copy values to simulation
if not decision.delivery_solver_name:
self._distributePropertyToSimulation(decision)
solveMovement(self, decision.delivery_solver_name,
decision.target_solver_name, divergence_list = [decision.divergence])
elif decision.decision == 'split':
solveMovement(self, decision.delivery_solver_name,
decision.target_solver_name, **decision.split_kw)
else: # aka - do nothing
pass
# adopt
adopt_decision_list = [q for q in decision_list \
if q.decision == 'adopt']
if adopt_decision_list:
self._updatePropertyFromSimulation(adopt_decision_list)
...@@ -34,64 +34,62 @@ from Products.ERP5Type.Accessor.Constant import PropertyGetter as ConstantGetter ...@@ -34,64 +34,62 @@ from Products.ERP5Type.Accessor.Constant import PropertyGetter as ConstantGetter
from Products.ERP5.Document.DeliveryCell import DeliveryCell from Products.ERP5.Document.DeliveryCell import DeliveryCell
class InventoryCell(DeliveryCell): class InventoryCell(DeliveryCell):
""" """
An InventoryCell allows to define specific inventory An InventoryCell allows to define specific inventory
for each variation of a resource in an inventory line. for each variation of a resource in an inventory line.
""" """
meta_type = 'ERP5 Inventory Cell'
portal_type = 'Inventory Cell'
add_permission = Permissions.AddPortalContent
isInventoryMovement = ConstantGetter('isInventoryMovement', value=True)
meta_type = 'ERP5 Inventory Cell' # Declarative security
portal_type = 'Inventory Cell' security = ClassSecurityInfo()
add_permission = Permissions.AddPortalContent security.declareObjectProtected(Permissions.AccessContentsInformation)
isInventoryMovement = ConstantGetter('isInventoryMovement', value=True)
# Declarative security # Declarative properties
security = ClassSecurityInfo() property_sheets = ( PropertySheet.Base
security.declareObjectProtected(Permissions.AccessContentsInformation) , PropertySheet.CategoryCore
, PropertySheet.Amount
, PropertySheet.InventoryMovement
, PropertySheet.Task
, PropertySheet.Movement
, PropertySheet.Price
, PropertySheet.Predicate
, PropertySheet.MappedValue
, PropertySheet.ItemAggregation
)
# Declarative properties security.declareProtected(Permissions.AccessContentsInformation, 'getTotalInventory')
property_sheets = ( PropertySheet.Base def getTotalInventory(self):
, PropertySheet.CategoryCore """
, PropertySheet.Amount Returns the inventory, as cells are not supposed to contain more cells.
, PropertySheet.InventoryMovement """
, PropertySheet.Task return self.getInventory()
, PropertySheet.Movement
, PropertySheet.Price
, PropertySheet.Predicate
, PropertySheet.MappedValue
, PropertySheet.ItemAggregation
)
security.declareProtected(Permissions.AccessContentsInformation, 'getTotalInventory') security.declareProtected(Permissions.AccessContentsInformation, 'getQuantity')
def getTotalInventory(self): def getQuantity(self):
""" """
Returns the inventory, as cells are not supposed to contain more cells. Computes a quantity which allows to reach inventory
""" """
if not self.hasCellContent():
# First check if quantity already exists
quantity = self._baseGetQuantity()
if quantity not in (0.0, 0, None):
return quantity
# Make sure inventory is defined somewhere (here or parent)
if getattr(aq_base(self), 'inventory', None) is None:
return 0.0 # No inventory defined, so no quantity
return self.getInventory() return self.getInventory()
else:
return None
security.declareProtected(Permissions.AccessContentsInformation, 'getQuantity') # Inventory cataloging
def getQuantity(self): security.declareProtected(Permissions.AccessContentsInformation, 'getConvertedInventory')
""" def getConvertedInventory(self):
Computes a quantity which allows to reach inventory """
""" provides a default inventory value - None since
if not self.hasCellContent(): no inventory was defined.
# First check if quantity already exists """
quantity = self._baseGetQuantity() return self.getInventory() # XXX quantity unit is missing
if quantity not in (0.0, 0, None): \ No newline at end of file
return quantity
# Make sure inventory is defined somewhere (here or parent)
if getattr(aq_base(self), 'inventory', None) is None:
return 0.0 # No inventory defined, so no quantity
return self.getInventory()
else:
return None
# Inventory cataloging
security.declareProtected(Permissions.AccessContentsInformation, 'getConvertedInventory')
def getConvertedInventory(self):
"""
provides a default inventory value - None since
no inventory was defined.
"""
return self.getInventory() # XXX quantity unit is missing
...@@ -36,112 +36,110 @@ from Products.ERP5.Document.Movement import Movement ...@@ -36,112 +36,110 @@ from Products.ERP5.Document.Movement import Movement
from Products.ERP5Type.Accessor.Constant import PropertyGetter as ConstantGetter from Products.ERP5Type.Accessor.Constant import PropertyGetter as ConstantGetter
class InventoryLine(DeliveryLine): class InventoryLine(DeliveryLine):
"""
An Inventory Line describe the inventory of a resource, by variations.
"""
meta_type = 'ERP5 Inventory Line'
portal_type = 'Inventory Line'
add_permission = Permissions.AddPortalContent
isInventoryMovement = ConstantGetter('isInventoryMovement', value=True)
# Declarative security
security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation)
# Declarative properties
property_sheets = ( PropertySheet.Base
, PropertySheet.XMLObject
, PropertySheet.CategoryCore
, PropertySheet.Amount
, PropertySheet.InventoryMovement
, PropertySheet.Task
, PropertySheet.Arrow
, PropertySheet.Movement
, PropertySheet.VariationRange
, PropertySheet.ItemAggregation
)
security.declareProtected(Permissions.AccessContentsInformation, 'getTotalInventory')
def getTotalInventory(self):
""" """
An Inventory Line describe the inventory of a resource, by variations. Returns the inventory if no cell or the total inventory if cells
""" """
if not self.hasCellContent():
meta_type = 'ERP5 Inventory Line' return self.getInventory()
portal_type = 'Inventory Line' else:
add_permission = Permissions.AddPortalContent total_quantity = 0.0
isInventoryMovement = ConstantGetter('isInventoryMovement', value=True) for cell in self.getCellValueList(base_id='movement'):
if cell.getInventory() is not None:
# Declarative security total_quantity += cell.getInventory()
security = ClassSecurityInfo() return total_quantity
security.declareObjectProtected(Permissions.AccessContentsInformation)
security.declareProtected(Permissions.AccessContentsInformation,
# Declarative properties 'getQuantity')
property_sheets = ( PropertySheet.Base def getQuantity(self):
, PropertySheet.XMLObject """
, PropertySheet.CategoryCore Computes a quantity which allows to reach inventory
, PropertySheet.Amount """
, PropertySheet.InventoryMovement if not self.hasCellContent():
, PropertySheet.Task # First check if quantity already exists
, PropertySheet.Arrow quantity = self._baseGetQuantity()
, PropertySheet.Movement if quantity not in (0.0,0,None):
, PropertySheet.VariationRange
, PropertySheet.ItemAggregation
)
security.declareProtected(Permissions.AccessContentsInformation, 'getTotalInventory')
def getTotalInventory(self):
"""
Returns the inventory if no cell or the total inventory if cells
"""
if not self.hasCellContent():
return self.getInventory()
else:
total_quantity = 0.0
for cell in self.getCellValueList(base_id='movement'):
if cell.getInventory() is not None:
total_quantity += cell.getInventory()
return total_quantity
security.declareProtected(Permissions.AccessContentsInformation,
'getQuantity')
def getQuantity(self):
"""
Computes a quantity which allows to reach inventory
"""
if not self.hasCellContent():
# First check if quantity already exists
quantity = self._baseGetQuantity()
if quantity not in (0.0,0,None):
return quantity
# Make sure inventory is defined somewhere (here or parent)
inventory = getattr(aq_base(self), 'inventory', None)
if inventory is not None:
return inventory
return quantity return quantity
else: # Make sure inventory is defined somewhere (here or parent)
return None inventory = getattr(aq_base(self), 'inventory', None)
if inventory is not None:
# Inventory cataloging return inventory
security.declareProtected(Permissions.AccessContentsInformation, return quantity
'getConvertedInventory') else:
def getConvertedInventory(self): return None
"""
provides a default inventory value - None since # Inventory cataloging
no inventory was defined. security.declareProtected(Permissions.AccessContentsInformation,
""" 'getConvertedInventory')
return self.getInventory() # XXX quantity unit is missing def getConvertedInventory(self):
"""
# Required for indexing provides a default inventory value - None since
security.declareProtected(Permissions.AccessContentsInformation, no inventory was defined.
'getInventoriatedQuantity') """
def getInventoriatedQuantity(self): return self.getInventory() # XXX quantity unit is missing
"""
Take into account efficiency in converted target quantity # Required for indexing
""" security.declareProtected(Permissions.AccessContentsInformation,
return Movement.getInventoriatedQuantity(self) 'getInventoriatedQuantity')
def getInventoriatedQuantity(self):
# XXX: Dirty but required for erp5_banking_core """
getBaobabSourceUid = lambda x: x.getSourceUid() Take into account efficiency in converted target quantity
getBaobabSourceUid__roles__ = PermissionRole(Permissions.View) """
return Movement.getInventoriatedQuantity(self)
getBaobabDestinationUid = lambda x: x.getDestinationUid()
getBaobabDestinationUid__roles__ = PermissionRole(Permissions.View) # XXX: Dirty but required for erp5_banking_core
getBaobabSourceUid = lambda x: x.getSourceUid()
getBaobabSourceSectionUid = lambda x: x.getSourceSectionUid() getBaobabSourceUid__roles__ = PermissionRole(Permissions.View)
getBaobabSourceSectionUid__roles__ = PermissionRole(Permissions.View)
getBaobabDestinationUid = lambda x: x.getDestinationUid()
getBaobabDestinationSectionUid = lambda x: x.getDestinationSectionUid() getBaobabDestinationUid__roles__ = PermissionRole(Permissions.View)
getBaobabDestinationSectionUid__roles__ = PermissionRole(Permissions.View)
getBaobabSourceSectionUid = lambda x: x.getSourceSectionUid()
getBaobabSourcePaymentUid = lambda x: x.getSourcePaymentUid() getBaobabSourceSectionUid__roles__ = PermissionRole(Permissions.View)
getBaobabSourcePaymentUid__roles__ = PermissionRole(Permissions.View)
getBaobabDestinationSectionUid = lambda x: x.getDestinationSectionUid()
getBaobabDestinationPaymentUid = lambda x: x.getDestinationPaymentUid() getBaobabDestinationSectionUid__roles__ = PermissionRole(Permissions.View)
getBaobabDestinationPaymentUid__roles__ = PermissionRole(Permissions.View)
getBaobabSourcePaymentUid = lambda x: x.getSourcePaymentUid()
getBaobabSourceFunctionUid = lambda x: x.getSourceFunctionUid() getBaobabSourcePaymentUid__roles__ = PermissionRole(Permissions.View)
getBaobabSourceFunctionUid__roles__ = PermissionRole(Permissions.View)
getBaobabDestinationPaymentUid = lambda x: x.getDestinationPaymentUid()
getBaobabDestinationFunctionUid = lambda x: x.getDestinationFunctionUid() getBaobabDestinationPaymentUid__roles__ = PermissionRole(Permissions.View)
getBaobabDestinationFunctionUid__roles__ = PermissionRole(Permissions.View)
getBaobabSourceFunctionUid = lambda x: x.getSourceFunctionUid()
getBaobabSourceProjectUid = lambda x: x.getSourceProjectUid() getBaobabSourceFunctionUid__roles__ = PermissionRole(Permissions.View)
getBaobabSourceProjectUid__roles__ = PermissionRole(Permissions.View)
getBaobabDestinationFunctionUid = lambda x: x.getDestinationFunctionUid()
getBaobabDestinationProjectUid = lambda x: x.getDestinationProjectUid() getBaobabDestinationFunctionUid__roles__ = PermissionRole(Permissions.View)
getBaobabDestinationProjectUid__roles__ = PermissionRole(Permissions.View)
getBaobabSourceProjectUid = lambda x: x.getSourceProjectUid()
getBaobabSourceProjectUid__roles__ = PermissionRole(Permissions.View)
getBaobabDestinationProjectUid = lambda x: x.getDestinationProjectUid()
getBaobabDestinationProjectUid__roles__ = PermissionRole(Permissions.View)
\ No newline at end of file
...@@ -33,59 +33,57 @@ from Products.ERP5Type import Permissions, PropertySheet ...@@ -33,59 +33,57 @@ from Products.ERP5Type import Permissions, PropertySheet
from Products.ERP5.Document.DeliveryCell import DeliveryCell from Products.ERP5.Document.DeliveryCell import DeliveryCell
class OrderCell(DeliveryCell): class OrderCell(DeliveryCell):
""" """
A OrderCell allows to define specific quantities A OrderCell allows to define specific quantities
for each variation of a resource in a delivery line. for each variation of a resource in a delivery line.
""" """
meta_type = 'ERP5 Order Cell'
portal_type = 'Order Cell'
isCell = 1
meta_type = 'ERP5 Order Cell' # Declarative security
portal_type = 'Order Cell' security = ClassSecurityInfo()
isCell = 1 security.declareObjectProtected(Permissions.AccessContentsInformation)
# Declarative security # Declarative properties
security = ClassSecurityInfo() property_sheets = ( PropertySheet.Base
security.declareObjectProtected(Permissions.AccessContentsInformation) , PropertySheet.CategoryCore
, PropertySheet.Arrow
, PropertySheet.Amount
, PropertySheet.Task
, PropertySheet.Movement
, PropertySheet.Price
, PropertySheet.Predicate
, PropertySheet.MappedValue
, PropertySheet.ItemAggregation
)
# Declarative properties def reindexObject(self, *k, **kw):
property_sheets = ( PropertySheet.Base """
, PropertySheet.CategoryCore Reindex children and simulation
, PropertySheet.Arrow """
, PropertySheet.Amount self.recursiveReindexObject(*k,**kw)
, PropertySheet.Task
, PropertySheet.Movement
, PropertySheet.Price
, PropertySheet.Predicate
, PropertySheet.MappedValue
, PropertySheet.ItemAggregation
)
def reindexObject(self, *k, **kw):
"""
Reindex children and simulation
"""
self.recursiveReindexObject(*k,**kw)
security.declareProtected(Permissions.AccessContentsInformation, security.declareProtected(Permissions.AccessContentsInformation,
'isMovement') 'isMovement')
def isMovement(self): def isMovement(self):
""" """
should be considered as a movement if the parent does not have sub lines should be considered as a movement if the parent does not have sub lines
""" """
return not self.getParentValue().hasLineContent() return not self.getParentValue().hasLineContent()
security.declareProtected(Permissions.AccessContentsInformation, security.declareProtected(Permissions.AccessContentsInformation,
'getTotalPrice') 'getTotalPrice')
def getTotalPrice(self, default=0.0, *args, **kw): def getTotalPrice(self, default=0.0, *args, **kw):
"only return a value if self is a movement" "only return a value if self is a movement"
if not self.isMovement(): if not self.isMovement():
return default return default
return DeliveryCell.getTotalPrice(self, default=default, *args, **kw) return DeliveryCell.getTotalPrice(self, default=default, *args, **kw)
security.declareProtected(Permissions.AccessContentsInformation,
'getTotalQuantity')
def getTotalQuantity(self, default=0.0, *args, **kw):
"only return a value if self is a movement"
if not self.isMovement():
return default
return DeliveryCell.getTotalQuantity(self, default=default, *args, **kw)
security.declareProtected(Permissions.AccessContentsInformation,
'getTotalQuantity')
def getTotalQuantity(self, default=0.0, *args, **kw):
"only return a value if self is a movement"
if not self.isMovement():
return default
return DeliveryCell.getTotalQuantity(self, default=default, *args, **kw)
\ No newline at end of file
...@@ -32,27 +32,26 @@ from Products.ERP5Type import Permissions, PropertySheet ...@@ -32,27 +32,26 @@ from Products.ERP5Type import Permissions, PropertySheet
from Products.ERP5.Document.DeliveryLine import DeliveryLine from Products.ERP5.Document.DeliveryLine import DeliveryLine
class OrderLine(DeliveryLine): class OrderLine(DeliveryLine):
""" """
A order line defines quantity and price A order line defines quantity and price
""" """
meta_type = 'ERP5 Order Line'
portal_type = 'Order Line'
meta_type = 'ERP5 Order Line' # Declarative security
portal_type = 'Order Line' security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation)
# Declarative security # Declarative properties
security = ClassSecurityInfo() property_sheets = ( PropertySheet.Base
security.declareObjectProtected(Permissions.AccessContentsInformation) , PropertySheet.XMLObject
, PropertySheet.CategoryCore
# Declarative properties , PropertySheet.Amount
property_sheets = ( PropertySheet.Base , PropertySheet.Task
, PropertySheet.XMLObject , PropertySheet.DublinCore
, PropertySheet.CategoryCore , PropertySheet.Arrow
, PropertySheet.Amount , PropertySheet.Movement
, PropertySheet.Task , PropertySheet.Price
, PropertySheet.DublinCore , PropertySheet.VariationRange
, PropertySheet.Arrow , PropertySheet.ItemAggregation
, PropertySheet.Movement )
, PropertySheet.Price \ No newline at end of file
, PropertySheet.VariationRange
, PropertySheet.ItemAggregation
)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment