20121001

Defining Workflows

In einem Workflow können jetzt verschiedene Aktionen zu einem gleichen Zustand führen. Z.B. auf einer Begleitung im Status “Vorgeschlagen” führt ein Klick auf “[akzeptieren]” zum Status “Aktiv”, auf einer Begleitung im Status “Standby” führt ein Klick auf “[reaktivieren]” zum gleichen Status “Aktiv”.

Überhaupt ist die Beschreibung jetzt intuitiver. Der Lebenzyklus einer Begleitung sieht im Code jetzt so aus:

class CoachingStates(dd.Workflow):
    ...

add = CoachingStates.add_item
add('10', _("Suggested"),'suggested')
add('20', _("Refused"),'refused')
add('30', _("Active"),'active')
add('40', _("Standby"),'standby')
add('50', _("Ended"),'ended')

CoachingStates.refused.add_workflow(states='suggested standby',owner=True)
CoachingStates.active.add_workflow(_("Accept"),states='suggested',owner=True)
CoachingStates.active.add_workflow(_("Reactivate"),
    states='standby',owner=True,
    help_text=_("Client has become active again after having been standby."))
CoachingStates.standby.add_workflow(states='active',owner=True)
CoachingStates.ended.add_workflow(_("End coaching"),
    states='active standby',owner=True,
    help_text=_("User no longer coaches this client."))

Ein Bild sagt mehr als tausend Worte:

.. graphviz::
   :caption: Lifecycle of a coaching

   digraph foo {
      suggested -> refused [label="[ablehnen]"];
      standby -> refused;
      suggested -> active [label="[akzeptieren]"];
      standby -> active [label="[reaktivieren]"];
      active -> standby;
      standby -> ended [label="[beenden]"];
      active -> ended [label="[beenden]"];

      active [label="Aktiv"];
      suggested [label="Vorgeschlagen"];
      refused [label="Abgelehnt"];
      standby [label="Standby"];
      ended [label="Beendet"];
   }

TODO:

Der Willkommensgruß

Ich habe heute Morgen noch eine geniale Idee gehabt: Statt dass Caroline dem Hubert eine E-Mail schickt, wenn er einen Neuen zugewiesen bekommen hat, sieht Hubert das direkt in seinem Willkommensbildschirm. Das Welcome-Panel. Ein Willkommensgruß mit einer Übersicht dessen, was der Benutzer jetzt dringend mal anschauen müsste. Der Willkommensgruß ersett wahrscheinlich bald die beiden Panels “Ausblick” und “Rückblick”. Zeigt nicht nur Termine und Aufgaben, sondern auch z.B. die zu bestätigenden Einladungen und eben (das war der Auslöser) unsere neue Liste der “zu bestätigenden Begleitungsvorschlägen”.

Endspurt

Viele Kleinigkeiten sind noch zu regeln. Aber langsam kommt Land in Sicht…

Ich habe auch eine neue Regel ausgedacht: dass Klienten nur dann im Status “Begleitet” sein können, wenn sie eine gültige NISS haben. Also besagte Klienten werden bei der Datenübernahme (wenn sie nicht in TIM schon unter Inaktive standen) Es gibt auch einen neuen Status “Ungültig” : für Klienten ohne NISS, die bisher weder inaktiv noch neu waren. So was ist jetzt nicht mehr erlaubt.

Ein subtiler Bug war folgender: Wenn ich als root eingeloggt war und als Mélanie arbeitete, hatte ich in meinem Welcome-Panel

“You have 2 entries in Suggested coachings” Und wenn ich drauf klickte, hatte ich korrekterweise die MySuggestedCoachings von Mélanie, aber die workflow_buttons waren leer.

Erklärung: das Fenster wurde mit folgender url aufgerufen:

javascript:Lino.pcsw.MySuggestedCoachings.default_action.run({ "base_params": { "mt": 7, "mk": 5 } })

Also das su war verloren gegangen. Eigentlich musste die url sein:

javascript:Lino.pcsw.MySuggestedCoachings.default_action.run({ "base_params": { "su": 5 } })

Der Fehler war hier:

@dd.virtualfield(dd.HtmlBox(_('Welcome')))
def welcome(cls,self,ar):
    u = ar.get_user()
    story = []
    story.append(xghtml.E.p(_("Hi, "),u.first_name,'! '))
    ...
    for T in (MySuggestedCoachings,cal.MyTasksToDo):
        r = T.request(user=u) #          <<< (1) BAD
        r = T.request(subst_user=u) #    <<< (2) GOOD
        r = ar.spawn(T) #                <<< (3) BETTER
        if r.get_total_count() != 0:
            ...

Yes, it is recommended to use spawn here instead of building a new ActionRequest from scratch.

Baustellenbesichtigung

Folgende Änderungen sind Resultat einer Baustellenbesichtigung mit Gerd.

  • Die mit assign_coach erstellten Begleitungen haben eine leere Begleitungsart.

    –> Neues Feld einen FK zu CoachingType in User einfügen. Also jeder Benutzer kriegt seinen CoachingType zugewiesen.

  • Was mach ich mit den vorgeschlagenen Begleitungen, deren Benutzer gar nicht in Lino arbeiten? Erstens müssen die ebenfalls per Mail benachrichtigt werden und zweitens sollte deren Coaching direkt im Status “Aktiv” stehen.

    Antwort: neue Regel: wenn user.profile leer ist, wird Coaching.state sogleich auf active gesetzt. Außerdem kriegt der Begleiter jetzt auch immer eine Mail.

  • Irgendwie konfigurierbar machen, wer bei assign_coach (außer evtl. dem Agenten selber) eine Benachrichtigung per Mail geschickt kriegen soll. Konkret handelt es sich um Theresia und evtl. Isabelle. Nennen wir sie die Coaching-Supervisoren. Die müssen nichts anderes tun als dann in TIM das Attribut N ausschalten und PAR->IdUsr auffüllen.

    –> Ankreuzfeld “Coaching-Supervisor”

  • Es sollte zwei Versionen von assign_coach geben: die erste schickt ihre Mail im Hintergrund ohne vorherigen Dialog, die andere zeigt die generierte outbox.Mail vor dem Abschicken an.

    –> Eigentlich ist das auch ein Fall für die kommenden (aber noch nicht fertigen) action dialogs. Provisorischer Workaround: abhängig vom UserLevel: normale User kriegen die erstellte Mail nicht zu sehen.

TODO:

  • Klient 23363 ist seit 01.09.2012 begleitet, coach1 ist Elmar, coach2 ist Mélanie. Sollen beide Coachings am 01.09.2012 beginnen?

  • watch_tim ist noch nicht fertig. Krankenkasse und Apotheke. get_object()

  • Coachings sollte nur der Systemverwalter löschen können.

  • virtuelle Tabelle HistoryByClient : notes.Notes, outbox.Mails, cal.Events, postings.Postings

  • MySettings : Speichern funktioniert nicht:

    Http404
    users.MySettings has no url action u''
    
    TRACEBACK:
      File "l:\snapshots\django\django\core\handlers\base.py", line 111, in get_response
        response = callback(request, *callback_args, **callback_kwargs)
    
      File "l:\snapshots\django\django\views\generic\base.py", line 58, in view
        return self.dispatch(request, *args, **kwargs)
    
      File "l:\snapshots\django\django\views\generic\base.py", line 79, in dispatch
        return handler(request, *args, **kwargs)
    
      File "t:\hgwork\lino\lino\ui\extjs3\views.py", line 786, in put
        ar = action_request(app_label,actor,request,data)
    
      File "t:\hgwork\lino\lino\ui\extjs3\views.py", line 92, in action_request
        raise http.Http404("%s has no url action %r" % (rpt,action_name))