Unterschiedliche Preise für das gleiche Produkt je nach Zugriffsland per Kundengruppe - aber welchen

Hallo zusammen!

Vorweg: Es geht mir nicht darum das Thema inhaltlich oder rechtlich zu diskutieren, das hab ich schon zur Genüge durch. Es geht nur um die Umsetzung.

Wir haben Herstellervorgaben, für bestimmte Artikel amerikanischen Kunden andere Preise anzuzeigen. Ich versuche das gerade aufgrund von Kundengruppen zu lösen, gibt ja diverse Plugins im Store, die z.B. mittels Kundengruppen andere Preise je nach Device zeigen. Für unseren konkreten Anwendungsfall gibt es aber nichts. Es gibt leider auch nicht die Möglichkeit, das über verschiedene Domains und damit verschiedene Subshops zu lösen.

Shopware ist aktuell mit 5.4.2, das setzen einer Kundengruppe ‚USA‘ aufgrund einer IP-Adress-Datenbank funktioniert auch problemlos. Aber der Cache grätscht mir jedes Mal dazwischen. Beim ersten Aufruf ist der Preis gern mal falsch und zwar in einem völlig anderen Browser bzw. sogar auf einem völlig anderen Device.

Aufruf in Safari mit US-IP über VPN, Cache frisch geleert: Alles gut. Preis stimmt und ist in US Dollar.

Trenne ich jetzt die VPN-Verbindung und rufe dann das gleiche Produkt z.B. in Firefox auf oder auch z.B. auf einem iPhone (also komplett anderes Device) habe ich immer noch Dollar. Ich müsste aber eigentlich Euro gezeigt bekommen.

Lade ich jetzt die Seite noch mal neu passt alles für den aktuellen Browser. Für den nächsten, der mit einem völlig anderen Device auf diese Seite kommt, vermutlich nicht.

Die Soll-Angabe im Template ist über einen ESI-Tag gelöst. Da ist also die überschriebene Kundengruppe richtig vorhanden. Zum Zeitpunkt wo der Cache entscheidet, die alte Seite auszuliefern, offensichtlich noch nicht (oder die Kundengruppe wird dafür gar nicht betrachtet).

Ich hab diverses ausprobiert:

$httpCache = $this->bootstrap->get('plugins')->Core()->HttpCache();
$httpCache->setNoCacheTag('price');

bringt keinerlei Erfolg.

Ich habe versucht die CacheID mit der Kundengruppe anzureichern und nutze dafür den Event Shopware_Plugins_HttpCache_GetCacheIds. Aber auch das bringt nichts.

Auch beim setzen der neuen Kundengruppe habe ich mittlerweile jeden Hookpoint durch der mir sinnvoll erschien:
Enlight_Controller_Front_StartDispatch
onInitResourceSystem
Enlight_Bootstrap_InitResource_http_cache.cache_control
Enlight_Bootstrap_InitResource_Modules
Enlight_Bootstrap_InitResource_System

Die Funktion macht selbst nicht viel (sCountry wird dabei von der Datenbankabfrage anhand der IP geliefert):
 

if((in_array($sCountry, ['US', 'CA', 'PR']))) {
	Shopware()->Session()->offsetSet('sUserGroup', 'USA');
	$this->get('shopware_storefront.context_service')->initializeShopContext();
	$oCustomerGroupModel = Shopware()->Models()->getRepository('Shopware\Models\Customer\Group');
	$oCustomerGroup = $oCustomerGroupModel->findOneBy(array('key' => 'USA'));
	$oCurrencyModel = Shopware()->Models()->getRepository('Shopware\Models\Shop\Currency');
	$oCurrency = $oCurrencyModel->findOneBy(array('currency' => 'USD'));
	Shopware()->Shop()->setCurrency($oCurrencyModel->findOneBy(array('currency' => 'USD')));
	Shopware()->Session()->offsetSet('wib_ip2location', $sCountry);
	Shopware()->Session()->offsetSet('wib_displayed_currency', 'USD');
	Shopware()->Shop()->registerResources(Shopware()->Bootstrap());
	return;
}

Immer das gleiche Bild: Der erste Aufruf, der von einer abweichenden Kundengruppe kommt, ist häufig falsch. Wenn ich dann noch unter Shopware_Plugins_HttpCache_GetCacheIds mitloggen lasse fällt auf, dass er im Fehlerfall die Funktion gar nicht aufruft. Also bin ich da entweder auch am falschen Hookpoint oder es ist nicht möglich eigene Cache-IDs zu ergänzen.

Bin über jeden Tipp dankbar was ich hier falsch mache und wie ich es vernünftig zum Laufen bekommen kann. Mehr Code kann ich gerne liefern wenn er benötigt wird. Das ganze über ESI-Tags zu lösen halte ich übrigens für keine gangbare Lösung, da bei einem Produktlisting ja jedes Produkt noch einmal geholt werden müsste um an den echten Preis zu kommen…

Matt
 

Hallo @msslovi0‍,

kannst du mir sagen welche Hookpoint benutzst du jetzt.

und kannst du die ganze Funktion schreiben.

und probier mal :

dass du rufst die  initializeShopContext funktion nach dem registerResources funktion.

VG,

 

Tel.: +49 755 - 183 990 00 | Web: http://enbit.de/

Danke, der Tausch von initalizieShopContext und registerRessources bringt leider keine Änderung. Derzeit nehme ich den Event Enlight_Controller_Front_StartDispatch. Der komplette Code sieht so aus (altes Plugin-Konzept, sollte ja aber kein Problem sein):

subscribeEvent(
            'Enlight_Controller_Front_StartDispatch',
            'onPreDispatch'
        );

        $this->_initDb();

        return array(
            'success' => true,
            // 'invalidateCache' => array( "frontend", "backend", "config" )
        );
    }

    /**
     * @param Enlight_Event_EventArgs $args
     */
    public function onPreDispatch(Enlight_Event_EventArgs $args) {
        $subject = $args->getSubject();
        if($subject->Request()->getModuleName() == "backend" || $subject->Request()->getModuleName() == "api") return;

        $httpCache = Shopware()->Plugins()->Core()->HttpCache();
        $httpCache->setNoCacheTag('price');

        $this->setZone($args->getRequest());
    }

    private function setZone($oRequest) {
        $sIP2Location = Shopware()->Session()->offsetGet('wib_ip2location');

        $sSql = sprintf("select country from geo_ip2location where ? between ip_from and ip_to");
        $oResult = Shopware()->Db()->query($sSql, array($this->ip2val($_SERVER['REMOTE_ADDR'])));
        $aIP2L = $oResult->fetch();
        $sCountry = $aIP2L['country'];
        // echo "*".$sCountry."*";

        if((gettype($sIP2Location)==='NULL')) {
            if(empty($sCountry)) {
                $sIP = $_SERVER['REMOTE_ADDR'];
                $sCountryInfo = file_get_contents("http://ipinfo.io/".($sIP)."/country");
                $aIP2L['country'] = $sCountryInfo;
                $sCountry = $sCountryInfo;
            }
            if((in_array($sCountry, ['US', 'CA', 'PR']))) {
                $oCustomerGroupModel = Shopware()->Models()->getRepository('Shopware\Models\Customer\Group');
                $oCustomerGroup = $oCustomerGroupModel->findOneBy(array('key' => 'USA'));
                $oCurrencyModel = Shopware()->Models()->getRepository('Shopware\Models\Shop\Currency');
                $oCurrency = $oCurrencyModel->findOneBy(array('currency' => 'USD'));
                Shopware()->Shop()->setCurrency($oCurrencyModel->findOneBy(array('currency' => 'USD')));
                Shopware()->Session()->offsetSet('wib_ip2location', $sCountry);
                Shopware()->Shop()->registerResources(Shopware()->Bootstrap());
                Shopware()->Session()->offsetSet('sUserGroup', 'USA');
                $this->get('shopware_storefront.context_service')->initializeShopContext();
                return;
            } else {
                $sCurrency = 'EUR';
                Shopware()->Session()->offsetSet('wib_ip2location', $sCountry);
                $oCustomerGroupModel = Shopware()->Models()->getRepository('Shopware\Models\Customer\Group');
                $oCustomerGroup = $oCustomerGroupModel->findOneBy(array('key' => 'EK'));
                $oCurrencyModel = Shopware()->Models()->getRepository('Shopware\Models\Shop\Currency');
                $oCurrency = $oCurrencyModel->findOneBy(array('currency' => $sCurrency));
                Shopware()->Shop()->setCurrency($oCurrencyModel->findOneBy(array('currency' => $sCurrency)));
                Shopware()->Shop()->registerResources(Shopware()->Bootstrap());
                Shopware()->Session()->offsetSet('sUserGroup', 'EK');
                $this->get('shopware_storefront.context_service')->initializeShopContext();
                return;
            }
        }
        return;
    }

    private function ip2val($sVal) {
        $iIP=0;
        $aParts=explode(".",$sVal);
        for($iCnt=0;$iCnt<4;$iCnt++) {
            $iIP=$iIP<<8;
            $iIP+=$aParts[$iCnt];
        }
        return $iIP;
    }

    private function _initDb() {
        $sSql = "CREATE TABLE IF NOT EXISTS `geo_ip2location` (
          `id` int(11) NOT NULL auto_increment,
          `ip_from` bigint(20) NOT NULL,
          `ip_to` bigint(20) NOT NULL,
          `ipdot_from` varchar(16) COLLATE utf8_unicode_ci NOT NULL,
          `ipdot_to` varchar(16) COLLATE utf8_unicode_ci NOT NULL,
          `country` varchar(2) COLLATE utf8_unicode_ci NOT NULL,
          PRIMARY KEY (`id`),
          KEY `ip_from_idx` (`ip_from`),
          KEY `ip_to_idx` (`ip_to`),
          KEY `country_idx` (`country`)
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;";
        Shopware()->Db()->query($sSql);

        $sSql = "TRUNCATE TABLE geo_ip2location;";
        Shopware()->Db()->query($sSql);

        $rFile = file_put_contents($this->Path().'geoip.zip', file_get_contents("http://download.maxmind.com/app/geoip_download?edition_id=108&suffix=zip&license_key=abc"));

        $this->zipFlatten($this->Path().'geoip.zip', $this->Path().'geoip/');

        $sSqlInsert = 'insert into geo_ip2location (ip_from, ip_to, ipdot_from, ipdot_to, country) values ';
        $rFile = fopen($this->Path()."geoip/GeoIP-108.csv", "r");
        $iCnt = 0;
        while(!feof($rFile)) {
            $aData = fgetcsv($rFile, 10000);
            if(!isset($aData[1]) || !is_numeric($aData[2])) {
                continue;
            }
            $sSqlInsert .= sprintf("(%d, %d, '%s', '%s', '%s'),\n",
                $aData[2],
                $aData[3],
                $aData[0],
                $aData[1],
                $aData[4]
            );
        }
        $sSqlInsert = preg_replace("/,$/",";",$sSqlInsert);
        Shopware()->Db()->query($sSqlInsert);
        fclose($rFile);
        unlink($this->Path()."geoip/GeoIP-108.csv");
        unlink($this->Path()."geoip/COPYRIGHT.txt");
        unlink($this->Path()."geoip/LICENSE.txt");
        unlink($this->Path()."geoip.zip");
    }

    private function zipFlatten($sZipFile, $sDest='.') {
        $oZip = new ZipArchive;
        if($oZip->open($sZipFile)) {
            for($iCnt=0;$iCntnumFiles;$iCnt++) {
                $sEntry = $oZip->getNameIndex($iCnt);
                if(substr($sEntry, -1 ) == '/') {
                    continue; // skip directories
                }

                $rFP = $oZip->getStream($sEntry);
                $rOFP = fopen($sDest.'/'.basename($sEntry), 'w');
                if(!$rFP) {
                    throw new Exception('Unable to extract the file.');
                }

                while(!feof($rFP)) {
                    fwrite($rOFP, fread($rFP, 8192));
                }
                fclose($rFP);
                fclose($rOFP);
            }
            $oZip->close();
        } else {
            return false;
        }
        return $oZip;
    }

    public function getInfo() {
        return [
            'version' => $this->getVersion(),
            'label' => $this->getLabel(),
            'author' => $this->getAuthor(),
            'link' => 'http://www.wibros.de/',
            'description' => file_get_contents($this->Path() . 'info.html')
        ];
    }
}

 

Niemand? Es muss doch möglich sein, dem Cache beizubringen, dass eine für die Kundengruppe USA gecachte Version eben nicht identisch ist mit einer für die Kundengruppe EK bzw. es muss doch einen Hookpoint geben, der bei Überschreiben der Kundengruppe dies dem Cache rechtzeitig und korrekt mitteilt…

Matt

Hi. Hast eine Lösung gefunden?

Nein, leider nicht.

Gruß

Matt

ich habe anders gemacht, aber wenn der Kunde eingellogt ist und andere SprachShop auswählt funktioniert nicht richtig (nur nach neuladen) und ich habe keine Ahnung warum

https://forum.shopware.com/discussion/62792/verschiedene-preise-kundengruppen-funktioniert-nicht-fuer-eingeloggte-kunden