Abweichende Artikeldaten Help

Frontend

Das CMS-Element

Das Element trägt den Typ custom-products. Es besteht aus drei Teilen:

Teil

Ort

Komponente

src/Resources/app/administration/src/module/sw-cms/elements/custom-products/component/

Vorschau

.../custom-products/preview/

Storefront-Template

src/Resources/views/storefront/element/cms-element-custom-products.html.twig

Das Storefront-Template erweitert das Grundgerüst aus BusinessTransactions:

{% sw_extends '@BusinessTransactions/storefront/element/transactions_base_element.html.twig' %}

Im Block container werden die Optionen für das JavaScript-Plugin zusammengesetzt — vor allem die Store-API-URL und der Name des Zusatzfeldes, das die Kundenzuweisung trägt:

{% set options = options|merge({ url: path('store-api.business_custom_products.custom-products', {}, true), CUSTOMER_ASSIGNMENT: constant('\\Leoparden\\BusinessCustomProducts\\LeopardenBusinessCustomProducts::CUSTOMER_ASSIGNMENT') }) %}

Der Feldname wird also nicht im Template wiederholt, sondern aus der PHP-Konstante gezogen. Im HMR-Betrieb wird die URL zusätzlich auf Port 9998 umgebogen.

Der Block content enthält die Tabelle. Sie wird clientseitig mit Vue-Direktiven gefüllt (v-if, v-for), die Twig über {% verbatim %} unangetastet durchreicht. Zum Überschreiben stehen die Blöcke header_product_number, header_customer_assignment, body_product_number und body_customer_assignment bereit.

Das Storefront-Plugin

src/Resources/app/storefront/src/custom-products.plugin.ts erweitert AbstractEntityListingPlugin aus @leoparden/plugin-tools-storefront. Damit kommen Laden, Sortieren und Blättern aus der Basisklasse; das Plugin steuert nur noch drei Dinge bei.

Sortierung. Vorgabe ist productNumber.

Anfrage. createBody() fordert die Assoziationen seoUrls und eine auf einen Eintrag begrenzte translations an:

createBody(): BodyType { return { sort: [{field: this.sorting || "productNumber", order: ...}], associations: {seoUrls, translations: {limit: 1}}, }; }

Antwort. processResponse() macht die SEO-Pfade absolut und hebt die Erweiterungen aus product.extensions auf die Artikelebene, damit das Template direkt product.customer_assignment.customerNumber schreiben kann. Anschließend läuft die Antwort noch durch ProcessTransactionResponseFunction aus BusinessTransactions.

Administration

Kundendetailseite

Das Plugin erweitert sw-customer-detail um eine Ansicht custom-products (src/Resources/app/administration/src/module/sw-customer/). Sie lädt über eine TypedRepository<"product"> alle Artikel, deren Zuweisung die Kunden-ID enthält:

criteria.addFilter(Criteria.contains("customFields.customer_assignment", this.customer.id));

Dargestellt wird das Ergebnis in einer sw-entity-listing mit den Spalten Artikelnummer, Bezeichnung und Eigenes Produkt. Die Spalte Eigenes Produkt wird in updateRecords() berechnet: Sie ist gesetzt, wenn die Zuweisung genau diesem Kunden entspricht.

Snippets

Die Beschriftungen der Administration liegen unter src/Resources/app/administration/src/module/BusinessCustomProducts/snippet/:

Schlüssel

de-DE

plugin.leoparden.BusinessCustomProducts.custom-products.label

Abweichende Artikeldaten

plugin.leoparden.BusinessCustomProducts.title

Abweichende Artikeldaten

plugin.leoparden.BusinessCustomProducts.productNumber

Art. Nr

plugin.leoparden.BusinessCustomProducts.name

Bezeichnung

plugin.leoparden.BusinessCustomProducts.direct

Eigenes Produkt

Bauen und testen

# Administration und Storefront bauen composer build:js # Jest-Suiten cd src/Resources/app/administration && npm run test cd src/Resources/app/storefront && npm run test

Die Storefront-Suite löst die Shopware-Quellen über die paths in tsconfig.json auf. Diese zeigen auf das Verzeichnislayout der CI; lokal schlägt die Auflösung deshalb fehl, in der Pipeline läuft sie durch.

Last modified: 06 August 2026