Grundlegendes Problem in checkout_process.php?

Thema wurde von Avenger, 14. Februar 2013 erstellt.

  1. Avenger

    Avenger G-WARD 2012/13/14/15

    Registriert seit:
    26. April 2011
    Beiträge:
    4.771
    Danke erhalten:
    1.478
    Danke vergeben:
    89
    #1 Avenger, 14. Februar 2013
    Zuletzt bearbeitet: 14. Februar 2013
    Bei den Zahlungsarten wie PayPal, Kreditkarten usw. wird ja nach der Bestellbestätigung auf die Bezahlseite verzweigt.

    In der checkout_process.php wird dabei eine Bestellung angelegt, und die Lagerbestände werden aktualisiert.

    Wenn die Zahlung dann aber abgebrochen wird, sind m.E. die Lagerbestände falsch, da die ja schon vor der Verzweigung zur Zahlungsseite aktualisiert, und bei Fehlschlagen der Zahlung nicht korrigiert werden.

    Habe ich etwas übersehen?

    EDIT:

    Diese Daten dürfen also erst nach wirklich positivem Bestellabschluss aktualisiert werden.

    Ebenso die Zuordnung zu Kampagnen.
     
  2. Avenger

    Avenger G-WARD 2012/13/14/15

    Registriert seit:
    26. April 2011
    Beiträge:
    4.771
    Danke erhalten:
    1.478
    Danke vergeben:
    89
    Keine Meinung dazu von der Gambio GmbH?

    Wenn meine Erkenntnis stimmt (wovon ich mal ausgehe), muss das sicher schnell gelöst werden!
     
  3. Steffen (indiv-style.de)

    Steffen (indiv-style.de) G-WARD 2013/14/15/16

    Registriert seit:
    30. Juni 2011
    Beiträge:
    5.143
    Danke erhalten:
    1.466
    Danke vergeben:
    452
    Beruf:
    Systemadmin, Webentwickler bei Indiv-Style
    Ort:
    PhpStorm
    Das gleiche Problem wie bei den Bestellbestätigungsmails! Diese werden teils versendet obwohl die Zahlung nicht durch ist! Ich hab das bei uns in die checkout_succsess.php ausgelagert!
     
  4. Avenger

    Avenger G-WARD 2012/13/14/15

    Registriert seit:
    26. April 2011
    Beiträge:
    4.771
    Danke erhalten:
    1.478
    Danke vergeben:
    89
    Das wundert mich eigentlich.....

    Weil im Fehlerfall die "checkout_process.php" nicht gestartet wird (in der die eMails verschickt werden), sondern die Zahlungsseite..
     
  5. barbara

    barbara G-WARD 2014-2020

    Registriert seit:
    14. August 2011
    Beiträge:
    35.543
    Danke erhalten:
    11.305
    Danke vergeben:
    1.611
    da gab es kürzlich schon mal was....(Link nur für registrierte Nutzer sichtbar.)
     
  6. Avenger

    Avenger G-WARD 2012/13/14/15

    Registriert seit:
    26. April 2011
    Beiträge:
    4.771
    Danke erhalten:
    1.478
    Danke vergeben:
    89
    Ja, genau das ist das Problem,,,,

    m.E. kann es aber keine unterschiedlichen Ansichten geben, ob das richtig oder falsch ist: es ist definitiv falsch!

    Es darf natürlich nicht sein, dass der Lagerbestand verändert wird, bevor sicher ist, dass der Kunde auch bezahlt hat.

    Und das Problem ist auch einfach lösbar:

    man darf den Bestand erst dann anpassen, wenn die Bezahlung erfolgt ist.

    Und das ist einfach realisierbar, auch innerhalb der "checkout_process.php".

    In der "checkout_succes.php" ist es insofern schwieriger, weil der Warenkorb nicht mehr existiert.
     
  7. Steffen (indiv-style.de)

    Steffen (indiv-style.de) G-WARD 2013/14/15/16

    Registriert seit:
    30. Juni 2011
    Beiträge:
    5.143
    Danke erhalten:
    1.466
    Danke vergeben:
    452
    Beruf:
    Systemadmin, Webentwickler bei Indiv-Style
    Ort:
    PhpStorm
    Das ist ja richtig, aber das senden der Mails ist auch in der checkout_process.php und die wird ja aufgerufen! Wir haben dies geändert, sodas die mails erst in der checkout_succsess.php versendet werden. Keine Zahlung, keine Mails! ;)
     
  8. Avenger

    Avenger G-WARD 2012/13/14/15

    Registriert seit:
    26. April 2011
    Beiträge:
    4.771
    Danke erhalten:
    1.478
    Danke vergeben:
    89
    Aber im Fehlerfall wird ja die "checkout_process.php" nicht aktiviert, sondern die Zahlungsseite "checkout_payment.php"

    Und nur in der "checkout_process.php" werden die Mails versendet, und nur nach erfolgreicher Zahlung!

    Aus meiner Sicht gibt es nur das Problem mit der Lagerbestandsführung, die zu früh erfolgt.

    Verwendest Du Deinen "one-page-checkout"?

    Gibt es evtl. da ein Problem?
     
  9. Steffen (indiv-style.de)

    Steffen (indiv-style.de) G-WARD 2013/14/15/16

    Registriert seit:
    30. Juni 2011
    Beiträge:
    5.143
    Danke erhalten:
    1.466
    Danke vergeben:
    452
    Beruf:
    Systemadmin, Webentwickler bei Indiv-Style
    Ort:
    PhpStorm
    Es könnte am OPC liegen, naja wir haben es geändert und nu passt es ja. Das mit dem Lagerbestand ist aber auch beim OPC der Fall, was etwas nervt!
     
  10. Avenger

    Avenger G-WARD 2012/13/14/15

    Registriert seit:
    26. April 2011
    Beiträge:
    4.771
    Danke erhalten:
    1.478
    Danke vergeben:
    89
    #10 Avenger, 16. Februar 2013
    Zuletzt bearbeitet: 16. Februar 2013
    Ich habe mir das mal angesehen, und folgende Problemlösung erarbeitet:

    die Idee ist, dass man im Falle einer externen Zahlungsart die Lagerbestand-SQLs, die erzeugt werden, nicht direkt anwendet, sondern in der Session zwischenspeichert.

    Und die erst dann anwendet, wenn der Zahlungs-Prozess erfolgreich abgeschlossen ist.

    Dann kann man die vorhandene Logik weitestgehend beibehalten, und muss nur moderat in den Code eingreifen.

    In "checkout_process.php" folgendes ändern:

    Die beiden folgenden Änderungen sind notwendig, weil bei mir das verwendete "$$_SESSION['payment']" "NULL" ist, und so durch "$GLOBALS[$_SESSION['payment']]" ersetzt wird...

    (Mit "$$_SESSION['payment']" verlässt man sich m.E. darauf, dass "register_globals" auf "on" gesetzt ist.)

    Vor
    PHP:
    if (isset ($_SESSION['tmp_oID']) && is_int($_SESSION['tmp_oID'])) {
    einfügen

    PHP:
    //Avenger
    $payment=$GLOBALS[$_SESSION['payment']];
    //Avenger
    Alle

    PHP:
    $$_SESSION['payment']
    ersetzen mit

    PHP:
    $payment
    PHP:
                xtc_db_query("update ".TABLE_PRODUCTS." set products_quantity = '".$stock_left."' where products_id = '".xtc_get_prid($order->products[$i]['id'])."'");
                
    // BOF GM_MOD:
                
    if (($stock_left 1) && (STOCK_ALLOW_CHECKOUT == 'false') && GM_SET_OUT_OF_STOCK_PRODUCTS == 'true') {
                    
    xtc_db_query("update ".TABLE_PRODUCTS." set products_status = '0' where products_id = '".xtc_get_prid($order->products[$i]['id'])."'");
                }
    ersetzen mit

    PHP:
          //Avenger      
          //Delayed stock updates
          //For external payment-methods adjust stock only after real payment! 
          //In that case store updates sql in session and do not apply directly!
          
    $update="update ".TABLE_PRODUCTS." set ";
          
    $where=" where products_id = '".xtc_get_prid($order->products[$i]['id'])."'";
          
    $stock_update_sql=$update."products_quantity = '".$stock_left."'".$where;      
          
    $status_update_sql=$update."products_status = '0' ".$where;      
          
    $no_stock_left=$stock_left && (STOCK_ALLOW_CHECKOUT == 'false') && GM_SET_OUT_OF_STOCK_PRODUCTS == 'true';
          if (
    $tmp)                  
          {
            
    $_SESSION{'stock_update_sql'}[]=$stock_update_sql;
            
    // BOF GM_MOD:
            
    if ($no_stock_left
            {
              
    $_SESSION{'status_update_sql'}[]=$status_update_sql;
            }
          }
          else
          {
            
    xtc_db_query($stock_update_sql);
            
    // BOF GM_MOD:
            
    if ($no_stock_left
            {
              
    xtc_db_query("update ".TABLE_PRODUCTS." set products_status = '0' where products_id = '".xtc_get_prid($order->products[$i]['id'])."'");
            }
          }
          
    //Avenger
    Nach
    PHP:
    if (!$tmp) {
    einfügen

    PHP:
      //Avenger     
      //Delayed stock updates
      //For external payment-methods adjust stock only after real payment! 
      //In that case updates sql have been stored in session and not have been applied directly!
      
    $updates_sql_names=array('stock_update_sql','status_update_sql');
      foreach (
    $updates_sql_names as $updates_sql_name)
      {
        
    $update_sqls=$_SESSION{$updates_sql_name};
        if (
    $update_sqls)
        {
          foreach (
    $update_sqls as $update_sql)
          {
            
    xtc_db_query($update_sqls);
          }
          unset(
    $_SESSION{$updates_sql_name});
        }
      }
      
    //Avenger
    Wie immer gilt:

    Anwendung ausschließlich auf eigenes Risiko des Verwenders.

    Eine Gewährleistung jeglicher Art ist ausgeschlossen.

    Vor Einbau eine Sicherung der Shop-Programme vornehmen.

    Erst im Testshop testen.
     
  11. Avenger

    Avenger G-WARD 2012/13/14/15

    Registriert seit:
    26. April 2011
    Beiträge:
    4.771
    Danke erhalten:
    1.478
    Danke vergeben:
    89
    Das war noch nicht ganz vollständig.....

    In "checkout_process.php" folgendes ändern:

    Nach

    PHP:
       Copyright (c2012 Gambio GmbH
    einfügen

    PHP:
       Copyright (c2013 Avengerentwicklung@powertemplate.de
       Delayed stock updates
       
    For external payment-methods adjust stock only after real payment!
       
    In that case store updates sql in session and do not apply directly!
    Die beiden folgenden Änderungen sind notwendig, weil bei mir das verwendete "$$_SESSION['payment']" "NULL" ist, und so durch "$GLOBALS[$_SESSION['payment']]" ersetzt wird...

    (Mit "$$_SESSION['payment']" verlässt man sich m.E. darauf, dass "register_globals" auf "on" gesetzt ist.)

    Vor
    PHP:
    if (isset ($_SESSION['tmp_oID']) && is_int($_SESSION['tmp_oID'])) {
    einfügen

    PHP:
    //Avenger
    $payment=$GLOBALS[$_SESSION['payment']];
    $updates_names=array('stock_update_sql','status_update_sql','properties_update_data','attributes_update_sql');
    //Avenger
    Alle

    PHP:
    $$_SESSION['payment']
    ersetzen mit

    PHP:
    $payment
    Nach

    PHP:
            $tmp_status $payment->tmpStatus;
    einfügen
    PHP:
        //Avenger     
        //Initialize stock update parameters arrays
        
    foreach ($updates_names as $updates_name)
        {
          
    $_SESSION{$updates_name}=array();
        }
        
    //Avenger
    PHP:
                xtc_db_query("update  ".TABLE_PRODUCTS." set products_quantity = '".$stock_left."' where  products_id = '".xtc_get_prid($order->products[$i]['id'])."'");
                
    // BOF GM_MOD:
                
    if (($stock_left 1) && (STOCK_ALLOW_CHECKOUT ==  'false') && GM_SET_OUT_OF_STOCK_PRODUCTS == 'true') {
                    
    xtc_db_query("update ".TABLE_PRODUCTS." set  products_status = '0' where products_id =  '".xtc_get_prid($order->products[$i]['id'])."'");
                }
    ersetzen mit

    PHP:
          //Avenger      
          //Delayed stock updates
          //For external payment-methods adjust stock only after real payment!
          //In that case store updates sql in session and do not apply directly!
          
    $update="UPDATE ".TABLE_PRODUCTS." SET ";
          
    $products_id=xtc_get_prid($order->products[$i]['id']);
          
    $where=" WHERE products_id = '".$products_id."'";
          
    $stock_update_sql=$update."products_quantity = '".$stock_left."'".$where;      
          
    $status_update_sql=$update."products_status = '0' ".$where;      
          
    $no_stock_left=$stock_left && (STOCK_ALLOW_CHECKOUT == 'false') && GM_SET_OUT_OF_STOCK_PRODUCTS == 'true';
          if (
    $tmp)                  
          {
            
    $_SESSION{'stock_update_sql'}[]=$stock_update_sql;
            
    // BOF GM_MOD:
            
    if ($no_stock_left)
            {
              
    $_SESSION{'status_update_sql'}[]=$status_update_sql;
            }
          }
          else
          {
            
    xtc_db_query($stock_update_sql);
            
    // BOF GM_MOD:
            
    if ($no_stock_left)
            {
              
    xtc_db_query(xtc_db_query($status_update_sql));
            }
          }
          
    //Avenger
    PHP:
            if(($t_use_combis_quantity == && STOCK_CHECK ==  'true' && ATTRIBUTES_STOCK_CHECK == 'true') ||  $t_use_combis_quantity == 2){
                
    $t_quantity_change $order->products[$i]['qty'] * -1;
                
    $val $coo_properties->change_combis_quantity($t_combis_id$t_quantity_change);
            }
    ersetzen mit

    PHP:
           if(($t_use_combis_quantity == && STOCK_CHECK == 'true'  && ATTRIBUTES_STOCK_CHECK == 'true') || $t_use_combis_quantity  == 2){
            
    //Avenger
        //Delayed stock updates
        //For external payment-methods adjust stock only after real payment! 
            
    $t_quantity_change = -$order->products[$i]['qty'];
            if (
    $tmp)
            {
              
    $_SESSION['properties_update_data'][$t_combis_id]=$t_quantity_change;
            }
            else
            {
              
    $val $coo_properties->change_combis_quantity($t_combis_id$t_quantity_change);
            }
            
    //Avenger
          
    }
    PHP:
                xtc_db_query("UPDATE ".TABLE_PRODUCTS_ATTRIBUTES." set
                                                           attributes_stock=attributes_stock - '"
    .$order->products[$i]['qty']."'
                                                           where
                                                           products_id='"
    .$order->products[$i]['id']."'
                                                            and  options_values_id='"
    .$order->products[$i]['attributes'][$j]['value_id']."'
                                                            and  options_id='"
    .$order->products[$i]['attributes'][$j]['option_id']."'
                                                           "
    );
    ersetzen mit

    PHP:
          //Avenger
        //Delayed stock updates
        //For external payment-methods adjust stock only after real payment! 
          
    $sql="
            UPDATE 
              "
    .TABLE_PRODUCTS_ATTRIBUTES.
            SET
               attributes_stock=attributes_stock - '"
    .$order->products[$i]['qty']."'
            WHERE
               products_id='"
    .$products_id."'
               AND options_values_id='"
    .$order->products[$i]['attributes'][$j]['value_id']."'
               AND options_id='"
    .$order->products[$i]['attributes'][$j]['option_id']."'";
          if (
    $tmp)                  
          {
            
    $_SESSION['attributes_update_sql'][]=$sql;
          }
          else
          {
            
    xtc_db_query($sql);
          }
          
    //Avenger
    Nach
    PHP:
    if (!$tmp) {
    einfügen

    PHP:
      //Avenger     
      //Delayed stock updates
      //For external payment-methods adjust stock only after real payment! 
      //In that case updates sql have been stored in session and not have been applied directly!
      
    foreach ($updates_names as $updates_name)
      {
        
    $update_sqls=$_SESSION{$updates_name};
        if (
    $update_sqls)
        {
          if (
    $updates_name=='properties_update_data')
          {
            
    $coo_properties MainFactory::create_object('PropertiesControl');
            foreach (
    $update_sqls as $t_combis_id=>$t_quantity_change)
            {
              
    $val $coo_properties->change_combis_quantity($t_combis_id$t_quantity_change);
            }
          }
          else
          {
            foreach (
    $update_sqls as $update_sql)
            {
              
    xtc_db_query($update_sqls);
            }
          }
        }
        unset(
    $_SESSION{$updates_name});
      }
      
    //Avenger
    Wie immer gilt:

    Anwendung ausschließlich auf eigenes Risiko des Verwenders.

    Eine Gewährleistung jeglicher Art ist ausgeschlossen.

    Vor Einbau eine Sicherung der Shop-Programme vornehmen.

    Erst im Testshop testen.
     
  12. maxwell

    maxwell Erfahrener Benutzer

    Registriert seit:
    2. März 2012
    Beiträge:
    148
    Danke erhalten:
    18
    Danke vergeben:
    62
  13. Avenger

    Avenger G-WARD 2012/13/14/15

    Registriert seit:
    26. April 2011
    Beiträge:
    4.771
    Danke erhalten:
    1.478
    Danke vergeben:
    89
    Ich kann ja schon ganz schön viel, aber zaubern (noch?) nicht. :cool:

    Allerdings mit meinem USERMOD-Konzept kann man auch das updatesicher machen, da man im USERMOD-Bereich ein modifizierte Kopie davon anlegen kann.

    Die Lösung liegt ja vor....

     
  14. maxwell

    maxwell Erfahrener Benutzer

    Registriert seit:
    2. März 2012
    Beiträge:
    148
    Danke erhalten:
    18
    Danke vergeben:
    62
    Ich habe mich heute mal drangesetzt und im Testshop Deine Erweiterung installiert.
    Leider bekomme ich einen SQL-Fehler:

    ================================================================================
    2014-03-15 12-51-02 (0.0.0.0)
    WARNING(2): ltrim() expects parameter 1 to be string, array given
    in /www/htdocs/localhost/gx2/inc/xtc_db_query.inc.php:48
    Backtrace:
    #0 ltrim called at [/www/htdocs/localhost/gx2/inc/xtc_db_query.inc.php:48]
    #1 xtc_db_query called at [/www/htdocs/localhost/gx2/checkout_process.php:683]

    ================================================================================
    2014-03-15 12-51-02 (0.0.0.0)
    WARNING(2): mysql_query() expects parameter 1 to be string, array given
    in /www/htdocs/localhost/gx2/inc/xtc_db_query.inc.php:68
    Backtrace:
    #0 mysql_query called at [/www/htdocs/localhost/gx2/inc/xtc_db_query.inc.php:68]
    #1 xtc_db_query called at [/www/htdocs/localhost/gx2/checkout_process.php:683]

    ================================================================================
    ================================================================================

    Query: Array

    Error: (error 0)

    ================================================================================
    2014-03-15 12-51-02 (0.0.0.0)
    WARNING(512): SQL Error
    in /www/htdocs/localhost/gx2/inc/xtc_db_error.inc.php:33
    Backtrace:
    #0 trigger_error called at [/www/htdocs/localhost/gx2/inc/xtc_db_error.inc.php:33]
    #1 xtc_db_error called at [/www/htdocs/localhost/gx2/inc/xtc_db_query.inc.php:68]
    #2 xtc_db_query called at [/www/htdocs/localhost/gx2/checkout_process.php:683]

    Ich habe 2.0.14.4 und es handelte sich um eine Paypal-Sandbox-Zahlung. Vorkasse/Überweisung funktionierte übrigens.

    Hast Du ne Idee, woran das liegen könnte?
     
  15. Petra

    Petra G-WARD 2013/14/15

    Registriert seit:
    27. August 2011
    Beiträge:
    6.998
    Danke erhalten:
    1.225
    Danke vergeben:
    227
    Avenger, endlich mal einer, der mich versteht! Das mit den Lagerbeständen ist ein riesiges Problem, wenn man nicht als Dropshipper mit unendlichen Lagerbeständen arbeitet. Was mir auch aufgefallen ist - was ich bisher aber nicht kapiert habe - ist folgendes:

    Wir haben das PayPal-Gold Modul. Selbst damit werden im Shop Bestellungen generiert, die bold bleiben (also die Bestellbestätigungen nicht verschickt wurden). Die Lagerbestände werden abgezogen. Das Spiel können Kunden bis zum Ende des Lagerbestandes spielen.

    Dein Ansatz könnte die Lösung auch dafür sein. Allerdings verstehe ich es immer noch nicht so richtig, denn die Kunden müssen die Bestellung erst abschicken, dann erst kommen sie zum PP-Link. Also müsste die Bestellbestätigung doch definitiv versendet werden?
     
  16. Anonymous

    Anonymous Erfahrener Benutzer

    Registriert seit:
    10. August 2012
    Beiträge:
    1.554
    Danke erhalten:
    455
    Danke vergeben:
    96
    Marco hat dazu (Link nur für registrierte Nutzer sichtbar.) was geschrieben. Bei den Zahlarten die extern ablaufen wird die Bestätigung erst verschickt, wenn der Kunde wieder zurück im Shop ist.
     
  17. Avenger

    Avenger G-WARD 2012/13/14/15

    Registriert seit:
    26. April 2011
    Beiträge:
    4.771
    Danke erhalten:
    1.478
    Danke vergeben:
    89
    Das hatten wir ja auf dem User-Meeting schon diskutiert....

    Dein Ansatz ist eigentlich logisch, weil die Bestellung im Prinzip nicht mit der Zahlung verbunden ist.

    Daher wäre es logisch direkt nach Bestellung die Bestätigung zu versenden, statt auf die erfolgreiche Zahlung zu warten.

    Gambio arbeitet aber nicht so, sondern bestätigt bei externen Zahlungen erst, wenn die Zahlung Erfolg hatte.
     
  18. nicolesundermann

    nicolesundermann Mitglied

    Registriert seit:
    10. Januar 2014
    Beiträge:
    23
    Danke erhalten:
    0
    Danke vergeben:
    6
    Ist es nicht so, das sobald der Kunde auf "bestellen" gedrückt hat, auch der Vertrag gilt? Egal ob die Zahlung abbricht oder nicht? Dann ist doch der Kunde dazu verpflichtet zu zahlen egal wie... (mal abgesehen vom Widerrufsrecht) Also macht es doch sinn, das der Lagerbestand singt.. oder steh ich da auf dem Schlauch?
     
  19. Anonymous

    Anonymous Erfahrener Benutzer

    Registriert seit:
    6. Juni 2012
    Beiträge:
    433
    Danke erhalten:
    65
    Danke vergeben:
    69
    In vielen Fällen sind die Shop-AGB als "Invitatio ad offerendum" ausgelegt. D.h., der Kunde gibt mit der Bestellung lediglich seine Willenserklärung ab. Der Verkäufer behält sich das Recht vor, die Bestellung anzunehmen oder abzulehnen.

    Jedoch macht es meiner Meinung nach dennoch auch in vielen Fällen des Invitatio ad offerendum Sinn, den Lagerbestand sofort mit Bestellung sinken zu lassen - es kommt auf die Art der Produkte und der Konfektionierung an.
    Gambio hatte doch mal den Vorschlag gemacht, dem Shop-Betreiber beide Varianten zur Auswahl zu stellen - wahlweise Lagerbestand sinken bei Bestellung oder bei externer Zahlung. Diese Auswahl scheint mir die beste Lösung.
     
  20. Avenger

    Avenger G-WARD 2012/13/14/15

    Registriert seit:
    26. April 2011
    Beiträge:
    4.771
    Danke erhalten:
    1.478
    Danke vergeben:
    89
    Im Moment führt es aber dazu, dass der Lagerbestand auch sinkt, wenn die Bezahlung abgebrochen wird, und der Besteller auf Nimmerwiedersehen.verschwindet....