def change_state(self, instance, method, *args, **kwargs): meta = method._django_fsm method_name = method.__name__ current_state = self.get_state(instance) if not meta.has_transition(current_state): raise TransitionNotAllowed( "Can't switch from state '{0}' using method '{1}'".format(current_state, method_name), object=instance, method=method, ) if not meta.conditions_met(instance, current_state): raise TransitionNotAllowed( "Transition conditions have not been met for method '{0}'".format(method_name), object=instance, method=method, ) next_state = meta.next_state(current_state) signal_kwargs = { 'sender': instance.__class__, 'instance': instance, 'name': method_name, 'field': meta.field, 'source': current_state, 'target': next_state, 'method_args': args, 'method_kwargs': kwargs, } pre_transition.send(**signal_kwargs) # Add states to func kwargs kwargs['fsm_current_state'] = current_state kwargs['fsm_next_state'] = next_state try: result = method(instance, *args, **kwargs) if next_state is not None: if hasattr(next_state, 'get_state'): next_state = next_state.get_state(instance, transition, result, args=args, kwargs=kwargs) signal_kwargs['target'] = next_state self.set_proxy(instance, next_state) self.set_state(instance, next_state) except Exception as exc: exception_state = meta.exception_state(current_state) if exception_state: self.set_proxy(instance, exception_state) self.set_state(instance, exception_state) signal_kwargs['target'] = exception_state signal_kwargs['exception'] = exc post_transition.send(**signal_kwargs) raise else: post_transition.send(**signal_kwargs) return result
def change_state(self, instance, method, *args, **kwargs): meta = method._django_fsm method_name = method.__name__ current_state = self.get_state(instance) try: current_state_name = list( filter(lambda x: x[0] == current_state, meta.field.choices))[0][1] except Exception: current_state_name = current_state if not meta.has_transition(current_state): raise TransitionNotAllowed( "Can't switch from state '{0}' using method '{1}'".format( current_state_name, method_name), object=instance, method=method, ) if not meta.conditions_met(instance, current_state): raise TransitionNotAllowed( "Transition conditions have not been met for method '{0}'". format(method_name), object=instance, method=method, ) next_state = meta.next_state(current_state) signal_kwargs = { 'sender': instance.__class__, 'instance': instance, 'name': method_name, 'source': current_state, 'target': next_state, } pre_transition.send(**signal_kwargs) try: result = method(instance, *args, **kwargs) if next_state is not None: self.set_proxy(instance, next_state) self.set_state(instance, next_state) except Exception as exc: exception_state = meta.exception_state(current_state) if exception_state: self.set_proxy(instance, exception_state) self.set_state(instance, exception_state) signal_kwargs['target'] = exception_state signal_kwargs['exception'] = exc post_transition.send(**signal_kwargs) raise else: post_transition.send(**signal_kwargs) return result
def reassign(self, new_user): """ Reasignment method. Encapsulates any business rules for sending signals or issuing new commands that may be associated with a new assignment. Args: new_user: the new assigned reviewer Returns: None """ if new_user == self.reviewer: return None if self.status != Resource.PENDING: raise TransitionNotAllowed("Cannot reassign a completed review") self._status_changed = True old_reviewer = self.reviewer self.reviewer = new_user tasks.send_review_assignment_email(self) ReviewLogEntry.objects.create( review=self, review_status=self.status, action="Reassigned from {0} to {1}".format(old_reviewer, new_user), )
def transition_to(self, new_status, save=True): # If the new_status is the same as then current then return early if self.status == new_status: return # Lookup the available next transition - from Django FSM available_transitions = self.get_available_status_transitions() logging.debug("{0} (pk={1}) state changing: '{2}' to '{3}'".format( self.__class__.__name__, self.pk, self.status, new_status)) # Check that the new_status is in the available transitions - # created with Django FSM decorator for transition in available_transitions: if transition.name == new_status: transition_method = transition.method # Call state transition method try: instance_method = getattr(self, transition_method.__name__) instance_method() except UnboundLocalError: raise TransitionNotAllowed( "Can't switch from state '{0}' to state '{1}' for {2}".format( self.status, new_status, self.__class__.__name__)) if save: self.save()
def _issue(self, issue_date=None, due_date=None): if issue_date: self.issue_date = datetime.strptime(issue_date, '%Y-%m-%d').date() elif not self.issue_date and not issue_date: self.issue_date = timezone.now().date() if not self.transaction_xe_rate: if not self.transaction_xe_date: self.transaction_xe_date = self.issue_date try: xe_rate = CurrencyConverter.convert(1, self.currency, self.transaction_currency, self.transaction_xe_date) except RateNotFound: raise TransitionNotAllowed('Couldn\'t automatically obtain an ' 'exchange rate.') self.transaction_xe_rate = xe_rate if due_date: self.due_date = datetime.strptime(due_date, '%Y-%m-%d').date() elif not self.due_date and not due_date: delta = timedelta(days=PAYMENT_DUE_DAYS) self.due_date = timezone.now().date() + delta if not self.sales_tax_name: self.sales_tax_name = self.customer.sales_tax_name if not self.sales_tax_percent: self.sales_tax_percent = self.customer.sales_tax_percent if not self.number: self.number = self._generate_number() self.archived_customer = self.customer.get_archivable_field_values()
def confirm(self, encrypted_keys=None): encrypted_keys = encrypted_keys or {} patients_ids = list( self.doctor.doctortopatient_set.values_list( 'patient_id', flat=True)) doctor_id = self.site.site_coordinator_id if set(patients_ids) != set(encrypted_keys.keys()): raise TransitionNotAllowed( "Not enough encrypted keys", object=self, method=self.confirm) DoctorToPatient.objects.bulk_create([ DoctorToPatient( doctor_id=doctor_id, patient_id=patient_id, encrypted_key=encrypted_key) for patient_id, encrypted_key in encrypted_keys.items() ]) self.doctor.my_coordinator_id = self.site.site_coordinator_id self.doctor.save() DoctorSharedPatientsEmail(context={ 'site_title': self.site.title, 'doctor': self.doctor }).send([Doctor.objects.get(id=self.site.site_coordinator_id).email])
def transition_wrapper(instance, *args, **kwargs): with transaction.atomic(): locked_instance = instance.__class__.objects\ .filter(id=instance.id)\ .select_for_update()\ .first() field_name = field if isinstance(field, str) else field.name field_value = getattr(instance, field_name) saved_field_value = getattr(locked_instance, field_name) strict_fields = [ strict_field if isinstance(strict_field, str) else strict_field.name for strict_field in getattr(instance, 'strict_fields', []) ] for strict_field in strict_fields: if getattr(locked_instance, strict_field) != getattr( instance, strict_field): raise TransitionNotAllowed( f"{instance.__class__}'s {strict_field} value has concurrently changed." ) if source != '*': if isinstance(source, (list, tuple, set)): if saved_field_value not in source: raise TransitionNotAllowed( f"Saved object's {field} is not a valid source for this transition." ) elif field_value != saved_field_value: raise TransitionNotAllowed( f"Object {field} is {field_value}, " f"while the saved field is {saved_field_value}.") # post transition signal receivers are also executed inside this atomic transaction result = original_wrapped_transition_method( instance, *args, **kwargs) setattr(instance, f'{field_name}_recently_transitioned_to', target) if save: instance.save() return result
def record_comment(self, author, message, comment_type, attachments): if comment_type == RESPONSE and author not in (self.requester, self.responsible.email): try: user = User.objects.get(email=author) except User.DoesNotExist: raise TransitionNotAllowed('{} is not allowed to respond.'.format(author)) if attachments: for payload in attachments: Attachment.objects.create(request=self, payload=payload) Update.objects.create(request=self, author=author, message=message, type=comment_type)
def unassign_unit(self, assignment, created_by): """ Remove a unit assignment from the referral. """ unit = assignment.unit if self.units.count() <= 1: raise TransitionNotAllowed() if self.assignees.filter(unitmembership__unit=unit): raise TransitionNotAllowed() assignment.delete() self.refresh_from_db() ReferralActivity.objects.create( actor=created_by, verb=ReferralActivityVerb.UNASSIGNED_UNIT, referral=self, item_content_object=unit, ) return self.state
def _change_state(instance, *args, **kwargs): meta = func._django_fsm if not meta.has_transition(instance): raise TransitionNotAllowed( "Can't switch from state '%s' using method '%s'" % (FSMMeta.current_state(instance), func.func_name)) result = func(instance, *args, **kwargs) # sth make the function smarter. for condition in conditions: if not condition(instance): return False meta.to_next_state(instance) if save: instance.save() return result
def pause(request, board_id): """ pause """ print('*** pause') board = util.get_board(board_id) try: board.pause_sm() except TransitionNotAllowed: print('\n\njx internal - ERROR: TransitionNotAllowed\n\n') raise TransitionNotAllowed( '\n\n\njx - Error caught - Pause - Transition not allowed.\n\n\n') else: print('SUCCESS') board.save() return HttpResponseRedirect(reverse('show', args=(board_id, )))