class Proceeding(BaseModel): class Meta: app_label = 'river' verbose_name = _("Proceeding") verbose_name_plural = _("Proceedings") objects = ProceedingManager() content_type = models.ForeignKey(app_config.CONTENT_TYPE_CLASS, verbose_name=_('Content Type'), on_delete=CASCADE) object_id = models.PositiveIntegerField(verbose_name=_('Related Object')) workflow_object = GenericForeignKey('content_type', 'object_id') meta = models.ForeignKey(ProceedingMeta, verbose_name=_('Meta'), related_name="proceedings", on_delete=CASCADE) transactioner = models.ForeignKey(app_config.USER_CLASS, verbose_name=_('Transactioner'), null=True, blank=True, on_delete=CASCADE) transaction_date = models.DateTimeField(null=True, blank=True) status = models.IntegerField(_('Status'), choices=PROCEEDING_STATUSES, default=PENDING) skip = models.BooleanField(_('Skip'), default=False) permissions = models.ManyToManyField(app_config.PERMISSION_CLASS, verbose_name=_('Permissions')) groups = models.ManyToManyField(app_config.GROUP_CLASS, verbose_name=_('Groups')) order = models.IntegerField(default=0, verbose_name=_('Order')) enabled = models.BooleanField(_('Enabled?'), default=True) previous = TreeOneToOneField("self", verbose_name=_('Previous Proceeding'), related_name="next_proceeding",null=True, blank=True, on_delete=CASCADE) cloned = models.BooleanField(_('Cloned?'), default=False)
class ApprovementTrack(BaseModel): class Meta: verbose_name = _("Approvement Track") verbose_name_plural = _("Approvement Tracks") approvement = models.ForeignKey(Approvement, verbose_name=_('Approvement'), related_name="tracks") process_date = models.DateTimeField(auto_now_add=True, null=True, blank=True) previous_track = TreeOneToOneField("self", verbose_name=_('Previous track'), related_name="next_track", null=True, blank=True)
class ProceedingTrack(BaseModel): class Meta: app_label = 'river' verbose_name = _("Proceeding Track") verbose_name_plural = _("Proceeding Tracks") proceeding = models.ForeignKey(Proceeding, verbose_name=_('Proceeding'), related_name="tracks") process_date = models.DateTimeField(auto_now_add=True, null=True, blank=True) previous_track = TreeOneToOneField("self", verbose_name=_('Previous track'), related_name="next_track", null=True, blank=True)
class TransitionApproval(BaseModel): class Meta: app_label = 'river' verbose_name = _("Transition Approval") verbose_name_plural = _("Transition Approvals") objects = TransitionApprovalManager() content_type = models.ForeignKey(app_config.CONTENT_TYPE_CLASS, verbose_name=_('Content Type'), on_delete=CASCADE) object_id = models.CharField(max_length=50, verbose_name=_('Related Object')) workflow_object = GenericForeignKey('content_type', 'object_id') meta = models.ForeignKey(TransitionApprovalMeta, verbose_name=_('Meta'), related_name="transition_approvals", null=True, blank=True, on_delete=SET_NULL) workflow = models.ForeignKey(Workflow, verbose_name=_("Workflow"), related_name='transition_approvals', on_delete=PROTECT) transition = models.ForeignKey(Transition, verbose_name=_("Transition"), related_name='transition_approvals', on_delete=PROTECT) transactioner = models.ForeignKey(app_config.USER_CLASS, verbose_name=_('Transactioner'), null=True, blank=True, on_delete=SET_NULL) transaction_date = models.DateTimeField(null=True, blank=True) status = models.CharField(_('Status'), choices=STATUSES, max_length=100, default=PENDING) permissions = models.ManyToManyField(app_config.PERMISSION_CLASS, verbose_name=_('Permissions')) groups = models.ManyToManyField(app_config.GROUP_CLASS, verbose_name=_('Groups')) priority = models.IntegerField(default=0, verbose_name=_('Priority')) previous = TreeOneToOneField("self", verbose_name=_('Previous Transition'), related_name="next_transition", null=True, blank=True, on_delete=CASCADE) @property def peers(self): return TransitionApproval.objects.filter( workflow_object=self.workflow_object, workflow=self.workflow, transition=self.transition, ).exclude(pk=self.pk)
class ReferencingModel(models.Model): fk = TreeForeignKey(Category, related_name='+', on_delete=models.CASCADE) one = TreeOneToOneField(Category, related_name='+', on_delete=models.CASCADE) m2m = TreeManyToManyField(Category, related_name='+')
class TransitionApproval(BaseModel): class Meta: app_label = 'river' verbose_name = _("Transition Approval") verbose_name_plural = _("Transition Approvals") objects = TransitionApprovalManager() content_type = models.ForeignKey(app_config.CONTENT_TYPE_CLASS, verbose_name=_('Content Type'), on_delete=CASCADE) field_name = models.CharField(_("Field Name"), max_length=200) object_id = models.CharField(max_length=50, verbose_name=_('Related Object')) workflow_object = GenericForeignKey('content_type', 'object_id') meta = models.ForeignKey(TransitionApprovalMeta, verbose_name=_('Meta'), related_name="proceedings", on_delete=CASCADE) source_state = models.ForeignKey( State, verbose_name=_("Source State"), related_name='transition_approvals_as_source', on_delete=CASCADE) destination_state = models.ForeignKey( State, verbose_name=_("Next State"), related_name='transition_approvals_as_destination', on_delete=CASCADE) transactioner = models.ForeignKey(app_config.USER_CLASS, verbose_name=_('Transactioner'), null=True, blank=True, on_delete=CASCADE) transaction_date = models.DateTimeField(null=True, blank=True) status = models.IntegerField(_('Status'), choices=PROCEEDING_STATUSES, default=PENDING) skip = models.BooleanField(_('Skip'), default=False) permissions = models.ManyToManyField(app_config.PERMISSION_CLASS, verbose_name=_('Permissions')) groups = models.ManyToManyField(app_config.GROUP_CLASS, verbose_name=_('Groups')) priority = models.IntegerField(default=0, verbose_name=_('Priority')) enabled = models.BooleanField(_('Enabled?'), default=True) previous = TreeOneToOneField("self", verbose_name=_('Previous Transition'), related_name="next_transition", null=True, blank=True, on_delete=CASCADE) cloned = models.BooleanField(_('Cloned?'), default=False)
class TransitionApproval(BaseModel): class Meta: app_label = 'river' verbose_name = _("Transition Approval") verbose_name_plural = _("Transition Approvals") objects = TransitionApprovalManager() content_type = models.ForeignKey(app_config.CONTENT_TYPE_CLASS, verbose_name=_('Content Type'), on_delete=CASCADE) object_id = models.CharField(max_length=50, verbose_name=_('Related Object')) workflow_object = GenericForeignKey('content_type', 'object_id') meta = models.ForeignKey(TransitionApprovalMeta, verbose_name=_('Meta'), related_name="transition_approvals", on_delete=CASCADE) workflow = models.ForeignKey(Workflow, verbose_name=_("Workflow"), related_name='transition_approvals', on_delete=CASCADE) source_state = models.ForeignKey( State, verbose_name=_("Source State"), related_name='transition_approvals_as_source', on_delete=CASCADE) destination_state = models.ForeignKey( State, verbose_name=_("Next State"), related_name='transition_approvals_as_destination', on_delete=CASCADE) transactioner = models.ForeignKey(app_config.USER_CLASS, verbose_name=_('Transactioner'), null=True, blank=True, on_delete=CASCADE) transaction_date = models.DateTimeField(null=True, blank=True) status = models.IntegerField(_('Status'), choices=STATUSES, default=PENDING) skipped = models.BooleanField(_('Skip'), default=False) permissions = models.ManyToManyField(app_config.PERMISSION_CLASS, verbose_name=_('Permissions')) groups = models.ManyToManyField(app_config.GROUP_CLASS, verbose_name=_('Groups')) priority = models.IntegerField(default=0, verbose_name=_('Priority')) enabled = models.BooleanField(_('Enabled?'), default=True) previous = TreeOneToOneField("self", verbose_name=_('Previous Transition'), related_name="next_transition", null=True, blank=True, on_delete=CASCADE) skipped_from = models.ManyToManyField("self", verbose_name=_("Skipped from"), related_name='created_after_skipped') @transaction.atomic def skip(self): if self.skipped: LOGGER.info("TransitionApproval with id %s is already skipped.") return self.skipped = True self.save() if self._can_skip_whole_step: self._link_to_downstream(self.source_state) for skipped_peer in self.peers.filter(skipped=True): self._link_to_downstream(skipped_peer.source_state) self.downstream.filter(skipped=False).update(skipped=True) @property def peers(self): return TransitionApproval.objects.filter( workflow_object=self.workflow_object, workflow=self.workflow, source_state=self.source_state, destination_state=self.destination_state).exclude(pk=self.pk) @property def downstream(self): return TransitionApproval.objects.filter( workflow_object=self.workflow_object, workflow=self.workflow, source_state=self.destination_state, ) @property def _can_skip_whole_step(self): return self.peers.filter(skipped=False).count() == 0 def _link_to_downstream(self, source_state): for downstream_approval in self.downstream.filter(skipped=False): transition_approval, created = TransitionApproval.objects.update_or_create( # pylint: disable=unused-variable workflow_object=self.workflow_object, workflow=self.workflow, source_state=source_state, destination_state=downstream_approval.destination_state, priority=self.priority, meta=self.meta, transactioner=downstream_approval.transactioner, status=PENDING) transition_approval.skipped_from.add(self) transition_approval.permissions.add( *downstream_approval.permissions.all()) transition_approval.groups.add(*downstream_approval.groups.all())