PrestaShop PunchOut Integration
Voraussetzungen
- PrestaShop 1.7.x oder 8.x
- Admin-Zugriff auf PrestaShop
- SSL-Zertifikat (HTTPS)
- PunchFlow Account (Registrierung)
Schnellstart (3 Minuten)
Kein Modul nötig!
PunchFlow verbindet sich direkt über die PrestaShop WebService API. Sie müssen kein Modul installieren - alles läuft über die Standard-API.
Schritt 1: WebService aktivieren
- PrestaShop Backoffice öffnen
- Erweiterte Parameter → Webservice
- "Webservice aktivieren" auf Ja
- "Neuen Schlüssel hinzufügen" klicken
- Konfiguration:
Schlüsselname: PunchFlow Connector
Berechtigungen:
✅ products (GET)
✅ categories (GET)
✅ customers (GET, POST, PUT)
✅ carts (GET, POST, PUT, DELETE)
✅ orders (GET, POST)
✅ stock_availables (GET)
✅ combinations (GET)
✅ product_options (GET)
✅ product_option_values (GET)
✅ manufacturers (GET)
✅ currencies (GET)
✅ languages (GET)
✅ shops (GET) - API-Schlüssel 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": "prestashop",
"name": "PrestaShop Connector",
"api_url": "https://ihr-shop.de/api",
"authentication": {
"auth_type": "api_key",
"api_key": "XXXXXXXXXXXXXXXXXXXXX"
},
"custom_settings": {
"shop_id": 1,
"language_id": 1
}
}'
Erweiterte Konfiguration
API-Konfiguration
# PunchFlow-Einstellungen (in app.punchflow.de)
shop_connection:
type: "prestashop"
api_version: "1.7" # oder "8.0"
output_format: "JSON" # oder "XML"
# PunchOut-Einstellungen
punchout:
session_timeout: 3600 # Sekunden
allowed_protocols:
- cxml
- oci
auto_login: true
# Produkt-Mapping
mapping:
product_id_field: "reference" # oder "ean13", "upc"
price_calculation: "price_with_tax"
stock_management: true
include_combinations: true
# Kunden-Einstellungen
customers:
auto_create: true
default_group_id: 3 # B2B-Gruppe
require_approval: false
# Multistore
multistore:
enabled: false
shop_id: 1
shop_group_id: 1
# Logging
debug:
enabled: false
log_level: "info"
Multistore Konfiguration
// Dedizierter Shop für PunchOut
// In PrestaShop Admin: Shop-Parameter → Multistore
// Shop-Konfiguration via API
GET /api/shops?output_format=JSON
{
"shops": [
{
"id": 1,
"name": "Standard Shop"
},
{
"id": 2,
"name": "PunchOut B2B",
"theme_name": "punchout-theme"
}
]
}
Workflow-Integration
1. Session-Start
sequenceDiagram
ERP->>PunchFlow: PunchOut Setup Request
PunchFlow->>PrestaShop: Kunde anlegen/finden
PrestaShop->>PunchFlow: Customer ID
PunchFlow->>PrestaShop: Warenkorb erstellen
PrestaShop->>PunchFlow: Cart ID + Token
PunchFlow->>ERP: Setup Response mit URL
ERP->>PrestaShop: User Redirect zum Shop
2. WebService API Calls
// Warenkorb erstellen
$xml = '<?xml version="1.0" encoding="UTF-8"?>
<prestashop>
<cart>
<id_customer>' . $customerId . '</id_customer>
<id_currency>1</id_currency>
<id_lang>1</id_lang>
<associations>
<cart_rows>
<cart_row>
<id_product>' . $productId . '</id_product>
<id_product_attribute>0</id_product_attribute>
<quantity>1</quantity>
</cart_row>
</cart_rows>
</associations>
</cart>
</prestashop>';
$response = $webService->add([
'resource' => 'carts',
'postXml' => $xml
]);
3. Warenkorb-Transfer
// Cart zu cXML konvertieren
class PunchOutTransferService
{
public function transferCart(int $cartId, PunchOutSession $session): string
{
$cart = new Cart($cartId);
$products = $cart->getProducts();
$cxml = new CxmlBuilder();
$cxml->startPunchOutOrderMessage($session->getBuyerCookie());
foreach ($products as $product) {
$cxml->addItem([
'sku' => $product['reference'],
'name' => $product['name'],
'quantity' => $product['quantity'],
'unitPrice' => $product['price_with_tax'],
'currency' => $this->getCurrencyCode()
]);
}
$cxml->setTotal($cart->getOrderTotal(true));
return $cxml->build();
}
}
Produkt-Synchronisation
REST API Abfragen
# Alle Produkte abrufen
GET /api/products?output_format=JSON&display=full
# Produkt mit Kombinationen
GET /api/products/123?output_format=JSON&display=full
# Lagerbestand
GET /api/stock_availables?filter[id_product]=123&output_format=JSON
Produktdaten-Struktur
{
"product": {
"id": 123,
"reference": "SKU-001",
"name": [
{"id": 1, "value": "Produkt Name"}
],
"description": [
{"id": 1, "value": "Beschreibung..."}
],
"price": "99.990000",
"wholesale_price": "75.000000",
"ean13": "1234567890123",
"upc": "",
"manufacturer_name": "Hersteller",
"quantity": 50,
"active": "1",
"associations": {
"combinations": [
{"id": 45},
{"id": 46}
],
"categories": [
{"id": 2},
{"id": 5}
],
"images": [
{"id": 12}
]
}
}
}
Automatische Sync-Konfiguration
// modules/punchflow/classes/ProductSync.php
class ProductSync
{
public function syncProducts(): void
{
$products = Product::getProducts(
$this->context->language->id,
0, // Start
0, // Limit (0 = alle)
'id_product',
'ASC',
false,
true // Nur aktive
);
foreach ($products as $product) {
$this->punchflowApi->syncProduct([
'sku' => $product['reference'],
'name' => $product['name'],
'price' => Product::getPriceStatic($product['id_product']),
'stock' => StockAvailable::getQuantityAvailableByProduct($product['id_product'])
]);
}
}
}
Kunden-Management
Kunde erstellen
// Via WebService API
$xml = '<?xml version="1.0" encoding="UTF-8"?>
<prestashop>
<customer>
<lastname>Mustermann</lastname>
<firstname>Max</firstname>
<email>max@company.com</email>
<passwd>hashed_password</passwd>
<id_default_group>3</id_default_group>
<id_lang>1</id_lang>
<active>1</active>
<newsletter>0</newsletter>
<optin>0</optin>
</customer>
</prestashop>';
$customerId = $webService->add([
'resource' => 'customers',
'postXml' => $xml
]);
Kundengruppen für B2B
-- B2B Kundengruppe mit speziellen Preisen
INSERT INTO ps_group (id_group, reduction, price_display_method, show_prices, date_add, date_upd)
VALUES (3, 10.00, 1, 1, NOW(), NOW());
INSERT INTO ps_group_lang (id_group, id_lang, name)
VALUES (3, 1, 'B2B PunchOut');
Frontend-Anpassungen
PunchOut-Modus erkennen
{* templates/checkout/cart.tpl *}
{if isset($punchout_session)}
<div class="punchout-banner alert alert-info">
<p>{l s='Sie befinden sich in einer PunchOut-Sitzung'}</p>
<p>{l s='Käufer:'} {$punchout_session.buyer_id}</p>
</div>
<button type="button" class="btn btn-primary punchout-transfer"
data-session="{$punchout_session.token}">
{l s='Warenkorb an ERP übertragen'}
</button>
{/if}
JavaScript Integration
// themes/punchout/assets/js/punchout.js
document.addEventListener('DOMContentLoaded', function() {
const transferBtn = document.querySelector('.punchout-transfer');
if (transferBtn) {
transferBtn.addEventListener('click', async function() {
const sessionToken = this.dataset.session;
try {
const response = await fetch('/module/punchflow/transfer', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-PunchOut-Session': sessionToken
}
});
const data = await response.json();
if (data.redirect_url) {
window.location.href = data.redirect_url;
}
} catch (error) {
console.error('Transfer failed:', error);
alert('Übertragung fehlgeschlagen. Bitte versuchen Sie es erneut.');
}
});
}
});
Checkout-Anpassungen
// modules/punchflow/controllers/front/checkout.php
class PunchflowCheckoutModuleFrontController extends ModuleFrontController
{
public function initContent()
{
parent::initContent();
if ($this->isPunchOutSession()) {
// Zahlungsarten ausblenden
$this->context->smarty->assign([
'hide_payment' => true,
'punchout_mode' => true
]);
}
}
public function postProcess()
{
if (Tools::isSubmit('punchout_transfer')) {
$this->transferCart();
}
}
}
B2B-Funktionen
Spezielle B2B-Preise
// Preisberechnung für B2B-Kunden
class B2BPriceCalculator
{
public function getB2BPrice(int $productId, int $customerId): float
{
$customer = new Customer($customerId);
$groups = $customer->getGroups();
// Gruppenspezifischer Preis
$specificPrice = SpecificPrice::getSpecificPrice(
$productId,
$this->context->shop->id,
$this->context->currency->id,
$this->context->country->id,
$groups[0], // B2B Gruppe
1
);
if ($specificPrice) {
return $specificPrice['price'];
}
return Product::getPriceStatic($productId);
}
}
Staffelpreise
// Staffelpreise abrufen
$quantityDiscounts = SpecificPrice::getQuantityDiscounts(
$productId,
$shopId,
$currencyId,
$countryId,
$groupId
);
// Struktur: quantity, price, reduction, reduction_type
Testing
Test-Umgebung
# PrestaShop Test-Installation
docker run -d --name prestashop-test \
-e PS_INSTALL_AUTO=1 \
-e DB_SERVER=db \
-e DB_NAME=prestashop \
-p 8080:80 \
prestashop/prestashop:1.7
# Test-Produkte importieren
php bin/console prestashop:import:catalog test-products.csv
# WebService Test
curl -u "API_KEY:" "https://test.shop.de/api/products?output_format=JSON"
Automatische Tests
// tests/PunchOutFlowTest.php
class PunchOutFlowTest extends \PHPUnit\Framework\TestCase
{
public function testWebServiceConnection(): void
{
$webService = new PrestaShopWebService(
$this->shopUrl,
$this->apiKey,
false
);
$products = $webService->get([
'resource' => 'products',
'display' => '[id,reference,name]'
]);
$this->assertNotEmpty($products->products);
}
public function testCartCreation(): void
{
$cartId = $this->createPunchOutCart($this->customerId);
$this->assertIsInt($cartId);
$this->assertGreaterThan(0, $cartId);
}
public function testCartTransfer(): void
{
$session = $this->createPunchOutSession();
$cxml = $this->transferService->transfer($session);
$this->assertStringContainsString('<PunchOutOrderMessage>', $cxml);
}
}
Monitoring
Log-Konfiguration
// modules/punchflow/classes/Logger.php
class PunchFlowLogger
{
public function log(string $message, string $level = 'info'): void
{
PrestaShopLogger::addLog(
$message,
$this->getLevelCode($level),
null,
'PunchFlow',
null,
true
);
// Zusätzlich in Datei
file_put_contents(
_PS_LOG_DIR_ . 'punchflow.log',
date('Y-m-d H:i:s') . " [$level] $message\n",
FILE_APPEND
);
}
}
Admin Dashboard Widget
// modules/punchflow/views/templates/admin/dashboard.tpl
<div class="panel">
<div class="panel-heading">
PunchOut Analytics
</div>
<div class="panel-body">
<div class="row">
<div class="col-md-3">
<div class="stat-box">
<span class="value">{$sessions_today}</span>
<span class="label">Sessions heute</span>
</div>
</div>
<div class="col-md-3">
<div class="stat-box">
<span class="value">{$success_rate}%</span>
<span class="label">Erfolgsrate</span>
</div>
</div>
</div>
</div>
</div>
Troubleshooting
Häufige Probleme
Problem: WebService 401 Unauthorized
# API-Schlüssel prüfen
curl -v -u "API_KEY:" "https://shop.de/api/"
# SSL-Verifizierung
curl -k -u "API_KEY:" "https://shop.de/api/"
Problem: Produkte werden nicht gefunden
# Produkt-Resource prüfen
GET /api/products?filter[active]=1&output_format=JSON
# Reference/SKU Mapping prüfen
GET /api/products?filter[reference]=SKU-001&output_format=JSON
Problem: Warenkorb wird nicht erstellt
// Cart Debug
$cart = new Cart();
$cart->id_customer = $customerId;
$cart->id_currency = Configuration::get('PS_CURRENCY_DEFAULT');
$cart->id_lang = Configuration::get('PS_LANG_DEFAULT');
if (!$cart->add()) {
error_log('Cart creation failed: ' . Db::getInstance()->getMsgError());
}
Debug-Tools
# WebService Debug aktivieren
# In classes/webservice/WebserviceRequest.php
# $this->_debug = true;
# Request/Response loggen
tail -f var/logs/webservice.log
Performance-Optimierung
Caching
// Cache für Produktdaten
class ProductCache
{
private $cache;
public function getProduct(int $productId): ?array
{
$cacheKey = "product_$productId";
if ($cached = $this->cache->get($cacheKey)) {
return $cached;
}
$product = $this->loadProduct($productId);
$this->cache->set($cacheKey, $product, 3600);
return $product;
}
}
Batch-Operationen
// Mehrere Produkte in einem Request
GET /api/products?filter[id]=[1|2|3|4|5]&output_format=JSON&display=full
// Oder via SQL für bessere Performance (nur lesend)
$products = Db::getInstance()->executeS('
SELECT p.*, pl.name, sa.quantity
FROM ' . _DB_PREFIX_ . 'product p
LEFT JOIN ' . _DB_PREFIX_ . 'product_lang pl ON p.id_product = pl.id_product
LEFT JOIN ' . _DB_PREFIX_ . 'stock_available sa ON p.id_product = sa.id_product
WHERE p.active = 1
AND pl.id_lang = ' . (int)$langId
);
Weitere Ressourcen
Best Practices
- WebService Berechtigungen minimal halten
- Dedizierter Shop für PunchOut-Traffic (Multistore)
- B2B-Kundengruppe für Preisdifferenzierung
- Caching aktivieren für bessere Performance
- API-Key regelmäßig rotieren
- Logging aktivieren für Troubleshooting
Support
Bei Fragen oder Problemen:
- Email: prestashop@punchflow.de
- Telefon: +49 30 123 456 78
- Chat: app.punchflow.de/chat