20120616

Zum Thema “Workflows”. Darunter verstehen wir die Möglichkeit, dass der Systemverwalter per UI eine Liste von lokal konfigurierbaren “Statuswechsel-Aktionen” verwaltet. Eine Tabelle, die besagt: “Wer was wann klicken darf”.

Eine Workflow-Aktion (kurz Workflow) tut zunächst mal nichts anderes, als den Status eines Objekts zu wechseln. Wie das Objekt auf einen Statuswechsel reagiert (also was daraufhin eventuell noch alles tut), das ist anwendungsspezifisch und Programmierersache (d.h. dazu muss man Python-Code schreiben).

Der Benutzer sieht die Workflows eines Objekts als eine (virtuelle) Kolonne, deren Inhalt eine Serie von anklickbaren Buttons ist. In dieser Liste stehen natürlich nur die Workflows, die der ausführen darf. Sie ist dynamisch und hängt vom aktuellen Status des Objekts ab.

Workflows-Aktionen

Modell Bezeichnung Wer darf Status vorher Status nachher
cal.Task Erledigt Eigentümer todo done
cal.Task Zurück Dienstleiter done todo
cal.Event Einladungen schicken Eigentümer geplant scheduled
cal.Event Absagen Eigentümer geplant cancelled
cal.Event Stattgefunden Eigentümer geplant stattgefunden
cal.Event Abgesagt Eigentümer geplant cancelled
cal.Event Bericht verfassen Alle stattgefunden bericht
cal.Event Bericht verfassen Eigentümer stattgefunden done

“Wer darf” ist eigentlich eine Kombination von drei Feldern:

  • user_level : man muss mindestens diesen Benutzerlevel haben
  • user_groups : man muss mindestens einer dieser Gruppen angehören
  • owned_only : falls angekreuzt, gilt diese Aktion nur für “meine” Objekte (Datensätze)

Die Auswahlliste der möglichen Zustände (Statusse) ist ebenfalls anwendungsspezifisch, aber Programmierersache (d.h. dazu muss man Python-Code schreiben).

Entwurf Modell:

from lino.utils import ViewPermission

class Workflow(babel.BabelNamed,mixins.Sequenced):
    class Meta:
        sort_order = ['content_type','seqno']

    content_type = ForeignKey(ContentType)
    user_level = UserLevel.field()
    user_groups = CharField
    owned_only = BooleanField
    from_state = CharField
    to_state = CharField

    def get_permission(self,user):
        vp = ViewPermission(required_user_level=self.user_level,
          required_user_groups=self.user_groups.split())
        return vp.get_view_permission(user)



class Workflowable(models.Model):
    class Meta:
        abstract = True

    workflow_state_field = 'state' # subclasses usually override this

    @dd.displayfield
    def workflows(self,ar):
        ct = ContentType.objects.get_for_model(self.__class__)
        for wf in Workflow.objects.filter(content_type=ct):
            if wf.get_permission(ar.get_user())

“Status” or “State”?

The Introduction to Plone workflows speaks about “states” and never uses the word “status”. I am rather used to call it a “status”. Who’s right?

  • “a state is any condition which is durable or lasting (Zustand, Istzustand) whereas a status is a classification of state among several well-defined possibilities. An immigrant’s status is either legal or illegal, and if he is the latter, he may be in an anxious emotional state.” (konungursvia on wordreference.com
  • “State generally refers to the entire state of an entity - all its values and relationships at a particular point in time (usually, current). Status is more of a time-point, say, where something is at in a process or workflow - is it dirty (therefore requiring saving), is it complete, is it pending input, etc” (Luke Schafer on stackoverflow)

Conclusion for Lino. I suggest to adapt the following convention: use “state” at least when this field is being used as workflow selector. The default value for lino.models.Workflowable.workflow_state_field).

Changes in lino.modlib.cal

Replaced the models GuestStatus, TaskStatus and EventStatus by the choicelists GuestState, TaskState and EventState.