From a12f451d2363d4715057eec89a6c123f3d96e488 Mon Sep 17 00:00:00 2001 From: Guillaume Michon <guillaume@nexedi.com> Date: Wed, 1 Mar 2006 15:14:09 +0000 Subject: [PATCH] Moved immobilisation code to ImmobilisableItem.py git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@5892 20353a03-c40f-0410-a6d1-a30d3c3de9de --- product/ERP5/Document/Item.py | 877 +--------------------------------- 1 file changed, 2 insertions(+), 875 deletions(-) diff --git a/product/ERP5/Document/Item.py b/product/ERP5/Document/Item.py index 7530bb4529..57b7e94f56 100755 --- a/product/ERP5/Document/Item.py +++ b/product/ERP5/Document/Item.py @@ -42,7 +42,7 @@ from Products.ERP5Type.DateUtils import same_movement_interval, number_of_months from Products.ERP5.Document.Amount import Amount from Products.CMFCore.WorkflowCore import WorkflowMethod from Products.CMFCore.utils import getToolByName -from Products.ERP5.Document.Immobilisation import Immobilisation +from Products.ERP5.Document.ImmobilisableItem import ImmobilisableItem from zLOG import LOG @@ -50,7 +50,7 @@ from zLOG import LOG NEGLIGEABLE_PRICE = 10e-8 -class Item(XMLObject, Amount): +class Item(XMLObject, Amount, ImmobilisableItem): """ Items in ERP5 are intended to provide a way to track objects """ @@ -85,876 +85,3 @@ class Item(XMLObject, Amount): """ return XMLObject.generateNewId(self, id_group=id_group, default=default, method=method) - ### Amortisation - - # _update_data and _get_data are used to implement a semi-cache system on - # heavy calculation methods. - def _update_data(self, cached_data, date, id, value): - """ - Used to implement a semi-cache system on heavy calculation methods - """ - if getattr(cached_data, "cached_dict", None) is None: - cached_data.cached_dict = {} - if cached_data.cached_dict.get(date, None) is None: - cached_data.cached_dict[date] = {} - cached_data.cached_dict[date][id] = value - - - def _get_data(self, cached_data, date, id): - """ - Used to implement a semi-cache system on heavy calculation methods - """ - if cached_data: - cached_dict = getattr(cached_data,"cached_dict", None) - if cached_dict is not None: - cached_date = cached_dict.get(date, None) - if cached_date is not None: - cached_value = cached_date.get(id, None) - if cached_value is not None: - return cached_value - return None - - - security.declareProtected(Permissions.View, 'getImmobilisationMovementValueList') - def getImmobilisationMovementValueList(self, from_date=None, to_date=None, - sort_on="stop_date", filter_valid=1, - owner_change=1, single_from=0, single_to=0, - property_filter=['price', 'duration', 'durability'], - workflow_states = [], **kw): - """ - Returns a list of immobilisation movements applied to current item from date to date - Argument filter_valid allows to select only the valid immobilisation movements - Argument owner_change allows to create temporarily some immobilisation movements - when the owner of the item changes. - Arguments single_from and single_to (exclusive from each other) allow to dramatically - reduce the calculation time, but it returns only one movement : the nearest from - from_date or to_date. - Argument property_filter has the same goal. Its role is to reduce the number of calculated - properties when a temporary immobilisation movement is created - Argument workflow_states allows to filter by states of workflows. It is a list of tuples (wf_name,wf_variable,state) - """ - accessor = 'get' - if sort_on is not None: - word_list = sort_on.split('_') - for i in range(len(word_list)): - accessor += word_list[i].capitalize() - - def cmpfunc(a,b, accessor = accessor): - """ - Compares the two objects according to the accessor value. - """ - access_a = getattr(a, accessor, None) - access_b = getattr(b, accessor, None) - if access_a is None or access_b is None: - return 0 - return cmp(access_a(), access_b()) - - - # Build the immobilisation movement list - immobilisation_list = [] - for immobilisation in self.contentValues(filter = { 'portal_type':'Immobilisation' } ): - if filter_valid: - invalid = immobilisation.checkImmobilisationConsistency() - else: - invalid = 0 - if not invalid: - immo_date = immobilisation.getStopDate() - if ( to_date is None or immo_date - to_date <= 0 ) and \ - ( from_date is None or immo_date - from_date >= 0 ): - immobilisation_list.append(immobilisation) - - wf_tool = self.portal_workflow - for wf, wf_variable, state in workflow_states: - try: - temp_immo_list = [x for x in immobilisation_list if wf_tool.getStatusOf(wf, x)[wf_variable] == state] - immobilisation_list = temp_immo_list - except: - LOG('error on wf %s, wf_variable %s, state %s' % (wf, wf_variable, state), 0, '') - pass - - # Look for each change of ownership and an immobilisation movement within 1 hour - # If found, adapt the immobilisation date to be correctly interpreted - # If not found, and owner_change set to 1, create a context immobilisation movement - ownership_list = self.getSectionList(to_date) - if single_from or single_to: - immobilisation_list.sort(cmpfunc) - if single_from: - if len(immobilisation_list) > 0: immobilisation_list = immobilisation_list[:1] - if len(ownership_list) > 0: ownership_list = ownership_list[:1] - else: - if len(immobilisation_list) > 0: immobilisation_list = immobilisation_list[-1:] - if len(ownership_list) > 0: ownership_list = ownership_list[-1:] - - for ownership in ownership_list: - owner_date = ownership['date'] - found_immo = None - nearest_immo = None - i = 0 - # Find the nearest immobilisation movement from the propertyship change - # and an immobilisation movement within a tolerance interval - while i < len(immobilisation_list) and found_immo is None: - immobilisation = immobilisation_list[i] - current_immo_stop_date = immobilisation.getStopDate() - if (current_immo_stop_date is not None) and (current_immo_stop_date - owner_date < 0) \ - and (nearest_immo is None \ - or nearest_immo.getStopDate() - current_immo_stop_date < 0): - nearest_immo = immobilisation - if (current_immo_stop_date is not None) and abs(owner_date - current_immo_stop_date) < same_movement_interval: - found_immo = immobilisation - i += 1 - - if found_immo is None and owner_change and nearest_immo is not None: - # None immobilisation movement was found within the tolerance interval - # and argument owner_change is set. So we need to create a temporary - # immobilisation movement on the change date. - # This has to be done only if nearest_immo is defined, since the temporary - # movement gets most of its data on the previous movement, which is nearest_immo - added_immo = self._createTemporaryImmobilisationMovement(nearest_immo, - owner_date, - property_filter, - **kw) - immobilisation_list.append(added_immo) - found_immo = added_immo - - if found_immo is not None: - # It means an immobilisation movement is located within the tolerance interval - # Two cases : - # - An unimmobilising movement and ownership change are close : - # the unimmobilising movement has to be before the ownership change - # - An immobilising movement and ownership change are close : - # the immobilising movement has to be after the ownership change - found_date = found_immo.getStopDate() - if found_immo.getImmobilisation(): - if found_date - owner_date < 0: - found_immo.setStopDate(owner_date + centis) - else: - if found_date - owner_date > 0: - found_immo.setStopDate(owner_date - centis) - - if sort_on is not None: - immobilisation_list.sort(cmpfunc) - self._unconfuseImmobilisationMovementList(immobilisation_list) - return immobilisation_list - - - def _unconfuseImmobilisationMovementList(self, immobilisation_list): - """ - Check if some movements have the same stop_date. If it is the case, since - it is impossible to know which movement has to be before the other ones, - change arbitrarily the date of one of them, in order to at least - have always the same behavior - """ - immo_list = [x for x in immobilisation_list if x.getStopDate() is not None] - immo_list.sort(lambda x,y: cmp(x.getStopDate(), y.getStopDate())) - for i in range(len(immo_list)): - immobilisation = immo_list[i] - ref_date = immobilisation.getStopDate() - immobilisation_sublist = [immobilisation] - j = 1 - while i+j < len(immo_list) and immo_list[i+j].getStopDate() == ref_date: - immobilisation_sublist.append(immo_list[i+j]) - j += 1 - for j in range(len(immobilisation_sublist)): - immobilisation_sublist[j].setStopDate( ref_date + j * millis ) - - - def _createTemporaryImmobilisationMovement(self, base_movement, base_date, property_filter=[], **kw): - """ - Create a temporary immobilisation movement from base_movement - """ - added_immo = base_movement.asContext() - added_immo.setStopDate(base_date + millis) - if "durability" in property_filter: - added_immo.setDurability(added_immo.getDefaultDurability(**kw)) - kwd = {} - if added_immo.getImmobilisation(): - if 'price' in property_filter: - vat = base_movement.getVat() - previous_value = base_movement.getAmortisationOrDefaultAmortisationPrice(**kw) - current_value = added_immo.getDefaultAmortisationPrice(**kw) - kwd['amortisation_start_price'] = current_value - kwd['vat'] = vat * current_value / previous_value - added_immo._edit(**kwd) - kwd = {} - if 'duration' in property_filter: - kwd['amortisation_duration'] = added_immo.getDefaultAmortisationDuration(**kw) - kwd['input_account'] = added_immo.getOutputAccount() - added_immo._edit(**kwd) - return added_immo - - - security.declareProtected(Permissions.View, 'getUnfilteredImmobilisationMovementValueList') - def getUnfilteredImmobilisationMovementValueList(self, from_date=None, to_date=None, sort_on="stop_date", owner_change=0, **kw): - """ - Returns a list of immobilisation applied to the current item from date to date - All of the movements are returned, not even those which are valid - """ - return self.getImmobilisationMovementValueList(from_date=from_date, - to_date=to_date, - sort_on=sort_on, - owner_change=owner_change, - filter_valid=0, **kw) - - - security.declareProtected(Permissions.View, 'getPastImmobilisationMovementValueList') - def getPastImmobilisationMovementValueList(self, from_date=None, at_date=None, sort_on="stop_date", owner_change=1, **kw): - """ - Returns a list of immobilisation movements applied to current item before the given date, or now - """ - if at_date is None: at_date = DateTime() - result = self.getImmobilisationMovementValueList(from_date = from_date, - to_date = at_date, - sort_on = sort_on, - owner_change = owner_change, **kw ) - return result - - - security.declareProtected(Permissions.View, 'getFutureImmobilisationMovementValueList') - def getFutureImmobilisationMovementValueList(self, to_date=None, at_date=None, sort_on="stop_date", owner_change=1, **kw): - """ - Returns a list of immobilisation movements applied to current item after the given date, or now - """ - if at_date is None: at_date = DateTime() - result = self.getImmobilisationMovementValueList(from_date = at_date, - to_date = to_date, - sort_on = sort_on, - owner_change = owner_change, **kw) - return result - - - security.declareProtected(Permissions.View, 'getLastImmobilisationMovementValue') - def getLastImmobilisationMovementValue(self, at_date=None, owner_change=1, **kw): - """ - Returns the last immobilisation movement before the given date, or now - """ - past_list = self.getPastImmobilisationMovementValueList(at_date = at_date, - owner_change=owner_change, - single_to = 1, **kw) - - if len(past_list) > 0: - return past_list[-1] - return None - - - security.declareProtected(Permissions.View, 'getNextImmobilisationMovementValue') - def getNextImmobilisationMovementValue(self, at_date=None, owner_change=1, **kw): - """ - Returns the first immobilisation movement after the given date, or now - """ - future_list = self.getFutureImmobilisationMovementValueList(at_date = at_date, - owner_change = owner_change, - single_from = 1, **kw) - if len(future_list) > 0: - return future_list[0] - return None - - - security.declareProtected(Permissions.View, 'getLastMovementAmortisationDuration') - def getLastMovementAmortisationDuration(self, at_date=None, owner_change=1, **kw): - """ - Returns the remaining duration of amortisation for this item - as it was entered on the last immobilisation movement - """ - last_immobilisation_movement = self.getLastImmobilisationMovementValue(at_date = at_date, - owner_change=owner_change, - property_filter = ['duration'], - **kw) - if last_immobilisation_movement is not None: - return last_immobilisation_movement.getAmortisationOrDefaultAmortisationDuration(**kw) - else: - return None - - - security.declareProtected(Permissions.View, 'isCurrentlyImmobilised') - def isCurrentlyImmobilised(self, **kw): - """ Returns true if the item is immobilised at this time """ - return self.isImmobilised(at_date = DateTime(), **kw) - - - security.declareProtected(Permissions.View, 'isNotCurrentlyImmobilised') - def isNotCurrentlyImmobilised(self, **kw): - """ Returns true if the item is not immobilised at this time """ - return not self.isCurrentlyImmobilised(**kw) - - - security.declareProtected(Permissions.View, 'isImmobilised') - def isImmobilised(self, at_date=None, **kw): - """ - Returns true if the item is immobilised at the given date. - If at_date = None, returns true if the item has ever been immobilised. - """ - if at_date is not None: - is_immobilised = 0 - last_immobilisation_movement = self.getLastImmobilisationMovementValue(at_date = at_date, **kw) - if last_immobilisation_movement is not None: - is_immobilised = last_immobilisation_movement.getImmobilisation() - else: - past_immobilisation_movement_list = self.getPastImmobilisationMovementValueList(at_date = DateTime(), **kw) - for past_immobilisation in past_immobilisation_movement_list: - if past_immobilisation.getImmobilisation(): - return 1 - return is_immobilised - - - security.declareProtected(Permissions.View, 'getCurrentAmortisationDuration') - def getCurrentAmortisationDuration(self, **kw): - """ Returns the calculated remaining amortisation duration for this item at the current time. """ - return self.getRemainingAmortisationDuration(at_date = DateTime(), **kw) - - - security.declareProtected(Permissions.View, 'getCurrentRemainingAmortisationDuration') - def getCurrentRemainingAmortisationDuration(self, **kw): - """ Returns the calculated remaining amortisation duration for this item at the current time. """ - return self.getRemainingAmortisationDuration(at_date = DateTime(), **kw) - - - security.declareProtected(Permissions.View, 'getRemainingAmortisationDuration') - def getRemainingAmortisationDuration(self, at_date=None, from_immobilisation=0, **kw): - """ - Returns the calculated remaining amortisation duration for the item. - It is based on the latest immobilisation period at given date, or now. - - If from_immobilisation is set, we don't take the very last immobilisation movement - at the date. It is needed if the function is called by this particular movement, unless - the function will never end. - """ - if at_date is None: - at_date = DateTime() - - # Find the latest movement whose immobilisation is true - if from_immobilisation: - my_at_date = at_date - centis - else: - my_at_date = at_date - - cached_data = kw.get("cached_data", None) - cached_duration = self._get_data(cached_data, my_at_date, 'duration') - if cached_duration is not None: - return cached_duration - - last_immobilisation_movement = self.getLastImmobilisationMovementValue(at_date = my_at_date, - property_filter = ['duration'], - **kw) - previous_loop_movement = None - start_movement = None - stop_movement = None - current_search_date = None - while last_immobilisation_movement is not None and start_movement is None: - if last_immobilisation_movement.getImmobilisation(): - start_movement = last_immobilisation_movement - stop_movement = previous_loop_movement - if not start_movement: - previous_loop_movement = last_immobilisation_movement - last_date = last_immobilisation_movement.getStopDate() - centis - last_immobilisation_movement = self.getLastImmobilisationMovementValue(at_date = last_date, - property_filter = ['duration'], - **kw) - - if start_movement is None: - # Neither of past immobilisation movements did immobilise the item... - duration = self.getLastMovementAmortisationDuration(at_date=my_at_date, **kw) - if duration is not None: - if cached_data: self._update_data(cached_data, my_at_date, 'duration', int(duration)) - return int(duration) - return None - # We found the last immobilising movement - # Two cases are possible : - # - The item is still in an amortisation period (i.e. the immobilising movement is the latest) - # - The item is not in an amortisation period : in this case, we have to find the date of the unimmobilising movement - if stop_movement is None: - # Item is currently in an amortisation period - immo_period_stop_date = at_date - else: - immo_period_stop_date = stop_movement.getStopDate() - immo_period_start_date = start_movement.getStopDate() - immo_period_remaining = start_movement.getAmortisationOrDefaultAmortisationDuration(**kw) - immo_period_duration = getRoundedMonthBetween(immo_period_start_date, immo_period_stop_date) - returned_value = immo_period_remaining - immo_period_duration - if returned_value < 0: - returned_value = 0 - if cached_data: self._update_data(cached_data, my_at_date, 'duration', returned_value) - return int(returned_value) - - - security.declareProtected(Permissions.View, 'getRemainingDurability') - def getRemainingDurability(self, at_date=None, from_immobilisation=0, **kw): - """ - Returns the durability of the item at the given date, or now. - The durability is quantity of something which corresponds to the 'life' of the item - (ex : km for a car, or time for anything) - - Each Immobilisation Movement stores the durability at a given time, so it is possible - to approximate the durability between two Immobilisation Movements by using a simple - linear calculation. - """ - if at_date is None: - at_date = DateTime() - my_at_date = at_date - if from_immobilisation: - my_at_date -= centis - - cached_data = kw.get("cached_data", None) - cached_durability = self._get_data(cached_data, my_at_date, "durability") - if cached_durability is not None: - return cached_durability - - last_movement = self.getLastImmobilisationMovementValue(at_date = my_at_date, - property_filter = ['durability', 'duration'], - **kw) - if last_movement is not None: - if not last_movement.getImmobilisation(): - # The item is not currently amortised - # The current durability is the durability on - # last immobilisation movement - return_value = last_movement.getDurability() - if cached_data: self._update_data(cached_data, my_at_date, 'durability', return_value) - return return_value - start_durability = last_movement.getDurability() - start_date = last_movement.getStopDate() - - my_at_date = at_date - if from_immobilisation: - my_at_date += centis - - next_movement = self.getNextImmobilisationMovementValue(at_date = my_at_date + millis, - property_filter = ['durability'], - **kw) - if next_movement is not None: - stop_durability = next_movement.getDurability() - stop_date = last_movement.getStopDate() - else: - # In this case, we take the end of life of the item and use - # it like an immobilisation movement with values set to 0 - last_remaining_months = last_movement.getAmortisationOrDefaultAmortisationDuration(**kw) - stop_date = addToDate(start_date, month=last_remaining_months) - stop_durability = 0 - - consumpted_durability = start_durability - stop_durability - consumpted_time = getRoundedMonthBetween(start_date, stop_date) - current_consumpted_time = getRoundedMonthBetween(start_date, at_date) - if consumpted_time <= 0 or current_consumpted_time <= 0: - return_value = start_durability - else: - return_value = start_durability - consumpted_durability * current_consumpted_time / consumpted_time - else: - return_value = None - - if cached_data: self._update_data(cached_data, my_at_date, 'durability', return_value) - return return_value - - - security.declareProtected(Permissions.View, 'getCurrentRemainingDurability') - def getCurrentRemainingDurability(self, **kw): - """ - Returns the remaining durability at the current date - """ - return self.getRemainingDurability(at_date = DateTime(), **kw) - - - security.declareProtected(Permissions.View, 'getAmortisationPrice') - def getAmortisationPrice(self, at_date=None, from_immobilisation=0, with_currency=0, **kw): - """ - Returns the deprecated value of item at given date, or now. - - If from_immobilisation is set, we don't take the very last immobilisation movement - at the date. It is needed if the function is called by this particular movement, unless - the function will never end. - - If with_currency is set, returns a string containing the value and the corresponding currency. - """ - if at_date is None: - at_date = DateTime() - # Find the latest movement whose immobilisation is true - if from_immobilisation: - # We need to exclude the immobilisation movement which calls currently the method, - # unless the method will never end - my_at_date = at_date - centis - else: - my_at_date = at_date - - cached_data = kw.get("cached_data", None) - cached_price = self._get_data(cached_data, my_at_date, 'price') - if cached_price is not None: - return cached_price - - last_immobilisation_movement = self.getLastImmobilisationMovementValue(at_date = my_at_date, - **kw) - previous_loop_movement = None - start_movement = None - stop_movement = None - current_search_date = None - while last_immobilisation_movement is not None and start_movement is None: - if last_immobilisation_movement.getImmobilisation(): - start_movement = last_immobilisation_movement - stop_movement = previous_loop_movement - if not start_movement: - previous_loop_movement = last_immobilisation_movement - last_date = last_immobilisation_movement.getStopDate() - millis - last_immobilisation_movement = self.getLastImmobilisationMovementValue(at_date = last_date, - **kw) - - if start_movement is None: - # Neither of past immobilisation movements did immobilise the item... - LOG ('ERP5 Warning :',0,'Neither of past immobilisation movements did immobilise the item %s' % self.getTitle()) - last_immobilisation_movement = self.getLastImmobilisationMovementValue(at_date = my_at_date, - **kw) - if last_immobilisation_movement: - returned_price = last_immobilisation_movement.getAmortisationOrDefaultAmortisationPrice(**kw) - if with_currency: - return '%s %s' % (repr(round(returned_price,2)), immobilisation_movements[-1].getPriceCurrency()) - if cached_data: self._update_data(cached_data, my_at_date, 'price', returned_price) - return returned_price - return None # XXX How to find the buy value ? - - # Find the latest immobilisation period and gather information - currency = start_movement.getPriceCurrency() - start_date = start_movement.getStopDate() - if stop_movement is None: - # Item is currently in an amortisation period - stop_date = at_date - else: - # Item is not in an amortisation period - stop_date = stop_movement.getStopDate() - - - start_price = start_movement.getAmortisationOrDefaultAmortisationPrice(**kw) - disposal_price = start_movement.getDisposalPrice() - depreciable_price = start_price - disposal_price - start_remaining_months = start_movement.getAmortisationOrDefaultAmortisationDuration(**kw) - stop_remaining_months = 0 - start_durability = start_movement.getDurability(**kw) - stop_durability = 0 - section = start_movement.getSectionValue() - financial_date = section.getFinancialYearStopDate() - amortisation_method = "erp5_accounting_" + start_movement.getAmortisationMethod() - next_date = stop_date - - if stop_movement is not None: - stop_remaining_months = stop_movement.getDefaultAmortisationDuration(**kw) - stop_durability = stop_movement.getDurabilityOrDefaultDurability(**kw) - else: - next_movement = self.getNextImmobilisationMovementValue(at_date = my_at_date + millis, - property_filter = ['durability'], - **kw) - if next_movement is not None: - stop_durability = next_movement.getDurabilityOrDefaultDurability(**kw) - stop_remaining_months = next_movement.getDefaultAmortisationDuration(**kw) - next_date = next_movement.getStopDate() - else: - next_date = addToDate(start_date, month = start_remaining_months) - - # Get the amortisation method parameters - amortisation_parameters = start_movement.getAmortisationMethodParameter(parameter_list = [ - "cut_annuities", "price_calculation_basis", "prorata_precision", - "round_duration", "specific_parameter_list", "date_precision"]) - cut_annuities = amortisation_parameters["cut_annuities"] - price_calculation_basis = amortisation_parameters["price_calculation_basis"] - prorata_precision = amortisation_parameters["prorata_precision"] - round_duration = amortisation_parameters["round_duration"] - date_precision = amortisation_parameters["date_precision"] - specific_parameter_list = amortisation_parameters["specific_parameter_list"] - - # Adjust some values according to the parameters - start_date = getClosestDate(date=financial_date, target_date=start_date, - precision=date_precision, before=1, strict=0) - stop_date = getClosestDate(date=financial_date, target_date=stop_date, - precision=date_precision, before=0, strict=0) - - if prorata_precision == 'day': - local_stop_date = addToDate(start_date, month = start_remaining_months) - start_remaining_annuities = getBissextilCompliantYearFraction(from_date = start_date, - to_date = local_stop_date, - reference_date = financial_date) - local_stop_date = addToDate(next_date, month = stop_remaining_months) - stop_remaining_annuities = getBissextilCompliantYearFraction(from_date = next_date, - to_date = local_stop_date, - reference_date = financial_date) - else: - start_remaining_annuities = getYearFraction(months = start_remaining_months) - stop_remaining_annuities = getYearFraction(months = stop_remaining_months) - - - if round_duration == "greater annuity": - if start_remaining_annuities != int(start_remaining_annuities): - start_remaining_annuities = int(start_remaining_annuities) + 1 - else: - start_remaining_annuities = int(start_remaining_annuities) - elif round_duration == "lower annuity": - start_remaining_annuities = int(start_remaining_annuities) - - # Get specific parameters - specific_parameter_dict = {} - for specific_parameter in specific_parameter_list: - getter = getattr(start_movement, - 'get' + ''.join( [capitalize(x) for x in specific_parameter.split("_")] ), - None - ) - if getter is not None: - specific_parameter_dict[specific_parameter] = getter() - - def calculatePrice(at_date): - # First we calculate which is the current annuity - annuity_number = 0 - if cut_annuities: - current_date = getClosestDate(date = financial_date, - target_date = start_date, - precision = "year", - before = 0) - if getIntervalBetweenDates(current_date, start_date, keys={'day':1})['day'] == 0: - current_date = addToDate(current_date, year=+1) - else: - current_date = addToDate(start_date, year=1) - while current_date - at_date < 0: - annuity_number += 1 - current_date = addToDate(current_date, year=1) - annuity_start_date = addToDate(current_date, year=-1) - annuity_stop_date = current_date - current_annuity_stop_date = annuity_stop_date - current_annuity_start_date = annuity_start_date - if stop_date < annuity_stop_date: - current_annuity_stop_date = stop_date - if start_date > annuity_start_date: - current_annuity_start_date = start_date - - # Get the current ratio - current_ratio = self.restrictedTraverse(amortisation_method).ratioCalculation( - start_remaining_annuities = start_remaining_annuities - ,stop_remaining_annuities = stop_remaining_annuities - ,current_annuity = annuity_number - ,start_remaining_durability = start_durability - ,stop_remaining_durability = stop_durability - ,**specific_parameter_dict) - if current_ratio is None: - LOG("ERP5 Warning :",0,"Unable to calculate the ratio during the amortisation calculation on item %s at date %s" % ( - repr(self), repr(at_date))) - return None - - # Calculate the value at the beginning of the annuity - annuity_start_price = depreciable_price - if annuity_number: - annuity_start_price = calculatePrice(annuity_start_date) - if annuity_start_price is None: - return None - - # Calculate the raw annuity value - if price_calculation_basis == "start price": - raw_annuity_price = depreciable_price * current_ratio - elif price_calculation_basis == "annuity start price": - raw_annuity_price = annuity_start_price * current_ratio - - # Apply the prorata temporis on the raw annuity value - if start_date <= annuity_start_date and stop_date >= annuity_stop_date: - annuity_value = raw_annuity_price - else: - if prorata_precision == 'month': - month_value = raw_annuity_price / number_of_months_in_year - duration = getMonthAndDaysBetween(current_annuity_start_date, current_annuity_stop_date) - month_number = duration['month'] - day_number = duration['day'] - annuity_value = month_value * (month_number + getMonthFraction(current_annuity_stop_date, day_number)) - elif prorata_precision == 'day': - annuity_value = raw_annuity_price * getBissextilCompliantYearFraction(current_annuity_start_date, - current_annuity_stop_date, - reference_date=financial_date) - # Deduct the price at the given date - returned_price = annuity_start_price - annuity_value - if returned_price < 0: - returned_price = 0 - return returned_price - ### End of calculatePrice() - - calculated_price = calculatePrice(at_date) - if calculated_price is None: - return None - if calculated_price < NEGLIGEABLE_PRICE: - calculated_price = 0. - returned_price = calculated_price + disposal_price - - if cached_data: self._update_data(cached_data, my_at_date, 'price', returned_price) - if with_currency: - return '%0.2f %s' % (returned_price, currency) - return returned_price - - security.declareProtected(Permissions.View, 'getCurrentAmortisationPrice') - def getCurrentAmortisationPrice(self, with_currency=0, **kw): - """ Returns the deprecated value of item at current time """ - return self.getAmortisationPrice (at_date = DateTime(), with_currency=with_currency, **kw) - - security.declareProtected(Permissions.ModifyPortalContent, 'immobilise') - def immobilise(self, **kw): - """ Create the immobilisation movement to immobilise the item """ - return self._createImmobilisationMovement(immobilisation_state = 1, **kw) - - security.declareProtected(Permissions.ModifyPortalContent, 'unimmobilise') - def unimmobilise(self, **kw): - """ Create the immobilisation movement to unimmobilise the item """ - return self._createImmobilisationMovement(immobilisation_state = 0, **kw) - - security.declareProtected(Permissions.ModifyPortalContent, '_createImmobilisationMovement') - def _createImmobilisationMovement(self, immobilisation_state, **kw): - """ Build a new Immobilisation Movement into the current Item """ - new_id = str(self.generateNewId()) - self.newContent(portal_type = "Immobilisation", id=new_id) - immobilisation = self[new_id] - immobilisation.setStopDate(DateTime()) - immobilisation.setImmobilisation(immobilisation_state) - self.expandAmortisation() - return 1 - - security.declareProtected(Permissions.ModifyPortalContent, '_createAmortisationRule') - def _createAmortisationRule(self): - """ - Build or update the amortisation rule related to this item, then expand the rule - """ - applied_rule_list = self.getCausalityRelatedValueList(portal_type='Applied Rule') - my_applied_rule_list = [] - for applied_rule in applied_rule_list: - specialise_value = applied_rule.getSpecialiseValue() - if specialise_value is not None and specialise_value.getPortalType() == "Amortisation Rule": - my_applied_rule_list.append(applied_rule) - - if len(my_applied_rule_list) == 0: - # Create a new applied order rule (portal_rules.order_rule) - portal_rules = getToolByName(self, 'portal_rules') - portal_simulation = getToolByName(self, 'portal_simulation') - my_applied_rule = portal_rules.default_amortisation_rule.constructNewAppliedRule(portal_simulation) - # Set causality - my_applied_rule.setCausalityValue(self) - - elif len(my_applied_rule_list) == 1: - # Re expand the rule if possible - my_applied_rule = my_applied_rule_list[0] - else: - # Delete first rules and re expand if possible - for my_applied_rule in my_applied_rule_list[:-1]: - my_applied_rule.aq_parent._delObject(my_applied_rule.getId()) - my_applied_rule = my_applied_rule_list[-1] - - # We are now certain we have a single applied rule - # It is time to expand it - my_applied_rule.expand() - - def expandAmortisation(self): - """ - Calculate the amortisation annuities for the item - in an activity - """ - self.activate().immediateExpandAmortisation() - - def immediateExpandAmortisation(self): - """ - Calculate the amortisation annuities for the item - """ - self._createAmortisationRule() - - security.declareProtected(Permissions.View, 'getSectionChangeValueList') - def getSectionChangeValueList(self, at_date=None): - """ - Return the list of deliveries which change the item ownership - If at_date is None, return the result for all the time - XXX To add : a verification on delivery state ; does an item belong to - the destination section of a delivery if this delivery is on draft state ? - """ - def cmpfunc(a,b): - """ - Compares the objects on their stop_date - """ - date_a = a.getStopDate() - date_b = b.getStopDate() - if date_a is None and date_b is None: - return 0 - return cmp(date_a, date_b) - - raw_list = self.getAggregateRelatedValueList() - delivery_list = [] - for movement in raw_list: - if movement.getPortalType() in self.getPortalMovementTypeList(): - date = movement.getStopDate() - if date is None: - try: - date = movement.getParent().getStopDate() - except AttributeError: - pass - if date is not None and (at_date is None or date - at_date <= 0): - current_owner = movement.getDestinationSectionValue() - previous_owner = movement.getSourceSectionValue() - if current_owner is None: - try: - current_owner = movement.getParent().getDestinationSectionValue() - except AttributeError: - pass - if previous_owner is None: - try: - previous_owner = movement.getParent().getSourceSectionValue() - except AttributeError: - pass - if current_owner is not None and previous_owner != current_owner: - delivery_list.append(movement) - delivery_list.sort(cmpfunc) - return delivery_list - - - security.declareProtected(Permissions.View, 'getSectionList') - def getSectionList(self, at_date=None): - """ - Return the list of successive owners of the item with - the corresponding ownership change dates - If at_date is None, return the result all the time - """ - delivery_list = self.getSectionChangeValueList(at_date = at_date) - owner_list = [] - for delivery in delivery_list: - owner_list.append( { 'owner' : delivery.getDestinationSectionValue(), 'date' : delivery.getStopDate() } ) - return owner_list - - - security.declareProtected(Permissions.View, 'getSectionValue') - def getSectionValue(self, at_date=None): - """ - Return the owner of the item at the given date - If at_date is None, return the last owner without time limit - """ - owner_list = self.getSectionList(at_date = at_date) - if len(owner_list) > 0: - return owner_list[-1]['owner'] - return None - - - security.declareProtected(Permissions.View, 'getCurrentSectionValue') - def getCurrentSectionValue(self): - """ - Return the current owner of the item - """ - return self.getSectionValue( at_date = DateTime() ) - - - 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, 'isUsingEuLinearAmortisationMethod') - def isUsingEuLinearAmortisationMethod(self): - """ - Return true if this item is using this method - """ - return self.isUsingAmortisationMethod('eu/linear') - - security.declareProtected(Permissions.View, 'isUsingFrDegressiveAmortisationMethod') - def isUsingFrDegressiveAmortisationMethod(self): - """ - Return true if this item is using this method - """ - return self.isUsingAmortisationMethod('fr/degressive') - - security.declareProtected(Permissions.View, 'isUsingFrActualUseAmortisationMethod') - def isUsingFrActualUseAmortisationMethod(self): - """ - Return true if this item is using this method - """ - return self.isUsingAmortisationMethod('fr/actual_use') - -- 2.30.9