Documentation

Feiertagsmanagement

Das ShopBite Plugin bietet ein umfassendes Feiertagsmanagement-System, das speziell für Gastronomie- und Einzelhandelsbetriebe entwickelt wurde. Dieses Kapitel erklärt die detaillierte Konfiguration und Verwaltung von Feiertagen und Schließtagen.

Übersicht

Das Feiertagsmanagement-System ermöglicht:

  • Einmalige Feiertage: Konfiguration individueller Schließtage
  • Wiederkehrende Feiertage: Jährlich wiederholende Feiertage
  • Zeitraum-basierte Schließungen: Mehrtägige Schließungen (z.B. Weihnachten)
  • Sales Channel-spezifisch: Unterschiedliche Feiertage für verschiedene Vertriebskanäle
  • API-Integration: Abruf über die Shopware Store API

Datenbankstruktur

CREATE TABLE `shopbite_holiday` (
    `id` BINARY(16) NOT NULL,
    `start` DATETIME(3) NOT NULL,  -- Beginn der Schließung
    `end` DATETIME(3) NOT NULL,    -- Ende der Schließung
    `sales_channel_id` BINARY(16) NOT NULL,
    `name` VARCHAR(255) NULL,     -- Name des Feiertags
    `description` TEXT NULL,      -- Beschreibung
    `recurring` TINYINT(1) DEFAULT 0,  -- Jährlich wiederholend
    `created_at` DATETIME(3) NOT NULL,
    `updated_at` DATETIME(3) NULL,
    PRIMARY KEY (`id`),
    KEY `fk.shopbite_holiday.sales_channel_id` (`sales_channel_id`),
    CONSTRAINT `fk.shopbite_holiday.sales_channel_id` 
        FOREIGN KEY (`sales_channel_id`) 
        REFERENCES `sales_channel` (`id`) 
        ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

Administrationsoberfläche

Feiertags-Liste

  1. ShopBite > Feiertage navigieren
  2. Übersicht aller konfigurierten Feiertage
  3. Filterung nach Sales Channel und Datum
  4. Massenaktionen (Export, Import)

Neuen Feiertag hinzufügen

  1. Neuen Feiertag hinzufügen klicken
  2. Formular ausfüllen:

Formularfelder

FeldTypBeschreibungBeispiel
NameTextName des Feiertags"Weihnachten"
StartdatumDatum/ZeitBeginn der Schließung24.12.2024 18:00
EnddatumDatum/ZeitEnde der Schließung26.12.2024 23:59
Sales ChannelDropdownVertriebskanal auswählen"Mein Restaurant"
Jährlich wiederholenCheckboxFeiertag jährlich wiederholen
BeschreibungTextareaOptional Beschreibung"Weihnachtsferien - geschlossen"

Feiertage bearbeiten

  1. Bearbeiten-Button klicken
  2. Felder anpassen
  3. Speichern klicken

Feiertage löschen

  1. Löschen-Button klicken
  2. Bestätigung dialog
  3. Bestätigen klicken

API-Integration

API-Endpunkt

GET /store-api/shopbite/holiday

Anfrageparameter

ParameterTypBeschreibungBeispiel
sales-channel-idUUIDFilter nach Sales Channel019a36f224b0704fb6835914050392f4
from-dateDatumFilter nach Startdatum2024-01-01
to-dateDatumFilter nach Enddatum2024-12-31
include-recurringBooleanWiederkehrende Feiertage einbeziehentrue

Beispielanfrage

curl -X GET "https://Ihre-Shopware-Domain.de/store-api/shopbite/holiday" \
  -H "Authorization: Bearer IhrAPIToken" \
  -H "sw-access-key: IhrAccessKey" \
  -H "Accept: application/json"

Beispielantwort

{
  "apiAlias": "shopbite_holiday",
  "data": [
    {
      "id": "019a36f224b0704fb6835914050392f4",
      "start": "2024-12-24T18:00:00+01:00",
      "end": "2024-12-26T23:59:00+01:00",
      "salesChannelId": "019a36f224b0704fb6835914050392f4",
      "name": "Weihnachten",
      "description": "Weihnachtsferien - geschlossen",
      "recurring": false,
      "createdAt": "2024-01-11T14:30:00+01:00",
      "updatedAt": "2024-01-11T14:30:00+01:00",
      "salesChannel": {
        "id": "019a36f224b0704fb6835914050392f4",
        "name": "Mein Restaurant",
        "typeId": "019a36f224b0704fb6835914050392f4"
      }
    },
    {
      "id": "019a36f224b0704fb6835914050392f5",
      "start": "2024-01-01T00:00:00+01:00",
      "end": "2024-01-01T23:59:00+01:00",
      "salesChannelId": "019a36f224b0704fb6835914050392f4",
      "name": "Neujahr",
      "description": "Geschlossen",
      "recurring": true,
      "createdAt": "2024-01-11T14:30:00+01:00",
      "updatedAt": "2024-01-11T14:30:00+01:00",
      "salesChannel": {
        "id": "019a36f224b0704fb6835914050392f4",
        "name": "Mein Restaurant",
        "typeId": "019a36f224b0704fb6835914050392f4"
      }
    }
  ],
  "total": 10
}

Fehlerbehandlung

StatuscodeBedeutungLösung
200ErfolgDaten erfolgreich abgerufen
401UnauthorizedAPI-Zugangsdaten prüfen
403ForbiddenBerechtigungen prüfen
404Not FoundEndpunkt oder Sales Channel nicht gefunden
500Internal Server ErrorServer-Logs prüfen

Wiederkehrende Feiertage

Funktionsweise

Wiederkehrende Feiertage werden automatisch für jedes Jahr neu erstellt:

  • Jährliche Erstellung: Am 1. Januar jedes Jahres
  • Zeitraum: Basierend auf dem ursprünglichen Datum
  • Benachrichtigung: Admin-Benachrichtigung bei Erstellung

Verwaltung

  1. ShopBite > Feiertage > Wiederkehrende Feiertage navigieren
  2. Neuen wiederkehrenden Feiertag hinzufügen klicken
  3. Formular ausfüllen:

Formularfelder

FeldTypBeschreibungBeispiel
NameTextName des Feiertags"Weihnachten"
MonatDropdownMonat auswählenDezember
TagZahlTag im Monat25
StartzeitZeitBeginn der Schließung18:00
EndzeitZeitEnde der Schließung23:59
Sales ChannelDropdownVertriebskanal auswählen"Mein Restaurant"
BeschreibungTextareaOptional Beschreibung"Weihnachtsferien"

API-Abfrage für wiederkehrende Feiertage

curl -X GET "https://Ihre-Shopware-Domain.de/store-api/shopbite/holiday?include-recurring=true" \
  -H "Authorization: Bearer IhrAPIToken" \
  -H "sw-access-key: IhrAccessKey"

Best Practices

1. Konsistente Datumsformate

  • Verwenden Sie immer das ISO-8601-Format (YYYY-MM-DD)
  • Zeitangaben im 24-Stunden-Format (HH:MM:SS)
  • Berücksichtigen Sie Zeitzonen (Standard: Europe/Berlin)

2. Überlappende Feiertage vermeiden

  • Prüfen Sie auf Überlappungen mit anderen Feiertagen
  • Verwenden Sie den Kalender in der Administration
  • Nutzen Sie die Validierung beim Speichern

3. Performance-Optimierung

-- Indizes für bessere Performance
CREATE INDEX `idx_sales_channel` ON `shopbite_holiday` (`sales_channel_id`);
CREATE INDEX `idx_date_range` ON `shopbite_holiday` (`start`, `end`);
CREATE INDEX `idx_recurring` ON `shopbite_holiday` (`recurring`);

4. Caching-Strategie

# In config/packages/cache.yaml
framework:
    cache:
        pools:
            shopbite.holidays:
                adapter: cache.adapter.redis
                default_lifetime: 86400  # 24 Stunden Cache

5. Automatische Benachrichtigungen

Richten Sie Benachrichtigungen für anstehende Feiertage ein:

// In einem Cron-Job oder Event-Listener
$upcomingHolidays = $holidayRepository->getUpcomingHolidays(7); // Nächste 7 Tage

foreach ($upcomingHolidays as $holiday) {
    $mailer->sendHolidayReminder($holiday);
}

Integration mit der Storefront

JavaScript-Beispiel

// Feiertage abrufen
async function fetchHolidays(salesChannelId, fromDate, toDate) {
  const params = new URLSearchParams({
    'sales-channel-id': salesChannelId,
    'from-date': fromDate,
    'to-date': toDate
  });
  
  const response = await fetch(
    `/store-api/shopbite/holiday?${params.toString()}`,
    {
      headers: {
        'Authorization': `Bearer ${apiToken}`,
        'sw-access-key': accessKey
      }
    }
  );
  
  if (!response.ok) {
    throw new Error('Failed to fetch holidays');
  }
  
  return await response.json();
}

// Feiertage anzeigen
function displayHolidays(holidays) {
  holidays.data.forEach(holiday => {
    const start = new Date(holiday.start);
    const end = new Date(holiday.end);
    
    console.log(`${holiday.name}: ${start.toLocaleDateString()} - ${end.toLocaleDateString()}`);
    console.log(`Beschreibung: ${holiday.description || 'Keine Beschreibung'}`);
  });
}

// Beispielaufruf
const today = new Date().toISOString().split('T')[0];
const nextYear = new Date();
nextYear.setFullYear(nextYear.getFullYear() + 1);
const nextYearEnd = nextYear.toISOString().split('T')[0];

fetchHolidays('019a36f224b0704fb6835914050392f4', today, nextYearEnd)
  .then(displayHolidays)
  .catch(console.error);

Vue.js-Komponente

<template>
  <div class="holidays">
    <h3>Feiertage und Schließtage</h3>
    <div v-for="holiday in holidays" :key="holiday.id" class="holiday-item">
      <div class="holiday-header">
        <span class="holiday-name">{{ holiday.name }}</span>
        <span v-if="holiday.recurring" class="badge recurring">Jährlich</span>
      </div>
      <div class="holiday-dates">
        {{ formatDate(holiday.start) }} - {{ formatDate(holiday.end) }}
      </div>
      <div v-if="holiday.description" class="holiday-description">
        {{ holiday.description }}
      </div>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      holidays: [],
      loading: false,
      error: null
    };
  },
  
  async mounted() {
    await this.fetchHolidays();
  },
  
  methods: {
    formatDate(dateString) {
      const date = new Date(dateString);
      return date.toLocaleDateString('de-DE', {
        weekday: 'short',
        day: 'numeric',
        month: 'short',
        year: 'numeric',
        hour: '2-digit',
        minute: '2-digit'
      });
    },
    
    async fetchHolidays() {
      this.loading = true;
      this.error = null;
      
      try {
        const response = await this.$axios.get('/store-api/shopbite/holiday');
        this.holidays = response.data.data;
      } catch (error) {
        console.error('Failed to fetch holidays:', error);
        this.error = 'Feiertage konnten nicht geladen werden.';
      } finally {
        this.loading = false;
      }
    }
  }
};
</script>

<style scoped>
.holidays {
  margin: 20px 0;
  padding: 15px;
  background: #fff5f5;
  border-radius: 8px;
  border: 1px solid #ffebee;
}

.holiday-item {
  padding: 12px 0;
  border-bottom: 1px solid #ffcdcd;
}

.holiday-item:last-child {
  border-bottom: none;
}

.holiday-header {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 4px;
}

.holiday-name {
  font-weight: bold;
  color: #d32f2f;
}

.badge {
  padding: 2px 6px;
  border-radius: 4px;
  font-size: 12px;
  font-weight: bold;
}

.badge.recurring {
  background: #ffeb3b;
  color: #000;
}

.holiday-dates {
  color: #b71c1c;
  font-size: 14px;
  margin-bottom: 4px;
}

.holiday-description {
  color: #666;
  font-size: 13px;
  font-style: italic;
}
</style>

Fehlerbehandlung und Debugging

Häufige Probleme

Problem: Feiertage werden nicht berücksichtigt

Symptome:

  • Bestellungen an Feiertagen möglich
  • Feiertage nicht in API sichtbar

Lösungen:

# Feiertagsdaten prüfen
mysql -u shopware -p shopware -e "SELECT * FROM shopbite_holiday;"

# Zeitformat prüfen
bin/console database:check-timezone

# API-Abfrage testen
curl -X GET "https://Ihre-Domain.de/store-api/shopbite/holiday" -H "Authorization: Bearer IhrToken"

Problem: Wiederkehrende Feiertage werden nicht erstellt

Symptome:

  • Wiederkehrende Feiertage fehlen
  • Keine automatische Erstellung

Lösungen:

# Cron-Job prüfen
crontab -l

# Manuell ausführen
bin/console shopbite:holidays:generate-recurring

# Logs prüfen
tail -n 50 /var/log/shopware/prod.log | grep holiday

Problem: Zeitüberschneidungen

Symptome:

  • Feiertage überlappen sich
  • Falsche Schließzeiten

Lösungen:

# Überlappungen prüfen
mysql -u shopware -p shopware -e "
  SELECT * FROM shopbite_holiday 
  WHERE start < (SELECT end FROM shopbite_holiday WHERE id != shopbite_holiday.id)
  AND end > (SELECT start FROM shopbite_holiday WHERE id != shopbite_holiday.id);"

# Validierung aktivieren
bin/console config:set ShopBitePlugin.config.validateHolidayOverlaps true

Nächste Schritte