Event-Export

Um Events aus co*pilot exportieren zu können, wurde ein flexibler Event-Export geschaffen. Hiermit lassen sich sowohl Dokumente wie z.B. Production Sheets auf Basis einzelner Events wie auch Auswertungen über mehrere Events hinweg generieren. Exporte werden auf Basis von Export-Konfigurationen durchgeführt. In einer solchen Export-Konfiguration wird festgelegt, welche Daten eines Events in welchem Format ausgespielt werden.

Über den Unterpunkt „Exporte“ des Event-Menus können im Anschluss Events selektiert und exportiert werden. Zudem lassen sich einzelne Events auch über die Event-Detail-Seite exportieren.

Wir haben einige Beispiel-Exporte ausgearbeitet, die du als Grundlage für deine Anforderungen verwenden kannst. Komplexere Anpassungen oder komplett neuartige Exporte erfordern grundlegende Kenntnisse in Markdown/CSS und ggfs. JavaScript. Gerne können wir das für euch im Auftrag erledigen.

Export-Konfiguration

Beim Anlegen einer neuen Export-Konfiguration in den Einstellungen werden folgende Felder belegt:

(1) Name

Name der Konfiguration

(2) Format

  • HTML
  • CSV

HTML

HTML ist eine Seitenbeschreibungssprache um Inhalte zu formatieren. Dieses Format eignet sich sehr gut, um Detailseiten auszugeben.

Ein HTML-Export kann als Word oder PDF File ausgegeben werden.

CSV

CSV ist ein gängiges Format um Informationen tabellarisch darzustellen. Hierbei werden Spalten mittels Komma oder Semikolon separiert.

  • https://de.wikipedia.org/wiki/CSV_(Dateiformat)

(3) Default Seitenlayout

Das Seitenlayout ost für die Darstellung der Exporte nötig. Für Daten,, wie z.B. größere Tabellen, die nur angezeigt werden sollen, bietet sich das „freie“ Format an.

  • A4 Hochformat
  • A4 Querformat
  • frei

(4) Beispiel Template laden

Hinterlegte Vorlagen laden.

(5) Preprocessing Script (Fortgeschritten)

Hier können die Input-Daten via JavaScript transformiert werden. Der Rückgabewert dieses Scripts ersetzt die eigentlichen Input-Daten des Exports. Es ist nur der Funktions-Rumpf anzugeben, wobei die Input-Daten als ctx zur Verfügung stehen.

Hier ein Beispiel:

return { ...ctx, 
  // Folgende Zeile ersetzt 
  // die ursprünglichen Events 
  events: ctx.events.map(e => e.start), 
 foo: "bar" 
}

(6) Template

Die Vorlage wird in der Templating Language Handlebars verfasst. Auf Basis dieser Vorlage und den Input-Daten wird die Ausgabe generiert. Daten werden mittels Platzhalter (= „Handlebars Expressions“) übergeben, die in „{{ }}“ eingeschlossen sind.

(7) Vertraulich

Wird ein Export als „vertraulich“ deklariert, werden zudem vertrauliche Daten (wie z.B. vertrauliche Benutzerfelder, Deals und Angebote) im Export verfügbar.

Vertrauliche Exporte können nur von Benutzer:innen mit der Berechtigung „ACCESS_CONFIDENTIAL“ oder „ADMIN“ erzeugt werden.

(8) Perspektive

Perspektive auswählen um Events für die Vorschau zu laden.

(9) Event suchen

Bestimmten Event anhand des Namens suchen, um diesen für die Vorschau zu laden.

(10) Vorschau

Vorschau der Ausgabe

(11) Code

Erzeugten Code anzeigen

(12) Input-Daten

Geladene Beispiel-Daten anzeigen

Beispiel-Exporte

https://support.ov2b.de/docs-category/exporte/

Input-Daten

Aktuell steht die Liste an Events in der Vorlage zur Verfügung. Das können die selektierten Events auf der Export-Seite sein, alle Events, die eine Perspektive zurückliefert oder auch nur ein einzelnes Event, wenn ein Export von einer Event-Detail-Seite aus gestartet wird.

{
  baseData: BaseDataPayload,
  events: EventExportPayload[]
}

BaseData (Stammdaten)

BaseDataPayload {
  name: string
  additionalName: string
  department: string
  memo: string
  addresses: EventExportPayloadAdress[]
  links: EventExportPayloadLink[]
  email: string
  phone: string
  web: string
  images: ExportPayloadImage[]
}

Event

EventExportPayload {
  copilotUrl: string
  id: string
  slug: string
  status: string
  optionEnd?: Date
  kind: string
  start: Date
  name: string
  subTitle?: string
  eventType: string
  memo?: string
  createdAt: Date
  updatedAt: Date
  displayNames: {
    title: string
    eventTitleWithArtists: string
    eventTitleWithArtistsAndShows: string
    artists: string
    artistsAndShows: string
    rooms: string
    locationsWithRooms: string
    locationsWithCityAndRooms: string
    locationsWithAddressAndRooms: string
  }
  activePromotions: { name: string }[]
  images?: ExportPayloadImage[]
  files?: ExportPayloadFile[]
  links?: EventExportPayloadLink[]
  locations?: {
    name: string
    address: EventExportPayloadAdress
    operator?: {
      displayName: string
      email: string
      phone: string
    }
    contacts?: {
      role: string
      displayName: string
      firstName?: string
      lastName?: string
      email: string
      phone: string
    }[]
    images: ExportPayloadImage[]
    files: ExportPayloadFile[]
    rooms?: {
      name: string
      images?: ExportPayloadImage[]
      files?: ExportPayloadFile[]
    }[]
  }[]
  artists?: {
    name: string
    description: string
    deals?: {
      name: string
      description: string
      guarantee: number
      artistPercentage: number
      breakEvenSales: number
    }[]
    show?: {
      slug: string
      name: string
      releasesAt?: Date
      memo?: string
      images?: ExportPayloadImage[]
      files?: ExportPayloadFile[]
      artistShowInformations?: PublicCustomField[]
    }
    contacts?: {
      role: string
      displayName: string
      firstName?: string
      lastName?: string
      address: EventExportPayloadAdress
      email: string
      phone: string
      contactInformations?: PublicCustomField[]
      bankAccounts?: EventExportPayloadBankAccount[]
    }[]
    images: ExportPayloadImage[]
    files: ExportPayloadFile[]
    links?: EventExportPayloadLink[]
    artistInformations?: PublicCustomField[]
  }[]
  contacts?: {
    role: string
    displayName: string
    firstName?: string
    lastName?: string
    address: EventExportPayloadAdress
    email: string
    phone: string
    contactInformations?: PublicCustomField[]
    images?: ExportPayloadImage[]
    files?: ExportPayloadFile[]
  }[]
  schedule?: {
    name: string
    date: Date
  }[]
  eventInformations?: PublicCustomField[]
  offersOnEvent?: {
    offerStatus: string
    name: string
    description: string
    discount: number
    netTotal: number
    grossTotal: number
    netTotalByVat: Record<number, number>
    roomsOnOffer?: {
      room: string
      description: string
      price: number
      discount: number
      vat: number
      netTotal: number
      grossTotal: number
      commodityGroup?:{
        name: string
        vatBusiness: number
        vatPrivate: number
      }
    }[]
    resourcesOnOffer?: {
      resource: string
      description: string
      amount: number
      unit: string
      price: number
      discount: number
      vat: number
      netTotal: number
      grossTotal: number
      categories?: string[]
      commodityGroup?:{
        name: string
        vatBusiness: number
        vatPrivate: number
      }
  }[]
  ticketing?: {
    ticketOffice: string
    category: string
    contingent: number
    vat: number
    netPrice: number
    grossPrice: number
    timestamp: Date
    soldTickets: number
    saleTotal: number
  }[]
  shopEvent?: {
    start: Date
    name: string
    subTitle?: string
    description?: string
    location?: string
    image?: ExportPayloadImage
    url?: string
  }
}

export type EventExportPayloadBankAccount = {
  bankAccountType: string
  institute: string | null
  username: string | null
  owner: string | null
  iban: string | null
  bic: string | null
}

export type EventExportPayloadAdress = {
  street: string
  addStreet: string
  zip: string
  city: string
  country: string
  lat: string
  lng: string
}

export type EventExportPayloadLink = {
  type: string
  value: string
}

Helper-Funktionen

Standard

Folgend ein Auszug der zur Verfügung stehenden Standar-Helper. Siehe https://handlebarsjs.com/guide/builtin-helpers.html für weitere und Details.

each

Die each Funktion iteriert (Schleife) über ein angegebenes Array. Sie beginnt immer mit {{#each}} und endet mit {{/each}}

Sie verlangt das Array als Parameter.

Beispiel

Eine Schleife über alle events. Die Daten eines Events müssen dann mit this.* angesprochen werden

{{#each events}}
<h1>{{{this.name}}}</h1>
<p>Datum: {{formatDate this.start "d.m.Y"}}</p>
{{/each }}

if

Die if Funktion überprüft, ob ein Element vorhanden ist. Sie beginnt immer mit {{#if}} und endet mit {{/if}}

Sie verlangt das zu prüfende Element als Parameter.

Beispiel

Alle Event Informationen ausgeben, sofern ein Wert gesetzt ist:

{{#each this.eventInformations}}

{{#if this.value}}
<p>{{ this.name }}</p>
{{ this.value }}
{{/if}}

{{/each}}

lookup

Funktion, um Elemente aus einem Objekt zu extrahieren.
Die Funktion verlangt 2 Parameter:

  • Ein Objekt, z.B. einen Kontakt
  • den Namen des Elements
Beispiel
{{ lookup (contactByRole this.contacts "Mieter") "displayName" }}  

Custom

formatDate

Funktion um Datum und Uhrzeit spezifisch auszugeben.
Die Funktion verlangt 2 Parameter:

  • das Datum (Date ISO)
  • das Datumsformat (Die Optionen sind hier gelistet)
Beispiel
{{ formatDate this.start "d.m.Y" }}
  => Ausgabe: deutsches Datum, z.B. 03.08.2022

{{ formatDate this.start "D d.m.Y" }}
  => Ausgabe: deutsches Datum mit Wochentag,
     z.B. Mi. 03.08.2022

{{ formatDate this.start "H:i" }}
  => Ausgabe: Uhrzeit, z.B. 20:00

{{ formatDate this.start "d.m.Y H:i" }}
  => Ausgabe: Datum mit Uhrzeit, z.B. 20.11.2021 20:00

contactByRole

Funktion, um einen Kontakt aus einem Array anhand seiner Rolle zu extrahieren.
Die Funktion verlangt 2 Parameter:

  • Ein Array mit Kontakten
  • Den Namen der Rolle
Beispiel
{{#each (contactByRole this.contacts "Veranstalter:in")}}
  {{@key}}: {{this}}
{{/each}}
  => Ausgabe
    role: Veranstalter:in
    displayName: ABC Firma
    email: info@abc.de
    phone: +030 8877665

{{ lookup (contactByRole this.contacts "Veranstalter:in") "displayName" }}  
  => Ausgabe: ABC Firma

scheduleValueByName

Funktion, um einen Schedule-Eintrag anhand des Namens zu extrahieren.
Die Funktion hat 3 Parameter:

  • Den Schedule
  • Den Namen des Schedule-Eintrags
  • Datum einblenden (optional): default true, auf false setzen um nur Uhrzeit anzuzeigen
Beispiel
{{ scheduleValueByName this.schedule "Curfew" }}
  => Ausgabe
  20.09.2023 22:00
{{ scheduleValueByName this.schedule "Curfew" false }}
  => Ausgabe
  22:00

linkByType

Funktion, um einen Eintrag der Links anhand des Typs zu extrahieren.
Die Funktion verlangt 2 Parameter:

  • Die Links
  • Den Typ des Eintrags (z.B. Web, Facebook)
{{ linkByType @root.baseData.links "Web" }}

eventInformationByName

Funktion, um einen Eintrag der Event Informationen anhand des Namens zu extrahieren.
Die Funktion verlangt 2 Parameter:

  • Die Event Informationen
  • Den Namen des Eintrags
{{ eventInformationByName this.eventInformations "Hotel" }}

md2html

Konvertiert Markdown to HTML

{{md2html memo}}

csvQuote

Tauchen in CSV Exporten Spalten mit Anführungszeichen auf, müssen diese Spalten mit dem Helper `csvQuote` escaped werden: z.B.

{{ start }};{{ csvQuote name }}

currentDate

Aktuellles Datum

Die Funktion verlangt 1 Parameter:

{{ currentDate "P" }}

Beispiele

Einfaches Markdown Beispiel

{{#each events}}

<h1>{{this.name}}</h1>
<p>Type: {{this.eventType}}</p>
<p>Status: {{this.status}}</p> 
<p>Datum: {{ formatDate this.start "P" }} | {{ formatDate this.start "p" }} Uhr  </p>
<p>Name: {{this.displayNames.eventTitleWithArtistsAndShows}}  </p>
<p>Ort: {{this.displayNames.locationsWithRooms}}</p>

{{/each}}

Einfaches CSV Beispiel

Status;Datum;Titel
{{#each events}}
{{this.status}};{{formatDate this.start "P"}};{{{this.name}}}
{{/each }}

VVK-Zahlen

<h1>Verkäufe</h1>
<p>Event:  {{this.name}} | {{ formatDate this.start "P" }}</p>
<p>Location: {{this.displayNames.locationsWithRooms}}</p>
{{#if this.ticketing}}
<h2>Tickets</h2>
<table>
    <thead>
        <tr>
            <th>VVK-Stelle</th>
            <th>Kategory</th>
            <th>Ticketpreis (brutto)</th>
            <th>Verkauft</th>
            <th>Kontingent</th>
            <th>Gesamt (brutto)</th>
        </tr>
    </thead>
    <tbody>
      {{#each this.ticketing}}
        <tr>
            <td>{{ this.ticketOffice }}</td>
            <td>{{ this.category }}</td>
            <td>{{ formatEuro this.grossPrice }}</td>
            <td>{{ this.soldTickets }}</td>
            <td>{{ this.contingent }}</td>
            <td>{{ formatEuro this.saleTotal }}</td> 
        </tr>
        {{/each}}
<tr>
            <th>Summe</th>
            <th></th>
            <th></th>
            <th>{{ sumBy this.ticketing "soldTickets" }}</th>
            <th>{{ sumBy this.ticketing "contingent" }}</th>
            <th>{{ formatEuro (sumBy this.ticketing "saleTotal" ) }}</th>
        </tr>
    </tbody>
</table>

{{/if}}

Event-Informationen

Alle Event-Informationen außer „Gästeliste“ auflisten.

<h2>Event Informationen</h2>
{{#each this.eventInformations}}
{{#unless (isEqual name "Gästeliste")}}
 
<h3>{{this.name}}</h3>
{{this.value}}
{{/unless}}
{{/each}} 

Artist-Tabelle mit Bilder

<h2>Artists</h2>

<table class="artistTable">
    <thead>
        <tr>
            <th>Pic</th>
            <th>Name</th>
        </tr>
    </thead>
    <tbody>
        {{#each this.artists}}
        <tr>
            <td><img src="{{ lookup this.images.0.sizes "640" }}" /></td>
            <td>
              <h3>{{ this.name }}</h3>
              <p>{{ this.description }}</p>
            </td>
        </tr>
        {{/each}}
    </tbody>
</table>

Dateien verlinken

<h2>Dateien</h2>

{{#each this.files}}

<h3>{{this.name}}</h3>
<a href="{{this.path}}">{{this.path}}</a>

{{/each}}

Anmerkung: Nur als „öffentlich“ gekennzeichnete Dateien können im Export eingebunden werden. „Öffentlich“ bedeutet hierbei lediglich, dass eine Datei ohne Login verfügbar wird. Ohne die URL bzw. konkreter die zufallsgenerierte ID besteht aber trotzdem keine Zugriffsmöglichkeit. D.h. es können durchaus Dateien wie Tech Rider auf öffentlich gesetzt und somit in einen Export eingebunden werden.

Tipps

Bedingte Darstellung

Um eine Sektion nur anzuzeigen, wenn das entsprechende Feld gesetzt ist, kann sie mit einem #if Block-Helper umschlossen werden:

{{#if (eventInformationByName this.eventInformations "Hotel")}}
<h3>Hotel</h3>
{{eventInformationByName this.eventInformations "Hotel"}}
{{/if}}

Seitenumbruch

Für PDF-Exporte können Seitenumbrüche eingefügt werden. Bei Word-Exporten hat das allerdings keinen Effekt.

Inhalt vor dem Seitenumbruch

{{pagebreak}}

Inhalt nach dem Seitenumbruch

Die Leerzeile vor {{pagebreak}} ist notwendig.

Styling

Styling von Exporten ist via CSS möglich. Globale Stile können ganz am Anfang einer Exportvorlage in einem Style-Tag angegeben werden:

<style>
...
</style>

Alternativ sind auch Inline-Stile auf z.B. einzelnen Absätzen oder Paragraphen anwendbar. Hierfür muss die entsprechende Passage dann allerdings in HTML statt Markdown geschrieben werden:

<p style="...">...</p>

Schriften

Folgende Schriftarten stehen zur Verfügung:

Beispiel: Überschriften mit Serifen, Absätze serifenlos

<style>
h1, h2, h3, h4 {
  font-family: DM Serif Display;
}
body, p, th, td {
  font-family: Ubuntu;
}
</style>

<h1>Globale Stile</h1>

<p>Ein Absatz</p>
<ul>
<li>eine</li>
<li>Liste</li>
</ul>

<h2>Tabelle</h2>
<table>
    <thead>
        <tr>
            <th>Spalte A</th>
            <th>Spalte B</th>
            <th>Spalte C</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>A1</td>
            <td>B1</td>
            <td>C1</td>
        </tr>
        <tr>
            <td>A2</td>
            <td>B2</td>
            <td>C2</td>
        </tr>
    </tbody>
</table>

Beispiel: Einzelner Absatz in anderer Schriftart

Erster Absatz

<p style="font-family: Indie Flower">Zweiter Absatz</p>

Weitere Möglichkeiten

<p style="color: blue">blau</p>
<p style="color: blue; font-weight: bold;">blau & fettgedruckt</p>
<mark>highlighted</mark>
<p style="text-decoration: underline;">unterstrichen</p>