Skip to main content

Magento 2 PunchOut Integration

Voraussetzungen​

  • Magento 2.4.0 oder höher
  • Admin-Zugriff auf Magento
  • SSL-Zertifikat (HTTPS)
  • PunchFlow Account (Registrierung)

Schnellstart (3 Minuten)​

Kein Modul nötig!

PunchFlow verbindet sich direkt ĂŒber die Magento 2 REST/GraphQL API. Sie mĂŒssen kein Modul installieren - alles lĂ€uft ĂŒber die Standard-API.

Schritt 1: Integration Token erstellen​

  1. Magento Admin öffnen
  2. System → Integrationen
  3. "Neue Integration hinzufĂŒgen" klicken
  4. Konfiguration:
    Name: PunchFlow Connector

    API Ressourcen-Zugriff:
    ✅ Catalog (Lesen)
    ✅ Sales (Lesen/Schreiben)
    ✅ Customers (Lesen/Schreiben)
    ✅ Carts (Lesen/Schreiben)
    ✅ Store (Lesen)
  5. Integration aktivieren und Access Token kopieren

Schritt 2: PunchFlow konfigurieren​

# Via API
curl -X POST "https://api.punchflow.de/api/v1/connectors?merchant_id=<YOUR_MERCHANT_ID>" \
-H "Authorization: Bearer YOUR_PUNCHFLOW_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"type": "magento2",
"name": "Magento 2 Connector",
"api_url": "https://ihr-shop.de/rest/V1",
"authentication": {
"auth_type": "bearer",
"access_token": "your-integration-token"
},
"custom_settings": {
"store_code": "default",
"use_graphql": true
}
}'

Erweiterte Konfiguration​

API-Konfiguration​

PunchFlow unterstĂŒtzt sowohl REST als auch GraphQL:

# PunchFlow-Einstellungen (in app.punchflow.de)
shop_connection:
type: "magento2"
api_version: "V1"
use_graphql: true # Aktiviert GraphQL fĂŒr schnellere Produktabfragen

# PunchOut-Einstellungen
punchout:
session_timeout: 3600 # Sekunden
allowed_protocols:
- cxml
- oci
auto_login: true

# Produkt-Mapping
mapping:
product_id_field: "sku" # oder "entity_id"
price_calculation: "final_price" # oder "price", "special_price"
stock_management: true

# Kunden-Einstellungen
customers:
auto_create: true
default_group_id: 2 # B2B-Kundengruppe
require_approval: false

# Logging
debug:
enabled: false
log_level: "info"

Store View Konfiguration​

Dedizierter Store View fĂŒr PunchOut:

# Store View erstellen via CLI
bin/magento store:create \
--name="PunchOut B2B" \
--code="punchout_b2b" \
--website_id=1 \
--group_id=1

# Konfiguration setzen
bin/magento config:set --scope=stores --scope-code=punchout_b2b \
web/unsecure/base_url "https://punchout.ihr-shop.de/"

Benutzer-Authentifizierung​

Automatische Anmeldung​

// app/code/PunchFlow/PunchOut/Plugin/CustomerSessionPlugin.php
class CustomerSessionPlugin
{
public function aroundAuthenticate(
\Magento\Customer\Model\Session $subject,
callable $proceed,
$customerId
) {
// PunchOut Session Check
if ($this->punchoutSession->isActive()) {
$customer = $this->getOrCreateCustomer(
$this->punchoutSession->getBuyerEmail()
);
return $subject->loginById($customer->getId());
}

return $proceed($customerId);
}
}

Kundengruppen-Mapping​

// di.xml Konfiguration
<type name="PunchFlow\PunchOut\Model\CustomerMapper">
<arguments>
<argument name="groupMapping" xsi:type="array">
<item name="ariba" xsi:type="number">3</item>
<item name="coupa" xsi:type="number">4</item>
<item name="oracle" xsi:type="number">5</item>
</argument>
</arguments>
</type>

Workflow-Integration​

1. Session-Start​

sequenceDiagram
ERP->>PunchFlow: PunchOut Setup Request
PunchFlow->>Magento: REST/GraphQL Session erstellen
Magento->>Magento: Kunde anlegen/anmelden
Magento->>PunchFlow: Session URL
PunchFlow->>ERP: Setup Response mit URL
ERP->>Magento: User Redirect zum Shop

2. Warenkorb-Transfer​

// Observer fĂŒr Cart Transfer
namespace PunchFlow\PunchOut\Observer;

class CheckoutSubmitObserver implements ObserverInterface
{
public function execute(Observer $observer)
{
$quote = $observer->getEvent()->getQuote();

if ($this->punchoutSession->isActive()) {
// Warenkorb an PunchFlow senden
$this->punchoutService->transferCart($quote);

// Redirect zur ERP
throw new LocalizedException(
__('Redirecting to procurement system...')
);
}
}
}

GraphQL Integration​

Produkt-Abfragen​

PunchFlow nutzt GraphQL fĂŒr effiziente Produktabfragen:

query GetProducts($search: String, $pageSize: Int, $currentPage: Int) {
products(
search: $search
pageSize: $pageSize
currentPage: $currentPage
) {
items {
sku
name
description {
html
}
price_range {
minimum_price {
final_price {
value
currency
}
}
}
stock_status
image {
url
}
... on ConfigurableProduct {
variants {
product {
sku
name
}
attributes {
code
value_index
}
}
}
}
total_count
page_info {
current_page
page_size
total_pages
}
}
}

Cart-Operationen​

mutation CreateCart {
createEmptyCart
}

mutation AddToCart($cartId: String!, $sku: String!, $quantity: Float!) {
addSimpleProductsToCart(
input: {
cart_id: $cartId
cart_items: [
{
data: {
sku: $sku
quantity: $quantity
}
}
]
}
) {
cart {
items {
id
product {
sku
name
}
quantity
prices {
row_total {
value
}
}
}
prices {
grand_total {
value
currency
}
}
}
}
}

Produkt-Synchronisation​

Automatische Sync-Konfiguration​

<!-- etc/crontab.xml -->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<group id="punchflow">
<job name="punchflow_sync_products"
instance="PunchFlow\PunchOut\Cron\SyncProducts"
method="execute">
<schedule>*/5 * * * *</schedule>
</job>
</group>
</config>

Manueller Sync​

# Alle Produkte synchronisieren
bin/magento punchflow:sync:products

# Nur geÀnderte Produkte (seit letztem Sync)
bin/magento punchflow:sync:products --changed-only

# Spezifische Kategorie
bin/magento punchflow:sync:products --category-id=42

Frontend-Anpassungen​

PunchOut-Modus erkennen​

<?php // view/frontend/templates/checkout/button.phtml ?>
<?php if ($block->isPunchoutSession()): ?>
<button type="button"
class="action primary checkout"
id="punchout-transfer-button"
data-mage-init='{"punchoutTransfer": {}}'>
<span><?= __('Zum Einkaufssystem zurĂŒck') ?></span>
</button>
<?php else: ?>
<?= $block->getChildHtml('default.checkout.button') ?>
<?php endif; ?>

JavaScript Integration​

// view/frontend/web/js/punchout-transfer.js
define([
'jquery',
'mage/url',
'mage/storage'
], function ($, urlBuilder, storage) {
'use strict';

return function (config, element) {
$(element).on('click', function () {
var serviceUrl = urlBuilder.build('punchout/cart/transfer');

$('body').trigger('processStart');

storage.post(serviceUrl, JSON.stringify({}))
.done(function (response) {
if (response.redirect_url) {
window.location.href = response.redirect_url;
}
})
.fail(function () {
alert($.mage.__('Transfer failed. Please try again.'));
})
.always(function () {
$('body').trigger('processStop');
});
});
};
});

B2B-Funktionen (Magento Commerce)​

Shared Catalog Integration​

// Preisberechnung fĂŒr B2B-Kunden
class B2BPriceResolver
{
public function getPrice(
ProductInterface $product,
CustomerInterface $customer
): float {
// Shared Catalog Preis abrufen
$sharedCatalogId = $this->getSharedCatalogId($customer);

if ($sharedCatalogId) {
return $this->sharedCatalogPrice->getPrice(
$product->getSku(),
$sharedCatalogId
);
}

return $product->getFinalPrice();
}
}

Company Account Mapping​

// Buyer zu Company zuordnen
class CompanyMapper
{
public function mapBuyerToCompany(
string $buyerId,
string $companyCode
): void {
$company = $this->companyRepository->get($companyCode);

// Kunde der Company zuordnen
$this->customerCompanyRelation->assign(
$buyerId,
$company->getId()
);
}
}

Testing​

Test-Umgebung einrichten​

# Test-Datenbank erstellen
bin/magento setup:db-schema:split-quote --host="localhost" --dbname="magento_quote"

# Test-Fixtures laden
bin/magento punchflow:fixtures:load --env=testing

# Test-Session erstellen
bin/magento punchflow:test:session \
--protocol=cxml \
--buyer-email=test@example.com

Automatische Tests​

// Test/Integration/PunchOutFlowTest.php
class PunchOutFlowTest extends \PHPUnit\Framework\TestCase
{
public function testCxmlSetupRequest(): void
{
$cxml = file_get_contents(__DIR__ . '/_files/setup-request.xml');

$request = $this->createRequest('POST', '/punchout/setup')
->withHeader('Content-Type', 'application/xml')
->withBody($cxml);

$response = $this->dispatch($request);

$this->assertEquals(200, $response->getStatusCode());
$this->assertStringContainsString(
'<Status code="200"',
$response->getBody()->getContents()
);
}

public function testCartTransfer(): void
{
// Session erstellen
$session = $this->createPunchoutSession();

// Produkt zum Warenkorb hinzufĂŒgen
$this->addProductToCart('TEST-SKU', 2);

// Transfer ausfĂŒhren
$response = $this->post('/punchout/transfer', [
'session_token' => $session->getToken()
]);

$this->assertStringContainsString(
'<PunchOutOrderMessage>',
$response->getContent()
);
}
}

Monitoring & Analytics​

Admin Dashboard Widget​

// Block/Adminhtml/Dashboard/PunchOut.php
class PunchOut extends \Magento\Backend\Block\Template
{
public function getSessionStats(): array
{
return [
'today' => $this->sessionRepository->countToday(),
'week' => $this->sessionRepository->countThisWeek(),
'month' => $this->sessionRepository->countThisMonth(),
'success_rate' => $this->calculateSuccessRate(),
];
}

public function getRecentSessions(): Collection
{
return $this->sessionRepository
->getList($this->getDefaultCriteria())
->setPageSize(10);
}
}

Logging​

<!-- etc/logging.xml -->
<config>
<group name="punchflow">
<handler name="punchflow_file" type="file">
<param name="path">var/log/punchflow.log</param>
<param name="level">INFO</param>
</handler>
<logger name="punchflow">
<handler>punchflow_file</handler>
</logger>
</group>
</config>

Troubleshooting​

HĂ€ufige Probleme​

Problem: Session wird nicht erstellt​

# Debug-Modus aktivieren
bin/magento config:set punchflow/debug/enabled 1

# Logs prĂŒfen
tail -f var/log/punchflow.log

# Verbindung testen
bin/magento punchflow:test:connection --verbose

Problem: GraphQL Fehler​

# GraphQL Schema neu generieren
bin/magento setup:upgrade
bin/magento cache:flush

# GraphQL Query testen
curl -X POST https://ihr-shop.de/graphql \
-H "Content-Type: application/json" \
-d '{"query": "{ products(search: \"test\") { items { sku name } } }"}'

Problem: Customer Token ungĂŒltig​

# Token-Lebensdauer prĂŒfen
bin/magento config:show oauth/access_token_lifetime/customer

# Token neu generieren
bin/magento punchflow:auth:refresh --customer-id=123

Debug-Tools​

# PunchOut Session simulieren
bin/magento punchflow:debug:session \
--dump-request \
--dump-response

# cXML validieren
bin/magento punchflow:validate:xml var/import/request.xml

Performance-Optimierung​

Caching-Strategie​

<!-- etc/cache.xml -->
<config>
<type name="punchflow_products" translate="label">
<label>PunchFlow Product Cache</label>
<description>Cached product data for PunchOut</description>
<lifetime>3600</lifetime>
</type>
</config>

Indexer fĂŒr Produktdaten​

// Indexer/ProductData.php
class ProductData implements IndexerActionInterface
{
public function executeFull(): void
{
// Alle Produkte fĂŒr PunchOut indizieren
$this->indexer->reindexAll();
}

public function executeRow($id): void
{
// Einzelnes Produkt neu indizieren
$this->indexer->reindexRow($id);
}
}

Weitere Ressourcen​

Best Practices​

  1. Separater Store View fĂŒr PunchOut-Traffic
  2. GraphQL nutzen fĂŒr schnellere Produktabfragen
  3. B2B Kundengruppen fĂŒr Preisdifferenzierung
  4. Caching aktivieren fĂŒr bessere Performance
  5. RegelmĂ€ĂŸige Synchronisation der Produktdaten
  6. Logging aktivieren fĂŒr Troubleshooting

Support​

Bei Fragen oder Problemen: