Magento-Bestellungen mit externen Systemen erzeugen

Was tun, wenn Bestellungen außerhalb des Webshops generiert werden (zum Beispiel im Ladengeschäft), aber im Magento-Shop verwaltet werden müssen? Diese Frage hatte ein Nutzer bei Magento Stackexchange („Create sale in magento using pos application“).

Da das externe System mit hoher Wahrscheinlichkeit auf einer anderen Programmiersprache als Magento basiert, bietet es sich an, die Bestellungen über die SOAP-v2-API im WS-I-Modus anzulegen.

SOAP-v2-API im WS-I-Modus?

Kurz gesagt: die SOAP-v2-API mit aktivierter WS-I-Compliance soll dafür sorgen, dass beim Zugriff auf Magento-Funktionen durch andere Programmiersprachen möglichst keine Kompatibilitätsprobleme auftreten.

Was verbirgt sich hinter diesem kryptischen Kürzel?

Eine API stellt eine Schnittelle dar. Über diese Schnittstelle können z.B. Programme miteinander kommunizieren.

SOAP ist ein Netzwerkprotokoll. Mit SOAP kann eine Webservice-API erstellt werden, also eine Schnittstelle, mittels der Systeme über das World Wide Web miteinander kommunizieren können.

Von dem Protokoll SOAP gibt es mehrere Versionen, die auch in Magento implementiert wurden. Mit den neueren Spezifikationen wurde die Kompatibilität zwischen Programmiersprachen erhöht. Das ist wichtig, weil die im Web sehr beliebte und für Magento verwendete Programmiersprache PHP in der Regel nicht für Warenwirtschafts- oder Kassensysteme verwendet wird.

Die von Magento als SOAP v2 bezeichnete Schnittstelle ermöglicht es prinzipiell, mit anderen Programmiersprachen auf Magento zuzugreifen, während v1 für PHP konzipiert ist. Um die Kompatibilität weiter zu erhöhen, kann der WS-I-Compliance-Modus aktiviert werden. Dank ihm erfüllt die Schnittstelle die Spezifikation der WS-Interoperability Organization. Diese Gruppe von Industriepartnern hat sich auf die Fahnen geschrieben, Betriebssystem- und Plattform-unabhängige Webservices (deswegen „WS“) durchzusetzen. Zu dieser Gruppe zählen illustre Namen wie Microsoft, SAP, Oracle, IBM und Intel.

Der Weg zur Bestellung

Um mit der SOAP-API zu arbeiten muss man wie oben beschrieben den WS-I-Modus aktivieren und unter „System > Web Services > SOAP/XML-RPC – Roles“ bzw. „System > Web Services > SOAP/XML-RPC – Users“ einen API-User mit den benötigten Rechten erstellen.

Eine Bestellung erzeugen Sie in den folgenden Schritten:

  • API-Session starten
  • „Einkaufswagen“ anlegen
  • Produkte hinzufügen
  • Kunde definieren
  • Rechnungs- und Lieferadresse hinzufügen
  • Versandart festlegen
  • Zahlungsart festlegen
  • Bestellung erzeugen

Den kompletten PHP-Code für die folgenden Abschnitte finden Sie auf GitHub: mzeis/Magento-SOAP-v2-WS-I-Examples

API-Session starten

Melden Sie sich mit den Zugangsdaten Ihres API-Users beim Webshop an.

$client = new MagentoSoapClient('http://test02.magentoshops.vm/api/v2_soap?wsdl=1');
$client->login("Admin", "Admin123");

Die Hauptaufrufe (wie oben zu sehen) finden Sie in createOrder.php. Sie rufen Methoden der Klasse MagentoSoapClient auf (siehe unten).

public function login($name, $password)
{
    $data = array(
        'username' => $name,
        'apiKey' => $password
    );
    $response = $this->_client->login($data);
    $this->_sessionId = $response->result;
}

Verwendet man die Magento SOAP-API v2 mit aktivierter WS-I-Compliance, dann müssen die Argumente als assoziatives Array (in PHP) oder Objekt (in PHP und anderen Sprachen) übergeben werden.

$this->_client ist eine SOAP-Client-Instanz (Klasse SoapClient).  login ist die API-Methode, die aufgerufen wird.

Die Antwort, die Sie von Magento erhalten, ist ein Objekt. result enthält die eigentlichen Antwortdaten.

Die login-Methode gibt eine Session-ID zurück. Wir benötigen sie bei den folgenden Aufrufen, um uns zu identifizieren.

Dokumentation: http://www.magentocommerce.com/api/soap/introduction.html

„Einkaufswagen“ anlegen

Erstellen Sie einen „Einkaufswagen“ bzw. „Warenkorb“ (in Magento als „cart“ bezeichnet bzw. in unserem Fall gleichbedeutend mit einer „quote“ ). Der Einkaufswagen wird im letzten Schritt in eine Bestellung umgewandelt.

$cartId = $client->createCart();

Sie erhalten als Rückmeldung eine Cart-ID (bzw. „Quote-ID“). Sie werden sie für die weiteren Schritte benötigen.

public function createCart()
{
    $data = array(
        'sessionId' => $this->_sessionId
    );
    $response = $this->_client->shoppingCartCreate($data);
    return $response->result;
}

shoppingCartCreate ist die API-Methode, die Sie aufrufen müssen. Beachten Sie bitte, dass die Session-ID bei jedem Aufruf übergeben wird.

In der Dokumentation der API-Methoden finden Sie alle Parameter, die Sie an Magento übergeben können. Zum Beispiel übermittle ich keinen Store-Code. Dadurch werden die Bestellungen im Admin-Store angelegt. Sie werden die Bestellungen vermutlich in einem anderen Store erstellen wollen.

Dokumentation: http://www.magentocommerce.com/api/soap/checkout/cart/cart.create.html

Produkte hinzufügen

Fügen wir ein simples Produkt zum Warenkorb hinzu.

$products = array(
    array(
        'sku' => 'test',
        'qty' => 1
    )
);
$productsAdded = $client->addProductsToCart($cartId, $products);

Solange man keine Optionen oder komplexere Produktarten verwendet, ist dieser Aufruf sehr einfach. Mit einem Aufruf können mehrere Produkte übergeben werden.

public function addProductsToCart($cartId, array $products)
{
    $data = array(
        'sessionId' => $this->_sessionId,
        'quoteId' => $cartId,
        'productsData' => $products
    );
    $response = $this->_client->shoppingCartProductAdd($data);
    return $response->result;
}

Die API-Methode lautet shoppingCartProductAdd. Bitte beachten Sie, dass wir von nun an nicht nur die Session-ID, sondern immer auch die Cart-ID („Quote-ID“) übergeben.

Dokumentation: http://www.magentocommerce.com/api/soap/checkout/cartProduct/cart_product.add.html

Kunde definieren

Nun müssen Sie den Kunden für den Warenkorb definieren.

$customer = array(
    'firstname' => 'John',
    'lastname' => 'Doe',
    'email' => '[email protected]',
    'mode' => 'guest'
);
$customerSet = $client->setCustomerForCart($cartId, $customer);

Das ist die einfachste Form. Je nach Ihren Anforderungen können Sie auch vorhandene Magento-Kunden verwenden oder neue anlegen. Um das Beispiel übersichtlich zu halten, führe ich eine Gastbestellung aus.

public function setCustomerForCart($cartId, array $customer)
{
    $data = array(
        'sessionId' => $this->_sessionId,
        'quoteId' => $cartId,
        'customerData' => $customer
    );
    $response = $this->_client->shoppingCartCustomerSet($data);
    return $response->result;
}

Die API-Methode heißt shoppingCartCustomerSet.

Dokumentation: http://www.magentocommerce.com/api/soap/checkout/cartCustomer/cart_customer.set.html

Rechnungs- und Lieferadresse hinzufügen

Im nächsten Schritt müssen Sie die Rechnungs- und Lieferadresse festlegen.

$billingAdress = array(
    'mode' => 'billing',
    'firstname' => 'John',
    'lastname' => 'Doe',
    'street' => ' Street 123',
    'city' => 'Vienna',
    'region' => 'WI',
    'postcode' => '1170',
    'country_id' => 'AT',
    'telephone' => '+431234567890',
    'is_default_billing' => 1
);
$shippingAddress = array(
    'mode' => 'shipping',
    'firstname' => 'John',
    'lastname' => 'Doe',
    'street' => ' Street 123',
    'city' => 'Vienna',
    'region' => 'WI',
    'postcode' => '1170',
    'country_id' => 'AT',
    'telephone' => '+431234567890',
    'is_default_shipping' => 1
);
$addresses = array(
    $billingAdress,
    $shippingAddress
);
$addressesAdded = $client->addAddressesToCart($cartId, $addresses);

Beachten Sie, dass Sie spezielle Codes für „Region“ und die „Country-ID“ angeben müssen. Sie können die verfügbaren Länder und Regionen über die API abfragen. Wenn Sie keine Rechnungs- oder Lieferadressen verwalten müssen, können Sie eine fixe Adresse hinterlegen und ersparen sich das Mapping Ihrer Codes auf die Magento-Codes.

Dieser sowie die folgenden Aufrufe geben einen boolschen Wert zurück. Er zeigt an, ob die Aktion erfolgreich ausgeführt werden konnte.

public function addAddressesToCart($cartId, array $addresses)
{
    $data = array(
        'sessionId' => $this->_sessionId,
        'quoteId' => $cartId,
        'customerAddressData' => $addresses
    );
    $response = $this->_client->shoppingCartCustomerAddresses($data);
    return $response->result;
}

Auch hier gibt es wenig Neues. shoppingCartCustomerAddresses ist die API-Methode der Wahl.

Dokumentation: http://www.magentocommerce.com/api/soap/checkout/cartCustomer/cart_customer.addresses.html

Versandart festlegen

Nun definieren Sie die Versandart.

$shippingMethodSet = $client->setShippingMethodForCart($cartId, 'flatrate_flatrate');

Ich habe die Standardversandart einer neuen Magento-Installation gewählt. Sie werden vermutlich die Liste der verfügbaren Versandarten abfragen wollen.

public function setShippingMethodForCart($cartId, $shippingMethod)
{
    $data = array(
        'sessionId' => $this->_sessionId,
        'quoteId' => $cartId,
        'shippingMethod' => $shippingMethod
    );
    $response = $this->_client->shoppingCartShippingMethod($data);
    return $response->result;
}

Die Versandart wird über die API-Methode `shoppingCartShippingMethod gesetzt.

Dokumentation: http://www.magentocommerce.com/api/soap/checkout/cartShipping/cart_shipping.method.html

Zahlungsart festlegen

Nun tun wir das gleiche für die Zahlungsart.

$paymentMethodSet = $client->setPaymentMethodForCart($cartId, 'checkmo');

Auch hier verwende ich die Standard-Zahlungsart („Zahlungsanweisung“). Sie können die Liste der verfügbaren Zahlungsarten über die API abfragen.

public function setPaymentMethodForCart($cartId, $paymentMethod)
{
    $data = array(
        'sessionId' => $this->_sessionId,
        'quoteId' => $cartId,
        'paymentData' => array(
            'method' => $paymentMethod
        )
    );
    $response = $this->_client->shoppingCartPaymentMethod($data);
    return $response->result;
}

Wie Sie sehen können heißt die API-Methode shoppingCartPaymentMethod. In der Dokumentation finden Sie zusätzliche Informationen, die für Zahlungen übermittelt werden können.

Dokumentation: http://www.magentocommerce.com/api/soap/checkout/cartPayment/cart_payment.method.html

Bestellung erzeugen

Nun können wir die Bestellung anlegen.

$orderId = $client->createOrderFromCart($cartId);

Als Rückmeldung erhalten Sie die „Increment Order ID“ von Magento, also die Bestellnummer. Wenn alles funktioniert hat, finden Sie im Magento-Backend eine Bestellung vor. Mit den in der API-Dokumentation aufgeführten Methoden können Sie damit weitere Informationen über die Bestellung abfragen.

public function createOrderFromCart($cartId)
{
    $data = array(
        'sessionId' => $this->_sessionId,
        'quoteId' => $cartId
    );
    $response = $this->_client->shoppingCartOrder($data);
    return $response->result;
}

Der letzte API-Aufruf ist shoppingCartOrder.

Dokumentation: http://www.magentocommerce.com/api/soap/checkout/cart/cart.order.html

Fazit

Wenn man nicht auf einen der ab und zu vorhandenen Bugs stößt, ist der Umgang mit der Magento-API gar nicht so schwierig (sobald man die Funktionsweise einmal verstanden hat).

Vergewissern Sie sich, dass Sie den WSDL-Cache aktiviert haben. Ansonsten können die Aufrufe sehr lange dauern. Wenn alle Caches aktiviert sind, sollten alle Aufrufe sehr schnell sein (mit Ausnahme des letzten Aufrufs zur Erzeugung der Bestellung – er kann einige Sekunden benötigen).

Falls Sie feststellen, dass Magento Ihre Anwendung blockiert oder aufgrund der Bestellmengen eine Abwicklung in Echtzeit nicht möglich ist, müssen Sie eventuell eine Queue implementieren und die Bestellungen asynchron einspielen.

3 Antworten

  1. Hi Matthias,
    vielen Dank für diese Erläuterung und den Code. Sehr schön und detailliert erläutert. Ich war neugierig ob es möglich ist eine Bestellung in Magento von ausserhalb Magentos zu erstellen und bin so auf deinen Blog gekommen.

    Mir geht’s darum weniger ein POS oder Warenwirtschaftssystem die Bestellung erzeugen zu lassen, sondern eher zum Beispiel einen oder auch mehrere Großkunden, über eine entsprechende Schnittstelle.
    Dabei wäre es natürlich wichtig, dass der Kunde lediglich die jeweiligen Produkte, die bestellt werden sollen, und seine Kundennummer übermittelt, aber keine Möglichkeit hat z.B. die Versandart, Zahlart und ggf. auch nicht die Kundendaten, Rechnungsadresse oder Lieferadresse zu ändern.

    Ich gehe davon aus, dass man mit deinem Codebeispiel eine solche Schnittstelle herstellen könnte?

    Ein vermutlich größeres Problem ist unser Bedarf Produkt-Optionen und sogar ein Foto übermittelt zu bekommen, wäre das ebenfalls über die SOAP API möglich?

    Gruss
    Etienne Renaud

  2. Robin sagt:

    Hallo Matthias,

    Dein Beispiel funktioniert nach einigen Problemchen in der Konfiguration ganz gut. Ich mußte allerdings index.php voranstellen:


    new MagentoSoapClient('http://test02.magentoshops.vm/index.php/api/v2_soap?wsdl=1');

    Aktuell versuche ich benutzerdefinierte Attribute mit zu übergeben und verzweifle ein wenig. Habe verschiedene Varianten ausprobiert. Dem Test-Artikel habe ich ein neues Default Attribut hinzugefügt (einfaches Texteingabefeld).


    $products = array(
    array(
    'sku' => 'test',
    'qty' => 1,
    'additional_attributes' => array(
    'single_data' => array(
    "key" => "testattr1", "value" => "Hallo Welt"
    )
    )
    )
    );

    andere Variante


    $products = array(
    array(
    'sku' => 'test',
    'qty' => 1,
    'options' => array(
    'testattr1' => "Hallo Welt"
    )
    )
    )
    );

    Leider funktioniert das nicht wirklich, ist der Ansatz falsch?

    Liebe Grüße aus Bonn

    Robin

    • Hallo Robin,
      du bist auf einen Bug in der SOAP-v2-WS-I-API gestoßen, von dem auch meine Kollegin Anna betroffen war.
      Du kannst den Code wie dort erwähnt oder wie in diesem für mageplus beschriebenen Patch anpassen und dann die zusätzlichen Attribute direkt als assoziatives Array unterhalb von „additional_attributes“ angeben (ohne die Ebene „single_data“).