INHALTSVERZEICHNIS

Generelles

  • Für die Benutzung ist ein Planik-Benutzer zwingend nötig. Dieser muss lesenden Zugriff haben oder, für den Endpoint planungsverlauf, schreibenden Zugriff. D.h, im Fall 1 reicht die Rolle "Leser", sonst aber ist die Rolle "Planer" nötig
  • Die Zeiten werden gemäss ISO 8601 Standard in lokaler (schweizer) Zeit inklusive Offset zu UTC angegeben.
  • Maximal werden 1000 Records pro Anfrage geliefert. Ist Ihre Abfrage grösser (möglich bei der Abfragen der Dienste in einem grossen Team mit langer Zeitspanne), so verwenden Sie bitte DB-Paging. Hier ein Beispiel mit einer Pagesize von 10. Beispiel:
'https://api.planik.ch/api/v1/dienste?filter[team_id]=1152&filter[zwischen]=2018-08-01,2018-08-31&page[size]=10&page[number]=1'
# Die ersten 10 Dienste:
page[size]=10&page[number]=0
# Oder 
page[size]=10&page[number]=1
# die nächsten 10 Dienste
page[size]=10&page[number]=2
# Die folgenden 10 Dienste
page[size]=10&page[number]=3
  • Die Daten werden als JSON Files unformatiert übertragen.Für eine für den Menschen schöne Darstellung der JSON Dokumente benutzen Sie zum Beispiel http://jsonprettyprint.com

Verfügbare Endpoints

login (POST)

  • Jeder Planik-Benutzer welcher die entsprechenden Rechte hat (Lesender Zugriff auf Dienste und Mitarbeiter) kann grundsätzlich die API aufrufen.
  • Wir verwenden eine tokenbasierte Authentifikation.
  • Die Tokens sind maximal 24 Stunden gültig, danach müssen neue angefordert werden.

Abfrage mit curl:

 curl -i \
 -H 'Content-Type: application/json' \
 -d '{"benutzer": {"email": "test@planik.ch", "password": "xxx"}}' \
 https://api.planik.ch/api/v1/login

Details:

Login mit Email und Passwort in einem Json Objekt als POST-Request

{ "benutzer": {
    "email": "test@planik.ch", 
    "password": "xxx"
  }
}

Zurück kommen drei verschiedene Headers, welch man für die späteren Aufrufe verwenden muss:

  • access-token (Beispiel: f2FLH8Xpo1ZQnt5OOdCP4g)
  • client (pDumX4XC_34BS_2fN0_5jQ)
  • uid (Emailadresse)

Der Body der Antwort kann ignoriert werden. Er sieht zum Beispiel so aus:

{ "data": {
    "email": "alexander.schuppisser@optor.ch",
    "vorname":"<Vorname>",
    "nachname":"<Nachname>",
    "id":123,
    "uid":"alexander.schuppisser@optor.ch",
    "is_internal_super_user":true,
    "wuenscht_email_wenn_plan_berechnet":true,
    "provider":"email",
    "locale_id":1,
    "dashboard_favorit_organisation_id":null,
    "dashboard_favorit_team_id":null,
    "type":"benutzer"
  }
}

Klappt das Einloggen nicht, so wird folgende Meldung im Body der Antwort zurückgegeben:

{ "success": false,
  "errors": ["Ungültige Anmeldeinfomration. Bitte versuchen Sie es erneut."]
}

mitarbeiter (GET)

Abfrage mit curl:

# -i include the headers
# -g switches off the "URL globbing parser". Für [] in der URL
curl -i -g \
-H 'Accept: application/json' \
-H 'access-token:NOMgqk2sS-850Dk5qzUlZQ' \
-H 'uid:christian.muehlethaler@planik.ch' \
-H 'client:4lKfU3CpTBuiTcvr-7XbuQ' \
'https://api.planik.ch/api/v1/mitarbeiter?filter[team_id]=959&filter[angestellt_zwischen]=2018-08-01,2018-08-31'

Filter:

Default Filter:
  Keine. Es werden alle Mitarbeiter des Teams zurückgeliefert, auch solche die schon ausgetreten sind.

Zwingende Filter: 
  filter[team_id]
Optionale Filter:
  filter[angestellt_zwischen]
     Werte: Zwei Daten, kommasepariert.
     Interpretation: Alle Mitarbeiter welche zwischen diesen Daten irgendwann angestellt sind
  filter[id]
     Werte: Kommaseparierte Liste von Mitarbeiter-IDs
  filter[kuerzel]
     Werte: Kommaseparierte Liste von Mitarbeiterkuerzel
  filter[personalnummer]
     Werte: Kommaseparierte Liste von Mitarbeiterpersonalnummer
  filter[schlagwort]
     Werte: Kommaseparierte Liste von Mitarbeiterschlagworte

fields:

  fields[mitarbeiter]:
     Kommaseparierte Felder der Mitarbeiter welche interessieren
  fields[anstellung]:
  fields[arbeitsvertrag]:

include:
Die verknüpften Ressourcen, welche man gerne in der gleichen Abfrage erhalten möchte. Möglich sind: 'anstellungen' und 'anstellungen.arbeitsvertrag'

  filter[anstellungen][aktiv_zwischen]: 
     Werte: Zwei Daten, kommasepariert.
     Interpretation: Alle Dienste welche zwischen diesen Daten beginnen

arbeitsvertraege (GET)

Liefert alle Typen von Arbeitsverträgen.

Abfrage mit curl:

# -i include the headers
# -g switches off the "URL globbing parser". Für [] in der URL
curl -i -g \
-H 'Accept: application/json' \
-H 'access-token:NOMgqk2sS-850Dk5qzUlZQ' \
-H 'uid:christian.muehlethaler@planik.ch' \
-H 'client:4lKfU3CpTBuiTcvr-7XbuQ' \
'https://api.planik.ch/api/v1/arbeitsvertraege?filter[team_id]=959'

Filter:

Default Filter:
  Keine.
Zwingende Filter: 
  filter[team_id]
Optionale Filter:
  keine

fields:

  fields[arbeitsvertrag]:
     Kommaseparierte Felder der Mitarbeiter welche interessieren

include:

 keine

plaene (GET)

Liefert alle veröffentlichte Pläne eines Teams, aufsteigend sortiert. Es wird datum_von und datum_bis des Plans geliefert.

Abfrage mit curl:

# -i include the headers
# -g switches off the "URL globbing parser". Für [] in der URL
curl -i -g \
-H 'Accept: application/json' \
-H 'access-token:NOMgqk2sS-850Dk5qzUlZQ' \
-H 'uid:christian.muehlethaler@planik.ch' \
-H 'client:4lKfU3CpTBuiTcvr-7XbuQ' \
'https://api.planik.ch/api/v1/plaene?filter[team_id]=959&filter[zwischen]=2020-01-01,2020-08-31'

Filter:

Default Filter:
  Keine.
Zwingende Filter: 
  filter[team_id]
Optionale Filter:
  filter[zwischen]=2020-01-01,2020-08-31: Alle Pläne welche zwischen den beiden 
  Datenpunkte beginnen

fields:

  fields[plan]: datum_von, datum_bis

include:

 keine

dienstvorlagen (GET)

Liefert alle Dienstvorlagen eines Teams.

Abfrage mit curl

# -i include the headers
# -g switches off the "URL globbing parser". Für [] in der URL
curl -i -g \
-H 'Accept: application/json' \
-H 'access-token:NOMgqk2sS-850Dk5qzUlZQ' \
-H 'uid:christian.muehlethaler@planik.ch' \
-H 'client:4lKfU3CpTBuiTcvr-7XbuQ' \
'https://api.planik.ch/api/v1/dienstvorlagen?filter[team_id]=959'

Beispielsantwort:

{
  "data": [
    {
      "id": "64572",
      "type": "dienstvorlage",
      "attributes": {
        "kuerzel": "SPEZ",
        "schluessel_dienst_typ": "DIENST",
        "zeit_von": "2000-01-01T15:00:00+01:00",
        "zeit_bis": "2000-01-01T20:00:00+01:00",
        "legende": "Spezialdienst Plaza",
        "notiz": "",
        "pause_zeit_von": null,
        "pause_zeit_bis": null,
        "schlagworte": []
      }
    },
    ...

Filter:

Default Filter:
  filter[aktivitaetstyp] Kommaseparierte Liste der Werte 'aktiv' und 'inaktiv'.  
  Defaultwert ist 'aktiv'
Zwingende Filter: 
  filter[team_id]
Optionale Filter:
  filter[kuerzel] 
  filter[schluessel_dienst_typ] Kommaseparierte Liste von Schlüssel der Diensttypen DIENST, FERIEN, ABWESENHEIT 
  filter[schlagwort] Kommaseparierte Liste von Schlagworte

fields:

  fields[dienstvorlage]:

include:

 keine

dienste (GET)

Liefert alle veröffentlichten Dienste eines Teams innerhalb eines bestimmten Zeitfensters.

Abfrage mit curl:

# -i include the headers
# -g switches off the "URL globbing parser". Für [] in der URL
curl -i -g \
-H 'Accept: application/json' \
-H 'access-token:NOMgqk2sS-850Dk5qzUlZQ' \
-H 'uid:christian.muehlethaler@planik.ch' \
-H 'client:4lKfU3CpTBuiTcvr-7XbuQ' \
'https://api.planik.ch/api/v1/dienste?filter[team_id]=959&filter[zwischen]=2018-04-01,2018-04-30&include=mitarbeiter'

Beispielsantwort (ohne include):

{
  "data": [
    {
      "id": "40573157",
      "type": "dienst",
      "attributes": {
        "datum_zeit_von": "2022-04-01T00:00:00+02:00",
        "datum_zeit_bis": "2022-04-01T23:59:00+02:00",
        "pause_datum_zeit_von": "2022-04-01T12:00:00+02:00",
        "pause_datum_zeit_bis": "2022-04-01T12:30:00+02:00",
        "mitarbeiter_id": 60467,
        "kuerzel": "Fe",
        "schluessel_dienst_typ": "FERIEN",
        "arbeitszeit_sekunden": 0,
        "schlagworte": [],
        "notiz": null,
        "aenderung_id": "91904"
      },
      "relationships": {
        "mitarbeiter": {
          "meta": {
            "included": false
          }
        }
      }
    },
    ...
  ],
  "meta": {}
}

Filter:

Default Filter:
  filter[nur_zugewiesene][eq]=true
  filter[zwischen]: Dienste zwischen heute und 30 Tage in der Zukunft
Zwingende Filter: 
  filter[team_id] 
Optionale Filter:
  filter[zwischen]: 
     Werte: Zwei Daten, kommasepariert.
     Interpretation: Alle Dienste welche zwischen diesen Daten beginnen
  filter[schluessel_dienst_typ]: 
     Werte: Kommaseparierte Liste der Diensttypen DIENST, FERIEN, ABWESENHEIT.
     Interpretation: OR-Verknüpfung
  filter[schlagwort]: 
     Werte: Kommaseparierte Liste von Schlagworte auf den Dienstvorlagen.
     Interpretation: OR-Verknüpfung
  filter[mitarbeiter_kuerzel]: 
     Werte: Kommaseparierte Liste von Mitarbeiterkürzel
     Interpretation: Nur Dienste dieser Mitarbeiter
  filter[mitarbeiter_personalnummer]: 
     Werte: Kommaseparierte Liste von Personalnummern
     Interpretation: Nur Dienste dieser Mitarbeiter
  filter[mitarbeiter_schlagwort]: 
     Werte: Kommaseparierte Liste von Schlagworte auf den Mitarbeitern
     Interpretation: Nur Dienste dieser Mitarbeiter

fields:

  fields[dienst]:
     Kommaseparierte Felder der Dienstressource welche interessieren (inklusive der Notizen der Dienste als String)
  fields[mitarbeiter]:
     Kommaseparierte Felder der Mitarbeiter welche interessieren. (In dem Fall muss die Mitarbeiter-Ressource inkludiert werden)

include:

Möglich sind: 'mitarbeiter', 'mitarbeiter.anstellungen' und 'mitarbeiter.anstellungen.arbeitsvertrag'.

Beispiel:
include=mitarbeiter,mitarbeiter.anstellungen,mitarbeiter.anstellungen.arbeitsvertrag

Werden diese inkludiert, so kann man noch weitere Filter setzen. Bsp: Nur Anstellungen welche in der gewünschten Zeitperiode relevant sind:
  
   filter[mitarbeiter.anstellung][aktiv_zwischen]: 
     Werte: Zwei Daten, kommasepariert.
     Interpretation: Alle Dienste welche zwischen diesen Daten beginnen

Sortierung:

Default: Nach 'datum_zeit_von' aufsteigend
Spezifiziert, Beispiele:
  &sort=mitarbeiter_id,datum_zeit_von 
  &sort=-datum_zeit_von

Statistiken:

stats[total]=count: Die Anzahl Dienste in der Abfrage (Paging wird ignoriert)

api/v1/dienste?filter[team_id]=1152&filter[zwischen]=2018-08-01,2018-08-31&stats[total]=count

Die Anzahl wird im "statistic" Block der Antwort geliefert. (Nach allen Diensten). Antwortbeispiel:

 "meta": {
   "stats": {
     "total": {
       "count": 31
     }
   }
 }

Zusätzliche Information:

Beispiel von mehreren Abfragen im Life-cycle eines Plans

Für Jede Planänderung (Dienst erstellen, Dienst ändern (auch Dienst verschieben), Dienst löschen, Plan veröffentlichen) wird eine neue ÄnderungID generiert und der betroffenen Dienstversion zugeordnet. Hier schematisch ein Beispiel wie das in einem LifeCycle eines Plans aussieht.

# Curl-Abfrage eines Plans: Nur Kürzel und ÄnderungID der Dienste 
curl -i -g \
... \
'https://api.planik.ch/api/v1/dienste?filter[team_id]=673&filter[zwischen]=2018-10-01,2018-10-31&&fields[dienst]=kuerzel,aenderung_id'
#-> Im Planik GUI leerer Oktoberplan erstellt
#-> NeuerDienst F1 erstellt: 3943
#-> Plan veröffentlicht: ÄnderungID 3944
#-> Resultat der Abfrage: 
{"kuerzel":"F1","aenderung_id":3943} # Auch ein neuer Dienst hat seine ÄnderungID
#-> Neuer Dienst F2 erstellt: ÄnderungID 3945
#-> Plan veröffentlicht: ÄnderungID 3946
#-> Resultat der Abfrage: 
{"kuerzel":"F1","aenderung_id":3943},
{"kuerzel":"F2","aenderung_id":3945}
#-> Neuer Dienst in anderer Zeitperiode (aber auf gleichem Team) erstellt: ÄnderungID 3947
#-> Neuer Dienst F3 erstellt: ÄnderungID 3948
#-> Plan veröffentlicht: ÄnderungID 3949
#-> Resultat der Abfrage: 
{"kuerzel":"F1","aenderung_id":3943}
{"kuerzel":"F2","aenderung_id":3945}
{"kuerzel":"F3","aenderung_id":3948}
#-> Dienst F2 gelöscht: ÄnderungID 3949
#-> Dienst F1 geändert: ÄnderungID 3950
#-> Plan veröffentlicht: ÄnderungID 3951
#-> Resultat der Abfrage:
{"kuerzel":"F1","aenderung_id":3951} # Wurde geändert, darum neue ÄnderungID
{"kuerzel":"F3","aenderung_id":3948} # Wurde nicht geändert, darum ursprüngliche ÄnderungID

planungsverlauf/[team_id] (PATCH)

Dieser Endpoint ist ein schreibender Endpoint. Es wir der Planungsverlauf manipuliert. Dienste werden gelöscht und neue Dienste werden hinzugefügt.


Die Informationen über die einzelnen Aktionen werden im payload (JSON File) beschrieben. Aktuell gibt es 3 verschiedene Aktionen mit denen die Dienste gelöscht und hinzugefügt werden können.

  • Dienste löschen mit der Action "delete"
  • Dienste hinzufügen mit den Action "add" und "add_sequence"

Abfrage mit curl:

  • Die team_id wird in der URL mitgeliefert, im Beispiel 999
  • Ein oder mehere Actions werden als Attribute im JSON File geliefert
curl -i \
 --header "Content-Type: application/json" \
 -H 'access-token:5bb7p1t5PMIIr9c2KeoU6Q' \
 -H 'uid:christian.muehlethaler@planik.ch' \
 -H 'client:aF8uyWRcdGNkwAKZcGy_0A' \
 --request PATCH \
 --data '{
  "data": {
    "type": "planungsverlauf",
    "attributes": {
      "actions": [
        {
          "action": "add",
          "type": "dienst",
          "attributes": {
            "datum": "2019-01-06"
          },
          "relationships": {
            "dienstart": {
              "data": {
                "type": "dienstart",
                "filters": {
                  "kuerzel": {
                    "eq": "B" 
                  } 
                }
              }
            },
            "mitarbeiter": {
              "data": {
                "type": "mitarbeiter",
                "filters": {
                  "kuerzel": {
                    "eq": "SKO"
                  }  
                }
              }  
            }  
          }
        }
      ]
    }
  }
}' \
https://api.planik.ch/api/v1/planungsverlauf/999

Action-Elemente:

Es gibt drei verschiedene Aktionstypen:

  • delete: löscht alle spezifizierten Dienste
  • add: Erstellt den spezifizierten Dienst für den spezifzierten Mitarbeiter
  • add_sequence: erstellt die spezifizierten Dienste dem spezifizieren Mitarbeiter (es können auch mehrere Sein) in der spezifizierten Periodizität

Diese Actions werden nacheinander innerhalb der gleichen DB-Transaktion abgearbeitet. Schlägt also eine einzige Action fehl, so wird gar nichts auf die Datenbank geschrieben, auch nicht die vorhergegangenen erfolgreichen Aktionen.


Action 'delete'
ElementNameVerwendungWerteBeispiel
filterdatum_zeit_vonzwingendArray von zwei Daten"datum_zeit_von": { "between": ["2020-03-01", "2020-03-31"]}
filtermitarbeiter_idoptionalInteger oder "null" (Alle Dienste welche keinem Mitarbeiter zugewiesen sind)"mitarbeiter_id": { "eq": null}
filtermitarbeiter.kuerzeloptionalEinzelner oder Array von Mitarbeiterkürzel als Strings"mitarbeiter.kuerzel": { "eq": ["SI", "MU"]}
filtermitarbeiter.personalnummeroptionalEinzelner oder Array von Personalnummer als Strings"mitarbeiter.personalnummer": { "eq": ["2589", "33984"]}
filterdienstart.kuerzeloptional. Wenn nicht gesetzt: Alle Dienste unabhängig der DienstvorlageEinzelner oder  Array von Dienstvorlagenkürzel als Strings"dienstart.kuerzel": { "eq": ["Früh", "Mi"]}


Beispiel:

{
   "action": "delete",
   "type": "dienst",
   "filters": {
     "datum_zeit_von": {
       "between": [
         "2020-03-01",
         "2020-03-31"
       ]
     },
     "mitarbeiter.kuerzel": { "eq": "IZ"},
     "dienstart.kuerzel": { "eq": "HVZ"}
}

Action 'add':


Fügt einen einzelnen Dienst in den Planungsverlauf hinzu. Dieser Dienst kann von der Dienstvorlage abweichen, falls gewünscht. Entweder wird der Dienst direkt einem Mitarbeiter zugewiesen (relationship 'mitarbeiter') oder, falls diese fehlt, dem Planbedarf hinzugefügt.

ElementNameVerwendungWerteBeispiel
Attributdatumzwingend (optional wenn 'datum_zeit_von' und 'datum_zeit_bis' gesetzt)ISO String des Datums. Definiert das Startdatum des Dienstes"datum": "2020-03-06"
Attributdatum_zeit_vonoptional (zwingend wenn 'datum' nicht gesetzt)ISO String eines Zeitstempels. Überschreibt "zeit_von" der Dienstvorlage"datum_zeit_von": "2020-03-06 08:15:00 +0100"
Attributdatum_zeit_bisoptional (zwingend wenn 'datum' nicht gesetzt)ISO String eines Zeitstempels. Überschreibt "zeit_bis" der Dienstvorlage"datum_zeit_von": "2020-03-06 16:00:00 +0100"
relationshipdienstartzwingendJSON Element welche die Dienstvorlage für den gewünschten definiert
"dienstart": {
  "data": {
    "type": "dienstart",
    "filters": {
      "kuerzel": {
        "eq": "B"
      }
    }
  }
}
relationshipmitarbeiteroptional. Wenn nicht gesetzt, so wird der Dienst im Dienstbedarf erstellt.
"mitarbeiter": {
  "data": {
    "type": "mitarbeiter",
    "filters": {
      "kuerzel": {
        "eq": "ZI"
      }
    }
  }
}


Beispiel:

{
  "action": "add",
  "type": "dienst",
  "attributes": {
    "datum_zeit_von": "2020-03-06 08:15:00 +0100",
    "datum_zeit_bis": "2020-03-06 16:00:00 +0100"
  },
  "relationships": {
    "dienstart": {
      "data": {
        "type": "dienstart",
        "filters": {
          "kuerzel": {
            "eq": "B"
          }
        }
      }
    },
    "mitarbeiter": {
      "data": {
        "type": "mitarbeiter",
        "filters": {
          "kuerzel": {
            "eq": "ZI"
          }
        }
      }
    }
  }
}

Action 'add_sequence':


Mit dieser Action können ganze Sequenzen von Dienste hinzugefügt werden. Zum Beispiel ist es möglich, jedem Mittwoch im Sommerhalbjahr den Mitarbeitern X, Y und Z einen Dienst "A" hinzuzufügen.

Im Gegensatz zur 'add' Action ist es jedoch nicht mögich, den Diensten von der Dienstvorlage abweichende Attributwerte mitzugeben.

ElementNameVerwendungWerteBeispiel
AttributquantityzwingendInteger, zwischen 1 und 5
AttributperiodzwingendString, entweder "daily" oder "weekly""period": "weekly",
AttributstartzwingendISO String eines Datums"start": "2020-03-06"
AttributendzwingendISO String eines Datums"end": "2020-03-10"
relationshipdienstartzwingendJSON Element welche die Dienstvorlage für den gewünschten definiert
"dienstart": {
  "data": {
    "type": "dienstart",
    "filters": {
      "kuerzel": {
        "eq": "B"
      }
    }
  }
}
relationshipmitarbeiteroptional. Wenn nicht gesetzt, so werden die Dienste im Dienstbedarf erstellt. Sonst wird jedem Mitarbeiter, die der Filter liefert, die Dienste erstellt
"mitarbeiter": {
  "data": {
    "type": "mitarbeiter",
    "filters": {
      "kuerzel": {
        "eq": "ZI"
      }
    }
  }
}


Beispiel:

{
  "action": "add_sequence",
  "type": "dienst",
  "attributes": {
    "quantity": 1,
    "period": "daily",
    "start": "2019-01-01",
    "end": "2019-01-31"
  },
  "relationships": {
    "dienstart": {
      "data": {
        "type": "dienstart",
        "filters": {
          "kuerzel": {
            "eq": ["B", "SU"] 
          } 
        }
      }
    },
    "mitarbeiter": {
      "type": "mitarbeiter",
      "data": {
        "type": "mitarbeiter",
        "filters": {
          "kuerzel": {
            "eq": ["SKO"]
          }  
        }
      }
    }
  }
}