def expand(self, applied_rule, activate_kw=None,**kw): """ Expands the current movement downward. -> new status -> expanded An applied rule can be expanded only if its parent movement is expanded. """ parent_movement = applied_rule.getParentValue() # Calculate the previous supply link supply_chain = self.getSupplyChain(parent_movement.getParentValue()) parent_supply_link = self.getCurrentSupplyLink(parent_movement) previous_supply_link_list = supply_chain.\ getPreviousPackingListSupplyLinkList( parent_supply_link, movement=parent_movement) if len(previous_supply_link_list) == 0: raise TransformationSourcingRuleError,\ "Expand must not be called on %r" %\ applied_rule.getRelativeUrl() else: movement_dict = {} for previous_supply_link in previous_supply_link_list: # Calculate the source source_value = None source_node = previous_supply_link.getSourceValue() if source_node is not None: source_value = source_node.getDestinationValue() source_section_value = previous_supply_link.getSourceSectionValue() # Generate the dict stop_date = parent_movement.getStartDate() movement_dict.update({ "ts": { 'source_value': source_value, 'source_section_value': source_section_value, 'destination_value': parent_movement.getSourceValue(), 'destination_section_value': \ parent_movement.getSourceSectionValue(), 'resource_value': parent_movement.getResourceValue(), 'variation_category_list': parent_movement.\ getVariationCategoryList(), "variation_property_dict": \ parent_movement.getVariationPropertyDict(), 'quantity': parent_movement.getNetQuantity(), # getNetQuantity to support efficency from transformation 'price': parent_movement.getPrice(), 'quantity_unit': parent_movement.getQuantityUnit(), 'start_date': previous_supply_link.calculateStartDate(stop_date), 'stop_date': stop_date, # Save the value of the current supply link 'causality_value': previous_supply_link, } }) # Build the movement self._buildMovementList(applied_rule, movement_dict, activate_kw=activate_kw) # Create one submovement which sources the transformation Rule.expand(self, applied_rule, activate_kw=activate_kw, **kw)
def expand(self, applied_rule, **kw): """ Expands the current movement downward. -> new status -> expanded An applied rule can be expanded only if its parent movement is expanded. """ parent_movement = applied_rule.getParentValue() explanation = self.getExplanationValue(applied_rule=applied_rule) state = parent_movement.getCausalityValue().getPredecessorValue() path_list = state.getSuccessorRelatedValueList() if len(path_list) == 0: raise TransformationSourcingRuleError,\ "Not found deliverable business path" if len(path_list) > 1: raise TransformationSourcingRuleError,\ "Found 2 or more deliverable business path" path = path_list[0] source_section = path.getSourceSection(context=parent_movement) destination_section = path.getDestinationSection(context=parent_movement) source = path.getSource(context=parent_movement) destination = path.getDestination(context=parent_movement) start_date = path.getExpectedStartDate(explanation) stop_date = path.getExpectedStopDate(explanation) quantity = parent_movement.getNetQuantity() * path.getQuantity() price = parent_movement.getPrice() if price is not None: price *= path.getQuantity() factory = self.getFactory() factory.requestSourcing( causality_value=path, source=source, source_section=source_section, destination=destination, destination_section=destination_section, resource=parent_movement.getResource(), variation_category_list=parent_movement.getVariationCategoryList(), variation_property_dict=parent_movement.getVariationPropertyDict(), quantity=quantity, price=price, quantity_unit=parent_movement.getQuantityUnit(), start_date=start_date, stop_date=stop_date, ) factory.makeMovements(applied_rule) Rule.expand(self, applied_rule, **kw)
def expand(self, applied_rule, force=0, **kw): """ """ immutable_movement_list = [] root_simulation_movement = applied_rule.getRootSimulationMovement() order_movement = root_simulation_movement.getDefaultOrderValue() if order_movement is None: order_movement = root_simulation_movement.getDefaultDeliveryValue() order_movement_dict = {} for s_m in applied_rule.objectValues(): order_movement_dict.setdefault(s_m.getOrder() or s_m.getDelivery(), []).append(s_m) order_movement_total_price = order_movement.getTotalPrice() root_simulation_movement_total_price = \ root_simulation_movement.getTotalPrice() # XXX round if order_movement_total_price != 0 and \ root_simulation_movement_total_price != 0: ratio = root_simulation_movement_total_price / \ order_movement_total_price for tax_movement in order_movement\ .DeliveryMovement_getCorrespondingTaxLineList(): existing_simulation_movement_list = order_movement_dict.get( tax_movement.getRelativeUrl(), []) property_dict = dict() for prop in ('price', 'base_application_list', 'price_currency', 'payment_mode', 'base_contribution_list', 'resource'): property_dict[prop] = tax_movement.getProperty(prop) property_dict['quantity'] = tax_movement.getQuantity() * ratio if not existing_simulation_movement_list: applied_rule.newContent( portal_type=self.movement_type, order_value=tax_movement, order_ratio=1, delivery_ratio=1, **property_dict ) else: for existing_simulation_movement in \ existing_simulation_movement_list: if existing_simulation_movement.getDelivery() is None\ and not "split" in existing_simulation_movement.getId(): existing_simulation_movement.edit(**property_dict) # Pass to base class Rule.expand(self, applied_rule, force=force, **kw)
def expand(self, applied_rule, **kw): """ Expands the current movement downward. -> new status -> expanded An applied rule can be expanded only if its parent movement is expanded. """ parent_movement = applied_rule.getParentValue() # Get production node and production section production = parent_movement.getSource() production_section = parent_movement.getSourceSection() # Get the current supply link used to calculate consumed resource # The current supply link is calculated from the parent AppliedRule. supply_chain = self.getSupplyChain(parent_movement.getParentValue()) parent_supply_link = self.getCurrentSupplyLink(parent_movement) current_supply_link_list = supply_chain.\ getPreviousProductionSupplyLinkList(parent_supply_link) if len(current_supply_link_list) != 1: # We shall no pass here. # The test method returned a wrong value ! raise TransformationRuleError,\ "Expand must not be called on %r" %\ applied_rule.getRelativeUrl() else: current_supply_link = current_supply_link_list[0] # Generate produced movement movement_dict = self._expandProducedResource(applied_rule, production, production_section, current_supply_link) # Generate consumed movement consumed_mvt_dict = self._expandConsumedResource(applied_rule, production, production_section, current_supply_link) movement_dict.update(consumed_mvt_dict) # Finally, build movement self._buildMovementList(applied_rule, movement_dict, **kw) # Expand each movement created Rule.expand(self, applied_rule, **kw)
def expand(self, applied_rule, force=0, calculation_base_date=None, **kw): """ Expands the Order to a new simulation tree. expand is only allowed to modify a simulation movement if it doesn't have a delivery relation yet. If the movement is in ordered or planned state, has no delivered child, and is not in order, it can be deleted. Else, if the movement is in ordered or planned state, has no delivered child, and is in order, it can be modified. Else, it cannot be modified. """ order = applied_rule.getDefaultCausalityValue() if getattr(order, 'expandOpenOrderRule', None) is not None: # Delegate implementation of expand to the SubscriptionItem or # to the OpenOrder instance return order.expandOpenOrderRule(applied_rule, force=force, **kw) if order is not None: order_movement_list = order.getMovementList( portal_type=order.getPortalOrderMovementTypeList()) now = DateTime() passed_calculation_base_date = calculation_base_date for order_movement in order_movement_list: if passed_calculation_base_date is None: end_date = order_movement.getStopDate() - order.getForecastingTermDayCount() if end_date > now: calculation_base_date = now else: calculation_base_date = end_date else: calculation_base_date = passed_calculation_base_date last_simulation_movement = self._getLastSimulationMovementValue(applied_rule, order_movement) if last_simulation_movement is not None: schedule_start_date = last_simulation_movement.getStartDate() schedule_list = self._getOrderDateScheduleTupleList(order_movement, schedule_start_date, calculation_base_date=calculation_base_date, **kw) else: # Because order's start_date might be matched with the periodicity. order_start_date = order_movement.getStartDate() schedule_start_date = order_start_date - 1 schedule_list = [] for date_pair in self._getOrderDateScheduleTupleList(order_movement, schedule_start_date, calculation_base_date=calculation_base_date, **kw): if date_pair[0] >= order_start_date: schedule_list.append(date_pair) for start_date, stop_date in schedule_list: property_dict = {'start_date':start_date, 'stop_date':stop_date} property_dict = self._getExpandablePropertyDict(order_movement, property_dict) simulation_movement = applied_rule.newContent( portal_type=self.movement_type, order_value=order_movement, order_ratio=1, delivery_ratio=1, **property_dict ) # Pass to base class Rule.expand(self, applied_rule, force=force, **kw)
def expand(self, applied_rule, **kw): """ """ parent_movement = applied_rule.getParentValue() transformation = self.getTransformationValue(movement=parent_movement) business_process = self.getBusinessProcessValue(movement=parent_movement) explanation = self.getExplanationValue(movement=parent_movement) # get all trade_phase of the Business Process trade_phase_list = business_process.getTradePhaseList() # get head of production path from business process with trade_phase_list head_production_path_value_list = self.getHeadProductionPathValueList(transformation, business_process) # the factory which is to make simulation movements factory = self.getFactory() factory.product = dict( resource=transformation.getResource(), quantity=parent_movement.getNetQuantity(), quantity_unit=parent_movement.getQuantityUnit(), variation_category_list=parent_movement.getVariationCategoryList(), variation_property_dict=parent_movement.getVariationPropertyDict(),) # consumed amounts are sorted by phase, but not ordered. amount_dict = {} for amount in transformation.getAggregatedAmountList(): phase = amount.getTradePhase() if phase not in trade_phase_list: raise TransformationRuleError,\ "the trade phase %r is not part of Business Process %r" % (phase, business_process) amount_dict.setdefault(phase, []) amount_dict[phase].append(amount) transformation_phase_list = amount_dict.keys() last_phase_path_list = list() # to keep phase_path_list last_prop_dict = dict() for (phase, amount_list) in amount_dict.items(): phase_path_value_list = business_process.getPathValueList(phase) """ XXX: In this context, we assume quantity as ratio, but this "quantity as ratio" is consistent with transformation. """ if sum(map(lambda path: path.getQuantity(), phase_path_value_list)) != 1: raise TransformationRuleError,\ "the sum ratio at the Trade Phase %r on the Business Process %r is not 1"\ % (phase, business_process) for path in phase_path_value_list: path_common_dict = dict(causality_value=path, start_date=path.getExpectedStartDate(explanation), stop_date=path.getExpectedStopDate(explanation)) # the quantity which is produced/consumed at the path. quantity = factory.product['quantity'] * path.getQuantity() # nodes at the path source_section = path.getSourceSection(context=parent_movement) destination_section = path.getDestinationSection(context=parent_movement) source = path.getSource(context=parent_movement) destination = path.getDestination(context=parent_movement) # the remaining at the start and the end on the path predecessor_remaining_phase_list = path.getPredecessorValue()\ .getRemainingTradePhaseList(explanation, trade_phase_list=transformation_phase_list) successor_remaining_phase_list = path.getSuccessorValue()\ .getRemainingTradePhaseList(explanation, trade_phase_list=transformation_phase_list) consumed_common_dict = dict(source_section=source_section, destination_section=destination_section, source=source, **path_common_dict) produced_common_dict = dict(source_section=source_section, destination_section=destination_section, destination=destination, trade_phase_value_list=successor_remaining_phase_list, **path_common_dict) # when the path is not a part in the last phase on the transformation. if len(successor_remaining_phase_list) != 0: # partial produced movement factory.requestProduced( quantity=quantity, **produced_common_dict) else: last_phase_path_list.append(path) # used for matching work_dict = dict(filter(lambda x: x[0] != 'causality_value', produced_common_dict.items())) # when empty if not last_prop_dict: last_prop_dict.update(work_dict) # must be same, because the path(s) are integrated in the last phase on the transformation. if last_prop_dict != work_dict: raise TransformationRuleError,\ """the Properties which is used to make a movement on the last path are different with the Transformation %r and the Business Process %r"""\ % (transformation, business_process) # when the path is part of production, but not first, consume previous partial product if path not in head_production_path_value_list: factory.requestConsumed( quantity=quantity, trade_phase_value_list=predecessor_remaining_phase_list, **consumed_common_dict) # consumed movement for amount in amount_list: factory.requestConsumed( resource=amount.getResource(), quantity=quantity * amount.getQuantity() / amount.getEfficiency(), quantity_unit=amount.getQuantityUnit(), trade_phase=path.getTradePhase(), **consumed_common_dict) """ valid graph for transformation a --- b --- c a -- \ X b / c -- invalid graph a ------- b c ------- d -- b / a X \ -- c """ # when empty if last_phase_path_list is None or len(last_phase_path_list) == 0: raise TransformationRuleError,\ """could not make the product with the Transformation %r on the Business Process %r, because last_phase_path_list is empty.""" % (transformation, business_process) factory.requestProduced( causality_value_list=last_phase_path_list, # in the last phase of transformation, produced quantity must be planned as same as ordered. quantity=factory.product['quantity'], **last_prop_dict) # make actual simulation movements factory.makeMovements(applied_rule) Rule.expand(self, applied_rule, **kw)