Laut Preisangabenverordnung müssen in Online-Shops Mehrwertsteuer sowie Hinweise auf Versandkosten deutlich sichtbar angezeigt werden. Ein “allgemeiner” Hinweis am unteren Seitenrand sollte nach gesundem Menschenverstand eigentlich ausreichen - außerdem rechnet vermutlich kaum ein Versandhandels-Kunde damit, Porto und Verpackungskosten geschenkt zu bekommen - dennoch gibt es, wie u.a. bei Internetrecht-Rostock.de zu lesen ist, auch Urteile, in denen eine andere Meinung durchgesetzt wurde.

Vor teuren Abmahnungen scheint man also am sichersten zu sein, wenn man direkt unter oder neben jeder Preis-Angabe auch gleich den enthaltenen Mehrwertsteuersatz sowie die Versandkosten anzeigt.

xt:Commerce ist standardmäßig schon ganz gut ausgerüstet - aber in einigen Produkt-Auflistungen gibt es keine vorgefertigte Funktion, mit der man sich den jeweils gültigen Steuersatz anzeigen lassen kann.

Man könnte jetzt natürlich in Klarschrift den Hinweis “inkl. 16% USt.” nebst Versandkosten-Link direkt in allen Template-Dateien nachtragen, denen diese Information fehlt.

Damit bringt man sich allerdings in Schwierigkeiten, wenn man …

  • einen mehrsprachigen Shop betreibt
  • unterschiedlich besteuerte Artikel anbietet
  • nicht nur an Endkunden, sondern auch an Händler verkauft

Der saubere Weg ist also der, sich Steuern und Versandkosten-Link vom System generieren zu lassen und nicht “hartcodiert” irgendwelche Texte und Links in sein Template zu schreiben. Vor allem der angezeigte Steuersatz muss zum Artikel bzw. zur Kundengruppe passen.

 

Bestandsaufnahme

In sämtlichen “boxes” (linke und rechte Spalte), die Preise anzeigen, fehlen Steuersatz und Versandkosten-Info:

  • “box_whatsnew.html”
    (zufällige Anzeige eines neuen Produkts)
  • “box_specials.html”
    (zufällige Anzeige eines Sonderangebotes)
  • “box_best_sellers.html”
    (Auflistung der bestverkauften Produkte, abhängig von der aktiven Shop–Kategorie)
  • “box_last_viewed.html”
    (Zuletzt angesehene Artikel)

Im Content-Bereich (also in der mittleren Spalte) sieht’s besser aus, dort fehlen diese Infos nur bei:

  • “also_purchased.html”
    (Kunden, die dies gekauft haben, haben auch jenes gekauft)
  • “cross_selling” und “reverse_cross_selling.html”
    (zu diesem Produkt empfehlen wir …)
  • “account.html”
    (”Ihr Konto” - die dort erscheinende Auflistung der zuletzt angesehenen Artikel)

Alle anderen Bereiche, in denen Preise angezeigt werden, sind komplett:

  • Produktbeschreibungen
    (die Einzel-Ansicht eines Produktes)
  • “normale” Produktlisten
    (also Anzeige mehrerer Produkte nach Hersteller, Kategorie oder als Suchergebnis)
  • die Auflistung der neuesten Produkte
    (normalerweise auf der Shop-Startseite)
  • “Specials”-Liste
    (die Sonderangebote … übrigens gibt’s dort überraschenderweise keinen “Jetzt kaufen!”-Knopf. Auch das werden wir ändern.)

 

Es gibt viel zu tun

Die Versandkosten-Info wird von xt:Commerce in einem PopUp angezeigt, das für Besucher mit abgeschaltetem JavaScript allerdings schlichtweg nicht erreichbar ist. Es wird oft empfohlen, diese Links so umzugestalten, dass sie auch ohne JavaScript funktionieren.

Auf der Seite “Ihr Konto” gibt’s zudem (manchmal) einen kleinen Fehler: Dort werden dem Besucher die zuletzt angesehenen Produkte gezeigt. Der “Jetzt kaufen!”-Knopf funktioniert in dieser Auflistung aber nicht, wenn man für seinen Shop die Option “Suchmaschinenfreundliche URLs benutzen” aktiviert hat

Die Liste der zu bearbeitenden Dateien ist inzwischen recht lang geworden:

Template-Files

  • meinshop.de/templates/meintemplate/source/boxes/best_sellers.php
  • meinshop.de/templates/meintemplate/source/boxes/last_viewed.php
  • meinshop.de/templates/meintemplate/source/boxes/specials.php
  • meinshop.de/templates/meintemplate/source/boxes/whats_new.php

Diese Dateien müssen bearbeitet werden, damit den (oben aufgelisteten) html-”Box”-Dateien im Template die entsprechenden Tags wie z.B. {$box_data.TAX_INFO} oder {$box_data.PRODUCTS_SHIPPING_LINK} zur Verfügung stehen.

System-Dateien 1

  • meinshop.de/account.php
  • meinshop.de/includes/modules/product_info.php

In diesen Dateien befinden sich die Ausgabe-Funktionen von den (ebenfalls oben aufgeführten) Produkt-Auflistungen, denen die benötigten Tags für Steuersatz und Versandkosten-Link fehlen.

System-Dateien 2

  • meinshop.de/specials.php
  • meinshop.de/includes/modules/new_products.php
  • meinshop.de/includes/modules/product_info.php
  • meinshop.de/includes/modules/product_listing.php

Diese Dateien sind komplett - bloß wenn man schon mal dabei ist, kann man auch gleich die den JavaScript-Link zu den Versandkosten umbauen. Außerdem vermisse bestimmt nicht nur ich einen “Jetzt kaufen!”-Knopf bei der Auflistung von Sonderangeboten.

 

Beispiel - Vorlage

Angesichts der Anzahl zu bearbeitender Dateien werde ich nicht auf jede einzelne eingehen, sondern nur an einem Beispiel zeigen, wie man eine Produkt-Auflistung um die fehlenden {$irgendwas.TAX_INFO} bzw. {$irgendwas.PRODUCTS_SHIPPING_LINK}-Tags erweitert.

Unten gibt’s übrigens alles als Download …

Zunächst einmal brauchen wir eine Vorlage, in der “alles drin” ist, was benötigt wird. Dazu bietet sich die “product_listing.php” an. In Zeile 91 bis 105 wird überprüft, ob der Besucher in einer Kundengruppe ist, für die ein Steuersatz angezeigt werden soll, welcher Steuersatz für das jeweilige Produkt gilt - und dann die erforderliche Anzeige in die Variable $tax_info geschrieben:

if ($_SESSION['customers_status']['customers_status_show_price'] != 0) {
	$tax_rate = $xtPrice->TAX[$listing['products_tax_class_id']];
	// price incl tax
	if ($tax_rate > 0 && $_SESSION['customers_status']['customers_status_show_price_tax'] != 0) {
		$tax_info = sprintf(TAX_INFO_INCL, $tax_rate.' %');
	}
	// excl tax + tax at checkout
	if ($tax_rate > 0 && $_SESSION['customers_status']['customers_status_show_price_tax'] == 0 && $_SESSION['customers_status']['customers_status_add_tax_ot'] == 1) {
		$tax_info = sprintf(TAX_INFO_ADD, $tax_rate.' %');
	}
	// excl tax
	if ($tax_rate > 0 && $_SESSION['customers_status']['customers_status_show_price_tax'] == 0 && $_SESSION['customers_status']['customers_status_add_tax_ot'] == 0) {
		$tax_info = sprintf(TAX_INFO_EXCL, $tax_rate.' %');
	}
}
	

Direkt danach (Zeile 106 bis 109) wird - sofern Versandkosten-angezeigt werden sollen - der HTML-Text des Versandkosten-Links in der Variablen $ship_info abgelegt.

$ship_info="";
if (SHOW_SHIPPING=='true') {
	$ship_info=' '.SHIPPING_EXCL.'<a href="javascript:newWin=void(window.open(\''.xtc_href_link(FILENAME_POPUP_CONTENT, 'coID='.SHIPPING_INFOS).'\', \'popup\', \'toolbar=0, width=640, height=600\'))"> '.SHIPPING_COSTS.'</a>';
	}
	

Den Versandkosten-Link kann man bei der Gelegenheit gleich so umbauen, dass er auch ohne JavaScript funktioniert. Man könnte jetzt einfach einen ganz “normalen” Link mit “target=_blank” einsetzen, aber dann würden alle Besucher auf das PopUp verzichten müssen.

Und ich persönlich finde es ja schon ganz schick, wenn sich die Versandkosten in passender Größe und ohne Adresszeile öffnen. Benutzt man nur “target=_blank”, kann’s gut passieren, dass der Klick auf die Versandkosten gleich ein maximiertes Browser-Fenster über den Shop setzt. Da darf man meiner Meinung nach ruhig mal die “guten Sitten” über Bord werfen und ausnahmsweise PopUp-Links gut finden :-)

Also schlage ich die Wahl einer Variante vor, mit der Beides möglich ist:

Ein normaler Link innerhalb eines <span onClick="window.open(…..)"><span> Dass dadurch für Besucher mit JavaScript bei Klick gleich zwei Fenster geöffnet werden, kann man vermeiden, in dem man für beide Links bei “target= …” das selbe Ziel einträgt.

if (SHOW_SHIPPING=='true') {
	$ship_info= ' '.SHIPPING_EXCL.' <span onClick="window.open(\''.xtc_href_link(FILENAME_POPUP_CONTENT, 'coID='.SHIPPING_INFOS).'\', \'popup\', \'toolbar=0\', \'menubar=0\', \'width=640\', \'height=600\')"><a target="popup" href="'.xtc_href_link(FILENAME_POPUP_CONTENT, 'coID='.SHIPPING_INFOS).'">'.SHIPPING_COSTS.'</a></span>';
	}
	

Von Zeile 110 bis 124 werden die {$irgendwas}-Tags bezeichnet und mit Werten gefüllt, die im Template bei Produkt-Auflistungen zur Verfügung stehen:

$module_content[] = array ('PRODUCTS_NAME' => $listing['products_name'],
	   'PRODUCTS_MODEL' => $listing['products_model'],
 	   'PRODUCTS_EAN' => $listing['products_ean'],
	   'PRODUCTS_TAX_INFO' => $tax_info,
	   'PRODUCTS_SHIPPING_LINK' => $ship_info,
	   'PRODUCTS_SHORT_DESCRIPTION' => $listing['products_short_description'],
	   'PRODUCTS_IMAGE' => $image,
	   'PRODUCTS_PRICE' => $price['formated'],
	   'PRODUCTS_VPE' => $vpePrice,
	   'PRODUCTS_LINK' => xtc_href_link(FILENAME_PRODUCT_INFO, xtc_product_link($listing['products_id'],$listing['products_name'])),
	   'BUTTON_BUY_NOW' => $buy_now,
	   'PRODUCTS_FSK18' => $fsk18,
	   'SHIPPING_NAME' => $shipping_status_name,
	   'SHIPPING_IMAGE' => $shipping_status_image,
	   'PRODUCTS_ID' => $listing['products_id']);
	   

Damit hätten wir unsere Vorlage. Die Zeilen 91 bis 124 sollte man kopieren und am Besten einen Text-Editor zum “Zwischenlagern” öffnen und dort erst einmal einfügen.

 

Beispiel - Bearbeitung

Hier hab ich mich für die Artikel-Auflistung im Bereich “Ihr Konto” entschieden - Auch weil dort der “Jetzt kaufen!”-Knopf nicht immer funktioniert. In der Datei “account.php” (zu finden im Hauptverzeichnis des Shops) werden die Tags, die man für die Auflistung der zuletzt angesehenen Produkte braucht, von Zeile 40 bis 60 innerhalb einer Schleife erzeugt.

$i = 0;
$max = count($_SESSION['tracking']['products_history']);

while ($i < $max) {

	$product_history_query = xtDBquery("select * from ".TABLE_PRODUCTS." where products_status = '1' and products_id = '".$_SESSION['tracking']['products_history'][$i]."'");
	$history_product = xtc_db_fetch_array($product_history_query, true);
	$products_name = xtc_get_products_name($_SESSION['tracking']['products_history'][$i]);
	$products_image = xtc_get_products_image((int) $_SESSION['tracking']['products_history'][$i]);
	$products_price = $xtPrice->xtcGetPrice($history_product['products_id'], $format = true, 1, $history_product['products_tax_class_id'], $history_product['products_price']);
	$buy_now = '<a href="'.xtc_href_link(basename($PHP_SELF), xtc_get_all_get_params(array ('action')).'action=buy_now&amp;BUYproducts_id='.$_SESSION['tracking']['products_history'][$i], 'NONSSL').'">'.xtc_image_button('button_buy_now.gif', TEXT_BUY.$products_name.TEXT_NOW).'</a>';
	$cpath = xtc_get_product_path($_SESSION['tracking']['products_history'][$i]);
	if ($history_product['products_status'] != 0) {
		$products_history[] = array ('PRODUCTS_NAME' => $products_name,
			'PRODUCTS_IMAGE' => DIR_WS_THUMBNAIL_IMAGES.$products_image,
			'PRODUCTS_PRICE' => $products_price,
			'PRODUCTS_URL' => xtc_href_link(FILENAME_PRODUCT_INFO, xtc_product_link($_SESSION['tracking']['products_history'][$i],$products_name)),
			'PRODUCTS_CATEGORY_URL' => xtc_href_link(FILENAME_DEFAULT, 'cPath='.$cpath), 'BUY_NOW_BUTTON' => $buy_now);
		$i ++;
	}
}
	

Zunächst ist der “Jetzt kaufen!”-Button an der Reihe. Wenn Suchmaschinen freundliche URLs aktiviert sind, funktioniert der Knopf nicht - dazu muss man in der Zeile 50 buy_now&amp;BUYproducts_id durch action=buy_now&BUYproducts_id ersetzen.

Wenn man öfter Shops aufsetzt - und mal SEF-Links möglich sind und mal nicht - kann’s gut sein, dass man vielleicht vergisst, diesen Knopf auf Funktionsfähigkeit zu prüfen. Deshalb würde ich an dieser Stelle eine Fallunterscheidung vorschlagen:

if (SEARCH_ENGINE_FRIENDLY_URLS == 'true') {
	$buy_now = '<a href="'.xtc_href_link(basename($PHP_SELF), xtc_get_all_get_params(array ('action')).'action=buy_now&BUYproducts_id='.$_SESSION['tracking']['products_history'][$i], 'NONSSL').'">'.xtc_image_button('button_buy_now.gif', TEXT_BUY.$products_name.TEXT_NOW).'</a>';
} else {
	$buy_now = '<a href="'.xtc_href_link(basename($PHP_SELF), xtc_get_all_get_params(array ('action')).'action=buy_now&amp;BUYproducts_id='.$_SESSION['tracking']['products_history'][$i], 'NONSSL').'">'.xtc_image_button('button_buy_now.gif', TEXT_BUY.$products_name.TEXT_NOW).'</a>';
}
	

Zwischen Zeile 49 und Zeile 50 (also direkt nach der Zeile, die mit $products_price = … beginnt) dann aus der “Vorlage” den Bereich einfügen, mit dem Steuersatz und Versandkosten-Link erzeugt werden.

Update! Die Zeile $tax_rate = $xtPrice->TAX[$listing['products_tax_class_id']]; muss dabei angepasst werden: $tax_rate = $xtPrice->TAX[$history_product['products_tax_class_id']];

Es ergibt sich:

if ($_SESSION['customers_status']['customers_status_show_price'] != 0) {
	$tax_rate = $xtPrice->TAX[$history_product['products_tax_class_id']];
	// price incl tax
	if ($tax_rate > 0 && $_SESSION['customers_status']['customers_status_show_price_tax'] != 0) {
		$tax_info = sprintf(TAX_INFO_INCL, $tax_rate.' %');
	}
	// excl tax + tax at checkout
	if ($tax_rate > 0 && $_SESSION['customers_status']['customers_status_show_price_tax'] == 0 && $_SESSION['customers_status']['customers_status_add_tax_ot'] == 1) {
		$tax_info = sprintf(TAX_INFO_ADD, $tax_rate.' %');
	}
	// excl tax
	if ($tax_rate > 0 && $_SESSION['customers_status']['customers_status_show_price_tax'] == 0 && $_SESSION['customers_status']['customers_status_add_tax_ot'] == 0) {
		$tax_info = sprintf(TAX_INFO_EXCL, $tax_rate.' %');
	}
}
$ship_info="";
if (SHOW_SHIPPING=='true') {
	$ship_info=' '.SHIPPING_EXCL.' <span onClick="window.open(\''.xtc_href_link(FILENAME_POPUP_CONTENT, 'coID='.SHIPPING_INFOS).'\', \'popup\', \'toolbar=0\', \'menubar=0\', \'width=640\', \'height=600\')"><a target="popup" href="'.xtc_href_link(FILENAME_POPUP_CONTENT, 'coID='.SHIPPING_INFOS).'">'.SHIPPING_COSTS.'</a></span>';
	}
	

Damit wären die Variablen bezeichnet und gefüllt, aus denen im letzten vorletzten Schritt weiter unten die Tags {$products_history.PRODUCTS_TAX_INFO} und {$products_history.PRODUCTS_SHIPPING_LINK} gebildet werden sollen, die danach in der Datei “account.html” (im Template-Ordner “module”) zur Verfügung stehen.

Der Array $products_history[] muss also noch erweitert werden:

$products_history[] = array ('PRODUCTS_NAME' => $products_name,
	 'PRODUCTS_IMAGE' => DIR_WS_THUMBNAIL_IMAGES.$products_image,
	 'PRODUCTS_PRICE' => $products_price,
	 'PRODUCTS_TAX_INFO' => $tax_info, // adding tax info
	 'PRODUCTS_SHIPPING_LINK' => $ship_info, // adding shipping link
	 'PRODUCTS_URL' => xtc_href_link(FILENAME_PRODUCT_INFO, xtc_product_link($_SESSION['tracking']['products_history'][$i],$products_name)),
	 'PRODUCTS_CATEGORY_URL' => xtc_href_link(FILENAME_DEFAULT, 'cPath='.$cpath), 'BUY_NOW_BUTTON' => $buy_now);
	 

Jetzt kann man in seiner “account.html” mit oben genannten Tags auch Steuersatz und Versandkosten-Info ausgeben lassen.

Nach diesem Muster sind auch die anderen (oben angegebenen) System- bzw. Template-Dateien zu erweitern. Dort ist dann aber natürlich keine Bearbeitung des Kaufen-Buttons nötig.

In manchen dieser Dateien werden allerdings keine Auflistungen erzeugt, sondern nur einzelne Artikel gezeigt. Dort ändert sich an der Verfahrensweise jedoch auch nicht viel - Es gibt dann bloß bei den Smarty-Zuweisungen ein paar Änderungen.

 

Alle Dateien als Download

Da dieser Beitrag reichlich lang werden würde, wenn ich für zehn Dateien alle Änderungen ausführlich beschreibe, stelle ich alle genannten die System- und Template-Source-Dateien fertig bearbeitet zum Download zur Verfügung.

1. August 2006

Korrekturen: Einige Dateien im alten Set waren fehlerhaft und haben keinen Steuersatz ausgegeben. Da sind mir vermutlich ein paar ungetestete Versionen dazwischen gerutscht - ich bitte um Entschuldigung. Mit der “Version 4″ dürfte aber alle Fehler behoben sein.

Update: Zusätzlich ist in der Datei “meinshop.de/includes/classes/product.php” die hier beschriebene Korrektur bei der Berechnung von Staffelpreisen mit gleichzeitigem Artikel-Rabatt umgesetzt.

Update: Um verwirrende Preisangaben zu vermeiden, wird außerdem in der Datei “meinshop.de/includes/modules/product_info.php” die Anzeige von Staffelpreisen und Artikel-Rabatt unterbunden, sofern ein Sonderpreis für den jeweiligen Artikel vorliegt. Siehe hier

Bitte nutzen Sie die aktuellste Version!

Inhalt

  • meinshop.de/account.php
  • meinshop.de/specials.php
  • meinshop.de/includes/classes/product.php
  • meinshop.de/includes/modules/new_products.php
  • meinshop.de/includes/modules/product_info.php
  • meinshop.de/includes/modules/product_listing.php
  • meinshop.de/templates/meintemplate/source/boxes/best_sellers.php
  • meinshop.de/templates/meintemplate/source/boxes/last_viewed.php
  • meinshop.de/templates/meintemplate/source/boxes/specials.php
  • meinshop.de/templates/meintemplate/source/boxes/whats_new.php

Änderungen

  • Versandkosten-Link überall auch ohne JavaScript funktionsfähig
  • “Jetzt kaufen!”-Button im Bereich “Ihr Konto” (hoffentlich) gefixt
  • In jeder Template-Datei, in der Preise auftauchen, gibt’s ein Tag für Versandkosten und Steuersatz
  • Bei der Artikel-Auflistung von Sonderangeboten gibt’s ein Tag für einen “Jetzt kaufen!”-Knopf

Achtung: In xt:Commerce gibt’s mehrere gleich benannte System-Dateien z.B. “product_info.php” - Ein bisschen muss man beim Hochladen also aufpassen … Damit es da kein Durcheinander gibt, habe ich die Dateien in der entsprechenden Ordner-Struktur zusammen mit einem Info-Text gezippt.

Mit dem Hochladen ist die Arbeit aber noch nicht ganz abgeschlossen - denn jetzt stehen die Funktionen bloß an jeder Steller zur Verfügung. Im Template müssen die entsprechenden Tags natürlich noch überall nachgetragen werden, wo Versandkosten und Steuersatz fehlen. In jeder geänderten Datei steht am Anfang im Kommentar-Bereich, welche Tags durch die Bearbeitung in welchen Template-HTML-Dateien hinzugekommen sind.

Und wie immer: Sicherheitskopien anfertigen! Denn in diesem Fall sind auch etliche Dateien dabei, die zum xt:Commerce-System gehören. Außerdem sollte man sich irgendwo notieren, welche Dateien man geändert hat bzw. die Sicherheitskopien gleich online lassen - damit man bei eventuellen Software-Updates keine Probleme hat.

 

 

Alle Dateien sind für xt:Commerce 3.04 SP1 erstellt und auch nur mit dieser Version getestet. Sollten Sie eine andere Version installiert haben, rate ich von der Verwendung der zur Verfügung gestellten Dateien ab. Einer Haftung für eventuelle System-Ausfälle widerspreche ich ausdrücklich.

Bitte beachten Sie unbedingt die allgemeinen Hinweise zur Verwendung hier veröffentlichter Code-Beispiele!