Newwebshop/app/controllers/admin/PaymentController.php

464 lines
15 KiB
PHP

<?php
/**
* Copyright seit 2024 Webshop System
*
* Payment Controller für Admin-Bereich
*
* @author Webshop System
* @license GPL v3
*/
namespace App\Controllers\Admin;
use App\Core\Payment;
use App\Core\MultiShop;
use App\Core\Security;
use App\Core\Configuration;
class PaymentController
{
private $payment;
private $multiShop;
private $security;
private $config;
public function __construct()
{
$this->payment = new Payment();
$this->multiShop = new MultiShop();
$this->security = new Security();
$this->config = new Configuration();
// Session-Check
if (!isset($_SESSION['admin_logged_in']) || !$_SESSION['admin_logged_in']) {
header('Location: /admin/login');
exit;
}
}
/**
* Payment-Dashboard anzeigen
*/
public function index()
{
$shopId = $this->multiShop->getCurrentShopId();
// Payment-Statistiken abrufen
$statistics = $this->payment->getPaymentStatistics($shopId);
// Verfügbare Zahlungsmethoden
$availableMethods = $this->payment->getAvailablePaymentMethods();
// Provider-Status prüfen
$providerStatus = [];
foreach (['paypal', 'stripe', 'sepa'] as $provider) {
$providerStatus[$provider] = $this->payment->checkPaymentProviderStatus($provider);
}
$data = [
'statistics' => $statistics,
'available_methods' => $availableMethods,
'provider_status' => $providerStatus,
'shop_id' => $shopId
];
$this->render('admin/payment/index.html.twig', $data);
}
/**
* PayPal-Konfiguration anzeigen
*/
public function paypal()
{
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$this->updatePayPalConfig();
}
$shopId = $this->multiShop->getCurrentShopId();
$data = [
'enabled' => $this->multiShop->getShopConfig('PAYMENT_PAYPAL_ENABLED', false),
'sandbox' => $this->multiShop->getShopConfig('PAYMENT_PAYPAL_SANDBOX', true),
'client_id' => $this->multiShop->getShopConfig('PAYMENT_PAYPAL_CLIENT_ID', ''),
'client_secret' => $this->multiShop->getShopConfig('PAYMENT_PAYPAL_CLIENT_SECRET', ''),
'webhook_id' => $this->multiShop->getShopConfig('PAYMENT_PAYPAL_WEBHOOK_ID', ''),
'connection_status' => $this->payment->checkPaymentProviderStatus('paypal'),
'shop_id' => $shopId
];
$this->render('admin/payment/paypal.html.twig', $data);
}
/**
* PayPal-Konfiguration aktualisieren
*/
private function updatePayPalConfig()
{
$shopId = $this->multiShop->getCurrentShopId();
// CSRF-Schutz
if (!$this->security->validateCSRFToken($_POST['csrf_token'] ?? '')) {
$this->addError('Sicherheitsfehler: Ungültiger Token');
return;
}
$config = [
'enabled' => isset($_POST['enabled']),
'sandbox' => isset($_POST['sandbox']),
'client_id' => trim($_POST['client_id'] ?? ''),
'client_secret' => trim($_POST['client_secret'] ?? ''),
'webhook_id' => trim($_POST['webhook_id'] ?? '')
];
// Validierung
if ($config['enabled']) {
if (empty($config['client_id'])) {
$this->addError('PayPal Client ID ist erforderlich');
return;
}
if (empty($config['client_secret'])) {
$this->addError('PayPal Client Secret ist erforderlich');
return;
}
}
// Konfiguration speichern
foreach ($config as $key => $value) {
$this->multiShop->setShopConfig("PAYMENT_PAYPAL_" . strtoupper($key), $value);
}
$this->addSuccess('PayPal-Konfiguration wurde erfolgreich aktualisiert');
}
/**
* Stripe-Konfiguration anzeigen
*/
public function stripe()
{
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$this->updateStripeConfig();
}
$shopId = $this->multiShop->getCurrentShopId();
$data = [
'enabled' => $this->multiShop->getShopConfig('PAYMENT_STRIPE_ENABLED', false),
'test_mode' => $this->multiShop->getShopConfig('PAYMENT_STRIPE_TEST_MODE', true),
'publishable_key' => $this->multiShop->getShopConfig('PAYMENT_STRIPE_PUBLISHABLE_KEY', ''),
'secret_key' => $this->multiShop->getShopConfig('PAYMENT_STRIPE_SECRET_KEY', ''),
'webhook_secret' => $this->multiShop->getShopConfig('PAYMENT_STRIPE_WEBHOOK_SECRET', ''),
'connection_status' => $this->payment->checkPaymentProviderStatus('stripe'),
'shop_id' => $shopId
];
$this->render('admin/payment/stripe.html.twig', $data);
}
/**
* Stripe-Konfiguration aktualisieren
*/
private function updateStripeConfig()
{
$shopId = $this->multiShop->getCurrentShopId();
// CSRF-Schutz
if (!$this->security->validateCSRFToken($_POST['csrf_token'] ?? '')) {
$this->addError('Sicherheitsfehler: Ungültiger Token');
return;
}
$config = [
'enabled' => isset($_POST['enabled']),
'test_mode' => isset($_POST['test_mode']),
'publishable_key' => trim($_POST['publishable_key'] ?? ''),
'secret_key' => trim($_POST['secret_key'] ?? ''),
'webhook_secret' => trim($_POST['webhook_secret'] ?? '')
];
// Validierung
if ($config['enabled']) {
if (empty($config['publishable_key'])) {
$this->addError('Stripe Publishable Key ist erforderlich');
return;
}
if (empty($config['secret_key'])) {
$this->addError('Stripe Secret Key ist erforderlich');
return;
}
}
// Konfiguration speichern
foreach ($config as $key => $value) {
$this->multiShop->setShopConfig("PAYMENT_STRIPE_" . strtoupper($key), $value);
}
$this->addSuccess('Stripe-Konfiguration wurde erfolgreich aktualisiert');
}
/**
* SEPA-Konfiguration anzeigen
*/
public function sepa()
{
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$this->updateSEPAConfig();
}
$shopId = $this->multiShop->getCurrentShopId();
$data = [
'enabled' => $this->multiShop->getShopConfig('PAYMENT_SEPA_ENABLED', false),
'test_mode' => $this->multiShop->getShopConfig('PAYMENT_SEPA_TEST_MODE', true),
'merchant_id' => $this->multiShop->getShopConfig('PAYMENT_SEPA_MERCHANT_ID', ''),
'iban' => $this->multiShop->getShopConfig('PAYMENT_SEPA_IBAN', ''),
'bic' => $this->multiShop->getShopConfig('PAYMENT_SEPA_BIC', ''),
'connection_status' => $this->payment->checkPaymentProviderStatus('sepa'),
'shop_id' => $shopId
];
$this->render('admin/payment/sepa.html.twig', $data);
}
/**
* SEPA-Konfiguration aktualisieren
*/
private function updateSEPAConfig()
{
$shopId = $this->multiShop->getCurrentShopId();
// CSRF-Schutz
if (!$this->security->validateCSRFToken($_POST['csrf_token'] ?? '')) {
$this->addError('Sicherheitsfehler: Ungültiger Token');
return;
}
$config = [
'enabled' => isset($_POST['enabled']),
'test_mode' => isset($_POST['test_mode']),
'merchant_id' => trim($_POST['merchant_id'] ?? ''),
'iban' => trim($_POST['iban'] ?? ''),
'bic' => trim($_POST['bic'] ?? '')
];
// Validierung
if ($config['enabled']) {
if (empty($config['merchant_id'])) {
$this->addError('SEPA Merchant ID ist erforderlich');
return;
}
if (empty($config['iban'])) {
$this->addError('SEPA IBAN ist erforderlich');
return;
}
if (empty($config['bic'])) {
$this->addError('SEPA BIC ist erforderlich');
return;
}
// IBAN-Validierung
if (!$this->validateIBAN($config['iban'])) {
$this->addError('Ungültige IBAN');
return;
}
// BIC-Validierung
if (!$this->validateBIC($config['bic'])) {
$this->addError('Ungültige BIC');
return;
}
}
// Konfiguration speichern
foreach ($config as $key => $value) {
$this->multiShop->setShopConfig("PAYMENT_SEPA_" . strtoupper($key), $value);
}
$this->addSuccess('SEPA-Konfiguration wurde erfolgreich aktualisiert');
}
/**
* IBAN validieren
*/
private function validateIBAN($iban)
{
$iban = str_replace(' ', '', strtoupper($iban));
if (strlen($iban) < 15 || strlen($iban) > 34) {
return false;
}
// IBAN-Prüfziffer berechnen
$country = substr($iban, 0, 2);
$check = substr($iban, 2, 2);
$account = substr($iban, 4);
$iban = $account . $country . $check;
$iban = str_replace(
['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'],
['10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23', '24', '25', '26', '27', '28', '29', '30', '31', '32', '33', '34', '35'],
$iban
);
return bcmod($iban, '97') == '1';
}
/**
* BIC validieren
*/
private function validateBIC($bic)
{
$bic = strtoupper($bic);
// BIC sollte 8 oder 11 Zeichen haben
if (strlen($bic) !== 8 && strlen($bic) !== 11) {
return false;
}
// Format: 4 Zeichen Bank-Code + 2 Zeichen Ländercode + 2 Zeichen Ort + 3 Zeichen Filiale (optional)
if (!preg_match('/^[A-Z]{4}[A-Z]{2}[A-Z0-9]{2}([A-Z0-9]{3})?$/', $bic)) {
return false;
}
return true;
}
/**
* Payment-Transaktionen anzeigen
*/
public function transactions()
{
$shopId = $this->multiShop->getCurrentShopId();
$page = (int)($_GET['page'] ?? 1);
$limit = 20;
$offset = ($page - 1) * $limit;
try {
$conn = $this->payment->getConnection();
// Transaktionen abrufen
$stmt = $conn->prepare('
SELECT
pt.*,
o.order_number,
o.total_amount as order_amount,
o.currency as order_currency
FROM ws_payment_transaction pt
JOIN ws_order o ON pt.order_id = o.id
WHERE o.shop_id = ?
ORDER BY pt.created_at DESC
LIMIT ? OFFSET ?
');
$stmt->execute([$shopId, $limit, $offset]);
$transactions = $stmt->fetchAllAssociative();
// Gesamtanzahl abrufen
$stmt = $conn->prepare('
SELECT COUNT(*) as total
FROM ws_payment_transaction pt
JOIN ws_order o ON pt.order_id = o.id
WHERE o.shop_id = ?
');
$stmt->execute([$shopId]);
$total = $stmt->fetchAssociative()['total'];
$data = [
'transactions' => $transactions,
'total' => $total,
'page' => $page,
'limit' => $limit,
'total_pages' => ceil($total / $limit),
'shop_id' => $shopId
];
$this->render('admin/payment/transactions.html.twig', $data);
} catch (\Exception $e) {
$this->addError('Fehler beim Laden der Transaktionen: ' . $e->getMessage());
$this->render('admin/payment/transactions.html.twig', ['transactions' => [], 'total' => 0]);
}
}
/**
* Payment-Statistiken als JSON
*/
public function statistics()
{
$shopId = $this->multiShop->getCurrentShopId();
$statistics = $this->payment->getPaymentStatistics($shopId);
header('Content-Type: application/json');
echo json_encode($statistics);
}
/**
* Payment-Provider testen
*/
public function testProvider()
{
$provider = $_POST['provider'] ?? '';
if (!in_array($provider, ['paypal', 'stripe', 'sepa'])) {
http_response_code(400);
echo json_encode(['success' => false, 'message' => 'Ungültiger Provider']);
return;
}
$status = $this->payment->checkPaymentProviderStatus($provider);
echo json_encode([
'success' => true,
'provider' => $provider,
'status' => $status,
'message' => $status ? 'Verbindung erfolgreich' : 'Verbindung fehlgeschlagen'
]);
}
/**
* Template rendern
*/
private function render($template, $data = [])
{
// CSRF-Token generieren
$data['csrf_token'] = $this->security->generateCSRFToken();
// Flash-Messages
$data['success_messages'] = $_SESSION['success_messages'] ?? [];
$data['error_messages'] = $_SESSION['error_messages'] ?? [];
// Session-Messages löschen
unset($_SESSION['success_messages'], $_SESSION['error_messages']);
// Template laden
$templatePath = __DIR__ . '/../../templates/' . $template;
if (file_exists($templatePath)) {
extract($data);
include $templatePath;
} else {
throw new \Exception("Template nicht gefunden: {$template}");
}
}
/**
* Erfolgs-Message hinzufügen
*/
private function addSuccess($message)
{
if (!isset($_SESSION['success_messages'])) {
$_SESSION['success_messages'] = [];
}
$_SESSION['success_messages'][] = $message;
}
/**
* Fehler-Message hinzufügen
*/
private function addError($message)
{
if (!isset($_SESSION['error_messages'])) {
$_SESSION['error_messages'] = [];
}
$_SESSION['error_messages'][] = $message;
}
}