Blog: Latest Entries (15):


Shopware 6: Bestellstatus ändern ohne Mail zu verschicken

Oft will man einfach nur den Status der Stellung anpassen, weil irgendwas mit der Bestellung nicht stimmt oder man sie auf abgeschlossen setzen will, aber der Rest über das ERP/die WaWi läuft. Man will keine Mail an den Kunden senden. Leider ist die Mail immer direkt aktiviert und man muss immer daran denken diese zu deaktivieren.

Nervig.. also ein tolles kleines (wirklich kleines) Plugin-Projekt:

https://gitlab.com/hpries/HPrSendMailStateChange

normal
bbcode-image


jetzt
bbcode-image

JavaScript: Detect scroll to bottom

Um einen einfachen kleinen Dialog zum Akzeptieren von AGBs/T&Cs/etc braucht man nur relativ wenig JavaScript Code und auch kein JQuery mehr.


<html>
<head>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css"
rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC"
crossorigin="anonymous">
<style>
#reader {
max-height: 200px;
border: 1px solid lightgray;
border-radius: 3px;
overflow: auto;
padding: 0.25rem;
}

#page {
display: flex;
justify-content: center;
padding-top: 5rem;
}
</style>
</head>
<body><div id="page">

<div class="card" style="width: 18rem;">
<div class="card-body">
<h5 class="card-title">Scroll to Accept</h5>
<p class="card-text">
<div id="reader">
Gott zum Gruße! Das feist Weichteile. Die geflissentlich
Begrüßungsgeld meucheln. Der töricht Lump grämen. Das bräsig Schürzenjäger.
Der grobschlächtig Edelmut. Der Kummerspeck anschwärzen der bierernst Lump.
Fatzke und Panzerkampfwagen flanieren pompös Schindluder. Die pomadig Bagage
foppen. Narr und Affenzahn schlampampen feist Quasselstrippe. Presssack und
Kuppelei picheln altbacken Kummerspeck. Die geflissentlich Luder frickeln.
Das Begrüßungsgeld schlampampen die gebeutelt Flegel. Habe die Ehre!
</div>
</p>
<button id="ok" class="btn btn-primary" disabled type="button">Accept</button>
</div>
</div>
<script>
document.getElementById('reader').addEventListener('scroll',
(e) => {
const element = e.target;
if(element.offsetHeight + element.scrollTop >= element.scrollHeight) {
document.getElementById('ok').removeAttribute('disabled');
}
}
, true)
</script>
</div>
</body>
</html>

Shopware 6: Storefront Plugins

Ein JavaScript Plugin für die Shopware 6 Storefront zu schreiben ist an sich sehr einfach.
Das Plugin an sich ist sehr einfach strukturiert.

example-plugin/index.js

import Plugin from 'src/plugin-system/plugin.class';

export default class ExamplePlugin extends Plugin {
init() {
console.log('plugin is bind to this element', this.el);
}
}


Die Klasse registiert man in der main.js:


import ExamplePlugin from './example-plugin/';

window.PluginManager.register('ExamplePlugin', ExamplePlugin, '[data-example-plugin]');


Nun muss man das nur noch an ein HTML-Element binden, so dass es wenn dieses Element geladen wird auch gestartet wird.


...
<div data-example-plugin="true"></div>
...


Im Plugin sucht man sich dann alle benötigten Elemente und registriert dort alle benötigten Listener.

Ausführlich steht alles hier: https://developer.shopware.com/docs/guides/plugins/plugins/storefront/add-custom-javascript

Wobei ich eher diese Seite https://mrtnschndlr.medium.com/die-neue-shopware-6-storefront-und-was-du-alles-dar%C3%BCber-wissen-solltest-e1e5621b6397 empfehlen würde.

die Art und Weise erinnert mich etwas wie ich damals bei meinen cJSv2-Framework die Controller an Elemente gebunden und initialisiert habe.. der default-Name der Init-Methode war da auch init.

Der DomAccess-Helper ist super und sollte man so verwenden. Über den kann man auch den QuerySelector nutzen und dass schützt hoffentlich davor, dass ein Haufen klassischer Webdesigner versuchen JQuery wieder da rein zu bringen. Der HttpClient ist auch nett aber man kann genau so gut direkt mit fetch() arbeiten, wenn man nicht unbedingt irgendwelche Steinzeit Browser supporten möchte. Aber besonder mag ich von den Helpern DeviceDetection.isTouchDevice() weil man damit einfach unterschieden kann ob man gerade ein Touch oder ein MouseEnter
Event nutzen muss.

Shopware 6: Lesbares Javascript

Wenn man in der Storefront an einem eignem JavaScript-Plugin arbeitet ist es beim Debuggen, oft nervig, dass der JavaScript Code nicht direkt lesbar ist. Oft weiß man beim eigenen Code direkt was los ist, aber gerade wenn 3rd Party Plugins auch mit rein spielen, kommt man nicht drum herum sich Exceptions mit lesbaren Stacktrace anzeigen zu lassen.

Das ist zum Glück extrem einfach:

* Port 9998 aus dem Docker-Container durchleiten
* Dem SalesChannel in dem man entwickelt die Domain "localhost" zu ordnen
* das Script bin/watch-storefront.sh starten

Nun kann man localhost:9998 im Browser aufrufen. Der JavaScript Code ist lesbar und Änderungen werden sofort übernommen ohne dass man die Storefront neu bauen muss.

Shopware 6: Produkt-Analyse per SQL

Einmal schnell gucken, wie viele und welche Art von Produkten über welchen SalesChannel und URL zu kaufen sind.


SELECT x.url, 'single' type, count(x.id)
FROM (
select d.url, p.id, p.parent_id, count(p2.id) children from sales_channel_domain d
join sales_channel sc on d.sales_channel_id = sc.id
join product_visibility pv on pv.sales_channel_id = sc.id
join product p on p.id = pv.product_id
left outer join product p2 on p.id = p2.parent_id
where sc.active = 1
group by d.url, p.id, p.parent_id
)x
WHERE x.parent_id is null and x.children < 1
group by x.url

union all

SELECT x.url, 'main' type, count(x.id)
FROM (
select d.url, p.id, p.parent_id, count(p2.id) children from sales_channel_domain d
join sales_channel sc on d.sales_channel_id = sc.id
join product_visibility pv on pv.sales_channel_id = sc.id
join product p on p.id = pv.product_id
left outer join product p2 on p.id = p2.parent_id
where sc.active = 1
group by d.url, p.id, p.parent_id
)x
WHERE x.parent_id is null and x.children > 0
group by x.url

union all

SELECT x.url, 'variant' type, count(x.id)
FROM (
select d.url, p2.id, p2.parent_id, 0 children from sales_channel_domain d
join sales_channel sc on d.sales_channel_id = sc.id
join product_visibility pv on pv.sales_channel_id = sc.id
join product p on p.id = pv.product_id
left outer join product p2 on p.id = p2.parent_id
where sc.active = 1
)x
group by x.url


Shopware 6: Id und die DBAL-Connection

Gerade in Migrations kommt man manchmal in darum herum mit den UUIDs arbeiten zu müssen. Da es binary-Daten sind muss man etwas mit den anstellen, um die aus Shopware 6 bekannte Darstellung zu erreichen und auch um diese wieder die in Datenbank zu bekommen.

Lesen der Id:
Um die aus Shopware 6 gewohnte Darstellung zu bekommen muss man in MySQL die HEX-Function verwenden. Zusätzlich muss der String noch in Kleinbuchstaben umgewandelt werden.

Schreiben der Id:
Zuerst wieder alles in Großbuchstaben umwandelnt. Dann muss mit der MySQL-Function UNHEX der Hex-String wieder in binary Data umgewandelt werden.

Es bleibt zwar etwas umständlich, aber ist damit durch aus handhabbar. Da es in dem Sinne kein Autoincrement gibt für die UUIDs hilft dann dort Uuid::randomHex().


Shopware 6: Was schon alles damit entwickelt wurde

Ich arbeite nun doch schon einige Zeit mit Shopware 6. Während ich am Anfang vielen Konzepten etwas kritisch gegenüberstand, bin ich nun doch sehr von fast allen Dingen überzeugt. Ich habe viele verschiedene Dinge schon mit Shopware 6 realisiert und einiges wäre in Shopware 5 nicht so einfach gewesen.
Gerade Vue.js in der Administration ohne irgendwelche zusätzlichen Lizenzen nutzen zu können ist super. Ich mochte immer Vue + Bootstrap und Symfony. Also am Ende fühle ich mich so was von extrem in meinen Vorlieben bestätigt... wenn auch Shopware diese Kombinationen nutzt muss ich ja schon immer richtig gelegen haben :-)

Varianten sind immer noch viel zu kompliziert. Daten in das Model für Emails rein zubekommen ist wirklich viel zu umständlich. N:M Relation in DAL ist umständlich bzw wie früher mit puren SQL. Entweder alles vorher löschen oder sich merken was genutzt wird und alles was nicht dazugehört löschen. Aber am Ende kommt man ja gut damit klar... ist eben wie mit JDBC oder PDO direkt zu arbeiten und dass habe ich lange genug gemacht.

So.. aber was kann man alles mit Shopware 6 so alles bauen? Ich habe bis jetzt nur für Kunden direkt entwickelt und falls jemand etwas hier von gerne hätte, geht das leider nur über Anfrage und dann wird ein Angebot erstellt.

1. Adressänderungen verhindern
Wie schon bei Shopware 5 war es nötig, weil SAP sonst überfordert ist.

bbcode-image


2. Register-Form erweitern
Das zu Erweitern war am Ende sehr viel einfacher als gedacht und ich nutzt einfach das Data-Mapping Event für den Customer. Der richtige Weg? Für mich funktioniert er gut.

bbcode-image


3. Blog Einträge
Das kostenlose Blog-Plugin ist schon echt super. Es fehlt nur ein Flag um Posts von er Suche auszuschließen, Typen, Rechte über Rules und Datei-Anhänge. Ja.. ich weiß.. ich könnte mich da beteiligen und alles einbauen.. sollte ich wirklich machen. Aber bis jetzt war nur Zeit das Plugin zu erweitern um Rezepte aus einem Panipro-System zu importieren.

bbcode-image


Typen sind natürlich dynamisch und es werden nur Typen auf der linken Seite angezeigt, die auch gefunden wurden.

4. Bonuspunkte und passende Produkte
Produkte die man nur oder auch gegen Bonuspunkte kaufen kann. Das war etwas komplexer und man musste über Collector und Processor des Carts eingreifen. Heute würde ich wohl einiges ein wenig anders machen, aber nicht viel und auch nur minimale Änderungen.

bbcode-image


5. Konfigurator Style #1
So kann man sich z.B. Geschenkkörbe oder PCs/Notebooks konfigurieren. In der Administration kann man sich ein Config-Preset anlegen und es verschiedenen Products zuordnen.

bbcode-image


6. Konfigurator Style #2
Ein Produkt das z.B. Hackfleisch beinhaltet so konfigurieren in welchen Formen man das Hack gerne geliefert bekommen würde. Wurde als Teil von Punkt 7 entwickelt.

bbcode-image


7. Paket verkauf
Erst alle Pakete verkaufen und dann erst das Tier schlachten. Spart Lagerkosten und andere Aufwände. Hier habe ich gelernt warum Varianten noch immer umständlich sind und CustomFields zu syncen zwischen Varianten schlechter ist als eine eigene Entity dafür zu erstellen. Aber die Anforderungen waren zuerst so das CustomFields die einfacher Lösung waren.

In Aktion:
https://www.mein-elbtaler-shop.de/Bio-Rind-Demeter/ME-1130.1

Wem also etwas hier von gefallen hat, kann sich gerne melden. Wir freuen uns immer über Anfragen.

Shopware 6: Hauptvariante ändern

Etwas was bei Shopware 6 so komplett fehlt und wo ich schon mehrmals gehört habe, dass es Kunden/Benutzern Probleme macht, ist die Hauptvariante bei Shopware 6. Die Hauptvariante ist immer die Variante, die im Dialog beim Erzeugen der Varianten zuerst gewählt wurde. Es gibt danach keine Möglichkeit mehr es zu ändern.

An sich ist die Hauptvariante aber auch nur ein FK am Product. Man kann dort einfach eine andere Variante eintragen und schon hat man seine neue Hauptvariante. Also alles auf DB-Ebene sehr einfach.

Auch das in die Administration einbauen war dann relativ einfach. Man brauchte nur zusätzlich ein Repository und eine Criteria für Varianten (WHERE parent_id = ... ). Die Id kann man direkt per v-model setzen am Product.

https://gitlab.com/hpries/HPrMainVariant

Dort habe ich meine Implementierung einmal hinterlegt. Darf gerne verwendet werden, wenn jemand oder ein Kunde auch dieses Problem hat.

bbcode-image

Shopware 6: Non-Stackable Cart-Items

Gerade wenn man ein Produkt konfigurieren kann, ist es wichtig, dass CartItems nicht einfach aufaddiert werden, sondern jede Konfiguration als eigenes CartItem im Warenkorb abgelegt wird. Das CartItem von Shopware 6 hat auch ein stackable-Flag. Nun könnte man glauben, wenn man dieses auf false setzt, dass nicht das vorhandene CartItem geändert sondern ein neues angelegt wird, wenn erkannt wird, dass das vorhandene nicht stackable ist. Falsch! Man bekommt eine Exception.

Die Lösung ist zum Glück sehr einfach. Man muss selbst die Id des CartItems ändern um ein neues anzulegen. Also wenn man setStackable(false) setzt auch gleich die Id neu setzen. Oder man baut sich ein allgemeines Plugin, dass es macht.

BeforeLineItemAddedEvent:

if (!$event->getLineItem()->isStackable()) {
$event->getLineItem()->setId(Uuid::randomHex());
}

Systemd und Tomcat 9: ProcessBuilder Exceptions

Manchmal möchte man aus einem Tomcat heraus Processe und Programme aufrufen. Wie bei SQL-Injections muss man das natürlich stark absichern, aber das Konvertieren von Bildern und Video geschieht meistens auf diese Art und Weise.

Was aber wenn der Tomcat per ProcessBuilder nichts mehr aufrufen kann außerhalb seines Verzeichnisses, obwohl er alle Recht haben sollte? Wenn es ein System mit systemd ist (z.B. ein Ubuntu) ist, kann es einfach eine Security-Einstellung sein, die den Aufruf verhindert.

Hier muss man die Start-Config für den Service anpassen. "ProtectSystem=false" ist zum Prüfen der Lösung ganz gut, sollte aber später durch eine genauere Anpassung der ReadWritePaths geöst werden.

https://stackoverflow.com/questions/64038094/disable-sandbox-tomcat-9-ubuntu-20-04

Shopware 6: Placeholder Icon ersetzen

Bei Shopware 6 ist es etwas anders das Platzhalter-Bild für Produkte ohne Bilder zu ersetzen. An sich ist es ganz einfach, wenn man weiß wie es geht. Auch Anleitungen aus dem Internet von 2019 sind nicht mehr aktuell, denn es geht nun noch einfacher!

DAs Bild ist ein SVG-Icon mit dem Namen 'placeholder'. Man kann mit der Suche schnell herausfinden, wo es überall verwendet wird. Nun muss man nur ein eigenes Icon in per Plugin einbringen. Das ist auch an sich sehr einfach. Man legt einen Pfad in seinem Plugin an "src/Resources/app/storefront/dist/assets/icon/myiconpack/" und kopiert dort seine SVG-Datei rein. Die SVG kann auch gerne als placeholder.svg bennant sein. Nun muss man den Twig-Tag "sw_icon" noch um zwei Werte ergänzen. "pack" ist der oben im Pfad genutzte Icon-Pack Name und der "namesapce" ist einfach der Name des Plugins in dem man sich gerade befindet.


{% sw_icon 'placeholder' style {
'size': 'fluid',
'pack': 'myiconpack',
'namespace': 'MyPlugin'
} %}


Nun einmal die Storefront neu bauen und schon sollte das eigene Icon genutzt werden, da wo man die Shopware-Templates entsprechend extended hat.

bbcode-image

Shopware 5: Detail Meta-Description ändern

Einfach mal die Meta-Description mit einem Prefix versehen, um kleinere SEO-Probleme zu beheben. Klingt einfach und führt schnell zur Verzweiflung. frontend/detail/header.tpl angepasst und es funktioniert nicht. Keywords ändern ist kein Problem nur die Meta-Description des Artikels will sich nicht ändern.

Lösung
Wie man schnell vermutet wird die eigene Änderung überschrieben. Der Schuldige ist das SEO-Plugin und da muss man die index.tpl anpassen. Die Änderung kann z.B. so aussehen:


{block name='frontend_index_header_meta_description'}
{if $Controller=='detail'}
EAN:{$sArticle.ean} - {$SeoMetaDescription|truncate:150:"...":true}
{elseif $SeoMetaDescription}
{$SeoMetaDescription|truncate:150:"...":true}
{else}
{$smarty.block.parent}
{/if}
{/block}


Older posts:

Möchtest Du AdSense-Werbung erlauben und mir damit helfen die laufenden Kosten des Blogs tragen zu können?