def test_transition_next(self): _get = Mock() _get.side_effect = [ ContractStage(stage=self.stage1), ContractStage(stage=self.stage2) ] ContractStage.get_one = _get _fix = Mock(return_value=[]) ContractStage._fix_start_time = _fix self.active_contract.current_stage_id = self.stage1.id self.active_contract.current_stage = self.stage1 action = self.active_contract.transition(self.user) self.assertEquals(len(action), 2) self.assertTrue(_get.called) self.assertTrue(_fix.called_once) self.assertEquals(action[0].action_type, 'exited') self.assertEquals(action[0].action_detail['stage_name'], self.stage1.name) self.assertEquals(action[1].action_type, 'entered') self.assertEquals(action[1].action_detail['stage_name'], self.stage2.name) self.assertEquals(self.active_contract.current_stage_id, self.stage2.id)
def _transition_to_next(self, user): stages = self.flow.stage_order current_stage_idx = stages.index(self.current_stage.id) current_stage = ContractStage.get_one(self.id, self.flow.id, self.current_stage.id) next_stage = ContractStage.get_one( self.id, self.flow.id, self.flow.stage_order[current_stage_idx + 1] ) self.current_stage_id = next_stage.stage.id return [current_stage.log_exit(user), next_stage.log_enter(user)]
def test_transition_backward(self): _get = Mock(return_value=[ContractStage(stage=self.stage1), ContractStage(stage=self.stage2)]) ContractStage.get_multiple = _get self.active_contract.current_stage_id = self.stage2.id self.active_contract.current_stage = self.stage2 action = self.active_contract.transition(self.user, destination=self.stage1.id) self.assertEquals(_get.call_count, 1) self.assertEquals(len(action), 1) self.assertEquals(action[0].action_type, 'reversion') self.assertTrue(_get.called_once) self.assertEquals(self.active_contract.current_stage_id, self.stage1.id)
def _transition_to_first(self, user): contract_stage = ContractStage.get_one( self.id, self.flow.id, self.flow.stage_order[0] ) self.current_stage_id = self.flow.stage_order[0] return [contract_stage.log_enter(user)]
def current_contract_stage(self): """The contract's current stage Because the :py:class:`~purchasing.data.contract_stages.ContractStage` model has a three-part compound primary key, we pass the contract's ID, the contract's :py:class:`~purchasing.data.flows.Flow` id and its :py:class:`~purchasing.data.stages.Stage` id """ return ContractStage.get_one(self.id, self.flow.id, self.current_stage.id)
def test_transition_start(self): _get = Mock(return_value=ContractStage(stage=self.stage1)) ContractStage.get_one = _get self.assertTrue(self.active_contract.current_stage_id is None) action = self.active_contract.transition(self.user) self.assertEquals(_get.call_count, 1) self.assertEquals(len(action), 1) self.assertEquals(action[0].action_type, 'entered') self.assertEquals(self.active_contract.current_stage_id, self.stage1.id)
def current_contract_stage(self): '''The contract's current stage Because the :py:class:`~purchasing.data.contract_stages.ContractStage` model has a three-part compound primary key, we pass the contract's ID, the contract's :py:class:`~purchasing.data.flows.Flow` id and its :py:class:`~purchasing.data.stages.Stage` id ''' return ContractStage.get_one(self.id, self.flow.id, self.current_stage.id)
def test_transition_last(self, complete): _get = Mock(return_value=ContractStage(stage=self.stage1)) ContractStage.get_one = _get self.active_contract.parent = ContractBaseFactory.build(description='test') self.active_contract.current_stage_id = self.stage3.id self.active_contract.current_stage = self.stage3 action = self.active_contract.transition(self.user) self.assertEquals(_get.call_count, 1) self.assertEquals(len(action), 1) self.assertEquals(action[0].action_type, 'exited') self.assertTrue(complete.called_once)
def _transition_to_next(self, user, complete_time): stages = self.flow.stage_order current_stage_idx = stages.index(self.current_stage.id) current_stage = self.current_contract_stage next_stage = ContractStage.get_one( self.id, self.flow.id, self.flow.stage_order[current_stage_idx + 1]) self.current_stage_id = next_stage.stage.id return [ current_stage.log_exit(user, complete_time), next_stage.log_enter(user, complete_time) ]
def create_contract_stages(self, contract): '''Creates new rows in contract_stage table. Extracts the rows out of the given flow, and creates new rows in the contract_stage table for each of them. If the stages already exist, that means that the contract is switching back into a flow that it had already been in. To handle this, the "revert" flag is set to true, which should signal to a downstream process to roll the stages back to the first one in the current flow. Arguments: contract: A :py:class:`~purchasing.data.contracts.ContractBase` object Returns: A three-tuple of (the flow's stage order, a list of the flow's :py:class:`~purchasing.data.contract_stages.ContractStage` objects, whether the we are "reverting") ''' revert = False contract_stages = [] for stage_id in self.stage_order: try: contract_stages.append(ContractStage.create( contract_id=contract.id, flow_id=self.id, stage_id=stage_id, )) except (IntegrityError, FlushError): revert = True db.session.rollback() stage = ContractStage.query.filter( ContractStage.contract_id == contract.id, ContractStage.flow_id == self.id, ContractStage.stage_id == stage_id ).first() if stage: contract_stages.append(stage) else: raise IntegrityError except Exception: raise contract.flow_id = self.id db.session.commit() return self.stage_order, contract_stages, revert
def create_contract_stages(self, contract): '''Creates new rows in contract_stage table. Extracts the rows out of the given flow, and creates new rows in the contract_stage table for each of them. If the stages already exist, that means that the contract is switching back into a flow that it had already been in. To handle this, the "revert" flag is set to true, which should signal to a downstream process to roll the stages back to the first one in the current flow. Arguments: contract: A :py:class:`~purchasing.data.contracts.ContractBase` object Returns: A three-tuple of (the flow's stage order, a list of the flow's :py:class:`~purchasing.data.contract_stages.ContractStage` objects, whether the we are "reverting") ''' revert = False contract_stages = [] for stage_id in self.stage_order: try: contract_stages.append( ContractStage.create( contract_id=contract.id, flow_id=self.id, stage_id=stage_id, )) except (IntegrityError, FlushError): revert = True db.session.rollback() stage = ContractStage.query.filter( ContractStage.contract_id == contract.id, ContractStage.flow_id == self.id, ContractStage.stage_id == stage_id).first() if stage: contract_stages.append(stage) else: raise IntegrityError except Exception: raise contract.flow_id = self.id db.session.commit() return self.stage_order, contract_stages, revert
def _transition_backwards_to_destination(self, user, destination): destination_idx = self.flow.stage_order.index(destination) current_stage_idx = self.flow.stage_order.index(self.current_stage_id) if destination_idx > current_stage_idx: raise Exception('Skipping stages is not currently supported') stages = self.flow.stage_order[destination_idx:current_stage_idx + 1] to_revert = ContractStage.get_multiple(self.id, self.flow_id, stages) actions = [] for contract_stage_ix, contract_stage in enumerate(to_revert): if contract_stage_ix == 0: actions.append(contract_stage.log_reopen(user)) contract_stage.entered = datetime.datetime.now() contract_stage.exited = None self.current_stage_id = contract_stage.stage.id else: contract_stage.full_revert() return actions
def _transition_backwards_to_destination(self, user, destination, complete_time): destination_idx = self.flow.stage_order.index(destination) current_stage_idx = self.flow.stage_order.index(self.current_stage_id) if destination_idx > current_stage_idx: raise Exception('Skipping stages is not currently supported') stages = self.flow.stage_order[destination_idx:current_stage_idx + 1] to_revert = ContractStage.get_multiple(self.id, self.flow_id, stages) actions = [] for contract_stage_ix, contract_stage in enumerate(to_revert): if contract_stage_ix == 0: actions.append(contract_stage.log_reopen(user, complete_time)) contract_stage.entered = complete_time contract_stage.exited = None self.current_stage_id = contract_stage.stage.id else: contract_stage.full_revert() return actions
def create_contract_stages(flow_id, contract_id, contract=None): '''Creates new rows in contract_stage table. Extracts the rows out of the given flow, and creates new rows in the contract_stage table for each of them. ''' revert = False contract = contract if contract else ContractBase.query.get(contract_id) stages = Flow.query.get(flow_id).stage_order contract_stages = [] for stage_id in stages: try: contract_stages.append(ContractStage.create( contract_id=contract_id, flow_id=flow_id, stage_id=stage_id, )) except (IntegrityError, FlushError): revert = True db.session.rollback() stage = ContractStage.query.filter( ContractStage.contract_id == contract_id, ContractStage.flow_id == flow_id, ContractStage.stage_id == stage_id ).first() if stage: contract_stages.append(stage) else: raise IntegrityError except Exception: raise contract.flow_id = flow_id db.session.commit() return stages, contract_stages, revert
def current_contract_stage(self): return ContractStage.get_one(self.id, self.flow.id, self.current_stage.id)
def _transition_to_first(self, user, complete_time): contract_stage = ContractStage.get_one(self.id, self.flow.id, self.flow.stage_order[0]) self.current_stage_id = self.flow.stage_order[0] return [contract_stage.log_enter(user, complete_time)]
def _transition_to_last(self, user): current_stage = ContractStage.get_one(self.id, self.flow.id, self.current_stage.id) exit = current_stage.log_exit(user) self.parent.complete() return [exit]