Jörg: Warum wird die falsche Endsumme ausgegeben?

Hallo,

ich drucke eine Rechnung als PDF aus, mithilfe von fpdf. Auf mehrseitigen Rechn ungen drucke ich hierbei Zwischensummen aus, die auf der letzten Seite ggf. noch um einen Gesamtrabatt oder geleistete Anzahlungen reduziert werden kann.

Meine Funktion für das Setzen und die Ausgabe der Zwischensummen:

function myArrayZwischensumme($set_get,$Art,$betrag,$page)
{

    $ergebnis = 0;
    $overwrite = 0;
    if(!isset($arrPage)) {
        static $arrPage = [];
    }

    if($set_get == 'set') {
        $arrPage[$page] = $arrPage[$page] + $betrag;
        logge('Ergebnis Seite '.$page.' :'.$arrPage[$page],'__test.txt');
    } elseif($set_get == 'overwrite') {
        $arrPage[$page] = $betrag;
        $overwrite++;
    } elseif($set_get == 'get') {
        logge('Get Seite '.$page.' :'.$arrPage[$page],'__test.txt');
        if($overwrite == 0) {
            for($i = 1;$i <= $page;$i++) {
                $ergebnis = $ergebnis + $arrPage[$i];
            }
        } else {
            $ergebnis = $betrag;
        }
        logge('return Seite '.$page.' = '.$ergebnis, '__test.txt');
        return number_format($ergebnis,2,".","");

    }
    return;
}

Das Endergebnis fordere ich wie folgt an:

 logge('Endergebnis anfordern','__test.txt');
 $pdf->MultiCell(30,5,myArrayZwischensumme('get','Endsumme',0,$pdf->PageNo()),0,'L',0);

Und ich erhalte folgende Logdatei:

23.11.2022 12:06:24.756200: Ergebnis Seite  :0
23.11.2022 12:06:24.764400: Ergebnis Seite  :0
23.11.2022 12:06:24.789200: Ergebnis Seite 1 :3545
23.11.2022 12:06:24.796600: Ergebnis Seite 1 :3545
23.11.2022 12:06:24.801400: Ergebnis Seite 1 :7000
23.11.2022 12:06:24.806100: Get Seite 1 :7000
23.11.2022 12:06:24.811800: return Seite 1 = 7000
23.11.2022 12:06:24.862400: Endergebnis anfordern
23.11.2022 12:06:24.866600: Get Seite 2 :0
23.11.2022 12:06:24.870800: return Seite 2 = 7000

Die ersten beiden Einträge der Logdatei bedeuten, dass in 2 Arten von Dienstleistungen keine Leistung geflossen ist. Erst im der 3. Art von Dienstleistung sind 2 Posten in die Rechnung eingeflossen. Beide mit einem Betrag von 3545 Euro. Beide stehen auf Seite 1 der Rechnung. Dann wird das Zwischenergebnis der Seite 1 angefordert und auch returniert.
Auf Seite 2 stehen weitere Informatijonen und es werden 2 Anzahlungen in Gesamthöhe von 7000,- Euro abgezogen (aus der Logdatei nicht ersichtlich, aber mit Parameter "overwrite" an die Funktion übergeben)

Somit steht leider im PDF in Seite 2 nicht 0.00 als Ergebnis, sondern 7000. Und das ist ja definitiv falsch.

Liegt wohl daran, dass $overwrite bei jedem Funktionsaufruf wieder auf 0 gesetzt wird. Aber es kann doch nicht die Lösung sein, hieraus eine statische Variable zu sein, oder?

Ich habe vielmehr den Eindruck, dass meine Funktion selber nicht ganz optimal ist. Kann da mal jemand von Euch mit drüber schauen? Ich hoffe, mein Input hierfür reicht aus. Falls nicht, bitte danach fragen.

Jörg

  1. Hi,

    Erst im der 3. Art von Dienstleistung sind 2 Posten in die Rechnung eingeflossen. Beide mit einem Betrag von 3545 Euro. Beide stehen auf Seite 1 der Rechnung. Dann wird das Zwischenergebnis der Seite 1 angefordert und auch returniert.
    Auf Seite 2 stehen weitere Informatijonen und es werden 2 Anzahlungen in Gesamthöhe von 7000,- Euro abgezogen (aus der Logdatei nicht ersichtlich, aber mit Parameter "overwrite" an die Funktion übergeben)

    2*3545 = 7090, nach Abzug von 7000 Anzahlung ergibt sich ein Rest von 90.

    Somit steht leider im PDF in Seite 2 nicht 0.00 als Ergebnis, sondern 7000.

    Wieso erwartest Du 0 statt 90?

    Liegt wohl daran, dass $overwrite bei jedem Funktionsaufruf wieder auf 0 gesetzt wird. Aber es kann doch nicht die Lösung sein, hieraus eine statische Variable zu sein, oder?

    Naja, wenn der Wert von einem zum nächsten Funktionsaufruf erhalten bleiben soll, dann kann die Variable ja nicht nur innerhalb der Funktion existieren.

    Statisch muß sie deswegen aber nicht sein. Sie könnte ja in der aufrufenden Funktion als lokale Variable existieren und jeweils mit reingereicht werden …

    cu,
    Andreas a/k/a MudGuard

    1. Hallo Andreas,

      2*3545 = 7090, nach Abzug von 7000 Anzahlung ergibt sich ein Rest von 90.

      Oh ja.
      Dann habe ich eine 2. Baustelle.
      Im Original sind die Beträge nämlich 3545 und 3455.
      Das habe ich überlesen, eröffnet aber grad ein weiteres Problem: Warum wird 2 x 3545 eingetragen? 😲

      Naja, wenn der Wert von einem zum nächsten Funktionsaufruf erhalten bleiben soll, dann kann die Variable ja nicht nur innerhalb der Funktion existieren.

      Statisch muß sie deswegen aber nicht sein. Sie könnte ja in der aufrufenden Funktion als lokale Variable existieren und jeweils mit reingereicht werden …

      Ja, ok.
      Aber ich bin insgesamt mit der Funktion nicht ganz zufrieden. Weiß gar nicht genau, warum.

      Jörg

  2. Hallo Jörg,

    zum Verständnis des Geschehens wäre es wohl wesentlich sinnvoller, wenn Du vor jeder Logik erstmal loggst, mit welchen Argumenten deine Funktion aufgerufen wird.

        if(!isset($arrPage)) {
            static $arrPage = [];
        }
    

    Die Abfrage ist unnötig. PHP initialisiert eine static-Variable nur beim ersten Aufruf der Funktion.

    Wenn Du Dir den $overwrite über alle Aufrufe merken willst, muss der auch static sein. Aber warte noch...

    Ansonsten ist die Funktion - finde ich - Kraut und Rüben. Der Parameter $set_get ist ein drohender Unfall. Der Wert "set" addiert, entgegen seiner suggerierten Funktion. Der Wert "overwrite" setzt dagegen etwas. Und mit "get" bekommst Du einen aufsummierten Betrag über die Seiten hinweg, aber laut Plan nur dann, wenn's vorher mal einen Overwrite gab. Ansonsten kriegst Du den Wert zurück, den Du schon mitgegeben hast. Und du gibst eine $Art hinein, die Du aber gar nicht verwendest. Hä?!

    Wenn Du pro Seite was aufsummieren willst, dann mach dafür eine "add" Operation (und nenn $get_set dann auch $operation oder so). Wenn Du auf der Seite was von dieser Summe abziehen willst, mach eine "sub" Operation und rechne nicht außerhalb nochmal rum. Lass "get" den Wert für die aktuelle Seite zurückgeben, sofern das überhaupt nötig ist, und für die Summe über alle Seiten mach eine "total" Operation. Ich glaube nicht, dass Du Dir dafür merken musst, ob es mal einen "overwrite" gegeben hat.

    Frage ist auch, ob eine Funktion mit static-Variablen wirklich Mittel der Wahl ist. Warum keine Klasse mit Methoden add, subtract, getPage und getTotal. Davon erzeugst Du ein Objekt und rufst bei Bedarf die Methode auf. Dieses Objekt kannst Du, wenn es kompliziert ist, das herumzureichen, auch an das FPDF-Objekt anpappen. Du könntest auch eine Klasse von FPDF ableiten, um das zu managen.

    Rolf

    --
    sumpsi - posui - obstruxi
    1. Hallo Rolf,

      zum Verständnis des Geschehens wäre es wohl wesentlich sinnvoller, wenn Du vor jeder Logik erstmal loggst, mit welchen Argumenten deine Funktion aufgerufen wird.

      Ok, einverstaanden.

      Die Abfrage ist unnötig. PHP initialisiert eine static-Variable nur beim ersten Aufruf der Funktion.

      Alles klar. nehm ich raus.

      Ansonsten ist die Funktion - finde ich - Kraut und Rüben.

      Mir gefällt sie auch nicht.
      Und sie macht ja auch nicht, was ich eigentlich will.

      Der Parameter $set_get ist ein drohender Unfall. Der Wert "set" addiert, entgegen seiner suggerierten Funktion. Der Wert "overwrite" setzt dagegen etwas. Und mit "get" bekommst Du einen aufsummierten Betrag über die Seiten hinweg, aber laut Plan nur dann, wenn's vorher mal einen Overwrite gab.

      Na, nicht ganz.
      Den kummulierten betrag erhalte ich nur dann, wenn es zuvor keinen Overwrite gab.

      Ansonsten kriegst Du den Wert zurück, den Du schon mitgegeben hast.

      Genau.

      Und du gibst eine $Art hinein, die Du aber gar nicht verwendest. Hä?!

      Das war nur für frühere Logs da, damit ichs zuordnen konnte.

      Wenn Du pro Seite was aufsummieren willst, dann mach dafür eine "add" Operation (und nenn $get_set dann auch $operation oder so). Wenn Du auf der Seite was von dieser Summe abziehen willst, mach eine "sub" Operation und rechne nicht außerhalb nochmal rum. Lass "get" den Wert für die aktuelle Seite zurückgeben, sofern das überhaupt nötig ist, und für die Summe über alle Seiten mach eine "total" Operation. Ich glaube nicht, dass Du Dir dafür merken musst, ob es mal einen "overwrite" gegeben hat.

      Versuche ich mal, so umzusetzen und meld mich dann wieder zurück.

      Frage ist auch, ob eine Funktion mit static-Variablen wirklich Mittel der Wahl ist. Warum keine Klasse mit Methoden add, subtract, getPage und getTotal. Davon erzeugst Du ein Objekt und rufst bei Bedarf die Methode auf. Dieses Objekt kannst Du, wenn es kompliziert ist, das herumzureichen, auch an das FPDF-Objekt anpappen. Du könntest auch eine Klasse von FPDF ableiten, um das zu managen.

      Bin ich nicht mehr fit genug, um das oo zu programmieren. Ich versuchs erstmal so, wie Du zuvor gesagt hattest.

      Jörg

      1. Warum keine Klasse mit Methoden add, subtract, getPage und getTotal. Davon erzeugst Du ein Objekt und rufst bei Bedarf die Methode auf. Dieses Objekt kannst Du, wenn es kompliziert ist, das herumzureichen, auch an das FPDF-Objekt anpappen. Du könntest auch eine Klasse von FPDF ableiten, um das zu managen.

        Bin ich nicht mehr fit genug, um das oo zu programmieren.

        Nur, dass es eben um Klassen einfacher wäre, eine Klasse und daraus das Objekt zu bauen. Du solltest Dich also eher fragen, ob Du noch fit genug bist, das mit der Funktion machen zu wollen.

        1. Hi Willi,

          Nur, dass es eben um Klassen einfacher wäre, eine Klasse und daraus das Objekt zu bauen. Du solltest Dich also eher fragen, ob Du noch fit genug bist, das mit der Funktion machen zu wollen.

          hab ich gemacht und das Ergbnis ist mein Post hier. 😬😉

      2. Versuche ich mal, so umzusetzen und meld mich dann wieder zurück.

        function myArrayZwischensumme($operation,$Art,$betrag,$page)
        {
            logge('Seite'.$page.'/ Operation: '.$operation.'/ Art: '.$Art.'/ Betrag='.$betrag,'__test.txt');
        
            $ergebnis = 0;
            static $arrPage = [];
        
            if($operation == 'add' || $operation == 'sub') {
                if($operation == 'sub') {
                    $betrag = $betrag * (-1);
                }
                $arrPage[$page] = $arrPage[$page] + $betrag;
                logge('Ergebnis Seite '.$page.' :'.$arrPage[$page],'__test.txt');
                return;
            }
        
            if($operation == 'get') {
                logge('Get Seite '.$page.' :'.$arrPage[$page],'__test.txt');
                for($i = 1;$i <= $page;$i++) {
                    $ergebnis = $ergebnis + $arrPage[$i];
                }
                logge('return Seite '.$page.' = '.$ergebnis,'__test.txt');
                return number_format($ergebnis,2,".","");
            }
        }
        
        23.11.2022 13:11:37.909100: Seite/ Operation: add/ Art: F/ Betrag=0
        23.11.2022 13:11:37.919100: Ergebnis Seite  :0
        23.11.2022 13:11:37.928000: Seite/ Operation: add/ Art: A/ Betrag=0
        23.11.2022 13:11:37.936500: Ergebnis Seite  :0
        23.11.2022 13:11:37.974000: Seite1/ Operation: add/ Art: T/ Betrag=3545
        23.11.2022 13:11:37.982000: Ergebnis Seite 1 :3545
        23.11.2022 13:11:37.990100: Seite1/ Operation: add/ Art: T/ Betrag=0
        23.11.2022 13:11:37.998400: Ergebnis Seite 1 :3545
        23.11.2022 13:11:38.006700: Seite1/ Operation: add/ Art: T/ Betrag=3455
        23.11.2022 13:11:38.014900: Ergebnis Seite 1 :7000
        23.11.2022 13:11:38.023800: Seite1/ Operation: get/ Art: Zwischensumme/ Betrag=0
        23.11.2022 13:11:38.031900: Get Seite 1 :7000
        23.11.2022 13:11:38.039900: return Seite 1 = 7000
        23.11.2022 13:11:38.084700: Seite2/ Operation: sub/ Art: RGA-Zusatz/ Betrag=7000
        23.11.2022 13:11:38.092500: Ergebnis Seite 2 :-7000
        23.11.2022 13:11:38.146100: Endergebnis anfordern
        23.11.2022 13:11:38.153400: Seite2/ Operation: get/ Art: Endsumme/ Betrag=0
        23.11.2022 13:11:38.161800: Get Seite 2 :-7000
        23.11.2022 13:11:38.170400: return Seite 2 = 0
        

        Im Ausdruck passen die Werte nun, aber in den Logdaten sind ja immer noch falsche Werte drin. Wie Andreas weiter oben schon bemerkt hatte, werden mit den falschen beträgen (2 x 3545) die richtigen ergebnisse erzielt.)

        Meine Vermutung außerdem:

        $ergebnis = 0 ist nicht korrekt.

        Jörg

        1. Hallo Jörg,

          offenbar verstehe ich deine Fachlichkeit mal wieder nicht, denn das, was da passiert, sieht für mich richtig aus.

          Seite 1: 3545 + 3455 ergibt +7000 auf Seite 1- check Seite 2: -7000 ergibt -7000 auf Seite 2 - check Total ist das 0. Check.

          Rolf

          --
          sumpsi - posui - obstruxi
          1. Hallo Rolf,

            Seite 1: 3545 + 3455 ergibt +7000 auf Seite 1- check Seite 2: -7000 ergibt -7000 auf Seite 2 - check Total ist das 0. Check.

            Ich hätte wohl irgendwie ein Beispiel mit anderen Werten nehmen sollen.
            Ich krieg die Zahlen nicht auseinander gehalten. 🤪

            Irgendwie traue ich der Funktion trotzem noch nicht.
            Kannst Du mir erklären, wie man das als Klasse gemacht hätte?
            Und noch ne Frage: Wäre es seeehr übertrieben, die Werte temporär in eine DB zu schreiben und dort wieder abzuholen?

            Ach, noch eine Frage: Was ist mit dem Gültigkeitsbereich einer statischen Varable? Gilt die über den Scriptaufruf hinaus? Ich frage, weil ich mich dann darum kümmern müsste, ob ich sie irgendwann zerstören muss.

            Gruß, Jörg