Eine nette Funktion von xt:Commerce ist die “Erweiterte Suche” (Advanced Search), in der man neben gewünschten Kategorien, Herstellern etc. auch Preisbereiche angeben kann, aus denen die Ergebnisse kommen sollen.

Allerdings werden die Steuern der Artikel dabei nicht berücksichtigt. Gibt man also ein, man möchte alle Artikel bis maximal 100,- € angezeigt bekommen, sieht man als Kunde defacto alles, was exklusive der Steuern 100,- € und weniger kostet.

Im Regelfall werden daher alle Produkte bis 119,- € (statt bis 100,- €) gefunden.

Vadder Staat langt mit der vielgeliebten “Märchensteuer” seit jeher kräftigst zu, und so macht diese “kleine Ungenauigkeit” bei den Steuern (für die meisten Produkte) immerhin knapp ein Fünftel aus. Da darf man den Preisfilter von xt:C schon guten Gewissens als “etwas unpräzise” bezeichnen.

 

Abhilfe: (außer Auswandern)

In der Datei “advanced_search_result.php” wird die Datenbank-Abfrage für die Suche zusammengesetzt. Dort müssen wir also ansetzen.


1) Brauchen wir den Steuersatz?

Die “tax_rate” brauchen wir nur dann, wenn a) nach Preisen gefragt wird und b) die jeweilige Kundengruppe ihre Preise inklusive Steuern sehen soll.

Da sich die Datenbank-Abfrage, sobald wir die “tax_rate” benötigen, ändern (und ein bisschen verkomplizieren) wird, führen wir eine Kontroll-Variable $NeedTax ein, die zunächst einmal den Wert ‘false’ hat.

Ein geeigneter Punkt sind die Zeilen, in denen festgestellt wird, ob nach einem Preis gefragt wurde. Im Original Zeile 140 bis 149:


if ($_GET['pfrom'] || $_GET['pto']) {
	$rate = xtc_get_currencies_values($_SESSION['currency']);
	$rate = $rate['value'];
	if ($rate && $_GET['pfrom'] != '') {
		$pfrom = $_GET['pfrom'] / $rate;
	}
	if ($rate && $_GET['pto'] != '') {
		$pto = $_GET['pto'] / $rate;
	}
}
	

Diese Zeilen ändern wir wie folgt:


$NeedTax = false;
if ($_GET['pfrom'] || $_GET['pto']) {
	$rate = xtc_get_currencies_values($_SESSION['currency']);
	$rate = $rate['value'];
	if ($rate && $_GET['pfrom'] != '') {
		$pfrom = $_GET['pfrom'] / $rate;
	}
	if ($rate && $_GET['pto'] != '') {
		$pto = $_GET['pto'] / $rate;
	}
	if($_SESSION['customers_status']['customers_status_show_price_tax']) {
		$NeedTax = true;
	}
}
	


2) Der Preisfilter …

Als Nächstes ist der Preisfilter dran. Im Original wird nur der Artikelpreis bzw. der Sonderpreis (wenn vorhanden) ermittelt und mit den Werten aus $_GET['pfrom'] und $_GET['pto'] (”Preis von, Preis bis”) verglichen.

In der Original-Datei sind es die Zeilen 151 bis 162, nach unserer Änderung werden die Nummern ein bisschen verrutscht sein …
:-)
Aber zur Not hat man ja noch die Sicherheitskopie (Die hat man doch? Wink mit dem Zaunpfahl - Schnell eine machen!)


//price filters
if (($pfrom != '') && (is_numeric($pfrom))) {
	$pfrom_check = " AND (IF(s.status = '1' AND p.products_id = s.products_id, s.specials_new_products_price, p.products_price) >= ".$pfrom.") ";
} else {
	unset ($pfrom_check);
}

if (($pto != '') && (is_numeric($pto))) {
	$pto_check = " AND (IF(s.status = '1' AND p.products_id = s.products_id, s.specials_new_products_price, p.products_price) <= ".$pto." ) ";
} else {
	unset ($pto_check);
}
	

Diese Zeilen ändern wir - um die ‘tax_rate’ mit einzuberechnen - wie folgt:


//price filters
if (($pfrom != '') && (is_numeric($pfrom))) {
	if($NeedTax)
		$pfrom_check = " AND (IF(s.status = '1' AND p.products_id = s.products_id, s.specials_new_products_price, p.products_price) >= round((".$pfrom."/(1+tax_rate/100)),".PRICE_PRECISION.") ) ";
	else
		$pfrom_check = " AND (IF(s.status = '1' AND p.products_id = s.products_id, s.specials_new_products_price, p.products_price) >= round(".$pfrom.",".PRICE_PRECISION.") ) ";

} else {
	unset ($pfrom_check);
}

if (($pto != '') && (is_numeric($pto))) {
	if($NeedTax)
		$pto_check = " AND (IF(s.status = '1' AND p.products_id = s.products_id, s.specials_new_products_price, p.products_price) <= round((".$pto."/(1+tax_rate/100)),".PRICE_PRECISION.") ) ";
	else
		$pto_check = " AND (IF(s.status = '1' AND p.products_id = s.products_id, s.specials_new_products_price, p.products_price) <= round(".$pto.",".PRICE_PRECISION.") ) ";
} else {
	unset ($pto_check);
}
	

Als “Rundungsgenauigkeit” benutzen wir die Konstante PRICE_PRECISION, die (im Admin-Bereich eingestellt) für die Genauigkeit in Sachen Steuerberechnung genutzt wird.

Und, ja diese Rechnung stimmt:

Natürlich ist der Endpreis gleich dem Artikelpreis MAL eins-plus-tax_rate-durch-hundert.
Da an dieser Stelle aber nur der Artikelpreis bekannt ist, müssen wir die “Preis-von”- und die “Preis-bis”-Angabe DURCH eins-plus-tax_rate-durch-hundert teilen, um sie korrekt mit dem Grundpreis vergleichen zu können.


3) Der letzte Schritt: $from_str und $tax_where

Gegen Ende hat die Original “advanced_search_result.php” noch einen kleinen Fehler drin - Die Konstante DISPLAY_PRICE_WITH_TAX ist irgendwie immer leer.

Daher muss dieser Absatz - im Original Zeile 184 bis 193 - korrigiert werden:


if ((DISPLAY_PRICE_WITH_TAX == 'true') && ((isset ($_GET['pfrom']) && xtc_not_null($_GET['pfrom'])) || (isset ($_GET['pto']) && xtc_not_null($_GET['pto'])))) {
	if (!isset ($_SESSION['customer_country_id'])) {
		$_SESSION['customer_country_id'] = STORE_COUNTRY;
		$_SESSION['customer_zone_id'] = STORE_ZONE;
	}
	$from_str .= " LEFT OUTER JOIN ".TABLE_TAX_RATES." tr ON (p.products_tax_class_id = tr.tax_class_id) LEFT OUTER JOIN ".TABLE_ZONES_TO_GEO_ZONES." gz ON (tr.tax_zone_id = gz.geo_zone_id) ";
	$tax_where = " AND (gz.zone_country_id IS NULL OR gz.zone_country_id = '0' OR gz.zone_country_id = '".(int) $_SESSION['customer_country_id']."') AND (gz.zone_id is null OR gz.zone_id = '0' OR gz.zone_id = '".(int) $_SESSION['customer_zone_id']."')";
} else {
	unset ($tax_where);
}
	

Am besten wir nutzen dazu $NeedTax - und dann sieht das Ganze in etwa so aus:


if($NeedTax) {
	if (!isset ($_SESSION['customer_country_id'])) {
		$_SESSION['customer_country_id'] = STORE_COUNTRY;
		$_SESSION['customer_zone_id'] = STORE_ZONE;
	}
	$from_str .= " LEFT OUTER JOIN ".TABLE_TAX_RATES." tr ON (p.products_tax_class_id = tr.tax_class_id) LEFT OUTER JOIN ".TABLE_ZONES_TO_GEO_ZONES." gz ON (tr.tax_zone_id = gz.geo_zone_id) ";
	$tax_where = " AND (gz.zone_country_id IS NULL OR gz.zone_country_id = '0' OR gz.zone_country_id = '".(int) $_SESSION['customer_country_id']."') AND (gz.zone_id is null OR gz.zone_id = '0' OR gz.zone_id = '".(int) $_SESSION['customer_zone_id']."')";
} else {
	unset ($tax_where);
}
	

 

Download und Installation:

Wer diese Änderungen nicht selbst nachtragen möchte, kann sich hier die veränderte “advanced_search_result.php” (als ZIP-File) kostenlos herunterladen.

  1. Die Datei » advanced_search_result_tax01.zip downloaden und entpacken
  2. Mit der “advanced_search_result.php” (im Haupt-Ordner Ihres Shops, Sicherheitskopie nicht vergessen!) austauschen
  3. Und fertig

Hinweis: Diese Version ist eine bis auf die oben beschriebenen Bearbeitungen) unveränderte Original-Datei.

Tipp: Alle Änderungen im Code sind mit
(Änderungs-Anfang) // GUNNAR: irgendein Kommentar und
(Änderungs-Ende) //--> gekennzeichnet.
Der Original-Code ist nie komplett entfernt, sondern lediglich auskommentiert worden. So hat man’s beim Einbau einiger Erweiterungen (z.B. Sortier-Funktionen u.ä.) ein bisschen leichter.

 

Bitte beachten Sie:

  1. Ich kann nicht 100%ig ausschließen, dass weiterhin einige Preisgrenzen nicht korrekt gefunden werden, denn Rundungs-Ungenauigkeiten können hier und da eine Rolle spielen.
    In meinem Testsystem hatte ich z.B einen Artikel mit 149,- € (inkl. 19%) - Dieser wurde bei einer Preisgrenze bis 149,- € erst gefunden, nachdem ich die Rundungsgenauigkeit auf PRICE_PRECISION gesetzt hatte … Also ein bisschen was kann sicher noch daneben gehen, diese Fehler dürften jedoch den Cent-Bereich nicht überschreiten… Außerdem suchen die meisten Besucher nicht nach Fehlern, sondern nach Artikeln. Oder was machen Sie, wenn Sie einkaufen wollen?
  2. Händlerpreise: Für Kundengruppen, die ihre Preise exklusive Steuern angezeigt bekommen, ändert sich nichts. Wenn die ihre Suche auf Artikel unter 100,- € beschränken möchten, werden weiterhin auch die Artikel ausgegeben, die für “Normalsterbliche” 119,- € (bzw. 107,- €) kosten würden.
  3. Kompatibilität: Diese Datei ist getetestet mit xt:Commerce v3.04 SP2.1 - Aktuell nur für Shops mit einer Währung. Sollte jedoch auch für Shops mit mehreren Währungen hinhauen. Falls nicht, bitte ich um Nachsicht und vor allem um Nachricht.
  4. b careful: Wie immer gilt - Bitte nicht sofort mit einem Live-Shop ausprobieren.