Eigene Order für jeden einzelnen Warenkorbartikel abspeichern

module
oxid6
#1

Ich möchte aus jedem einzelnen Artikel eines Warenkorbs eine einzelne Order anlegen (ob das so Sinn macht ist erst mal wurscht). Dazu habe ich im OrderController die execute-Methode überschrieben und gehe je nach Anzahl der ursprünglichen Warenkorbartikel einmal durch und kreiere jeweils einen neuen Warenkorb den ich als eigene Order abspeichern möchte. Leider wird das völlig ignoriert und ich habe immer nur eine einzelne Order im Backend sichtbar bei der der jeweils erste Artikel der Bestellung in der Anzahl verdoppelt wird. Hier mal meine execute-Methode:

public function execute()
{
    if (!$this->getSession()->checkSessionChallenge()) {
        return;
    }

    if (!$this->_validateTermsAndConditions()) {
        $this->_blConfirmAGBError = 1;

        return;
    }

    // additional check if we really really have a user now
    $oUser = $this->getUser();
    if (!$oUser) {
        return 'user';
    }

    // get basket contents
    $oBasket = $this->getSession()->getBasket();
    if ($oBasket->getProductsCount()) {
        try {

            $basketitems = $oBasket->getContents();
        
            foreach ($basketitems as $basketitem) {
            
                $article = $basketitem->getArticle();
                $newBasket = oxNew(\OxidEsales\Eshop\Application\Model\Basket::class);
                $newBasket->setBasketUser($oUser);
                $newBasket->load();
                $newBasket->addToBasket($article->getId(), $basketitem->getAmount());
		    if ($newBasket->getProductsCount()) {
	                $oOrder = oxNew(\OxidEsales\Eshop\Application\Model\Order::class);
	                //finalizing ordering process (validating, storing order into DB, executing payment, setting status ...)
	                $iSuccess = $oOrder->finalizeOrder($newBasket, $oUser);
 	            }

	            // performing special actions after user finishes order (assignment to special user groups)
	            $oUser->onOrderExecute($newBasket, $iSuccess);
		}

            // proceeding to next view
            return $this->_getNextStep($iSuccess);
        } catch (\OxidEsales\Eshop\Core\Exception\OutOfStockException $oEx) {
            $oEx->setDestination('basket');
            \OxidEsales\Eshop\Core\Registry::getUtilsView()->addErrorToDisplay($oEx, false, true, 'basket');
        } catch (\OxidEsales\Eshop\Core\Exception\NoArticleException $oEx) {
            \OxidEsales\Eshop\Core\Registry::getUtilsView()->addErrorToDisplay($oEx);
        } catch (\OxidEsales\Eshop\Core\Exception\ArticleInputException $oEx) {
            \OxidEsales\Eshop\Core\Registry::getUtilsView()->addErrorToDisplay($oEx);
        }
    }
}

Was funktioniert da nicht? Oder habe ich einen kompletten Denkfehler und müsste ich das anders lösen?

#2

was heist das genau? Wird der Code nicht durchlaufen?

#3

Mir ist nicht klar wo $basketitems.her kommt.
Da hilft eigentlich nur Eclipse und debuggen.
Gruß

#4

Sorry,
die Zeile
$basketitems = $oBasket->getContents();
kommt als erstes im try/catch Block, hatte ich aus Versehen rausgelöscht. Hab’s im Code nachgetragen.

#5

Der Code wird ohne Fehler durchlaufen, nur werden nicht wie erwartet 2 Order geschrieben, sondern nur eine.

#6

Ist wohl der reload blocker, die OXID wird im OrderController::render gesetzt.

#7
 $newBasket->load();

füllt Deinen neuen Basket mit den Artikeln.
So ist es 4.10.4 codiert.

public function load()
{
$oUser = $this->getBasketUser();
if (!$oUser) {
return;
}

    $oBasket = $oUser->getBasket('savedbasket');

    // restoring from saved history
    $aSavedItems = $oBasket->getItems();
    foreach ($aSavedItems as $oItem) {
        try {
            $oSelList = $oItem->getSelList();

            $this->addToBasket($oItem->oxuserbasketitems__oxartid->value, $oItem->oxuserbasketitems__oxamount->value, $oSelList, $oItem->getPersParams(), true);
        } catch (oxArticleException $oEx) {
            // caught and ignored
        }
    }
}
#8

$newBasket->load(); lasse ich inzwischen weg, außerdem rufe ich die finalizeOrder noch mit einen dritten Parameter RecalculatingOrder = ‘true’ auf. Nun werden tatsächlich 2 (oder mehr) Order mit eigener Ordernummer angelegt.

Den beiden Ordern fehlen allerdings die neu zugeordneten Artikel, obwohl diese im neu angelegten Basket vorhanden sind (schreibe mir den Inhalt in ein Logfile raus), der Gesamtbetrag der Order stimmt dafür.

In der Tabelle oxorderarticles werden außerdem die Artikel der jeweiligen Order eingetragen, allerdings fehlt der Eintrag im Feld OXORDERID, also die Beziehung zwischen der Order und ihrem Artikel. Trage ich die OrderId manuell nach, stimmt alles.

Kann doch nur noch eine Kleinigkeit sein, was übersehe ich?

#9

evtl. $newBasket->setOrderId( $newID );

#10

Danke für den Tipp. Nutzt leider nichts. Wenn ich mir den Inhalt des neu erstellten Warenkorbs ausgeben lasse, passt alles, Artikel und Stückzahl. Wenn ich für die neu erstellte Order finalizeOrder aufrufe und den neuen Warenkorb übergebe, wird die Order auch geschrieben mit der korrekten Ordersumme. Den bestellten Artikel finde ich auch in der oxorderarticles, nur ohne Verbindung zur neu erstellten Order.

#11

Werden die Mails erzeugt ?

#12

Ich muss gestehen, ich steige nicht mehr so ganz durch. Rufe ich im OrderController in der execute()-Methode die finalizeOrder()-Methode des Order-Objekts mit meinen neuen Baskets, dem aktuellen User und dem dritte Parameter true (recalculatingOrder) auf, wird alles ordentlich angelegt, außer das die OrderArticles keinen Bezug zu ihrer Order haben. In diesem Fall werden auch keine Mails versandt, weil dann ja auch die sendOrderByEmail() Methode des Order-Objekts nicht aufgerufen wird.

Rufe ich die finalizeOrder()-Methode des Order-Objekts mit dem dritten Parameter false auf, wird nur eine Order mit nur einem Artikel angelegt (dem ersten meiner Schleife aus dem OrderController), alle weiteren Baskets, die ich per finalizeOrder() der Order.php übergebe werden ignoriert. Dafür werden die Emails mehrfach mit dem identischen Warenkorbinhalt verschickt.

Lasse ich mir die Inhalte meiner neu angelegten Warenkörbe im OrderController in ein Logfile ausgeben, stimmt alles, Artikel sowie deren Anzahl. Ich habe den Eindruck, dass die finalizeOrder-Methode nicht meine übergebenen Warenkörbe verwendet, sondern irgeneinen anderen, z.B. doch wieder aus der Session. Da steige ich dann aus :frowning:

So einfach scheint es dann doch nicht zu sein und im OrderController nur über den urspünglichen Warenkorb zu gehen und jeweils mit einem neuen Warenkorb pro Artikel die finalizeOrder()-Methode aufzurufen um jeweils neue Order anzulegen. Muss mir da wohl einen anderen Ansatz überlegen, so komme ich nicht weiter, vor allem sehe ich das Problem im Quellcode nicht.

#13

Wahrscheinlich einen, der keine gemeinsame OrderId hat. Ist keine vorhanden, legt oxid selbst eine an. Deswegen setorderid und evtl. auch calculateBasket auf true.

#14

1000 Dank rubbercut! Mit setOrderId($id) funktionierts. So ganz ist mir zwar nicht klar, wann man bei einem Objekt ‘manuell’ eine ID setzen muss und wann nicht, aber damit funktionierts.

Mit den doppelten Emails habe ich mir mal wieder selbst ein Bein gestellt, da ich mit dem Account die Testorder gemacht habe, der auch als Shopbetreiber eingetragen ist, die Mails habe ich also Kunde und als Shopbetreiber erhalten. So gesehen passt’s :slight_smile:

// send order by email to shop owner and current user
// skipping this action in case of order recalculation
if (!$blRecalculatingOrder) {
    $iRet = $this->_sendOrderByEmail($oUser, $oBasket, $oUserPayment);
} else {
    $iRet = self::ORDER_STATE_OK;
}

Da ich finalizeOrder mit $blRecalculatingOrder = true aufrufe, muss ich die if/else Abfrage auskommentieren, damit tatsächlich auch die Emails versendet werden. Das ist mit noch nicht ganz klar, aber es funktioniert.

Und die Order sehe ich im Backend erst, wenn ich die Selectbox von ‘neu’ auf ‘alle’ setze, ob die einlaufenden Order im Ordner ‘neu’ liegen und den Status ‘ok’ haben, ich sehe keinen Unterschied zu den Ordern, die gleich mit der Auswahl ‘neu’ angezeigt werden. Aber das scheint nur ein Detail zu sein, meibe Testorder sehen in den Tabellen oxorder und oxorderarticles gut aus.

Nochmals Danke.