# -*- coding: utf-8 -*- ############################################################################## # # Copyright (c) 2002-2009 Nexedi SA and Contributors. All Rights Reserved. # Jean-Paul Smets-Solanes <jp@nexedi.com> # Ćukasz Nowak <luke@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 AccessControl import ClassSecurityInfo from Products.ERP5Type import Permissions, PropertySheet from Products.ERP5.Document.BPMRule import BPMRule from Products.ERP5.Document.PredicateMatrix import PredicateMatrix class BPMInvoiceTransactionRule(BPMRule, PredicateMatrix): """ DISCLAIMER: Refer to BPMRule docstring disclaimer. This is BPM enabled Invoice Transaction Rule. """ # CMF Type Definition meta_type = 'ERP5 BPM Invoice Transaction Rule' portal_type = 'BPM Invoice Transaction Rule' # Declarative security security = ClassSecurityInfo() security.declareObjectProtected(Permissions.AccessContentsInformation) def _getCurrencyRatioByArrow(self, arrow, prevision_line): from Products.ERP5Type.Document import newTempSimulationMovement try: prevision_currency = prevision_line['resource_list'][0] except IndexError: prevision_currency = None temporary_movement = newTempSimulationMovement(self.getPortalObject(), '1', **prevision_line) exchange_ratio = None try: section = prevision_line['%s_list' % arrow][0] except IndexError: section = None if section is not None: currency_url = self.restrictedTraverse(section).getProperty( 'price_currency', None) else: currency_url = None if currency_url is not None and prevision_currency != currency_url: precision = section.getPriceCurrencyValue() \ .getQuantityPrecision() exchange_ratio = currency.getPrice( context=temporary_movement.asContext( categories=['price_currency/%s' % currency_url, 'resource/%s' % prevision_currency], start_date=temporary_movement.getStartDate())) return exchange_ratio #### Helper method for expand def _generatePrevisionList(self, applied_rule, **kw): """ Generate a list of movements, that should be children of this rule, based on its context (parent movement, delivery, configuration ...) These previsions are actually returned as dictionaries. """ input_movement, business_path = self._getInputMovementAndPathTupleList( applied_rule)[0] prevision_list = [] # Find a matching cell cell = self._getMatchingCell(input_movement) if cell is not None : # else, we do nothing for accounting_rule_cell_line in cell.objectValues() : # get the resource (in that order): # * resource from the invoice (using deliveryValue) # * price_currency from the invoice # * price_currency from the parents simulation movement's # deliveryValue # * price_currency from the top level simulation movement's # orderValue resource = None invoice_line = input_movement.getDeliveryValue() if invoice_line is not None : invoice = invoice_line.getExplanationValue() resource = invoice.getProperty('resource', invoice.getProperty('price_currency', None)) if resource is None : # search the resource on parents simulation movement's deliveries simulation_movement = applied_rule.getParentValue() portal_simulation = self.getPortalObject().portal_simulation while resource is None and \ simulation_movement != portal_simulation : delivery = simulation_movement.getDeliveryValue() if delivery is not None: resource = delivery.getProperty('price_currency', None) if (resource is None) and \ (simulation_movement.getParentValue().getParentValue() \ == portal_simulation) : # we are on the first simulation movement, we'll try # to get the resource from it's order price currency. order = simulation_movement.getOrderValue() if order is not None: resource = order.getProperty('price_currency', None) simulation_movement = simulation_movement\ .getParentValue().getParentValue() if resource is None : # last resort : get the resource from the rule resource = accounting_rule_cell_line.getResource() \ or cell.getResource() prevision_line = {} prevision_line.update(**self._getExpandablePropertyDict(applied_rule, input_movement, business_path)) prevision_line.update( source_list = [accounting_rule_cell_line.getSource()], destination_list = [accounting_rule_cell_line.getDestination()], quantity = (input_movement.getCorrectedQuantity() * input_movement.getPrice(0.0)) * accounting_rule_cell_line.getQuantity(), resource_list = [resource], price = 1, ) if resource is not None: #set asset_price on movement when resource is different from price #currency of the source/destination section destination_exchange_ratio = self._getCurrencyRatioByArrow( 'destination_section', prevision_line) if destination_exchange_ratio is not None: prevision_line.update(destination_total_asset_price=round( (destination_exchange_ratio* applied_rule.getParentValue().getTotalPrice()),precision)) source_exchange_ratio = self._getCurrencyRatioByArrow( 'source_section', prevision_line) if source_exchange_ratio is not None: prevision_line.update(source_total_asset_price=round( (source_exchange_ratio* applied_rule.getParentValue().getTotalPrice()),precision)) if accounting_rule_cell_line.hasProperty( 'generate_prevision_script_id'): generate_prevision_script_id = \ accounting_rule_cell_line.getGeneratePrevisionScriptId() prevision_line.update(getattr(input_movement, generate_prevision_script_id)(prevision_line)) prevision_list.append(prevision_line) return prevision_list # Matrix related security.declareProtected( Permissions.ModifyPortalContent, 'newCellContent' ) def newCellContent(self, id, portal_type='Accounting Rule Cell', **kw): """ Creates a new Cell. """ self.invokeFactory(type_name=portal_type, id=id) new_cell = self.get(id) return new_cell # Deliverability / orderability def isOrderable(self, m): return 1 def isDeliverable(self, m): if m.getSimulationState() in self.getPortalDraftOrderStateList(): return 0 return 1