diff --git a/product/ERP5/Document/ImmobilisationCell.py b/product/ERP5/Document/ImmobilisationCell.py new file mode 100755 index 0000000000000000000000000000000000000000..f3848b5af756446e00c9294d836cecb17ca74d71 --- /dev/null +++ b/product/ERP5/Document/ImmobilisationCell.py @@ -0,0 +1,76 @@ +############################################################################## +# +# Copyright (c) 2002 Nexedi SARL and Contributors. All Rights Reserved. +# Guillaume Michon <guillaume@nexedi.com> +# +# WARNING: This program as such is intended to be used by professional +# programmers who take the whole responsability of assessing all potential +# consequences resulting from its eventual inadequacies and bugs +# End users who are looking for a ready-to-use solution with commercial +# garantees and support are strongly adviced to contract a Free Software +# Service Company +# +# This program is Free Software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +############################################################################## + +from Globals import InitializeClass +from AccessControl import ClassSecurityInfo + +from Products.ERP5Type import Base, Permissions, PropertySheet, Constraint, Interface +from Products.ERP5.Core import MetaNode, MetaResource +from Products.CMFCore.WorkflowCore import WorkflowMethod + +from Products.ERP5Type.XMLObject import XMLObject +from Products.ERP5.Document.Amount import Amount +from Products.ERP5.Document.Movement import Movement +from Products.ERP5.Document.ImmobilisationMovement import ImmobilisationMovement + +from string import capitalize +from zLOG import LOG + +class ImmobilisationCell(Movement, XMLObject, ImmobilisationMovement): + """ + """ + meta_type = 'ERP5 Immobilisation Cell' + portal_type = 'Immobilisation Cell' + add_permission = Permissions.AddPortalContent + isPortalContent = 1 + isRADContent = 1 + isMovement = 1 + isAccountable = 0 # It should not be indexed in stock table + + # Declarative security + security = ClassSecurityInfo() + security.declareObjectProtected(Permissions.AccessContentsInformation) + + # Declarative interfaces + __implements__ = ( Interface.Variated, ) + + # Declarative properties + property_sheets = ( PropertySheet.Base + , PropertySheet.XMLObject + , PropertySheet.CategoryCore + , PropertySheet.DublinCore + , PropertySheet.Task + , PropertySheet.Arrow + , PropertySheet.Movement + , PropertySheet.Delivery + , PropertySheet.Reference + , PropertySheet.Amount + , PropertySheet.Price + , PropertySheet.Amortisation + ) + diff --git a/product/ERP5/Document/ImmobilisationDelivery.py b/product/ERP5/Document/ImmobilisationDelivery.py new file mode 100755 index 0000000000000000000000000000000000000000..be68082b1602bc6a96f54bc7e550116214eb71fd --- /dev/null +++ b/product/ERP5/Document/ImmobilisationDelivery.py @@ -0,0 +1,174 @@ +############################################################################## +# +# Copyright (c) 2002 Nexedi SARL and Contributors. All Rights Reserved. +# Guillaume Michon <guillaume.michon@e-asc.com> +# +# WARNING: This program as such is intended to be used by professional +# programmers who take the whole responsability of assessing all potential +# consequences resulting from its eventual inadequacies and bugs +# End users who are looking for a ready-to-use solution with commercial +# garantees and support are strongly adviced to contract a Free Software +# Service Company +# +# This program is Free Software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +############################################################################## + +from Globals import InitializeClass, PersistentMapping +from AccessControl import ClassSecurityInfo + +from DateTime import DateTime +from string import capitalize + +from Products.ERP5Type import Permissions, PropertySheet, Constraint, Interface +from Products.ERP5Type.XMLObject import XMLObject +from Products.ERP5Type.DateUtils import addToDate, getClosestDate, getIntervalBetweenDates +from Products.ERP5Type.DateUtils import getMonthAndDaysBetween, getRoundedMonthBetween +from Products.ERP5Type.DateUtils import getMonthFraction, getYearFraction, getBissextilCompliantYearFraction +from Products.ERP5Type.DateUtils import same_movement_interval, number_of_months_in_year, centis, millis +from Products.ERP5.Document.Amount import Amount +from Products.CMFCore.WorkflowCore import WorkflowMethod +from Products.CMFCore.utils import getToolByName +from Products.ERP5.Document.ImmobilisableItem import ImmobilisationValidityError + + +from zLOG import LOG + + +NEGLIGEABLE_PRICE = 10e-8 + +class ImmobilisationDelivery(XMLObject): + """ + An Immobilisation Delivery is an object whose role is to + contain delivery movements which can immobilise items. + """ + + meta_type = 'ERP5 Immobilisation Delivery' + portal_type = 'Immobilisation Delivery' + add_permission = Permissions.AddPortalContent + isPortalContent = 1 + isRADContent = 1 + + # Declarative security + security = ClassSecurityInfo() + security.declareObjectProtected(Permissions.AccessContentsInformation) + + # Declarative properties + property_sheets = ( PropertySheet.Base + , PropertySheet.XMLObject + , PropertySheet.CategoryCore + , PropertySheet.DublinCore + , PropertySheet.Task + , PropertySheet.Arrow + , PropertySheet.Movement + , PropertySheet.Delivery + , PropertySheet.Reference + ) + + def validate_immobilisation(self, **kw): + pass + def invalidate_immobilisation(self, **kw): + pass + def calculate_immobilisation_validity(self, **kw): + pass + + validate_immobilisation = WorkflowMethod(validate_immobilisation) + invalidate_immobilisation = WorkflowMethod(invalidate_immobilisation) + calculate_immobilisation_validity = WorkflowMethod(calculate_immobilisation_validity) + + security.declareProtected(Permissions.View, 'updateImmobilisationState') + def updateImmobilisationState(self,**kw): + """ + This is often called as an activity, it will check if the + delivery is valid as an immobilisation movement, and if so + it will put the delivery in a valid state, if not valid in + an invalid state + """ + if self.getImmobilisationState() == 'calculating': + try: + if self.isValidImmobilisationMovement(**kw): + self.validate_immobilisation() + else: + self.invalidate_immobilisation() + except ImmobilisationValidityError: + self.calculate_immobilisation_validity() + + security.declareProtected(Permissions.View, 'getImmobilisationState') + def getImmobilisationState(self, id_only=1): + """ + Returns the current state in immobilisation validity + """ + portal_workflow = getToolByName(self, 'portal_workflow') + wf = portal_workflow.getWorkflowById('immobilisation_workflow') + return wf._getWorkflowStateOf(self, id_only=id_only) + + security.declareProtected(Permissions.View, 'getImmobilisationMovementList') + def getImmobilisationMovementList(self, **kw): + """ + Return regular movements + immobilisation movements like + Immobilisation Line and Immobilisation Cell + """ + return self.getMovementList(self.getPortalMovementTypeList() + + ('Immobilisation Line', 'Immobilisation Cell'), **kw) + + security.declareProtected(Permissions.View, 'checkImmobilisationConsistency') + def checkImmobilisationConsistency(self, *args, **kw): + """ + Check the consistency about immobilisation values + """ + return_list = [] + for movement in self.getImmobilisationMovementList(): + return_list.extend(movement.checkImmobilisationConsistency()) + return return_list + + security.declareProtected(Permissions.View, 'isValidImmobilisationMovement') + def isValidImmobilisationMovement(self, *args, **kw): + """ + Return true if all submovements are valid in terms of immobilisation + """ + error_list = self.checkImmobilisationConsistency(*args, **kw) + if len(error_list) == 0: + return 1 + return 0 + + security.declareProtected(Permissions.View, 'isInvalidImmobilisationMovement') + def isInvalidImmobilisationMovement(self, *args, **kw): + """ + Return false if all submovements are valid in terms of immobilisation + """ + return not self.isValidImmobilisationMovement(*args, **kw) + + security.declareProtected(Permissions.View, 'getAggregatedItemsNextImmobilisationMovementValueList') + def getAggregatedItemsNextImmobilisationMovementValueList(self, **kw): + """ + Return the list of each next immobilisation movement for each aggregated item + """ + returned_list = [] + sub_movement_list = self.contentValues() + for movement in self.getImmobilisationMovementList(**kw): + for item in movement.getAggregateValueList(): + future_movement_list = item.getFutureImmobilisationMovementValueList( + at_date = self.getStopDate(), + from_movement = self, + filter_valid = 0) + if future_movement_list is not None: + for next_movement in future_movement_list: + if next_movement is not None and \ + next_movement not in sub_movement_list and \ + next_movement not in returned_list and \ + next_movement.getStopDate() != self.getStopDate(): + returned_list.append(next_movement) + return returned_list + diff --git a/product/ERP5/Document/ImmobilisationLine.py b/product/ERP5/Document/ImmobilisationLine.py new file mode 100755 index 0000000000000000000000000000000000000000..98960fb718d724d45bf6cfb78cd9bd6a0f657ebb --- /dev/null +++ b/product/ERP5/Document/ImmobilisationLine.py @@ -0,0 +1,76 @@ +############################################################################## +# +# Copyright (c) 2002 Nexedi SARL and Contributors. All Rights Reserved. +# Guillaume Michon <guillaume@nexedi.com> +# +# WARNING: This program as such is intended to be used by professional +# programmers who take the whole responsability of assessing all potential +# consequences resulting from its eventual inadequacies and bugs +# End users who are looking for a ready-to-use solution with commercial +# garantees and support are strongly adviced to contract a Free Software +# Service Company +# +# This program is Free Software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +############################################################################## + +from Globals import InitializeClass +from AccessControl import ClassSecurityInfo + +from Products.ERP5Type import Base, Permissions, PropertySheet, Constraint, Interface +from Products.ERP5.Core import MetaNode, MetaResource +from Products.CMFCore.WorkflowCore import WorkflowMethod + +from Products.ERP5Type.XMLObject import XMLObject +from Products.ERP5.Document.Amount import Amount +from Products.ERP5.Document.Movement import Movement +from Products.ERP5.Document.ImmobilisationMovement import ImmobilisationMovement +from Products.ERP5.Document.DeliveryLine import DeliveryLine + +from string import capitalize +from zLOG import LOG + +class ImmobilisationLine(Movement, XMLObject, ImmobilisationMovement, DeliveryLine): + """ + """ + meta_type = 'ERP5 Immobilisation Line' + portal_type = 'Immobilisation Line' + add_permission = Permissions.AddPortalContent + isPortalContent = 1 + isRADContent = 1 + isMovement = 1 + isAccountable = 0 # It should not be indexed in stock table + + # Declarative security + security = ClassSecurityInfo() + security.declareObjectProtected(Permissions.AccessContentsInformation) + + # Declarative interfaces + __implements__ = ( Interface.Variated, ) + + # Declarative properties + property_sheets = ( PropertySheet.Base + , PropertySheet.XMLObject + , PropertySheet.CategoryCore + , PropertySheet.DublinCore + , PropertySheet.Task + , PropertySheet.Arrow + , PropertySheet.Movement + , PropertySheet.Delivery + , PropertySheet.Reference + , PropertySheet.Amount + , PropertySheet.Price + , PropertySheet.Amortisation + ) diff --git a/product/ERP5/Document/ImmobilisationMovement.py b/product/ERP5/Document/ImmobilisationMovement.py new file mode 100755 index 0000000000000000000000000000000000000000..8bfb744f5ff973fcee9ddf9bf1fed8112980c79c --- /dev/null +++ b/product/ERP5/Document/ImmobilisationMovement.py @@ -0,0 +1,372 @@ +############################################################################## +# +# Copyright (c) 2002 Nexedi SARL and Contributors. All Rights Reserved. +# Guillaume Michon <guillaume.michon@e-asc.com> +# +# WARNING: This program as such is intended to be used by professional +# programmers who take the whole responsability of assessing all potential +# consequences resulting from its eventual inadequacies and bugs +# End users who are looking for a ready-to-use solution with commercial +# garantees and support are strongly adviced to contract a Free Software +# Service Company +# +# This program is Free Software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +############################################################################## + +from Globals import InitializeClass +from AccessControl import ClassSecurityInfo + +from Products.ERP5Type import Base, Permissions, PropertySheet, Constraint, Interface +from Products.ERP5.Core import MetaNode, MetaResource +from Products.CMFCore.WorkflowCore import WorkflowMethod + +from Products.ERP5Type.XMLObject import XMLObject +from Products.ERP5.Document.Amount import Amount +from Products.ERP5.Document.Movement import Movement +from Products.ERP5Type.DateUtils import millis + +from string import capitalize +from zLOG import LOG + +UNIMMOBILISING_METHOD = "unimmobilise" +NO_CHANGE_METHOD = "no_change" +AMORTISATION_METHOD_PREFIX = "erp5_accounting_" +IMMOBILISATION_NEEDED_PROPERTY_LIST = [ + ("date", "stop_date", "Date"), + ("method", "amortisation_method", "Amortisation Method"), + ] +IMMOBILISATION_UNCONTINUOUS_NEEDED_PROPERTY_LIST = [ + ("main_price", "amortisation_start_price", "Immobilised Price"), + ("disposal_price", "disposal_price", "Disposal Price"), + ("duration", "amortisation_duration", "Amortisation Duration"), + ("vat", "immobilisation_vat", "VAT"), + ("input_account", "input_account", "Input Account"), + ("output_account", "output_account", "Output Account"), + ("immobilisation_account", "immobilisation_account", "Immobilisation Account"), + ("amortisation_account", "amortisation_account", "Amortisation Account"), + ("depreciation_account", "depreciation_account", "Depreciation Account"), + ("vat_account", "immobilisation_vat_account", "VAT Account"), + ("extra_cost_account", "extra_cost_account", "Extra Costs Account"), + ] +IMMOBILISATION_FACULTATIVE_PROPERTY_LIST = [ + ("monthly_amortisation_account", "monthly_amortisation_account", "Monthly Amortisation Account"), + ("extra_cost_price", "extra_cost_price", "Extra Costs Price"), + ("durability", "durability", "Durability"), + ] + + + +class ImmobilisationMovement(Movement, XMLObject): + """ + An ImmobilisationMovement is a generic object representing an immobilisation + and optional amortisation decision for any item. It holds information about + an accounting immobilisation (in order to amortise an object) + """ + meta_type = 'ERP5 Immobilisation Movement' + portal_type = 'Immobilisation Movement' + add_permission = Permissions.AddPortalContent + isPortalContent = 1 + isRADContent = 1 + + # Declarative security + security = ClassSecurityInfo() + security.declareObjectProtected(Permissions.AccessContentsInformation) + + # Declarative interfaces + __implements__ = ( Interface.Variated, ) + + # Declarative properties + property_sheets = ( PropertySheet.Base + , PropertySheet.XMLObject + , PropertySheet.CategoryCore + , PropertySheet.DublinCore + , PropertySheet.Task + , PropertySheet.Arrow + , PropertySheet.Movement + , PropertySheet.Delivery + , PropertySheet.Reference + , PropertySheet.Amount + , PropertySheet.Price + , PropertySheet.Amortisation + ) + + + def _checkImmobilisationConsistency(self, fixit=0, mapped_value_property_list=()): + relative_url = self.getRelativeUrl() + + def checkValuesAreNotNone(property_list): + errors = [] + for key, value, name in property_list: + value = 'get' + ''.join(map(capitalize, value.split('_'))) + value = getattr(self, value, None) + if value is not None: + value = value() + if key == 'method' and not value: + value = NO_CHANGE_METHOD + errors.extend(checkValue(variable=value, + forbidden_value_list=[None], + error_message=["Property value inconsistency", 0, "%s property is empty" % name] + ) + ) + return errors + + def checkValue(variable, + forbidden_value_list=None, + authorized_value_list=None, + error_message=["Error Type", 0, "Error message"]): + if forbidden_value_list is not None: + if type(forbidden_value_list) != type([]): + forbidden_value_list = [forbidden_value_list] + if variable in forbidden_value_list: + return [ tuple([relative_url] + error_message) ] + if authorized_value_list is not None: + if type(authorized_value_list) != type([]): + authorized_value_list = [authorized_value_list] + if variable not in authorized_value_list: + return [ tuple([relative_url] + error_message) ] + return [] + + errors = [] + # Check absolutely needed values + method = self.getAmortisationMethod() or NO_CHANGE_METHOD + errors.extend(checkValuesAreNotNone(IMMOBILISATION_NEEDED_PROPERTY_LIST)) + property_list = self.getNeededSpecificParameterListForItem(None) + errors.extend(checkValuesAreNotNone(property_list)) + + # Check if the date of this movement is unique + date_error = 0 + for item in self.getAggregateValueList(): + same_date_list = item.getUnfilteredImmobilisationMovementValueList( + from_date = self.getStopDate(), + to_date = self.getStopDate(), + include_to_date = 1) + error_found = 0 + for other_movement in same_date_list: + if other_movement != self and other_movement.getRootDeliveryValue().getImmobilisationState() == 'valid': + error_found = 1 + date_error = 1 + if error_found: + errors.append([self.getRelativeUrl(), + "Property value inconsistency", 0, + "An other movement already exists at the same date for item %s" % item.getRelativeUrl()]) + + # Return to avoid infinite loops in case of date errors + if date_error: + return errors + + item_list = self.getAggregateValueList() + if len(item_list) == 0: + # No item aggregated, so the movement is considered as valid + #errors.append([self.getRelativeUrl(), + # "Property value inconsistency", 0, + # "No item aggregated"]) + return errors + + # Check values needed if the amortisation method is not continuous + check_uncontinuous = 0 + if self.getStopDate() is not None: + if method not in [None, "", NO_CHANGE_METHOD, UNIMMOBILISING_METHOD]: + continuous = self.getAmortisationMethodParameter("continuous")["continuous"] + if not continuous: + check_uncontinuous = 1 + else: + # We need to check if the preceding movement is in the same period, and if it is valid + # This check must be done on each item + def checkPreviousMovementForItem(movement, item): + previous_movement = item.getLastImmobilisationMovementValue(at_date=movement.getStopDate()) + if previous_movement is None: + return 0 + if previous_movement.getImmobilisationState() == 'valid': + if previous_movement.getAmortisationMethod() not in ("", NO_CHANGE_METHOD): + return 1 + return checkPreviousMovementForItem(previous_movement, item) + return checkPreviousMovementForItem(previous_movement, item) + for item in self.getAggregateValueList(): + if not checkPreviousMovementForItem(self,item): + check_uncontinuous = 1 + else: + # The last movement which is not a NO_CHANGE is valid + # Now check if the method is the same, then if the period is really continuing from previous movement + previous_movement = item.getLastImmobilisationMovementValue(at_date=self.getStopDate()) + previous_movement_method = previous_movement.getActualAmortisationMethodForItem(item) + if previous_movement_method != method: + check_uncontinuous = 1 + # If the previous method is the same, it means the previous movement did + # not stop the immobilisation, because stopping is a particular method + if check_uncontinuous: + errors.extend(checkValuesAreNotNone(IMMOBILISATION_UNCONTINUOUS_NEEDED_PROPERTY_LIST)) + property_list = self.getUncontinuousNeededSpecificParameterListForItem(None) + errors.extend(checkValuesAreNotNone(property_list)) + + # Do not check facultative properties (of course) + + # Check owner change for each aggregated item + # XXX Checking it here would be inadequate, since the owner can change by multiple ways : + # adding a new movement for this item, changing it, modifying related organisation, etc... + # It is not compatible with a validity workflow approach since the causalities are too numerous + # The actual check is done in ImmobilisableItem.getImmobilisationPeriodList() + return errors + + + security.declareProtected(Permissions.View, 'checkImmobilisationConsistency') + def checkImmobilisationConsistency(self, *args, **kw): + """ + Checks the consistency about immobilisation values + """ + return_value = self._checkImmobilisationConsistency(*args, **kw) + return return_value + + + security.declareProtected(Permissions.View, 'getAmortisationMethodParameter') + def getAmortisationMethodParameter(self, parameter_list, **kw): + """ + Returns a dictionary containing the value of each parameter + whose name is given in parameter_list. + Warning : can only be used on a movement whose amortisation_method + is not in (None, NO_CHANGE_METHOD) + """ + if self.getAmortisationMethod() in (None, "", NO_CHANGE_METHOD): + return None + return self.getAmortisationMethodParameterForItem(None, parameter_list, **kw) + + + security.declareProtected(Permissions.View, 'getAmortisationMethodParameter') + def getAmortisationMethodParameterForItem(self, item, parameter_list, split_char=None, split_qty=3, **kw): + """ + Returns a dictionary containing the value of each parameter + whose name is given in parameter_list. + The value is get from the amortisation method parameter folder + (e.g. portal_skins/erp5_accounting_eu/linear) + This folder has specifical parameters needed for calculation + 'item' can be None to access parameters on a movement whose method is not NO_CHANGE_METHOD nor None + """ + parameter_dict = {} + if type(parameter_list) == type(""): + parameter_list = [parameter_list] + for parameter in parameter_list: + parameter_dict[parameter] = None + amortisation_method = self.getActualAmortisationMethodForItem(item, **kw) + if amortisation_method not in (None, NO_CHANGE_METHOD, UNIMMOBILISING_METHOD, ""): + parameter_object = self.restrictedTraverse(AMORTISATION_METHOD_PREFIX + amortisation_method) + if parameter_object is not None: + for parameter in parameter_list: + parameter_dict[parameter] = getattr(parameter_object, parameter, None) + + if (split_char is not None) and (split_qty != 0): + new_parameter_dict = {} + for key in parameter_dict.keys(): + param_list = parameter_dict[key] + if param_list is None: + new_parameter_dict[key] = [] + if type(param_list) != type([]) and type(param_list) != type(()): + param_list = [param_list] + new_param_list = [] + for param in param_list: + if param is not None: + if param.find(split_char) != -1: + param = param.split(split_char) + param = [x.strip() for x in param] + if type(param) != type([]) and type(param) != type(()): + param = [param] + if len(param) > split_qty: + param = param[:split_qty] + while len(param) < split_qty: + param.append(param[-1]) + new_param_list.append(param) + new_parameter_dict[key] = new_param_list + parameter_dict = new_parameter_dict + + return parameter_dict + + + security.declareProtected(Permissions.View, 'getActualAmortisationMethod') + def getActualAmortisationMethodForItem(self, item, **kw): + """ + Returns the actual amortisation method by getting the previous + movement method if the current one is NO_CHANGE_METHOD + """ + method = self.getAmortisationMethod() + if method not in (None, "", NO_CHANGE_METHOD): + return method + + stop_date = self.getStopDate() + if stop_date is None or item is None: + return None + previous_movement_list = item.getPastImmobilisationMovementValueList(at_date=stop_date, **kw) + if previous_movement_list is None: + return None + for i in range(len(previous_movement_list)-1, -1, -1): + movement = previous_movement_list[i] + if movement.getAmortisationMethod() not in (None, "", NO_CHANGE_METHOD): + return movement.getAmortisationMethod() + return None + + + security.declareProtected(Permissions.View, 'getNeededSpecificParameterListForItem()') + def getNeededSpecificParameterListForItem(self, item, **kw): + """ + Returns the list of specific parameters which are + needed for the amortisation calculation for the given item + """ + return self.getAmortisationMethodParameterForItem(item=item, + parameter_list="needed_specific_parameter_list", + split_char = '|', + split_qty = 3, + **kw)["needed_specific_parameter_list"] + + + security.declareProtected(Permissions.View, 'getUncontinuousNeededSpecificParameterListForItem()') + def getUncontinuousNeededSpecificParameterListForItem(self, item, **kw): + """ + Returns the list of specific parameters which are + needed for the amortisation calculation for the given item + when the amortisation is not continuing the previous period + """ + return self.getAmortisationMethodParameterForItem(item=item, + parameter_list="uncontinuous_needed_specific_parameter_list", + split_char = '|', + split_qty = 3, + **kw)["uncontinuous_needed_specific_parameter_list"] + + + security.declareProtected(Permissions.View, 'getFacultativeSpecificParameterListForItem()') + def getFacultativeSpecificParameterListForItem(self, item, **kw): + """ + Returns the list of specific parameters which are + facultative for the amortisation calculation for the given item + """ + return self.getAmortisationMethodParameterForItem(item=item, + parameter_list="facultative_specific_parameter_list", + split_char = '|', + split_qty = 3, + **kw)["facultative_specific_parameter_list"] + + + security.declareProtected(Permissions.View, 'isUsingAmortisationMethod') + def isUsingAmortisationMethod(self, method): + """ + Return true if this item is using the given method + """ + if self.getAmortisationMethod() == method: + return 1 + return 0 + + security.declareProtected(Permissions.View, 'getImmobilisationState') + def getImmobilisationState(self, id_only=1): + """ + Return root delivery immobilisation state + """ + return self.getRootDeliveryValue().getImmobilisationState()