> ## Documentation Index
> Fetch the complete documentation index at: https://dokumentation.websale.de/llms.txt
> Use this file to discover all available pages before exploring further.

# Praxisbeispiele - Gutscheine

> Praxisbeispiele für Gutscheine in WEBSALE: Eingabeformular mit maximumCount-Check, Validierung, Einlösen im Checkout sowie Download-Links für gekaufte Gutscheine.

In diesem Abschnitt finden Sie Praxisbeispiele für die Verwendung von Gutscheinen im Template. Die ersten Beispiele behandeln das Einlösen im Checkout, das letzte die Ausgabe gekaufter Gutscheine.

Gutscheine werden im Admin-Interface angelegt. Dies wird auf den Seiten [Gutscheine](/admin-interface/marketing/gutscheine) und [Kaufgutschein-Produkt anlegen](/admin-interface/katalog/produkte/kaufgutschein-produkt) beschrieben.

***

## Gutscheineingabe-Formular mit `maximumCount`-Check

Die Eingabe-Form wird nur angezeigt, solange weniger Gutscheine eingelöst sind als erlaubt. Sobald die Höchstgrenze erreicht ist, verschwindet das Formular automatisch.

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
{{ var $cActionVoucherAdd = $wsActions.create("VoucherAdd") }}
{{ include "components/errorAlert.htm" with $cAction = $cActionVoucherAdd, $cViewEachField = true }}

{{ if len($wsVoucher.vouchers) < $wsVoucher.maximumCount }}
    <form method="post" action="{{= $wsViews.current.url() }}" data-ws-ajax-form>
        <input type="hidden" name="wsReplaceIds" value="wsBasketWrapper,wsBasketEntries,wsBasketOffcanvasContent">
        <input type="hidden" name="wsact"    value="{{= $cActionVoucherAdd.id }}">
        <input type="hidden" name="wscsrf"   value="{{= $cActionVoucherAdd.csrf }}">
        <input type="hidden" name="wstarget" value="{{= $wsViews.current.url() }}">

        <input type="text" name="id" value="" placeholder="Gutschein-Code eingeben">
        <button type="submit">Einlösen</button>
    </form>
{{ /if }}
```

<Info>
  Fehlermeldungen (z.B. "Mindestbestellwert nicht erreicht") werden über `components/errorAlert.htm` definiert und ausgegeben.
</Info>

***

## Liste eingelöster Gutscheine anzeigen

Pro Gutschein wird ein eigenes kleines Formular mit eindeutiger ID ausgegeben. Gültige Gutscheine erscheinen grün, ungültige rot.

```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
{{ if $wsVoucher.vouchers }}
    <p>Eingelöste Gutscheine</p>

    {{ foreach $cVoucher in $wsVoucher.vouchers }}
        {{ var $cVoucherIsValid = $cVoucher.valid | ifNull(true) }}
        {{ var $cActionVoucherDelete = $wsActions.create("VoucherDelete") }}

        <form method="post"
              action="{{= $wsViews.viewUrl('basket.htm') }}"
              data-ws-ajax-form>
            <input type="hidden" name="wsReplaceIds" value="wsBasketWrapper,wsBasketEntries,wsBasketOffcanvasContent">
            <input type="hidden" name="id"       value="{{= $cVoucher.id }}">
            <input type="hidden" name="wsact"    value="{{= $cActionVoucherDelete.id }}">
            <input type="hidden" name="wscsrf"   value="{{= $cActionVoucherDelete.csrf }}">
            <input type="hidden" name="wstarget" value="{{= $wsViews.current.url() }}">

            <span>{{= $cVoucher.id }}</span>
            <button type="submit">Entfernen</button>
        </form>
    {{ /foreach }}
{{ /if }}
```

***

## Alle eingelösten Gutscheine im Warenkorb ausgeben

In diesem Beispiel werden alle eingelösten Gutscheine im Warenkorb ausgegeben. So sieht der Kunde transparent, welche Codes im System sind und welcher davon gerade greift. Nicht wirksame Gutscheine werden nicht in die Liste aufgenommen und werden über eine Fehlermeldung gekennzeichnet.

```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
{{ var $cVoucherCount = 0 }}
{{ if $wsVoucher.vouchers }}
    {{ foreach $cVoucher in $wsVoucher.vouchers }}
        {{ $cVoucherCount = $cVoucherCount + 1 }}
        <tr>
            <td>
                <div>{{ if $cVoucherCount == 1 }}Gutschein{{ else }}Weiterer Gutschein{{ /if }}</div>
                <div>{{= $cVoucher.id }}</div>
            </td>
            <td>
                -{{= $cVoucher.value | currency }}
            </td>
        </tr>
    {{ /foreach }}
{{ /if }}
```

***

## Gutscheinfehler mit Grund und Gutschein-ID ausgeben

Statt eines allgemeinen Hinweises erhält der Kunde hier je Gutschein den konkreten Grund, warum der Gutschein nicht greift. Die Texte stammen aus [`checkout.voucherErrors`](/konfiguration/checkout-bestellablauf#checkout-vouchererrors-fehlertexte-zu-wirkungslosen-gutscheinen), der Fallback auf `code` greift nur, falls kein Text gepflegt ist.

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
{{ if $wsCheckout.isOrderBlockedByIneffectiveVoucher }}
    <div class="alert alert-danger" role="alert">
        <strong>Gutscheine können nicht eingelöst werden:</strong>
        <ul>
            {{ foreach $cError in $wsCheckout.ineffectiveVoucherErrors }}
                {{ if $cError.details.voucherId }}
                    <li>
                        Gutschein <strong>{{= $cError.details.voucherId }}</strong>:
                        {{= $cError.text | ifNull($cError.code) }}
                    </li>
                {{ else }}
                    {{#
                        Steht die Berechnung des Mindestbestellwerts auf "sum", wird die Summe
                        aller Mindestbestellwerte geprüft. Dieser Fehler gehört zu keinem
                        einzelnen Gutschein und kommt daher ohne Gutschein-ID.
                    #}}
                    <li>{{= $cError.text | ifNull($cError.code) }}</li>
                {{ /if }}
            {{ /foreach }}
        </ul>
    </div>
{{ /if }}
```

<Info>
  Prüfen Sie `details.voucherId` immer vor der Ausgabe. Die Gutschein-ID fehlt bewusst, wenn der Fehler aus der Summenprüfung der Mindestbestellwerte stammt. Welcher Fehler wann entsteht, steht unter [Wann welcher Fehler entsteht](/konfiguration/checkout-bestellablauf#wann-welcher-fehler-entsteht).
</Info>

***

## Kostenfreie Versandart für Gutschein-Warenkörbe

Enthält ein Warenkorb ausschließlich (Sofort-)Gutscheine, wird kein physischer Versand benötigt. Dafür lässt sich unter [`checkout.shippingMethod`](/konfiguration/checkout-bestellablauf#checkout-shippingmethod-versandarten) eine eigene, immer kostenfreie Versandart anlegen: Die Preisstaffel `basicCost` setzt die Kosten ab einer Zwischensumme von `0` auf `0`, und die Validierung [`shippingMethodValidation.productType`](/konfiguration/validierungs-und-prufservices) mit `rule: deny` sperrt die Versandart, sobald ein reguläres Produkt (Produkttyp `standard`) im Warenkorb liegt - sie ist also nur für reine Gutschein-Warenkörbe wählbar.

```json theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
{
  "active": true,
  "basicCost": [
    {
      "cost": 0,
      "subtotal": 0
    }
  ],
  "description": "checkout.shippingMethod.INSTANT_VOUCHER.description",
  "group": null,
  "id": "INSTANT_VOUCHER",
  "image": "",
  "link": "",
  "name": "checkout.shippingMethod.INSTANT_VOUCHER.name",
  "orderText": "checkout.shippingMethod.INSTANT_VOUCHER.orderText",
  "taxable": true,
  "type": "standard",
  "validations": [
    {
      "options": {
        "rule": "deny",
        "ruleList": [
          "standard"
        ]
      },
      "service": "shippingMethodValidation.productType"
    }
  ],
  "weightCost": null
}
```

<Info>
  Der Wert `standard` in der `ruleList` ist der **Wert des Produkttyp-Feldes** der Produkte (das über `content.usedFields` als Produkttyp definierte Produktdatenfeld) - nicht zu verwechseln mit dem Parameter `type: "standard"` der Versandart selbst. Produkte, bei denen das Produkttyp-Feld nicht gesetzt ist, bestehen die Prüfung immer.

  `name`, `description` und `orderText` verweisen im Beispiel auf Textbausteine, sodass die Texte je Sprache über den Textbaustein-Dienst gepflegt werden können.
</Info>

***

## Gekaufte Gutscheine zum Download anbieten

Dieses Beispiel gehört nicht zum Einlösen, sondern zum Verkauf: Wurde ein [Kaufgutschein-Produkt](/admin-interface/katalog/produkte/kaufgutschein-produkt) bestellt, erzeugt der Shop beim Bestellabschluss je bestellter Einheit einen Gutscheincode. Die Codes einer Warenkorbposition stehen im Template unter `voucherIds` bereit, das zugehörige PDF wird über den URL-Parameter `wsfilter=pdf` aus dem am Produkt hinterlegten View-Template erzeugt.

Der folgende Block gibt je Position und Code einen Download-Link aus. Er eignet sich für die Bestellbestätigungsseite und für das E-Mail-Template der Bestellbestätigung.

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
{{ foreach $basketItem in $wsBasket.items }}
   {{ if $basketItem.product.custom.voucherProductActive }}
      {{ foreach $voucherId in $basketItem.voucherIds }}
         <a href="{{= $wsViews.viewUrl('voucher/default_voucher.htm', {
             voucherId: $voucherId,
             productId: $basketItem.product.id,
             wsfilter: 'pdf'
         }, 'absolute') }}">
            Gutschein {{= $voucherId }} herunterladen
         </a>
      {{ /foreach }}
   {{ /if }}
{{ /foreach }}
```

<Info>
  Der Typ `absolute` erzeugt eine vollständige URL, weil E-Mails keine relativen Links verarbeiten. Die Parameter `voucherId` und `productId` machen den Aufruf unabhängig von der Session, sodass der Link auch später noch funktioniert.

  `voucher/default_voucher.htm` steht hier stellvertretend für das View-Template, das am Produkt im Feld "HTML-Template" hinterlegt ist. Wie PDF-Ansichten aufgebaut werden, beschreibt [PDF-Ansichten](/frontend/funktionsubersicht/pdf-ansichten).
</Info>

Für die Weiterverarbeitung außerhalb des Shops stehen dieselben Angaben in den Bestelldaten unter `data.orderList.item[].voucher`, siehe [API-Referenz Bestellungen](/schnittstellen/admin-interface-api/api-referenz-bestellungen).


## Related topics

- [Gutscheine](/admin-interface/marketing/gutscheine.md)
- [checkout - Bestellablauf](/konfiguration/checkout-bestellablauf.md)
- [$wsVoucher - Gutscheine](/frontend/referenz/module/wsvoucher.md)
- [Praxisbeispiele - Verknüpfung mit dem Zahlungsanbieter](/frontend/praxisbeispiele/verknuepfung-zahlungsanbieter.md)
- [$wsWatchList - Merklisten](/frontend/referenz/module/wswatchlist.md)
