Grundpreis - Vorschlag zur richtigen Berechnung

Grundpreisberechnung bisher:

in shop/core/oxaerticle.php wird der Grundpreis berechnet (zur Laufzeit, wird nicht in DB abgelegt), Zeilen 3915ff:

//price per unit handling
        if ((double) $this->oxarticles__oxunitquantity->value && $this->oxarticles__oxunitname->value) {
            $this->_fPricePerUnit = oxLang::getInstance()->formatCurrency($dPrice / (double) $this->oxarticles__oxunitquantity->value, $oCur);
        }

Dies nützt nur in wenigen Fällen, Problem: Bei z. B. 500ml Himbeersirup wird der Grundpreis für 1ml berechnet, richtig wäre aber für 1Liter,

bei 200g-Tafel Schokolade wird der Grundpreis für 1g berechnet, richtig wären 100g, bei 0,3L Bio-Kölsch wird 1Liter berechnet, richtig wären (meines Wissens) 100ml.

Problemlösung (Vorschlag von einem Ahnungslosen bez. PHP und Smarty, also alles unverbindlich und bitte gern Verbesserungsvorschläge):

[B]1. [/B]Weil ich die Daten aus oxunitquantity und oxunitname nicht nur zur Grundpreisberechnung nutze, sondern auch in den Templates zum Anzeigen des

Inhalts der Artikel (was ja juristisch fraglos auch nötig ist, was oxid aber nicht berücksichtigt), muss zunächst eine String-Variable definiert

werden, die die Berechnungsbasis des Grundpreises (z. B. ‘100ml’) anzeigen wird:

nach Zeile 177 in shop/core/oxaerticle.php einfügen:


protected $_Grundpreiseinheit = '';

[B]
2.[/B] Die ursprünglichen Zeilen zum price per unit handling (s. o.) ersetzen durch:

//price per unit handling, Ehlert: modifiziert!

        if ((double) $this->oxarticles__oxunitquantity->value && $this->oxarticles__oxunitname->value) { //berechne nur, wenn beide Werte vorliegen
           switch($this->oxarticles__oxunitname->value) {

            case 'g':
                 if ($this->oxarticles__oxunitquantity->value<=400) {
                 $this->_fPricePerUnit = oxLang::getInstance()->formatCurrency($dPrice / (double) $this->oxarticles__oxunitquantity->value * 100, $oCur);$this->_Grundpreiseinheit->value='100g';
                 break; }
                 if ($this->oxarticles__oxunitquantity->value>400) {
                 $this->_fPricePerUnit = oxLang::getInstance()->formatCurrency($dPrice / (double) $this->oxarticles__oxunitquantity->value * 1000, $oCur);$this->_Grundpreiseinheit->value='Kg';
                 break; }
            case 'Kg':
                 if ($this->oxarticles__oxunitquantity->value<=0.4) {
                 $this->_fPricePerUnit = oxLang::getInstance()->formatCurrency($dPrice / (double) $this->oxarticles__oxunitquantity->value / 10, $oCur);$this->_Grundpreiseinheit->value='100g';
                 break; }
                 if ($this->oxarticles__oxunitquantity->value>0.4) {
                 $this->_fPricePerUnit = oxLang::getInstance()->formatCurrency($dPrice / (double) $this->oxarticles__oxunitquantity->value, $oCur);$this->_Grundpreiseinheit->value='Kg';
                 break; }

            case 'ml':
                 if ($this->oxarticles__oxunitquantity->value<=400) {
                 $this->_fPricePerUnit = oxLang::getInstance()->formatCurrency($dPrice / (double) $this->oxarticles__oxunitquantity->value * 100, $oCur);$this->_Grundpreiseinheit->value='100ml';
                 break; }
                 if ($this->oxarticles__oxunitquantity->value>400) {
                 $this->_fPricePerUnit = oxLang::getInstance()->formatCurrency($dPrice / (double) $this->oxarticles__oxunitquantity->value * 1000, $oCur);$this->_Grundpreiseinheit->value='L';
                 break; }
            case 'L':
                 if ($this->oxarticles__oxunitquantity->value<=0.4) {
                 $this->_fPricePerUnit = oxLang::getInstance()->formatCurrency($dPrice / (double) $this->oxarticles__oxunitquantity->value / 10, $oCur);$this->_Grundpreiseinheit->value='100ml';
                 break; }
                 if ($this->oxarticles__oxunitquantity->value>0.4) {
                 $this->_fPricePerUnit = oxLang::getInstance()->formatCurrency($dPrice / (double) $this->oxarticles__oxunitquantity->value, $oCur);$this->_Grundpreiseinheit->value='L';
                 break; }


         } //switch-Ende
        }
        //Ehlert ENDE

Hier kann natürlich nach Bedarf ergänzt werden (z. B. Meter/ml). ‘Stück’ ist hier nicht berücksichtigt, weil zumindest in meiner Branche bei Stückangaben kein Grundpreis nötig ist.
Es kann sein, dass ich mich bei der Splittung <=400 irre, muss nochmal in der Grundpreisverordnung gucken.

[B]3.[/B] Grundpreis in Templates einbauen:

z. B. in details.tpl einbauen:

[{if $product->getPricePerUnit()}]
    <div id="test_product_price_unit" class="pperunit">
        ([{$product->getPricePerUnit()}][{$currency->sign}]/[{$product->_Grundpreiseinheit->value}])
    </div>
    [{/if}]

Sicherlich kann man die Fallunterscheidung auch viel eleganter lösen.
Aber worauf es mir ankam: Bei mir funktionerts!

Tschö
Ralf

[QUOTE=muwi;42032]Dies nützt nur in wenigen Fällen, Problem: Bei z. B. 500ml Himbeersirup wird der Grundpreis für 1ml berechnet, richtig wäre aber für 1Liter,

bei 200g-Tafel Schokolade wird der Grundpreis für 1g berechnet, richtig wären 100g, bei 0,3L Bio-Kölsch wird 1Liter berechnet, richtig wären (meines Wissens) 100ml.[/QUOTE]
Ist das so?

Wäre ein “dicker Hund”, weil das gegen die Preisangabenverordnung (PangV ) verstößt.

Würde mich schon wundern, wenn man damit ein “Trusted Shop”-Siegel bekäme, weil das ja auch die Rechstkonformität eines Shops mit prüft.

Habe mir das gerade mal im Demo-Shop angesehen:

Ich denke, Du hast da was in den Einstellungen falsch gemacht…

Die Erläuterung zu den Grundpreisen im Admin ist wie folgt:

Mit Menge und Mengeneinheit können Sie den Grundpreis des Artikels (Preis pro Mengeneinheit) einstellen (z. B. 1,43 EUR pro Liter): Geben Sie bei Menge die Menge des Artikels (z. B. 1,5) und bei Mengeneinheit die entsprechende Mengeneinheit (z. B. Liter) ein. Dann wird der Grundpreis pro Mengeneinheit berechnet und beim Artikel angezeigt.
Demnach kann man das sehr wohl richtig definieren, so dass es der PangV entspricht.

[QUOTE=muwi;42033]besser nicht aus dem Glashaus heraus mit Steinen auf den Monitor werfen.D
[/QUOTE]
@muwi: Ich werde mir Mühe geben, … aber

Wie ich schonmal gepostet habe:

Geben Sie bei Menge die Menge des Artikels (z. B. 1,5) und bei Mengeneinheit die entsprechende Mengeneinheit (z. B. Liter) ein. Dann wird der Grundpreis pro Mengeneinheit berechnet und beim Artikel angezeigt.

Kannst du mir mal erklären wie du den Hilfetext verstanden hast ? Was ist den die Menge des Artikels?

Immerhin hast du für dich eine Lösung gefunden die klappt. Alle anderen sollten aber bei der funktionierenden Lösung des Standard bleiben und die Menge des Artikels korrekt eintragen.
Versuch einfach mal dort “0,25” “2,5” und “250” einzutragen. Die Mengeneinheit sollte dann dem entsprechend gewählt werden.

P.S.: Kennst du den Spruch: Wenn man einen Hammer in der Hand hat sieht jedes Problem wie ein Nagel aus.
CYA

firefax, bitte einfach mal die Grundberechnung von oxid angucken und entdecken, dass man bei ganz korrekter Eingabe laut Anleitung - wie ich deutlichst beschrieben habe - das juristisch falsche Ergebnis erhält!
EINE GRUNDPREISANGABE wie 0,01Euro pro g ist FALSCH, aber genau das berechnet oxid, wenn man z. B. 250g und als Preis 2,79 eingibt. GRundpreise MÜSSEN in bestimmten Fällen (lies einfach den oben gegebenen PHP-Vorschlag) auf 100g und 100ml bezogen werden und das KANN Oxid NIIIIICHT!!!

Nochmal zur Verdeutlichung: Wenn man als Maßeinheit g (=Gramm) eingibt, wird Oxid immer!! den Grundpreis von 1g (von einem Gramm) berechnen und das ist FAAALLLSCH! IMMER!!! OHNE ZWEIFEL!!!

Und ich kann lesen.

[QUOTE=muwi;42047]firefax, bitte einfach mal die Grundberechnung von oxid angucken und entdecken, dass man bei [B]ganz korrekter Eingabe[/B] laut Anleitung - wie ich deutlichst beschrieben habe - das juristisch falsche Ergebnis erhält!
EINE GRUNDPREISANGABE wie 0,01Euro pro g ist FALSCH, aber genau das berechnet oxid, wenn man z. B. 250g und als Preis 2,79 eingibt. GRundpreise MÜSSEN in bestimmten Fällen (lies einfach den oben gegebenen PHP-Vorschlag) auf 100g und 100ml bezogen werden und das KANN Oxid NIIIIICHT!!![/QUOTE]

Ich gebe es auf.
Mein Oxid hat die funktionierende Standartfunktionalität und im Demoshop klappt das auch und Oxid KANN DAT. Basta!

hier scheint jemand ein bastelfimmelfurium zu lieben statt sich mal

admin - artikel verwalten - erweitert - grundpreisangabe vernünftig vor augen zu führen
dort korrekte eingaben gemacht, egal ob liter kilo oder sonstwat, dann funzt das auch

ausnahmsweise was wo ich sag, daß es stimmt und oxid korrekt arbeitet

bestimmt wollt ihr nur meine Frustrationsschwelle ausloten, richtig?

Also:
Ich benutze die Eingabefelder Menge und Mengeneinheit (wie ich oben geschrieben habe) zum [B]korrekten Anzeigen des Inhalts eines Artikels[/B] (weil Oxid hier sonst nichts vorgesehen hat!! Das Eingabefeld für Gewicht hat eine andere Funktion! In den Titel des Artikels gehört die Mengenangabe nicht),
[B]also bei 250ml Himbeersaft:
Menge 250
Mengeneinheit: ml[/B]

Das Rechenergebnis von Oxid ist dann: [B]0,01 Euro/ml[/B]
richtig müsste es heißen: 1,12 Euro/100ml

Oder da ihr so clever auf die Anleitung verweist:
Zitat:
“Geben Sie bei Menge die Menge des Artikels [ein]”: die Menge beträgt bei obigem Artikel 250.
“und bei Mengeneinheit die entsprechende Mengeneinheit”: g
Ich habe mich also an die Anleitung gehalten.

Es ist mir klar, dass man (notdürftig) das System überlisten kann, indem man sich NICHT an die Anleitung hält, auf die ihr so pocht, aber wenn ich Menge 2,5 und Einheit 100g eingebe, lautet die Angabe des Inhalts:
Inhalt: 2,5100g
es sind aber 250g!

also wenn ich das so wie in den 3 screens bei mir drin hab, sollte das auch bei dir so passe

Ich schrieb ja, dass man durch ein Workaround das System überlisten kann (also 100g bei Maßeinheit eingeben, statt korrekt g, um dann per Kopf ausrechnen zu müssen, was ins Mengenfeld gehört, nämlich nicht das, was auf der Verpackung steht).
Aber zum einen hat man ja einen Computer, der einem eigenes Rechnen abnehmen sollte, zum zweiten benötige ich für die Mengenangabe im Template die richtige Maßeinheit, und zum dritten wird einem doch wohl spätestens beim Stammdatenimport aus eine WaWi übel werden, wenn man die dortigen Angaben, die selbstredend in jeder Wawi korrekt sind und nicht so seltsam wie in Oxid, bei mehreren 1000 Artikeln einzeln überarbeiten muss.
Ist es denn nicht einleuchtend, stattdessen einmal eine korrekte Berechnung zu implementieren?

HÄ ?? deutsch, ich nix versteh, irgendwie reden wir hier alle an Dir vorbei

[QUOTE=muwi;42056]
Es ist mir klar, dass man (notdürftig) das System überlisten kann, indem man sich NICHT an die Anleitung hält, auf die ihr so pocht, aber wenn ich Menge 2,5 und Einheit 100g eingebe, lautet die Angabe des Inhalts:
Inhalt: 2,5100g
es sind aber 250g![/QUOTE]
Wie wäre es mit
Einheit: 0g
Menge: 25
echo 25.“0g”;
=> 250g

Oder stehe ich auf den Schlauch?

[QUOTE=muwi;42061]Ich schrieb ja, dass man durch ein Workaround das System überlisten kann (also 100g bei Maßeinheit eingeben, statt korrekt g, um dann per Kopf ausrechnen zu müssen, was ins Mengenfeld gehört, nämlich nicht das, was auf der Verpackung steht).
Aber zum einen hat man ja einen Computer, der einem eigenes Rechnen abnehmen sollte, zum zweiten benötige ich für die Mengenangabe im Template die richtige Maßeinheit, und zum dritten wird einem doch wohl spätestens beim Stammdatenimport aus eine WaWi übel werden, wenn man die dortigen Angaben, die selbstredend in jeder Wawi korrekt sind und nicht so seltsam wie in Oxid, bei mehreren 1000 Artikeln einzeln überarbeiten muss.
Ist es denn nicht einleuchtend, stattdessen einmal eine korrekte Berechnung zu implementieren?[/QUOTE]
Was muss man da rechnen???

Du guckst was auf der Verpackung drauf steht (z.B. 250 g), dann überlegst Du Dir, ob Du 100g oder 1000g als Bezugseinheit haben willst, gibst die Werte ein und fädisch…

…und das mach ich bei 4000 Artikeln, die ich aus der Warenwirtschaft importiert habe.

Oder anders: ich guck natürlich nicht auf die Verpackung, sonder habe die Artikelstammdaten bereits per bnn3-Standart in die Warenwirtschaft eingelesen. Nach dem Import in Oxid muss ich dann alle 4000 per Hand durcharbeiten, um aus z. B. 250 g -> 2,5 100g oder aus 750 ml -> 0,75 L zu machen. Ich bearbeite also 4000 mal 2 Felder, anstatt 1 x eine Funktion zu korrigieren?

Tschö

Ralf

[QUOTE=muwi;42360]…und das mach ich bei 4000 Artikeln, die ich aus der Warenwirtschaft importiert habe.

Oder anders: ich guck natürlich nicht auf die Verpackung, sonder habe die Artikelstammdaten bereits per bnn3-Standart in die Warenwirtschaft eingelesen. Nach dem Import in Oxid muss ich dann alle 4000 per Hand durcharbeiten, um aus z. B. 250 g -> 2,5 100g oder aus 750 ml -> 0,75 L zu machen. Ich bearbeite also 4000 mal 2 Felder, anstatt 1 x eine Funktion zu korrigieren?

Tschö

Ralf[/QUOTE]
Nun, natürlich muss eine Warenwirtschaft das so exportieren, wie der Shop das erwartet, um richtig zu funktionieren.

Wenn das nicht der Fall ist, kann man daraus sicher kein generelles Fehlverhalten der Shopsoftware ableiten, sondern eher eines der WaWi.

Und ja, in Deinem Fall, bei dem die WaWi keine richtig funktionierende OXID-Schnittstelle hat, macht es sicher Sinn, das so zu lösen, wie Du es getan hast.

Aber das ist eben keine notwendige allgemeine Problemlösung, da OXID ja richtig arbeitet, wenn man seine Vorgaben berücksichtigt.

Und es wäre sicher von Anfang an sinnvoll gewesen, wenn Du Deine speziellen Rahmenbedingungen (falscher Export von WaWi-Daten) mitgeteilt hättest…

[QUOTE=avenger;42393]
Und es wäre sicher von Anfang an sinnvoll gewesen, wenn Du Deine speziellen Rahmenbedingungen (falscher Export von WaWi-Daten) mitgeteilt hättest…[/QUOTE]

Jupp, sehe ich auch so, in diesem speziellen Sonderfall und unter den Rahmenbedingungen, macht es sicherlich Sinn eine spezielle Lösung dafür zu finden. Man will ja quasi seine Ausgangsdaten unaufbereitet in den Shop einstellen.

Die allgemeingültigere Lösung ist sicherlich die, die Oxid bereits implementiert hat. So einfach kann man über die selbe Sache reden und doch komplett aneinander vorbei.

CYA

mal ganz abgesehen von “falschen ex/importen” - wozu brauch man in einer Wawi den Grundpreis ??
schreibt etwa irgendwer auf ne Rechnung den Grundpreis drauf ??

Kann doch absolut Sinn machen, wenn man von seinen Artikeln das echte Brutto und netto Gewicht und die dazu passenden Einheit hat. Es sind ja diese Stammdaten des Artikels, aus denen eine Grundpreisanzeige automatisch generiert werden soll.

Vielleicht erstellt er auch Preisschilder über die Wawi, auf denen die Angabe zwingend drauf sein muss.

[QUOTE=muwi;42032]

//price per unit handling, Ehlert: modifiziert!

        if ((double) $this->oxarticles__oxunitquantity->value && $this->oxarticles__oxunitname->value) { //berechne nur, wenn beide Werte vorliegen
           switch($this->oxarticles__oxunitname->value) {

            case 'g':
                 if ($this->oxarticles__oxunitquantity->value<=400) {
                 $this->_fPricePerUnit = oxLang::getInstance()->formatCurrency($dPrice / (double) $this->oxarticles__oxunitquantity->value * 100, $oCur);$this->_Grundpreiseinheit->value='100g';
                 break; }
                 if ($this->oxarticles__oxunitquantity->value>400) {
                 $this->_fPricePerUnit = oxLang::getInstance()->formatCurrency($dPrice / (double) $this->oxarticles__oxunitquantity->value * 1000, $oCur);$this->_Grundpreiseinheit->value='Kg';
                 break; }
            case 'Kg':
                 if ($this->oxarticles__oxunitquantity->value<=0.4) {
                 $this->_fPricePerUnit = oxLang::getInstance()->formatCurrency($dPrice / (double) $this->oxarticles__oxunitquantity->value / 10, $oCur);$this->_Grundpreiseinheit->value='100g';
                 break; }
                 if ($this->oxarticles__oxunitquantity->value>0.4) {
                 $this->_fPricePerUnit = oxLang::getInstance()->formatCurrency($dPrice / (double) $this->oxarticles__oxunitquantity->value, $oCur);$this->_Grundpreiseinheit->value='Kg';
                 break; }

            case 'ml':
                 if ($this->oxarticles__oxunitquantity->value<=400) {
                 $this->_fPricePerUnit = oxLang::getInstance()->formatCurrency($dPrice / (double) $this->oxarticles__oxunitquantity->value * 100, $oCur);$this->_Grundpreiseinheit->value='100ml';
                 break; }
                 if ($this->oxarticles__oxunitquantity->value>400) {
                 $this->_fPricePerUnit = oxLang::getInstance()->formatCurrency($dPrice / (double) $this->oxarticles__oxunitquantity->value * 1000, $oCur);$this->_Grundpreiseinheit->value='L';
                 break; }
            case 'L':
                 if ($this->oxarticles__oxunitquantity->value<=0.4) {
                 $this->_fPricePerUnit = oxLang::getInstance()->formatCurrency($dPrice / (double) $this->oxarticles__oxunitquantity->value / 10, $oCur);$this->_Grundpreiseinheit->value='100ml';
                 break; }
                 if ($this->oxarticles__oxunitquantity->value>0.4) {
                 $this->_fPricePerUnit = oxLang::getInstance()->formatCurrency($dPrice / (double) $this->oxarticles__oxunitquantity->value, $oCur);$this->_Grundpreiseinheit->value='L';
                 break; }


         } //switch-Ende
        }
        //Ehlert ENDE

Hier kann natürlich nach Bedarf ergänzt werden (z. B. Meter/ml). ‘Stück’ ist hier nicht berücksichtigt, weil zumindest in meiner Branche bei Stückangaben kein Grundpreis nötig ist.
[/QUOTE]
Hallo Ralf,

ich versuche mal diesen Thread produktiv zu machen. :wink:

Schon mal daran gedacht hier das Factory-Pattern zu nutzen?

Währe wesentlich flexibler.

Das ganze ist natürlich ungetestet und bei weiten nicht optimal. Pfade (include) usw. dürften vorne und hinten nicht stimmen.

Modul (/modules/myUnit.php) (oxarticle=>myUnit)


class myUnit extends myUnit_parent{
    protected function _assignPrices(){
        $myConfig = $this->getConfig();
        // Performance
        if ( !$myConfig->getConfigParam( 'bl_perfLoadPrice' ) || !$this->_blLoadPrice ) {
            return;
        }
        if(!$this->isAdmin()&&(double) $this->oxarticles__oxunitquantity->value && $this->oxarticles__oxunitname->value){
            $sUnitClassName='calcunit'.strtolower($this->oxarticles__oxunitname->value);
            $sUnitClassPath='/core/units/'.$sUnitClassName.'.php';
            if(file_exits($sUnitClassPath)){
                include_once('/core/units/calcunitinterface.php');
                include_once($sUnitClassPath);
                $oUnit=new $sUnitClassName;
                $oUnit->setQuantity($this->oxarticles__oxunitquantity);
                $oUnit->setName($this->oxarticles__oxunitname);
                $oUnit->execute();
            }
        }
        parent::_assignPrices();
    }
}

Schnittstelle (/core/units/calcunitinterface.php)


interface calcunitinterface{
    public function setQuantity($oField);
    public function setName($oField);
    public function execute();
}

Testimplementation (/core/units/calcunitg.php)(g=gramm)


/**
 * g=gramm | Grundpreiseinheit ist immer g (=>1kg=1000g), oxFields(oxarticles__oxunitquantity|oxarticles__oxunitname) werden dementsprechend manipuliert
 * natürlich kann man beliebig viele klassen erzeugen
 * - calcunitm => meter
 * - calcunitm2 => meter²(meter*meter)
 * - calcunitl => liter (nach hektoliter usw.)
 * man kann auch je nach Sprache das einheitssystem wechseln (cm=>zoll)
 *
 * wenn man mehrere klassen hat, welche auf SI beruhen kann man eine grundklasse bilden welche (10^3=kilo, 10^6=mega usw.) umrechnet und die abgeleiteten klassen hängen die grundeinheit an
 */
class calcunitg implements interface calcunitinterface{
    protected $oQuantity=null
    protected $oName=null;
    public function setQuantity($oQuantity){
        $this->oQuantity=$oQuantity;
    }
    public function setName($oName){
       $oName->setValue('g');//immer gramm
        $this->oName=$oName;//kopie zum manipulieren
    }
    /**
    * manipuliert oField objects
    */
    public function execute(){
        if($this->oQuantity->value<100){
            //do nothing
            return;
        }
        if ($this->oQuantity->value<=400) {
            $this->oQuantity->setValue(100);
            $this->oName->setValue('100'.$this->oName->value);
            break;
        }
        if ($this->oQuantity->value>400) {
            $this->oQuantity->setValue(1000);
            $this->oName->setValue('K'.$this->oName->value);
            break; 
        }
        //usw.... anstatt der ganzen if abfragen kann man das auch schön mit ein wenig mathematik lösen :)
    }
}

Beispiel kg extends g (/core/units/calcunitkg.php)


include_once('/core/units/calcunitg.php');
/**
 * falls oxid unitname = kg ist, wird dieser erst in g umgerechnet
 */
class calcunitkg extends calcunitg implements calcunitinterface{
    public function setQuantity($oQuantity){
        $oQuantity->setValue($oQuantity->value*1000);
        parent::setQuantity($oQuantity);
    }
}

Hi Markus,

herzlichen Dank! Da muss ich erstmal genauer hinschauen - hab vom Factory-Pattern noch gar nichts gehört. Brauch aber eh ne bessere Lösung, weil es an einer Stelle mit den Varianten hakt.
Sobald ichs kapiert habe, gebe ich Rückmeldung.

Tschö

Ralf