mollie MyBank
-
+ img/method/mybank@2x.png
17
0
mollie.com
diff --git a/version/108/paymentmethod/JTLMollie.php b/version/108/paymentmethod/JTLMollie.php
index 4f71142..11511bc 100644
--- a/version/108/paymentmethod/JTLMollie.php
+++ b/version/108/paymentmethod/JTLMollie.php
@@ -628,6 +628,7 @@ public function finalizeOrder($order, $hash, $args)
$this->doLog("JTLMollie::finalizeOrder::locked ({$args['id']})", $logData, LOGLEVEL_DEBUG);
} else {
$this->doLog("JTLMollie::finalizeOrder::locked failed ({$args['id']})", $logData, LOGLEVEL_ERROR);
+ return false;
}
$oOrder = self::API()->orders->get($args['id'], ['embed' => 'payments']);
diff --git a/version/109/adminmenu/info.php b/version/109/adminmenu/info.php
new file mode 100644
index 0000000..292064e
--- /dev/null
+++ b/version/109/adminmenu/info.php
@@ -0,0 +1,64 @@
+assign('defaultTabbertab', Helper::getAdminmenu('Info'));
+ Helper::selfupdate();
+ }
+
+ $svgQuery = http_build_query([
+ 'p' => Helper::oPlugin()->cPluginID,
+ 'v' => Helper::oPlugin()->nVersion,
+ 's' => defined('APPLICATION_VERSION') ? APPLICATION_VERSION : JTL_VERSION,
+ 'b' => defined('JTL_MINOR_VERSION') ? JTL_MINOR_VERSION : '0',
+ 'd' => Helper::getDomain(),
+ 'm' => base64_encode(Helper::getMasterMail(true)),
+ 'php' => PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION . '.' . PHP_RELEASE_VERSION . PHP_EXTRA_VERSION,
+ ]);
+
+ echo "";
+ echo "" .
+ "
" .
+ "
" .
+ " " .
+ ' ' .
+ '
' .
+ "
" .
+ "
" .
+ " " .
+ ' ' .
+ '
' .
+ "
" .
+ "
" .
+ " " .
+ ' ' .
+ '
' .
+ '
';
+
+ try {
+ $latestRelease = Helper::getLatestRelease(array_key_exists('update', $_REQUEST));
+ if ((int)Helper::oPlugin()->nVersion < (int)$latestRelease->version) {
+ Shop::Smarty()->assign('update', $latestRelease);
+ }
+
+ } catch (\Exception $e) {
+ }
+
+ Shop::Smarty()->display(Helper::oPlugin()->cAdminmenuPfad . '/tpl/info.tpl');
+
+ if (file_exists(__DIR__ . '/_addon.php')) {
+ try {
+ include __DIR__ . '/_addon.php';
+ } catch (Exception $e) {
+ }
+ }
+
+} catch (Exception $e) {
+ echo "Fehler: {$e->getMessage()}
";
+ Helper::logExc($e);
+}
\ No newline at end of file
diff --git a/version/109/adminmenu/orders.php b/version/109/adminmenu/orders.php
new file mode 100644
index 0000000..ff35df5
--- /dev/null
+++ b/version/109/adminmenu/orders.php
@@ -0,0 +1,245 @@
+details). '
+ . 'Das kann dazu führen, dass Bestellungen, trotz erfolgreicher Zahlung, nicht abgeschlossen werden können. '
+ . 'Die Zahlung muss dann manuell storniert werden. Es wird empfohlen, die Session-Laufzeit mindestens auf '
+ . 'die längste Gültigkeit der verwendeten Zahlungsmethoden einzustellen (z.B. Klarna: 172800 Sekunden).',
+ ini_get('session.gc_maxlifetime')), 'warning', 'orders');
+ }
+
+ if (array_key_exists('action', $_REQUEST)) {
+ switch ($_REQUEST['action']) {
+
+
+ case 'export':
+
+ try {
+
+ $export = [];
+
+ $from = new DateTime($_REQUEST['from']);
+ $to = new DateTime($_REQUEST['to']);
+
+ $orders = Shop::DB()->executeQueryPrepared('SELECT * FROM xplugin_ws_mollie_payments WHERE kBestellung > 0 AND dCreatedAt >= :From AND dCreatedAt <= :To ORDER BY dCreatedAt', [
+ ':From' => $from->format('Y-m-d'),
+ ':To' => $to->format('Y-m-d'),
+ ], 2);
+
+
+ $api = JTLMollie::API();
+
+ header('Content-Type: application/csv');
+ header('Content-Disposition: attachment; filename=mollie-' . $from->format('Ymd') . '-' . $to->format('Ymd') . '.csv');
+ header('Pragma: no-cache');
+
+ $out = fopen('php://output', 'w');
+
+
+ fputcsv($out, [
+ 'kBestellung',
+ 'OrderID',
+ 'Status (mollie)',
+ 'BestellNr',
+ 'Status (JTL)',
+ 'Mode',
+ 'OriginalOrderNumber',
+ 'Currency',
+ 'Amount',
+ 'Method',
+ 'PaymentID',
+ 'Created'
+ ]);
+
+
+ foreach ($orders as $order) {
+ $tbestellung = Shop::DB()->executeQueryPrepared('SELECT cBestellNr, cStatus FROM tbestellung WHERE kBestellung = :kBestellung', [':kBestellung' => $order->kBestellung], 1);
+
+ $tmp = [
+ 'kBestellung' => $order->kBestellung,
+ 'cOrderId' => $order->kID,
+ 'cStatus' => $order->cStatus,
+ 'cBestellNr' => $tbestellung ? $tbestellung->cBestellNr : $order->cOrderNumber,
+ 'nStatus' => $tbestellung ? $tbestellung->cStatus : 0,
+ 'cMode' => $order->cMode,
+ 'cOriginalOrderNumber' => '',
+ 'cCurrency' => $order->cCurrency,
+ 'fAmount' => $order->fAmount,
+ 'cMethod' => $order->cMethod,
+ 'cPaymentId' => '',
+ 'dCreated' => $order->dCreatedAt,
+ ];
+
+ try {
+ $oOrder = $api->orders->get($order->kID, ['embed' => 'payments']);
+ $tmp['cStatus'] = $oOrder->status;
+ $tmp['cOriginalOrderNumber'] = isset($oOrder->metadata->originalOrderNumber) ? $oOrder->metadata->originalOrderNumber : '';
+ foreach ($oOrder->payments() as $payment) {
+ if ($payment->status === \Mollie\Api\Types\PaymentStatus::STATUS_PAID) {
+ $tmp['cPaymentId'] = $payment->id;
+ }
+ }
+ } catch (Exception $e) {
+ }
+ fputcsv($out, $tmp);
+
+ $export[] = $tmp;
+ }
+
+ fclose($out);
+ exit();
+
+ } catch (Exception $e) {
+ Helper::addAlert('Fehler:' . $e->getMessage(), 'danger', 'orders');
+ }
+ break;
+
+ case 'refund':
+ if (!array_key_exists('id', $_REQUEST)) {
+ Helper::addAlert('Keine ID angegeben!', 'danger', 'orders');
+ break;
+ }
+ $payment = Payment::getPaymentMollie($_REQUEST['id']);
+ if (!$payment) {
+ Helper::addAlert('Order nicht gefunden!', 'danger', 'orders');
+ break;
+ }
+
+ $order = JTLMollie::API()->orders->get($_REQUEST['id']);
+ if ($order->status === OrderStatus::STATUS_CANCELED) {
+ Helper::addAlert('Bestellung bereits storniert', 'danger', 'orders');
+ break;
+ }
+ $refund = JTLMollie::API()->orderRefunds->createFor($order, ['lines' => []]);
+ Mollie::JTLMollie()->doLog("Order refunded: " . print_r($refund, 1) . " ", '$' . $payment->kID . '#' . $payment->kBestellung . '§' . $payment->cOrderNumber, LOGLEVEL_NOTICE);
+
+ goto order;
+
+ case 'cancel':
+ if (!array_key_exists('id', $_REQUEST)) {
+ Helper::addAlert('Keine ID angeben!', 'danger', 'orders');
+ break;
+ }
+ $payment = Payment::getPaymentMollie($_REQUEST['id']);
+ if (!$payment) {
+ Helper::addAlert('Order nicht gefunden!', 'danger', 'orders');
+ break;
+ }
+ $order = JTLMollie::API()->orders->get($_REQUEST['id']);
+ if ($order->status == OrderStatus::STATUS_CANCELED) {
+ Helper::addAlert('Bestellung bereits storniert', 'danger', 'orders');
+ break;
+ }
+ $cancel = JTLMollie::API()->orders->cancel($order->id);
+ Mollie::JTLMollie()->doLog("Order canceled: " . print_r($cancel, 1) . " ", '$' . $payment->kID . '#' . $payment->kBestellung . '§' . $payment->cOrderNumber, LOGLEVEL_NOTICE);
+ goto order;
+
+ case 'capture':
+ if (!array_key_exists('id', $_REQUEST)) {
+ Helper::addAlert('Keine ID angeben!', 'danger', 'orders');
+ break;
+ }
+ $payment = Payment::getPaymentMollie($_REQUEST['id']);
+ if (!$payment) {
+ Helper::addAlert('Order nicht gefunden!', 'danger', 'orders');
+ break;
+ }
+ $order = JTLMollie::API()->orders->get($_REQUEST['id']);
+ if ($order->status !== OrderStatus::STATUS_AUTHORIZED && $order->status !== OrderStatus::STATUS_SHIPPING) {
+ Helper::addAlert('Nur autorisierte Zahlungen können erfasst werden!', 'danger', 'orders');
+ break;
+ }
+
+ $oBestellung = new Bestellung($payment->kBestellung, true);
+ if (!$oBestellung->kBestellung) {
+ Helper::addAlert('Bestellung konnte nicht geladen werden!', 'danger', 'orders');
+ break;
+ }
+
+ $logData = '#' . $payment->kBestellung . '$' . $payment->kID . "§" . $oBestellung->cBestellNr;
+
+ $options = ['lines' => []];
+ if ($oBestellung->cTracking) {
+ $tracking = new stdClass();
+ $tracking->carrier = utf8_encode($oBestellung->cVersandartName);
+ $tracking->url = utf8_encode($oBestellung->cTrackingURL);
+ $tracking->code = utf8_encode($oBestellung->cTracking);
+ $options['tracking'] = $tracking;
+ }
+
+ // CAPTURE ALL
+ $shipment = JTLMollie::API()->shipments->createFor($order, $options);
+ Helper::addAlert('Zahlung wurde erfolgreich erfasst!', 'success', 'orders');
+ Mollie::JTLMollie()->doLog('Shipment created' . print_r(['options' => $options, 'shipment' => $shipment], 1) . ' ', $logData);
+ goto order;
+
+ case 'order':
+ order:
+ if (!array_key_exists('id', $_REQUEST)) {
+ Helper::addAlert('Keine ID angeben!', 'danger', 'orders');
+ break;
+ }
+
+ $order = JTLMollie::API()->orders->get($_REQUEST['id'], ['embed' => 'payments,refunds']);
+ $payment = Payment::getPaymentMollie($_REQUEST['id']);
+ if ($payment) {
+ $oBestellung = new Bestellung($payment->kBestellung, false);
+ //\ws_mollie\Model\Payment::updateFromPayment($order, $oBestellung->kBestellung);
+ if ($oBestellung->kBestellung && $oBestellung->cBestellNr !== $payment->cOrderNumber) {
+ Shop::DB()->executeQueryPrepared("UPDATE xplugin_ws_mollie_payments SET cOrderNumber = :cBestellNr WHERE kID = :kID", [
+ ':cBestellNr' => $oBestellung->cBestellNr,
+ ':kID' => $payment->kID,
+ ], 3);
+ }
+ }
+ $logs = Shop::DB()->executeQueryPrepared("SELECT * FROM tzahlungslog WHERE cLogData LIKE :kBestellung OR cLogData LIKE :cBestellNr OR cLogData LIKE :MollieID ORDER BY dDatum DESC, cLog DESC", [
+ ':kBestellung' => '%#' . ($payment->kBestellung ?: '##') . '%',
+ ':cBestellNr' => '%§' . ($payment->cOrderNumber ?: '§§') . '%',
+ ':MollieID' => '%$' . ($payment->kID ?: '$$') . '%',
+ ], 2);
+
+ Shop::Smarty()->assign('payment', $payment)
+ ->assign('oBestellung', $oBestellung)
+ ->assign('order', $order)
+ ->assign('logs', $logs);
+ Shop::Smarty()->display($oPlugin->cAdminmenuPfad . '/tpl/order.tpl');
+ return;
+ }
+ }
+
+
+ Mollie::fixZahlungsarten();
+
+
+ $payments = Shop::DB()->executeQueryPrepared("SELECT * FROM xplugin_ws_mollie_payments WHERE kBestellung IS NOT NULL AND cStatus != 'created' ORDER BY dCreatedAt DESC LIMIT 1000;", [], 2);
+ foreach ($payments as $i => $payment) {
+ $payments[$i]->oBestellung = new Bestellung($payment->kBestellung, false);
+ }
+
+ Shop::Smarty()->assign('payments', $payments)
+ ->assign('admRoot', str_replace('http:', '', $oPlugin->cAdminmenuPfadURL))
+ ->assign('hasAPIKey', trim(Helper::getSetting("api_key")) !== '');
+
+ Shop::Smarty()->display($oPlugin->cAdminmenuPfad . '/tpl/orders.tpl');
+} catch (Exception $e) {
+ echo "" .
+ "{$e->getMessage()}
" .
+ "
{$e->getFile()}:{$e->getLine()}{$e->getTraceAsString()} " .
+ "
";
+ Helper::logExc($e);
+}
diff --git a/version/109/adminmenu/paymentmethods.php b/version/109/adminmenu/paymentmethods.php
new file mode 100644
index 0000000..1782978
--- /dev/null
+++ b/version/109/adminmenu/paymentmethods.php
@@ -0,0 +1,60 @@
+setApiKey(Helper::getSetting("api_key"));
+
+ $profile = $mollie->profiles->get('me');
+ /* $methods = $mollie->methods->all([
+ //'locale' => 'de_DE',
+ 'include' => 'pricing',
+ ]);*/
+
+ $za = filter_input(INPUT_GET, 'za', FILTER_VALIDATE_BOOLEAN);
+ $active = filter_input(INPUT_GET, 'active', FILTER_VALIDATE_BOOLEAN);
+ $amount = filter_input(INPUT_GET, 'amount', FILTER_VALIDATE_FLOAT) ?: null;
+ $locale = filter_input(INPUT_GET, 'locale', FILTER_VALIDATE_REGEXP, ['options' => ['regexp' => '/^[a-zA-Z]{2}_[a-zA-Z]{2}$/']]) ?: null;
+ $currency = filter_input(INPUT_GET, 'currency', FILTER_VALIDATE_REGEXP, ['options' => ['regexp' => '/^[a-zA-Z]{3}$/']]) ?: 'EUR';
+
+ if ($za) {
+ Shop::Smarty()->assign('defaultTabbertab', Helper::getAdminmenu("Zahlungsarten"));
+ }
+
+ $params = ['include' => 'pricing,issuers'];
+ if ($amount && $currency && $locale) {
+ $params['amount'] = ['value' => number_format($amount, 2, '.', ''), 'currency' => $currency];
+ $params['locale'] = $locale;
+ if ($active) {
+ $params['includeWallets'] = 'applepay';
+ $params['resource'] = 'orders';
+ }
+ }
+
+ if ($active) {
+ $allMethods = $mollie->methods->allActive($params);
+ } else {
+ $allMethods = $mollie->methods->allAvailable($params);
+ }
+
+ Shop::Smarty()->assign('profile', $profile)
+ ->assign('currencies', Mollie::getCurrencies())
+ ->assign('locales', Mollie::getLocales())
+ ->assign('allMethods', $allMethods);
+ Shop::Smarty()->display($oPlugin->cAdminmenuPfad . '/tpl/paymentmethods.tpl');
+} catch (Exception $e) {
+ echo "{$e->getMessage()}
";
+ Helper::logExc($e);
+}
diff --git a/version/109/adminmenu/tpl/info.tpl b/version/109/adminmenu/tpl/info.tpl
new file mode 100644
index 0000000..2952fc6
--- /dev/null
+++ b/version/109/adminmenu/tpl/info.tpl
@@ -0,0 +1,114 @@
+
+
+
+
+
+ {if isset($update)}
+
+
+
+
Update auf Version {$update->version} verfügbar!
+
+
+
+
Version:
+
{$update->version}
+
+
+
Erschienen:
+
{$update->create_date}
+
+
+
+
+
+
+ {else}
+
+ {/if}
+
+
+
+
+
+{if file_exists("{$smarty['current_dir']}/_addon.tpl")}
+ {include file="{$smarty['current_dir']}/_addon.tpl"}
+{/if}
+{if isset($oPlugin)}
+
+{/if}
diff --git a/version/109/adminmenu/tpl/mollie-account-erstellen.png b/version/109/adminmenu/tpl/mollie-account-erstellen.png
new file mode 100644
index 0000000..fc18192
Binary files /dev/null and b/version/109/adminmenu/tpl/mollie-account-erstellen.png differ
diff --git a/version/109/adminmenu/tpl/order.tpl b/version/109/adminmenu/tpl/order.tpl
new file mode 100644
index 0000000..4cc896f
--- /dev/null
+++ b/version/109/adminmenu/tpl/order.tpl
@@ -0,0 +1,281 @@
+
+
+ «
+ Bestellung: {$oBestellung->cBestellNr} -
+ {if $oBestellung->cStatus|intval == 1}
+ OFFEN
+ {elseif $oBestellung->cStatus|intval == 2}
+ IN BEARBEITUNG
+ {elseif $oBestellung->cStatus|intval == 3}
+ BEZAHLT
+ {elseif $oBestellung->cStatus|intval == 4}
+ VERSANDT
+ {elseif $oBestellung->cStatus|intval == 5}
+ TEILVERSANDT
+ {elseif $oBestellung->cStatus|intval == -1}
+ STORNO
+ {else}
+ n/a
+ {/if}
+
+
+{ws_mollie\Helper::showAlerts('orders')}
+
+
+
+ Mollie ID:
+ {$payment->kID}
+ Mode:
+ {$order->mode}
+ Status:
+
+ {$order->status}
+ {if $order->amountRefunded && $order->amountRefunded->value == $order->amount->value}
+ (total refund)
+ {elseif $order->amountRefunded && $order->amountRefunded->value > 0}
+ (partly refund)
+ {/if}
+
+
+
+
+ Betrag:
+ {$order->amount->value|number_format:2:',':''} {$order->amount->currency}
+ Captured:
+ {if $order->amountCaptured}{$order->amountCaptured->value|number_format:2:',':''} {$order->amountCaptured->currency}{else}-{/if}
+ Refunded:
+ {if $order->amountRefunded}{$order->amountRefunded->value|number_format:2:',':''} {$order->amountRefunded->currency} {else}-{/if}
+
+
+
+
+ Method:
+ {$order->method}
+ Locale:
+ {$order->locale}
+ Erstellt:
+ {"d. M Y H:i:s"|date:($order->createdAt|strtotime)}
+
+
+
+ Kunde:
+
+ {if $order->billingAddress->organizationName}{$order->billingAddress->organizationName}{else}{$order->billingAddress->title} {$order->billingAddress->givenName} {$order->billingAddress->familyName}{/if}
+
+ Zahlungslink:
+
+ {$payment->cCheckoutURL}
+
+
+
+
+{if $order->payments()->count > 0}
+ Zahlungen
+
+
+
+ ID
+ Status
+ Methode
+ Amount
+ Settlement
+ Refunded
+ Remaining
+ Details
+
+
+ {foreach from=$order->payments() item=payment}
+
+ {$payment->id}
+ {$payment->status}
+ {$payment->method}
+ {$payment->amount->value} {$payment->amount->currency}
+
+ {if $payment->settlementAmount}
+ {$payment->settlementAmount->value} {$payment->settlementAmount->currency}
+ {else}-{/if}
+
+
+ {if $payment->amountRefunded}
+ {$payment->amountRefunded->value} {$payment->amountRefunded->currency}
+ {else}-{/if}
+
+
+ {if $payment->amountRemaining}
+ {$payment->amountRemaining->value} {$payment->amountRemaining->currency}
+ {else}-{/if}
+
+
+
+ {foreach from=$payment->details item=value key=key}
+ {$key}: {if $value|is_scalar}{$value}{else}{$value|json_encode}{/if}
+ {/foreach}
+
+
+
+ {/foreach}
+
+{/if}
+
+
+Positionen:
+
+
+ {if ($order->status === 'authorized' || $order->status === 'shipping') && $oBestellung->cStatus|intval >= 3}
+
+ Zahlung erfassen1
+
+ {/if}
+ {if !$order->amountRefunded || ($order->amount->value > $order->amountRefunded->value && $order->amountCaptured->value > 0)}
+
Rückerstatten2
+
+ {/if}
+ {if $order->isCancelable}
+
Stornieren3
+
+ {/if}
+
+
+
+
+
+ Status
+ SKU
+ Name
+ Typ
+ Anzahl
+ MwSt
+ Steuer
+ Netto
+ Brutto
+
+
+
+
+ {assign var="vat" value=0}
+ {assign var="netto" value=0}
+ {assign var="brutto" value=0}
+ {foreach from=$order->lines item=line}
+
+ {assign var="vat" value=$vat+$line->vatAmount->value}
+ {assign var="netto" value=$netto+$line->totalAmount->value-$line->vatAmount->value}
+ {assign var="brutto" value=$brutto+$line->totalAmount->value}
+
+
+ {if $line->status == 'created'}
+ erstellt
+ {elseif $line->status == 'pending'}
+ austehend
+ {elseif $line->status == 'paid'}
+ bezahlt
+ {elseif $line->status == 'authorized'}
+ autorisiert
+ {elseif $line->status == 'shipping'}
+ versendet
+ {elseif $line->status == 'completed'}
+ abgeschlossen
+ {elseif $line->status == 'expired'}
+ abgelaufen
+ {elseif $line->status == 'canceled'}
+ storniert
+ {else}
+ Unbekannt: {$line->status}
+ {/if}
+
+ {$line->sku}
+ {$line->name|utf8_decode}
+ {$line->type}
+ {$line->quantity}
+ {$line->vatRate|floatval}%
+ {$line->vatAmount->value|number_format:2:',':''} {$line->vatAmount->currency}
+ {($line->totalAmount->value - $line->vatAmount->value)|number_format:2:',':''} {$line->vatAmount->currency}
+ {$line->totalAmount->value|number_format:2:',':''} {$line->totalAmount->currency}
+
+ {*if $line->quantity > $line->quantityShipped}
+
+
+
+ {/if}
+ {if $line->quantity > $line->quantityRefunded}
+
+
+
+ {/if}
+ {if $line->isCancelable}
+
+
+
+ {/if*}
+ {*$line|var_dump*}
+
+
+ {/foreach}
+
+
+
+
+ {$vat|number_format:2:',':''} {$order->amount->currency}
+ {$netto|number_format:2:',':''} {$order->amount->currency}
+ {$brutto|number_format:2:',':''} {$order->amount->currency}
+
+
+
+
+
+
+ 1 = Bestellung wird bei Mollie als versandt markiert. WAWI wird nicht informiert.
+ 2 = Bezahlter Betrag wird dem Kunden rckerstattet. WAWI wird nicht informiert.
+ 3 = Bestellung wird bei Mollie storniert. WAWI wird nicht informiert.
+
+
+Log
+
+
+ {foreach from=$logs item=log}
+
+
+ {if $log->nLevel == 1}
+ Fehler
+ {elseif $log->nLevel == 2}
+ Hinweis
+ {elseif $log->nLevel == 3}
+ Debug
+ {else}
+ unknown {$log->nLevel}
+ {/if}
+
+ {$log->cModulId}
+
+
+ {$log->cLog}
+
+
+ {$log->dDatum}
+
+ {/foreach}
+
+
+
diff --git a/version/109/adminmenu/tpl/orders.tpl b/version/109/adminmenu/tpl/orders.tpl
new file mode 100644
index 0000000..669015a
--- /dev/null
+++ b/version/109/adminmenu/tpl/orders.tpl
@@ -0,0 +1,132 @@
+{ws_mollie\Helper::showAlerts('orders')}
+
+{if $hasAPIKey == false}
+
+
+
+{else}
+
+
+
+ BestellNr.
+ ID
+ Mollie Status
+ JTL Status
+ Betrag
+ Währung
+ Locale
+ Methode
+ Erstellt
+
+
+
+ {foreach from=$payments item=payment}
+
+
+ {$payment->cOrderNumber}
+ {if $payment->cMode == 'test'}
+ TEST
+ {/if}
+ {if $payment->bLockTimeout}
+ LOCK TIMEOUT
+ {/if}
+
+
+ {$payment->kID}
+
+
+ {if $payment->cStatus == 'created'}
+ erstellt
+ {elseif $payment->cStatus == 'pending'}
+ austehend
+ {elseif $payment->cStatus == 'paid'}
+ bezahlt
+ {elseif $payment->cStatus == 'authorized'}
+ autorisiert
+ {elseif $payment->cStatus == 'shipping'}
+ versendet
+ {elseif $payment->cStatus == 'completed'}
+ abgeschlossen
+ {elseif $payment->cStatus == 'expired'}
+ abgelaufen
+ {elseif $payment->cStatus == 'canceled'}
+ storniert
+ {else}
+ Unbekannt: {$payment->cStatus}
+ {/if}
+ {if $payment->fAmountRefunded && $payment->fAmountRefunded == $payment->fAmount}
+ (total refund)
+ {elseif $payment->fAmountRefunded && $payment->fAmountRefunded > 0}
+ (partly refund)
+ {/if}
+
+
+
+ {if $payment->oBestellung->cStatus|intval == 1}
+ OFFEN
+ {elseif $payment->oBestellung->cStatus|intval == 2}
+ IN BEARBEITUNG
+ {elseif $payment->oBestellung->cStatus|intval == 3}
+ BEZAHLT
+ {elseif $payment->oBestellung->cStatus|intval == 4}
+ VERSANDT
+ {elseif $payment->oBestellung->cStatus|intval == 5}
+ TEILVERSANDT
+ {elseif $payment->oBestellung->cStatus|intval == -1}
+ STORNO
+ {else}
+ n/a
+ {/if}
+
+ {$payment->fAmount|number_format:2:',':''}
+ {$payment->cCurrency}
+ {$payment->cLocale}
+ {$payment->cMethod}
+ {"d. M Y H:i"|date:($payment->dCreatedAt|strtotime)}
+
+ {/foreach}
+
+
+ {if $payments|count > 900}
+ Hier werden nur die letzten 1000 Ergebnisse angezeigt.
+ {/if}
+
+
+
+
+{/if}
+
diff --git a/version/109/adminmenu/tpl/paymentmethods.tpl b/version/109/adminmenu/tpl/paymentmethods.tpl
new file mode 100644
index 0000000..4c37e02
--- /dev/null
+++ b/version/109/adminmenu/tpl/paymentmethods.tpl
@@ -0,0 +1,97 @@
+Account Status
+
+
+ Mode:
+ {$profile->mode}
+ Status:
+ {$profile->status}
+ {if $profile->review}
+ Review:
+ {$profile->review->status}
+ {/if}
+
+
+
+
+
+
+
+
+{if $allMethods && $allMethods|count}
+
+
+
+ Bild
+ ID
+ Name
+ Preise
+ Infos
+
+
+
+ {foreach from=$allMethods item=method}
+
+
+ {$method->id}
+ {$method->description|utf8_decode}
+
+
+ {foreach from=$method->pricing item=price}
+ {$price->description|utf8_decode}: {$price->fixed->value} {$price->fixed->currency}
+ {if $price->variable > 0.0}
+ + {$price->variable}%
+ {/if}
+
+ {/foreach}
+
+
+
+ Min: {if $method->minimumAmount}{$method->minimumAmount->value} {$method->minimumAmount->currency}{else}n/a{/if}
+
+ Max: {if $method->maximumAmount}{$method->maximumAmount->value} {$method->maximumAmount->currency}{else}n/a{/if}
+
+
+ {/foreach}
+
+
+{else}
+ Es konnten keine Methoden abgerufen werden.
+{/if}
\ No newline at end of file
diff --git a/version/109/class/ExclusiveLock.php b/version/109/class/ExclusiveLock.php
new file mode 100644
index 0000000..834e00f
--- /dev/null
+++ b/version/109/class/ExclusiveLock.php
@@ -0,0 +1,76 @@
+key = $key;
+ $this->path = rtrim(realpath($path), '/'). '/' ;
+ if(!is_dir($path) || !is_writable($path)){
+ throw new Exception("Lock Path '{$path}' doesn't exist, or is not writable!");
+ }
+ //create a new resource or get exisitng with same key
+ $this->file = fopen($this->path . "$key.lockfile", 'w+');
+ }
+
+
+ public function __destruct()
+ {
+ if( $this->own === true )
+ $this->unlock( );
+ }
+
+
+ public function lock()
+ {
+ if( !flock($this->file, LOCK_EX | LOCK_NB))
+ { //failed
+ $key = $this->key;
+ error_log("ExclusiveLock::acquire_lock FAILED to acquire lock [$key]");
+ return false;
+ }
+ //ftruncate($this->file, 0); // truncate file
+ //write something to just help debugging
+ //fwrite( $this->file, "Locked\n");
+ fwrite( $this->file, "Locked - " . microtime(true) . "\n");
+ fflush( $this->file );
+
+ $this->own = true;
+ return true; // success
+ }
+
+
+ public function unlock()
+ {
+ $key = $this->key;
+ if( $this->own === true )
+ {
+ if( !flock($this->file, LOCK_UN) )
+ { //failed
+ error_log("ExclusiveLock::lock FAILED to release lock [$key]");
+ return false;
+ }
+ //ftruncate($this->file, 0); // truncate file
+ //write something to just help debugging
+ fwrite( $this->file, "Unlocked - " . microtime(true) . "\n");
+ fflush( $this->file );
+ $this->own = false;
+ }
+ else
+ {
+ error_log("ExclusiveLock::unlock called on [$key] but its not acquired by caller");
+ }
+ return true; // success
+ }
+}
diff --git a/version/109/class/Helper.php b/version/109/class/Helper.php
new file mode 100644
index 0000000..5f2a8be
--- /dev/null
+++ b/version/109/class/Helper.php
@@ -0,0 +1,352 @@
+short_url != '' ? $release->short_url : $release->full_url;
+ $filename = basename($release->full_url);
+ $tmpDir = PFAD_ROOT . PFAD_COMPILEDIR;
+ $pluginsDir = PFAD_ROOT . PFAD_PLUGIN;
+
+ // 1. PRE-CHECKS
+ if (file_exists($pluginsDir . self::oPlugin()->cVerzeichnis . '/.git') && is_dir($pluginsDir . self::oPlugin()->cVerzeichnis . '/.git')) {
+ throw new Exception('Pluginordner enthält ein GIT Repository, kein Update möglich!');
+ }
+
+ if (!function_exists("curl_exec")) {
+ throw new Exception("cURL ist nicht verfügbar!!");
+ }
+ if (!is_writable($tmpDir)) {
+ throw new Exception("Temporäres Verzeichnis_'{$tmpDir}' ist nicht beschreibbar!");
+ }
+ if (!is_writable($pluginsDir . self::oPlugin()->cVerzeichnis)) {
+ throw new Exception("Plugin Verzeichnis_'" . $pluginsDir . self::oPlugin()->cVerzeichnis . "' ist nicht beschreibbar!");
+ }
+ if (file_exists($tmpDir . $filename)) {
+ if (!unlink($tmpDir . $filename)) {
+ throw new Exception("Temporäre Datei '" . $tmpDir . $filename . "' konnte nicht gelöscht werden!");
+ }
+ }
+
+ // 2. DOWNLOAD
+ $fp = fopen($tmpDir . $filename, 'w+');
+ $ch = curl_init($url);
+ curl_setopt($ch, CURLOPT_TIMEOUT, 50);
+ curl_setopt($ch, CURLOPT_FILE, $fp);
+ curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
+ curl_exec($ch);
+ $info = curl_getinfo($ch);
+ curl_close($ch);
+ fclose($fp);
+ if ($info['http_code'] !== 200) {
+ throw new Exception("Unerwarteter Status Code '" . $info['http_code'] . "'!");
+ }
+ if ($info['download_content_length'] <= 0) {
+ throw new Exception("Unerwartete Downloadgröße '" . $info['download_content_length'] . "'!");
+ }
+
+ // 3. UNZIP
+ require_once PFAD_ROOT . PFAD_PCLZIP . 'pclzip.lib.php';
+ $zip = new PclZip($tmpDir . $filename);
+ $content = $zip->listContent();
+
+ if (!is_array($content) || !isset($content[0]['filename']) || strpos($content[0]['filename'], '.') !== false) {
+ throw new Exception("Das Zip-Archiv ist leider ungültig!");
+ } else {
+ $unzipPath = PFAD_ROOT . PFAD_PLUGIN;
+ $res = $zip->extract(PCLZIP_OPT_PATH, $unzipPath, PCLZIP_OPT_REPLACE_NEWER);
+ if ($res !== 0) {
+ header('Location: ' . Shop::getURL() . DIRECTORY_SEPARATOR . PFAD_ADMIN . 'pluginverwaltung.php', true);
+ } else {
+ throw new Exception('Entpacken fehlgeschlagen: ' . $zip->errorCode());
+ }
+ }
+ }
+
+ /**
+ * @param bool $force
+ * @return mixed
+ * @throws Exception
+ */
+ public static function getLatestRelease($force = false)
+ {
+ $lastCheck = (int)self::getSetting(__NAMESPACE__ . '_upd');
+ $lastRelease = file_exists(PFAD_ROOT . PFAD_COMPILEDIR . __NAMESPACE__ . '_upd') ? file_get_contents(PFAD_ROOT . PFAD_COMPILEDIR . __NAMESPACE__ . '_upd') : false;
+ if ($force || !$lastCheck || !$lastRelease || ($lastCheck + 12 * 60 * 60) < time()) {
+ $curl = curl_init('https://api.dash.bar/release/' . __NAMESPACE__);
+ @curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 5);
+ @curl_setopt($curl, CURLOPT_TIMEOUT, 5);
+ @curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
+ @curl_setopt($curl, CURLOPT_HEADER, 0);
+ @curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
+ @curl_setopt($curl, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
+
+ $data = curl_exec($curl);
+ $statusCode = (int)curl_getinfo($curl, CURLINFO_HTTP_CODE);
+ @curl_close($curl);
+ if ($statusCode !== 200) {
+ throw new Exception(__NAMESPACE__ . ': Could not fetch release info: ' . $statusCode);
+ }
+ $json = json_decode($data);
+ if (json_last_error() || $json->status != 'ok') {
+ throw new Exception(__NAMESPACE__ . ': Could not decode release info: ' . $data);
+ }
+ self::setSetting(__NAMESPACE__ . '_upd', time());
+ file_put_contents(PFAD_ROOT . PFAD_COMPILEDIR . __NAMESPACE__ . '_upd', json_encode($json->data));
+ return $json->data;
+ } else {
+ return json_decode($lastRelease);
+ }
+ }
+
+ /**
+ * Register PSR-4 autoloader
+ * Licence-Check
+ * @return bool
+ */
+ public static function init()
+ {
+ ini_set('xdebug.default_enable', defined('WS_XDEBUG_ENABLED'));
+ return self::autoload();
+ }
+
+ /**
+ * @var stdClass[]
+ */
+ public static $alerts = [];
+
+ /**
+ * Usage:
+ *
+ * Helper::addAlert('Success Message', 'success', 'namespace');
+ *
+ * @param $content
+ * @param $type
+ * @param $namespace
+ */
+ public static function addAlert($content, $type, $namespace)
+ {
+ if (!array_key_exists($namespace, self::$alerts)) {
+ self::$alerts[$namespace] = new stdClass();
+ }
+
+ self::$alerts[$namespace]->{$type . '_' . microtime(true)} = $content;
+ }
+
+ /**
+ * Usage in Smarty:
+ *
+ * {ws_mollie\Helper::showAlerts('namespace')}
+ *
+ * @param $namespace
+ * @return string
+ * @throws \SmartyException
+ */
+ public static function showAlerts($namespace)
+ {
+ if (array_key_exists($namespace, self::$alerts) && file_exists(self::oPlugin()->cAdminmenuPfad . '../tpl/_alerts.tpl')) {
+ Shop::Smarty()->assign('alerts', self::$alerts[$namespace]);
+ return Shop::Smarty()->fetch(self::oPlugin()->cAdminmenuPfad . '../tpl/_alerts.tpl');
+ }
+ return '';
+ }
+
+ /**
+ * Sets a Plugin Setting and saves it to the DB
+ *
+ * @param $name
+ * @param $value
+ * @return int
+ */
+ public static function setSetting($name, $value)
+ {
+ $setting = new stdClass;
+ $setting->kPlugin = self::oPlugin()->kPlugin;
+ $setting->cName = $name;
+ $setting->cWert = $value;
+
+ if (array_key_exists($name, self::oPlugin()->oPluginEinstellungAssoc_arr)) {
+ $return = Shop::DB()->updateRow('tplugineinstellungen', ['kPlugin', 'cName'], [$setting->kPlugin, $setting->cName], $setting);
+ } else {
+ $return = Shop::DB()->insertRow('tplugineinstellungen', $setting);
+ }
+ self::oPlugin()->oPluginEinstellungAssoc_arr[$name] = $value;
+ self::oPlugin(true); // invalidate cache
+ return $return;
+ }
+
+ /**
+ * Get Plugin Object
+ *
+ * @param bool $force disable Cache
+ * @return Plugin|null
+ */
+ public static function oPlugin($force = false)
+ {
+ if ($force === true) {
+ self::$oPlugin = new Plugin(self::oPlugin(false)->kPlugin, true);
+ } else if (null === self::$oPlugin) {
+ self::$oPlugin = Plugin::getPluginById(__NAMESPACE__);
+ }
+ return self::$oPlugin;
+ }
+
+ /**
+ * get a Plugin setting
+ *
+ * @param $name
+ * @return null|mixed
+ */
+ public static function getSetting($name)
+ {
+ if (array_key_exists($name, self::oPlugin()->oPluginEinstellungAssoc_arr ?: [])) {
+ return self::oPlugin()->oPluginEinstellungAssoc_arr[$name];
+ }
+ return null;
+ }
+
+ /**
+ * Get Domain frpm URL_SHOP without www.
+ *
+ * @param string $url
+ * @return string
+ */
+ public static function getDomain($url = URL_SHOP)
+ {
+ $matches = array();
+ @preg_match("/^((http(s)?):\/\/)?(www\.)?([a-zA-Z0-9-\.]+)(\/.*)?$/i", $url, $matches);
+ return strtolower(isset($matches[5]) ? $matches[5] : $url);
+ }
+
+ /**
+ * @param bool $e
+ * @return mixed
+ */
+ public static function getMasterMail($e = false)
+ {
+ $settings = Shop::getSettings(array(CONF_EMAILS));
+ $mail = trim($settings['emails']['email_master_absender']);
+ if ($e === true && $mail != '') {
+ $mail = base64_encode($mail);
+ $eMail = "";
+ foreach (str_split($mail, 1) as $c) {
+ $eMail .= chr(ord($c) ^ 0x00100110);
+ }
+ return base64_encode($eMail);
+ }
+ return $mail;
+ }
+
+ /**
+ * @param Exception $exc
+ * @param bool $trace
+ * @return void
+ */
+ public static function logExc(Exception $exc, $trace = true)
+ {
+ Jtllog::writeLog(__NAMESPACE__ . ': ' . $exc->getMessage() . ($trace ? ' - ' . $exc->getTraceAsString() : ''));
+ }
+
+ /**
+ * Checks if admin session is loaded
+ *
+ * @return bool
+ */
+ public static function isAdminBackend()
+ {
+ return session_name() === 'eSIdAdm';
+ }
+
+ /**
+ * Returns kAdminmenu ID for given Title, used for Tabswitching
+ *
+ * @param $name string CustomLink Title
+ * @return int
+ */
+ public static function getAdminmenu($name)
+ {
+ $kPluginAdminMenu = 0;
+ foreach (self::oPlugin()->oPluginAdminMenu_arr as $adminmenu) {
+ if (strtolower($adminmenu->cName) == strtolower($name)) {
+ $kPluginAdminMenu = $adminmenu->kPluginAdminMenu;
+ break;
+ }
+ }
+ return $kPluginAdminMenu;
+ }
+
+ }
+ }
+
+}
diff --git a/version/109/class/Model/AbstractModel.php b/version/109/class/Model/AbstractModel.php
new file mode 100644
index 0000000..5638700
--- /dev/null
+++ b/version/109/class/Model/AbstractModel.php
@@ -0,0 +1,7 @@
+id;
+ $data = [
+ ':kID' => $oMolliePayment->id,
+ ':kBestellung' => (int)$kBestellung ?: null,
+ ':kBestellung1' => (int)$kBestellung ?: null,
+ ':cMode' => $oMolliePayment->mode,
+ ':cStatus' => $oMolliePayment->status,
+ ':cStatus1' => $oMolliePayment->status,
+ ':cHash' => $hash,
+ ':fAmount' => $oMolliePayment->amount->value,
+ ':cOrderNumber' => $oMolliePayment->orderNumber,
+ ':cOrderNumber1' => $oMolliePayment->orderNumber,
+ ':cCurrency' => $oMolliePayment->amount->currency,
+ ':cMethod' => $oMolliePayment->method,
+ ':cMethod1' => $oMolliePayment->method,
+ ':cLocale' => $oMolliePayment->locale,
+ ':bCancelable' => $oMolliePayment->isCancelable,
+ ':bCancelable1' => $oMolliePayment->isCancelable,
+ ':cWebhookURL' => $oMolliePayment->webhookUrl,
+ ':cRedirectURL' => $oMolliePayment->redirectUrl,
+ ':cCheckoutURL' => $oMolliePayment->getCheckoutUrl(),
+ ':cCheckoutURL1' => $oMolliePayment->getCheckoutUrl(),
+ ':fAmountCaptured' => $oMolliePayment->amountCaptured ? $oMolliePayment->amountCaptured->value : null,
+ ':fAmountCaptured1' => $oMolliePayment->amountCaptured ? $oMolliePayment->amountCaptured->value : null,
+ ':fAmountRefunded' => $oMolliePayment->amountRefunded ? $oMolliePayment->amountRefunded->value : null,
+ ':fAmountRefunded1' => $oMolliePayment->amountRefunded ? $oMolliePayment->amountRefunded->value : null,
+ ':dCreatedAt' => $oMolliePayment->createdAt ? date('Y-m-d H:i:s', strtotime($oMolliePayment->createdAt)) : null,
+ ];
+ Mollie::JTLMollie()->doLog('Payment::updateFromPayment' . print_r([$kBestellung, $oMolliePayment], 1) . ' ', $logData);
+ return Shop::DB()->executeQueryPrepared(
+ 'INSERT INTO ' . self::TABLE . ' (kID, kBestellung, cMode, cStatus, cHash, fAmount, cOrderNumber, cCurrency, cMethod, cLocale, bCancelable, cWebhookURL, cRedirectURL, cCheckoutURL, fAmountCaptured, fAmountRefunded, dCreatedAt) '
+ . 'VALUES (:kID, :kBestellung, :cMode, :cStatus, :cHash, :fAmount, :cOrderNumber, :cCurrency, :cMethod, :cLocale, :bCancelable, :cWebhookURL, :cRedirectURL, IF(:cCheckoutURL IS NULL, cCheckoutURL, :cCheckoutURL1), :fAmountCaptured, :fAmountRefunded, :dCreatedAt) '
+ . 'ON DUPLICATE KEY UPDATE kBestellung = :kBestellung1, cOrderNumber = :cOrderNumber1, cStatus = :cStatus1, cMethod = :cMethod1, bCancelable = :bCancelable1, fAmountCaptured = :fAmountCaptured1, fAmountRefunded = :fAmountRefunded1',
+ $data,
+ 3
+ );
+ }
+
+ public static function getPayment($kBestellung)
+ {
+ $payment = Shop::DB()->executeQueryPrepared('SELECT * FROM ' . self::TABLE . ' WHERE kBestellung = :kBestellung', [':kBestellung' => $kBestellung], 1);
+ if ($payment && $payment->kBestellung) {
+ $payment->oBestellung = new Bestellung($payment->kBestellung, false);
+ }
+ return $payment;
+ }
+
+ public static function getPaymentMollie($kID)
+ {
+ $payment = Shop::DB()->executeQueryPrepared('SELECT * FROM ' . self::TABLE . ' WHERE kID = :kID', [':kID' => $kID], 1);
+ if ($payment && $payment->kBestellung) {
+ $payment->oBestellung = new Bestellung($payment->kBestellung, false);
+ }
+ return $payment;
+ }
+
+ /**
+ * @param $cHash
+ * @return array|int|object
+ */
+ public static function getPaymentHash($cHash)
+ {
+ $payment = Shop::DB()->executeQueryPrepared('SELECT * FROM ' . self::TABLE . ' WHERE cHash = :cHash', [':cHash' => $cHash], 1);
+ if ($payment && $payment->kBestellung) {
+ $payment->oBestellung = new Bestellung($payment->kBestellung, false);
+ }
+ return $payment;
+ }
+}
diff --git a/version/109/class/Mollie.php b/version/109/class/Mollie.php
new file mode 100644
index 0000000..1f87dbe
--- /dev/null
+++ b/version/109/class/Mollie.php
@@ -0,0 +1,556 @@
+getValue(CONF_KAUFABWICKLUNG, 'bestellabschluss_abschlussseite');
+
+ $bestellid = Shop::DB()->select("tbestellid ", 'kBestellung', (int)$kBestellung);
+ $url = Shop::getURL() . '/bestellabschluss.php?i=' . $bestellid->cId;
+
+
+ if ($mode == 'S' || !$bestellid) { // Statusseite
+ $bestellstatus = Shop::DB()->select('tbestellstatus', 'kBestellung', (int)$kBestellung);
+ $url = Shop::getURL() . '/status.php?uid=' . $bestellstatus->cUID;
+ }
+
+ if ($redirect) {
+ if (!headers_sent()) {
+ header('Location: ' . $url);
+ }
+ echo "redirect ... ";
+ exit();
+ }
+ return $url;
+ }
+
+ /**
+ * @param Order $order
+ * @param $kBestellung
+ * @param bool $newStatus
+ * @return array
+ * @throws Exception
+ */
+ public static function getShipmentOptions(Order $order, $kBestellung, $newStatus = false)
+ {
+ if (!$order || !$kBestellung) {
+ throw new Exception('Mollie::getShipmentOptions: order and kBestellung are required!');
+ }
+
+ $oBestellung = new Bestellung($kBestellung, true);
+ if ($newStatus === false) {
+ $newStatus = $oBestellung->cStatus;
+ }
+ $options = [];
+
+ // Tracking Data
+ if ($oBestellung->cTracking) {
+ $tracking = new stdClass();
+ $tracking->carrier = $oBestellung->cVersandartName;
+ $tracking->url = $oBestellung->cTrackingURL;
+ $tracking->code = $oBestellung->cTracking;
+ $options['tracking'] = $tracking;
+ }
+
+ $logData = '#' . $oBestellung->kBestellung . '§' . $oBestellung->cBestellNr . '$' . $order->id;
+
+ switch ((int)$newStatus) {
+ case BESTELLUNG_STATUS_VERSANDT:
+ Mollie::JTLMollie()->doLog('181_sync: Bestellung versandt', $logData, LOGLEVEL_DEBUG);
+ $options['lines'] = [];
+ break;
+ case BESTELLUNG_STATUS_TEILVERSANDT:
+ $lines = [];
+ foreach ($order->lines as $i => $line) {
+ if ($line->totalAmount->value > 0.0)
+ if (($quantity = Mollie::getBestellPosSent($line->sku, $oBestellung)) !== false && ($quantity - $line->quantityShipped) > 0) {
+ $x = min($quantity - $line->quantityShipped, $line->shippableQuantity);
+ if ($x > 0) {
+ $lines[] = (object)[
+ 'id' => $line->id,
+ 'quantity' => $x,
+ 'amount' => (object)[
+ 'currency' => $line->totalAmount->currency,
+ 'value' => number_format($x * $line->unitPrice->value, 2),
+ ],
+ ];
+ }
+ }
+ }
+ Mollie::JTLMollie()->doLog('181_sync: Bestellung teilversandt', $logData, LOGLEVEL_DEBUG);
+ if (count($lines)) {
+ $options['lines'] = $lines;
+ }
+ break;
+ case BESTELLUNG_STATUS_STORNO:
+ Mollie::JTLMollie()->doLog('181_sync: Bestellung storniert', $logData, LOGLEVEL_DEBUG);
+ $options = null;
+ break;
+ case BESTELLUNG_STATUS_BEZAHLT:
+ case BESTELLUNG_STATUS_IN_BEARBEITUNG:
+ case BESTELLUNG_STATUS_OFFEN:
+ // NOTHING TO DO!
+ break;
+ default:
+ Mollie::JTLMollie()->doLog('181_sync: Bestellungstatus unbekannt: ' . $newStatus . '/' . $oBestellung->cStatus, $logData, LOGLEVEL_DEBUG);
+ }
+
+ return $options;
+ }
+
+ /**
+ * @return JTLMollie
+ * @throws Exception
+ */
+ public static function JTLMollie()
+ {
+ if (self::$_jtlmollie === null) {
+ $pza = Shop::DB()->select('tpluginzahlungsartklasse', 'cClassName', 'JTLMollie');
+ if (!$pza) {
+ throw new Exception("Mollie Zahlungsart nicht in DB gefunden!");
+ }
+ require_once __DIR__ . '/../paymentmethod/JTLMollie.php';
+ self::$_jtlmollie = new JTLMollie($pza->cModulId);
+ }
+ return self::$_jtlmollie;
+ }
+
+ /**
+ * Returns amount of sent items for SKU
+ * @param $sku
+ * @param Bestellung $oBestellung
+ * @return float|int
+ * @throws Exception
+ */
+ public static function getBestellPosSent($sku, Bestellung $oBestellung)
+ {
+ if ($sku === null) {
+ return 1;
+ }
+ /** @var WarenkorbPos $oPosition */
+ foreach ($oBestellung->Positionen as $oPosition) {
+ if ($oPosition->cArtNr === $sku) {
+ $sent = 0;
+ /** @var Lieferschein $oLieferschein */
+ foreach ($oBestellung->oLieferschein_arr as $oLieferschein) {
+ /** @var Lieferscheinpos $oLieferscheinPos */
+ foreach ($oLieferschein->oLieferscheinPos_arr as $oLieferscheinPos) {
+ if ($oLieferscheinPos->getBestellPos() == $oPosition->kBestellpos) {
+ $sent += $oLieferscheinPos->getAnzahl();
+ }
+ }
+ }
+ return $sent;
+ }
+ }
+ return false;
+ }
+
+ /**
+ *
+ */
+ public static function fixZahlungsarten()
+ {
+ $kPlugin = Helper::oPlugin()->kPlugin;
+ if ((int)$kPlugin) {
+ $test1 = 'kPlugin_%_mollie%';
+ $test2 = 'kPlugin_' . $kPlugin . '_mollie%';
+ $conflicted_arr = Shop::DB()->executeQueryPrepared("SELECT kZahlungsart, cName, cModulId FROM `tzahlungsart` WHERE cModulId LIKE :test1 AND cModulId NOT LIKE :test2", [
+ ':test1' => $test1,
+ ':test2' => $test2,
+ ], 2);
+ if ($conflicted_arr && count($conflicted_arr)) {
+ foreach ($conflicted_arr as $conflicted) {
+ Shop::DB()->executeQueryPrepared('UPDATE tzahlungsart SET cModulId = :cModulId WHERE kZahlungsart = :kZahlungsart', [
+ ':cModulId' => preg_replace('/^kPlugin_\d+_/', 'kPlugin_' . $kPlugin . '_', $conflicted->cModulId),
+ ':kZahlungsart' => $conflicted->kZahlungsart,
+ ], 3);
+ }
+ }
+ }
+ }
+
+ /**
+ * @param Order $order
+ * @param null $kBestellung
+ * @return bool
+ * @throws Exception
+ */
+ public static function handleOrder(Order $order, $kBestellung)
+ {
+ $logData = '$' . $order->id . '#' . $kBestellung . "§" . $order->orderNumber;
+
+ $oBestellung = new Bestellung($kBestellung);
+ if ($oBestellung->kBestellung) {
+
+ Shop::DB()->executeQueryPrepared("INSERT INTO tbestellattribut (kBestellung, cName, cValue) VALUES (:kBestellung, 'mollie_oid', :mollieId1) ON DUPLICATE KEY UPDATE cValue = :mollieId2;", [
+ ':kBestellung' => $kBestellung,
+ ':mollieId1' => $order->id,
+ ':mollieId2' => $order->id,
+ ], 3);
+
+ Shop::DB()->executeQueryPrepared("INSERT INTO tbestellattribut (kBestellung, cName, cValue) VALUES (:kBestellung, 'mollie_cBestellNr', :orderId1) ON DUPLICATE KEY UPDATE cValue = :orderId2;", [
+ ':kBestellung' => $kBestellung,
+ ':orderId1' => $oBestellung->cBestellNr,
+ ':orderId2' => $oBestellung->cBestellNr,
+ ], 3);
+
+ if (isset($order->metadata->originalOrderNumber)) {
+ Shop::DB()->executeQueryPrepared("INSERT INTO tbestellattribut (kBestellung, cName, cValue) VALUES (:kBestellung, 'mollie_cFakeBestellNr', :orderId1) ON DUPLICATE KEY UPDATE cValue = :orderId2;", [
+ ':kBestellung' => $kBestellung,
+ ':orderId1' => $order->metadata->originalOrderNumber,
+ ':orderId2' => $order->metadata->originalOrderNumber,
+ ], 3);
+ }
+
+ $mPayment = null;
+ if ($payments = $order->payments()) {
+ /** @var \Mollie\Api\Resources\Payment $payment */
+ foreach ($payments as $payment) {
+ if (in_array($payment->status, [PaymentStatus::STATUS_AUTHORIZED, PaymentStatus::STATUS_PAID])) {
+ $mPayment = $payment;
+ }
+ }
+ }
+ if ($mPayment) {
+ Shop::DB()->executeQueryPrepared("INSERT INTO tbestellattribut (kBestellung, cName, cValue) VALUES (:kBestellung, 'mollie_tid', :mollieId1) ON DUPLICATE KEY UPDATE cValue = :mollieId2;", [
+ ':kBestellung' => $kBestellung,
+ ':mollieId1' => $mPayment->id,
+ ':mollieId2' => $mPayment->id,
+ ], 3);
+ }
+
+ try {
+ // Try to change the orderNumber
+ if ($order->orderNumber !== $oBestellung->cBestellNr) {
+ JTLMollie::API()->performHttpCall("PATCH", sprintf('orders/%s', $order->id), json_encode(['orderNumber' => $oBestellung->cBestellNr]));
+ }
+ } catch (Exception $e) {
+ self::JTLMollie()->doLog('Mollie::handleOrder: ' . $e->getMessage(), $logData);
+ }
+
+ $_payment = self::getLastPayment($order);
+
+ if ($_payment && $_payment->description !== $oBestellung->cBestellNr) {
+ JTLMollie::API()->performHttpCall('PATCH', sprintf('payments/%s', $_payment->id), json_encode(['description' => $oBestellung->cBestellNr]));
+ }
+
+
+ $order->orderNumber = $oBestellung->cBestellNr;
+ Payment::updateFromPayment($order, $kBestellung);
+
+ $oIncomingPayment = Shop::DB()->executeQueryPrepared("SELECT * FROM tzahlungseingang WHERE kBestellung = :kBestellung", [':kBestellung' => $oBestellung->kBestellung], 1);
+ if (!$oIncomingPayment) {
+ $oIncomingPayment = new stdClass();
+ }
+
+ // 2. Check PaymentStatus
+ switch ($order->status) {
+ case OrderStatus::STATUS_PAID:
+ case OrderStatus::STATUS_COMPLETED:
+ case OrderStatus::STATUS_AUTHORIZED:
+
+ $cHinweis = $order->id;
+ if ($mPayment) {
+ $cHinweis .= ' / ' . $mPayment->id;
+ }
+ if (Helper::getSetting('wawiPaymentID') === 'ord') {
+ $cHinweis = $order->id;
+ } elseif ($mPayment && Helper::getSetting('wawiPaymentID') === 'tr') {
+ $cHinweis = $mPayment->id;
+ }
+
+ if($mPayment->method === PaymentMethod::PAYPAL && isset($mPayment->details->paypalReference)){
+ $cHinweis = $mPayment->details->paypalReference;
+ $oIncomingPayment->cZahler = isset($payment->details->paypalPayerId) ? $payment->details->paypalPayerId : '';
+ }
+
+ $oIncomingPayment->fBetrag = $order->amount->value;
+ $oIncomingPayment->cISO = $order->amount->currency;
+ $oIncomingPayment->cHinweis = $cHinweis;
+ Mollie::JTLMollie()->addIncomingPayment($oBestellung, $oIncomingPayment);
+ Mollie::JTLMollie()->setOrderStatusToPaid($oBestellung);
+ Mollie::JTLMollie()->doLog('Mollie::handleOrder/PaymentStatus: ' . $order->status . ' => Zahlungseingang (' . $order->amount->value . ')', $logData, LOGLEVEL_DEBUG);
+ break;
+ case OrderStatus::STATUS_SHIPPING:
+ case OrderStatus::STATUS_PENDING:
+ Mollie::JTLMollie()->setOrderStatusToPaid($oBestellung);
+ Mollie::JTLMollie()->doLog('Mollie::handleOrder/PaymentStatus: ' . $order->status . ' => Bestellung bezahlt, KEIN Zahlungseingang', $logData, LOGLEVEL_NOTICE);
+ break;
+ case OrderStatus::STATUS_CANCELED:
+ case OrderStatus::STATUS_EXPIRED:
+ Mollie::JTLMollie()->doLog('Mollie::handleOrder/PaymentStatus: ' . $order->status, $logData, LOGLEVEL_ERROR);
+ break;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * @param Order $order
+ * @return \Mollie\Api\Resources\Payment|null
+ */
+ public static function getLastPayment(Order $order)
+ {
+ $payment = null;
+ if ($order->payments()) {
+ /** @var \Mollie\Api\Resources\Payment $p */
+ foreach ($order->payments() as $p) {
+ if (!$payment) {
+ $payment = $p;
+ continue;
+ }
+ if (strtotime($p->createdAt) > strtotime($payment->createdAt)) {
+ $payment = $p;
+ }
+ }
+ }
+ return $payment;
+ }
+
+ public static function getLocales()
+ {
+ $locales = ['en_US',
+ 'nl_NL',
+ 'nl_BE',
+ 'fr_FR',
+ 'fr_BE',
+ 'de_DE',
+ 'de_AT',
+ 'de_CH',
+ 'es_ES',
+ 'ca_ES',
+ 'pt_PT',
+ 'it_IT',
+ 'nb_NO',
+ 'sv_SE',
+ 'fi_FI',
+ 'da_DK',
+ 'is_IS',
+ 'hu_HU',
+ 'pl_PL',
+ 'lv_LV',
+ 'lt_LT',];
+
+ $laender = [];
+ $shopLaender = Shop::DB()->executeQuery("SELECT cLaender FROM tversandart", 2);
+ foreach ($shopLaender as $sL) {
+ $laender = array_merge(explode(' ', $sL->cLaender));
+ }
+ $laender = array_unique($laender);
+
+ $result = [];
+ $shopSprachen = Shop::DB()->executeQuery("SELECT * FROM tsprache", 2);
+ foreach ($shopSprachen as $sS) {
+ foreach ($laender as $land) {
+ $result[] = JTLMollie::getLocale($sS->cISO, $land);
+ }
+ }
+ return array_unique($result);
+ }
+
+ public static function getCurrencies()
+ {
+ $currencies = ['AED' => 'AED - United Arab Emirates dirham',
+ 'AFN' => 'AFN - Afghan afghani',
+ 'ALL' => 'ALL - Albanian lek',
+ 'AMD' => 'AMD - Armenian dram',
+ 'ANG' => 'ANG - Netherlands Antillean guilder',
+ 'AOA' => 'AOA - Angolan kwanza',
+ 'ARS' => 'ARS - Argentine peso',
+ 'AUD' => 'AUD - Australian dollar',
+ 'AWG' => 'AWG - Aruban florin',
+ 'AZN' => 'AZN - Azerbaijani manat',
+ 'BAM' => 'BAM - Bosnia and Herzegovina convertible mark',
+ 'BBD' => 'BBD - Barbados dollar',
+ 'BDT' => 'BDT - Bangladeshi taka',
+ 'BGN' => 'BGN - Bulgarian lev',
+ 'BHD' => 'BHD - Bahraini dinar',
+ 'BIF' => 'BIF - Burundian franc',
+ 'BMD' => 'BMD - Bermudian dollar',
+ 'BND' => 'BND - Brunei dollar',
+ 'BOB' => 'BOB - Boliviano',
+ 'BRL' => 'BRL - Brazilian real',
+ 'BSD' => 'BSD - Bahamian dollar',
+ 'BTN' => 'BTN - Bhutanese ngultrum',
+ 'BWP' => 'BWP - Botswana pula',
+ 'BYN' => 'BYN - Belarusian ruble',
+ 'BZD' => 'BZD - Belize dollar',
+ 'CAD' => 'CAD - Canadian dollar',
+ 'CDF' => 'CDF - Congolese franc',
+ 'CHF' => 'CHF - Swiss franc',
+ 'CLP' => 'CLP - Chilean peso',
+ 'CNY' => 'CNY - Renminbi (Chinese) yuan',
+ 'COP' => 'COP - Colombian peso',
+ 'COU' => 'COU - Unidad de Valor Real (UVR)',
+ 'CRC' => 'CRC - Costa Rican colon',
+ 'CUC' => 'CUC - Cuban convertible peso',
+ 'CUP' => 'CUP - Cuban peso',
+ 'CVE' => 'CVE - Cape Verde escudo',
+ 'CZK' => 'CZK - Czech koruna',
+ 'DJF' => 'DJF - Djiboutian franc',
+ 'DKK' => 'DKK - Danish krone',
+ 'DOP' => 'DOP - Dominican peso',
+ 'DZD' => 'DZD - Algerian dinar',
+ 'EGP' => 'EGP - Egyptian pound',
+ 'ERN' => 'ERN - Eritrean nakfa',
+ 'ETB' => 'ETB - Ethiopian birr',
+ 'EUR' => 'EUR - Euro',
+ 'FJD' => 'FJD - Fiji dollar',
+ 'FKP' => 'FKP - Falkland Islands pound',
+ 'GBP' => 'GBP - Pound sterling',
+ 'GEL' => 'GEL - Georgian lari',
+ 'GHS' => 'GHS - Ghanaian cedi',
+ 'GIP' => 'GIP - Gibraltar pound',
+ 'GMD' => 'GMD - Gambian dalasi',
+ 'GNF' => 'GNF - Guinean franc',
+ 'GTQ' => 'GTQ - Guatemalan quetzal',
+ 'GYD' => 'GYD - Guyanese dollar',
+ 'HKD' => 'HKD - Hong Kong dollar',
+ 'HNL' => 'HNL - Honduran lempira',
+ 'HRK' => 'HRK - Croatian kuna',
+ 'HTG' => 'HTG - Haitian gourde',
+ 'HUF' => 'HUF - Hungarian forint',
+ 'IDR' => 'IDR - Indonesian rupiah',
+ 'ILS' => 'ILS - Israeli new shekel',
+ 'INR' => 'INR - Indian rupee',
+ 'IQD' => 'IQD - Iraqi dinar',
+ 'IRR' => 'IRR - Iranian rial',
+ 'ISK' => 'ISK - Icelandic króna',
+ 'JMD' => 'JMD - Jamaican dollar',
+ 'JOD' => 'JOD - Jordanian dinar',
+ 'JPY' => 'JPY - Japanese yen',
+ 'KES' => 'KES - Kenyan shilling',
+ 'KGS' => 'KGS - Kyrgyzstani som',
+ 'KHR' => 'KHR - Cambodian riel',
+ 'KMF' => 'KMF - Comoro franc',
+ 'KPW' => 'KPW - North Korean won',
+ 'KRW' => 'KRW - South Korean won',
+ 'KWD' => 'KWD - Kuwaiti dinar',
+ 'KYD' => 'KYD - Cayman Islands dollar',
+ 'KZT' => 'KZT - Kazakhstani tenge',
+ 'LAK' => 'LAK - Lao kip',
+ 'LBP' => 'LBP - Lebanese pound',
+ 'LKR' => 'LKR - Sri Lankan rupee',
+ 'LRD' => 'LRD - Liberian dollar',
+ 'LSL' => 'LSL - Lesotho loti',
+ 'LYD' => 'LYD - Libyan dinar',
+ 'MAD' => 'MAD - Moroccan dirham',
+ 'MDL' => 'MDL - Moldovan leu',
+ 'MGA' => 'MGA - Malagasy ariary',
+ 'MKD' => 'MKD - Macedonian denar',
+ 'MMK' => 'MMK - Myanmar kyat',
+ 'MNT' => 'MNT - Mongolian tögrög',
+ 'MOP' => 'MOP - Macanese pataca',
+ 'MRU' => 'MRU - Mauritanian ouguiya',
+ 'MUR' => 'MUR - Mauritian rupee',
+ 'MVR' => 'MVR - Maldivian rufiyaa',
+ 'MWK' => 'MWK - Malawian kwacha',
+ 'MXN' => 'MXN - Mexican peso',
+ 'MXV' => 'MXV - Mexican Unidad de Inversion (UDI)',
+ 'MYR' => 'MYR - Malaysian ringgit',
+ 'MZN' => 'MZN - Mozambican metical',
+ 'NAD' => 'NAD - Namibian dollar',
+ 'NGN' => 'NGN - Nigerian naira',
+ 'NIO' => 'NIO - Nicaraguan córdoba',
+ 'NOK' => 'NOK - Norwegian krone',
+ 'NPR' => 'NPR - Nepalese rupee',
+ 'NZD' => 'NZD - New Zealand dollar',
+ 'OMR' => 'OMR - Omani rial',
+ 'PAB' => 'PAB - Panamanian balboa',
+ 'PEN' => 'PEN - Peruvian sol',
+ 'PGK' => 'PGK - Papua New Guinean kina',
+ 'PHP' => 'PHP - Philippine peso',
+ 'PKR' => 'PKR - Pakistani rupee',
+ 'PLN' => 'PLN - Polish z?oty',
+ 'PYG' => 'PYG - Paraguayan guaraní',
+ 'QAR' => 'QAR - Qatari riyal',
+ 'RON' => 'RON - Romanian leu',
+ 'RSD' => 'RSD - Serbian dinar',
+ 'RUB' => 'RUB - Russian ruble',
+ 'RWF' => 'RWF - Rwandan franc',
+ 'SAR' => 'SAR - Saudi riyal',
+ 'SBD' => 'SBD - Solomon Islands dollar',
+ 'SCR' => 'SCR - Seychelles rupee',
+ 'SDG' => 'SDG - Sudanese pound',
+ 'SEK' => 'SEK - Swedish krona/kronor',
+ 'SGD' => 'SGD - Singapore dollar',
+ 'SHP' => 'SHP - Saint Helena pound',
+ 'SLL' => 'SLL - Sierra Leonean leone',
+ 'SOS' => 'SOS - Somali shilling',
+ 'SRD' => 'SRD - Surinamese dollar',
+ 'SSP' => 'SSP - South Sudanese pound',
+ 'STN' => 'STN - São Tomé and Príncipe dobra',
+ 'SVC' => 'SVC - Salvadoran colón',
+ 'SYP' => 'SYP - Syrian pound',
+ 'SZL' => 'SZL - Swazi lilangeni',
+ 'THB' => 'THB - Thai baht',
+ 'TJS' => 'TJS - Tajikistani somoni',
+ 'TMT' => 'TMT - Turkmenistan manat',
+ 'TND' => 'TND - Tunisian dinar',
+ 'TOP' => 'TOP - Tongan pa?anga',
+ 'TRY' => 'TRY - Turkish lira',
+ 'TTD' => 'TTD - Trinidad and Tobago dollar',
+ 'TWD' => 'TWD - New Taiwan dollar',
+ 'TZS' => 'TZS - Tanzanian shilling',
+ 'UAH' => 'UAH - Ukrainian hryvnia',
+ 'UGX' => 'UGX - Ugandan shilling',
+ 'USD' => 'USD - United States dollar',
+ 'UYI' => 'UYI - Uruguay Peso en Unidades Indexadas',
+ 'UYU' => 'UYU - Uruguayan peso',
+ 'UYW' => 'UYW - Unidad previsional',
+ 'UZS' => 'UZS - Uzbekistan som',
+ 'VES' => 'VES - Venezuelan bolívar soberano',
+ 'VND' => 'VND - Vietnamese ??ng',
+ 'VUV' => 'VUV - Vanuatu vatu',
+ 'WST' => 'WST - Samoan tala',
+ 'YER' => 'YER - Yemeni rial',
+ 'ZAR' => 'ZAR - South African rand',
+ 'ZMW' => 'ZMW - Zambian kwacha',
+ 'ZWL' => 'ZWL - Zimbabwean dollar'];
+
+ $shopCurrencies = Shop::DB()->executeQuery("SELECT * FROM twaehrung", 2);
+
+ $result = [];
+
+ foreach ($shopCurrencies as $sC) {
+ if (array_key_exists($sC->cISO, $currencies)) {
+ $result[$sC->cISO] = $currencies[$sC->cISO];
+ }
+ }
+
+ return $result;
+ }
+}
diff --git a/version/109/frontend/131_globalinclude.php b/version/109/frontend/131_globalinclude.php
new file mode 100644
index 0000000..5778e21
--- /dev/null
+++ b/version/109/frontend/131_globalinclude.php
@@ -0,0 +1,120 @@
+cNotifyID;
+
+ if (!(int)$oZahlungSession->kBestellung && $oZahlungSession->cNotifyID) {
+ Mollie::JTLMollie()->doLog("Hook 131: Bestellung noch nicht finalisiert ({$oZahlungSession->cNotifyID})", $logData, LOGLEVEL_DEBUG);
+ // Bestellung noch nicht finalisiert
+ $mOrder = JTLMollie::API()->orders->get($oZahlungSession->cNotifyID, ['embed' => 'payments']);
+ if ($mOrder && $mOrder->id === $oZahlungSession->cNotifyID) {
+
+ $lock = new \ws_mollie\ExclusiveLock('mollie_' . $mOrder->id, PFAD_ROOT . PFAD_COMPILEDIR);
+ $logged = false;
+ $maxWait = 120;
+ while (!$lock->lock() && $maxWait > 0) {
+ if (!$logged) {
+ Mollie::JTLMollie()->doLog("Hook 131: Order currently locked ({$oZahlungSession->cNotifyID})", $logData, LOGLEVEL_DEBUG);
+ $logged = microtime(true);
+ }
+ usleep(1000000);
+ $maxWait--;
+ }
+
+ if ($logged) {
+ Mollie::JTLMollie()->doLog("Hook 131: Order unlocked (after " . round(microtime(true) - $logged, 2) . "s - maxWait left: {$maxWait})", $logData, LOGLEVEL_DEBUG);
+ } else {
+ Mollie::JTLMollie()->doLog("Hook 131: Order locked - maxWait left: {$maxWait})", $logData, LOGLEVEL_DEBUG);
+ }
+
+ $oZahlungSession = JTLMollie::getZahlungSession($_REQUEST['mollie']);
+ if ((int)$oZahlungSession->kBestellung) {
+ Mollie::JTLMollie()->doLog("Hook 131: Order finalized already ({$oZahlungSession->kBestellung}) => redirect", $logData, LOGLEVEL_DEBUG);
+ return Mollie::getOrderCompletedRedirect($oZahlungSession->kBestellung, true);
+ }
+
+ Mollie::JTLMollie()->doLog("Hook 131: Order {$mOrder->id} - {$mOrder->status} " . print_r($mOrder, 1) . " ", $logData, LOGLEVEL_DEBUG);
+ if (!in_array($mOrder->status, [OrderStatus::STATUS_EXPIRED, OrderStatus::STATUS_CANCELED])) {
+
+ $payment = Mollie::getLastPayment($mOrder);
+ if (in_array($payment->status, [PaymentStatus::STATUS_AUTHORIZED, PaymentStatus::STATUS_PAID, PaymentStatus::STATUS_PENDING])) {
+
+ if (session_id() !== $oZahlungSession->cSID) {
+ Mollie::JTLMollie()->doLog("Hook 131: Switch to PaymentSession " . print_r([session_id(), $oZahlungSession], 1) . " ", $logData, LOGLEVEL_DEBUG);
+ session_destroy();
+ session_id($oZahlungSession->cSID);
+ $session = Session::getInstance(true, true);
+ } else {
+ Mollie::JTLMollie()->doLog("Hook 131: Already in PaymentSession " . print_r([session_id(), $oZahlungSession], 1) . " ", $logData, LOGLEVEL_DEBUG);
+ $session = Session::getInstance(false, false);
+ }
+
+ require_once PFAD_ROOT . 'includes/bestellabschluss_inc.php';
+ require_once PFAD_ROOT . 'includes/mailTools.php';
+
+ $order = fakeBestellung();
+ $order = finalisiereBestellung();
+ $session->cleanUp();
+ $logData .= '#' . $order->kBestellung . 'ß' . $order->cBestellNr;
+ Mollie::JTLMollie()->doLog("Hook 131: Bestellung finalisiert " . print_r([$order->kBestellung, $order->cBestellNr], 1) . " ", $logData, LOGLEVEL_DEBUG);
+
+ if ($order->kBestellung > 0) {
+ Mollie::JTLMollie()->doLog("Hook 131: Finalisierung erfolgreich, kBestellung: {$order->kBestellung} / {$order->cBestellNr}", $logData, LOGLEVEL_DEBUG);
+ $oZahlungSession->nBezahlt = 1;
+ $oZahlungSession->dZeitBezahlt = 'now()';
+ $oZahlungSession->kBestellung = (int)$order->kBestellung;
+ $oZahlungSession->dNotify = strtotime($oZahlungSession->dNotify > 0) ? $oZahlungSession->dNotify : date("Y-m-d H:i:s");
+ Shop::DB()->update('tzahlungsession', 'cZahlungsID', $oZahlungSession->cZahlungsID, $oZahlungSession);
+ Mollie::handleOrder($mOrder, $order->kBestellung);
+ return Mollie::getOrderCompletedRedirect($order->kBestellung, true);
+ } else {
+ Mollie::JTLMollie()->doLog("Hook 131: Fionalisierung fehlgeschlagen " . print_r($order, 1) . " ", $logData, LOGLEVEL_ERROR);
+ }
+ } else {
+ Mollie::JTLMollie()->doLog("Hook 131: Invalid PaymentStatus: {$payment->status} for {$payment->id} ", $logData, LOGLEVEL_ERROR);
+ header('Location: ' . Shop::getURL() . '/bestellvorgang.php?editZahlungsart=1&mollieStatus=' . $payment->status);
+ exit();
+ }
+
+ } else {
+ Mollie::JTLMollie()->doLog("Hook 131: Invalid OrderStatus: {$mOrder->status} for {$mOrder->id} ", $logData, LOGLEVEL_ERROR);
+ header('Location: ' . Shop::getURL() . '/bestellvorgang.php?editZahlungsart=1&mollieStatus=' . $mOrder->status);
+ exit();
+ }
+ } else {
+ Mollie::JTLMollie()->doLog("Hook 131: Could not get Order for {$oZahlungSession->cNotifyID}", $logData, LOGLEVEL_ERROR);
+ header('Location: ' . Shop::getURL() . '/bestellvorgang.php?editZahlungsart=1');
+ exit();
+ }
+ } else {
+ Mollie::JTLMollie()->doLog("Hook 131: already finalized => redirect / kBestellung:{$oZahlungSession->kBestellung} && cNotifyID:{$oZahlungSession->cNotifyID}", $logData, LOGLEVEL_NOTICE);
+ }
+ return Mollie::getOrderCompletedRedirect((int)$oZahlungSession->kBestellung, true);
+ }
+ }
+ ob_end_flush();
+} catch (Exception $e) {
+ Helper::logExc($e);
+}
+
+
diff --git a/version/109/frontend/140_smarty.php b/version/109/frontend/140_smarty.php
new file mode 100644
index 0000000..ac119c6
--- /dev/null
+++ b/version/109/frontend/140_smarty.php
@@ -0,0 +1,78 @@
+oPluginSprachvariableAssoc_arr['error_' . $status];
+ pq('#fieldset-payment')->prepend('' . $text . '
');
+ }
+
+ $applePayId = "kPlugin_" . Helper::oPlugin()->kPlugin . "_mollieapplepay";
+ if (pq('#' . $applePayId)) {
+ $selector = 'body';
+ if (array_key_exists('isAjax', $_REQUEST)) {
+ $selector = '#checkout';
+ }
+
+ pq($selector)->append(<<
+//
+HTML
+ );
+ }
+
+ switch (Helper::getSetting('load_styles')) {
+ case 'Y':
+ $selector = '#fieldset-payment [id*="_mollie"]';
+ $border = "";
+ break;
+ case 'A':
+ $selector = '#fieldset-payment';
+ $border = "border-bottom: 1px solid #ccc;";
+ break;
+ case 'N':
+ default:
+ return;
+ }
+
+ $lh = "30px";
+ if (Helper::getSetting('paymentmethod_sync') === 'size2x') {
+ $lh = "40px";
+ }
+
+ pq('head')->append(
+ <<
+ /* MOLLIE CHECKOUT STYLES*/
+ #fieldset-payment .form-group > div:hover, #checkout-shipping-payment .form-group > div:hover {
+ background-color: #eee;
+ color: black;
+ }
+
+ {$selector} label > span {
+ line-height: {$lh};
+ }
+ {$selector} label {
+ {$border}
+ }
+ {$selector} label img {
+ float: right;
+ }
+
+HTML
+ );
+} catch (Exception $e) {
+ Helper::logExc($e);
+}
diff --git a/version/109/frontend/144_notify.php b/version/109/frontend/144_notify.php
new file mode 100644
index 0000000..d1826a4
--- /dev/null
+++ b/version/109/frontend/144_notify.php
@@ -0,0 +1,63 @@
+ Update Payment, stop skript
+ * - ELSE weiter mit der notify.php
+ */
+
+
+use ws_mollie\Helper;
+use ws_mollie\Mollie;
+
+try {
+
+ require_once __DIR__ . '/../class/Helper.php';
+
+ Helper::init();
+
+ require_once __DIR__ . '/../paymentmethod/JTLMollie.php';
+
+ $orderId = array_key_exists('id', $_REQUEST) ? $_REQUEST['id'] : false;
+ if (!$orderId) {
+ // NOT A MOLLIE NOTIFICATION!
+ return;
+ }
+ $sh = array_key_exists('sh', $_REQUEST) ? $_REQUEST['sh'] : false;
+ if (!$sh) {
+ // NO SESSION HASH GIVEN!
+ return;
+ }
+
+ $logData = '$' . $orderId;
+
+ if ($oZahlungSession = JTLMollie::getZahlungSession(md5(trim($sh, '_')))) {
+
+ if (trim($oZahlungSession->cNotifyID) === '') {
+ $oZahlungSession->cNotifyID = $orderId;
+ Shop::DB()->update('tzahlungsession', 'cZahlungsID', $oZahlungSession->cZahlungsID, $oZahlungSession);
+ }
+
+ if ((int)$oZahlungSession->kBestellung <= 0) {
+ // Bestellung noch nicht abgeschlossen, weiter mit standard
+ Mollie::JTLMollie()->doLog("Hook 144: orderId open, finalize with shop standard: {$orderId} / {$oZahlungSession->cZahlungsID}", $logData, LOGLEVEL_NOTICE);
+ return;
+ }
+
+ if (trim($oZahlungSession->cNotifyID) === trim($orderId)) {
+ $logData = '$' . $oZahlungSession->cNotifyID;
+ Mollie::JTLMollie()->doLog("Hook 144: order finalized already => handleNotification", $logData, LOGLEVEL_NOTICE);
+ // Bestellung bereits finalisiert => evtl. Statusänderung
+ $oOrder = JTLMollie::API()->orders->get($orderId, ['embed' => 'payments']);
+ Mollie::handleOrder($oOrder, (int)$oZahlungSession->kBestellung);
+ exit();
+ } else {
+ Mollie::JTLMollie()->doLog("Hook 144: orderId invalid: {$orderId} / {$oZahlungSession->cNotifyID}", $logData, LOGLEVEL_ERROR);
+ }
+ } else {
+ Mollie::JTLMollie()->doLog("Hook 144: couldn't load ZahlungSession => {$sh}", $logData, LOGLEVEL_DEBUG);
+ }
+
+} catch (Exception $e) {
+ Helper::logExc($e);
+}
diff --git a/version/109/frontend/181_sync.php b/version/109/frontend/181_sync.php
new file mode 100644
index 0000000..86c610c
--- /dev/null
+++ b/version/109/frontend/181_sync.php
@@ -0,0 +1,43 @@
+kBestellung && $payment = Payment::getPayment($oBestellung->kBestellung)) {
+ $logData = '#' . $payment->kBestellung . '$' . $payment->kID . "§" . $oBestellung->cBestellNr;
+ Mollie::JTLMollie()->doLog("WAWI Abgleich: HOOK_BESTELLUNGEN_XML_BESTELLSTATUS" . print_r($args_arr, 1) . " ", $logData, LOGLEVEL_DEBUG);
+ try {
+ $order = JTLMollie::API()->orders->get($payment->kID);
+ //$order->orderNumber = $oBestellung->cBestellNr;
+ Mollie::handleOrder($order, $oBestellung->kBestellung);
+ if ($order->isCreated() || $order->isPaid() || $order->isAuthorized() || $order->isShipping() || $order->isPending()) {
+ $options = Mollie::getShipmentOptions($order, $oBestellung->kBestellung, $status);
+ if ($options && array_key_exists('lines', $options) && is_array($options['lines'])) {
+ require_once __DIR__ . '/../paymentmethod/JTLMollie.php';
+ $shipment = JTLMollie::API()->shipments->createFor($order, $options);
+ Mollie::JTLMollie()->doLog('Shipment created' . print_r(['options' => $options, 'shipment' => $shipment], 1) . ' ', $logData, LOGLEVEL_NOTICE);
+ } elseif ((int)$status !== BESTELLUNG_STATUS_BEZAHLT) {
+ Mollie::JTLMollie()->doLog('181_sync: options don\'t contain lines' . print_r([$order, $options], 1) . ' ', $logData, LOGLEVEL_ERROR);
+ }
+ }
+ } catch (Exception $e) {
+ Mollie::JTLMollie()->doLog('Fehler: ' . $e->getMessage() . '' . print_r($e->getTrace(), 1) . ' ', $logData, LOGLEVEL_ERROR);
+ }
+ }
+
+ //}
+} catch (Exception $e) {
+ Helper::logExc($e);
+}
diff --git a/version/109/frontend/img/trust_eng.png b/version/109/frontend/img/trust_eng.png
new file mode 100644
index 0000000..3d01773
Binary files /dev/null and b/version/109/frontend/img/trust_eng.png differ
diff --git a/version/109/frontend/img/trust_fre.png b/version/109/frontend/img/trust_fre.png
new file mode 100644
index 0000000..ed1a2f6
Binary files /dev/null and b/version/109/frontend/img/trust_fre.png differ
diff --git a/version/109/frontend/img/trust_ger.png b/version/109/frontend/img/trust_ger.png
new file mode 100644
index 0000000..e42821b
Binary files /dev/null and b/version/109/frontend/img/trust_ger.png differ
diff --git a/version/109/paymentmethod/JTLMollie.php b/version/109/paymentmethod/JTLMollie.php
new file mode 100644
index 0000000..214a5e8
--- /dev/null
+++ b/version/109/paymentmethod/JTLMollie.php
@@ -0,0 +1,774 @@
+ (int)$order->kBestellung,
+ 'cZahlungsanbieter' => empty($order->cZahlungsartName) ? $this->name : $order->cZahlungsartName,
+ 'fBetrag' => 0,
+ 'fZahlungsgebuehr' => 0,
+ 'cISO' => array_key_exists('Waehrung', $_SESSION) ? $_SESSION['Waehrung']->cISO : $payment->cISO,
+ 'cEmpfaenger' => '',
+ 'cZahler' => '',
+ 'dZeit' => 'now()',
+ 'cHinweis' => '',
+ 'cAbgeholt' => 'N'
+ ], (array)$payment);
+
+ $logData = '#' . $order->kBestellung;
+
+ if (isset($model->kZahlungseingang) && $model->kZahlungseingang > 0) {
+ Mollie::JTLMollie()->doLog('JTLMollie::addIncomingPayment (update)' . print_r([$model, $payment], 1) . ' ', $logData);
+ Shop::DB()->update('tzahlungseingang', 'kZahlungseingang', $model->kZahlungseingang, $model);
+ } else {
+ Mollie::JTLMollie()->doLog('JTLMollie::addIncomingPayment (create)' . print_r([$model, $payment], 1) . ' ', $logData);
+ Shop::DB()->insert('tzahlungseingang', $model);
+ }
+
+ return $this;
+ }
+
+ /**
+ * @param string $msg
+ * @param null $data
+ * @param int $level
+ * @return $this
+ */
+ public function doLog($msg, $data = null, $level = LOGLEVEL_NOTICE)
+ {
+ ZahlungsLog::add($this->moduleID, "[" . microtime(true) . " - " . $_SERVER['PHP_SELF'] . "] " . $msg, $data, $level);
+ return $this;
+ }
+
+ /**
+ * @param Bestellung $order
+ * @return PaymentMethod|void
+ */
+ public function setOrderStatusToPaid($order)
+ {
+ // If paid already, do nothing
+ if ((int)$order->cStatus >= BESTELLUNG_STATUS_BEZAHLT) {
+ return $this;
+ }
+ parent::setOrderStatusToPaid($order);
+ }
+
+ /**
+ * Prepares everything so that the Customer can start the Payment Process.
+ * Tells Template Engine.
+ *
+ * @param Bestellung $order
+ * @return bool|string
+ */
+ public function preparePaymentProcess($order)
+ {
+ $logData = '#' . $order->kBestellung . "§" . $order->cBestellNr;
+
+ $payable = (float)$order->fGesamtsumme > 0;
+
+ if ($payable) {
+ $this->updateMollieCustomer($_SESSION['Kunde']);
+ }
+
+ try {
+
+ if ($order->kBestellung) {
+ if ($payable) {
+ $payment = Payment::getPayment($order->kBestellung);
+ $oMolliePayment = self::API()->orders->get($payment->kID, ['embed' => 'payments']);
+ Mollie::handleOrder($oMolliePayment, $order->kBestellung);
+ if ($payment && in_array($payment->cStatus, [OrderStatus::STATUS_CREATED]) && $payment->cCheckoutURL) {
+ $logData .= '$' . $payment->kID;
+ if (!$this->duringCheckout) {
+ Session::getInstance()->cleanUp();
+ }
+ header('Location: ' . $payment->cCheckoutURL);
+ echo "redirect to payment ... ";
+ exit();
+ }
+ } else {
+ return Mollie::getOrderCompletedRedirect($order->kBestellung, true);
+ }
+ }
+ } catch (Exception $e) {
+ $this->doLog("Get Payment Error: " . $e->getMessage() . ". Create new ORDER...", $logData, LOGLEVEL_ERROR);
+ }
+
+
+ try {
+
+
+ if (!$payable) {
+ $bestellung = finalisiereBestellung();
+ if ($bestellung && (int)$bestellung->kBestellung > 0) {
+ return Mollie::getOrderCompletedRedirect($bestellung->kBestellung, true);
+ }
+ header('Location: ' . Shop::getURL() . '/bestellvorgang.php?editZahlungsart=1&mollieStatus=failed');
+ echo "redirect... ";
+ exit();
+ }
+
+ if (!array_key_exists('oMolliePayment', $_SESSION) || !($_SESSION['oMolliePayment'] instanceof Order)) {
+ $hash = $this->generateHash($order);
+ //$_SESSION['cMollieHash'] = $hash;
+ $orderData = $this->getOrderData($order, $hash);
+ $oMolliePayment = self::API()->orders->create($orderData);
+ $this->updateHash($hash, $oMolliePayment->id);
+ $_SESSION['oMolliePayment'] = $oMolliePayment;
+ } else {
+ $oMolliePayment = $_SESSION['oMolliePayment'];
+ }
+ $logData .= '$' . $oMolliePayment->id;
+ $this->doLog('Mollie Create Payment Redirect: ' . $oMolliePayment->getCheckoutUrl() . "" . print_r($oMolliePayment, 1) . " ", $logData, LOGLEVEL_DEBUG);
+ Payment::updateFromPayment($oMolliePayment, $order->kBestellung, md5(trim($hash, '_')));
+ Shop::Smarty()->assign('oMolliePayment', $oMolliePayment);
+ if (!$this->duringCheckout) {
+ Session::getInstance()->cleanUp();
+ }
+
+ if (!$oMolliePayment->getCheckoutUrl() && ($oMolliePayment->isAuthorized() || $oMolliePayment->isPaid())) {
+ header('Location: ' . $oMolliePayment->redirectUrl);
+ echo "redirect to order ... ";
+ } else {
+ header('Location: ' . $oMolliePayment->getCheckoutUrl());
+ echo "redirect to payment ... ";
+ }
+ unset($_SESSION['oMolliePayment']);
+
+ exit();
+ } catch (ApiException $e) {
+ $this->doLog("Create Payment Error: " . $e->getMessage() . '' . print_r($orderData, 1) . ' ', $logData, LOGLEVEL_ERROR);
+ header('Location: ' . Shop::getURL() . '/bestellvorgang.php?editZahlungsart=1&mollieStatus=failed');
+ echo "redirect... ";
+ exit();
+ }
+ }
+
+ /**
+ * @param $oKunde Kunde
+ */
+ public function updateMollieCustomer($oKunde)
+ {
+
+ return;
+
+// if (!$oKunde->kKunde || (int)$oKunde->nRegistriert <= 0) {
+// return;
+// }
+// try {
+// $customerId = Shop::DB()->select('xplugin_ws_mollie_kunde', 'kKunde', (int)$oKunde->kKunde);
+// $api = JTLMollie::API();
+// /** @var Customer $customer */
+// $customer = new stdClass();
+// if ($customerId && isset($customerId->customerId)) {
+// try {
+// $customer = $api->customers->get($customerId->customerId);
+// } catch (Exception $e) {
+// Helper::logExc($e);
+// }
+// }
+//
+// $customer->name = utf8_encode(trim($oKunde->cVorname . ' ' . $oKunde->cNachname));
+// $customer->email = utf8_encode($oKunde->cMail);
+// $customer->locale = self::getLocale($_SESSION['cISOSprache'], $_SESSION['Kunde']->cLand);
+// $customer->metadata = [
+// 'kKunde' => (int)$oKunde->kKunde,
+// 'kKundengruppe' => (int)$oKunde->kKundengruppe,
+// 'cKundenNr' => utf8_encode($oKunde->cKundenNr),
+// ];
+//
+// if ($customer instanceof Customer) {
+// $customer->update();
+// } else {
+// if ($customer = $api->customers->create((array)$customer)) {
+// if (self::getMollieCustomerId($oKunde->kKunde) === false) {
+// Shop::DB()->insert('xplugin_ws_mollie_kunde', (object)[
+// 'kKunde' => (int)$oKunde->kKunde,
+// 'customerId' => $customer->id,
+// ]);
+// } else {
+// Shop::DB()->update('xplugin_ws_mollie_kunde', 'kKunde', (int)$oKunde->kKunde, (object)[
+// 'customerId' => $customer->id,
+// ]);
+// }
+//
+// }
+// }
+//
+// } catch (Exception $e) {
+// Helper::logExc($e);
+// }
+ }
+
+ /**
+ * @return MollieApiClient
+ * @throws ApiException
+ * @throws IncompatiblePlatform
+ */
+ public static function API()
+ {
+ Helper::init();
+ if (self::$_mollie === null) {
+ self::$_mollie = new MollieApiClient(new Client([
+ RequestOptions::VERIFY => CaBundle::getBundledCaBundlePath(),
+ RequestOptions::TIMEOUT => 60,
+ ]));
+ self::$_mollie->setApiKey(Helper::getSetting('api_key'));
+ self::$_mollie->addVersionString("JTL-Shop/" . JTL_VERSION . '.' . JTL_MINOR_VERSION);
+ self::$_mollie->addVersionString("ws_mollie/" . Helper::oPlugin()->nVersion);
+ }
+ return self::$_mollie;
+ }
+
+ /**
+ * @param Bestellung $order
+ * @param $hash
+ * @return array
+ */
+ protected function getOrderData(Bestellung $order, $hash)
+ {
+ $locale = self::getLocale($_SESSION['cISOSprache'], $_SESSION['Kunde']->cLand);
+
+ $_currencyFactor = (float)$order->Waehrung->fFaktor;
+
+ $data = [
+ 'locale' => $locale ?: 'de_DE',
+ 'amount' => (object)[
+ 'currency' => $order->Waehrung->cISO,
+ //'value' => number_format($order->fGesamtsummeKundenwaehrung, 2, '.', ''),
+ // runden auf 5 Rappen berücksichtigt
+ 'value' => number_format($this->optionaleRundung($order->fGesamtsumme * $_currencyFactor), 2, '.', ''),
+ ],
+ 'orderNumber' => utf8_encode($order->cBestellNr),
+ 'lines' => [],
+ 'billingAddress' => new stdClass(),
+ 'metadata' => ['originalOrderNumber' => utf8_encode($order->cBestellNr)],
+ 'redirectUrl' => (int)$this->duringCheckout ? Shop::getURL() . '/bestellabschluss.php?mollie=' . md5(trim($hash, '_')) : $this->getReturnURL($order),
+ 'webhookUrl' => $this->getNotificationURL($hash), // . '&hash=' . md5(trim($hash, '_')),
+ ];
+
+ if (static::MOLLIE_METHOD !== '') {
+ $data['method'] = static::MOLLIE_METHOD;
+ }
+
+ if (static::MOLLIE_METHOD === \Mollie\Api\Types\PaymentMethod::CREDITCARD && array_key_exists('mollieCardToken', $_SESSION)) {
+ $data['payment'] = new stdClass();
+ $data['payment']->cardToken = trim($_SESSION['mollieCardToken']);
+ }
+
+ if (($customerId = self::getMollieCustomerId((int)$_SESSION['Kunde']->kKunde)) !== false) {
+ if (!array_key_exists('payment', $data)) {
+ $data['payment'] = new stdClass();
+ }
+ $data['payment']->customerId = $customerId;
+ }
+
+ if ($organizationName = utf8_encode(trim($order->oRechnungsadresse->cFirma))) {
+ $data['billingAddress']->organizationName = $organizationName;
+ }
+ $data['billingAddress']->title = utf8_encode($order->oRechnungsadresse->cAnrede === 'm' ? Shop::Lang()->get('mr') : Shop::Lang()->get('mrs'));
+ $data['billingAddress']->givenName = utf8_encode($order->oRechnungsadresse->cVorname);
+ $data['billingAddress']->familyName = utf8_encode($order->oRechnungsadresse->cNachname);
+ $data['billingAddress']->email = utf8_encode($order->oRechnungsadresse->cMail);
+ $data['billingAddress']->streetAndNumber = utf8_encode($order->oRechnungsadresse->cStrasse . ' ' . $order->oRechnungsadresse->cHausnummer);
+ $data['billingAddress']->postalCode = utf8_encode($order->oRechnungsadresse->cPLZ);
+ $data['billingAddress']->city = utf8_encode($order->oRechnungsadresse->cOrt);
+ $data['billingAddress']->country = $order->oRechnungsadresse->cLand;
+
+ if (array_key_exists('Kunde', $_SESSION)) {
+ if (isset($_SESSION['Kunde']->dGeburtstag) && trim($_SESSION['Kunde']->dGeburtstag) !== '0000-00-00' && preg_match('/^\d{4}-\d{2}-\d{2}$/', trim($_SESSION['Kunde']->dGeburtstag))) {
+
+ $data['consumerDateOfBirth'] = trim($_SESSION['Kunde']->dGeburtstag);
+ }
+ if (isset($_SESSION['Kunde']->cAdressZusatz) && trim($_SESSION['Kunde']->cAdressZusatz) !== '') {
+ $data['billingAddress']->streetAdditional = utf8_encode(trim($_SESSION['Kunde']->cAdressZusatz));
+ }
+ }
+
+ if ($order->Lieferadresse !== null) {
+ $data['shippingAddress'] = new stdClass();
+ if ($organizationName = utf8_encode(trim($order->Lieferadresse->cFirma))) {
+ $data['shippingAddress']->organizationName = $organizationName;
+ }
+ $data['shippingAddress']->title = utf8_encode($order->Lieferadresse->cAnrede === 'm' ? Shop::Lang()->get('mr') : Shop::Lang()->get('mrs'));
+ $data['shippingAddress']->givenName = utf8_encode($order->Lieferadresse->cVorname);
+ $data['shippingAddress']->familyName = utf8_encode($order->Lieferadresse->cNachname);
+ $data['shippingAddress']->email = utf8_encode($order->oRechnungsadresse->cMail);
+ $data['shippingAddress']->streetAndNumber = utf8_encode($order->Lieferadresse->cStrasse . ' ' . $order->Lieferadresse->cHausnummer);
+ $data['shippingAddress']->postalCode = utf8_encode($order->Lieferadresse->cPLZ);
+ $data['shippingAddress']->city = utf8_encode($order->Lieferadresse->cOrt);
+ $data['shippingAddress']->country = $order->Lieferadresse->cLand;
+
+ if (array_key_exists('Lieferadresse', $_SESSION) && isset($_SESSION['Lieferadresse']->cAdressZusatz) && trim($_SESSION['Lieferadresse']->cAdressZusatz) !== '') {
+ $data['shippingAddress']->streetAdditional = utf8_encode(trim($_SESSION['Lieferadresse']->cAdressZusatz));
+ }
+ }
+
+
+ foreach ($order->Positionen as $oPosition) {
+
+ $line = new stdClass();
+ $line->name = utf8_encode($oPosition->cName);
+
+ $_netto = round($oPosition->fPreis, 2);
+ $_vatRate = (float)$oPosition->fMwSt / 100;
+ $_amount = (float)$oPosition->nAnzahl;
+
+ if (Helper::getSetting("supportQ") === 'Y') {
+ // Rationale Stückzahlen aktiviert
+ if ((int)$oPosition->nPosTyp === (int)C_WARENKORBPOS_TYP_ARTIKEL && $oPosition->Artikel->cTeilbar === 'Y'
+ && fmod($oPosition->nAnzahl, 1) !== 0.0) {
+ $_netto *= $_amount;
+ $_amount = 1;
+ $line->name .= sprintf(" (%.2f %s)", (float)$oPosition->nAnzahl, $oPosition->cEinheit);
+ }
+ }
+
+ $unitPriceNetto = round(($_currencyFactor * $_netto), 2);
+ $unitPrice = round($unitPriceNetto * (1 + $_vatRate), 2);
+ $totalAmount = round($_amount * $unitPrice, 2);
+ $vatAmount = round($totalAmount - ($totalAmount / (1 + $_vatRate)), 2);
+
+ $line->quantity = (int)$_amount;
+ $line->unitPrice = (object)[
+ 'value' => number_format($unitPrice, 2, '.', ''),
+ 'currency' => $order->Waehrung->cISO,
+ ];
+ $line->totalAmount = (object)[
+ 'value' => number_format($totalAmount, 2, '.', ''),
+ 'currency' => $order->Waehrung->cISO,
+ ];
+ $line->vatRate = "{$oPosition->fMwSt}";
+
+ $line->vatAmount = (object)[
+ 'value' => number_format($vatAmount, 2, '.', ''),
+ 'currency' => $order->Waehrung->cISO,
+ ];
+
+ switch ((int)$oPosition->nPosTyp) {
+ case (int)C_WARENKORBPOS_TYP_GRATISGESCHENK:
+ case (int)C_WARENKORBPOS_TYP_ARTIKEL:
+ $line->type = OrderLineType::TYPE_PHYSICAL;
+ $line->sku = utf8_encode($oPosition->cArtNr);
+ break;
+ case (int)C_WARENKORBPOS_TYP_VERSANDPOS:
+ $line->type = OrderLineType::TYPE_SHIPPING_FEE;
+ break;
+ case (int)C_WARENKORBPOS_TYP_VERPACKUNG:
+ case (int)C_WARENKORBPOS_TYP_VERSANDZUSCHLAG:
+ case (int)C_WARENKORBPOS_TYP_ZAHLUNGSART:
+ case (int)C_WARENKORBPOS_TYP_VERSAND_ARTIKELABHAENGIG:
+ case (int)C_WARENKORBPOS_TYP_TRUSTEDSHOPS:
+ $line->type = OrderLineType::TYPE_SURCHARGE;
+ break;
+ case (int)C_WARENKORBPOS_TYP_GUTSCHEIN:
+ case (int)C_WARENKORBPOS_TYP_KUPON:
+ case (int)C_WARENKORBPOS_TYP_NEUKUNDENKUPON:
+ $line->type = OrderLineType::TYPE_DISCOUNT;
+ break;
+ }
+ if (isset($line->type)) {
+ $data['lines'][] = $line;
+ }
+ }
+
+ if ((int)$order->GuthabenNutzen === 1 && $order->fGuthaben < 0) {
+ $line = new stdClass();
+ $line->type = OrderLineType::TYPE_STORE_CREDIT;
+ $line->name = 'Guthaben';
+ $line->quantity = 1;
+ $line->unitPrice = (object)[
+ 'value' => number_format($order->Waehrung->fFaktor * $order->fGuthaben, 2, '.', ''),
+ 'currency' => $order->Waehrung->cISO,
+ ];
+ $line->totalAmount = (object)[
+ 'value' => number_format($order->Waehrung->fFaktor * $order->fGuthaben, 2, '.', ''),
+ 'currency' => $order->Waehrung->cISO,
+ ];
+ $line->vatRate = "0.00";
+ $line->vatAmount = (object)[
+ 'value' => number_format(0, 2, '.', ''),
+ 'currency' => $order->Waehrung->cISO,
+ ];
+ $data['lines'][] = $line;
+ }
+
+ // RUNDUNGSAUSGLEICH
+ $sum = .0;
+ foreach ($data['lines'] as $line) {
+ $sum += (float)$line->totalAmount->value;
+ }
+ if (abs($sum - (float)$data['amount']->value) > 0) {
+ $diff = (round((float)$data['amount']->value - $sum, 2));
+ if ($diff !== 0) {
+ $line = new stdClass();
+ $line->type = $diff > 0 ? OrderLineType::TYPE_SURCHARGE : OrderLineType::TYPE_DISCOUNT;
+ $line->name = 'Rundungsausgleich';
+ $line->quantity = 1;
+ $line->unitPrice = (object)[
+ 'value' => number_format($diff, 2, '.', ''),
+ 'currency' => $order->Waehrung->cISO,
+ ];
+ $line->totalAmount = (object)[
+ 'value' => number_format($diff, 2, '.', ''),
+ 'currency' => $order->Waehrung->cISO,
+ ];
+ $line->vatRate = "0.00";
+ $line->vatAmount = (object)[
+ 'value' => number_format(0, 2, '.', ''),
+ 'currency' => $order->Waehrung->cISO,
+ ];
+ $data['lines'][] = $line;
+ }
+ }
+ return $data;
+ }
+
+ public static function getLocale($cISOSprache, $country = null)
+ {
+ switch ($cISOSprache) {
+ case "ger":
+ if ($country === "AT") {
+ return "de_AT";
+ }
+ if ($country === "CH") {
+ return "de_CH";
+ }
+ return "de_DE";
+ case "fre":
+ if ($country === "BE") {
+ return "fr_BE";
+ }
+ return "fr_FR";
+ case "dut":
+ if ($country === "BE") {
+ return "nl_BE";
+ }
+ return "nl_NL";
+ case "spa":
+ return "es_ES";
+ case "ita":
+ return "it_IT";
+ case "pol":
+ return "pl_PL";
+ case "hun":
+ return "hu_HU";
+ case "por":
+ return "pt_PT";
+ case "nor":
+ return "nb_NO";
+ case "swe":
+ return "sv_SE";
+ case "fin":
+ return "fi_FI";
+ case "dan":
+ return "da_DK";
+ case "ice":
+ return "is_IS";
+ default:
+ return "en_US";
+ }
+ }
+
+ public function optionaleRundung($gesamtsumme)
+ {
+ $conf = Shop::getSettings([CONF_KAUFABWICKLUNG]);
+ if (isset($conf['kaufabwicklung']['bestellabschluss_runden5']) && (int)$conf['kaufabwicklung']['bestellabschluss_runden5'] === 1) {
+ $waehrung = isset($_SESSION['Waehrung']) ? $_SESSION['Waehrung'] : null;
+ if ($waehrung === null || !isset($waehrung->kWaehrung)) {
+ $waehrung = Shop::DB()->select('twaehrung', 'cStandard', 'Y');
+ }
+ $faktor = $waehrung->fFaktor;
+ $gesamtsumme *= $faktor;
+
+ // simplification. see https://de.wikipedia.org/wiki/Rundung#Rappenrundung
+ $gesamtsumme = round($gesamtsumme * 20) / 20;
+ $gesamtsumme /= $faktor;
+ }
+
+ return $gesamtsumme;
+ }
+
+ public static function getMollieCustomerId($kKunde)
+ {
+ //if ($row = Shop::DB()->select('xplugin_ws_mollie_kunde', 'kKunde', (int)$kKunde)) {
+ // return $row->customerId;
+ //}
+ return false;
+ }
+
+ public function updateHash($hash, $orderID)
+ {
+ $hash = trim($hash, '_');
+ $_upd = new stdClass();
+ $_upd->cNotifyID = $orderID;
+ return Shop::DB()->update('tzahlungsession', 'cZahlungsID', $hash, $_upd);
+ }
+
+ /**
+ * @param Bestellung $order
+ * @param string $hash
+ * @param array $args
+ */
+ public function handleNotification($order, $hash, $args)
+ {
+
+ $logData = '#' . $order->kBestellung . "§" . $order->cBestellNr;
+ $this->doLog('JTLMollie::handleNotification' . print_r([$hash, $args], 1) . ' ', $logData, LOGLEVEL_DEBUG);
+
+ try {
+ $oMolliePayment = self::API()->orders->get($args['id'], ['embed' => 'payments']);
+ Mollie::handleOrder($oMolliePayment, $order->kBestellung);
+ } catch (Exception $e) {
+ $this->doLog('JTLMollie::handleNotification: ' . $e->getMessage(), $logData);
+ }
+ }
+
+ /**
+ * @param Bestellung $order
+ * @param string $hash
+ * @param array $args
+ *
+ * @return boolean, true, if $order should be finalized
+ */
+ public function finalizeOrder($order, $hash, $args)
+ {
+ $result = false;
+ try {
+ if ($oZahlungSession = self::getZahlungSession(md5($hash))) {
+ if ((int)$oZahlungSession->kBestellung <= 0) {
+
+ $logData = '$' . $args['id'];
+ $GLOBALS['mollie_notify_lock'] = new \ws_mollie\ExclusiveLock('mollie_' . $args['id'], PFAD_ROOT . PFAD_COMPILEDIR);
+ if ($GLOBALS['mollie_notify_lock']->lock()) {
+ $this->doLog("JTLMollie::finalizeOrder::locked ({$args['id']})", $logData, LOGLEVEL_DEBUG);
+ } else {
+ $this->doLog("JTLMollie::finalizeOrder::locked failed ({$args['id']})", $logData, LOGLEVEL_ERROR);
+ Shop::DB()->executeQueryPrepared("UPDATE xplugin_ws_mollie_payments SET bLockTimeout = 1 WHERE kID = :kID;", [
+ ':kID' => $args['id']
+ ], 3);
+ return false;
+ }
+
+ $oOrder = self::API()->orders->get($args['id'], ['embed' => 'payments']);
+ $result = in_array($oOrder->status, [OrderStatus::STATUS_PAID, OrderStatus::STATUS_AUTHORIZED, OrderStatus::STATUS_PENDING, OrderStatus::STATUS_COMPLETED]);
+ $this->doLog('JTLMollie::finalizeOrder (' . ($result ? 'true' : 'false') . ')' . print_r([$hash, $args, $oOrder], 1) . ' ', $logData, LOGLEVEL_DEBUG);
+ //Payment::updateFromPayment($oMolliePayment, $order->kBestellung);
+ }
+ }
+ } catch (Exception $e) {
+ $this->doLog('JTLMollie::finalizeOrder: ' . $e->getMessage(), "#" . $hash);
+ }
+ return $result;
+ }
+
+ public static function getZahlungSession($hash)
+ {
+ return Shop::DB()->executeQueryPrepared("SELECT * FROM tzahlungsession WHERE MD5(cZahlungsID) = :cZahlungsID", [':cZahlungsID' => trim($hash, '_')], 1);
+ }
+
+ /**
+ * @return bool
+ */
+ public function canPayAgain()
+ {
+ return true;
+ }
+
+ /**
+ * determines, if the payment method can be selected in the checkout process
+ *
+ * @return bool
+ */
+ public function isSelectable()
+ {
+
+ if (array_key_exists('mollieDeleteToken', $_REQUEST) && (int)$_REQUEST['mollieDeleteToken'] === 1) {
+ unset($_SESSION['mollieCardToken']);
+ unset($_SESSION['mollieCardTokenTS']);
+ }
+
+ /** @var Warenkorb $wk */
+ $wk = $_SESSION['Warenkorb'];
+ if (Helper::getSetting("supportQ") !== 'Y') {
+ // Rationale Stückzahlen vorhanden?
+ foreach ($wk->PositionenArr as $oPosition) {
+ if ((int)$oPosition->nPosTyp === (int)C_WARENKORBPOS_TYP_ARTIKEL && $oPosition->Artikel && $oPosition->Artikel->cTeilbar === 'Y'
+ && fmod($oPosition->nAnzahl, 1) !== 0.0) {
+ return false;
+ }
+ }
+ }
+
+ $locale = self::getLocale($_SESSION['cISOSprache'], $_SESSION['Kunde']->cLand);
+ if (static::MOLLIE_METHOD !== '') {
+ try {
+ $amount = $wk->gibGesamtsummeWaren(true) * $_SESSION['Waehrung']->fFaktor;
+ if ($amount <= 0) {
+ $amount = 0.01;
+ }
+ $method = self::PossiblePaymentMethods(static::MOLLIE_METHOD, $locale, $_SESSION['Kunde']->cLand, $_SESSION['Waehrung']->cISO, $amount);
+ if ($method !== null) {
+
+ if ((int)$this->duringCheckout === 1 && !static::ALLOW_PAYMENT_BEFORE_ORDER) {
+ $this->doLog(static::MOLLIE_METHOD . " cannot be used for payment before order.");
+ return false;
+ }
+
+ $this->updatePaymentMethod($_SESSION['cISOSprache'], $method);
+ $this->cBild = $method->image->size2x;
+ return true;
+ }
+ return false;
+ } catch (Exception $e) {
+ $this->doLog('Method ' . static::MOLLIE_METHOD . ' not selectable:' . $e->getMessage());
+ return false;
+ }
+ } else if ((int)$this->duringCheckout === 0 && static::MOLLIE_METHOD === '') {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * @param $method
+ * @param $locale
+ * @param $billingCountry
+ * @param $currency
+ * @param $amount
+ * @return mixed|null
+ * @throws ApiException
+ * @throws IncompatiblePlatform
+ */
+ protected static function PossiblePaymentMethods($method, $locale, $billingCountry, $currency, $amount)
+ {
+ $key = md5(serialize([$locale, $billingCountry, $amount, $currency]));
+ if (!array_key_exists($key, self::$_possiblePaymentMethods)) {
+ self::$_possiblePaymentMethods[$key] = self::API()->methods->allActive(['amount' => ['currency' => $currency, 'value' => number_format($amount, 2, '.', '')], 'billingCountry' => $_SESSION['Kunde']->cLand, 'locale' => $locale, 'includeWallets' => 'applepay', 'include' => 'pricing,issuers', 'resource' => 'orders']);
+ }
+
+ if ($method !== null) {
+ foreach (self::$_possiblePaymentMethods[$key] as $m) {
+ if ($m->id === $method) {
+ return $m;
+ }
+ }
+ return null;
+ }
+ return self::$_possiblePaymentMethods[$key];
+ }
+
+ /**
+ * @param $cISOSprache
+ * @param $method
+ */
+ protected function updatePaymentMethod($cISOSprache, $method)
+ {
+ if (Helper::getSetting('paymentmethod_sync') === 'N') {
+ return;
+ }
+ $size = Helper::getSetting('paymentmethod_sync');
+ if ((!isset($this->cBild) || $this->cBild === '') && isset($method->image->$size)) {
+ Shop::DB()->executeQueryPrepared("UPDATE tzahlungsart SET cBild = :cBild WHERE cModulId = :cModulId", [':cBild' => $method->image->$size, ':cModulId' => $this->cModulId], 3);
+ }
+ if ($za = Shop::DB()->executeQueryPrepared('SELECT kZahlungsart FROM tzahlungsart WHERE cModulID = :cModulID', [':cModulID' => $this->moduleID], 1)) {
+ Shop::DB()->executeQueryPrepared("INSERT INTO tzahlungsartsprache (kZahlungsart, cISOSprache, cName, cGebuehrname, cHinweisText) VALUES (:kZahlungsart, :cISOSprache, :cName, :cGebuehrname, :cHinweisText) ON DUPLICATE KEY UPDATE cName = IF(cName = '',:cName1,cName), cHinweisTextShop = IF(cHinweisTextShop = '' || cHinweisTextShop IS NULL,:cHinweisTextShop,cHinweisTextShop);", [
+ ':kZahlungsart' => (int)$za->kZahlungsart,
+ ':cISOSprache' => $cISOSprache,
+ ':cName' => utf8_decode($method->description),
+ ':cGebuehrname' => '',
+ ':cHinweisText' => '',
+ ':cHinweisTextShop' => utf8_decode($method->description),
+ 'cName1' => $method->description,
+ ], 3);
+ }
+ }
+
+ /**
+ * @param array $args_arr
+ * @return bool
+ */
+ public function isValidIntern($args_arr = [])
+ {
+ if (Helper::getSetting("api_key")) {
+ return true;
+ }
+ $this->doLog("isValdid failed: init failed or no API Key given. Try clear the Cache.");
+ return false;
+ }
+}
diff --git a/version/109/paymentmethod/JTLMollieApplePay.php b/version/109/paymentmethod/JTLMollieApplePay.php
new file mode 100644
index 0000000..ecf20a8
--- /dev/null
+++ b/version/109/paymentmethod/JTLMollieApplePay.php
@@ -0,0 +1,8 @@
+ time()
+ && array_key_exists('mollieCardToken', $_SESSION) && trim($_SESSION['mollieCardToken']) !== '') {
+ return true;
+ }
+
+ unset($_SESSION['mollieCardToken']);
+ unset($_SESSION['mollieCardTokenTS']);
+
+ if (array_key_exists('cardToken', $aPost_arr) && trim($aPost_arr['cardToken'])) {
+ $_SESSION['mollieCardToken'] = trim($aPost_arr['cardToken']);
+ $_SESSION['mollieCardTokenTS'] = time() + 3600;
+ return true;
+ }
+
+ Shop::Smarty()->assign('profileId', $profileId)
+ ->assign('errorMessage', json_encode(utf8_encode(Helper::oPlugin()->oPluginSprachvariableAssoc_arr['mcErrorMessage'])))
+ ->assign('locale', self::getLocale($_SESSION['cISOSprache'], $_SESSION['Kunde']->cLand))
+ ->assign('testmode', strpos(trim(Helper::getSetting('api_key')), 'test_') === 0)
+ ->assign('mollieLang', Helper::oPlugin()->oPluginSprachvariableAssoc_arr)
+ ->assign('trustBadge', Helper::getSetting('loadTrust') === 'Y' ? Helper::oPlugin()->cFrontendPfadURLSSL . 'img/trust_' . $_SESSION['cISOSprache'] . '.png' : false);
+
+ return false;
+ }
+
+
+}
diff --git a/version/109/paymentmethod/JTLMollieDirectDebit.php b/version/109/paymentmethod/JTLMollieDirectDebit.php
new file mode 100644
index 0000000..ce0441d
--- /dev/null
+++ b/version/109/paymentmethod/JTLMollieDirectDebit.php
@@ -0,0 +1,8 @@
+
+ {$oMollieException->getMessage()}
+
+{/if}
\ No newline at end of file
diff --git a/version/109/paymentmethod/tpl/mollieComponents.tpl b/version/109/paymentmethod/tpl/mollieComponents.tpl
new file mode 100644
index 0000000..825bc9f
--- /dev/null
+++ b/version/109/paymentmethod/tpl/mollieComponents.tpl
@@ -0,0 +1,103 @@
+{$mollieLang.cctitle}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/version/109/sql/109.sql b/version/109/sql/109.sql
new file mode 100644
index 0000000..41cda01
--- /dev/null
+++ b/version/109/sql/109.sql
@@ -0,0 +1,2 @@
+ALTER TABLE `xplugin_ws_mollie_payments`
+ ADD `bLockTimeout` tinyint(1) NOT NULL;
\ No newline at end of file
diff --git a/version/109/tpl/_alerts.tpl b/version/109/tpl/_alerts.tpl
new file mode 100644
index 0000000..5279fa3
--- /dev/null
+++ b/version/109/tpl/_alerts.tpl
@@ -0,0 +1,10 @@
+{if $alerts}
+ {assign var=alert_arr value=$alerts|get_object_vars}
+ {if $alert_arr|count}
+
+ {foreach from=$alert_arr item=alert key=id}
+
{$alert}
+ {/foreach}
+
+ {/if}
+{/if}