From b86d561f069416744935f74698fd6608eb03b483 Mon Sep 17 00:00:00 2001 From: "dash.bar" Date: Tue, 4 Dec 2018 11:18:07 +0100 Subject: [PATCH 001/280] Init --- .gitignore | 2 + composer.json | 15 + info.xml | 26 ++ version/100/adminmenu/custom.php.dist | 15 + version/100/adminmenu/info.php | 43 +++ version/100/class/Foo/Base.php.dist | 19 ++ version/100/class/Helper.php | 414 ++++++++++++++++++++++++++ version/100/frontend/hook.php.dist | 15 + 8 files changed, 549 insertions(+) create mode 100644 .gitignore create mode 100644 composer.json create mode 100644 info.xml create mode 100644 version/100/adminmenu/custom.php.dist create mode 100644 version/100/adminmenu/info.php create mode 100644 version/100/class/Foo/Base.php.dist create mode 100644 version/100/class/Helper.php create mode 100644 version/100/frontend/hook.php.dist diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d1502b0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +vendor/ +composer.lock diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..87b014b --- /dev/null +++ b/composer.json @@ -0,0 +1,15 @@ +{ + "name": "webstollen/ws_mollie", + "description": "mollie", + "type": "project", + "require": { + "roave/security-advisories": "dev-master" + }, + "license": "Proprietary", + "authors": [ + { + "name": "Proske", + "email": "proske@webstollen.de" + } + ] +} diff --git a/info.xml b/info.xml new file mode 100644 index 0000000..b6cf739 --- /dev/null +++ b/info.xml @@ -0,0 +1,26 @@ + + + mollie + WebStollen Base Plugin + WebStollen + http://www.webstollen.de/ + 102 + ws_mollie + + + 2017-12-18 + + + + + + + Info + info.php + + + + 404 + diff --git a/version/100/adminmenu/custom.php.dist b/version/100/adminmenu/custom.php.dist new file mode 100644 index 0000000..d34226d --- /dev/null +++ b/version/100/adminmenu/custom.php.dist @@ -0,0 +1,15 @@ + \ws_mollie\Helper::oPlugin()->cPluginID, + 'v' => \ws_mollie\Helper::oPlugin()->nVersion, + 's' => defined('APPLICATION_VERSION') ? APPLICATION_VERSION : JTL_VERSION, + 'd' => \ws_mollie\Helper::getDomain(), + 'php' => PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION . '.' . PHP_RELEASE_VERSION, + ]); + + echo ""; + echo "
" . + "
" . + " " . + " Lizenz Informationen" . + ' ' . + '
' . + "
" . + " " . + " Update Informationen" . + ' ' . + '
' . + "
" . + " " . + " Plugin informationen" . + ' ' . + '
' . + '
'; + + if (\ws_mollie\Helper::_licCache()->disabled) { + echo "
Die Pluginlizenz und das Plugin wurden deaktiviert. " + . "" + . "Klicke hier um die Lizenz erneut zu überprüfen.
"; + } + +} catch (Exception $e) { + echo "
Fehler: {$e->getMessage()}
"; + \ws_mollie\Helper::logExc($e); +} \ No newline at end of file diff --git a/version/100/class/Foo/Base.php.dist b/version/100/class/Foo/Base.php.dist new file mode 100644 index 0000000..6f3b6a5 --- /dev/null +++ b/version/100/class/Foo/Base.php.dist @@ -0,0 +1,19 @@ +assign('defaultTabbertab', self::getAdminmenu('Info')); + } + + + return self::$_autoload && self::$_licence; + } + + /** + * @param $oL + * @return mixed + */ + private static function _licActivate($oL) + { + $oL->nextCheck = 0; + $oL->fails = 0; + $oL->disabled = 0; + self::_licSave($oL); + return $oL; + } + + /** + * @param $oL + * @param bool $checksum + * @return mixed + */ + private static function _licSave($oL, $checksum = false) + { + self::setSetting('lic_validUntil', $oL->validUntil); + self::setSetting('lic_nextCheck', $oL->nextCheck); + self::setSetting('lic_test', $oL->test); + if ($checksum === true) { + self::setSetting('lic_checkSum', base64_encode(sha1($oL->validUntil . $oL->nextCheck . $oL->test . $oL->disabled . $oL->fails . __NAMESPACE__, true))); + } + self::setSetting('lic_disabled', (int)$oL->disabled); + self::setSetting('lic_fails', $oL->fails); + return $oL; + } + + /** + * 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; + } + + /** + * @param $oL + * @return bool|string + */ + private static function _licValid($oL) + { + if ($nextCheck = strtotime($oL->nextCheck)) { + if ($nextCheck > time()) { + if ($validUntil = strtotime($oL->validUntil)) { + if ($validUntil > time() || (int)$oL->test === 0) { + return md5(self::$_tmpLicence); + } + } + } + } + return false; + + } + + /** + * @return \stdClass + */ + public static function _licCache() + { + $oL = new \stdClass(); + $oL->validUntil = self::getSetting('lic_validUntil'); + $oL->nextCheck = self::getSetting('lic_nextCheck'); + $oL->test = self::getSetting('lic_test'); + $oL->checksum = self::getSetting('lic_checkSum'); + $oL->disabled = self::getSetting('lic_disabled') === null ? 0 : (int)self::getSetting('lic_disabled'); + $oL->fails = self::getSetting('lic_fails') ?: 0; + return $oL; + } + + /** + * 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; + } + + /** + * @param $x + * @return bool|string + */ + private static function licCheck($x) + { + if ($x !== md5(self::$_tmpLicence)) { + return false; + } + $oL = self::_licCache(); + if (self::_licCRC($oL) === true) { + // CRC OK? + if (self::_licValid($oL) === md5(self::$_tmpLicence)) { + return md5(self::$_tmpLicence); + } + } + if ($oL->disabled === 0) { + $oL = self::_licLive($oL); + + if ($oL->disabled === 0 && self::_licValid($oL) === md5(self::$_tmpLicence)) { + return md5(self::$_tmpLicence); + } + } + return false; + + } + + /** + * @param $oL + * @return bool + */ + private static function _licCRC($oL) + { + $crc_valid = false; + if ($checksum = base64_encode(sha1($oL->validUntil . $oL->nextCheck . $oL->test . $oL->disabled . $oL->fails . __NAMESPACE__, true))) { + $crc_valid = $checksum == $oL->checksum; + } + return $oL->checksum && $crc_valid; + } + + /** + * @param $oL + * @return mixed + */ + private static function _licLive($oL) + { + try { + + if (!function_exists('curl_init')) { + throw new \Exception(__NAMESPACE__ . ': cURL needs to be installed!'); + } + + $urlShop = self::getDomain(); + + $params = [ + 'domain' => $urlShop, + 'plugin_version' => (int)self::oPlugin()->nVersion, + 'plugin_id' => self::oPlugin()->cPluginID, + 'email' => self::_masterMail(), + 'shop_version' => (string)(defined('APPLICATION_VERSION') ? APPLICATION_VERSION : JTL_VERSION), + 'shop_build' => defined('APPLICATION_BUILD_SHA') ? APPLICATION_BUILD_SHA : '', + 'php_version' => PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION . '.' . PHP_RELEASE_VERSION, + 'php_extra_version' => PHP_EXTRA_VERSION, + 'php_os' => PHP_OS, + 'server' => array_key_exists('SERVER_SOFTWARE', $_SERVER) ? $_SERVER['SERVER_SOFTWARE'] : '', + ]; + $curl = curl_init('https://lic.dash.bar'); + @curl_setopt($curl, CURLOPT_POST, 1); + @curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($params)); // http_build_query($params, '', '&')); + @curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 3); + @curl_setopt($curl, CURLOPT_TIMEOUT, 3); + @curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + @curl_setopt($curl, CURLOPT_HEADER, 0); + @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 licence info: ' . $statusCode); + } + /** @noinspection UnserializeExploitsInspection */ + if ($response = json_decode($data)) { + + $checksum = md5(base64_encode($response->data->validUntil . $response->data->nextCheck . ($response->data->testLicence ? 'Y' : 'N'))); + + if (!$response || !isset($response->data) || $response->data === false || !isset($response->checksum) || $response->checksum !== $checksum) { + throw new \Exception(__NAMESPACE__ . ': Invalid licence info: ' . print_r($response, 1)); + } + $oLL = $response->data; + if (self::isPresent($oLL->validUntil)) { + $oL->validUntil = date('Y-m-d', $oLL->validUntil); + } + if (self::isPresent($oLL->nextCheck)) { + $oL->nextCheck = date('Y-m-d', $oLL->nextCheck); + } + if (self::isPresent($oLL->testLicence)) { + $oL->test = $oLL->testLicence ? 1 : 0; + } + $oL->fails = 0; + self::_licSave($oL, true); + + } else { + throw new \Exception(__NAMESPACE__ . ': Could not decode licence info: ' . print_r($response, 1)); + } + + } catch (\Exception $e) { + $oL->disabled = (++$oL->fails) >= 3 ? 1 : 0; + $oL->nextCheck = date("Y-m-d", strtotime("+1 DAY")); + $oL->validUntil = date("Y-m-d", strtotime("+1 DAY"));; + + self::logExc($e, false); + self::_licSave($oL, true); + } + return $oL; + } + + + /** + * @param $val + * @return bool + * @throws \Exception + */ + private static function ispresent($val) + { + if (isset($val)) { + return true; + } else { + throw new \Exception(__NAMESPACE__ . ': Could ned find value from license server ' . print_r($val, 1)); + } + } + + /** + * 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); + } + + /** + * @return mixed + */ + private static function _masterMail() + { + $settings = \Shop::getSettings(array(CONF_EMAILS)); + return $settings['emails']['email_master_absender']; + } + + /** + * @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/100/frontend/hook.php.dist b/version/100/frontend/hook.php.dist new file mode 100644 index 0000000..ddeee70 --- /dev/null +++ b/version/100/frontend/hook.php.dist @@ -0,0 +1,15 @@ + Date: Mon, 10 Dec 2018 15:48:30 +0100 Subject: [PATCH 002/280] plugin setup #3 --- composer.json | 5 +- info.xml | 36 +++- version/100/paymentmethod/Mollie.php | 158 ++++++++++++++++++ .../paymentmethod/tpl/bestellabschluss.tpl | 5 + 4 files changed, 198 insertions(+), 6 deletions(-) create mode 100644 version/100/paymentmethod/Mollie.php create mode 100644 version/100/paymentmethod/tpl/bestellabschluss.tpl diff --git a/composer.json b/composer.json index 87b014b..5a9036b 100644 --- a/composer.json +++ b/composer.json @@ -3,12 +3,13 @@ "description": "mollie", "type": "project", "require": { - "roave/security-advisories": "dev-master" + "roave/security-advisories": "dev-master", + "mollie/mollie-api-php": "^2.2" }, "license": "Proprietary", "authors": [ { - "name": "Proske", + "name": "C. Proske", "email": "proske@webstollen.de" } ] diff --git a/info.xml b/info.xml index b6cf739..3bdc59a 100644 --- a/info.xml +++ b/info.xml @@ -1,7 +1,7 @@ mollie - WebStollen Base Plugin + Zahlungsart plugin für mollie.com WebStollen http://www.webstollen.de/ 102 @@ -12,15 +12,43 @@ - + + API Key: + Füge hier deinen mollie API Key ein + api_key + + + + Info info.php + + + + mollie + 1 + 0 + mollie.com + OTHER + 0 + 1 + 0 + Mollie.php + Mollie + tpl/bestellabschluss.tpl + + mollie + mollie + Bezahlen Sie bequem mit verschiedenen Zahlungsmethoden. + + + - 404 + 405 diff --git a/version/100/paymentmethod/Mollie.php b/version/100/paymentmethod/Mollie.php new file mode 100644 index 0000000..908c32b --- /dev/null +++ b/version/100/paymentmethod/Mollie.php @@ -0,0 +1,158 @@ +setApiKey(\ws_mollie\Helper::getSetting('api_key')); + } + return self::$_mollie; + } + + /** + * @return \ws_mollie\Helper + */ + public static function Helper() + { + if (self::$_helper === null) { + self::$_helper = new ws_mollie\Helper(); + } + return self::$_helper; + } + + /** + * Prepares everything so that the Customer can start the Payment Process. + * Tells Template Engine. + * + * @param Bestellung $order + */ + public function preparePaymentProcess($order) + { + $data = [ + 'amount' => [ + 'currency' => $order->Waehrung->cISO, + 'value' => number_format($order->fGesamtsumme, 2, '.', ''), + ], + 'description' => 'Ihre Bestellung bei XXX: ' . $order->cBestellNr, + 'redirectUrl' => $this->getReturnURL($order), + 'webhookUrl' => $this->getNotificationURL($this->generateHash($order)) + ]; + try { + $oMolliePayment = static::API()->payments->create($data); + $this->doLog('Mollie Create Payment Redirect: ' . $oMolliePayment->getCheckoutUrl()); + Shop::Smarty()->assign('oMolliePayment', $oMolliePayment); + header('Location: ' . $oMolliePayment->getCheckoutUrl()); + exit(); + } catch (\Mollie\Api\Exceptions\ApiException $e) { + Shop::Smarty()->assign('oMollieException', $e); + $this->doLog("Create Payment Error: " . $e->getMessage() . '
>
' . print_r($data, 1) . '
'); + } + } + + /** + * @param Bestellung $order + * @param string $hash + * @param array $args + */ + public function handleNotification($order, $hash, $args) + { + + } + + /** + * @param Bestellung $order + * @param string $hash + * @param array $args + * + * @return true, if $order should be finalized + */ + public function finalizeOrder($order, $hash, $args) + { + return false; + } + + /** + * @return bool + */ + public function canPayAgain() + { + return true; + } + + /** + * determines, if the payment method can be selected in the checkout process + * + * @return bool + */ + public function isSelectable() + { + return true; + } + + /** + * + * @param object $customer + * @param Warenkorb $cart + * @return bool - true, if $customer with $cart may use Payment Method + */ + public function isValid($customer, $cart) + { + if (\ws_mollie\Helper::init() && \ws_mollie\Helper::getSetting("api_key")) { + return true; + } + $this->doLog("isValdid failed: init failed or no API Key given. Try clear the Cache."); + return false; + } + + /** + * @param array $args_arr + * @return bool + */ + public function isValidIntern($args_arr = []) + { + if (\ws_mollie\Helper::init() && \ws_mollie\Helper::getSetting("api_key")) { + return true; + } + $this->doLog("isValdid failed: init failed or no API Key given. Try clear the Cache."); + return false; + } + + /** + * @return bool + */ + public function redirectOnCancel() + { + return parent::redirectOnCancel(); // TODO: Change the autogenerated stub + } +} \ No newline at end of file diff --git a/version/100/paymentmethod/tpl/bestellabschluss.tpl b/version/100/paymentmethod/tpl/bestellabschluss.tpl new file mode 100644 index 0000000..f7680f0 --- /dev/null +++ b/version/100/paymentmethod/tpl/bestellabschluss.tpl @@ -0,0 +1,5 @@ +{if isset($oMollieException)} +
+ {$oMollieException->getMessage()} +
+{/if} \ No newline at end of file From 1d5d3e89f0ca588ce1a44147be215f7986345600 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Wed, 12 Dec 2018 09:46:22 +0100 Subject: [PATCH 003/280] return after payment --- info.xml | 180 +++++++++++++++++- version/100/class/Foo/Base.php.dist | 19 -- version/100/class/Model/AbstractModel.php | 7 + version/100/class/Model/Payment.php | 29 +++ version/100/frontend/131_globalinclude.php | 25 +++ .../{Mollie.php => JTLMollie.php} | 61 +++++- .../100/paymentmethod/JTLMollieBancontact.php | 9 + .../paymentmethod/JTLMollieBanktransfer.php | 9 + .../100/paymentmethod/JTLMollieBelfius.php | 9 + .../100/paymentmethod/JTLMollieBitcoin.php | 9 + .../100/paymentmethod/JTLMollieCreditCard.php | 9 + .../paymentmethod/JTLMollieDirectDebit.php | 9 + version/100/paymentmethod/JTLMollieEPS.php | 9 + .../100/paymentmethod/JTLMollieGiftcard.php | 9 + .../100/paymentmethod/JTLMollieGiropay.php | 9 + version/100/sql/100.sql | 14 ++ 16 files changed, 389 insertions(+), 27 deletions(-) delete mode 100644 version/100/class/Foo/Base.php.dist create mode 100644 version/100/class/Model/AbstractModel.php create mode 100644 version/100/class/Model/Payment.php create mode 100644 version/100/frontend/131_globalinclude.php rename version/100/paymentmethod/{Mollie.php => JTLMollie.php} (54%) create mode 100644 version/100/paymentmethod/JTLMollieBancontact.php create mode 100644 version/100/paymentmethod/JTLMollieBanktransfer.php create mode 100644 version/100/paymentmethod/JTLMollieBelfius.php create mode 100644 version/100/paymentmethod/JTLMollieBitcoin.php create mode 100644 version/100/paymentmethod/JTLMollieCreditCard.php create mode 100644 version/100/paymentmethod/JTLMollieDirectDebit.php create mode 100644 version/100/paymentmethod/JTLMollieEPS.php create mode 100644 version/100/paymentmethod/JTLMollieGiftcard.php create mode 100644 version/100/paymentmethod/JTLMollieGiropay.php create mode 100644 version/100/sql/100.sql diff --git a/info.xml b/info.xml index 3bdc59a..e1018bd 100644 --- a/info.xml +++ b/info.xml @@ -9,7 +9,11 @@ 2017-12-18 + 100.sql + + 131_globalinclude.php + @@ -39,8 +43,8 @@ 0 1 0 - Mollie.php - Mollie + JTLMollie.php + JTLMollie tpl/bestellabschluss.tpl mollie @@ -48,6 +52,178 @@ Bezahlen Sie bequem mit verschiedenen Zahlungsmethoden. + + + mollie Kreditkarte + 2 + 0 + mollie.com + OTHER + 0 + 1 + 0 + JTLMollieCreditCard.php + JTLMollieCreditCard + tpl/bestellabschluss.tpl + + mollie Kreditkarte + mollie + Bezahlen Sie bequem mit Kreditkarte. + + + + + mollie Bitcoin + 2 + 0 + mollie.com + OTHER + 0 + 1 + 0 + JTLMollieBitcoin.php + JTLMollieBitcoin + tpl/bestellabschluss.tpl + + mollie Bitcoin + mollie + Bezahlen Sie bequem mit Bitcoins. + + + + + mollie Bancontact + 2 + 0 + mollie.com + OTHER + 0 + 1 + 0 + JTLMollieBancontact.php + JTLMollieBancontact + tpl/bestellabschluss.tpl + + mollie Bancontact + mollie + Bezahlen Sie bequem mit Bancontact. + + + + + mollie Banktransfer + 2 + 0 + mollie.com + OTHER + 0 + 1 + 0 + JTLMollieBanktransfer.php + JTLMollieBanktransfer + tpl/bestellabschluss.tpl + + mollie SEPA Überweisung + mollie + Bezahlen Sie bequem mit SEPA Überweisung. + + + + + mollie Belfius + 2 + 0 + mollie.com + OTHER + 0 + 1 + 0 + JTLMollieBelfius.php + JTLMollieBelfius + tpl/bestellabschluss.tpl + + mollie SEPA Überweisung + mollie + Bezahlen Sie bequem mit Belfius. + + + + + mollie DirectDebit + 2 + 0 + mollie.com + OTHER + 0 + 1 + 0 + JTLMollieDirectDebit.php + JTLMollieDirectDebit + tpl/bestellabschluss.tpl + + mollie SEPA Lastschrift + mollie + Bezahlen Sie bequem mit SEPA Lastschrift. + + + + + mollie EPS + 2 + 0 + mollie.com + OTHER + 0 + 1 + 0 + JTLMollieEPS.php + JTLMollieEPS + tpl/bestellabschluss.tpl + + mollie EPS + mollie + Bezahlen Sie bequem mit EPS. + + + + + mollie Giftcard + 2 + 0 + mollie.com + OTHER + 0 + 1 + 0 + JTLMollieGiftcard.php + JTLMollieGiftcard + tpl/bestellabschluss.tpl + + mollie Gift cards + mollie + Bezahlen Sie bequem mit Gift cards. + + + + + mollie Giropay + 2 + 0 + mollie.com + OTHER + 0 + 1 + 0 + JTLMollieGiropay.php + JTLMollieGiropay + tpl/bestellabschluss.tpl + + mollie Giropay + mollie + Bezahlen Sie bequem mit Giropay. + + + 405 diff --git a/version/100/class/Foo/Base.php.dist b/version/100/class/Foo/Base.php.dist deleted file mode 100644 index 6f3b6a5..0000000 --- a/version/100/class/Foo/Base.php.dist +++ /dev/null @@ -1,19 +0,0 @@ -executeQueryPrepared('INSERT INTO ' . self::TABLE . ' (kID, kBestellung, cStatus, fAmount, cCurrency, cMethod, cHash, dCreatedAt, dPaidAt) VALUES (:kID, :kBestellung, :cStatus, :fAmount, :cCurrency, :cMethod, :cHash, :dCreatedAt, :dPaidAt) ' + .' ON DUPLICATE KEY UPDATE kBestellung = :kBestellung1, cStatus = :cStatus1, cMethod = :cMethod1, dPaidAt = :dPaidAt1', [ + ':kID' => $oMolliePayment->id, + ':kBestellung' => $kBestellung, + ':kBestellung1' => $kBestellung, + ':cStatus' => $oMolliePayment->status, + ':cStatus1' => $oMolliePayment->status, + ':fAmount' => $oMolliePayment->amount->value, + ':cCurrency' => $oMolliePayment->amount->currency, + ':cMethod' => $oMolliePayment->method, + ':cMethod1' => $oMolliePayment->method, + ':cHash' => $hash, + ':dCreatedAt' => $oMolliePayment->createdAt ? date('Y-m-d H:i:s', strtotime($oMolliePayment->createdAt)) : null, + ':dPaidAt' => $oMolliePayment->paidAt ? date('Y-m-d H:i:s', strtotime($oMolliePayment->paidAt)) : null, + ':dPaidAt1' => $oMolliePayment->paidAt ? date('Y-m-d H:i:s', strtotime($oMolliePayment->paidAt)) : null, + ], 3); + } +} \ No newline at end of file diff --git a/version/100/frontend/131_globalinclude.php b/version/100/frontend/131_globalinclude.php new file mode 100644 index 0000000..cd23d96 --- /dev/null +++ b/version/100/frontend/131_globalinclude.php @@ -0,0 +1,25 @@ +executeQueryPrepared("SELECT * FROM " . \ws_mollie\Model\Payment::TABLE . " WHERE cHash = :cHash", [':cHash' => $_REQUEST['mollie']], 1); + if((int)$payment->kBestellung){ + $bestellid = \Shop::DB()->executeQueryPrepared("SELECT * FROM tbestellid WHERE kBestellung = :kBestellung", [':kBestellung' => $payment->kBestellung], 1); + if($bestellid){ + header('Location: ' . SHop::getURL() . '/bestellabschluss.php?i='.$bestellid->cId); + exit(); + } + } + } +} catch (Exception $e) { + \ws_mollie\Helper::logExc($e); +} \ No newline at end of file diff --git a/version/100/paymentmethod/Mollie.php b/version/100/paymentmethod/JTLMollie.php similarity index 54% rename from version/100/paymentmethod/Mollie.php rename to version/100/paymentmethod/JTLMollie.php index 908c32b..516f6b1 100644 --- a/version/100/paymentmethod/Mollie.php +++ b/version/100/paymentmethod/JTLMollie.php @@ -8,7 +8,9 @@ require_once __DIR__ . '/../class/Helper.php'; -class Mollie extends PaymentMethod +use Mollie\Api\Types\PaymentStatus as MolliePaymentStatus; + +class JTLMollie extends PaymentMethod { const MOLLIE_METHOD = ""; @@ -59,18 +61,25 @@ public static function Helper() */ public function preparePaymentProcess($order) { + + $hash = $this->generateHash($order); $data = [ 'amount' => [ 'currency' => $order->Waehrung->cISO, - 'value' => number_format($order->fGesamtsumme, 2, '.', ''), + 'value' => number_format($order->fGesamtsummeKundenwaehrung, 2, '.', ''), ], 'description' => 'Ihre Bestellung bei XXX: ' . $order->cBestellNr, - 'redirectUrl' => $this->getReturnURL($order), - 'webhookUrl' => $this->getNotificationURL($this->generateHash($order)) + 'redirectUrl' => (int)$this->duringCheckout ? Shop::getURL() . '/bestellabschluss.php?mollie=' .md5($hash) : $this->getReturnURL($order), + 'webhookUrl' => $this->getNotificationURL($hash) ]; + if(static::MOLLIE_METHOD !== ''){ + $data['method'] = static::MOLLIE_METHOD; + } try { $oMolliePayment = static::API()->payments->create($data); - $this->doLog('Mollie Create Payment Redirect: ' . $oMolliePayment->getCheckoutUrl()); + $_SESSION['oMolliePayment'] = $oMolliePayment; + $this->doLog('Mollie Create Payment Redirect: ' . $oMolliePayment->getCheckoutUrl() . "
" . print_r($oMolliePayment,1) . "
", LOGLEVEL_DEBUG); + \ws_mollie\Model\Payment::updateFromPayment($oMolliePayment, $order->kBestellung, md5($hash)); Shop::Smarty()->assign('oMolliePayment', $oMolliePayment); header('Location: ' . $oMolliePayment->getCheckoutUrl()); exit(); @@ -87,7 +96,25 @@ public function preparePaymentProcess($order) */ public function handleNotification($order, $hash, $args) { - + \ws_mollie\Helper::autoload(); + try{ + $oMolliePayment = self::API()->payments->get($args['id']); + $this->doLog('Received Notification
' . print_r([$hash, $args, $oMolliePayment],1) . '
', LOGLEVEL_DEBUG); + + \ws_mollie\Model\Payment::updateFromPayment($oMolliePayment, $order->kBestellung); + + if($oMolliePayment->status === MolliePaymentStatus::STATUS_PAID){ + $oIncomingPayment = new stdClass(); + $oIncomingPayment->fBetrag = $order->fGesamtsummeKundenwaehrung; + $oIncomingPayment->cISO = $order->Waehrung->cISO; + $oIncomingPayment->chinweis = $oMolliePayment->id; + $this->addIncomingPayment($order, $oIncomingPayment); + $this->setOrderStatusToPaid($order); + } + + }catch(\Exception $e){ + $this->doLog($e->getMessage()); + } } /** @@ -99,6 +126,15 @@ public function handleNotification($order, $hash, $args) */ public function finalizeOrder($order, $hash, $args) { + try{ + \ws_mollie\Helper::autoload(); + $oMolliePayment = self::API()->payments->get($args['id']); + $this->doLog('Received Notification Finalize Order
' . print_r([$hash, $args, $oMolliePayment],1) . '
', LOGLEVEL_DEBUG); + \ws_mollie\Model\Payment::updateFromPayment($oMolliePayment, $order->kBestellung); + return !in_array([MolliePaymentStatus::STATUS_FAILED, MolliePaymentStatus::STATUS_CANCELED, MolliePaymentStatus::STATUS_EXPIRED, MolliePaymentStatus::STATUS_OPEN],$oMolliePayment->status); + }catch(\Exception $e){ + $this->doLog($e->getMessage()); + } return false; } @@ -117,6 +153,19 @@ public function canPayAgain() */ public function isSelectable() { + + if(static::MOLLIE_METHOD !== ''){ + try { + $method = self::API()->methods->get(static::MOLLIE_METHOD, ['locale' => 'de_DE', 'include' => 'pricing,issuers']); + \Shop::DB()->executeQueryPrepared("UPDATE tzahlungsart SET cBild = :cBild WHERE cModulId = :cModulId", [':cBild' => $method->image->size2x, ':cModulId' => $this->cModulId], 3); + $this->cBild = $method->image->size2x; + var_dump($method->issuers); + return true; + }catch(Exception $e){ + $this->doLog('Method ' . static::MOLLIE_METHOD . ' not selectable:' . $e->getMessage()); + return false; + } + } return true; } diff --git a/version/100/paymentmethod/JTLMollieBancontact.php b/version/100/paymentmethod/JTLMollieBancontact.php new file mode 100644 index 0000000..34910f3 --- /dev/null +++ b/version/100/paymentmethod/JTLMollieBancontact.php @@ -0,0 +1,9 @@ + Date: Wed, 12 Dec 2018 10:17:09 +0100 Subject: [PATCH 004/280] fix #3 --- info.xml | 153 ++++++++++++++++++ version/100/paymentmethod/JTLMollieIDEAL.php | 15 ++ .../100/paymentmethod/JTLMollieINGHomePay.php | 15 ++ version/100/paymentmethod/JTLMollieKBC.php | 15 ++ .../paymentmethod/JTLMollieKlarnaPayLater.php | 15 ++ .../paymentmethod/JTLMollieKlarnaSliceIt.php | 15 ++ version/100/paymentmethod/JTLMolliePayPal.php | 15 ++ .../paymentmethod/JTLMolliePaysafecard.php | 15 ++ version/100/paymentmethod/JTLMollieSofort.php | 15 ++ 9 files changed, 273 insertions(+) create mode 100644 version/100/paymentmethod/JTLMollieIDEAL.php create mode 100644 version/100/paymentmethod/JTLMollieINGHomePay.php create mode 100644 version/100/paymentmethod/JTLMollieKBC.php create mode 100644 version/100/paymentmethod/JTLMollieKlarnaPayLater.php create mode 100644 version/100/paymentmethod/JTLMollieKlarnaSliceIt.php create mode 100644 version/100/paymentmethod/JTLMolliePayPal.php create mode 100644 version/100/paymentmethod/JTLMolliePaysafecard.php create mode 100644 version/100/paymentmethod/JTLMollieSofort.php diff --git a/info.xml b/info.xml index e1018bd..4fe7135 100644 --- a/info.xml +++ b/info.xml @@ -223,6 +223,159 @@ Bezahlen Sie bequem mit Giropay. + + + mollie iDEAL + 2 + 0 + mollie.com + OTHER + 0 + 1 + 0 + JTLMollieIDEAL.php + JTLMollieIDEAL + tpl/bestellabschluss.tpl + + mollie Giropay + mollie + Bezahlen Sie bequem mit iDEAL. + + + + + mollie ING Home'Pay + 2 + 0 + mollie.com + OTHER + 0 + 1 + 0 + JTLMollieINGHomePay.php + JTLMollieINGHomePay + tpl/bestellabschluss.tpl + + mollie ING Home'Pay + mollie + Bezahlen Sie bequem mit ING Home'Pay. + + + + + mollie KBC + 2 + 0 + mollie.com + OTHER + 0 + 1 + 0 + JTLMollieKBC.php + JTLMollieKBC + tpl/bestellabschluss.tpl + + mollie KBC + mollie + Bezahlen Sie bequem mit KBC. + + + + + mollie PayPal + 2 + 0 + mollie.com + OTHER + 0 + 1 + 0 + JTLMolliePayPal.php + JTLMolliePayPal + tpl/bestellabschluss.tpl + + mollie PayPal + mollie + Bezahlen Sie bequem mit PayPal. + + + + + mollie paysafecard + 2 + 0 + mollie.com + OTHER + 0 + 1 + 0 + JTLMolliePaysafecard.php + JTLMolliePaysafecard + tpl/bestellabschluss.tpl + + mollie paysafecard + mollie + Bezahlen Sie bequem mit paysafecard. + + + + + mollie SOFORT + 2 + 0 + mollie.com + OTHER + 0 + 1 + 0 + JTLMollieSofort.php + JTLMollieSofort + tpl/bestellabschluss.tpl + + mollie SOFORT + mollie + Bezahlen Sie bequem mit SOFORT. + + + + + mollie Klarna Pay Later + 2 + 0 + mollie.com + OTHER + 0 + 1 + 0 + JTLMollieKlarnaPayLater.php + JTLMollieKlarnaPayLater + tpl/bestellabschluss.tpl + + mollie Klarna Pay Later + mollie + Bezahlen Sie bequem mit Klarna Pay Later. + + + + + mollie Klarna Slice It + 2 + 0 + mollie.com + OTHER + 0 + 1 + 0 + JTLMollieKlarnaSliceIt.php + JTLMollieKlarnaSliceIt + tpl/bestellabschluss.tpl + + mollie Klarna Slice It + mollie + Bezahlen Sie bequem mit Klarna Slice It. + + + diff --git a/version/100/paymentmethod/JTLMollieIDEAL.php b/version/100/paymentmethod/JTLMollieIDEAL.php new file mode 100644 index 0000000..7eb2072 --- /dev/null +++ b/version/100/paymentmethod/JTLMollieIDEAL.php @@ -0,0 +1,15 @@ + Date: Wed, 12 Dec 2018 15:51:04 +0100 Subject: [PATCH 005/280] #5 --- info.xml | 6 +- version/100/class/Model/Payment.php | 35 ++-- version/100/paymentmethod/JTLMollie.php | 202 ++++++++++++++++++++---- version/100/sql/100.sql | 31 ++-- 4 files changed, 221 insertions(+), 53 deletions(-) diff --git a/info.xml b/info.xml index 4fe7135..a199134 100644 --- a/info.xml +++ b/info.xml @@ -244,7 +244,7 @@ - mollie ING Home'Pay + mollie ING HomePay 2 0 mollie.com @@ -256,9 +256,9 @@ JTLMollieINGHomePay tpl/bestellabschluss.tpl - mollie ING Home'Pay + mollie ING HomePay mollie - Bezahlen Sie bequem mit ING Home'Pay. + Bezahlen Sie bequem mit ING HomePay. diff --git a/version/100/class/Model/Payment.php b/version/100/class/Model/Payment.php index edeb821..609b30e 100644 --- a/version/100/class/Model/Payment.php +++ b/version/100/class/Model/Payment.php @@ -4,26 +4,39 @@ use ws_mollie\Model\AbstractModel; -class Payment extends AbstractModel { - +class Payment extends AbstractModel +{ + public const TABLE = 'xplugin_ws_mollie_payments'; - - public static function updateFromPayment(\Mollie\Api\Resources\Payment $oMolliePayment, $kBestellung = null, $hash = null){ - return \Shop::DB()->executeQueryPrepared('INSERT INTO ' . self::TABLE . ' (kID, kBestellung, cStatus, fAmount, cCurrency, cMethod, cHash, dCreatedAt, dPaidAt) VALUES (:kID, :kBestellung, :cStatus, :fAmount, :cCurrency, :cMethod, :cHash, :dCreatedAt, :dPaidAt) ' - .' ON DUPLICATE KEY UPDATE kBestellung = :kBestellung1, cStatus = :cStatus1, cMethod = :cMethod1, dPaidAt = :dPaidAt1', [ + + public static function updateFromPayment(\Mollie\Api\Resources\Order $oMolliePayment, $kBestellung = null, $hash = null) + { + 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, :cCheckoutURL, :fAmountCaptured, :fAmountRefunded, :dCreatedAt) ' + . 'ON DUPLICATE KEY UPDATE kBestellung = :kBestellung1, cStatus = :cStatus1, cMethod = :cMethod1, bCancelable = :bCancelable1, fAmountCaptured = :fAmountCaptured1, fAmountRefunded = :fAmountRefunded1', [ ':kID' => $oMolliePayment->id, - ':kBestellung' => $kBestellung, - ':kBestellung1' => $kBestellung, + ':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, ':cCurrency' => $oMolliePayment->amount->currency, ':cMethod' => $oMolliePayment->method, ':cMethod1' => $oMolliePayment->method, - ':cHash' => $hash, + ':cLocale' => $oMolliePayment->locale, + ':bCancelable' => $oMolliePayment->isCancelable, + ':bCancelable1' => $oMolliePayment->isCancelable, + ':cWebhookURL' => $oMolliePayment->webhookUrl, + ':cRedirectURL' => $oMolliePayment->redirectUrl, + ':cCheckoutURL' => $oMolliePayment->getCheckoutUrl(), + ':fAmountCaptured' => $oMolliePayment->amountCaptured, + ':fAmountCaptured1' => $oMolliePayment->amountCaptured, + ':fAmountRefunded' => $oMolliePayment->amountRefunded, + ':fAmountRefunded1' => $oMolliePayment->amountRefunded, ':dCreatedAt' => $oMolliePayment->createdAt ? date('Y-m-d H:i:s', strtotime($oMolliePayment->createdAt)) : null, - ':dPaidAt' => $oMolliePayment->paidAt ? date('Y-m-d H:i:s', strtotime($oMolliePayment->paidAt)) : null, - ':dPaidAt1' => $oMolliePayment->paidAt ? date('Y-m-d H:i:s', strtotime($oMolliePayment->paidAt)) : null, ], 3); } } \ No newline at end of file diff --git a/version/100/paymentmethod/JTLMollie.php b/version/100/paymentmethod/JTLMollie.php index 516f6b1..e475c24 100644 --- a/version/100/paymentmethod/JTLMollie.php +++ b/version/100/paymentmethod/JTLMollie.php @@ -13,12 +13,24 @@ class JTLMollie extends PaymentMethod { + /** + * PaymentMethod identifier + */ const MOLLIE_METHOD = ""; + + /** + * Use OrderAPI for this PaymentMethod + */ + const ORDER_API = true; + /** * @var \ws_mollie\Helper */ protected static $_helper; + /** + * @var \Mollie\Api\MollieApiClient + */ protected static $_mollie; @@ -54,31 +66,166 @@ public static function Helper() } /** - * Prepares everything so that the Customer can start the Payment Process. - * Tells Template Engine. - * * @param Bestellung $order + * @return array */ - public function preparePaymentProcess($order) + protected function getOrderData(Bestellung $order) { - $hash = $this->generateHash($order); $data = [ + 'locale' => 'de_DE', // TODO: mapping with language? 'amount' => [ 'currency' => $order->Waehrung->cISO, 'value' => number_format($order->fGesamtsummeKundenwaehrung, 2, '.', ''), ], - 'description' => 'Ihre Bestellung bei XXX: ' . $order->cBestellNr, - 'redirectUrl' => (int)$this->duringCheckout ? Shop::getURL() . '/bestellabschluss.php?mollie=' .md5($hash) : $this->getReturnURL($order), + 'orderNumber' => $order->cBestellNr, + 'lines' => [], + 'billingAddress' => new stdClass(), + 'redirectUrl' => (int)$this->duringCheckout ? Shop::getURL() . '/bestellabschluss.php?mollie=' . md5($hash) : $this->getReturnURL($order), 'webhookUrl' => $this->getNotificationURL($hash) ]; - if(static::MOLLIE_METHOD !== ''){ + if (static::MOLLIE_METHOD !== '') { $data['method'] = static::MOLLIE_METHOD; } + $data['billingAddress']->organizationName = utf8_encode($order->oRechnungsadresse->cFirma); + $data['billingAddress']->title = $order->oRechnungsadresse->cAnrede === 'm' ? 'Herr' : 'Frau'; // TODO: Sprachvariable + $data['billingAddress']->givenName = utf8_encode($order->oRechnungsadresse->cVorname); + $data['billingAddress']->familyName = utf8_encode($order->oRechnungsadresse->cNachname); + $data['billingAddress']->email = $order->oRechnungsadresse->cMail; + $data['billingAddress']->streetAndNumber = utf8_encode($order->oRechnungsadresse->cStrasse . ' ' . $order->oRechnungsadresse->cHausnummer); + $data['billingAddress']->postalCode = $order->oRechnungsadresse->cPLZ; + $data['billingAddress']->city = utf8_encode($order->oRechnungsadresse->cOrt); + $data['billingAddress']->country = $order->oRechnungsadresse->cLand; + + /** @var WarenkorbPos $oPosition */ + foreach ($order->Positionen as $oPosition) { + $line = new stdClass(); + switch ((int)$oPosition->nPosTyp) { + case (int)C_WARENKORBPOS_TYP_GRATISGESCHENK: + case (int)C_WARENKORBPOS_TYP_ARTIKEL: + $line->type = \Mollie\Api\Types\OrderLineType::TYPE_PHYSICAL; + $line->name = utf8_encode($oPosition->cName); + $line->quantity = $oPosition->nAnzahl; + $line->unitPrice = (object)[ + 'value' => number_format($oPosition->fPreis * ((float)$oPosition->fMwSt / 100 + 1), 2, '.', ''), + 'currency' => $order->Waehrung->cISO, + ]; + $line->totalAmount = (object)[ + 'value' => number_format($oPosition->fPreis * $oPosition->nAnzahl * ((float)$oPosition->fMwSt / 100 + 1), 2, '.', ''), + 'currency' => $order->Waehrung->cISO, + ]; + $line->vatRate = $oPosition->fMwSt; + $line->vatAmount = (object)[ + 'value' => number_format($line->totalAmount->value - ($oPosition->fPreis * $oPosition->nAnzahl), 2, '.', ''), + 'currency' => $order->Waehrung->cISO, + ]; + $line->sku = $oPosition->cArtNr; + break; + case (int)C_WARENKORBPOS_TYP_VERSANDPOS: + $line->type = \Mollie\Api\Types\OrderLineType::TYPE_SHIPPING_FEE; + $line->name = utf8_encode($oPosition->cName); + $line->quantity = $oPosition->nAnzahl; + $line->unitPrice = (object)[ + 'value' => number_format($oPosition->fPreis * ((float)$oPosition->fMwSt / 100 + 1), 2, '.', ''), + 'currency' => $order->Waehrung->cISO, + ]; + $line->totalAmount = (object)[ + 'value' => number_format($oPosition->fPreis * $oPosition->nAnzahl * ((float)$oPosition->fMwSt / 100 + 1), 2, '.', ''), + 'currency' => $order->Waehrung->cISO, + ]; + $line->vatRate = $oPosition->fMwSt; + $line->vatAmount = (object)[ + 'value' => number_format($line->totalAmount->value - ($oPosition->fPreis * $oPosition->nAnzahl), 2, '.', ''), + 'currency' => $order->Waehrung->cISO, + ]; + 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 = \Mollie\Api\Types\OrderLineType::TYPE_SURCHARGE; + $line->name = utf8_encode($oPosition->cName); + $line->quantity = $oPosition->nAnzahl; + $line->unitPrice = (object)[ + 'value' => number_format($oPosition->fPreis * ((float)$oPosition->fMwSt / 100 + 1), 2, '.', ''), + 'currency' => $order->Waehrung->cISO, + ]; + $line->totalAmount = (object)[ + 'value' => number_format($oPosition->fPreis * $oPosition->nAnzahl * ((float)$oPosition->fMwSt / 100 + 1), 2, '.', ''), + 'currency' => $order->Waehrung->cISO, + ]; + $line->vatRate = $oPosition->fMwSt; + $line->vatAmount = (object)[ + 'value' => number_format($line->totalAmount->value - ($oPosition->fPreis * $oPosition->nAnzahl), 2, '.', ''), + 'currency' => $order->Waehrung->cISO, + ]; + break; + case (int)C_WARENKORBPOS_TYP_GUTSCHEIN: + case (int)C_WARENKORBPOS_TYP_KUPON: + case (int)C_WARENKORBPOS_TYP_NEUKUNDENKUPON: + $line->type = \Mollie\Api\Types\OrderLineType::TYPE_DISCOUNT; + $line->name = $oPosition->cName; + $line->quantity = $oPosition->nAnzahl; + $line->unitPrice = (object)[ + 'value' => number_format($oPosition->fPreis * ((float)$oPosition->fMwSt / 100 + 1), 2, '.', ''), + 'currency' => $order->Waehrung->cISO, + ]; + $line->totalAmount = (object)[ + 'value' => number_format($oPosition->fPreis * $oPosition->nAnzahl * ((float)$oPosition->fMwSt / 100 + 1), 2, '.', ''), + 'currency' => $order->Waehrung->cISO, + ]; + $line->vatRate = $oPosition->fMwSt; + $line->vatAmount = (object)[ + 'value' => number_format($line->totalAmount->value - ($oPosition->fPreis * $oPosition->nAnzahl), 2, '.', ''), + 'currency' => $order->Waehrung->cISO, + ]; + break; + } + if (isset($line->type)) { + $data['lines'][] = $line; + } + } + + if ((int)$order->GuthabenNutzen === 1 && $order->fGuthaben < 0) { + $line = new stdClass(); + $line->type = \Mollie\Api\Types\OrderLineType::TYPE_STORE_CREDIT; + $line->name = 'Guthaben'; + $line->quantity = 1; + $line->unitPrice = (object)[ + 'value' => number_format($order->fGuthaben, 2, '.', ''), + 'currency' => $order->Waehrung->cISO, + ]; + $line->unitPrice = (object)[ + 'value' => number_format($order->fGuthaben, 2, '.', ''), + 'currency' => $order->Waehrung->cISO, + ]; + $line->totalAmount = (object)[ + 'value' => number_format($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; + } + return $data; + } + + /** + * Prepares everything so that the Customer can start the Payment Process. + * Tells Template Engine. + * + * @param Bestellung $order + */ + public function preparePaymentProcess($order) + { try { - $oMolliePayment = static::API()->payments->create($data); + $oMolliePayment = self::API()->orders->create($this->getOrderData($order)); $_SESSION['oMolliePayment'] = $oMolliePayment; - $this->doLog('Mollie Create Payment Redirect: ' . $oMolliePayment->getCheckoutUrl() . "
" . print_r($oMolliePayment,1) . "
", LOGLEVEL_DEBUG); + $this->doLog('Mollie Create Payment Redirect: ' . $oMolliePayment->getCheckoutUrl() . "
" . print_r($oMolliePayment, 1) . "
", LOGLEVEL_DEBUG); \ws_mollie\Model\Payment::updateFromPayment($oMolliePayment, $order->kBestellung, md5($hash)); Shop::Smarty()->assign('oMolliePayment', $oMolliePayment); header('Location: ' . $oMolliePayment->getCheckoutUrl()); @@ -97,22 +244,22 @@ public function preparePaymentProcess($order) public function handleNotification($order, $hash, $args) { \ws_mollie\Helper::autoload(); - try{ + try { $oMolliePayment = self::API()->payments->get($args['id']); - $this->doLog('Received Notification
' . print_r([$hash, $args, $oMolliePayment],1) . '
', LOGLEVEL_DEBUG); - + $this->doLog('Received Notification
' . print_r([$hash, $args, $oMolliePayment], 1) . '
', LOGLEVEL_DEBUG); + \ws_mollie\Model\Payment::updateFromPayment($oMolliePayment, $order->kBestellung); - - if($oMolliePayment->status === MolliePaymentStatus::STATUS_PAID){ - $oIncomingPayment = new stdClass(); + + if ($oMolliePayment->status === MolliePaymentStatus::STATUS_PAID) { + $oIncomingPayment = new stdClass(); $oIncomingPayment->fBetrag = $order->fGesamtsummeKundenwaehrung; - $oIncomingPayment->cISO = $order->Waehrung->cISO; + $oIncomingPayment->cISO = $order->Waehrung->cISO; $oIncomingPayment->chinweis = $oMolliePayment->id; $this->addIncomingPayment($order, $oIncomingPayment); $this->setOrderStatusToPaid($order); } - - }catch(\Exception $e){ + + } catch (\Exception $e) { $this->doLog($e->getMessage()); } } @@ -126,13 +273,13 @@ public function handleNotification($order, $hash, $args) */ public function finalizeOrder($order, $hash, $args) { - try{ + try { \ws_mollie\Helper::autoload(); - $oMolliePayment = self::API()->payments->get($args['id']); - $this->doLog('Received Notification Finalize Order
' . print_r([$hash, $args, $oMolliePayment],1) . '
', LOGLEVEL_DEBUG); + $oMolliePayment = self::API()->orders->get($args['id'], ['embed' => 'payments']); + $this->doLog('Received Notification Finalize Order
' . print_r([$hash, $args, $oMolliePayment], 1) . '
', LOGLEVEL_DEBUG); \ws_mollie\Model\Payment::updateFromPayment($oMolliePayment, $order->kBestellung); - return !in_array([MolliePaymentStatus::STATUS_FAILED, MolliePaymentStatus::STATUS_CANCELED, MolliePaymentStatus::STATUS_EXPIRED, MolliePaymentStatus::STATUS_OPEN],$oMolliePayment->status); - }catch(\Exception $e){ + return !in_array([MolliePaymentStatus::STATUS_FAILED, MolliePaymentStatus::STATUS_CANCELED, MolliePaymentStatus::STATUS_EXPIRED, MolliePaymentStatus::STATUS_OPEN], $oMolliePayment->status); + } catch (\Exception $e) { $this->doLog($e->getMessage()); } return false; @@ -153,15 +300,14 @@ public function canPayAgain() */ public function isSelectable() { - - if(static::MOLLIE_METHOD !== ''){ + + if (static::MOLLIE_METHOD !== '') { try { $method = self::API()->methods->get(static::MOLLIE_METHOD, ['locale' => 'de_DE', 'include' => 'pricing,issuers']); \Shop::DB()->executeQueryPrepared("UPDATE tzahlungsart SET cBild = :cBild WHERE cModulId = :cModulId", [':cBild' => $method->image->size2x, ':cModulId' => $this->cModulId], 3); $this->cBild = $method->image->size2x; - var_dump($method->issuers); return true; - }catch(Exception $e){ + } catch (Exception $e) { $this->doLog('Method ' . static::MOLLIE_METHOD . ' not selectable:' . $e->getMessage()); return false; } diff --git a/version/100/sql/100.sql b/version/100/sql/100.sql index 3b6aedd..55da87a 100644 --- a/version/100/sql/100.sql +++ b/version/100/sql/100.sql @@ -1,14 +1,23 @@ -CREATE TABLE `xplugin_ws_mollie_payments` ( - `kID` varchar(32) NOT NULL, - `kBestellung` INT(11) NULL, - `cStatus` varchar(16) NOT NULL, - `cHash` varchar(32) NULL, - `fAmount` float NOT NULL, - `cCurrency` varchar(3) NOT NULL, - `cMethod` varchar(16) NULL, - `dCreatedAt` datetime NULL, - `dPaidAt` datetime NULL +CREATE TABLE `xplugin_ws_mollie_payments` +( + `kID` VARCHAR(32) NOT NULL, + `kBestellung` INT(11) NULL, + `cMode` VARCHAR(16) NULL, + `cStatus` VARCHAR(16) NOT NULL, + `cHash` VARCHAR(32) NULL, + `fAmount` FLOAT NOT NULL, + `cOrderNumber` VARCHAR(32) DEFAULT '' NOT NULL, + `cCurrency` VARCHAR(3) NOT NULL, + `cMethod` VARCHAR(16) NULL, + `cLocale` VARCHAR(5) NOT NULL, + `bCancelable` INT(1) NOT NULL, + `cWebhookURL` VARCHAR(255) DEFAULT '' NOT NULL, + `cRedirectURL` VARCHAR(255) DEFAULT '' NOT NULL, + `cCheckoutURL` VARCHAR(255) DEFAULT '' NOT NULL, + `fAmountCaptured` FLOAT NULL, + `fAmountRefunded` FLOAT NULL, + `dCreatedAt` DATETIME NULL ); ALTER TABLE `xplugin_ws_mollie_payments` -ADD PRIMARY KEY `kID` (`kID`); \ No newline at end of file + ADD PRIMARY KEY `kID` (`kID`); \ No newline at end of file From 52a35d30b62371190e2497fcd9c5f2b574299fa5 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Thu, 13 Dec 2018 11:12:39 +0100 Subject: [PATCH 006/280] order api --- version/100/class/Model/Payment.php | 14 ++++++++++---- version/100/paymentmethod/JTLMollie.php | 8 ++++---- version/100/sql/100.sql | 3 +-- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/version/100/class/Model/Payment.php b/version/100/class/Model/Payment.php index 609b30e..dadbc03 100644 --- a/version/100/class/Model/Payment.php +++ b/version/100/class/Model/Payment.php @@ -11,9 +11,8 @@ class Payment extends AbstractModel public static function updateFromPayment(\Mollie\Api\Resources\Order $oMolliePayment, $kBestellung = null, $hash = null) { - 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, :cCheckoutURL, :fAmountCaptured, :fAmountRefunded, :dCreatedAt) ' - . 'ON DUPLICATE KEY UPDATE kBestellung = :kBestellung1, cStatus = :cStatus1, cMethod = :cMethod1, bCancelable = :bCancelable1, fAmountCaptured = :fAmountCaptured1, fAmountRefunded = :fAmountRefunded1', [ + + $data = [ ':kID' => $oMolliePayment->id, ':kBestellung' => (int)$kBestellung ?: NULL, ':kBestellung1' => (int)$kBestellung ?: NULL, @@ -32,11 +31,18 @@ public static function updateFromPayment(\Mollie\Api\Resources\Order $oMolliePay ':cWebhookURL' => $oMolliePayment->webhookUrl, ':cRedirectURL' => $oMolliePayment->redirectUrl, ':cCheckoutURL' => $oMolliePayment->getCheckoutUrl(), + ':cCheckoutURL1' => $oMolliePayment->getCheckoutUrl(), ':fAmountCaptured' => $oMolliePayment->amountCaptured, ':fAmountCaptured1' => $oMolliePayment->amountCaptured, ':fAmountRefunded' => $oMolliePayment->amountRefunded, ':fAmountRefunded1' => $oMolliePayment->amountRefunded, ':dCreatedAt' => $oMolliePayment->createdAt ? date('Y-m-d H:i:s', strtotime($oMolliePayment->createdAt)) : null, - ], 3); + ]; + + + 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, cStatus = :cStatus1, cMethod = :cMethod1, bCancelable = :bCancelable1, fAmountCaptured = :fAmountCaptured1, fAmountRefunded = :fAmountRefunded1', + $data, 3); } } \ No newline at end of file diff --git a/version/100/paymentmethod/JTLMollie.php b/version/100/paymentmethod/JTLMollie.php index e475c24..e1553f7 100644 --- a/version/100/paymentmethod/JTLMollie.php +++ b/version/100/paymentmethod/JTLMollie.php @@ -69,9 +69,8 @@ public static function Helper() * @param Bestellung $order * @return array */ - protected function getOrderData(Bestellung $order) + protected function getOrderData(Bestellung $order, $hash) { - $hash = $this->generateHash($order); $data = [ 'locale' => 'de_DE', // TODO: mapping with language? 'amount' => [ @@ -223,7 +222,8 @@ protected function getOrderData(Bestellung $order) public function preparePaymentProcess($order) { try { - $oMolliePayment = self::API()->orders->create($this->getOrderData($order)); + $hash = $this->generateHash($order); + $oMolliePayment = self::API()->orders->create($this->getOrderData($order, $hash)); $_SESSION['oMolliePayment'] = $oMolliePayment; $this->doLog('Mollie Create Payment Redirect: ' . $oMolliePayment->getCheckoutUrl() . "
" . print_r($oMolliePayment, 1) . "
", LOGLEVEL_DEBUG); \ws_mollie\Model\Payment::updateFromPayment($oMolliePayment, $order->kBestellung, md5($hash)); @@ -245,7 +245,7 @@ public function handleNotification($order, $hash, $args) { \ws_mollie\Helper::autoload(); try { - $oMolliePayment = self::API()->payments->get($args['id']); + $oMolliePayment = self::API()->orders->get($args['id']); $this->doLog('Received Notification
' . print_r([$hash, $args, $oMolliePayment], 1) . '
', LOGLEVEL_DEBUG); \ws_mollie\Model\Payment::updateFromPayment($oMolliePayment, $order->kBestellung); diff --git a/version/100/sql/100.sql b/version/100/sql/100.sql index 55da87a..a6cf185 100644 --- a/version/100/sql/100.sql +++ b/version/100/sql/100.sql @@ -1,5 +1,4 @@ -CREATE TABLE `xplugin_ws_mollie_payments` -( +CREATE TABLE `xplugin_ws_mollie_payments` ( `kID` VARCHAR(32) NOT NULL, `kBestellung` INT(11) NULL, `cMode` VARCHAR(16) NULL, From 1ff0ab7c68fc1f29196c25270d5aef1174703c4c Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Thu, 20 Dec 2018 14:29:09 +0100 Subject: [PATCH 007/280] #8, #7 --- version/100/class/Model/Payment.php | 10 +- version/100/paymentmethod/JTLMollie.php | 156 ++++++++++++++++++++---- 2 files changed, 138 insertions(+), 28 deletions(-) diff --git a/version/100/class/Model/Payment.php b/version/100/class/Model/Payment.php index dadbc03..03bff98 100644 --- a/version/100/class/Model/Payment.php +++ b/version/100/class/Model/Payment.php @@ -32,14 +32,12 @@ public static function updateFromPayment(\Mollie\Api\Resources\Order $oMolliePay ':cRedirectURL' => $oMolliePayment->redirectUrl, ':cCheckoutURL' => $oMolliePayment->getCheckoutUrl(), ':cCheckoutURL1' => $oMolliePayment->getCheckoutUrl(), - ':fAmountCaptured' => $oMolliePayment->amountCaptured, - ':fAmountCaptured1' => $oMolliePayment->amountCaptured, - ':fAmountRefunded' => $oMolliePayment->amountRefunded, - ':fAmountRefunded1' => $oMolliePayment->amountRefunded, + ':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, ]; - - 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, cStatus = :cStatus1, cMethod = :cMethod1, bCancelable = :bCancelable1, fAmountCaptured = :fAmountCaptured1, fAmountRefunded = :fAmountRefunded1', diff --git a/version/100/paymentmethod/JTLMollie.php b/version/100/paymentmethod/JTLMollie.php index e1553f7..0dbcd86 100644 --- a/version/100/paymentmethod/JTLMollie.php +++ b/version/100/paymentmethod/JTLMollie.php @@ -73,7 +73,7 @@ protected function getOrderData(Bestellung $order, $hash) { $data = [ 'locale' => 'de_DE', // TODO: mapping with language? - 'amount' => [ + 'amount' => (object)[ 'currency' => $order->Waehrung->cISO, 'value' => number_format($order->fGesamtsummeKundenwaehrung, 2, '.', ''), ], @@ -83,6 +83,7 @@ protected function getOrderData(Bestellung $order, $hash) 'redirectUrl' => (int)$this->duringCheckout ? Shop::getURL() . '/bestellabschluss.php?mollie=' . md5($hash) : $this->getReturnURL($order), 'webhookUrl' => $this->getNotificationURL($hash) ]; + if (static::MOLLIE_METHOD !== '') { $data['method'] = static::MOLLIE_METHOD; } @@ -106,16 +107,16 @@ protected function getOrderData(Bestellung $order, $hash) $line->name = utf8_encode($oPosition->cName); $line->quantity = $oPosition->nAnzahl; $line->unitPrice = (object)[ - 'value' => number_format($oPosition->fPreis * ((float)$oPosition->fMwSt / 100 + 1), 2, '.', ''), + 'value' => number_format($order->Waehrung->fFaktor * ($oPosition->fPreis * ((float)$oPosition->fMwSt / 100 + 1)), 2, '.', ''), 'currency' => $order->Waehrung->cISO, ]; $line->totalAmount = (object)[ - 'value' => number_format($oPosition->fPreis * $oPosition->nAnzahl * ((float)$oPosition->fMwSt / 100 + 1), 2, '.', ''), + 'value' => number_format($oPosition->nAnzahl * (float)$line->unitPrice->value, 2, '.', ''), 'currency' => $order->Waehrung->cISO, ]; $line->vatRate = $oPosition->fMwSt; $line->vatAmount = (object)[ - 'value' => number_format($line->totalAmount->value - ($oPosition->fPreis * $oPosition->nAnzahl), 2, '.', ''), + 'value' => number_format($line->totalAmount->value - ($line->totalAmount->value / (1 + (float)$oPosition->fMwSt / 100)), 2, '.', ''), 'currency' => $order->Waehrung->cISO, ]; $line->sku = $oPosition->cArtNr; @@ -125,16 +126,16 @@ protected function getOrderData(Bestellung $order, $hash) $line->name = utf8_encode($oPosition->cName); $line->quantity = $oPosition->nAnzahl; $line->unitPrice = (object)[ - 'value' => number_format($oPosition->fPreis * ((float)$oPosition->fMwSt / 100 + 1), 2, '.', ''), + 'value' => number_format($order->Waehrung->fFaktor * ($oPosition->fPreis * ((float)$oPosition->fMwSt / 100 + 1)), 2, '.', ''), 'currency' => $order->Waehrung->cISO, ]; $line->totalAmount = (object)[ - 'value' => number_format($oPosition->fPreis * $oPosition->nAnzahl * ((float)$oPosition->fMwSt / 100 + 1), 2, '.', ''), + 'value' => number_format($order->Waehrung->fFaktor * ($oPosition->fPreis * $oPosition->nAnzahl * ((float)$oPosition->fMwSt / 100 + 1)), 2, '.', ''), 'currency' => $order->Waehrung->cISO, ]; $line->vatRate = $oPosition->fMwSt; $line->vatAmount = (object)[ - 'value' => number_format($line->totalAmount->value - ($oPosition->fPreis * $oPosition->nAnzahl), 2, '.', ''), + 'value' => number_format($line->totalAmount->value - ($line->totalAmount->value / (1 + (float)$oPosition->fMwSt/100)), 2, '.', ''), 'currency' => $order->Waehrung->cISO, ]; break; @@ -147,16 +148,16 @@ protected function getOrderData(Bestellung $order, $hash) $line->name = utf8_encode($oPosition->cName); $line->quantity = $oPosition->nAnzahl; $line->unitPrice = (object)[ - 'value' => number_format($oPosition->fPreis * ((float)$oPosition->fMwSt / 100 + 1), 2, '.', ''), + 'value' => number_format($order->Waehrung->fFaktor * ($oPosition->fPreis * ((float)$oPosition->fMwSt / 100 + 1)), 2, '.', ''), 'currency' => $order->Waehrung->cISO, ]; $line->totalAmount = (object)[ - 'value' => number_format($oPosition->fPreis * $oPosition->nAnzahl * ((float)$oPosition->fMwSt / 100 + 1), 2, '.', ''), + 'value' => number_format($order->Waehrung->fFaktor * ($oPosition->fPreis * $oPosition->nAnzahl * ((float)$oPosition->fMwSt / 100 + 1)), 2, '.', ''), 'currency' => $order->Waehrung->cISO, ]; $line->vatRate = $oPosition->fMwSt; $line->vatAmount = (object)[ - 'value' => number_format($line->totalAmount->value - ($oPosition->fPreis * $oPosition->nAnzahl), 2, '.', ''), + 'value' => number_format($line->totalAmount->value - ($line->totalAmount->value / (1 + (float)$oPosition->fMwSt/100)), 2, '.', ''), 'currency' => $order->Waehrung->cISO, ]; break; @@ -167,16 +168,16 @@ protected function getOrderData(Bestellung $order, $hash) $line->name = $oPosition->cName; $line->quantity = $oPosition->nAnzahl; $line->unitPrice = (object)[ - 'value' => number_format($oPosition->fPreis * ((float)$oPosition->fMwSt / 100 + 1), 2, '.', ''), + 'value' => number_format($order->Waehrung->fFaktor * ($oPosition->fPreis * ((float)$oPosition->fMwSt / 100 + 1)), 2, '.', ''), 'currency' => $order->Waehrung->cISO, ]; $line->totalAmount = (object)[ - 'value' => number_format($oPosition->fPreis * $oPosition->nAnzahl * ((float)$oPosition->fMwSt / 100 + 1), 2, '.', ''), + 'value' => number_format($order->Waehrung->fFaktor * ($oPosition->fPreis * $oPosition->nAnzahl * ((float)$oPosition->fMwSt / 100 + 1)), 2, '.', ''), 'currency' => $order->Waehrung->cISO, ]; $line->vatRate = $oPosition->fMwSt; $line->vatAmount = (object)[ - 'value' => number_format($line->totalAmount->value - ($oPosition->fPreis * $oPosition->nAnzahl), 2, '.', ''), + 'value' => number_format($line->totalAmount->value - ($line->totalAmount->value / (1 + (float)$oPosition->fMwSt/100)), 2, '.', ''), 'currency' => $order->Waehrung->cISO, ]; break; @@ -192,15 +193,15 @@ protected function getOrderData(Bestellung $order, $hash) $line->name = 'Guthaben'; $line->quantity = 1; $line->unitPrice = (object)[ - 'value' => number_format($order->fGuthaben, 2, '.', ''), + 'value' => number_format($order->Waehrung->fFaktor * $order->fGuthaben, 2, '.', ''), 'currency' => $order->Waehrung->cISO, ]; $line->unitPrice = (object)[ - 'value' => number_format($order->fGuthaben, 2, '.', ''), + 'value' => number_format($order->Waehrung->fFaktor * $order->fGuthaben, 2, '.', ''), 'currency' => $order->Waehrung->cISO, ]; $line->totalAmount = (object)[ - 'value' => number_format($order->fGuthaben, 2, '.', ''), + 'value' => number_format($order->Waehrung->fFaktor * $order->fGuthaben, 2, '.', ''), 'currency' => $order->Waehrung->cISO, ]; $line->vatRate = "0.00"; @@ -210,6 +211,40 @@ protected function getOrderData(Bestellung $order, $hash) ]; $data['lines'][] = $line; } + + // RUNDUNGSAUSGLEICH + $sum = .0; + foreach($data['lines'] as $line){ + $sum += (float)$line->totalAmount->value; + } + if($sum <> (float)$data['amount']->value){ + $diff = (round((float)$data['amount']->value - $sum,2)); + if($diff !== 0){ + $line = new stdClass(); + $line->type = $diff > 0 ? \Mollie\Api\Types\OrderLineType::TYPE_SURCHARGE : \Mollie\Api\Types\OrderLineType::TYPE_DISCOUNT; + $line->name = 'Rundungsausgleich'; + $line->quantity = 1; + $line->unitPrice = (object)[ + 'value' => number_format($diff, 2, '.', ''), + 'currency' => $order->Waehrung->cISO, + ]; + $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; } @@ -254,7 +289,7 @@ public function handleNotification($order, $hash, $args) $oIncomingPayment = new stdClass(); $oIncomingPayment->fBetrag = $order->fGesamtsummeKundenwaehrung; $oIncomingPayment->cISO = $order->Waehrung->cISO; - $oIncomingPayment->chinweis = $oMolliePayment->id; + $oIncomingPayment->cHinweis = $oMolliePayment->id; $this->addIncomingPayment($order, $oIncomingPayment); $this->setOrderStatusToPaid($order); } @@ -278,7 +313,7 @@ public function finalizeOrder($order, $hash, $args) $oMolliePayment = self::API()->orders->get($args['id'], ['embed' => 'payments']); $this->doLog('Received Notification Finalize Order
' . print_r([$hash, $args, $oMolliePayment], 1) . '
', LOGLEVEL_DEBUG); \ws_mollie\Model\Payment::updateFromPayment($oMolliePayment, $order->kBestellung); - return !in_array([MolliePaymentStatus::STATUS_FAILED, MolliePaymentStatus::STATUS_CANCELED, MolliePaymentStatus::STATUS_EXPIRED, MolliePaymentStatus::STATUS_OPEN], $oMolliePayment->status); + return !in_array($oMolliePayment->status, [MolliePaymentStatus::STATUS_FAILED, MolliePaymentStatus::STATUS_CANCELED, MolliePaymentStatus::STATUS_EXPIRED, MolliePaymentStatus::STATUS_OPEN]); } catch (\Exception $e) { $this->doLog($e->getMessage()); } @@ -293,6 +328,79 @@ public function canPayAgain() return true; } + + 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 "eng": + return "en_US"; + 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"; + } + } + + protected static $_possiblePaymentMethods = []; + 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->all(['amount' => ['currency' => $currency, 'value' => number_format($amount,2,'.','')], 'billingCountry' => $_SESSION['Kunde']->cLand, 'locale' => $locale, '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]; + } + + protected function updatePaymentMethod($cISOSprache, $method){ + if($this->cBild === ''){ + \Shop::DB()->executeQueryPrepared("UPDATE tzahlungsart SET cBild = :cBild WHERE cModulId = :cModulId", [':cBild' => $method->image->size2x, ':cModulId' => $this->cModulId], 3); + } + if($za = \Shop::DB()->executeQueryPrepared('SELECT kZahlungsart FROM tzahlungsart WHERE cModulID = :cModulID',[':cModulID' => $this->moduleID],1)){ + $x = \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);", [ + ':kZahlungsart' => (int)$za->kZahlungsart, + ':cISOSprache' => $cISOSprache, + ':cName' => $method->description, + ':cGebuehrname' => '', + ':cHinweisText' => '', + 'cName1' => $method->description, + ], 3); + } + } + /** * determines, if the payment method can be selected in the checkout process * @@ -301,12 +409,16 @@ public function canPayAgain() public function isSelectable() { + $locale = self::getLocale($_SESSION['cISOSprache'], $_SESSION['Kunde']->cLand); if (static::MOLLIE_METHOD !== '') { try { - $method = self::API()->methods->get(static::MOLLIE_METHOD, ['locale' => 'de_DE', 'include' => 'pricing,issuers']); - \Shop::DB()->executeQueryPrepared("UPDATE tzahlungsart SET cBild = :cBild WHERE cModulId = :cModulId", [':cBild' => $method->image->size2x, ':cModulId' => $this->cModulId], 3); - $this->cBild = $method->image->size2x; - return true; + $method = self::PossiblePaymentMethods(static::MOLLIE_METHOD, $locale, $_SESSION['Kunde']->cLand, $_SESSION['Waehrung']->cISO, $_SESSION['Warenkorb']->gibGesamtsummeWaren() * $_SESSION['Waehrung']->fFaktor); + if($method !== null){ + $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; From 83f5d4aca3ab6b53d2fd80adb0d45e2a8a509a4f Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Tue, 8 Jan 2019 17:20:16 +0100 Subject: [PATCH 008/280] #5 session cleanup if payment after finalise order --- version/100/class/Model/Payment.php | 5 +++++ version/100/paymentmethod/JTLMollie.php | 20 ++++++++++++++++++-- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/version/100/class/Model/Payment.php b/version/100/class/Model/Payment.php index 03bff98..9960426 100644 --- a/version/100/class/Model/Payment.php +++ b/version/100/class/Model/Payment.php @@ -43,4 +43,9 @@ public static function updateFromPayment(\Mollie\Api\Resources\Order $oMolliePay . 'ON DUPLICATE KEY UPDATE kBestellung = :kBestellung1, cStatus = :cStatus1, cMethod = :cMethod1, bCancelable = :bCancelable1, fAmountCaptured = :fAmountCaptured1, fAmountRefunded = :fAmountRefunded1', $data, 3); } + + public static function getPayment($kBestellung){ + return \Shop::DB()->executeQueryPrepared('SELECT * FROM ' . self::TABLE . ' WHERE kBestellung = :kBestellung', [':kBestellung' => $kBestellung], 1); + } + } \ No newline at end of file diff --git a/version/100/paymentmethod/JTLMollie.php b/version/100/paymentmethod/JTLMollie.php index 0dbcd86..80ba142 100644 --- a/version/100/paymentmethod/JTLMollie.php +++ b/version/100/paymentmethod/JTLMollie.php @@ -256,6 +256,19 @@ protected function getOrderData(Bestellung $order, $hash) */ public function preparePaymentProcess($order) { + try { + $payment = \ws_mollie\Model\Payment::getPayment($order->kBestellung); + if($payment && in_array($payment->cStatus, [MolliePaymentStatus::STATUS_OPEN, 'created']) && $payment->cCheckoutURL){ + if(!$this->duringCheckout){ + Session::getInstance()->cleanUp(); + } + header('Location: ' . $payment->cCheckoutURL); + exit(); + } + }catch(\Exception $e){ + $this->doLog("Get Payment Error: " . $e->getMessage() . ". Create new ORDER..."); + } + try { $hash = $this->generateHash($order); $oMolliePayment = self::API()->orders->create($this->getOrderData($order, $hash)); @@ -263,11 +276,14 @@ public function preparePaymentProcess($order) $this->doLog('Mollie Create Payment Redirect: ' . $oMolliePayment->getCheckoutUrl() . "
" . print_r($oMolliePayment, 1) . "
", LOGLEVEL_DEBUG); \ws_mollie\Model\Payment::updateFromPayment($oMolliePayment, $order->kBestellung, md5($hash)); Shop::Smarty()->assign('oMolliePayment', $oMolliePayment); + if(!$this->duringCheckout){ + Session::getInstance()->cleanUp(); + } header('Location: ' . $oMolliePayment->getCheckoutUrl()); exit(); } catch (\Mollie\Api\Exceptions\ApiException $e) { Shop::Smarty()->assign('oMollieException', $e); - $this->doLog("Create Payment Error: " . $e->getMessage() . '
>
' . print_r($data, 1) . '
'); + $this->doLog("Create Payment Error: " . $e->getMessage() . '
' . print_r($data, 1) . '
'); } } @@ -393,7 +409,7 @@ protected function updatePaymentMethod($cISOSprache, $method){ $x = \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);", [ ':kZahlungsart' => (int)$za->kZahlungsart, ':cISOSprache' => $cISOSprache, - ':cName' => $method->description, + ':cName' => utf8_decode($method->description), ':cGebuehrname' => '', ':cHinweisText' => '', 'cName1' => $method->description, From ac99ac2b3f88e5a06d82af6f55b6bb9b57787ea9 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Wed, 9 Jan 2019 17:39:10 +0100 Subject: [PATCH 009/280] backend: orders, order details,, paymentmethods --- info.xml | 45 ++++--- version/100/adminmenu/orders.php | 63 ++++++++++ version/100/adminmenu/paymentmethods.php | 29 +++++ version/100/adminmenu/tpl/order.tpl | 126 +++++++++++++++++++ version/100/adminmenu/tpl/orders.tpl | 66 ++++++++++ version/100/adminmenu/tpl/paymentmethods.tpl | 48 +++++++ version/100/class/Model/Payment.php | 17 ++- version/100/paymentmethod/JTLMollie.php | 120 +++++++++++------- 8 files changed, 448 insertions(+), 66 deletions(-) create mode 100644 version/100/adminmenu/orders.php create mode 100644 version/100/adminmenu/paymentmethods.php create mode 100644 version/100/adminmenu/tpl/order.tpl create mode 100644 version/100/adminmenu/tpl/orders.tpl create mode 100644 version/100/adminmenu/tpl/paymentmethods.tpl diff --git a/info.xml b/info.xml index a199134..37fd020 100644 --- a/info.xml +++ b/info.xml @@ -1,7 +1,7 @@ mollie - Zahlungsart plugin für mollie.com + Zahlungsartplugin für mollie.com WebStollen http://www.webstollen.de/ 102 @@ -16,6 +16,15 @@ + + Bestellungen + orders.php + + + Zahlungsarten + paymentmethods.php + + Einstellungen @@ -66,7 +75,7 @@ JTLMollieCreditCard tpl/bestellabschluss.tpl - mollie Kreditkarte + Kreditkarte mollie Bezahlen Sie bequem mit Kreditkarte. @@ -85,7 +94,7 @@ JTLMollieBitcoin tpl/bestellabschluss.tpl - mollie Bitcoin + Bitcoin mollie Bezahlen Sie bequem mit Bitcoins. @@ -104,7 +113,7 @@ JTLMollieBancontact tpl/bestellabschluss.tpl - mollie Bancontact + Bancontact mollie Bezahlen Sie bequem mit Bancontact. @@ -123,7 +132,7 @@ JTLMollieBanktransfer tpl/bestellabschluss.tpl - mollie SEPA Überweisung + SEPA Überweisung mollie Bezahlen Sie bequem mit SEPA Überweisung. @@ -142,7 +151,7 @@ JTLMollieBelfius tpl/bestellabschluss.tpl - mollie SEPA Überweisung + SEPA Überweisung mollie Bezahlen Sie bequem mit Belfius. @@ -161,7 +170,7 @@ JTLMollieDirectDebit tpl/bestellabschluss.tpl - mollie SEPA Lastschrift + SEPA Lastschrift mollie Bezahlen Sie bequem mit SEPA Lastschrift. @@ -180,7 +189,7 @@ JTLMollieEPS tpl/bestellabschluss.tpl - mollie EPS + EPS mollie Bezahlen Sie bequem mit EPS. @@ -199,7 +208,7 @@ JTLMollieGiftcard tpl/bestellabschluss.tpl - mollie Gift cards + Gift cards mollie Bezahlen Sie bequem mit Gift cards. @@ -218,7 +227,7 @@ JTLMollieGiropay tpl/bestellabschluss.tpl - mollie Giropay + Giropay mollie Bezahlen Sie bequem mit Giropay. @@ -237,7 +246,7 @@ JTLMollieIDEAL tpl/bestellabschluss.tpl - mollie Giropay + Giropay mollie Bezahlen Sie bequem mit iDEAL. @@ -256,7 +265,7 @@ JTLMollieINGHomePay tpl/bestellabschluss.tpl - mollie ING HomePay + ING HomePay mollie Bezahlen Sie bequem mit ING HomePay. @@ -275,7 +284,7 @@ JTLMollieKBC tpl/bestellabschluss.tpl - mollie KBC + KBC mollie Bezahlen Sie bequem mit KBC. @@ -294,7 +303,7 @@ JTLMolliePayPal tpl/bestellabschluss.tpl - mollie PayPal + PayPal mollie Bezahlen Sie bequem mit PayPal. @@ -313,7 +322,7 @@ JTLMolliePaysafecard tpl/bestellabschluss.tpl - mollie paysafecard + paysafecard mollie Bezahlen Sie bequem mit paysafecard. @@ -332,7 +341,7 @@ JTLMollieSofort tpl/bestellabschluss.tpl - mollie SOFORT + SOFORT mollie Bezahlen Sie bequem mit SOFORT. @@ -351,7 +360,7 @@ JTLMollieKlarnaPayLater tpl/bestellabschluss.tpl - mollie Klarna Pay Later + Klarna Pay Later mollie Bezahlen Sie bequem mit Klarna Pay Later. @@ -370,7 +379,7 @@ JTLMollieKlarnaSliceIt tpl/bestellabschluss.tpl - mollie Klarna Slice It + Klarna Slice It mollie Bezahlen Sie bequem mit Klarna Slice It. diff --git a/version/100/adminmenu/orders.php b/version/100/adminmenu/orders.php new file mode 100644 index 0000000..f9d77c9 --- /dev/null +++ b/version/100/adminmenu/orders.php @@ -0,0 +1,63 @@ + 'danger', 'text' => 'Keine ID angeben!']; + break; + } + + $mollie = new \Mollie\Api\MollieApiClient(); + $mollie->setApiKey(\ws_mollie\Helper::getSetting("api_key")); + + $order = $mollie->orders->get($_REQUEST['id']); + $payment = \ws_mollie\Model\Payment::getPaymentMollie($_REQUEST['id']); + if ($payment) { + $oBestellung = new Bestellung($payment->kBestellung, false); + 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", [ + ':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; + } + } + + + $payments = Shop::DB()->executeQueryPrepared("SELECT * FROM xplugin_ws_mollie_payments", [], 2); + + Shop::Smarty()->assign('payments', $payments) + ->assign('ordersMsgs', $ordersMsgs); + + Shop::Smarty()->display($oPlugin->cAdminmenuPfad . '/tpl/orders.tpl'); + +} catch (Exception $e) { + echo "
{$e->getMessage()}
"; + \ws_mollie\Helper::logExc($e); +} \ No newline at end of file diff --git a/version/100/adminmenu/paymentmethods.php b/version/100/adminmenu/paymentmethods.php new file mode 100644 index 0000000..dde49ca --- /dev/null +++ b/version/100/adminmenu/paymentmethods.php @@ -0,0 +1,29 @@ +setApiKey(\ws_mollie\Helper::getSetting("api_key")); + + $profile = $mollie->profiles->get('me'); + $methods = $mollie->methods->all([ + 'locale' => 'de_DE', + 'include' => 'pricing', + ]); + + Shop::Smarty()->assign('methods', $methods) + ->assign('profile', $profile); + Shop::Smarty()->display($oPlugin->cAdminmenuPfad . '/tpl/paymentmethods.tpl'); + +} catch (Exception $e) { + echo "
{$e->getMessage()}
"; + \ws_mollie\Helper::logExc($e); +} \ No newline at end of file diff --git a/version/100/adminmenu/tpl/order.tpl b/version/100/adminmenu/tpl/order.tpl new file mode 100644 index 0000000..4cf808b --- /dev/null +++ b/version/100/adminmenu/tpl/order.tpl @@ -0,0 +1,126 @@ +

+ « + Bestellung: {$oBestellung->cBestellNr} - + {if (int)$oBestellung->cStatus == 1} + OFFEN + {elseif (int)$oBestellung->cStatus == 2} + IN BEARBEITUNG + {elseif (int)$oBestellung->cStatus == 3} + BEZAHLT + {elseif (int)$oBestellung->cStatus == 4} + VERSANDT + {elseif (int)$oBestellung->cStatus == 5} + TEILVERSANDT + {elseif (int)$oBestellung->cStatus == -1} + STORNO + {else} + n/a + {/if} +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Mollie ID:{$payment->kID}Mode:{$order->mode}Status:{$order->status}
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)}
+ +

Positionen:

+ + + + + + + + + + + + + + + {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} + + + + + + + + + + + {/foreach} + + + + + + + + + +
SKUNameTypAnzahlMwStSteuerNettoBrutto
{$line->sku}{$line->name|utf8_decode}{$line->type}{$line->quantity}{(float)$line->vatRate}%{$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}
{$vat|number_format:2:',':''} {$order->amount->currency}{$netto|number_format:2:',':''} {$order->amount->currency}{$brutto|number_format:2:',':''} {$order->amount->currency}
+ + +

Log

+ + + {foreach from=$logs item=log} + + + + + + + {/foreach} +
+ {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}
+ +{*$logs|var_dump} +{$payment|var_dump} +{$oBestellung|var_dump} +{$order|var_dump*} \ No newline at end of file diff --git a/version/100/adminmenu/tpl/orders.tpl b/version/100/adminmenu/tpl/orders.tpl new file mode 100644 index 0000000..7009c18 --- /dev/null +++ b/version/100/adminmenu/tpl/orders.tpl @@ -0,0 +1,66 @@ +{*$payments|var_dump*} + +{if count($ordersMsgs)} + {foreach from=$ordersMsgs item=alert} +
{$alert->text}
+ {/foreach} +
+{/if} + + + + + + + + + + + + + + + + {foreach from=$payments item=payment} + + + + + + + + + + + {/foreach} + +
BestellNr.IDStatusBetragWährungLocaleMethodeErstellt
{$payment->cOrderNumber} + {$payment->kID} + + {if $payment->cStatus == 'paid'} + bezahlt + {elseif $payment->cStatus == 'created'} + erstellt + {else} + {$payment->cStatus} + {/if} + {$payment->fAmount|number_format:2:',':''}{$payment->cCurrency}{$payment->cLocale}{$payment->cMethod}{"d. M Y H:i"|date:($payment->dCreatedAt|strtotime)}
+ + + \ No newline at end of file diff --git a/version/100/adminmenu/tpl/paymentmethods.tpl b/version/100/adminmenu/tpl/paymentmethods.tpl new file mode 100644 index 0000000..0064627 --- /dev/null +++ b/version/100/adminmenu/tpl/paymentmethods.tpl @@ -0,0 +1,48 @@ +

Account Status

+ + + + + + + + + +
Mode:{$profile->mode}Status:{$profile->status}Review:{$profile->review->status}
+ +
+ +{if $methods && $methods|count} + + + + + + + + + + + {foreach from=$methods item=method} + + + + + + + {/foreach} + +
BildIDNamePreise
{$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} +
+
+{else} +
Es konnten keine Methoden abgerufen werden.
+{/if} \ No newline at end of file diff --git a/version/100/class/Model/Payment.php b/version/100/class/Model/Payment.php index 9960426..8fee5b6 100644 --- a/version/100/class/Model/Payment.php +++ b/version/100/class/Model/Payment.php @@ -11,7 +11,7 @@ class Payment extends AbstractModel public static function updateFromPayment(\Mollie\Api\Resources\Order $oMolliePayment, $kBestellung = null, $hash = null) { - + $data = [ ':kID' => $oMolliePayment->id, ':kBestellung' => (int)$kBestellung ?: NULL, @@ -22,6 +22,7 @@ public static function updateFromPayment(\Mollie\Api\Resources\Order $oMolliePay ':cHash' => $hash, ':fAmount' => $oMolliePayment->amount->value, ':cOrderNumber' => $oMolliePayment->orderNumber, + ':cOrderNumber1' => $oMolliePayment->orderNumber, ':cCurrency' => $oMolliePayment->amount->currency, ':cMethod' => $oMolliePayment->method, ':cMethod1' => $oMolliePayment->method, @@ -40,12 +41,18 @@ public static function updateFromPayment(\Mollie\Api\Resources\Order $oMolliePay ]; 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, cStatus = :cStatus1, cMethod = :cMethod1, bCancelable = :bCancelable1, fAmountCaptured = :fAmountCaptured1, fAmountRefunded = :fAmountRefunded1', + . '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){ + + public static function getPayment($kBestellung) + { return \Shop::DB()->executeQueryPrepared('SELECT * FROM ' . self::TABLE . ' WHERE kBestellung = :kBestellung', [':kBestellung' => $kBestellung], 1); } - + + public static function getPaymentMollie($kID) + { + return \Shop::DB()->executeQueryPrepared('SELECT * FROM ' . self::TABLE . ' WHERE kID = :kID', [':kID' => $kID], 1); + } + } \ No newline at end of file diff --git a/version/100/paymentmethod/JTLMollie.php b/version/100/paymentmethod/JTLMollie.php index 80ba142..599b239 100644 --- a/version/100/paymentmethod/JTLMollie.php +++ b/version/100/paymentmethod/JTLMollie.php @@ -83,7 +83,7 @@ protected function getOrderData(Bestellung $order, $hash) 'redirectUrl' => (int)$this->duringCheckout ? Shop::getURL() . '/bestellabschluss.php?mollie=' . md5($hash) : $this->getReturnURL($order), 'webhookUrl' => $this->getNotificationURL($hash) ]; - + if (static::MOLLIE_METHOD !== '') { $data['method'] = static::MOLLIE_METHOD; } @@ -135,7 +135,7 @@ protected function getOrderData(Bestellung $order, $hash) ]; $line->vatRate = $oPosition->fMwSt; $line->vatAmount = (object)[ - 'value' => number_format($line->totalAmount->value - ($line->totalAmount->value / (1 + (float)$oPosition->fMwSt/100)), 2, '.', ''), + 'value' => number_format($line->totalAmount->value - ($line->totalAmount->value / (1 + (float)$oPosition->fMwSt / 100)), 2, '.', ''), 'currency' => $order->Waehrung->cISO, ]; break; @@ -157,7 +157,7 @@ protected function getOrderData(Bestellung $order, $hash) ]; $line->vatRate = $oPosition->fMwSt; $line->vatAmount = (object)[ - 'value' => number_format($line->totalAmount->value - ($line->totalAmount->value / (1 + (float)$oPosition->fMwSt/100)), 2, '.', ''), + 'value' => number_format($line->totalAmount->value - ($line->totalAmount->value / (1 + (float)$oPosition->fMwSt / 100)), 2, '.', ''), 'currency' => $order->Waehrung->cISO, ]; break; @@ -177,7 +177,7 @@ protected function getOrderData(Bestellung $order, $hash) ]; $line->vatRate = $oPosition->fMwSt; $line->vatAmount = (object)[ - 'value' => number_format($line->totalAmount->value - ($line->totalAmount->value / (1 + (float)$oPosition->fMwSt/100)), 2, '.', ''), + 'value' => number_format($line->totalAmount->value - ($line->totalAmount->value / (1 + (float)$oPosition->fMwSt / 100)), 2, '.', ''), 'currency' => $order->Waehrung->cISO, ]; break; @@ -211,15 +211,15 @@ protected function getOrderData(Bestellung $order, $hash) ]; $data['lines'][] = $line; } - + // RUNDUNGSAUSGLEICH $sum = .0; - foreach($data['lines'] as $line){ + foreach ($data['lines'] as $line) { $sum += (float)$line->totalAmount->value; } - if($sum <> (float)$data['amount']->value){ - $diff = (round((float)$data['amount']->value - $sum,2)); - if($diff !== 0){ + if ($sum <> (float)$data['amount']->value) { + $diff = (round((float)$data['amount']->value - $sum, 2)); + if ($diff !== 0) { $line = new stdClass(); $line->type = $diff > 0 ? \Mollie\Api\Types\OrderLineType::TYPE_SURCHARGE : \Mollie\Api\Types\OrderLineType::TYPE_DISCOUNT; $line->name = 'Rundungsausgleich'; @@ -244,7 +244,7 @@ protected function getOrderData(Bestellung $order, $hash) $data['lines'][] = $line; } } - + return $data; } @@ -256,37 +256,53 @@ protected function getOrderData(Bestellung $order, $hash) */ public function preparePaymentProcess($order) { + $logData = '#' . $order->kBestellung . "§" . $order->cBestellNr; try { $payment = \ws_mollie\Model\Payment::getPayment($order->kBestellung); - if($payment && in_array($payment->cStatus, [MolliePaymentStatus::STATUS_OPEN, 'created']) && $payment->cCheckoutURL){ - if(!$this->duringCheckout){ + if ($payment && in_array($payment->cStatus, [MolliePaymentStatus::STATUS_OPEN, 'created']) && $payment->cCheckoutURL) { + $logData .= '$' . $payment->kID; + if (!$this->duringCheckout) { Session::getInstance()->cleanUp(); } header('Location: ' . $payment->cCheckoutURL); exit(); } - }catch(\Exception $e){ - $this->doLog("Get Payment Error: " . $e->getMessage() . ". Create new ORDER..."); + } catch (\Exception $e) { + $this->doLog("Get Payment Error: " . $e->getMessage() . ". Create new ORDER...", $logData); } - + try { $hash = $this->generateHash($order); $oMolliePayment = self::API()->orders->create($this->getOrderData($order, $hash)); $_SESSION['oMolliePayment'] = $oMolliePayment; - $this->doLog('Mollie Create Payment Redirect: ' . $oMolliePayment->getCheckoutUrl() . "
" . print_r($oMolliePayment, 1) . "
", LOGLEVEL_DEBUG); + $logData .= '$' . $oMolliePayment->id; + $this->doLog('Mollie Create Payment Redirect: ' . $oMolliePayment->getCheckoutUrl() . "
" . print_r($oMolliePayment, 1) . "
", $logData, LOGLEVEL_DEBUG); \ws_mollie\Model\Payment::updateFromPayment($oMolliePayment, $order->kBestellung, md5($hash)); Shop::Smarty()->assign('oMolliePayment', $oMolliePayment); - if(!$this->duringCheckout){ + if (!$this->duringCheckout) { Session::getInstance()->cleanUp(); } header('Location: ' . $oMolliePayment->getCheckoutUrl()); exit(); } catch (\Mollie\Api\Exceptions\ApiException $e) { Shop::Smarty()->assign('oMollieException', $e); - $this->doLog("Create Payment Error: " . $e->getMessage() . '
' . print_r($data, 1) . '
'); + $this->doLog("Create Payment Error: " . $e->getMessage() . '
' . print_r($data, 1) . '
', $logData); } } + /** + * @param string $msg + * @param null $data + * @param int $level + * @return $this + */ + public function doLog($msg, $data = null, $level = LOGLEVEL_NOTICE) + { + ZahlungsLog::add($this->moduleID, $msg, $data, $level); + + return $this; + } + /** * @param Bestellung $order * @param string $hash @@ -295,13 +311,17 @@ public function preparePaymentProcess($order) public function handleNotification($order, $hash, $args) { \ws_mollie\Helper::autoload(); + $logData = '#' . $order->kBestellung . "§" . $order->cBestellNr; try { $oMolliePayment = self::API()->orders->get($args['id']); - $this->doLog('Received Notification
' . print_r([$hash, $args, $oMolliePayment], 1) . '
', LOGLEVEL_DEBUG); + $logData .= '$' . $oMolliePayment->id; + $this->doLog('Received Notification
' . print_r([$hash, $args, $oMolliePayment], 1) . '
', $logData, LOGLEVEL_DEBUG); + $oMolliePayment->orderNumber = $order->cBestellNr; \ws_mollie\Model\Payment::updateFromPayment($oMolliePayment, $order->kBestellung); if ($oMolliePayment->status === MolliePaymentStatus::STATUS_PAID) { + $this->doLog('PaymentStatus: PAID => Zahlungseingang', $logData, LOGLEVEL_DEBUG); $oIncomingPayment = new stdClass(); $oIncomingPayment->fBetrag = $order->fGesamtsummeKundenwaehrung; $oIncomingPayment->cISO = $order->Waehrung->cISO; @@ -311,7 +331,7 @@ public function handleNotification($order, $hash, $args) } } catch (\Exception $e) { - $this->doLog($e->getMessage()); + $this->doLog($e->getMessage(), $logData); } } @@ -324,14 +344,16 @@ public function handleNotification($order, $hash, $args) */ public function finalizeOrder($order, $hash, $args) { + $logData = '#' . $order->kBestellung . "§" . $order->cBestellNr; try { \ws_mollie\Helper::autoload(); $oMolliePayment = self::API()->orders->get($args['id'], ['embed' => 'payments']); - $this->doLog('Received Notification Finalize Order
' . print_r([$hash, $args, $oMolliePayment], 1) . '
', LOGLEVEL_DEBUG); + $logData .= '$' . $oMolliePayment->id; + $this->doLog('Received Notification Finalize Order
' . print_r([$hash, $args, $oMolliePayment], 1) . '
', $logData, LOGLEVEL_DEBUG); \ws_mollie\Model\Payment::updateFromPayment($oMolliePayment, $order->kBestellung); return !in_array($oMolliePayment->status, [MolliePaymentStatus::STATUS_FAILED, MolliePaymentStatus::STATUS_CANCELED, MolliePaymentStatus::STATUS_EXPIRED, MolliePaymentStatus::STATUS_OPEN]); } catch (\Exception $e) { - $this->doLog($e->getMessage()); + $this->doLog($e->getMessage(), $logData); } return false; } @@ -345,19 +367,28 @@ public function canPayAgain() } - public static function getLocale($cISOSprache, $country = null){ - switch($cISOSprache){ + public static function getLocale($cISOSprache, $country = null) + { + switch ($cISOSprache) { case "ger": - if($country === "AT"){ return "de_AT"; } - if($country === "CH"){ return "de_CH"; } + if ($country === "AT") { + return "de_AT"; + } + if ($country === "CH") { + return "de_CH"; + } return "de_DE"; case "eng": return "en_US"; case "fre": - if($country === "BE"){ return "fr_BE"; } + if ($country === "BE") { + return "fr_BE"; + } return "fr_FR"; case "dut": - if($country === "BE"){ return "nl_BE"; } + if ($country === "BE") { + return "nl_BE"; + } return "nl_NL"; case "spa": return "es_ES"; @@ -383,16 +414,18 @@ public static function getLocale($cISOSprache, $country = null){ return "en_US"; } } - + protected static $_possiblePaymentMethods = []; - 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->all(['amount' => ['currency' => $currency, 'value' => number_format($amount,2,'.','')], 'billingCountry' => $_SESSION['Kunde']->cLand, 'locale' => $locale, 'include' => 'pricing,issuers', 'resource' => 'orders']); + + 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->all(['amount' => ['currency' => $currency, 'value' => number_format($amount, 2, '.', '')], 'billingCountry' => $_SESSION['Kunde']->cLand, 'locale' => $locale, 'include' => 'pricing,issuers', 'resource' => 'orders']); } - if($method !== null){ - foreach(self::$_possiblePaymentMethods[$key] as $m){ - if($m->id === $method){ + if ($method !== null) { + foreach (self::$_possiblePaymentMethods[$key] as $m) { + if ($m->id === $method) { return $m; } } @@ -401,17 +434,18 @@ protected static function PossiblePaymentMethods($method, $locale, $billingCount return self::$_possiblePaymentMethods[$key]; } - protected function updatePaymentMethod($cISOSprache, $method){ - if($this->cBild === ''){ + protected function updatePaymentMethod($cISOSprache, $method) + { + if ($this->cBild === '') { \Shop::DB()->executeQueryPrepared("UPDATE tzahlungsart SET cBild = :cBild WHERE cModulId = :cModulId", [':cBild' => $method->image->size2x, ':cModulId' => $this->cModulId], 3); } - if($za = \Shop::DB()->executeQueryPrepared('SELECT kZahlungsart FROM tzahlungsart WHERE cModulID = :cModulID',[':cModulID' => $this->moduleID],1)){ + if ($za = \Shop::DB()->executeQueryPrepared('SELECT kZahlungsart FROM tzahlungsart WHERE cModulID = :cModulID', [':cModulID' => $this->moduleID], 1)) { $x = \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);", [ ':kZahlungsart' => (int)$za->kZahlungsart, - ':cISOSprache' => $cISOSprache, + ':cISOSprache' => $cISOSprache, ':cName' => utf8_decode($method->description), - ':cGebuehrname' => '', - ':cHinweisText' => '', + ':cGebuehrname' => '', + ':cHinweisText' => '', 'cName1' => $method->description, ], 3); } @@ -429,7 +463,7 @@ public function isSelectable() if (static::MOLLIE_METHOD !== '') { try { $method = self::PossiblePaymentMethods(static::MOLLIE_METHOD, $locale, $_SESSION['Kunde']->cLand, $_SESSION['Waehrung']->cISO, $_SESSION['Warenkorb']->gibGesamtsummeWaren() * $_SESSION['Waehrung']->fFaktor); - if($method !== null){ + if ($method !== null) { $this->updatePaymentMethod($_SESSION['cISOSprache'], $method); $this->cBild = $method->image->size2x; return true; From ff0c278ed0c83b8dc3abd5d41062e6b343831253 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Thu, 10 Jan 2019 17:03:13 +0100 Subject: [PATCH 010/280] #5, #4 --- info.xml | 1 + version/100/adminmenu/tpl/order.tpl | 16 ++++- version/100/adminmenu/tpl/orders.tpl | 2 +- version/100/class/Model/Payment.php | 5 ++ version/100/frontend/131_globalinclude.php | 62 ++++++++++++++++--- version/100/frontend/144_notify.php | 58 +++++++++++++++++ version/100/paymentmethod/JTLMollie.php | 39 ++++++------ .../paymentmethod/JTLMollieBanktransfer.php | 2 +- .../100/paymentmethod/JTLMollieGiropay.php | 2 +- version/100/paymentmethod/JTLMollieIDEAL.php | 8 +-- .../100/paymentmethod/JTLMollieINGHomePay.php | 8 +-- version/100/paymentmethod/JTLMollieKBC.php | 8 +-- .../paymentmethod/JTLMollieKlarnaPayLater.php | 8 +-- .../paymentmethod/JTLMollieKlarnaSliceIt.php | 8 +-- version/100/paymentmethod/JTLMolliePayPal.php | 8 +-- .../paymentmethod/JTLMolliePaysafecard.php | 8 +-- version/100/paymentmethod/JTLMollieSofort.php | 8 +-- 17 files changed, 163 insertions(+), 88 deletions(-) create mode 100644 version/100/frontend/144_notify.php diff --git a/info.xml b/info.xml index 37fd020..c57363b 100644 --- a/info.xml +++ b/info.xml @@ -13,6 +13,7 @@ 131_globalinclude.php + 144_notify.php diff --git a/version/100/adminmenu/tpl/order.tpl b/version/100/adminmenu/tpl/order.tpl index 4cf808b..e0d60dd 100644 --- a/version/100/adminmenu/tpl/order.tpl +++ b/version/100/adminmenu/tpl/order.tpl @@ -111,7 +111,7 @@ {$log->cModulId} -
+
{$log->cLog}
@@ -120,6 +120,20 @@ {/foreach} + + {*$logs|var_dump} {$payment|var_dump} {$oBestellung|var_dump} diff --git a/version/100/adminmenu/tpl/orders.tpl b/version/100/adminmenu/tpl/orders.tpl index 7009c18..6afdf21 100644 --- a/version/100/adminmenu/tpl/orders.tpl +++ b/version/100/adminmenu/tpl/orders.tpl @@ -7,7 +7,7 @@
{/if} - +
diff --git a/version/100/class/Model/Payment.php b/version/100/class/Model/Payment.php index 8fee5b6..16bc0b4 100644 --- a/version/100/class/Model/Payment.php +++ b/version/100/class/Model/Payment.php @@ -55,4 +55,9 @@ public static function getPaymentMollie($kID) return \Shop::DB()->executeQueryPrepared('SELECT * FROM ' . self::TABLE . ' WHERE kID = :kID', [':kID' => $kID], 1); } + public static function getPaymentHash($cHash) + { + return \Shop::DB()->executeQueryPrepared('SELECT * FROM ' . self::TABLE . ' WHERE cHash = :cHash', [':cHash' => $cHash], 1); + } + } \ No newline at end of file diff --git a/version/100/frontend/131_globalinclude.php b/version/100/frontend/131_globalinclude.php index cd23d96..80b62e2 100644 --- a/version/100/frontend/131_globalinclude.php +++ b/version/100/frontend/131_globalinclude.php @@ -1,25 +1,67 @@ executeQueryPrepared("SELECT * FROM " . \ws_mollie\Model\Payment::TABLE . " WHERE cHash = :cHash", [':cHash' => $_REQUEST['mollie']], 1); - if((int)$payment->kBestellung){ + if ((int)$payment->kBestellung) { + + $bestellid = \Shop::DB()->executeQueryPrepared("SELECT * FROM tbestellid WHERE kBestellung = :kBestellung", [':kBestellung' => $payment->kBestellung], 1); - if($bestellid){ - header('Location: ' . SHop::getURL() . '/bestellabschluss.php?i='.$bestellid->cId); + if ($bestellid) { + header('Location: ' . SHop::getURL() . '/bestellabschluss.php?i=' . $bestellid->cId); exit(); } + } elseif ($payment) { + + $mollie = new \Mollie\Api\MollieApiClient(); + $mollie->setApiKey(\ws_mollie\Helper::getSetting("api_key")); + + $order = $mollie->orders->get($payment->kID); + + if ($order) { + $session = Session::getInstance(); + require_once PFAD_ROOT . 'includes/bestellabschluss_inc.php'; + require_once PFAD_ROOT . 'includes/mailTools.php'; + + $oBestellung = fakeBestellung(); + $oBestellung = finalisiereBestellung(); + + $order->orderNumber = $oBestellung->cBestellNr; + \ws_mollie\Model\Payment::updateFromPayment($order, $oBestellung->kBestellung); + + $bestellid = (isset($oBestellung->kBestellung) && $oBestellung->kBestellung > 0) + ? Shop::DB()->select('tbestellid', 'kBestellung', $oBestellung->kBestellung) + : false; + + if ($bestellid) { + + $session->cleanUp(); + $linkHelper = LinkHelper::getInstance(); + + $orderCompleteURL = $linkHelper->getStaticRoute('bestellabschluss.php', true); + $successPaymentURL = (!empty($bestellid->cId)) ? + ($orderCompleteURL . '?i=' . $bestellid->cId) + : Shop::getURL(); + header('Location: ' . $successPaymentURL, 302); + exit(); + } + } } } + + ob_end_flush(); + } catch (Exception $e) { \ws_mollie\Helper::logExc($e); } \ No newline at end of file diff --git a/version/100/frontend/144_notify.php b/version/100/frontend/144_notify.php new file mode 100644 index 0000000..c75239d --- /dev/null +++ b/version/100/frontend/144_notify.php @@ -0,0 +1,58 @@ + Update Payment, stop skript + * - ELSE weiter + */ + +if (array_key_exists('hash', $_REQUEST)) { + require_once __DIR__ . '/../class/Helper.php'; + try { + if (!\ws_mollie\Helper::init()) { + // return; + } + + $pza = Shop::DB()->select('tpluginzahlungsartklasse', 'cClassName', 'JTLMollie'); + if (!$pza) { + return; + } + require_once __DIR__ . '/../paymentmethod/JTLMollie.php'; + + $oPaymentMethod = new JTLMollie($pza->cModulId); + $payment = \ws_mollie\Model\Payment::getPaymentHash($_REQUEST['hash']); + + if ($payment && $payment->kBestellung) { + + $mollie = new \Mollie\Api\MollieApiClient(); + $mollie->setApiKey(\ws_mollie\Helper::getSetting("api_key")); + $order = $mollie->orders->get($payment->kID); + $oBestellung = new Bestellung($payment->kBestellung); + $order->orderNumber = $oBestellung->cBestellNr; + \ws_mollie\Model\Payment::updateFromPayment($order, $payment->kBestellung); + + $logData = '#' . $payment->kBestellung . '$' . $payment->kID . "§" . $oBestellung->cBestellNr; + $oPaymentMethod->doLog('Received Notification
' . print_r([$order, $payment], 1) . '
', $logData, LOGLEVEL_DEBUG); + + switch ($order->status) { + case \Mollie\Api\Types\PaymentStatus::STATUS_PAID: + $oPaymentMethod->doLog('PaymentStatus: ' . $order->status . ' => Zahlungseingang (' . $order->amount->value . ')', $logData, LOGLEVEL_DEBUG); + $oIncomingPayment = new stdClass(); + $oIncomingPayment->fBetrag = $oMolliePayment->amount->value; + $oIncomingPayment->cISO = $oMolliePayment->amount->curreny; + $oIncomingPayment->cHinweis = $oMolliePayment->id; + $oPaymentMethod->addIncomingPayment($oBestellung, $oIncomingPayment); + case \Mollie\Api\Types\PaymentStatus::STATUS_AUTHORIZED: + $oPaymentMethod->doLog('PaymentStatus: ' . $order->status . ' => Bestellung bezahlt', $logData, LOGLEVEL_DEBUG); + $oPaymentMethod->setOrderStatusToPaid($oBestellung); + break; + } + exit(); + } + + + } catch (Exception $e) { + \ws_mollie\Helper::logExc($e); + } + +} diff --git a/version/100/paymentmethod/JTLMollie.php b/version/100/paymentmethod/JTLMollie.php index 599b239..1978e3e 100644 --- a/version/100/paymentmethod/JTLMollie.php +++ b/version/100/paymentmethod/JTLMollie.php @@ -1,16 +1,12 @@ [], 'billingAddress' => new stdClass(), 'redirectUrl' => (int)$this->duringCheckout ? Shop::getURL() . '/bestellabschluss.php?mollie=' . md5($hash) : $this->getReturnURL($order), - 'webhookUrl' => $this->getNotificationURL($hash) + 'webhookUrl' => $this->getNotificationURL($hash) . '&hash=' . md5($hash), ]; if (static::MOLLIE_METHOD !== '') { @@ -312,22 +308,28 @@ public function handleNotification($order, $hash, $args) { \ws_mollie\Helper::autoload(); $logData = '#' . $order->kBestellung . "§" . $order->cBestellNr; + $this->doLog('Received Notification
' . print_r([$hash, $args], 1) . '
', $logData, LOGLEVEL_DEBUG); + try { $oMolliePayment = self::API()->orders->get($args['id']); $logData .= '$' . $oMolliePayment->id; - $this->doLog('Received Notification
' . print_r([$hash, $args, $oMolliePayment], 1) . '
', $logData, LOGLEVEL_DEBUG); + $this->doLog('Got Mollie Payment:
' . print_r($oMolliePayment, 1) . '
', $logData, LOGLEVEL_DEBUG); $oMolliePayment->orderNumber = $order->cBestellNr; \ws_mollie\Model\Payment::updateFromPayment($oMolliePayment, $order->kBestellung); - if ($oMolliePayment->status === MolliePaymentStatus::STATUS_PAID) { - $this->doLog('PaymentStatus: PAID => Zahlungseingang', $logData, LOGLEVEL_DEBUG); - $oIncomingPayment = new stdClass(); - $oIncomingPayment->fBetrag = $order->fGesamtsummeKundenwaehrung; - $oIncomingPayment->cISO = $order->Waehrung->cISO; - $oIncomingPayment->cHinweis = $oMolliePayment->id; - $this->addIncomingPayment($order, $oIncomingPayment); - $this->setOrderStatusToPaid($order); + switch ($oMolliePayment->status) { + case MolliePaymentStatus::STATUS_PAID: + $this->doLog('PaymentStatus: ' . $oMolliePayment->status . ' => Zahlungseingang (' . $oMolliePayment->amount->value . ')', $logData, LOGLEVEL_DEBUG); + $oIncomingPayment = new stdClass(); + $oIncomingPayment->fBetrag = $oMolliePayment->amount->value; + $oIncomingPayment->cISO = $oMolliePayment->amount->curreny; + $oIncomingPayment->cHinweis = $oMolliePayment->id; + $this->addIncomingPayment($order, $oIncomingPayment); + case MolliePaymentStatus::STATUS_AUTHORIZED: + $this->doLog('PaymentStatus: ' . $oMolliePayment->status . ' => Bestellung bezahlt', $logData, LOGLEVEL_DEBUG); + $this->setOrderStatusToPaid($order); + break; } } catch (\Exception $e) { @@ -335,6 +337,7 @@ public function handleNotification($order, $hash, $args) } } + /** * @param Bestellung $order * @param string $hash @@ -351,7 +354,7 @@ public function finalizeOrder($order, $hash, $args) $logData .= '$' . $oMolliePayment->id; $this->doLog('Received Notification Finalize Order
' . print_r([$hash, $args, $oMolliePayment], 1) . '
', $logData, LOGLEVEL_DEBUG); \ws_mollie\Model\Payment::updateFromPayment($oMolliePayment, $order->kBestellung); - return !in_array($oMolliePayment->status, [MolliePaymentStatus::STATUS_FAILED, MolliePaymentStatus::STATUS_CANCELED, MolliePaymentStatus::STATUS_EXPIRED, MolliePaymentStatus::STATUS_OPEN]); + return in_array($oMolliePayment->status, [MolliePaymentStatus::STATUS_PAID, MolliePaymentStatus::STATUS_AUTHORIZED, MolliePaymentStatus::STATUS_PENDING]); } catch (\Exception $e) { $this->doLog($e->getMessage(), $logData); } diff --git a/version/100/paymentmethod/JTLMollieBanktransfer.php b/version/100/paymentmethod/JTLMollieBanktransfer.php index 23d8c4a..6fc14eb 100644 --- a/version/100/paymentmethod/JTLMollieBanktransfer.php +++ b/version/100/paymentmethod/JTLMollieBanktransfer.php @@ -1,5 +1,5 @@ Date: Fri, 11 Jan 2019 10:24:24 +0100 Subject: [PATCH 011/280] abschluss/statusseite --- version/100/class/Mollie.php | 43 ++++++++++++++++++++++ version/100/frontend/131_globalinclude.php | 30 ++------------- version/100/frontend/144_notify.php | 10 ++--- 3 files changed, 50 insertions(+), 33 deletions(-) create mode 100644 version/100/class/Mollie.php diff --git a/version/100/class/Mollie.php b/version/100/class/Mollie.php new file mode 100644 index 0000000..763d30a --- /dev/null +++ b/version/100/class/Mollie.php @@ -0,0 +1,43 @@ +getValue(CONF_KAUFABWICKLUNG, 'bestellabschluss_abschlussseite'); + if ($mode == 'S') { // Statusseite + + $bestellstatus = \Shop::DB()->select('tbestellstatus', 'kBestellung', (int)$kBestellung); + $url = \Shop::getURL() . '/status.php?uid=' . $bestellstatus->cUID; + + } else { // Abschlussseite + $bestellid = \Shop::DB()->select("tbestellid ", 'kBestellung', (int)$kBestellung); + $url = \Shop::getURL() . '/bestellabschluss.php?i=' . $bestellid->cId; + } + + if ($redirect) { + header('Location: ' . $url); + exit(); + } + + return $url; + + + } + +} \ No newline at end of file diff --git a/version/100/frontend/131_globalinclude.php b/version/100/frontend/131_globalinclude.php index 80b62e2..424b06f 100644 --- a/version/100/frontend/131_globalinclude.php +++ b/version/100/frontend/131_globalinclude.php @@ -8,20 +8,15 @@ require_once __DIR__ . '/../class/Helper.php'; try { - if (!\ws_mollie\Helper::init()) { - // return; - } + \ws_mollie\Helper::init(); + ob_start(); if (array_key_exists('mollie', $_REQUEST)) { $payment = \Shop::DB()->executeQueryPrepared("SELECT * FROM " . \ws_mollie\Model\Payment::TABLE . " WHERE cHash = :cHash", [':cHash' => $_REQUEST['mollie']], 1); if ((int)$payment->kBestellung) { + \ws_mollie\Mollie::getOrderCompletedRedirect($payment->kBestellung, true); - $bestellid = \Shop::DB()->executeQueryPrepared("SELECT * FROM tbestellid WHERE kBestellung = :kBestellung", [':kBestellung' => $payment->kBestellung], 1); - if ($bestellid) { - header('Location: ' . SHop::getURL() . '/bestellabschluss.php?i=' . $bestellid->cId); - exit(); - } } elseif ($payment) { $mollie = new \Mollie\Api\MollieApiClient(); @@ -39,29 +34,12 @@ $order->orderNumber = $oBestellung->cBestellNr; \ws_mollie\Model\Payment::updateFromPayment($order, $oBestellung->kBestellung); + \ws_mollie\Mollie::getOrderCompletedRedirect($oBestellung->kBestellung, true); - $bestellid = (isset($oBestellung->kBestellung) && $oBestellung->kBestellung > 0) - ? Shop::DB()->select('tbestellid', 'kBestellung', $oBestellung->kBestellung) - : false; - - if ($bestellid) { - - $session->cleanUp(); - $linkHelper = LinkHelper::getInstance(); - - $orderCompleteURL = $linkHelper->getStaticRoute('bestellabschluss.php', true); - $successPaymentURL = (!empty($bestellid->cId)) ? - ($orderCompleteURL . '?i=' . $bestellid->cId) - : Shop::getURL(); - header('Location: ' . $successPaymentURL, 302); - exit(); - } } } } - ob_end_flush(); - } catch (Exception $e) { \ws_mollie\Helper::logExc($e); } \ No newline at end of file diff --git a/version/100/frontend/144_notify.php b/version/100/frontend/144_notify.php index c75239d..15cc3ab 100644 --- a/version/100/frontend/144_notify.php +++ b/version/100/frontend/144_notify.php @@ -3,15 +3,13 @@ /** * Da Webhook nicht 100% sicher vor dem Redirekt ausgeführt wird: * - IF Bestellung bereits abgesclossen ? => Update Payment, stop skript - * - ELSE weiter + * - ELSE weiter mit der */ if (array_key_exists('hash', $_REQUEST)) { require_once __DIR__ . '/../class/Helper.php'; try { - if (!\ws_mollie\Helper::init()) { - // return; - } + \ws_mollie\Helper::init(); $pza = Shop::DB()->select('tpluginzahlungsartklasse', 'cClassName', 'JTLMollie'); if (!$pza) { @@ -47,12 +45,10 @@ $oPaymentMethod->setOrderStatusToPaid($oBestellung); break; } + // stop notify.php script exit(); } - - } catch (Exception $e) { \ws_mollie\Helper::logExc($e); } - } From b0d1f9323a18c9a4d8efd46d36987f9e310be934 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Fri, 11 Jan 2019 11:39:23 +0100 Subject: [PATCH 012/280] TSCode, Method Sync option --- info.xml | 77 +++++++++++++++---------- version/100/paymentmethod/JTLMollie.php | 28 ++++++++- 2 files changed, 70 insertions(+), 35 deletions(-) diff --git a/info.xml b/info.xml index c57363b..73baf29 100644 --- a/info.xml +++ b/info.xml @@ -33,6 +33,19 @@ Füge hier deinen mollie API Key ein api_key + + Zahlungsart Daten syncronisiernen + Lädt Name / Bild für die jeweilige Sprache automatisch von mollie, und speichert diese + in der Datenbank + + paymentmethod_sync + + + + + + + @@ -62,13 +75,13 @@ Bezahlen Sie bequem mit verschiedenen Zahlungsmethoden. - + mollie Kreditkarte 2 0 mollie.com - OTHER + CREDIT_CARD 0 1 0 @@ -81,10 +94,10 @@ Bezahlen Sie bequem mit Kreditkarte. - + mollie Bitcoin - 2 + 3 0 mollie.com OTHER @@ -100,10 +113,10 @@ Bezahlen Sie bequem mit Bitcoins. - + mollie Bancontact - 2 + 4 0 mollie.com OTHER @@ -119,10 +132,10 @@ Bezahlen Sie bequem mit Bancontact. - + mollie Banktransfer - 2 + 5 0 mollie.com OTHER @@ -138,10 +151,10 @@ Bezahlen Sie bequem mit SEPA Überweisung. - + mollie Belfius - 2 + 6 0 mollie.com OTHER @@ -157,13 +170,13 @@ Bezahlen Sie bequem mit Belfius. - + mollie DirectDebit - 2 + 7 0 mollie.com - OTHER + DIRECT_DEBIT 0 1 0 @@ -176,7 +189,7 @@ Bezahlen Sie bequem mit SEPA Lastschrift. - + mollie EPS 2 @@ -195,10 +208,10 @@ Bezahlen Sie bequem mit EPS. - + mollie Giftcard - 2 + 8 0 mollie.com OTHER @@ -214,13 +227,13 @@ Bezahlen Sie bequem mit Gift cards. - + mollie Giropay - 2 + 9 0 mollie.com - OTHER + GIROPAY 0 1 0 @@ -236,7 +249,7 @@ mollie iDEAL - 2 + 10 0 mollie.com OTHER @@ -255,7 +268,7 @@ mollie ING HomePay - 2 + 11 0 mollie.com OTHER @@ -274,7 +287,7 @@ mollie KBC - 2 + 12 0 mollie.com OTHER @@ -293,10 +306,10 @@ mollie PayPal - 2 + 13 0 mollie.com - OTHER + PAYPAL 0 1 0 @@ -312,7 +325,7 @@ mollie paysafecard - 2 + 14 0 mollie.com OTHER @@ -331,10 +344,10 @@ mollie SOFORT - 2 + 15 0 mollie.com - OTHER + DIRECT_E_BANKING 0 1 0 @@ -350,10 +363,10 @@ mollie Klarna Pay Later - 2 + 16 0 mollie.com - OTHER + INVOICE 0 1 0 @@ -369,10 +382,10 @@ mollie Klarna Slice It - 2 + 17 0 mollie.com - OTHER + FINANCING 0 1 0 @@ -386,7 +399,7 @@ - + 405 diff --git a/version/100/paymentmethod/JTLMollie.php b/version/100/paymentmethod/JTLMollie.php index 1978e3e..cf30be8 100644 --- a/version/100/paymentmethod/JTLMollie.php +++ b/version/100/paymentmethod/JTLMollie.php @@ -418,8 +418,21 @@ public static function getLocale($cISOSprache, $country = null) } } + /** + * @var array + */ protected static $_possiblePaymentMethods = []; + /** + * @param $method + * @param $locale + * @param $billingCountry + * @param $currency + * @param $amount + * @return mixed|null + * @throws \Mollie\Api\Exceptions\ApiException + * @throws \Mollie\Api\Exceptions\IncompatiblePlatform + */ protected static function PossiblePaymentMethods($method, $locale, $billingCountry, $currency, $amount) { $key = md5(serialize([$locale, $billingCountry, $amount, $currency])); @@ -437,18 +450,27 @@ protected static function PossiblePaymentMethods($method, $locale, $billingCount return self::$_possiblePaymentMethods[$key]; } + /** + * @param $cISOSprache + * @param $method + */ protected function updatePaymentMethod($cISOSprache, $method) { - if ($this->cBild === '') { - \Shop::DB()->executeQueryPrepared("UPDATE tzahlungsart SET cBild = :cBild WHERE cModulId = :cModulId", [':cBild' => $method->image->size2x, ':cModulId' => $this->cModulId], 3); + if (ws_mollie\Helper::getSetting('paymentmethod_sync') === 'N') { + return; + } + $size = ws_mollie\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)) { - $x = \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);", [ + \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); } From 159bf15acf84f9c7ac2a905c01e3093d5ac6a7bb Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Fri, 11 Jan 2019 11:54:42 +0100 Subject: [PATCH 013/280] fix incoming payment --- version/100/frontend/144_notify.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/version/100/frontend/144_notify.php b/version/100/frontend/144_notify.php index 15cc3ab..f115dc3 100644 --- a/version/100/frontend/144_notify.php +++ b/version/100/frontend/144_notify.php @@ -36,9 +36,9 @@ case \Mollie\Api\Types\PaymentStatus::STATUS_PAID: $oPaymentMethod->doLog('PaymentStatus: ' . $order->status . ' => Zahlungseingang (' . $order->amount->value . ')', $logData, LOGLEVEL_DEBUG); $oIncomingPayment = new stdClass(); - $oIncomingPayment->fBetrag = $oMolliePayment->amount->value; - $oIncomingPayment->cISO = $oMolliePayment->amount->curreny; - $oIncomingPayment->cHinweis = $oMolliePayment->id; + $oIncomingPayment->fBetrag = $order->amount->value; + $oIncomingPayment->cISO = $order->amount->curreny; + $oIncomingPayment->cHinweis = $order->id; $oPaymentMethod->addIncomingPayment($oBestellung, $oIncomingPayment); case \Mollie\Api\Types\PaymentStatus::STATUS_AUTHORIZED: $oPaymentMethod->doLog('PaymentStatus: ' . $order->status . ' => Bestellung bezahlt', $logData, LOGLEVEL_DEBUG); From 1eabda8e52e815ac212d97658d70e43d9d3860a9 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Mon, 14 Jan 2019 18:08:44 +0100 Subject: [PATCH 014/280] shipments --- info.xml | 1 + version/100/adminmenu/orders.php | 86 ++++++++++++++++++++++++- version/100/adminmenu/tpl/order.tpl | 41 ++++++++++++ version/100/adminmenu/tpl/orders.tpl | 52 ++++++++++++--- version/100/class/Model/Payment.php | 18 +++++- version/100/class/Mollie.php | 46 ++++++++++++- version/100/frontend/144_notify.php | 7 +- version/100/frontend/181_sync.php | 70 ++++++++++++++++++++ version/100/paymentmethod/JTLMollie.php | 9 +-- 9 files changed, 309 insertions(+), 21 deletions(-) create mode 100644 version/100/frontend/181_sync.php diff --git a/info.xml b/info.xml index 73baf29..eda52ab 100644 --- a/info.xml +++ b/info.xml @@ -14,6 +14,7 @@ 131_globalinclude.php 144_notify.php + 181_sync.php diff --git a/version/100/adminmenu/orders.php b/version/100/adminmenu/orders.php index f9d77c9..b6d2c22 100644 --- a/version/100/adminmenu/orders.php +++ b/version/100/adminmenu/orders.php @@ -13,6 +13,81 @@ if (array_key_exists('action', $_REQUEST)) { switch ($_REQUEST['action']) { + case 'capture': + if (!array_key_exists('id', $_REQUEST)) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; + break; + } + $payment = \ws_mollie\Model\Payment::getPaymentMollie($_REQUEST['id']); + if (!$payment) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; + break; + } + $mollie = new \Mollie\Api\MollieApiClient(); + $mollie->setApiKey(\ws_mollie\Helper::getSetting("api_key")); + $order = $mollie->orders->get($_REQUEST['id']); + if ($order->status !== \Mollie\Api\Types\OrderStatus::STATUS_AUTHORIZED && $order->status !== \Mollie\Api\Types\OrderStatus::STATUS_SHIPPING) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Nur authorisierte Zahlungen können erfasst werden!']; + break; + } + + $oBestellung = new Bestellung($payment->kBestellung, true); + if (!$oBestellung->kBestellung) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung konnte nicht geladen werden!']; + break; + } + + $logData = '#' . $payment->kBestellung . '$' . $payment->kID . "§" . $oBestellung->cBestellNr; + + $options = ['lines' => []]; + if ($oBestellung->cTracking) { + $tracking = new stdClass(); + $tracking->carrier = $oBestellung->cVersandartName; + $tracking->url = $oBestellung->cTrackingURL; + $tracking->code = $oBestellung->cTracking; + $options['tracking'] = $tracking; + } + + if ((int)$oBestellung->cStatus === BESTELLUNG_STATUS_VERSANDT) { + // CAPTURE ALL + $shipment = $mollie->shipments->createFor($order, $options); + $ordersMsgs[] = (object)['type' => 'success', 'text' => 'Zahlung wurde erfolgreich erfasst!']; + \ws_mollie\Mollie::JTLMollie()->doLog('Shipment created
' . print_r(['options' => $options, 'shipment' => $shipment], 1) . '
', $logData); + } elseif ((int)$oBestellung->cStatus === BESTELLUNG_STATUS_TEILVERSANDT) { + // CAPTURE Lieferschein + + $lines = []; + /** + * @var int $i + * @var \Mollie\Api\Resources\OrderLine $line + */ + foreach ($order->lines as $i => $line) { + if ($line->quantity <= $line->quantityShipped) { + continue; + } + if (($quantity = \ws_mollie\Mollie::getBestellPosSent($line->sku, $oBestellung)) !== false && $quantity > 0) { + $lines[] = (object)[ + 'id' => $line->id, + 'quantity' => $quantity, + 'amount' => (object)[ + 'currency' => $line->totalAmount->currency, + 'value' => number_format($quantity * $line->unitPrice->value, 2), + ], + ]; + } + } + if (count($lines)) { + $options = ['lines' => $lines]; + var_dump($lines); + $shipment = $mollie->shipments->createFor($order, $options); + \ws_mollie\Mollie::JTLMollie()->doLog('Partially Shipment created
' . print_r(['options' => $options, 'shipment' => $shipment], 1) . '
', $logData); + } else { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine Positionen zur Teillieferung gefunden!']; + + } + } + + case 'order': if (!array_key_exists('id', $_REQUEST)) { $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; @@ -43,7 +118,8 @@ Shop::Smarty()->assign('payment', $payment) ->assign('oBestellung', $oBestellung) ->assign('order', $order) - ->assign('logs', $logs); + ->assign('logs', $logs) + ->assign('ordersMsgs', $ordersMsgs); Shop::Smarty()->display($oPlugin->cAdminmenuPfad . '/tpl/order.tpl'); return; } @@ -51,6 +127,9 @@ $payments = Shop::DB()->executeQueryPrepared("SELECT * FROM xplugin_ws_mollie_payments", [], 2); + foreach ($payments as $i => $payment) { + $payments[$i]->oBestellung = new Bestellung($payment->kBestellung, false); + } Shop::Smarty()->assign('payments', $payments) ->assign('ordersMsgs', $ordersMsgs); @@ -58,6 +137,9 @@ Shop::Smarty()->display($oPlugin->cAdminmenuPfad . '/tpl/orders.tpl'); } catch (Exception $e) { - echo "
{$e->getMessage()}
"; + echo "
" . + "{$e->getMessage()}
" . + "
{$e->getFile()}:{$e->getLine()}
{$e->getTraceAsString()}
" . + "
"; \ws_mollie\Helper::logExc($e); } \ No newline at end of file diff --git a/version/100/adminmenu/tpl/order.tpl b/version/100/adminmenu/tpl/order.tpl index e0d60dd..1322fd0 100644 --- a/version/100/adminmenu/tpl/order.tpl +++ b/version/100/adminmenu/tpl/order.tpl @@ -18,6 +18,13 @@ {/if} +{if count($ordersMsgs)} + {foreach from=$ordersMsgs item=alert} +
{$alert->text}
+ {/foreach} +
+{/if} +
BestellNr.
@@ -48,6 +55,25 @@
Mollie ID:

Positionen:

+ +
+ {if ($order->status === 'authorized' || $order->status === 'shipping') && (int)$oBestellung->cStatus >= 4} + + Zahlung erfassen + + {/if} + + {if $order->isCancelable} + + {/if} +
+ @@ -59,6 +85,7 @@ + @@ -79,6 +106,19 @@ + {/foreach} @@ -88,6 +128,7 @@ +
Steuer Netto Brutto 
{$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} + {*$line|var_dump*} + + + + {if $line->isCancelable} + + + + {/if} +
{$vat|number_format:2:',':''} {$order->amount->currency} {$netto|number_format:2:',':''} {$order->amount->currency} {$brutto|number_format:2:',':''} {$order->amount->currency} 
diff --git a/version/100/adminmenu/tpl/orders.tpl b/version/100/adminmenu/tpl/orders.tpl index 6afdf21..4d653c9 100644 --- a/version/100/adminmenu/tpl/orders.tpl +++ b/version/100/adminmenu/tpl/orders.tpl @@ -7,12 +7,13 @@
{/if} - +
- + + @@ -23,24 +24,59 @@ {foreach from=$payments item=payment} - + + - {/foreach} diff --git a/version/100/class/Model/Payment.php b/version/100/class/Model/Payment.php index 16bc0b4..e91bf00 100644 --- a/version/100/class/Model/Payment.php +++ b/version/100/class/Model/Payment.php @@ -47,17 +47,29 @@ public static function updateFromPayment(\Mollie\Api\Resources\Order $oMolliePay public static function getPayment($kBestellung) { - return \Shop::DB()->executeQueryPrepared('SELECT * FROM ' . self::TABLE . ' WHERE kBestellung = :kBestellung', [':kBestellung' => $kBestellung], 1); + $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) { - return \Shop::DB()->executeQueryPrepared('SELECT * FROM ' . self::TABLE . ' WHERE kID = :kID', [':kID' => $kID], 1); + $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; } public static function getPaymentHash($cHash) { - return \Shop::DB()->executeQueryPrepared('SELECT * FROM ' . self::TABLE . ' WHERE cHash = :cHash', [':cHash' => $cHash], 1); + $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; } } \ No newline at end of file diff --git a/version/100/class/Mollie.php b/version/100/class/Mollie.php index 763d30a..9af86be 100644 --- a/version/100/class/Mollie.php +++ b/version/100/class/Mollie.php @@ -34,10 +34,54 @@ public static function getOrderCompletedRedirect($kBestellung, $redirect = true) header('Location: ' . $url); exit(); } - return $url; + } + protected static $_jtlmollie; + 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 + */ + 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; + } + + } \ No newline at end of file diff --git a/version/100/frontend/144_notify.php b/version/100/frontend/144_notify.php index f115dc3..4dd22fe 100644 --- a/version/100/frontend/144_notify.php +++ b/version/100/frontend/144_notify.php @@ -30,17 +30,18 @@ \ws_mollie\Model\Payment::updateFromPayment($order, $payment->kBestellung); $logData = '#' . $payment->kBestellung . '$' . $payment->kID . "§" . $oBestellung->cBestellNr; - $oPaymentMethod->doLog('Received Notification
' . print_r([$order, $payment], 1) . '
', $logData, LOGLEVEL_DEBUG); + $oPaymentMethod->doLog('Received Notification
' . print_r([$order, $payment], 1) . '
', $logData); switch ($order->status) { - case \Mollie\Api\Types\PaymentStatus::STATUS_PAID: + case \Mollie\Api\Types\OrderStatus::STATUS_COMPLETED: + case \Mollie\Api\Types\OrderStatus::STATUS_PAID: $oPaymentMethod->doLog('PaymentStatus: ' . $order->status . ' => Zahlungseingang (' . $order->amount->value . ')', $logData, LOGLEVEL_DEBUG); $oIncomingPayment = new stdClass(); $oIncomingPayment->fBetrag = $order->amount->value; $oIncomingPayment->cISO = $order->amount->curreny; $oIncomingPayment->cHinweis = $order->id; $oPaymentMethod->addIncomingPayment($oBestellung, $oIncomingPayment); - case \Mollie\Api\Types\PaymentStatus::STATUS_AUTHORIZED: + case \Mollie\Api\Types\OrderStatus::STATUS_AUTHORIZED: $oPaymentMethod->doLog('PaymentStatus: ' . $order->status . ' => Bestellung bezahlt', $logData, LOGLEVEL_DEBUG); $oPaymentMethod->setOrderStatusToPaid($oBestellung); break; diff --git a/version/100/frontend/181_sync.php b/version/100/frontend/181_sync.php new file mode 100644 index 0000000..2846b11 --- /dev/null +++ b/version/100/frontend/181_sync.php @@ -0,0 +1,70 @@ +kBestellung, false); + + if ($oBestellung->kBestellung && $payment = \ws_mollie\Model\Payment::getPayment($oBestellung->kBestellung)) { + + $logData = '#' . $payment->kBestellung . '$' . $payment->kID . "§" . $oBestellung->cBestellNr; + \ws_mollie\Mollie::JTLMollie()->doLog("WAWI Abgleich: HOOK_BESTELLUNGEN_XML_BESTELLSTATUS", $logData); + try { + + $mollie = new \Mollie\Api\MollieApiClient(); + $mollie->setApiKey(\ws_mollie\Helper::getSetting("api_key")); + $order = $mollie->orders->get($payment->kID); + + if ($order->status === \Mollie\Api\Types\OrderStatus::STATUS_AUTHORIZED || \Mollie\Api\Types\OrderStatus::STATUS_PAID) { + \ws_mollie\Mollie::JTLMollie()->doLog("Create Shippment:
" . print_r([$order, $args_arr], 1) . '
', $logData, LOGLEVEL_DEBUG); + + + if ($oBestellung->cTracking) { + $tracking = new stdClass(); + $tracking->carrier = $oBestellung->cVersandartName; + $tracking->url = $oBestellung->cTrackingURL; + $tracking->code = $oBestellung->cTracking; + $options['tracking'] = $tracking; + } + + if ($status === BESTELLUNG_STATUS_VERSANDT) { + $options = ['lines' => []]; + $shipment = $mollie->shipments->createFor($order, $options); + \ws_mollie\Mollie::JTLMollie()->doLog('Shipment created
' . print_r(['options' => $options, 'shipment' => $shipment], 1) . '
', $logData); + } elseif ($status === BESTELLUNG_STATUS_TEILVERSANDT) { + $lines = []; + /** + * @var int $i + * @var \Mollie\Api\Resources\OrderLine $line + */ + foreach ($order->lines as $i => $line) { + if (($quantity = \ws_mollie\Mollie::getBestellPosSent($line->sku, $oBestellung)) !== false) { + $lines[] = (object)[ + 'id' => $line->id, + 'quantity' => $quantity, + 'amount' => (object)[ + 'currency' => $line->totalAmount->currency, + 'value' => number_format($quantity * $line->unitPrice->value, 2), + ], + ]; + } + } + if (count($lines)) { + $options = ['lines' => $lines]; + } else { + throw new Exception("No Lines to ship found."); + } + $shipment = $mollie->shipments->createFor($order, $options); + \ws_mollie\Mollie::JTLMollie()->doLog('Partially Shipment created
' . print_r(['options' => $options, 'shipment' => $shipment], 1) . '
', $logData); + } + } + + } catch (Exception $e) { + \ws_mollie\Mollie::JTLMollie()->doLog('Fehler: ' . $e->getMessage() . '
' . print_r($e->getTrace(), 1) . '
', $logData, LOGLEVEL_ERROR); + } + } +} catch (Exception $e) { + \ws_mollie\Helper::logExc($e); +} \ No newline at end of file diff --git a/version/100/paymentmethod/JTLMollie.php b/version/100/paymentmethod/JTLMollie.php index cf30be8..733449a 100644 --- a/version/100/paymentmethod/JTLMollie.php +++ b/version/100/paymentmethod/JTLMollie.php @@ -255,7 +255,7 @@ public function preparePaymentProcess($order) $logData = '#' . $order->kBestellung . "§" . $order->cBestellNr; try { $payment = \ws_mollie\Model\Payment::getPayment($order->kBestellung); - if ($payment && in_array($payment->cStatus, [MolliePaymentStatus::STATUS_OPEN, 'created']) && $payment->cCheckoutURL) { + if ($payment && in_array($payment->cStatus, [\Mollie\Api\Types\OrderStatus::STATUS_CREATED]) && $payment->cCheckoutURL) { $logData .= '$' . $payment->kID; if (!$this->duringCheckout) { Session::getInstance()->cleanUp(); @@ -319,14 +319,15 @@ public function handleNotification($order, $hash, $args) \ws_mollie\Model\Payment::updateFromPayment($oMolliePayment, $order->kBestellung); switch ($oMolliePayment->status) { - case MolliePaymentStatus::STATUS_PAID: + case \Mollie\Api\Types\OrderStatus::STATUS_PAID: + case \Mollie\Api\Types\OrderStatus::STATUS_COMPLETED: $this->doLog('PaymentStatus: ' . $oMolliePayment->status . ' => Zahlungseingang (' . $oMolliePayment->amount->value . ')', $logData, LOGLEVEL_DEBUG); $oIncomingPayment = new stdClass(); $oIncomingPayment->fBetrag = $oMolliePayment->amount->value; $oIncomingPayment->cISO = $oMolliePayment->amount->curreny; $oIncomingPayment->cHinweis = $oMolliePayment->id; $this->addIncomingPayment($order, $oIncomingPayment); - case MolliePaymentStatus::STATUS_AUTHORIZED: + case \Mollie\Api\Types\OrderStatus::STATUS_AUTHORIZED: $this->doLog('PaymentStatus: ' . $oMolliePayment->status . ' => Bestellung bezahlt', $logData, LOGLEVEL_DEBUG); $this->setOrderStatusToPaid($order); break; @@ -354,7 +355,7 @@ public function finalizeOrder($order, $hash, $args) $logData .= '$' . $oMolliePayment->id; $this->doLog('Received Notification Finalize Order
' . print_r([$hash, $args, $oMolliePayment], 1) . '
', $logData, LOGLEVEL_DEBUG); \ws_mollie\Model\Payment::updateFromPayment($oMolliePayment, $order->kBestellung); - return in_array($oMolliePayment->status, [MolliePaymentStatus::STATUS_PAID, MolliePaymentStatus::STATUS_AUTHORIZED, MolliePaymentStatus::STATUS_PENDING]); + return in_array($oMolliePayment->status, [\Mollie\Api\Types\OrderStatus::STATUS_PAID, \Mollie\Api\Types\OrderStatus::STATUS_AUTHORIZED, \PayPal\Api\Order::STATUS_PENDING, \Mollie\Api\Types\OrderStatus::STATUS_COMPLETED]); } catch (\Exception $e) { $this->doLog($e->getMessage(), $logData); } From 3ea1f9387363bdb2c50159516b2a141599226324 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Tue, 15 Jan 2019 12:14:13 +0100 Subject: [PATCH 015/280] #14, #4, fix #15 --- version/100/adminmenu/orders.php | 10 +++++----- version/100/adminmenu/tpl/orders.tpl | 2 +- version/100/class/Mollie.php | 1 + version/100/frontend/131_globalinclude.php | 11 +++++++++-- version/100/frontend/144_notify.php | 17 +++++------------ version/100/frontend/181_sync.php | 9 +++++---- version/100/paymentmethod/JTLMollie.php | 4 ++-- 7 files changed, 28 insertions(+), 26 deletions(-) diff --git a/version/100/adminmenu/orders.php b/version/100/adminmenu/orders.php index b6d2c22..7244be9 100644 --- a/version/100/adminmenu/orders.php +++ b/version/100/adminmenu/orders.php @@ -27,7 +27,7 @@ $mollie->setApiKey(\ws_mollie\Helper::getSetting("api_key")); $order = $mollie->orders->get($_REQUEST['id']); if ($order->status !== \Mollie\Api\Types\OrderStatus::STATUS_AUTHORIZED && $order->status !== \Mollie\Api\Types\OrderStatus::STATUS_SHIPPING) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Nur authorisierte Zahlungen können erfasst werden!']; + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Nur autorisierte Zahlungen können erfasst werden!']; break; } @@ -65,20 +65,20 @@ if ($line->quantity <= $line->quantityShipped) { continue; } - if (($quantity = \ws_mollie\Mollie::getBestellPosSent($line->sku, $oBestellung)) !== false && $quantity > 0) { + if (($quantity = \ws_mollie\Mollie::getBestellPosSent($line->sku, $oBestellung)) !== false && $quantity - $line->quantityShipped > 0) { + $x = $quantity - $line->quantityShipped; $lines[] = (object)[ 'id' => $line->id, - 'quantity' => $quantity, + 'quantity' => $x, 'amount' => (object)[ 'currency' => $line->totalAmount->currency, - 'value' => number_format($quantity * $line->unitPrice->value, 2), + 'value' => number_format($x * $line->unitPrice->value, 2), ], ]; } } if (count($lines)) { $options = ['lines' => $lines]; - var_dump($lines); $shipment = $mollie->shipments->createFor($order, $options); \ws_mollie\Mollie::JTLMollie()->doLog('Partially Shipment created
' . print_r(['options' => $options, 'shipment' => $shipment], 1) . '
', $logData); } else { diff --git a/version/100/adminmenu/tpl/orders.tpl b/version/100/adminmenu/tpl/orders.tpl index 4d653c9..daa3e7a 100644 --- a/version/100/adminmenu/tpl/orders.tpl +++ b/version/100/adminmenu/tpl/orders.tpl @@ -41,7 +41,7 @@ {elseif $payment->cStatus == 'paid'} bezahlt {elseif $payment->cStatus == 'authorized'} - authorisiert + autorisiert {elseif $payment->cStatus == 'shipping'} versendet {elseif $payment->cStatus == 'completed'} diff --git a/version/100/class/Mollie.php b/version/100/class/Mollie.php index 9af86be..88e14ee 100644 --- a/version/100/class/Mollie.php +++ b/version/100/class/Mollie.php @@ -58,6 +58,7 @@ public static function JTLMollie() * @param $sku * @param \Bestellung $oBestellung * @return float|int + * @throws \Exception */ public static function getBestellPosSent($sku, \Bestellung $oBestellung) { diff --git a/version/100/frontend/131_globalinclude.php b/version/100/frontend/131_globalinclude.php index 424b06f..0185244 100644 --- a/version/100/frontend/131_globalinclude.php +++ b/version/100/frontend/131_globalinclude.php @@ -1,7 +1,5 @@ executeQueryPrepared("SELECT * FROM " . \ws_mollie\Model\Payment::TABLE . " WHERE cHash = :cHash", [':cHash' => $_REQUEST['mollie']], 1); if ((int)$payment->kBestellung) { + $logData = '$' . $payment->kID . '#' . $payment->kBestellung . "§" . $payment->cOrderNumber; + \ws_mollie\Mollie::JTLMollie()->doLog('Bestellung finalized => redirect abschluss/status', $logData); + \ws_mollie\Mollie::getOrderCompletedRedirect($payment->kBestellung, true); } elseif ($payment) { @@ -24,6 +25,9 @@ $order = $mollie->orders->get($payment->kID); + $logData = '$' . $order->id . '#' . $payment->kBestellung . "§" . $payment->cOrderNumber; + \ws_mollie\Mollie::JTLMollie()->doLog('Bestellung open => finalize', $logData); + if ($order) { $session = Session::getInstance(); require_once PFAD_ROOT . 'includes/bestellabschluss_inc.php'; @@ -34,6 +38,9 @@ $order->orderNumber = $oBestellung->cBestellNr; \ws_mollie\Model\Payment::updateFromPayment($order, $oBestellung->kBestellung); + + \ws_mollie\Mollie::JTLMollie()->doLog('Bestellung finalized => redirect
' . $order . '
', $logData, LOGLEVEL_DEBUG); + \ws_mollie\Mollie::getOrderCompletedRedirect($oBestellung->kBestellung, true); } diff --git a/version/100/frontend/144_notify.php b/version/100/frontend/144_notify.php index 4dd22fe..6ed1ad6 100644 --- a/version/100/frontend/144_notify.php +++ b/version/100/frontend/144_notify.php @@ -11,13 +11,6 @@ try { \ws_mollie\Helper::init(); - $pza = Shop::DB()->select('tpluginzahlungsartklasse', 'cClassName', 'JTLMollie'); - if (!$pza) { - return; - } - require_once __DIR__ . '/../paymentmethod/JTLMollie.php'; - - $oPaymentMethod = new JTLMollie($pza->cModulId); $payment = \ws_mollie\Model\Payment::getPaymentHash($_REQUEST['hash']); if ($payment && $payment->kBestellung) { @@ -30,20 +23,20 @@ \ws_mollie\Model\Payment::updateFromPayment($order, $payment->kBestellung); $logData = '#' . $payment->kBestellung . '$' . $payment->kID . "§" . $oBestellung->cBestellNr; - $oPaymentMethod->doLog('Received Notification
' . print_r([$order, $payment], 1) . '
', $logData); + \ws_mollie\Mollie::JTLMollie()->doLog('Received Notification
' . print_r([$order, $payment], 1) . '
', $logData); switch ($order->status) { case \Mollie\Api\Types\OrderStatus::STATUS_COMPLETED: case \Mollie\Api\Types\OrderStatus::STATUS_PAID: - $oPaymentMethod->doLog('PaymentStatus: ' . $order->status . ' => Zahlungseingang (' . $order->amount->value . ')', $logData, LOGLEVEL_DEBUG); + \ws_mollie\Mollie::JTLMollie()->doLog('PaymentStatus: ' . $order->status . ' => Zahlungseingang (' . $order->amount->value . ')', $logData, LOGLEVEL_DEBUG); $oIncomingPayment = new stdClass(); $oIncomingPayment->fBetrag = $order->amount->value; $oIncomingPayment->cISO = $order->amount->curreny; $oIncomingPayment->cHinweis = $order->id; - $oPaymentMethod->addIncomingPayment($oBestellung, $oIncomingPayment); + \ws_mollie\Mollie::JTLMollie()->addIncomingPayment($oBestellung, $oIncomingPayment); case \Mollie\Api\Types\OrderStatus::STATUS_AUTHORIZED: - $oPaymentMethod->doLog('PaymentStatus: ' . $order->status . ' => Bestellung bezahlt', $logData, LOGLEVEL_DEBUG); - $oPaymentMethod->setOrderStatusToPaid($oBestellung); + \ws_mollie\Mollie::JTLMollie()->doLog('PaymentStatus: ' . $order->status . ' => Bestellung bezahlt', $logData, LOGLEVEL_DEBUG); + \ws_mollie\Mollie::JTLMollie()->setOrderStatusToPaid($oBestellung); break; } // stop notify.php script diff --git a/version/100/frontend/181_sync.php b/version/100/frontend/181_sync.php index 2846b11..54ab00e 100644 --- a/version/100/frontend/181_sync.php +++ b/version/100/frontend/181_sync.php @@ -5,7 +5,7 @@ $status = (int)$args_arr['status']; /** @var Bestellung $oBestellung */ - $oBestellung = new Bestellung($args_arr['oBestellung']->kBestellung, false); + $oBestellung = new Bestellung($args_arr['oBestellung']->kBestellung, true); if ($oBestellung->kBestellung && $payment = \ws_mollie\Model\Payment::getPayment($oBestellung->kBestellung)) { @@ -40,13 +40,14 @@ * @var \Mollie\Api\Resources\OrderLine $line */ foreach ($order->lines as $i => $line) { - if (($quantity = \ws_mollie\Mollie::getBestellPosSent($line->sku, $oBestellung)) !== false) { + if (($quantity = \ws_mollie\Mollie::getBestellPosSent($line->sku, $oBestellung)) !== false && ($quantity - $line->quantityShipped) > 0) { + $x = $quantity - $line->quantityShipped; $lines[] = (object)[ 'id' => $line->id, - 'quantity' => $quantity, + 'quantity' => $x, 'amount' => (object)[ 'currency' => $line->totalAmount->currency, - 'value' => number_format($quantity * $line->unitPrice->value, 2), + 'value' => number_format($x * $line->unitPrice->value, 2), ], ]; } diff --git a/version/100/paymentmethod/JTLMollie.php b/version/100/paymentmethod/JTLMollie.php index 733449a..f5bc4da 100644 --- a/version/100/paymentmethod/JTLMollie.php +++ b/version/100/paymentmethod/JTLMollie.php @@ -213,9 +213,9 @@ protected function getOrderData(Bestellung $order, $hash) foreach ($data['lines'] as $line) { $sum += (float)$line->totalAmount->value; } - if ($sum <> (float)$data['amount']->value) { + if (abs($sum - (float)$data['amount']->value) > 0) { $diff = (round((float)$data['amount']->value - $sum, 2)); - if ($diff !== 0) { + if ($diff != 0) { $line = new stdClass(); $line->type = $diff > 0 ? \Mollie\Api\Types\OrderLineType::TYPE_SURCHARGE : \Mollie\Api\Types\OrderLineType::TYPE_DISCOUNT; $line->name = 'Rundungsausgleich'; From 591b1de5a782cdc13155b3173658e6878eba353a Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Tue, 15 Jan 2019 15:22:15 +0100 Subject: [PATCH 016/280] refund, cancel #9, #14 --- version/100/adminmenu/orders.php | 94 +++++++++++++++++------------ version/100/adminmenu/tpl/order.tpl | 70 ++++++++++++++++----- 2 files changed, 110 insertions(+), 54 deletions(-) diff --git a/version/100/adminmenu/orders.php b/version/100/adminmenu/orders.php index 7244be9..9c64c83 100644 --- a/version/100/adminmenu/orders.php +++ b/version/100/adminmenu/orders.php @@ -13,6 +13,54 @@ if (array_key_exists('action', $_REQUEST)) { switch ($_REQUEST['action']) { + + + case 'refund': + if (!array_key_exists('id', $_REQUEST)) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; + break; + } + $payment = \ws_mollie\Model\Payment::getPaymentMollie($_REQUEST['id']); + if (!$payment) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; + break; + } + + $mollie = new \Mollie\Api\MollieApiClient(); + $mollie->setApiKey(\ws_mollie\Helper::getSetting("api_key")); + $order = $mollie->orders->get($_REQUEST['id']); + if ($order->status == \Mollie\Api\Types\OrderStatus::STATUS_CANCELED) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung bereits storniert']; + break; + } + $refund = $mollie->orderRefunds->createFor($order, ['lines' => []]); + \ws_mollie\Mollie::JTLMollie()->doLog("Order refunded:
" . print_r($refund, 1) . "
", '$' . $payment->kID . '#' . $payment->kBestellung . '§' . $payment->cOrderNumber, LOGLEVEL_NOTICE); + + goto order; + break; + + case 'cancel'; + if (!array_key_exists('id', $_REQUEST)) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; + break; + } + $payment = \ws_mollie\Model\Payment::getPaymentMollie($_REQUEST['id']); + if (!$payment) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; + break; + } + $mollie = new \Mollie\Api\MollieApiClient(); + $mollie->setApiKey(\ws_mollie\Helper::getSetting("api_key")); + $order = $mollie->orders->get($_REQUEST['id']); + if ($order->status == \Mollie\Api\Types\OrderStatus::STATUS_CANCELED) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung bereits storniert']; + break; + } + $cancel = $mollie->orders->cancel($order->id); + \ws_mollie\Mollie::JTLMollie()->doLog("Order canceled:
" . print_r($cancel, 1) . "
", '$' . $payment->kID . '#' . $payment->kBestellung . '§' . $payment->cOrderNumber, LOGLEVEL_NOTICE); + goto order; + break; + case 'capture': if (!array_key_exists('id', $_REQUEST)) { $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; @@ -48,47 +96,14 @@ $options['tracking'] = $tracking; } - if ((int)$oBestellung->cStatus === BESTELLUNG_STATUS_VERSANDT) { - // CAPTURE ALL - $shipment = $mollie->shipments->createFor($order, $options); - $ordersMsgs[] = (object)['type' => 'success', 'text' => 'Zahlung wurde erfolgreich erfasst!']; - \ws_mollie\Mollie::JTLMollie()->doLog('Shipment created
' . print_r(['options' => $options, 'shipment' => $shipment], 1) . '
', $logData); - } elseif ((int)$oBestellung->cStatus === BESTELLUNG_STATUS_TEILVERSANDT) { - // CAPTURE Lieferschein - - $lines = []; - /** - * @var int $i - * @var \Mollie\Api\Resources\OrderLine $line - */ - foreach ($order->lines as $i => $line) { - if ($line->quantity <= $line->quantityShipped) { - continue; - } - if (($quantity = \ws_mollie\Mollie::getBestellPosSent($line->sku, $oBestellung)) !== false && $quantity - $line->quantityShipped > 0) { - $x = $quantity - $line->quantityShipped; - $lines[] = (object)[ - 'id' => $line->id, - 'quantity' => $x, - 'amount' => (object)[ - 'currency' => $line->totalAmount->currency, - 'value' => number_format($x * $line->unitPrice->value, 2), - ], - ]; - } - } - if (count($lines)) { - $options = ['lines' => $lines]; - $shipment = $mollie->shipments->createFor($order, $options); - \ws_mollie\Mollie::JTLMollie()->doLog('Partially Shipment created
' . print_r(['options' => $options, 'shipment' => $shipment], 1) . '
', $logData); - } else { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine Positionen zur Teillieferung gefunden!']; - - } - } - + // CAPTURE ALL + $shipment = $mollie->shipments->createFor($order, $options); + $ordersMsgs[] = (object)['type' => 'success', 'text' => 'Zahlung wurde erfolgreich erfasst!']; + \ws_mollie\Mollie::JTLMollie()->doLog('Shipment created
' . print_r(['options' => $options, 'shipment' => $shipment], 1) . '
', $logData); + goto order; case 'order': + order: if (!array_key_exists('id', $_REQUEST)) { $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; break; @@ -101,6 +116,7 @@ $payment = \ws_mollie\Model\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, diff --git a/version/100/adminmenu/tpl/order.tpl b/version/100/adminmenu/tpl/order.tpl index 1322fd0..aa60b3b 100644 --- a/version/100/adminmenu/tpl/order.tpl +++ b/version/100/adminmenu/tpl/order.tpl @@ -57,26 +57,32 @@

Positionen:

- {if ($order->status === 'authorized' || $order->status === 'shipping') && (int)$oBestellung->cStatus >= 4} + {if ($order->status === 'authorized' || $order->status === 'shipping') && (int)$oBestellung->cStatus >= 3} - Zahlung erfassen + Zahlung erfassen1 + + {/if} + {if $order->amount->value > $order->amountRefunded->value && $order->amountCaptured->value > 0} + Rückerstatten2 {/if} - {if $order->isCancelable} - + Stornieren3 + {/if}
BestellNr. IDStatusMollie StatusJTL Status Betrag Währung Locale
{$payment->cOrderNumber} + {$payment->cOrderNumber} + {if $payment->cMode == 'test'} + TEST + {/if} + {$payment->kID} - {if $payment->cStatus == 'paid'} - bezahlt - {elseif $payment->cStatus == 'created'} + {if $payment->cStatus == 'created'} erstellt + {elseif $payment->cStatus == 'pending'} + austehend + {elseif $payment->cStatus == 'paid'} + bezahlt + {elseif $payment->cStatus == 'authorized'} + authorisiert + {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 (int)$payment->oBestellung->cStatus == 1} + OFFEN + {elseif (int)$payment->oBestellung->cStatus == 2} + IN BEARBEITUNG + {elseif (int)$payment->oBestellung->cStatus == 3} + BEZAHLT + {elseif (int)$payment->oBestellung->cStatus == 4} + VERSANDT + {elseif (int)$payment->oBestellung->cStatus == 5} + TEILVERSANDT + {elseif (int)$payment->oBestellung->cStatus == -1} + STORNO {else} - {$payment->cStatus} + n/a {/if} {$payment->fAmount|number_format:2:',':''} {$payment->cCurrency} {$payment->cLocale} {$payment->cMethod}{"d. M Y H:i"|date:($payment->dCreatedAt|strtotime)}
+ @@ -98,6 +104,27 @@ {assign var="netto" value=$netto+$line->totalAmount->value-$line->vatAmount->value} {assign var="brutto" value=$brutto+$line->totalAmount->value} + @@ -107,17 +134,25 @@ {/foreach} @@ -133,6 +168,11 @@
Status SKU Name Typ
+ {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->totalAmount->value - $line->vatAmount->value)|number_format:2:',':''} {$line->vatAmount->currency} {$line->totalAmount->value|number_format:2:',':''} {$line->totalAmount->currency} - {*$line|var_dump*} - - - + {*if $line->quantity > $line->quantityShipped} + + + + {/if} + {if $line->quantity > $line->quantityRefunded} + + + + {/if} {if $line->isCancelable} - {/if} + {/if*} + {*$line|var_dump*}
+
+ 1 = Bestellung wird bei Mollie als versandt markiert. WAWI wird nicht informiert.
+ 2 = Bezahlter Betrag wird dem Kunden rückerstattet. WAWI wird nicht informiert.
+ 3 = Bestellung wird bei Mollie storniert. WAWI wird nicht informiert.
+

Log

From beeedd4e3d54326c14f9ec4d656a9b13f6f3287a Mon Sep 17 00:00:00 2001 From: WebStollen Server Date: Tue, 15 Jan 2019 15:27:33 +0100 Subject: [PATCH 017/280] php compatibility --- version/100/class/Model/Payment.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version/100/class/Model/Payment.php b/version/100/class/Model/Payment.php index 16bc0b4..4dfa98b 100644 --- a/version/100/class/Model/Payment.php +++ b/version/100/class/Model/Payment.php @@ -7,7 +7,7 @@ class Payment extends AbstractModel { - public const TABLE = 'xplugin_ws_mollie_payments'; + const TABLE = 'xplugin_ws_mollie_payments'; public static function updateFromPayment(\Mollie\Api\Resources\Order $oMolliePayment, $kBestellung = null, $hash = null) { From 1c3fa6e2e1a676a47a03fecccc588642fc39e30e Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Wed, 16 Jan 2019 12:55:10 +0100 Subject: [PATCH 018/280] #5 --- version/100/class/Mollie.php | 123 ++++++++++++++++++++- version/100/frontend/131_globalinclude.php | 63 +++++++---- version/100/frontend/144_notify.php | 31 +----- version/100/frontend/181_sync.php | 64 ++--------- version/100/paymentmethod/JTLMollie.php | 25 +---- 5 files changed, 178 insertions(+), 128 deletions(-) diff --git a/version/100/class/Mollie.php b/version/100/class/Mollie.php index 88e14ee..3a74cd7 100644 --- a/version/100/class/Mollie.php +++ b/version/100/class/Mollie.php @@ -9,6 +9,9 @@ namespace ws_mollie; +use Mollie\Api\Resources\Order; +use Mollie\Api\Types\OrderStatus; + abstract class Mollie { @@ -20,14 +23,14 @@ abstract class Mollie public static function getOrderCompletedRedirect($kBestellung, $redirect = true) { $mode = \Shopsetting::getInstance()->getValue(CONF_KAUFABWICKLUNG, 'bestellabschluss_abschlussseite'); - if ($mode == 'S') { // Statusseite + $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; - - } else { // Abschlussseite - $bestellid = \Shop::DB()->select("tbestellid ", 'kBestellung', (int)$kBestellung); - $url = \Shop::getURL() . '/bestellabschluss.php?i=' . $bestellid->cId; } if ($redirect) { @@ -85,4 +88,114 @@ public static function getBestellPosSent($sku, \Bestellung $oBestellung) } + /** + * @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; + } + + switch ((int)$newStatus) { + case BESTELLUNG_STATUS_VERSANDT: + $options['lines'] = []; + break; + case BESTELLUNG_STATUS_TEILVERSANDT: + $lines = []; + foreach ($order->lines as $i => $line) { + if (($quantity = Mollie::getBestellPosSent($line->sku, $oBestellung)) !== false && ($quantity - $line->quantityShipped) > 0) { + $x = $quantity - $line->quantityShipped; + $lines[] = (object)[ + 'id' => $line->id, + 'quantity' => $x, + 'amount' => (object)[ + 'currency' => $line->totalAmount->currency, + 'value' => number_format($x * $line->unitPrice->value, 2), + ], + ]; + } + } + if (count($lines)) { + $options['lines'] = $lines; + } + break; + case BESTELLUNG_STATUS_STORNO: + $options = null; + break; + } + + return $options; + } + + + /** + * @param Order $order + * @param null $kBestellung + * @return bool + * @throws \Exception + */ + public static function handleOrder(Order $order, $kBestellung = null) + { + + $logData = '$' . $order->id . '#' . $kBestellung . "§" . $order->orderNumber; + + // 1. Save to DB + \ws_mollie\Model\Payment::updateFromPayment($order, $kBestellung); + + if ($kBestellung) { + $oBestellung = new \Bestellung($kBestellung); + if ($oBestellung->kBestellung) { + + // 2. Check PaymentStatus + switch ($order->status) { + case OrderStatus::STATUS_PAID: + case OrderStatus::STATUS_COMPLETED: + $oIncomingPayment = new \stdClass(); + $oIncomingPayment->fBetrag = $order->amount->value; + $oIncomingPayment->cISO = $order->amount->curreny; + $oIncomingPayment->cHinweis = $order->id; + Mollie::JTLMollie()->addIncomingPayment($oBestellung, $oIncomingPayment); + Mollie::JTLMollie()->setOrderStatusToPaid($oBestellung); + Mollie::JTLMollie()->doLog('PaymentStatus: ' . $order->status . ' => Zahlungseingang (' . $order->amount->value . ')', $logData, LOGLEVEL_DEBUG); + break; + case OrderStatus::STATUS_SHIPPING: + case OrderStatus::STATUS_AUTHORIZED: + case OrderStatus::STATUS_PENDING: + Mollie::JTLMollie()->setOrderStatusToPaid($oBestellung); + Mollie::JTLMollie()->doLog('PaymentStatus: ' . $order->status . ' => Bestellung bezahlt', $logData, LOGLEVEL_NOTICE); + break; + case OrderStatus::STATUS_CANCELED: + case OrderStatus::STATUS_EXPIRED: + Mollie::JTLMollie()->doLog('PaymentStatus: ' . $order->status, $logData, LOGLEVEL_ERROR); + break; + + } + return true; + } + return false; + } + return true; + } + } \ No newline at end of file diff --git a/version/100/frontend/131_globalinclude.php b/version/100/frontend/131_globalinclude.php index 0185244..c4872d8 100644 --- a/version/100/frontend/131_globalinclude.php +++ b/version/100/frontend/131_globalinclude.php @@ -3,46 +3,61 @@ if (strpos($_SERVER['PHP_SELF'], 'bestellabschluss') === false) { return; } - require_once __DIR__ . '/../class/Helper.php'; try { \ws_mollie\Helper::init(); - + // suppress any output, for redirect ob_start(); if (array_key_exists('mollie', $_REQUEST)) { $payment = \Shop::DB()->executeQueryPrepared("SELECT * FROM " . \ws_mollie\Model\Payment::TABLE . " WHERE cHash = :cHash", [':cHash' => $_REQUEST['mollie']], 1); + // Bestellung finalized, redirect to status/completion page if ((int)$payment->kBestellung) { $logData = '$' . $payment->kID . '#' . $payment->kBestellung . "§" . $payment->cOrderNumber; \ws_mollie\Mollie::JTLMollie()->doLog('Bestellung finalized => redirect abschluss/status', $logData); - + $order = JTLMollie::API()->orders->get($payment->kID, ['embed' => 'payments']); + \ws_mollie\Mollie::handleOrder($order, $payment->kBestellung); \ws_mollie\Mollie::getOrderCompletedRedirect($payment->kBestellung, true); - } elseif ($payment) { - - $mollie = new \Mollie\Api\MollieApiClient(); - $mollie->setApiKey(\ws_mollie\Helper::getSetting("api_key")); - - $order = $mollie->orders->get($payment->kID); - + } elseif ($payment) { // payment, but no order => finalize it + require_once __DIR__ . '/../paymentmethod/JTLMollie.php'; + $order = JTLMollie::API()->orders->get($payment->kID, ['embed' => 'payments']); $logData = '$' . $order->id . '#' . $payment->kBestellung . "§" . $payment->cOrderNumber; - \ws_mollie\Mollie::JTLMollie()->doLog('Bestellung open => finalize', $logData); - - if ($order) { - $session = Session::getInstance(); - require_once PFAD_ROOT . 'includes/bestellabschluss_inc.php'; - require_once PFAD_ROOT . 'includes/mailTools.php'; - - $oBestellung = fakeBestellung(); - $oBestellung = finalisiereBestellung(); - $order->orderNumber = $oBestellung->cBestellNr; - \ws_mollie\Model\Payment::updateFromPayment($order, $oBestellung->kBestellung); - - \ws_mollie\Mollie::JTLMollie()->doLog('Bestellung finalized => redirect
' . $order . '
', $logData, LOGLEVEL_DEBUG); + // GET NEWEST PAYMENT: + $_payment = null; + if (isset($order->_embedded->payments) && is_array($order->_embedded->payments)) { + foreach ($order->_embedded->payments as $p) { + if (!$_payment) { + $_payment = $p; + continue; + } + if (strtotime($p->createdAt) > strtotime($payment->createdAt)) { + $_payment = $p; + } + } + } - \ws_mollie\Mollie::getOrderCompletedRedirect($oBestellung->kBestellung, true); + // finalize only, if order is not canceld/expired + if ($order && !$order->isCanceled() && !$order->isExpired()) { + // finalize only if payment is not expired/canceled,failed or open + if ($_payment && !in_array($_payment->status, [\Mollie\Api\Types\PaymentStatus::STATUS_EXPIRED, \Mollie\Api\Types\PaymentStatus::STATUS_CANCELED, \Mollie\Api\Types\PaymentStatus::STATUS_OPEN, \Mollie\Api\Types\PaymentStatus::STATUS_FAILED, \Mollie\Api\Types\PaymentStatus::STATUS_CANCELED])) { + \ws_mollie\Mollie::JTLMollie()->doLog('Bestellung open => finalize', $logData); + $session = Session::getInstance(); + require_once PFAD_ROOT . 'includes/bestellabschluss_inc.php'; + require_once PFAD_ROOT . 'includes/mailTools.php'; + $oBestellung = fakeBestellung(); + $oBestellung = finalisiereBestellung(); + $order->orderNumber = $oBestellung->cBestellNr; + \ws_mollie\Mollie::JTLMollie()->doLog('Bestellung finalized => redirect
' . print_r($order, 1) . '
', $logData, LOGLEVEL_DEBUG); + \ws_mollie\Mollie::handleOrder($order, $oBestellung->kBestellung); + \ws_mollie\Mollie::getOrderCompletedRedirect($oBestellung->kBestellung, true); + } else { + \ws_mollie\Mollie::JTLMollie()->doLog('Invalid Payment
' . print_r($payment, 1) . '
', $logData, LOGLEVEL_ERROR); + } + } else { + \ws_mollie\Mollie::JTLMollie()->doLog('Invalid Order
' . print_r($order, 1) . '
', $logData, LOGLEVEL_ERROR); } } } diff --git a/version/100/frontend/144_notify.php b/version/100/frontend/144_notify.php index 6ed1ad6..55c5501 100644 --- a/version/100/frontend/144_notify.php +++ b/version/100/frontend/144_notify.php @@ -3,43 +3,24 @@ /** * Da Webhook nicht 100% sicher vor dem Redirekt ausgeführt wird: * - IF Bestellung bereits abgesclossen ? => Update Payment, stop skript - * - ELSE weiter mit der + * - ELSE weiter mit der notify.php */ if (array_key_exists('hash', $_REQUEST)) { require_once __DIR__ . '/../class/Helper.php'; try { \ws_mollie\Helper::init(); - $payment = \ws_mollie\Model\Payment::getPaymentHash($_REQUEST['hash']); - + // If Bestellung already exists, treat as Notification if ($payment && $payment->kBestellung) { - - $mollie = new \Mollie\Api\MollieApiClient(); - $mollie->setApiKey(\ws_mollie\Helper::getSetting("api_key")); - $order = $mollie->orders->get($payment->kID); + require_once __DIR__ . '/../paymentmethod/JTLMollie.php'; + $order = JTLMollie::API()->orders->get($payment->kID); $oBestellung = new Bestellung($payment->kBestellung); $order->orderNumber = $oBestellung->cBestellNr; - \ws_mollie\Model\Payment::updateFromPayment($order, $payment->kBestellung); - $logData = '#' . $payment->kBestellung . '$' . $payment->kID . "§" . $oBestellung->cBestellNr; \ws_mollie\Mollie::JTLMollie()->doLog('Received Notification
' . print_r([$order, $payment], 1) . '
', $logData); - - switch ($order->status) { - case \Mollie\Api\Types\OrderStatus::STATUS_COMPLETED: - case \Mollie\Api\Types\OrderStatus::STATUS_PAID: - \ws_mollie\Mollie::JTLMollie()->doLog('PaymentStatus: ' . $order->status . ' => Zahlungseingang (' . $order->amount->value . ')', $logData, LOGLEVEL_DEBUG); - $oIncomingPayment = new stdClass(); - $oIncomingPayment->fBetrag = $order->amount->value; - $oIncomingPayment->cISO = $order->amount->curreny; - $oIncomingPayment->cHinweis = $order->id; - \ws_mollie\Mollie::JTLMollie()->addIncomingPayment($oBestellung, $oIncomingPayment); - case \Mollie\Api\Types\OrderStatus::STATUS_AUTHORIZED: - \ws_mollie\Mollie::JTLMollie()->doLog('PaymentStatus: ' . $order->status . ' => Bestellung bezahlt', $logData, LOGLEVEL_DEBUG); - \ws_mollie\Mollie::JTLMollie()->setOrderStatusToPaid($oBestellung); - break; - } - // stop notify.php script + \ws_mollie\Mollie::handleOrder($order, $payment->kBestellung); + // exit to stop execution of notify.php exit(); } } catch (Exception $e) { diff --git a/version/100/frontend/181_sync.php b/version/100/frontend/181_sync.php index 54ab00e..d7dc7b8 100644 --- a/version/100/frontend/181_sync.php +++ b/version/100/frontend/181_sync.php @@ -2,66 +2,26 @@ try { require_once __DIR__ . '/../class/Helper.php'; \ws_mollie\Helper::init(); - $status = (int)$args_arr['status']; /** @var Bestellung $oBestellung */ - $oBestellung = new Bestellung($args_arr['oBestellung']->kBestellung, true); - + $oBestellung = (int)$args_arr['oBestellung']; + // Order got paid with mollie: if ($oBestellung->kBestellung && $payment = \ws_mollie\Model\Payment::getPayment($oBestellung->kBestellung)) { - $logData = '#' . $payment->kBestellung . '$' . $payment->kID . "§" . $oBestellung->cBestellNr; \ws_mollie\Mollie::JTLMollie()->doLog("WAWI Abgleich: HOOK_BESTELLUNGEN_XML_BESTELLSTATUS", $logData); try { - - $mollie = new \Mollie\Api\MollieApiClient(); - $mollie->setApiKey(\ws_mollie\Helper::getSetting("api_key")); - $order = $mollie->orders->get($payment->kID); - - if ($order->status === \Mollie\Api\Types\OrderStatus::STATUS_AUTHORIZED || \Mollie\Api\Types\OrderStatus::STATUS_PAID) { - \ws_mollie\Mollie::JTLMollie()->doLog("Create Shippment:
" . print_r([$order, $args_arr], 1) . '
', $logData, LOGLEVEL_DEBUG); - - - if ($oBestellung->cTracking) { - $tracking = new stdClass(); - $tracking->carrier = $oBestellung->cVersandartName; - $tracking->url = $oBestellung->cTrackingURL; - $tracking->code = $oBestellung->cTracking; - $options['tracking'] = $tracking; - } - - if ($status === BESTELLUNG_STATUS_VERSANDT) { - $options = ['lines' => []]; - $shipment = $mollie->shipments->createFor($order, $options); - \ws_mollie\Mollie::JTLMollie()->doLog('Shipment created
' . print_r(['options' => $options, 'shipment' => $shipment], 1) . '
', $logData); - } elseif ($status === BESTELLUNG_STATUS_TEILVERSANDT) { - $lines = []; - /** - * @var int $i - * @var \Mollie\Api\Resources\OrderLine $line - */ - foreach ($order->lines as $i => $line) { - if (($quantity = \ws_mollie\Mollie::getBestellPosSent($line->sku, $oBestellung)) !== false && ($quantity - $line->quantityShipped) > 0) { - $x = $quantity - $line->quantityShipped; - $lines[] = (object)[ - 'id' => $line->id, - 'quantity' => $x, - 'amount' => (object)[ - 'currency' => $line->totalAmount->currency, - 'value' => number_format($x * $line->unitPrice->value, 2), - ], - ]; - } - } - if (count($lines)) { - $options = ['lines' => $lines]; - } else { - throw new Exception("No Lines to ship found."); - } - $shipment = $mollie->shipments->createFor($order, $options); - \ws_mollie\Mollie::JTLMollie()->doLog('Partially Shipment created
' . print_r(['options' => $options, 'shipment' => $shipment], 1) . '
', $logData); + $order = JTLMollie::API()->orders->get($payment->kID); + \ws_mollie\Mollie::handleOrder($order); + if ($order->isCreated() || $order->isPaid() || $order->isAuthorized() || $order->isShipping() || $order->isPending()) { + \ws_mollie\Mollie::JTLMollie()->doLog("Create Shippment:
" . print_r($args_arr, 1) . '
', $logData, LOGLEVEL_DEBUG); + $options = \ws_mollie\Mollie::getShipmentOptions($order, $oBestellung->kBestellung, $status); + if ($options && array_key_exists('lines', $options) && is_array($options['lines'])) { + $shipment = JTLMollie::API()->shipments->createFor($order, $options); + \ws_mollie\Mollie::JTLMollie()->doLog('Shipment created
' . print_r(['options' => $options, 'shipment' => $shipment], 1) . '
', $logData, LOGLEVEL_NOTICE); + return; } + \ws_mollie\Mollie::JTLMollie()->doLog('181_sync: options don\'t contain lines
' . print_r([$order, $options], 1) . '
', $logData, LOGLEVEL_ERROR); } - } catch (Exception $e) { \ws_mollie\Mollie::JTLMollie()->doLog('Fehler: ' . $e->getMessage() . '
' . print_r($e->getTrace(), 1) . '
', $logData, LOGLEVEL_ERROR); } diff --git a/version/100/paymentmethod/JTLMollie.php b/version/100/paymentmethod/JTLMollie.php index f5bc4da..4745672 100644 --- a/version/100/paymentmethod/JTLMollie.php +++ b/version/100/paymentmethod/JTLMollie.php @@ -308,33 +308,14 @@ public function handleNotification($order, $hash, $args) { \ws_mollie\Helper::autoload(); $logData = '#' . $order->kBestellung . "§" . $order->cBestellNr; - $this->doLog('Received Notification
' . print_r([$hash, $args], 1) . '
', $logData, LOGLEVEL_DEBUG); + $this->doLog('Received Notification
' . print_r([$hash, $args], 1) . '
', $logData, LOGLEVEL_NOTICE); try { $oMolliePayment = self::API()->orders->get($args['id']); - $logData .= '$' . $oMolliePayment->id; - $this->doLog('Got Mollie Payment:
' . print_r($oMolliePayment, 1) . '
', $logData, LOGLEVEL_DEBUG); - $oMolliePayment->orderNumber = $order->cBestellNr; - \ws_mollie\Model\Payment::updateFromPayment($oMolliePayment, $order->kBestellung); - - switch ($oMolliePayment->status) { - case \Mollie\Api\Types\OrderStatus::STATUS_PAID: - case \Mollie\Api\Types\OrderStatus::STATUS_COMPLETED: - $this->doLog('PaymentStatus: ' . $oMolliePayment->status . ' => Zahlungseingang (' . $oMolliePayment->amount->value . ')', $logData, LOGLEVEL_DEBUG); - $oIncomingPayment = new stdClass(); - $oIncomingPayment->fBetrag = $oMolliePayment->amount->value; - $oIncomingPayment->cISO = $oMolliePayment->amount->curreny; - $oIncomingPayment->cHinweis = $oMolliePayment->id; - $this->addIncomingPayment($order, $oIncomingPayment); - case \Mollie\Api\Types\OrderStatus::STATUS_AUTHORIZED: - $this->doLog('PaymentStatus: ' . $oMolliePayment->status . ' => Bestellung bezahlt', $logData, LOGLEVEL_DEBUG); - $this->setOrderStatusToPaid($order); - break; - } - + \ws_mollie\Mollie::handleOrder($oMolliePayment, $order->kBestellung); } catch (\Exception $e) { - $this->doLog($e->getMessage(), $logData); + $this->doLog('handleNotification: ' . $e->getMessage(), $logData); } } From ddd53743fca81ca4d289f251018511d0c18893c6 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Wed, 16 Jan 2019 14:09:10 +0100 Subject: [PATCH 019/280] #5 --- version/100/adminmenu/orders.php | 37 ++++-------- version/100/class/Mollie.php | 65 ++++++++++------------ version/100/frontend/131_globalinclude.php | 2 - version/100/frontend/144_notify.php | 4 +- version/100/frontend/181_sync.php | 6 +- version/100/paymentmethod/JTLMollie.php | 14 ++++- 6 files changed, 59 insertions(+), 69 deletions(-) diff --git a/version/100/adminmenu/orders.php b/version/100/adminmenu/orders.php index 9c64c83..39c97bd 100644 --- a/version/100/adminmenu/orders.php +++ b/version/100/adminmenu/orders.php @@ -6,15 +6,11 @@ echo "Kein gültige Lizenz?"; return; } - + require_once __DIR__ . '/../paymentmethod/JTLMollie.php'; global $oPlugin; - $ordersMsgs = []; - if (array_key_exists('action', $_REQUEST)) { switch ($_REQUEST['action']) { - - case 'refund': if (!array_key_exists('id', $_REQUEST)) { $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; @@ -26,14 +22,12 @@ break; } - $mollie = new \Mollie\Api\MollieApiClient(); - $mollie->setApiKey(\ws_mollie\Helper::getSetting("api_key")); - $order = $mollie->orders->get($_REQUEST['id']); + $order = JTLMollie::API()->orders->get($_REQUEST['id']); if ($order->status == \Mollie\Api\Types\OrderStatus::STATUS_CANCELED) { $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung bereits storniert']; break; } - $refund = $mollie->orderRefunds->createFor($order, ['lines' => []]); + $refund = JTLMollie::API()->orderRefunds->createFor($order, ['lines' => []]); \ws_mollie\Mollie::JTLMollie()->doLog("Order refunded:
" . print_r($refund, 1) . "
", '$' . $payment->kID . '#' . $payment->kBestellung . '§' . $payment->cOrderNumber, LOGLEVEL_NOTICE); goto order; @@ -49,14 +43,12 @@ $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; break; } - $mollie = new \Mollie\Api\MollieApiClient(); - $mollie->setApiKey(\ws_mollie\Helper::getSetting("api_key")); - $order = $mollie->orders->get($_REQUEST['id']); + $order = JTLMollie::API()->orders->get($_REQUEST['id']); if ($order->status == \Mollie\Api\Types\OrderStatus::STATUS_CANCELED) { $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung bereits storniert']; break; } - $cancel = $mollie->orders->cancel($order->id); + $cancel = JTLMollie::API()->orders->cancel($order->id); \ws_mollie\Mollie::JTLMollie()->doLog("Order canceled:
" . print_r($cancel, 1) . "
", '$' . $payment->kID . '#' . $payment->kBestellung . '§' . $payment->cOrderNumber, LOGLEVEL_NOTICE); goto order; break; @@ -71,9 +63,7 @@ $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; break; } - $mollie = new \Mollie\Api\MollieApiClient(); - $mollie->setApiKey(\ws_mollie\Helper::getSetting("api_key")); - $order = $mollie->orders->get($_REQUEST['id']); + $order = JTLMollie::API()->orders->get($_REQUEST['id']); if ($order->status !== \Mollie\Api\Types\OrderStatus::STATUS_AUTHORIZED && $order->status !== \Mollie\Api\Types\OrderStatus::STATUS_SHIPPING) { $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Nur autorisierte Zahlungen können erfasst werden!']; break; @@ -97,7 +87,7 @@ } // CAPTURE ALL - $shipment = $mollie->shipments->createFor($order, $options); + $shipment = JTLMollie::API()->shipments->createFor($order, $options); $ordersMsgs[] = (object)['type' => 'success', 'text' => 'Zahlung wurde erfolgreich erfasst!']; \ws_mollie\Mollie::JTLMollie()->doLog('Shipment created
' . print_r(['options' => $options, 'shipment' => $shipment], 1) . '
', $logData); goto order; @@ -109,10 +99,7 @@ break; } - $mollie = new \Mollie\Api\MollieApiClient(); - $mollie->setApiKey(\ws_mollie\Helper::getSetting("api_key")); - - $order = $mollie->orders->get($_REQUEST['id']); + $order = JTLMollie::API()->orders->get($_REQUEST['id']); $payment = \ws_mollie\Model\Payment::getPaymentMollie($_REQUEST['id']); if ($payment) { $oBestellung = new Bestellung($payment->kBestellung, false); @@ -126,9 +113,9 @@ } $logs = Shop::DB()->executeQueryPrepared("SELECT * FROM tzahlungslog WHERE cLogData LIKE :kBestellung OR cLogData LIKE :cBestellNr OR cLogData LIKE :MollieID ORDER BY dDatum DESC", [ - ':kBestellung' => '%#' . $payment->kBestellung . '%', - ':cBestellNr' => '%§' . $payment->cOrderNumber . '%', - ':MollieID' => '%$' . $payment->kID . '%', + ':kBestellung' => '%#' . ($payment->kBestellung ?: '##') . '%', + ':cBestellNr' => '%§' . ($payment->cOrderNumber ?: '§§') . '%', + ':MollieID' => '%$' . ($payment->kID ?: '$$') . '%', ], 2); Shop::Smarty()->assign('payment', $payment) @@ -142,7 +129,7 @@ } - $payments = Shop::DB()->executeQueryPrepared("SELECT * FROM xplugin_ws_mollie_payments", [], 2); + $payments = Shop::DB()->executeQueryPrepared("SELECT * FROM xplugin_ws_mollie_payments WHERE kBestellung IS NOT NULL AND cStatus != 'created'", [], 2); foreach ($payments as $i => $payment) { $payments[$i]->oBestellung = new Bestellung($payment->kBestellung, false); } diff --git a/version/100/class/Mollie.php b/version/100/class/Mollie.php index 3a74cd7..e9d4df6 100644 --- a/version/100/class/Mollie.php +++ b/version/100/class/Mollie.php @@ -155,47 +155,40 @@ public static function getShipmentOptions(Order $order, $kBestellung, $newStatus * @return bool * @throws \Exception */ - public static function handleOrder(Order $order, $kBestellung = null) + public static function handleOrder(Order $order, $kBestellung) { - $logData = '$' . $order->id . '#' . $kBestellung . "§" . $order->orderNumber; - // 1. Save to DB - \ws_mollie\Model\Payment::updateFromPayment($order, $kBestellung); - - if ($kBestellung) { - $oBestellung = new \Bestellung($kBestellung); - if ($oBestellung->kBestellung) { - - // 2. Check PaymentStatus - switch ($order->status) { - case OrderStatus::STATUS_PAID: - case OrderStatus::STATUS_COMPLETED: - $oIncomingPayment = new \stdClass(); - $oIncomingPayment->fBetrag = $order->amount->value; - $oIncomingPayment->cISO = $order->amount->curreny; - $oIncomingPayment->cHinweis = $order->id; - Mollie::JTLMollie()->addIncomingPayment($oBestellung, $oIncomingPayment); - Mollie::JTLMollie()->setOrderStatusToPaid($oBestellung); - Mollie::JTLMollie()->doLog('PaymentStatus: ' . $order->status . ' => Zahlungseingang (' . $order->amount->value . ')', $logData, LOGLEVEL_DEBUG); - break; - case OrderStatus::STATUS_SHIPPING: - case OrderStatus::STATUS_AUTHORIZED: - case OrderStatus::STATUS_PENDING: - Mollie::JTLMollie()->setOrderStatusToPaid($oBestellung); - Mollie::JTLMollie()->doLog('PaymentStatus: ' . $order->status . ' => Bestellung bezahlt', $logData, LOGLEVEL_NOTICE); - break; - case OrderStatus::STATUS_CANCELED: - case OrderStatus::STATUS_EXPIRED: - Mollie::JTLMollie()->doLog('PaymentStatus: ' . $order->status, $logData, LOGLEVEL_ERROR); - break; - - } - return true; + $oBestellung = new \Bestellung($kBestellung); + if ($oBestellung->kBestellung) { + $order->orderNumber = $oBestellung->cBestellNr; + \ws_mollie\Model\Payment::updateFromPayment($order, $kBestellung); + // 2. Check PaymentStatus + switch ($order->status) { + case OrderStatus::STATUS_PAID: + case OrderStatus::STATUS_COMPLETED: + $oIncomingPayment = new \stdClass(); + $oIncomingPayment->fBetrag = $order->amount->value; + $oIncomingPayment->cISO = $order->amount->curreny; + $oIncomingPayment->cHinweis = $order->id; + Mollie::JTLMollie()->addIncomingPayment($oBestellung, $oIncomingPayment); + Mollie::JTLMollie()->setOrderStatusToPaid($oBestellung); + Mollie::JTLMollie()->doLog('PaymentStatus: ' . $order->status . ' => Zahlungseingang (' . $order->amount->value . ')', $logData, LOGLEVEL_DEBUG); + break; + case OrderStatus::STATUS_SHIPPING: + case OrderStatus::STATUS_AUTHORIZED: + case OrderStatus::STATUS_PENDING: + Mollie::JTLMollie()->setOrderStatusToPaid($oBestellung); + Mollie::JTLMollie()->doLog('PaymentStatus: ' . $order->status . ' => Bestellung bezahlt', $logData, LOGLEVEL_NOTICE); + break; + case OrderStatus::STATUS_CANCELED: + case OrderStatus::STATUS_EXPIRED: + Mollie::JTLMollie()->doLog('PaymentStatus: ' . $order->status, $logData, LOGLEVEL_ERROR); + break; } - return false; + return true; } - return true; + return false; } } \ No newline at end of file diff --git a/version/100/frontend/131_globalinclude.php b/version/100/frontend/131_globalinclude.php index c4872d8..4f4d3ac 100644 --- a/version/100/frontend/131_globalinclude.php +++ b/version/100/frontend/131_globalinclude.php @@ -48,8 +48,6 @@ require_once PFAD_ROOT . 'includes/mailTools.php'; $oBestellung = fakeBestellung(); $oBestellung = finalisiereBestellung(); - $order->orderNumber = $oBestellung->cBestellNr; - \ws_mollie\Mollie::JTLMollie()->doLog('Bestellung finalized => redirect
' . print_r($order, 1) . '
', $logData, LOGLEVEL_DEBUG); \ws_mollie\Mollie::handleOrder($order, $oBestellung->kBestellung); \ws_mollie\Mollie::getOrderCompletedRedirect($oBestellung->kBestellung, true); diff --git a/version/100/frontend/144_notify.php b/version/100/frontend/144_notify.php index 55c5501..8856259 100644 --- a/version/100/frontend/144_notify.php +++ b/version/100/frontend/144_notify.php @@ -15,9 +15,7 @@ if ($payment && $payment->kBestellung) { require_once __DIR__ . '/../paymentmethod/JTLMollie.php'; $order = JTLMollie::API()->orders->get($payment->kID); - $oBestellung = new Bestellung($payment->kBestellung); - $order->orderNumber = $oBestellung->cBestellNr; - $logData = '#' . $payment->kBestellung . '$' . $payment->kID . "§" . $oBestellung->cBestellNr; + $logData = '#' . $payment->kBestellung . '$' . $payment->kID; \ws_mollie\Mollie::JTLMollie()->doLog('Received Notification
' . print_r([$order, $payment], 1) . '
', $logData); \ws_mollie\Mollie::handleOrder($order, $payment->kBestellung); // exit to stop execution of notify.php diff --git a/version/100/frontend/181_sync.php b/version/100/frontend/181_sync.php index d7dc7b8..3ad12c6 100644 --- a/version/100/frontend/181_sync.php +++ b/version/100/frontend/181_sync.php @@ -4,18 +4,20 @@ \ws_mollie\Helper::init(); $status = (int)$args_arr['status']; /** @var Bestellung $oBestellung */ - $oBestellung = (int)$args_arr['oBestellung']; + $oBestellung = $args_arr['oBestellung']; // Order got paid with mollie: if ($oBestellung->kBestellung && $payment = \ws_mollie\Model\Payment::getPayment($oBestellung->kBestellung)) { $logData = '#' . $payment->kBestellung . '$' . $payment->kID . "§" . $oBestellung->cBestellNr; \ws_mollie\Mollie::JTLMollie()->doLog("WAWI Abgleich: HOOK_BESTELLUNGEN_XML_BESTELLSTATUS", $logData); try { $order = JTLMollie::API()->orders->get($payment->kID); - \ws_mollie\Mollie::handleOrder($order); + $order->orderNumber = $oBestellung->cBestellNr; + \ws_mollie\Mollie::handleOrder($order, $oBestellung->kBestellung); if ($order->isCreated() || $order->isPaid() || $order->isAuthorized() || $order->isShipping() || $order->isPending()) { \ws_mollie\Mollie::JTLMollie()->doLog("Create Shippment:
" . print_r($args_arr, 1) . '
', $logData, LOGLEVEL_DEBUG); $options = \ws_mollie\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); \ws_mollie\Mollie::JTLMollie()->doLog('Shipment created
' . print_r(['options' => $options, 'shipment' => $shipment], 1) . '
', $logData, LOGLEVEL_NOTICE); return; diff --git a/version/100/paymentmethod/JTLMollie.php b/version/100/paymentmethod/JTLMollie.php index 4745672..44984cb 100644 --- a/version/100/paymentmethod/JTLMollie.php +++ b/version/100/paymentmethod/JTLMollie.php @@ -61,6 +61,19 @@ public static function Helper() return self::$_helper; } + /** + * @param Bestellung $order + * @return PaymentMethod|void + */ + public function setOrderStatusToPaid($order) + { + // If paid already, do nothing + if ((int)$order->cStatus >= BESTELLUNG_STATUS_BEZAHLT) { + return; + } + parent::setOrderStatusToPaid($order); + } + /** * @param Bestellung $order * @return array @@ -312,7 +325,6 @@ public function handleNotification($order, $hash, $args) try { $oMolliePayment = self::API()->orders->get($args['id']); - $oMolliePayment->orderNumber = $order->cBestellNr; \ws_mollie\Mollie::handleOrder($oMolliePayment, $order->kBestellung); } catch (\Exception $e) { $this->doLog('handleNotification: ' . $e->getMessage(), $logData); From ecbbfbe68c606479c312fc473ac2a9714621bddb Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Wed, 16 Jan 2019 17:23:41 +0100 Subject: [PATCH 020/280] shipping address --- version/100/paymentmethod/JTLMollie.php | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/version/100/paymentmethod/JTLMollie.php b/version/100/paymentmethod/JTLMollie.php index 44984cb..d1506b4 100644 --- a/version/100/paymentmethod/JTLMollie.php +++ b/version/100/paymentmethod/JTLMollie.php @@ -76,6 +76,7 @@ public function setOrderStatusToPaid($order) /** * @param Bestellung $order + * @param $hash * @return array */ protected function getOrderData(Bestellung $order, $hash) @@ -89,6 +90,7 @@ protected function getOrderData(Bestellung $order, $hash) 'orderNumber' => $order->cBestellNr, 'lines' => [], 'billingAddress' => new stdClass(), + 'shippingAddress' => new stdClass(), 'redirectUrl' => (int)$this->duringCheckout ? Shop::getURL() . '/bestellabschluss.php?mollie=' . md5($hash) : $this->getReturnURL($order), 'webhookUrl' => $this->getNotificationURL($hash) . '&hash=' . md5($hash), ]; @@ -97,7 +99,7 @@ protected function getOrderData(Bestellung $order, $hash) $data['method'] = static::MOLLIE_METHOD; } $data['billingAddress']->organizationName = utf8_encode($order->oRechnungsadresse->cFirma); - $data['billingAddress']->title = $order->oRechnungsadresse->cAnrede === 'm' ? 'Herr' : 'Frau'; // TODO: Sprachvariable + $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 = $order->oRechnungsadresse->cMail; @@ -106,6 +108,18 @@ protected function getOrderData(Bestellung $order, $hash) $data['billingAddress']->city = utf8_encode($order->oRechnungsadresse->cOrt); $data['billingAddress']->country = $order->oRechnungsadresse->cLand; + //if ((int)$order->kLieferadresse) { + $data['shippingAddress']->organizationName = utf8_encode($order->Lieferadresse->cFirma); + $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 = $order->oRechnungsadresse->cMail; + $data['shippingAddress']->streetAndNumber = utf8_encode($order->Lieferadresse->cStrasse . ' ' . $order->Lieferadresse->cHausnummer); + $data['shippingAddress']->postalCode = $order->Lieferadresse->cPLZ; + $data['shippingAddress']->city = utf8_encode($order->Lieferadresse->cOrt); + $data['shippingAddress']->country = $order->Lieferadresse->cLand; + //} + /** @var WarenkorbPos $oPosition */ foreach ($order->Positionen as $oPosition) { $line = new stdClass(); From 357e0ab608ed230d6390d36877b1112277e4cd59 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Fri, 18 Jan 2019 11:50:56 +0100 Subject: [PATCH 021/280] optimize code, remove licence check --- info.xml | 5 - version/100/adminmenu/custom.php.dist | 15 -- version/100/adminmenu/info.php | 6 - version/100/adminmenu/tpl/order.tpl | 17 +- version/100/adminmenu/tpl/orders.tpl | 21 +- version/100/adminmenu/tpl/paymentmethods.tpl | 19 +- version/100/class/Helper.php | 246 +----------------- version/100/class/Model/AbstractModel.php | 3 +- version/100/class/Model/Payment.php | 2 - version/100/class/Mollie.php | 7 +- version/100/frontend/131_globalinclude.php | 4 + version/100/frontend/hook.php.dist | 15 -- version/100/paymentmethod/JTLMollie.php | 14 +- .../100/paymentmethod/JTLMollieBancontact.php | 7 +- .../paymentmethod/JTLMollieBanktransfer.php | 7 +- .../100/paymentmethod/JTLMollieBelfius.php | 7 +- .../100/paymentmethod/JTLMollieBitcoin.php | 7 +- .../100/paymentmethod/JTLMollieCreditCard.php | 7 +- .../paymentmethod/JTLMollieDirectDebit.php | 7 +- version/100/paymentmethod/JTLMollieEPS.php | 7 +- .../100/paymentmethod/JTLMollieGiftcard.php | 7 +- .../100/paymentmethod/JTLMollieGiropay.php | 7 +- version/100/sql/100.sql | 3 +- 23 files changed, 92 insertions(+), 348 deletions(-) delete mode 100644 version/100/adminmenu/custom.php.dist delete mode 100644 version/100/frontend/hook.php.dist diff --git a/info.xml b/info.xml index eda52ab..e2259e6 100644 --- a/info.xml +++ b/info.xml @@ -17,7 +17,6 @@ 181_sync.php - Bestellungen orders.php @@ -47,16 +46,12 @@ - - - Info info.php - mollie diff --git a/version/100/adminmenu/custom.php.dist b/version/100/adminmenu/custom.php.dist deleted file mode 100644 index d34226d..0000000 --- a/version/100/adminmenu/custom.php.dist +++ /dev/null @@ -1,15 +0,0 @@ -' . '
'; - if (\ws_mollie\Helper::_licCache()->disabled) { - echo "
Die Pluginlizenz und das Plugin wurden deaktiviert. " - . "" - . "Klicke hier um die Lizenz erneut zu überprüfen.
"; - } - } catch (Exception $e) { echo "
Fehler: {$e->getMessage()}
"; \ws_mollie\Helper::logExc($e); diff --git a/version/100/adminmenu/tpl/order.tpl b/version/100/adminmenu/tpl/order.tpl index aa60b3b..b5c5403 100644 --- a/version/100/adminmenu/tpl/order.tpl +++ b/version/100/adminmenu/tpl/order.tpl @@ -1,17 +1,18 @@ +

« Bestellung: {$oBestellung->cBestellNr} - - {if (int)$oBestellung->cStatus == 1} + {if $oBestellung->cStatus|intval == 1} OFFEN - {elseif (int)$oBestellung->cStatus == 2} + {elseif $oBestellung->cStatus|intval == 2} IN BEARBEITUNG - {elseif (int)$oBestellung->cStatus == 3} + {elseif $oBestellung->cStatus|intval == 3} BEZAHLT - {elseif (int)$oBestellung->cStatus == 4} + {elseif $oBestellung->cStatus|intval == 4} VERSANDT - {elseif (int)$oBestellung->cStatus == 5} + {elseif $oBestellung->cStatus|intval == 5} TEILVERSANDT - {elseif (int)$oBestellung->cStatus == -1} + {elseif $oBestellung->cStatus|intval == -1} STORNO {else} n/a @@ -57,7 +58,7 @@

Positionen:

- {if ($order->status === 'authorized' || $order->status === 'shipping') && (int)$oBestellung->cStatus >= 3} + {if ($order->status === 'authorized' || $order->status === 'shipping') && $oBestellung->cStatus|intval >= 3} {$line->name|utf8_decode} {$line->type} {$line->quantity} - {(float)$line->vatRate}% + {$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} diff --git a/version/100/adminmenu/tpl/orders.tpl b/version/100/adminmenu/tpl/orders.tpl index daa3e7a..06f5ae9 100644 --- a/version/100/adminmenu/tpl/orders.tpl +++ b/version/100/adminmenu/tpl/orders.tpl @@ -1,5 +1,4 @@ -{*$payments|var_dump*} - + {if count($ordersMsgs)} {foreach from=$ordersMsgs item=alert}
{$alert->text}
@@ -56,17 +55,17 @@ - {if (int)$payment->oBestellung->cStatus == 1} + {if $payment->oBestellung->cStatus|intval == 1} OFFEN - {elseif (int)$payment->oBestellung->cStatus == 2} + {elseif $payment->oBestellung->cStatus|intval == 2} IN BEARBEITUNG - {elseif (int)$payment->oBestellung->cStatus == 3} + {elseif $payment->oBestellung->cStatus|intval == 3} BEZAHLT - {elseif (int)$payment->oBestellung->cStatus == 4} + {elseif $payment->oBestellung->cStatus|intval == 4} VERSANDT - {elseif (int)$payment->oBestellung->cStatus == 5} + {elseif $payment->oBestellung->cStatus|intval == 5} TEILVERSANDT - {elseif (int)$payment->oBestellung->cStatus == -1} + {elseif $payment->oBestellung->cStatus|intval == -1} STORNO {else} n/a @@ -85,10 +84,10 @@ - \ No newline at end of file + + + {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} \ No newline at end of file From 1820ebfd37a1c56fa99bc70596b1703745f37b10 Mon Sep 17 00:00:00 2001 From: "dash.bar" Date: Mon, 11 Feb 2019 16:44:14 +0100 Subject: [PATCH 031/280] update base files --- version/100/adminmenu/info.php | 21 + version/100/adminmenu/tpl/info.tpl | 41 ++ version/100/class/Helper.php | 635 ++++++++++++++++++++++------- 3 files changed, 554 insertions(+), 143 deletions(-) create mode 100644 version/100/adminmenu/tpl/info.tpl diff --git a/version/100/adminmenu/info.php b/version/100/adminmenu/info.php index 534253c..6876c3c 100644 --- a/version/100/adminmenu/info.php +++ b/version/100/adminmenu/info.php @@ -4,6 +4,11 @@ try { \ws_mollie\Helper::init(); + if (array_key_exists("action", $_REQUEST) && $_REQUEST['action'] === 'update-plugin') { + Shop::Smarty()->assign('defaultTabbertab', \ws_mollie\Helper::getAdminmenu('Info')); + \ws_mollie\Helper::selfupdate(); + } + $svgQuery = http_build_query([ 'p' => \ws_mollie\Helper::oPlugin()->cPluginID, 'v' => \ws_mollie\Helper::oPlugin()->nVersion, @@ -31,6 +36,22 @@ '
' . ''; + if (\ws_mollie\Helper::_licCache()->disabled) { + echo ""; + } + + try { + $latestRelease = \ws_mollie\Helper::getLatestRelease(array_key_exists('update', $_REQUEST)); + if ((int)\ws_mollie\Helper::oPlugin()->nVersion < (int)$latestRelease->version) { + Shop::Smarty()->assign('update', $latestRelease); + } + + } catch (\Exception $e) { + } + + Shop::Smarty()->display(\ws_mollie\Helper::oPlugin()->cAdminmenuPfad . '/tpl/info.tpl'); } catch (Exception $e) { echo "
Fehler: {$e->getMessage()}
"; \ws_mollie\Helper::logExc($e); diff --git a/version/100/adminmenu/tpl/info.tpl b/version/100/adminmenu/tpl/info.tpl new file mode 100644 index 0000000..eb5ae3a --- /dev/null +++ b/version/100/adminmenu/tpl/info.tpl @@ -0,0 +1,41 @@ +
+
+
+ {if isset($update)} + +
+

Update auf Version {$update->version} verfügbar!

+
+
+
+
Version:
+
{$update->version}
+
+
+
Erschienen:
+
{$update->create_date}
+
+
+
Changelog:
+
+ +
+
+ +
+
+ +
+
+ {/if} +
+
\ No newline at end of file diff --git a/version/100/class/Helper.php b/version/100/class/Helper.php index 96fa6bb..dd90ed3 100644 --- a/version/100/class/Helper.php +++ b/version/100/class/Helper.php @@ -3,174 +3,523 @@ namespace ws_mollie { - /** - * Class Helper - * @package ws_mollie - */ - final class Helper - { + if (!class_exists('ws_mollie\Helper')) { + /** + * Class Helper + * @package ws_mollie + */ + final class Helper + { - /** - * Is ::autoload() already called? - * - * @var bool|null - */ - private static $_autoload; + /** + * Is ::autoload() already called? + * + * @var bool|null + */ + private static $_autoload; - /** - * @var \Plugin - */ - private static $oPlugin; + /** + * Is Licence valid? + * + * @var bool|null + */ + private static $_licence; - /** - * Load Vendor Autoloader - * @return bool - */ - public static function autoload() - { - if (null === self::$_autoload) { - if (file_exists(__DIR__ . '/../../../vendor/autoload.php')) { - require_once __DIR__ . '/../../../vendor/autoload.php'; + /** + * @var string + */ + private static $_tmpLicence; + + /** + * @var \Plugin + */ + private static $oPlugin; + + /** + * Load Vendor Autoloader + * @return bool + */ + public static function autoload() + { + if (null === self::$_autoload) { + if (file_exists(__DIR__ . '/../../../vendor/autoload.php')) { + require_once __DIR__ . '/../../../vendor/autoload.php'; + } + + self::$_autoload = spl_autoload_register(function ($class) { + $prefix = 'ws_mollie\\'; + $baseDir = __DIR__ . DIRECTORY_SEPARATOR; + + $len = strlen($prefix); + if (strncmp($prefix, $class, $len) !== 0) { + return; + } + + $relativeClass = substr($class, $len); + $file = $baseDir . str_replace('\\', DIRECTORY_SEPARATOR, $relativeClass) . '.php'; + if (file_exists($file)) { + /** @noinspection PhpIncludeInspection */ + require_once $file; + } + }); } + return self::$_autoload; + } + + /** + * @throws \Exception + */ + public static function selfupdate() + { + + if(function_exists('opcache_reset')){ + opcache_reset(); + } + + // 0. GET RELEASE INFO + $release = self::getLatestRelease(true); + $url = $release->short_url != '' ? $release->short_url : $release->full_url; + $filename = basename($release->full_url); + $tmpDir = PFAD_ROOT . PFAD_COMPILEDIR; + $pluginsDir = PFAD_ROOT . PFAD_PLUGIN; - self::$_autoload = spl_autoload_register(function ($class) { - $prefix = 'ws_mollie\\'; - $baseDir = __DIR__ . DIRECTORY_SEPARATOR; + // 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!'); + } - $len = strlen($prefix); - if (strncmp($prefix, $class, $len) !== 0) { - return; + 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(); - $relativeClass = substr($class, $len); - $file = $baseDir . str_replace('\\', DIRECTORY_SEPARATOR, $relativeClass) . '.php'; - if (file_exists($file)) { - /** @noinspection PhpIncludeInspection */ - require_once $file; + 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); + if ($res !== 0) { + header('Location: ' . \Shop::getURL() . DIRECTORY_SEPARATOR . PFAD_ADMIN . 'pluginverwaltung.php', true); + } else { + throw new \Exception('Entpacken fehlgeschlagen: ' . $zip->errorCode()); } - }); + } } - return self::$_autoload; - } - /** - * Register PSR-4 autoloader - * Licence-Check - * @return bool - */ - public static function init() - { - return self::autoload(); - } + /** + * @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']); - /** - * 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; - } + $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); + } + } - /** - * 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__); + /** + * Register PSR-4 autoloader + * Licence-Check + * @return bool + */ + public static function init() + { + ini_set('xdebug.default_enable', defined('WS_XDEBUG_ENABLED')); + self::autoload(); + if (null === self::$_licence) { + + if (array_key_exists('_licActivate', $_REQUEST) && $_REQUEST['_licActivate'] === __NAMESPACE__) { + self::_licActivate(self::_licCache()); + } + + self::$_licence = false; + self::$_tmpLicence = md5(time()); + if ($_SERVER['HTTP_HOST'] === 'localhost') { + self::$_licence = true; + } else { + self::$_licence = self::licCheck(md5(self::$_tmpLicence)) === md5(self::$_tmpLicence); + } + } + + if (!self::$_licence && self::isAdminBackend()) { + \Shop::Smarty()->assign('defaultTabbertab', self::getAdminmenu('Info')); + } + + + return self::$_autoload && self::$_licence; } - 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]; + /** + * @param $oL + * @return mixed + */ + private static function _licActivate($oL) + { + $oL->nextCheck = 0; + $oL->fails = 0; + $oL->disabled = 0; + self::_licSave($oL); + return $oL; } - 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 $oL + * @param bool $checksum + * @return mixed + */ + private static function _licSave($oL, $checksum = false) + { + self::setSetting('lic_validUntil', $oL->validUntil); + self::setSetting('lic_nextCheck', $oL->nextCheck); + self::setSetting('lic_test', $oL->test); + if ($checksum === true) { + self::setSetting('lic_checkSum', base64_encode(sha1($oL->validUntil . $oL->nextCheck . $oL->test . $oL->disabled . $oL->fails . __NAMESPACE__, true))); + } + self::setSetting('lic_disabled', (int)$oL->disabled); + self::setSetting('lic_fails', $oL->fails); + return $oL; + } + /** + * 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; - /** - * @param \Exception $exc - * @param bool $trace - * @return void - */ - public static function logExc(\Exception $exc, $trace = true) - { - \Jtllog::writeLog(__NAMESPACE__ . ': ' . $exc->getMessage() . ($trace ? ' - ' . $exc->getTraceAsString() : '')); - } + 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; + } - /** - * Checks if admin session is loaded - * - * @return bool - */ - public static function isAdminBackend() - { - return session_name() === 'eSIdAdm'; - } + /** + * 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; + } - /** - * 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; + /** + * @param $oL + * @return bool|string + */ + private static function _licValid($oL) + { + if ($nextCheck = strtotime($oL->nextCheck)) { + if ($nextCheck > time()) { + if ($validUntil = strtotime($oL->validUntil)) { + if ($validUntil > time() || (int)$oL->test === 0) { + return md5(self::$_tmpLicence); + } + } + } } + return false; + } - return $kPluginAdminMenu; - } - } + /** + * @return \stdClass + */ + public static function _licCache() + { + $oL = new \stdClass(); + $oL->validUntil = self::getSetting('lic_validUntil'); + $oL->nextCheck = self::getSetting('lic_nextCheck'); + $oL->test = self::getSetting('lic_test'); + $oL->checksum = self::getSetting('lic_checkSum'); + $oL->disabled = self::getSetting('lic_disabled') === null ? 0 : (int)self::getSetting('lic_disabled'); + $oL->fails = self::getSetting('lic_fails') ?: 0; + return $oL; + } + + /** + * 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; + } + + /** + * @param $x + * @return bool|string + */ + private static function licCheck($x) + { + if ($x !== md5(self::$_tmpLicence)) { + return false; + } + $oL = self::_licCache(); + if (self::_licCRC($oL) === true) { + // CRC OK? + if (self::_licValid($oL) === md5(self::$_tmpLicence)) { + return md5(self::$_tmpLicence); + } + } + if ($oL->disabled === 0) { + $oL = self::_licLive($oL); + + if ($oL->disabled === 0 && self::_licValid($oL) === md5(self::$_tmpLicence)) { + return md5(self::$_tmpLicence); + } + } + return false; + + } + + /** + * @param $oL + * @return bool + */ + private static function _licCRC($oL) + { + $crc_valid = false; + if ($checksum = base64_encode(sha1($oL->validUntil . $oL->nextCheck . $oL->test . $oL->disabled . $oL->fails . __NAMESPACE__, true))) { + $crc_valid = $checksum == $oL->checksum; + } + return $oL->checksum && $crc_valid; + } + + /** + * @param $oL + * @return mixed + */ + private static function _licLive($oL) + { + try { + + if (!function_exists('curl_init')) { + throw new \Exception(__NAMESPACE__ . ': cURL needs to be installed!'); + } + + $urlShop = self::getDomain(); + $params = [ + 'domain' => $urlShop, + 'plugin_version' => (int)self::oPlugin()->nVersion, + 'plugin_id' => self::oPlugin()->cPluginID, + 'email' => self::_masterMail(), + 'shop_version' => (string)(defined('APPLICATION_VERSION') ? APPLICATION_VERSION : JTL_VERSION), + 'shop_build' => defined('APPLICATION_BUILD_SHA') ? APPLICATION_BUILD_SHA : '', + 'php_version' => PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION . '.' . PHP_RELEASE_VERSION, + 'php_extra_version' => PHP_EXTRA_VERSION, + 'php_os' => PHP_OS, + 'server' => array_key_exists('SERVER_SOFTWARE', $_SERVER) ? $_SERVER['SERVER_SOFTWARE'] : '', + ]; + $curl = curl_init('https://lic.dash.bar'); + @curl_setopt($curl, CURLOPT_POST, 1); + @curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($params)); // http_build_query($params, '', '&')); + @curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 3); + @curl_setopt($curl, CURLOPT_TIMEOUT, 3); + @curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + @curl_setopt($curl, CURLOPT_HEADER, 0); + @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 licence info: ' . $statusCode); + } + /** @noinspection UnserializeExploitsInspection */ + if ($response = json_decode($data)) { + + $checksum = md5(base64_encode($response->data->validUntil . $response->data->nextCheck . ($response->data->testLicence ? 'Y' : 'N'))); + + if (!$response || !isset($response->data) || $response->data === false || !isset($response->checksum) || $response->checksum !== $checksum) { + throw new \Exception(__NAMESPACE__ . ': Invalid licence info: ' . print_r($response, 1)); + } + $oLL = $response->data; + if (self::isPresent($oLL->validUntil)) { + $oL->validUntil = date('Y-m-d', $oLL->validUntil); + } + if (self::isPresent($oLL->nextCheck)) { + $oL->nextCheck = date('Y-m-d', $oLL->nextCheck); + } + if (self::isPresent($oLL->testLicence)) { + $oL->test = $oLL->testLicence ? 1 : 0; + } + $oL->fails = 0; + self::_licSave($oL, true); + + } else { + throw new \Exception(__NAMESPACE__ . ': Could not decode licence info: ' . print_r($response, 1)); + } + + } catch (\Exception $e) { + $oL->disabled = (++$oL->fails) >= 3 ? 1 : 0; + $oL->nextCheck = date("Y-m-d", strtotime("+1 DAY")); + $oL->validUntil = date("Y-m-d", strtotime("+1 DAY"));; + + self::logExc($e, false); + self::_licSave($oL, true); + } + return $oL; + } + + + /** + * @param $val + * @return bool + * @throws \Exception + */ + private static function ispresent($val) + { + if (isset($val)) { + return true; + } else { + throw new \Exception(__NAMESPACE__ . ': Could ned find value from license server ' . print_r($val, 1)); + } + } + + /** + * 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); + } + + /** + * @return mixed + */ + private static function _masterMail() + { + $settings = \Shop::getSettings(array(CONF_EMAILS)); + return $settings['emails']['email_master_absender']; + } + + /** + * @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; + } + + } + } } From 5db378a00b8a5e66b248864210f2803040feb960 Mon Sep 17 00:00:00 2001 From: "C. Proske" Date: Mon, 11 Feb 2019 16:53:37 +0100 Subject: [PATCH 032/280] push mollie php sdk to 2.6.1 --- composer.json | 2 +- composer.lock | 26 +++++++++++++------------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/composer.json b/composer.json index 5a9036b..9019abc 100644 --- a/composer.json +++ b/composer.json @@ -4,7 +4,7 @@ "type": "project", "require": { "roave/security-advisories": "dev-master", - "mollie/mollie-api-php": "^2.2" + "mollie/mollie-api-php": "^2.6.1" }, "license": "Proprietary", "authors": [ diff --git a/composer.lock b/composer.lock index d9ed733..e8d8655 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "5029290aeb5c14ac83a3fd115717bb00", + "content-hash": "1f1e6e29b31f6171b5cbf35bd44b668f", "packages": [ { "name": "composer/ca-bundle", @@ -247,16 +247,16 @@ }, { "name": "mollie/mollie-api-php", - "version": "v2.6.0", + "version": "v2.6.1", "source": { "type": "git", "url": "https://github.com/mollie/mollie-api-php.git", - "reference": "bb439a50e9601a612f5da2d10fb5d29d758b717d" + "reference": "e4ed1ba98ca690585dca613eded3f5ffe6c4ffb2" }, "dist": { "type": "zip", - "url": "https://github.com/gitapi/repos/mollie/mollie-api-php/zipball/bb439a50e9601a612f5da2d10fb5d29d758b717d", - "reference": "bb439a50e9601a612f5da2d10fb5d29d758b717d", + "url": "https://github.com/gitapi/repos/mollie/mollie-api-php/zipball/e4ed1ba98ca690585dca613eded3f5ffe6c4ffb2", + "reference": "e4ed1ba98ca690585dca613eded3f5ffe6c4ffb2", "shasum": "" }, "require": { @@ -328,7 +328,7 @@ "sofortbanking", "subscriptions" ], - "time": "2019-01-18T15:28:20+00:00" + "time": "2019-01-31T07:26:26+00:00" }, { "name": "psr/http-message", @@ -426,12 +426,12 @@ "source": { "type": "git", "url": "https://github.com/Roave/SecurityAdvisories.git", - "reference": "db876706aacd4ffbd1c253358d19a651e50e65c2" + "reference": "344bf4ed1263c75e7f96b87b80c52e8373561e19" }, "dist": { "type": "zip", - "url": "https://github.com/gitapi/repos/Roave/SecurityAdvisories/zipball/db876706aacd4ffbd1c253358d19a651e50e65c2", - "reference": "db876706aacd4ffbd1c253358d19a651e50e65c2", + "url": "https://github.com/gitapi/repos/Roave/SecurityAdvisories/zipball/344bf4ed1263c75e7f96b87b80c52e8373561e19", + "reference": "344bf4ed1263c75e7f96b87b80c52e8373561e19", "shasum": "" }, "conflict": { @@ -466,8 +466,8 @@ "doctrine/mongodb-odm-bundle": ">=2,<3.0.1", "doctrine/orm": ">=2,<2.4.8|>=2.5,<2.5.1", "dompdf/dompdf": ">=0.6,<0.6.2", - "drupal/core": ">=7,<7.60|>=8,<8.5.8|>=8.6,<8.6.2", - "drupal/drupal": ">=7,<7.60|>=8,<8.5.8|>=8.6,<8.6.2", + "drupal/core": ">=7,<7.62|>=8,<8.5.9|>=8.6,<8.6.6", + "drupal/drupal": ">=7,<7.62|>=8,<8.5.9|>=8.6,<8.6.6", "erusev/parsedown": "<1.7", "ezsystems/ezpublish-kernel": ">=5.3,<5.3.12.1|>=5.4,<5.4.13.1|>=6,<6.7.9.1|>=6.8,<6.13.5.1|>=7,<7.2.4.1|>=7.3,<7.3.2.1", "ezsystems/ezpublish-legacy": ">=5.3,<5.3.12.6|>=5.4,<5.4.12.3|>=2011,<2017.12.4.3|>=2018.6,<2018.6.1.4|>=2018.9,<2018.9.1.3", @@ -564,7 +564,7 @@ "symfony/yaml": ">=2,<2.0.22|>=2.1,<2.1.7", "tecnickcom/tcpdf": "<6.2.22", "thelia/backoffice-default-template": ">=2.1,<2.1.2", - "thelia/thelia": ">=2.1.0-beta1,<2.1.3|>=2.1,<2.1.2", + "thelia/thelia": ">=2.1,<2.1.2|>=2.1.0-beta1,<2.1.3", "theonedemon/phpwhois": "<=4.2.5", "titon/framework": ">=0,<9.9.99", "truckersmp/phpwhois": "<=4.3.1", @@ -622,7 +622,7 @@ } ], "description": "Prevents installation of composer packages with known security vulnerabilities: no API, simply require it", - "time": "2019-01-22T18:37:22+00:00" + "time": "2019-02-05T19:58:17+00:00" } ], "packages-dev": [], From 5d061d6e66caa9b2cbbf9660ed2ae000add96b70 Mon Sep 17 00:00:00 2001 From: "C. Proske" Date: Mon, 11 Feb 2019 17:15:49 +0100 Subject: [PATCH 033/280] log fix --- version/100/paymentmethod/JTLMollie.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/version/100/paymentmethod/JTLMollie.php b/version/100/paymentmethod/JTLMollie.php index dac1b63..8c8e62c 100644 --- a/version/100/paymentmethod/JTLMollie.php +++ b/version/100/paymentmethod/JTLMollie.php @@ -310,7 +310,7 @@ protected function getOrderData(Bestellung $order, $hash) */ public function preparePaymentProcess($order) { - $logData = '#' . $order->kBestellung . "" . $order->cBestellNr; + $logData = '#' . $order->kBestellung . "§" . $order->cBestellNr; try { $payment = \ws_mollie\Model\Payment::getPayment($order->kBestellung); if ($payment && in_array($payment->cStatus, [\Mollie\Api\Types\OrderStatus::STATUS_CREATED]) && $payment->cCheckoutURL) { @@ -365,7 +365,7 @@ public function doLog($msg, $data = null, $level = LOGLEVEL_NOTICE) public function handleNotification($order, $hash, $args) { \ws_mollie\Helper::autoload(); - $logData = '#' . $order->kBestellung . "" . $order->cBestellNr; + $logData = '#' . $order->kBestellung . "§" . $order->cBestellNr; $this->doLog('Received Notification
' . print_r([$hash, $args], 1) . '
', $logData, LOGLEVEL_NOTICE); try { @@ -386,7 +386,7 @@ public function handleNotification($order, $hash, $args) */ public function finalizeOrder($order, $hash, $args) { - $logData = '#' . $order->kBestellung . "" . $order->cBestellNr; + $logData = '#' . $order->kBestellung . "§" . $order->cBestellNr; try { \ws_mollie\Helper::autoload(); $oMolliePayment = self::API()->orders->get($args['id'], ['embed' => 'payments']); From a1b4577d6b238ebc5a1765e3afcbd70bd2755ad6 Mon Sep 17 00:00:00 2001 From: "dash.bar" Date: Mon, 11 Feb 2019 17:39:04 +0100 Subject: [PATCH 034/280] prepare finalize --- info.xml | 100 ++++++++++-------- version/100/adminmenu/info.php | 3 +- version/100/adminmenu/orders.php | 5 +- version/100/adminmenu/paymentmethods.php | 3 +- version/100/class/Helper.php | 16 +-- version/100/class/Model/AbstractModel.php | 3 +- version/100/class/Model/Payment.php | 16 +-- version/100/class/Mollie.php | 8 +- version/100/frontend/131_globalinclude.php | 4 +- version/100/frontend/140_smarty.php | 49 ++++----- version/100/frontend/181_sync.php | 6 +- version/100/paymentmethod/JTLMollie.php | 21 ++-- .../100/paymentmethod/JTLMollieBancontact.php | 4 +- .../paymentmethod/JTLMollieBanktransfer.php | 4 +- .../100/paymentmethod/JTLMollieBelfius.php | 4 +- .../100/paymentmethod/JTLMollieBitcoin.php | 4 +- .../100/paymentmethod/JTLMollieCreditCard.php | 4 +- .../paymentmethod/JTLMollieDirectDebit.php | 4 +- version/100/paymentmethod/JTLMollieEPS.php | 4 +- .../100/paymentmethod/JTLMollieGiftcard.php | 4 +- .../100/paymentmethod/JTLMollieGiropay.php | 4 +- version/100/paymentmethod/JTLMollieIDEAL.php | 3 +- .../100/paymentmethod/JTLMollieINGHomePay.php | 3 +- version/100/paymentmethod/JTLMollieKBC.php | 3 +- .../paymentmethod/JTLMollieKlarnaPayLater.php | 3 +- .../paymentmethod/JTLMollieKlarnaSliceIt.php | 3 +- version/100/paymentmethod/JTLMolliePayPal.php | 3 +- .../paymentmethod/JTLMolliePaysafecard.php | 3 +- version/100/paymentmethod/JTLMollieSofort.php | 3 +- 29 files changed, 133 insertions(+), 161 deletions(-) diff --git a/info.xml b/info.xml index 9b61585..c577167 100644 --- a/info.xml +++ b/info.xml @@ -1,15 +1,16 @@ mollie - Zahlungsartplugin für mollie.com + Zahlungsartplugin für mollie.com WebStollen http://www.webstollen.de/ 102 ws_mollie + 405 - 2017-12-18 100.sql + 2019-02-11 131_globalinclude.php @@ -26,50 +27,49 @@ Zahlungsarten paymentmethods.php - + + Info + info.php + Einstellungen API Key: - Füge hier deinen mollie API Key ein + Füge hier deinen mollie API Key ein api_key Zahlungsart Daten syncronisiernen - Lädt Name / Bild für die jeweilige Sprache automatisch von mollie, und speichert diese - in der Datenbank - + Lädt Name / Bild für die jeweilige Sprache automatisch von mollie, und speichert diese in der Datenbank paymentmethod_sync - - - - + + + + Checkout Styles laden - Lädt Stylesheets für das Evo Template, um den Checkout zu verschönern. + Lädt Stylesheets für das Evo Template, um den Checkout zu verschönern. load_styles - - - + + + - - Info - info.php -
mollie + 1 0 mollie.com OTHER + 0 0 1 0 @@ -82,13 +82,14 @@ Bezahlen Sie bequem mit verschiedenen Zahlungsmethoden. - mollie Kreditkarte + 2 0 mollie.com CREDIT_CARD + 0 0 1 0 @@ -101,13 +102,14 @@ Bezahlen Sie bequem mit Kreditkarte. - mollie Bitcoin + 3 0 mollie.com OTHER + 0 0 1 0 @@ -120,13 +122,14 @@ Bezahlen Sie bequem mit Bitcoins. - mollie Bancontact + 4 0 mollie.com OTHER + 0 0 1 0 @@ -139,13 +142,14 @@ Bezahlen Sie bequem mit Bancontact. - mollie Banktransfer + 5 0 mollie.com OTHER + 0 0 1 0 @@ -153,18 +157,19 @@ JTLMollieBanktransfer tpl/bestellabschluss.tpl - SEPA Überweisung + SEPA Ãœberweisung mollie - Bezahlen Sie bequem mit SEPA Überweisung. + Bezahlen Sie bequem mit SEPA Ãœberweisung. - mollie Belfius + 6 0 mollie.com OTHER + 0 0 1 0 @@ -172,18 +177,19 @@ JTLMollieBelfius tpl/bestellabschluss.tpl - SEPA Überweisung + SEPA Ãœberweisung mollie Bezahlen Sie bequem mit Belfius. - mollie DirectDebit + 7 0 mollie.com DIRECT_DEBIT + 0 0 1 0 @@ -196,13 +202,14 @@ Bezahlen Sie bequem mit SEPA Lastschrift. - mollie EPS + 2 0 mollie.com OTHER + 0 0 1 0 @@ -215,13 +222,14 @@ Bezahlen Sie bequem mit EPS. - mollie Giftcard + 8 0 mollie.com OTHER + 0 0 1 0 @@ -234,13 +242,14 @@ Bezahlen Sie bequem mit Gift cards. - mollie Giropay + 9 0 mollie.com GIROPAY + 0 0 1 0 @@ -253,13 +262,14 @@ Bezahlen Sie bequem mit Giropay. - mollie iDEAL + 10 0 mollie.com OTHER + 0 0 1 0 @@ -272,13 +282,14 @@ Bezahlen Sie bequem mit iDEAL. - mollie ING HomePay + 11 0 mollie.com OTHER + 0 0 1 0 @@ -291,13 +302,14 @@ Bezahlen Sie bequem mit ING HomePay. - mollie KBC + 12 0 mollie.com OTHER + 0 0 1 0 @@ -310,13 +322,14 @@ Bezahlen Sie bequem mit KBC. - mollie PayPal + 13 0 mollie.com PAYPAL + 0 0 1 0 @@ -329,13 +342,14 @@ Bezahlen Sie bequem mit PayPal. - mollie paysafecard + 14 0 mollie.com OTHER + 0 0 1 0 @@ -348,13 +362,14 @@ Bezahlen Sie bequem mit paysafecard. - mollie SOFORT + 15 0 mollie.com DIRECT_E_BANKING + 0 0 1 0 @@ -367,13 +382,14 @@ Bezahlen Sie bequem mit SOFORT. - mollie Klarna Pay Later + 16 0 mollie.com INVOICE + 0 0 1 0 @@ -386,13 +402,14 @@ Bezahlen Sie bequem mit Klarna Pay Later. - mollie Klarna Slice It + 17 0 mollie.com FINANCING + 0 0 1 0 @@ -405,9 +422,6 @@ Bezahlen Sie bequem mit Klarna Slice It. - - - 405 -
+ \ No newline at end of file diff --git a/version/100/adminmenu/info.php b/version/100/adminmenu/info.php index 6876c3c..74e4100 100644 --- a/version/100/adminmenu/info.php +++ b/version/100/adminmenu/info.php @@ -47,7 +47,6 @@ if ((int)\ws_mollie\Helper::oPlugin()->nVersion < (int)$latestRelease->version) { Shop::Smarty()->assign('update', $latestRelease); } - } catch (\Exception $e) { } @@ -55,4 +54,4 @@ } catch (Exception $e) { echo "
Fehler: {$e->getMessage()}
"; \ws_mollie\Helper::logExc($e); -} \ No newline at end of file +} diff --git a/version/100/adminmenu/orders.php b/version/100/adminmenu/orders.php index 27703bf..6d0a67c 100644 --- a/version/100/adminmenu/orders.php +++ b/version/100/adminmenu/orders.php @@ -33,7 +33,7 @@ goto order; break; - case 'cancel'; + case 'cancel': if (!array_key_exists('id', $_REQUEST)) { $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; break; @@ -140,11 +140,10 @@ ->assign('hasAPIKey', trim(\ws_mollie\Helper::getSetting("api_key")) !== ''); Shop::Smarty()->display($oPlugin->cAdminmenuPfad . '/tpl/orders.tpl'); - } catch (Exception $e) { echo "
" . "{$e->getMessage()}
" . "
{$e->getFile()}:{$e->getLine()}
{$e->getTraceAsString()}
" . "
"; \ws_mollie\Helper::logExc($e); -} \ No newline at end of file +} diff --git a/version/100/adminmenu/paymentmethods.php b/version/100/adminmenu/paymentmethods.php index dde49ca..ac1ec56 100644 --- a/version/100/adminmenu/paymentmethods.php +++ b/version/100/adminmenu/paymentmethods.php @@ -22,8 +22,7 @@ Shop::Smarty()->assign('methods', $methods) ->assign('profile', $profile); Shop::Smarty()->display($oPlugin->cAdminmenuPfad . '/tpl/paymentmethods.tpl'); - } catch (Exception $e) { echo "
{$e->getMessage()}
"; \ws_mollie\Helper::logExc($e); -} \ No newline at end of file +} diff --git a/version/100/class/Helper.php b/version/100/class/Helper.php index dd90ed3..d7a916f 100644 --- a/version/100/class/Helper.php +++ b/version/100/class/Helper.php @@ -72,8 +72,7 @@ public static function autoload() */ public static function selfupdate() { - - if(function_exists('opcache_reset')){ + if (function_exists('opcache_reset')) { opcache_reset(); } @@ -185,7 +184,6 @@ public static function init() ini_set('xdebug.default_enable', defined('WS_XDEBUG_ENABLED')); self::autoload(); if (null === self::$_licence) { - if (array_key_exists('_licActivate', $_REQUEST) && $_REQUEST['_licActivate'] === __NAMESPACE__) { self::_licActivate(self::_licCache()); } @@ -272,7 +270,7 @@ public static function oPlugin($force = false) { if ($force === true) { self::$oPlugin = new \Plugin(self::oPlugin(false)->kPlugin, true); - } else if (null === self::$oPlugin) { + } elseif (null === self::$oPlugin) { self::$oPlugin = \Plugin::getPluginById(__NAMESPACE__); } return self::$oPlugin; @@ -294,7 +292,6 @@ private static function _licValid($oL) } } return false; - } /** @@ -350,7 +347,6 @@ private static function licCheck($x) } } return false; - } /** @@ -373,7 +369,6 @@ private static function _licCRC($oL) private static function _licLive($oL) { try { - if (!function_exists('curl_init')) { throw new \Exception(__NAMESPACE__ . ': cURL needs to be installed!'); } @@ -410,7 +405,6 @@ private static function _licLive($oL) } /** @noinspection UnserializeExploitsInspection */ if ($response = json_decode($data)) { - $checksum = md5(base64_encode($response->data->validUntil . $response->data->nextCheck . ($response->data->testLicence ? 'Y' : 'N'))); if (!$response || !isset($response->data) || $response->data === false || !isset($response->checksum) || $response->checksum !== $checksum) { @@ -428,15 +422,14 @@ private static function _licLive($oL) } $oL->fails = 0; self::_licSave($oL, true); - } else { throw new \Exception(__NAMESPACE__ . ': Could not decode licence info: ' . print_r($response, 1)); } - } catch (\Exception $e) { $oL->disabled = (++$oL->fails) >= 3 ? 1 : 0; $oL->nextCheck = date("Y-m-d", strtotime("+1 DAY")); - $oL->validUntil = date("Y-m-d", strtotime("+1 DAY"));; + $oL->validUntil = date("Y-m-d", strtotime("+1 DAY")); + ; self::logExc($e, false); self::_licSave($oL, true); @@ -518,7 +511,6 @@ public static function getAdminmenu($name) } return $kPluginAdminMenu; } - } } diff --git a/version/100/class/Model/AbstractModel.php b/version/100/class/Model/AbstractModel.php index c50ea4b..5638700 100644 --- a/version/100/class/Model/AbstractModel.php +++ b/version/100/class/Model/AbstractModel.php @@ -4,5 +4,4 @@ abstract class AbstractModel { - -} \ No newline at end of file +} diff --git a/version/100/class/Model/Payment.php b/version/100/class/Model/Payment.php index 8b91125..8dea11d 100644 --- a/version/100/class/Model/Payment.php +++ b/version/100/class/Model/Payment.php @@ -4,16 +4,14 @@ class Payment extends AbstractModel { - const TABLE = 'xplugin_ws_mollie_payments'; public static function updateFromPayment(\Mollie\Api\Resources\Order $oMolliePayment, $kBestellung = null, $hash = null) { - $data = [ ':kID' => $oMolliePayment->id, - ':kBestellung' => (int)$kBestellung ?: NULL, - ':kBestellung1' => (int)$kBestellung ?: NULL, + ':kBestellung' => (int)$kBestellung ?: null, + ':kBestellung1' => (int)$kBestellung ?: null, ':cMode' => $oMolliePayment->mode, ':cStatus' => $oMolliePayment->status, ':cStatus1' => $oMolliePayment->status, @@ -37,10 +35,13 @@ public static function updateFromPayment(\Mollie\Api\Resources\Order $oMolliePay ':fAmountRefunded1' => $oMolliePayment->amountRefunded ? $oMolliePayment->amountRefunded->value : null, ':dCreatedAt' => $oMolliePayment->createdAt ? date('Y-m-d H:i:s', strtotime($oMolliePayment->createdAt)) : null, ]; - 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) ' + 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); + $data, + 3 + ); } public static function getPayment($kBestellung) @@ -69,5 +70,4 @@ public static function getPaymentHash($cHash) } return $payment; } - -} \ No newline at end of file +} diff --git a/version/100/class/Mollie.php b/version/100/class/Mollie.php index d1017e9..fd97087 100644 --- a/version/100/class/Mollie.php +++ b/version/100/class/Mollie.php @@ -8,7 +8,6 @@ namespace ws_mollie; - use Mollie\Api\Resources\Order; use Mollie\Api\Types\OrderStatus; use ws_mollie\Model\Payment; @@ -170,8 +169,8 @@ public static function handleOrder(Order $order, $kBestellung) Payment::updateFromPayment($order, $kBestellung); $oIncomingPayment = \Shop::DB()->executeQueryPrepared("SELECT * FROM tzahlungseingang WHERE cHinweis = :cHinweis AND kBestellung = :kBestellung", [':cHinweis' => $order->id, ':kBestellung' => $oBestellung->kBestellung], 1); - if(!$oIncomingPayment){ - $oIncomingPayment = new \stdClass(); + if (!$oIncomingPayment) { + $oIncomingPayment = new \stdClass(); } // 2. Check PaymentStatus @@ -200,5 +199,4 @@ public static function handleOrder(Order $order, $kBestellung) } return false; } - -} \ No newline at end of file +} diff --git a/version/100/frontend/131_globalinclude.php b/version/100/frontend/131_globalinclude.php index b81a06f..118f6b6 100644 --- a/version/100/frontend/131_globalinclude.php +++ b/version/100/frontend/131_globalinclude.php @@ -12,13 +12,11 @@ $payment = \Shop::DB()->executeQueryPrepared("SELECT * FROM " . \ws_mollie\Model\Payment::TABLE . " WHERE cHash = :cHash", [':cHash' => $_REQUEST['mollie']], 1); // Bestellung finalized, redirect to status/completion page if ((int)$payment->kBestellung) { - $logData = '$' . $payment->kID . '#' . $payment->kBestellung . "§" . $payment->cOrderNumber; \ws_mollie\Mollie::JTLMollie()->doLog('Bestellung finalized => redirect abschluss/status', $logData); $order = JTLMollie::API()->orders->get($payment->kID, ['embed' => 'payments']); \ws_mollie\Mollie::handleOrder($order, $payment->kBestellung); \ws_mollie\Mollie::getOrderCompletedRedirect($payment->kBestellung, true); - } elseif ($payment) { // payment, but no order => finalize it require_once __DIR__ . '/../paymentmethod/JTLMollie.php'; $order = JTLMollie::API()->orders->get($payment->kID, ['embed' => 'payments']); @@ -66,4 +64,4 @@ ob_end_flush(); } catch (Exception $e) { \ws_mollie\Helper::logExc($e); -} \ No newline at end of file +} diff --git a/version/100/frontend/140_smarty.php b/version/100/frontend/140_smarty.php index 25c425c..3f74d4f 100644 --- a/version/100/frontend/140_smarty.php +++ b/version/100/frontend/140_smarty.php @@ -1,30 +1,33 @@ append( + - pq('head')->append(<< /* MOLLIE CHECKOUT STYLES*/ @@ -45,8 +48,6 @@ CSS ); - - } catch (Exception $e) { \ws_mollie\Helper::logExc($e); -} \ No newline at end of file +} diff --git a/version/100/frontend/181_sync.php b/version/100/frontend/181_sync.php index f2a2257..be2fe16 100644 --- a/version/100/frontend/181_sync.php +++ b/version/100/frontend/181_sync.php @@ -20,8 +20,8 @@ require_once __DIR__ . '/../paymentmethod/JTLMollie.php'; $shipment = JTLMollie::API()->shipments->createFor($order, $options); \ws_mollie\Mollie::JTLMollie()->doLog('Shipment created
' . print_r(['options' => $options, 'shipment' => $shipment], 1) . '
', $logData, LOGLEVEL_NOTICE); - }else{ - \ws_mollie\Mollie::JTLMollie()->doLog('181_sync: options don\'t contain lines
' . print_r([$order, $options], 1) . '
', $logData, LOGLEVEL_ERROR); + } else { + \ws_mollie\Mollie::JTLMollie()->doLog('181_sync: options don\'t contain lines
' . print_r([$order, $options], 1) . '
', $logData, LOGLEVEL_ERROR); } } } catch (Exception $e) { @@ -30,4 +30,4 @@ } } catch (Exception $e) { \ws_mollie\Helper::logExc($e); -} \ No newline at end of file +} diff --git a/version/100/paymentmethod/JTLMollie.php b/version/100/paymentmethod/JTLMollie.php index 8c8e62c..7a2f110 100644 --- a/version/100/paymentmethod/JTLMollie.php +++ b/version/100/paymentmethod/JTLMollie.php @@ -52,11 +52,11 @@ public static function API() return self::$_mollie; } - /** - * @param Bestellung $order - * @param Object $payment (Key, Zahlungsanbieter, Abgeholt, Zeit is set here) - * @return $this - */ + /** + * @param Bestellung $order + * @param Object $payment (Key, Zahlungsanbieter, Abgeholt, Zeit is set here) + * @return $this + */ public function addIncomingPayment($order, $payment) { $model = (object)array_merge([ @@ -71,10 +71,10 @@ public function addIncomingPayment($order, $payment) 'cHinweis' => '', 'cAbgeholt' => 'N' ], (array)$payment); - if(isset($model->kZahlungseingang) && $model->kZahlungseingang > 0){ - Shop::DB()->update('tzahlungseingang', 'kZahlungseingang', $model->kZahlungseingang, $model); - }else{ - Shop::DB()->insert('tzahlungseingang', $model); + if (isset($model->kZahlungseingang) && $model->kZahlungseingang > 0) { + Shop::DB()->update('tzahlungseingang', 'kZahlungseingang', $model->kZahlungseingang, $model); + } else { + Shop::DB()->insert('tzahlungseingang', $model); } return $this; @@ -522,7 +522,6 @@ protected function updatePaymentMethod($cISOSprache, $method) */ public function isSelectable() { - $locale = self::getLocale($_SESSION['cISOSprache'], $_SESSION['Kunde']->cLand); if (static::MOLLIE_METHOD !== '') { try { @@ -570,4 +569,4 @@ public function isValidIntern($args_arr = []) $this->doLog("isValdid failed: init failed or no API Key given. Try clear the Cache."); return false; } -} \ No newline at end of file +} diff --git a/version/100/paymentmethod/JTLMollieBancontact.php b/version/100/paymentmethod/JTLMollieBancontact.php index 7ee02ad..0e5eeed 100644 --- a/version/100/paymentmethod/JTLMollieBancontact.php +++ b/version/100/paymentmethod/JTLMollieBancontact.php @@ -4,7 +4,5 @@ class JTLMollieBancontact extends JTLMollie { - const MOLLIE_METHOD = \Mollie\Api\Types\PaymentMethod::BANCONTACT; - -} \ No newline at end of file +} diff --git a/version/100/paymentmethod/JTLMollieBanktransfer.php b/version/100/paymentmethod/JTLMollieBanktransfer.php index 0198912..478988a 100644 --- a/version/100/paymentmethod/JTLMollieBanktransfer.php +++ b/version/100/paymentmethod/JTLMollieBanktransfer.php @@ -4,7 +4,5 @@ class JTLMollieBanktransfer extends JTLMollie { - const MOLLIE_METHOD = \Mollie\Api\Types\PaymentMethod::BANKTRANSFER; - -} \ No newline at end of file +} diff --git a/version/100/paymentmethod/JTLMollieBelfius.php b/version/100/paymentmethod/JTLMollieBelfius.php index d1412da..1347b8e 100644 --- a/version/100/paymentmethod/JTLMollieBelfius.php +++ b/version/100/paymentmethod/JTLMollieBelfius.php @@ -4,7 +4,5 @@ class JTLMollieBelfius extends JTLMollie { - const MOLLIE_METHOD = \Mollie\Api\Types\PaymentMethod::BELFIUS; - -} \ No newline at end of file +} diff --git a/version/100/paymentmethod/JTLMollieBitcoin.php b/version/100/paymentmethod/JTLMollieBitcoin.php index 4c176c6..c194fb0 100644 --- a/version/100/paymentmethod/JTLMollieBitcoin.php +++ b/version/100/paymentmethod/JTLMollieBitcoin.php @@ -4,7 +4,5 @@ class JTLMollieBitcoin extends JTLMollie { - const MOLLIE_METHOD = \Mollie\Api\Types\PaymentMethod::BITCOIN; - -} \ No newline at end of file +} diff --git a/version/100/paymentmethod/JTLMollieCreditCard.php b/version/100/paymentmethod/JTLMollieCreditCard.php index 2dd40bc..4364105 100644 --- a/version/100/paymentmethod/JTLMollieCreditCard.php +++ b/version/100/paymentmethod/JTLMollieCreditCard.php @@ -4,7 +4,5 @@ class JTLMollieCreditCard extends JTLMollie { - const MOLLIE_METHOD = \Mollie\Api\Types\PaymentMethod::CREDITCARD; - -} \ No newline at end of file +} diff --git a/version/100/paymentmethod/JTLMollieDirectDebit.php b/version/100/paymentmethod/JTLMollieDirectDebit.php index ecb0e2f..ce0441d 100644 --- a/version/100/paymentmethod/JTLMollieDirectDebit.php +++ b/version/100/paymentmethod/JTLMollieDirectDebit.php @@ -4,7 +4,5 @@ class JTLMollieDirectDebit extends JTLMollie { - const MOLLIE_METHOD = \Mollie\Api\Types\PaymentMethod::DIRECTDEBIT; - -} \ No newline at end of file +} diff --git a/version/100/paymentmethod/JTLMollieEPS.php b/version/100/paymentmethod/JTLMollieEPS.php index 1fdb813..9d06f83 100644 --- a/version/100/paymentmethod/JTLMollieEPS.php +++ b/version/100/paymentmethod/JTLMollieEPS.php @@ -4,7 +4,5 @@ class JTLMollieEPS extends JTLMollie { - const MOLLIE_METHOD = \Mollie\Api\Types\PaymentMethod::EPS; - -} \ No newline at end of file +} diff --git a/version/100/paymentmethod/JTLMollieGiftcard.php b/version/100/paymentmethod/JTLMollieGiftcard.php index fd1e8bd..3556aac 100644 --- a/version/100/paymentmethod/JTLMollieGiftcard.php +++ b/version/100/paymentmethod/JTLMollieGiftcard.php @@ -4,7 +4,5 @@ class JTLMollieGiftcard extends JTLMollie { - const MOLLIE_METHOD = \Mollie\Api\Types\PaymentMethod::GIFTCARD; - -} \ No newline at end of file +} diff --git a/version/100/paymentmethod/JTLMollieGiropay.php b/version/100/paymentmethod/JTLMollieGiropay.php index c954f35..9f4232b 100644 --- a/version/100/paymentmethod/JTLMollieGiropay.php +++ b/version/100/paymentmethod/JTLMollieGiropay.php @@ -4,7 +4,5 @@ class JTLMollieGiropay extends JTLMollie { - const MOLLIE_METHOD = \Mollie\Api\Types\PaymentMethod::GIROPAY; - -} \ No newline at end of file +} diff --git a/version/100/paymentmethod/JTLMollieIDEAL.php b/version/100/paymentmethod/JTLMollieIDEAL.php index a090987..e49cbf0 100644 --- a/version/100/paymentmethod/JTLMollieIDEAL.php +++ b/version/100/paymentmethod/JTLMollieIDEAL.php @@ -5,5 +5,4 @@ class JTLMollieIDEAL extends JTLMollie { const MOLLIE_METHOD = \Mollie\Api\Types\PaymentMethod::IDEAL; - -} \ No newline at end of file +} diff --git a/version/100/paymentmethod/JTLMollieINGHomePay.php b/version/100/paymentmethod/JTLMollieINGHomePay.php index 05331b5..be1003d 100644 --- a/version/100/paymentmethod/JTLMollieINGHomePay.php +++ b/version/100/paymentmethod/JTLMollieINGHomePay.php @@ -5,5 +5,4 @@ class JTLMollieINGHomePay extends JTLMollie { const MOLLIE_METHOD = \Mollie\Api\Types\PaymentMethod::INGHOMEPAY; - -} \ No newline at end of file +} diff --git a/version/100/paymentmethod/JTLMollieKBC.php b/version/100/paymentmethod/JTLMollieKBC.php index 36502a7..1dc7f07 100644 --- a/version/100/paymentmethod/JTLMollieKBC.php +++ b/version/100/paymentmethod/JTLMollieKBC.php @@ -5,5 +5,4 @@ class JTLMollieKBC extends JTLMollie { const MOLLIE_METHOD = \Mollie\Api\Types\PaymentMethod::KBC; - -} \ No newline at end of file +} diff --git a/version/100/paymentmethod/JTLMollieKlarnaPayLater.php b/version/100/paymentmethod/JTLMollieKlarnaPayLater.php index 2b3b1b2..fd8f78b 100644 --- a/version/100/paymentmethod/JTLMollieKlarnaPayLater.php +++ b/version/100/paymentmethod/JTLMollieKlarnaPayLater.php @@ -5,5 +5,4 @@ class JTLMollieKlarnaPayLater extends JTLMollie { const MOLLIE_METHOD = \Mollie\Api\Types\PaymentMethod::KLARNA_PAY_LATER; - -} \ No newline at end of file +} diff --git a/version/100/paymentmethod/JTLMollieKlarnaSliceIt.php b/version/100/paymentmethod/JTLMollieKlarnaSliceIt.php index 0dc1cc8..1ed2f03 100644 --- a/version/100/paymentmethod/JTLMollieKlarnaSliceIt.php +++ b/version/100/paymentmethod/JTLMollieKlarnaSliceIt.php @@ -5,5 +5,4 @@ class JTLMollieKlarnaSliceIt extends JTLMollie { const MOLLIE_METHOD = \Mollie\Api\Types\PaymentMethod::KLARNA_SLICE_IT; - -} \ No newline at end of file +} diff --git a/version/100/paymentmethod/JTLMolliePayPal.php b/version/100/paymentmethod/JTLMolliePayPal.php index 9a15c11..8879991 100644 --- a/version/100/paymentmethod/JTLMolliePayPal.php +++ b/version/100/paymentmethod/JTLMolliePayPal.php @@ -5,5 +5,4 @@ class JTLMolliePayPal extends JTLMollie { const MOLLIE_METHOD = \Mollie\Api\Types\PaymentMethod::PAYPAL; - -} \ No newline at end of file +} diff --git a/version/100/paymentmethod/JTLMolliePaysafecard.php b/version/100/paymentmethod/JTLMolliePaysafecard.php index 70d277e..3a179b0 100644 --- a/version/100/paymentmethod/JTLMolliePaysafecard.php +++ b/version/100/paymentmethod/JTLMolliePaysafecard.php @@ -5,5 +5,4 @@ class JTLMolliePaysafecard extends JTLMollie { const MOLLIE_METHOD = \Mollie\Api\Types\PaymentMethod::PAYSAFECARD; - -} \ No newline at end of file +} diff --git a/version/100/paymentmethod/JTLMollieSofort.php b/version/100/paymentmethod/JTLMollieSofort.php index f00b4f5..7fd186b 100644 --- a/version/100/paymentmethod/JTLMollieSofort.php +++ b/version/100/paymentmethod/JTLMollieSofort.php @@ -5,5 +5,4 @@ class JTLMollieSofort extends JTLMollie { const MOLLIE_METHOD = \Mollie\Api\Types\PaymentMethod::SOFORT; - -} \ No newline at end of file +} From 0a27a8eaf9aeb16efe4a04de710f1647219c93f7 Mon Sep 17 00:00:00 2001 From: "dash.bar" Date: Mon, 11 Feb 2019 17:39:05 +0100 Subject: [PATCH 035/280] init version 101 --- info.xml | 3 + version/101/adminmenu/info.php | 57 ++ version/101/adminmenu/orders.php | 149 +++++ version/101/adminmenu/paymentmethods.php | 28 + version/101/adminmenu/tpl/info.tpl | 41 ++ .../tpl/mollie-account-erstellen.png | Bin 0 -> 38998 bytes version/101/adminmenu/tpl/order.tpl | 217 +++++++ version/101/adminmenu/tpl/orders.tpl | 106 ++++ version/101/adminmenu/tpl/paymentmethods.tpl | 49 ++ version/101/class/Helper.php | 517 ++++++++++++++++ version/101/class/Model/AbstractModel.php | 7 + version/101/class/Model/Payment.php | 73 +++ version/101/class/Mollie.php | 202 +++++++ version/101/frontend/131_globalinclude.php | 67 ++ version/101/frontend/140_smarty.php | 53 ++ version/101/frontend/144_notify.php | 27 + version/101/frontend/181_sync.php | 33 + version/101/paymentmethod/JTLMollie.php | 572 ++++++++++++++++++ .../101/paymentmethod/JTLMollieBancontact.php | 8 + .../paymentmethod/JTLMollieBanktransfer.php | 8 + .../101/paymentmethod/JTLMollieBelfius.php | 8 + .../101/paymentmethod/JTLMollieBitcoin.php | 8 + .../101/paymentmethod/JTLMollieCreditCard.php | 8 + .../paymentmethod/JTLMollieDirectDebit.php | 8 + version/101/paymentmethod/JTLMollieEPS.php | 8 + .../101/paymentmethod/JTLMollieGiftcard.php | 8 + .../101/paymentmethod/JTLMollieGiropay.php | 8 + version/101/paymentmethod/JTLMollieIDEAL.php | 8 + .../101/paymentmethod/JTLMollieINGHomePay.php | 8 + version/101/paymentmethod/JTLMollieKBC.php | 8 + .../paymentmethod/JTLMollieKlarnaPayLater.php | 8 + .../paymentmethod/JTLMollieKlarnaSliceIt.php | 8 + version/101/paymentmethod/JTLMolliePayPal.php | 8 + .../paymentmethod/JTLMolliePaysafecard.php | 8 + version/101/paymentmethod/JTLMollieSofort.php | 8 + .../paymentmethod/tpl/bestellabschluss.tpl | 5 + version/101/sql/100.sql | 22 + 37 files changed, 2364 insertions(+) create mode 100644 version/101/adminmenu/info.php create mode 100644 version/101/adminmenu/orders.php create mode 100644 version/101/adminmenu/paymentmethods.php create mode 100644 version/101/adminmenu/tpl/info.tpl create mode 100644 version/101/adminmenu/tpl/mollie-account-erstellen.png create mode 100644 version/101/adminmenu/tpl/order.tpl create mode 100644 version/101/adminmenu/tpl/orders.tpl create mode 100644 version/101/adminmenu/tpl/paymentmethods.tpl create mode 100644 version/101/class/Helper.php create mode 100644 version/101/class/Model/AbstractModel.php create mode 100644 version/101/class/Model/Payment.php create mode 100644 version/101/class/Mollie.php create mode 100644 version/101/frontend/131_globalinclude.php create mode 100644 version/101/frontend/140_smarty.php create mode 100644 version/101/frontend/144_notify.php create mode 100644 version/101/frontend/181_sync.php create mode 100644 version/101/paymentmethod/JTLMollie.php create mode 100644 version/101/paymentmethod/JTLMollieBancontact.php create mode 100644 version/101/paymentmethod/JTLMollieBanktransfer.php create mode 100644 version/101/paymentmethod/JTLMollieBelfius.php create mode 100644 version/101/paymentmethod/JTLMollieBitcoin.php create mode 100644 version/101/paymentmethod/JTLMollieCreditCard.php create mode 100644 version/101/paymentmethod/JTLMollieDirectDebit.php create mode 100644 version/101/paymentmethod/JTLMollieEPS.php create mode 100644 version/101/paymentmethod/JTLMollieGiftcard.php create mode 100644 version/101/paymentmethod/JTLMollieGiropay.php create mode 100644 version/101/paymentmethod/JTLMollieIDEAL.php create mode 100644 version/101/paymentmethod/JTLMollieINGHomePay.php create mode 100644 version/101/paymentmethod/JTLMollieKBC.php create mode 100644 version/101/paymentmethod/JTLMollieKlarnaPayLater.php create mode 100644 version/101/paymentmethod/JTLMollieKlarnaSliceIt.php create mode 100644 version/101/paymentmethod/JTLMolliePayPal.php create mode 100644 version/101/paymentmethod/JTLMolliePaysafecard.php create mode 100644 version/101/paymentmethod/JTLMollieSofort.php create mode 100644 version/101/paymentmethod/tpl/bestellabschluss.tpl create mode 100644 version/101/sql/100.sql diff --git a/info.xml b/info.xml index c577167..3e0fa56 100644 --- a/info.xml +++ b/info.xml @@ -12,6 +12,9 @@ 100.sql 2019-02-11 + + 2019-02-11 + 131_globalinclude.php 144_notify.php diff --git a/version/101/adminmenu/info.php b/version/101/adminmenu/info.php new file mode 100644 index 0000000..74e4100 --- /dev/null +++ b/version/101/adminmenu/info.php @@ -0,0 +1,57 @@ +assign('defaultTabbertab', \ws_mollie\Helper::getAdminmenu('Info')); + \ws_mollie\Helper::selfupdate(); + } + + $svgQuery = http_build_query([ + 'p' => \ws_mollie\Helper::oPlugin()->cPluginID, + 'v' => \ws_mollie\Helper::oPlugin()->nVersion, + 's' => defined('APPLICATION_VERSION') ? APPLICATION_VERSION : JTL_VERSION, + 'd' => \ws_mollie\Helper::getDomain(), + 'php' => PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION . '.' . PHP_RELEASE_VERSION, + ]); + + echo ""; + echo "
" . + "
" . + " " . + " Lizenz Informationen" . + ' ' . + '
' . + "
" . + " " . + " Update Informationen" . + ' ' . + '
' . + "
" . + " " . + " Plugin informationen" . + ' ' . + '
' . + '
'; + + if (\ws_mollie\Helper::_licCache()->disabled) { + echo "
Die Pluginlizenz und das Plugin wurden deaktiviert. " + . "" + . "Klicke hier um die Lizenz erneut zu überprüfen.
"; + } + + try { + $latestRelease = \ws_mollie\Helper::getLatestRelease(array_key_exists('update', $_REQUEST)); + if ((int)\ws_mollie\Helper::oPlugin()->nVersion < (int)$latestRelease->version) { + Shop::Smarty()->assign('update', $latestRelease); + } + } catch (\Exception $e) { + } + + Shop::Smarty()->display(\ws_mollie\Helper::oPlugin()->cAdminmenuPfad . '/tpl/info.tpl'); +} catch (Exception $e) { + echo "
Fehler: {$e->getMessage()}
"; + \ws_mollie\Helper::logExc($e); +} diff --git a/version/101/adminmenu/orders.php b/version/101/adminmenu/orders.php new file mode 100644 index 0000000..6d0a67c --- /dev/null +++ b/version/101/adminmenu/orders.php @@ -0,0 +1,149 @@ + 'danger', 'text' => 'Keine ID angeben!']; + break; + } + $payment = \ws_mollie\Model\Payment::getPaymentMollie($_REQUEST['id']); + if (!$payment) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; + break; + } + + $order = JTLMollie::API()->orders->get($_REQUEST['id']); + if ($order->status == \Mollie\Api\Types\OrderStatus::STATUS_CANCELED) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung bereits storniert']; + break; + } + $refund = JTLMollie::API()->orderRefunds->createFor($order, ['lines' => []]); + \ws_mollie\Mollie::JTLMollie()->doLog("Order refunded:
" . print_r($refund, 1) . "
", '$' . $payment->kID . '#' . $payment->kBestellung . '§' . $payment->cOrderNumber, LOGLEVEL_NOTICE); + + goto order; + break; + + case 'cancel': + if (!array_key_exists('id', $_REQUEST)) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; + break; + } + $payment = \ws_mollie\Model\Payment::getPaymentMollie($_REQUEST['id']); + if (!$payment) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; + break; + } + $order = JTLMollie::API()->orders->get($_REQUEST['id']); + if ($order->status == \Mollie\Api\Types\OrderStatus::STATUS_CANCELED) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung bereits storniert']; + break; + } + $cancel = JTLMollie::API()->orders->cancel($order->id); + \ws_mollie\Mollie::JTLMollie()->doLog("Order canceled:
" . print_r($cancel, 1) . "
", '$' . $payment->kID . '#' . $payment->kBestellung . '§' . $payment->cOrderNumber, LOGLEVEL_NOTICE); + goto order; + break; + + case 'capture': + if (!array_key_exists('id', $_REQUEST)) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; + break; + } + $payment = \ws_mollie\Model\Payment::getPaymentMollie($_REQUEST['id']); + if (!$payment) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; + break; + } + $order = JTLMollie::API()->orders->get($_REQUEST['id']); + if ($order->status !== \Mollie\Api\Types\OrderStatus::STATUS_AUTHORIZED && $order->status !== \Mollie\Api\Types\OrderStatus::STATUS_SHIPPING) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Nur autorisierte Zahlungen können erfasst werden!']; + break; + } + + $oBestellung = new Bestellung($payment->kBestellung, true); + if (!$oBestellung->kBestellung) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung konnte nicht geladen werden!']; + break; + } + + $logData = '#' . $payment->kBestellung . '$' . $payment->kID . "§" . $oBestellung->cBestellNr; + + $options = ['lines' => []]; + if ($oBestellung->cTracking) { + $tracking = new stdClass(); + $tracking->carrier = $oBestellung->cVersandartName; + $tracking->url = $oBestellung->cTrackingURL; + $tracking->code = $oBestellung->cTracking; + $options['tracking'] = $tracking; + } + + // CAPTURE ALL + $shipment = JTLMollie::API()->shipments->createFor($order, $options); + $ordersMsgs[] = (object)['type' => 'success', 'text' => 'Zahlung wurde erfolgreich erfasst!']; + \ws_mollie\Mollie::JTLMollie()->doLog('Shipment created
' . print_r(['options' => $options, 'shipment' => $shipment], 1) . '
', $logData); + goto order; + + case 'order': + order: + if (!array_key_exists('id', $_REQUEST)) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; + break; + } + + $order = JTLMollie::API()->orders->get($_REQUEST['id']); + $payment = \ws_mollie\Model\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", [ + ':kBestellung' => '%#' . ($payment->kBestellung ?: '##') . '%', + ':cBestellNr' => '%§' . ($payment->cOrderNumber ?: '§§') . '%', + ':MollieID' => '%$' . ($payment->kID ?: '$$') . '%', + ], 2); + + Shop::Smarty()->assign('payment', $payment) + ->assign('oBestellung', $oBestellung) + ->assign('order', $order) + ->assign('logs', $logs) + ->assign('ordersMsgs', $ordersMsgs); + Shop::Smarty()->display($oPlugin->cAdminmenuPfad . '/tpl/order.tpl'); + return; + } + } + + + $payments = Shop::DB()->executeQueryPrepared("SELECT * FROM xplugin_ws_mollie_payments WHERE kBestellung IS NOT NULL AND cStatus != 'created'", [], 2); + foreach ($payments as $i => $payment) { + $payments[$i]->oBestellung = new Bestellung($payment->kBestellung, false); + } + + Shop::Smarty()->assign('payments', $payments) + ->assign('ordersMsgs', $ordersMsgs) + ->assign('admRoot', str_replace('http:', '', $oPlugin->cAdminmenuPfadURL)) + ->assign('hasAPIKey', trim(\ws_mollie\Helper::getSetting("api_key")) !== ''); + + Shop::Smarty()->display($oPlugin->cAdminmenuPfad . '/tpl/orders.tpl'); +} catch (Exception $e) { + echo "
" . + "{$e->getMessage()}
" . + "
{$e->getFile()}:{$e->getLine()}
{$e->getTraceAsString()}
" . + "
"; + \ws_mollie\Helper::logExc($e); +} diff --git a/version/101/adminmenu/paymentmethods.php b/version/101/adminmenu/paymentmethods.php new file mode 100644 index 0000000..ac1ec56 --- /dev/null +++ b/version/101/adminmenu/paymentmethods.php @@ -0,0 +1,28 @@ +setApiKey(\ws_mollie\Helper::getSetting("api_key")); + + $profile = $mollie->profiles->get('me'); + $methods = $mollie->methods->all([ + 'locale' => 'de_DE', + 'include' => 'pricing', + ]); + + Shop::Smarty()->assign('methods', $methods) + ->assign('profile', $profile); + Shop::Smarty()->display($oPlugin->cAdminmenuPfad . '/tpl/paymentmethods.tpl'); +} catch (Exception $e) { + echo "
{$e->getMessage()}
"; + \ws_mollie\Helper::logExc($e); +} diff --git a/version/101/adminmenu/tpl/info.tpl b/version/101/adminmenu/tpl/info.tpl new file mode 100644 index 0000000..eb5ae3a --- /dev/null +++ b/version/101/adminmenu/tpl/info.tpl @@ -0,0 +1,41 @@ +
+
+
+ {if isset($update)} + +
+

Update auf Version {$update->version} verfügbar!

+
+
+
+
Version:
+
{$update->version}
+
+
+
Erschienen:
+
{$update->create_date}
+
+
+
Changelog:
+
+ +
+
+ +
+
+ +
+
+ {/if} +
+
\ No newline at end of file diff --git a/version/101/adminmenu/tpl/mollie-account-erstellen.png b/version/101/adminmenu/tpl/mollie-account-erstellen.png new file mode 100644 index 0000000000000000000000000000000000000000..fc1819255ef725fa214cf2bf028cf3428794ecee GIT binary patch literal 38998 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 +

+ « + 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} +

+ +{if count($ordersMsgs)} + {foreach from=$ordersMsgs item=alert} +
{$alert->text}
+ {/foreach} +
+{/if} + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Mollie ID:{$payment->kID}Mode:{$order->mode}Status:{$order->status}
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)}
+ +

Positionen:

+ +
+ {if ($order->status === 'authorized' || $order->status === 'shipping') && $oBestellung->cStatus|intval >= 3} + + Zahlung erfassen1 + + {/if} + {if $order->amount->value > $order->amountRefunded->value && $order->amountCaptured->value > 0} + Rckerstatten2 + + {/if} + {if $order->isCancelable} + Stornieren3 + + {/if} +
+ + + + + + + + + + + + + + + + + + {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} + + + + + + + + + + + + + {/foreach} + + + + + + + + + + +
StatusSKUNameTypAnzahlMwStSteuerNettoBrutto 
+ {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*} +
{$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} + + + + + + + {/foreach} +
+ {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}
+ + diff --git a/version/101/adminmenu/tpl/orders.tpl b/version/101/adminmenu/tpl/orders.tpl new file mode 100644 index 0000000..50d5829 --- /dev/null +++ b/version/101/adminmenu/tpl/orders.tpl @@ -0,0 +1,106 @@ + +{if count($ordersMsgs)} + {foreach from=$ordersMsgs item=alert} +
{$alert->text}
+ {/foreach} +
+{/if} + +{if $hasAPIKey == false} + + Jetzt kostenlos Mollie Account eröffnen! + +{else} + + + + + + + + + + + + + + + + {foreach from=$payments item=payment} + + + + + + + + + + + + {/foreach} + +
BestellNr.IDMollie StatusJTL StatusBetragWährungLocaleMethodeErstellt
+ {$payment->cOrderNumber} + {if $payment->cMode == 'test'} + TEST + {/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->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)}
+ + +{/if} \ No newline at end of file diff --git a/version/101/adminmenu/tpl/paymentmethods.tpl b/version/101/adminmenu/tpl/paymentmethods.tpl new file mode 100644 index 0000000..cf3770e --- /dev/null +++ b/version/101/adminmenu/tpl/paymentmethods.tpl @@ -0,0 +1,49 @@ +

Account Status

+ + + + + + + + + +
Mode:{$profile->mode}Status:{$profile->status}Review:{$profile->review->status}
+ +
+ +{if $methods && $methods|count} + + + + + + + + + + + {foreach from=$methods item=method} + + + + + + + {/foreach} + +
BildIDNamePreise
{$method->description|utf8_decode}{$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} +
+
+{else} +
Es konnten keine Methoden abgerufen werden.
+{/if} \ No newline at end of file diff --git a/version/101/class/Helper.php b/version/101/class/Helper.php new file mode 100644 index 0000000..d7a916f --- /dev/null +++ b/version/101/class/Helper.php @@ -0,0 +1,517 @@ +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); + 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')); + self::autoload(); + if (null === self::$_licence) { + if (array_key_exists('_licActivate', $_REQUEST) && $_REQUEST['_licActivate'] === __NAMESPACE__) { + self::_licActivate(self::_licCache()); + } + + self::$_licence = false; + self::$_tmpLicence = md5(time()); + if ($_SERVER['HTTP_HOST'] === 'localhost') { + self::$_licence = true; + } else { + self::$_licence = self::licCheck(md5(self::$_tmpLicence)) === md5(self::$_tmpLicence); + } + } + + if (!self::$_licence && self::isAdminBackend()) { + \Shop::Smarty()->assign('defaultTabbertab', self::getAdminmenu('Info')); + } + + + return self::$_autoload && self::$_licence; + } + + /** + * @param $oL + * @return mixed + */ + private static function _licActivate($oL) + { + $oL->nextCheck = 0; + $oL->fails = 0; + $oL->disabled = 0; + self::_licSave($oL); + return $oL; + } + + /** + * @param $oL + * @param bool $checksum + * @return mixed + */ + private static function _licSave($oL, $checksum = false) + { + self::setSetting('lic_validUntil', $oL->validUntil); + self::setSetting('lic_nextCheck', $oL->nextCheck); + self::setSetting('lic_test', $oL->test); + if ($checksum === true) { + self::setSetting('lic_checkSum', base64_encode(sha1($oL->validUntil . $oL->nextCheck . $oL->test . $oL->disabled . $oL->fails . __NAMESPACE__, true))); + } + self::setSetting('lic_disabled', (int)$oL->disabled); + self::setSetting('lic_fails', $oL->fails); + return $oL; + } + + /** + * 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); + } elseif (null === self::$oPlugin) { + self::$oPlugin = \Plugin::getPluginById(__NAMESPACE__); + } + return self::$oPlugin; + } + + /** + * @param $oL + * @return bool|string + */ + private static function _licValid($oL) + { + if ($nextCheck = strtotime($oL->nextCheck)) { + if ($nextCheck > time()) { + if ($validUntil = strtotime($oL->validUntil)) { + if ($validUntil > time() || (int)$oL->test === 0) { + return md5(self::$_tmpLicence); + } + } + } + } + return false; + } + + /** + * @return \stdClass + */ + public static function _licCache() + { + $oL = new \stdClass(); + $oL->validUntil = self::getSetting('lic_validUntil'); + $oL->nextCheck = self::getSetting('lic_nextCheck'); + $oL->test = self::getSetting('lic_test'); + $oL->checksum = self::getSetting('lic_checkSum'); + $oL->disabled = self::getSetting('lic_disabled') === null ? 0 : (int)self::getSetting('lic_disabled'); + $oL->fails = self::getSetting('lic_fails') ?: 0; + return $oL; + } + + /** + * 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; + } + + /** + * @param $x + * @return bool|string + */ + private static function licCheck($x) + { + if ($x !== md5(self::$_tmpLicence)) { + return false; + } + $oL = self::_licCache(); + if (self::_licCRC($oL) === true) { + // CRC OK? + if (self::_licValid($oL) === md5(self::$_tmpLicence)) { + return md5(self::$_tmpLicence); + } + } + if ($oL->disabled === 0) { + $oL = self::_licLive($oL); + + if ($oL->disabled === 0 && self::_licValid($oL) === md5(self::$_tmpLicence)) { + return md5(self::$_tmpLicence); + } + } + return false; + } + + /** + * @param $oL + * @return bool + */ + private static function _licCRC($oL) + { + $crc_valid = false; + if ($checksum = base64_encode(sha1($oL->validUntil . $oL->nextCheck . $oL->test . $oL->disabled . $oL->fails . __NAMESPACE__, true))) { + $crc_valid = $checksum == $oL->checksum; + } + return $oL->checksum && $crc_valid; + } + + /** + * @param $oL + * @return mixed + */ + private static function _licLive($oL) + { + try { + if (!function_exists('curl_init')) { + throw new \Exception(__NAMESPACE__ . ': cURL needs to be installed!'); + } + + $urlShop = self::getDomain(); + + $params = [ + 'domain' => $urlShop, + 'plugin_version' => (int)self::oPlugin()->nVersion, + 'plugin_id' => self::oPlugin()->cPluginID, + 'email' => self::_masterMail(), + 'shop_version' => (string)(defined('APPLICATION_VERSION') ? APPLICATION_VERSION : JTL_VERSION), + 'shop_build' => defined('APPLICATION_BUILD_SHA') ? APPLICATION_BUILD_SHA : '', + 'php_version' => PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION . '.' . PHP_RELEASE_VERSION, + 'php_extra_version' => PHP_EXTRA_VERSION, + 'php_os' => PHP_OS, + 'server' => array_key_exists('SERVER_SOFTWARE', $_SERVER) ? $_SERVER['SERVER_SOFTWARE'] : '', + ]; + $curl = curl_init('https://lic.dash.bar'); + @curl_setopt($curl, CURLOPT_POST, 1); + @curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($params)); // http_build_query($params, '', '&')); + @curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 3); + @curl_setopt($curl, CURLOPT_TIMEOUT, 3); + @curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + @curl_setopt($curl, CURLOPT_HEADER, 0); + @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 licence info: ' . $statusCode); + } + /** @noinspection UnserializeExploitsInspection */ + if ($response = json_decode($data)) { + $checksum = md5(base64_encode($response->data->validUntil . $response->data->nextCheck . ($response->data->testLicence ? 'Y' : 'N'))); + + if (!$response || !isset($response->data) || $response->data === false || !isset($response->checksum) || $response->checksum !== $checksum) { + throw new \Exception(__NAMESPACE__ . ': Invalid licence info: ' . print_r($response, 1)); + } + $oLL = $response->data; + if (self::isPresent($oLL->validUntil)) { + $oL->validUntil = date('Y-m-d', $oLL->validUntil); + } + if (self::isPresent($oLL->nextCheck)) { + $oL->nextCheck = date('Y-m-d', $oLL->nextCheck); + } + if (self::isPresent($oLL->testLicence)) { + $oL->test = $oLL->testLicence ? 1 : 0; + } + $oL->fails = 0; + self::_licSave($oL, true); + } else { + throw new \Exception(__NAMESPACE__ . ': Could not decode licence info: ' . print_r($response, 1)); + } + } catch (\Exception $e) { + $oL->disabled = (++$oL->fails) >= 3 ? 1 : 0; + $oL->nextCheck = date("Y-m-d", strtotime("+1 DAY")); + $oL->validUntil = date("Y-m-d", strtotime("+1 DAY")); + ; + + self::logExc($e, false); + self::_licSave($oL, true); + } + return $oL; + } + + + /** + * @param $val + * @return bool + * @throws \Exception + */ + private static function ispresent($val) + { + if (isset($val)) { + return true; + } else { + throw new \Exception(__NAMESPACE__ . ': Could ned find value from license server ' . print_r($val, 1)); + } + } + + /** + * 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); + } + + /** + * @return mixed + */ + private static function _masterMail() + { + $settings = \Shop::getSettings(array(CONF_EMAILS)); + return $settings['emails']['email_master_absender']; + } + + /** + * @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/101/class/Model/AbstractModel.php b/version/101/class/Model/AbstractModel.php new file mode 100644 index 0000000..5638700 --- /dev/null +++ b/version/101/class/Model/AbstractModel.php @@ -0,0 +1,7 @@ + $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, + ]; + 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; + } + + 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/101/class/Mollie.php b/version/101/class/Mollie.php new file mode 100644 index 0000000..fd97087 --- /dev/null +++ b/version/101/class/Mollie.php @@ -0,0 +1,202 @@ +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) { + header('Location: ' . $url); + exit(); + } + return $url; + } + + protected static $_jtlmollie; + + /** + * @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; + } + + + /** + * @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; + } + + switch ((int)$newStatus) { + case BESTELLUNG_STATUS_VERSANDT: + $options['lines'] = []; + break; + case BESTELLUNG_STATUS_TEILVERSANDT: + $lines = []; + foreach ($order->lines as $i => $line) { + if (($quantity = Mollie::getBestellPosSent($line->sku, $oBestellung)) !== false && ($quantity - $line->quantityShipped) > 0) { + $x = $quantity - $line->quantityShipped; + $lines[] = (object)[ + 'id' => $line->id, + 'quantity' => $x, + 'amount' => (object)[ + 'currency' => $line->totalAmount->currency, + 'value' => number_format($x * $line->unitPrice->value, 2), + ], + ]; + } + } + if (count($lines)) { + $options['lines'] = $lines; + } + break; + case BESTELLUNG_STATUS_STORNO: + $options = null; + break; + } + + return $options; + } + + + /** + * @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) { + $order->orderNumber = $oBestellung->cBestellNr; + Payment::updateFromPayment($order, $kBestellung); + + $oIncomingPayment = \Shop::DB()->executeQueryPrepared("SELECT * FROM tzahlungseingang WHERE cHinweis = :cHinweis AND kBestellung = :kBestellung", [':cHinweis' => $order->id, ':kBestellung' => $oBestellung->kBestellung], 1); + if (!$oIncomingPayment) { + $oIncomingPayment = new \stdClass(); + } + + // 2. Check PaymentStatus + switch ($order->status) { + case OrderStatus::STATUS_PAID: + case OrderStatus::STATUS_COMPLETED: + $oIncomingPayment->fBetrag = $order->amount->value; + $oIncomingPayment->cISO = $order->amount->curreny; + $oIncomingPayment->cHinweis = $order->id; + Mollie::JTLMollie()->addIncomingPayment($oBestellung, $oIncomingPayment); + Mollie::JTLMollie()->setOrderStatusToPaid($oBestellung); + Mollie::JTLMollie()->doLog('PaymentStatus: ' . $order->status . ' => Zahlungseingang (' . $order->amount->value . ')', $logData, LOGLEVEL_DEBUG); + break; + case OrderStatus::STATUS_SHIPPING: + case OrderStatus::STATUS_AUTHORIZED: + case OrderStatus::STATUS_PENDING: + Mollie::JTLMollie()->setOrderStatusToPaid($oBestellung); + Mollie::JTLMollie()->doLog('PaymentStatus: ' . $order->status . ' => Bestellung bezahlt', $logData, LOGLEVEL_NOTICE); + break; + case OrderStatus::STATUS_CANCELED: + case OrderStatus::STATUS_EXPIRED: + Mollie::JTLMollie()->doLog('PaymentStatus: ' . $order->status, $logData, LOGLEVEL_ERROR); + break; + } + return true; + } + return false; + } +} diff --git a/version/101/frontend/131_globalinclude.php b/version/101/frontend/131_globalinclude.php new file mode 100644 index 0000000..118f6b6 --- /dev/null +++ b/version/101/frontend/131_globalinclude.php @@ -0,0 +1,67 @@ +executeQueryPrepared("SELECT * FROM " . \ws_mollie\Model\Payment::TABLE . " WHERE cHash = :cHash", [':cHash' => $_REQUEST['mollie']], 1); + // Bestellung finalized, redirect to status/completion page + if ((int)$payment->kBestellung) { + $logData = '$' . $payment->kID . '#' . $payment->kBestellung . "§" . $payment->cOrderNumber; + \ws_mollie\Mollie::JTLMollie()->doLog('Bestellung finalized => redirect abschluss/status', $logData); + $order = JTLMollie::API()->orders->get($payment->kID, ['embed' => 'payments']); + \ws_mollie\Mollie::handleOrder($order, $payment->kBestellung); + \ws_mollie\Mollie::getOrderCompletedRedirect($payment->kBestellung, true); + } elseif ($payment) { // payment, but no order => finalize it + require_once __DIR__ . '/../paymentmethod/JTLMollie.php'; + $order = JTLMollie::API()->orders->get($payment->kID, ['embed' => 'payments']); + $logData = '$' . $order->id . '#' . $payment->kBestellung . "§" . $payment->cOrderNumber; + + // GET NEWEST PAYMENT: + /** @var \Mollie\Api\Resources\Paymentt $_payment */ + $_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; + } + } + } + + // finalize only, if order is not canceld/expired + if ($order && !$order->isCanceled() && !$order->isExpired()) { + // finalize only if payment is not expired/canceled,failed or open + if ($_payment && !in_array($_payment->status, [\Mollie\Api\Types\PaymentStatus::STATUS_EXPIRED, \Mollie\Api\Types\PaymentStatus::STATUS_CANCELED, \Mollie\Api\Types\PaymentStatus::STATUS_OPEN, \Mollie\Api\Types\PaymentStatus::STATUS_FAILED, \Mollie\Api\Types\PaymentStatus::STATUS_CANCELED])) { + \ws_mollie\Mollie::JTLMollie()->doLog('Bestellung open => finalize', $logData); + $session = Session::getInstance(); + /** @noinspection PhpIncludeInspection */ + require_once PFAD_ROOT . 'includes/bestellabschluss_inc.php'; + /** @noinspection PhpIncludeInspection */ + require_once PFAD_ROOT . 'includes/mailTools.php'; + $oBestellung = fakeBestellung(); + $oBestellung = finalisiereBestellung(); + \ws_mollie\Mollie::JTLMollie()->doLog('Bestellung finalized => redirect
' . print_r($order, 1) . '
', $logData, LOGLEVEL_DEBUG); + \ws_mollie\Mollie::handleOrder($order, $oBestellung->kBestellung); + \ws_mollie\Mollie::getOrderCompletedRedirect($oBestellung->kBestellung, true); + } else { + \ws_mollie\Mollie::JTLMollie()->doLog('Invalid Payment
' . print_r($payment, 1) . '
', $logData, LOGLEVEL_ERROR); + } + } else { + \ws_mollie\Mollie::JTLMollie()->doLog('Invalid Order
' . print_r($order, 1) . '
', $logData, LOGLEVEL_ERROR); + } + } + } + ob_end_flush(); +} catch (Exception $e) { + \ws_mollie\Helper::logExc($e); +} diff --git a/version/101/frontend/140_smarty.php b/version/101/frontend/140_smarty.php new file mode 100644 index 0000000..3f74d4f --- /dev/null +++ b/version/101/frontend/140_smarty.php @@ -0,0 +1,53 @@ +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; + } + +CSS +); +} catch (Exception $e) { + \ws_mollie\Helper::logExc($e); +} diff --git a/version/101/frontend/144_notify.php b/version/101/frontend/144_notify.php new file mode 100644 index 0000000..8856259 --- /dev/null +++ b/version/101/frontend/144_notify.php @@ -0,0 +1,27 @@ + Update Payment, stop skript + * - ELSE weiter mit der notify.php + */ + +if (array_key_exists('hash', $_REQUEST)) { + require_once __DIR__ . '/../class/Helper.php'; + try { + \ws_mollie\Helper::init(); + $payment = \ws_mollie\Model\Payment::getPaymentHash($_REQUEST['hash']); + // If Bestellung already exists, treat as Notification + if ($payment && $payment->kBestellung) { + require_once __DIR__ . '/../paymentmethod/JTLMollie.php'; + $order = JTLMollie::API()->orders->get($payment->kID); + $logData = '#' . $payment->kBestellung . '$' . $payment->kID; + \ws_mollie\Mollie::JTLMollie()->doLog('Received Notification
' . print_r([$order, $payment], 1) . '
', $logData); + \ws_mollie\Mollie::handleOrder($order, $payment->kBestellung); + // exit to stop execution of notify.php + exit(); + } + } catch (Exception $e) { + \ws_mollie\Helper::logExc($e); + } +} diff --git a/version/101/frontend/181_sync.php b/version/101/frontend/181_sync.php new file mode 100644 index 0000000..be2fe16 --- /dev/null +++ b/version/101/frontend/181_sync.php @@ -0,0 +1,33 @@ +kBestellung && $payment = \ws_mollie\Model\Payment::getPayment($oBestellung->kBestellung)) { + $logData = '#' . $payment->kBestellung . '$' . $payment->kID . "§" . $oBestellung->cBestellNr; + \ws_mollie\Mollie::JTLMollie()->doLog("WAWI Abgleich: HOOK_BESTELLUNGEN_XML_BESTELLSTATUS", $logData); + try { + $order = JTLMollie::API()->orders->get($payment->kID); + $order->orderNumber = $oBestellung->cBestellNr; + \ws_mollie\Mollie::handleOrder($order, $oBestellung->kBestellung); + if ($order->isCreated() || $order->isPaid() || $order->isAuthorized() || $order->isShipping() || $order->isPending()) { + \ws_mollie\Mollie::JTLMollie()->doLog("Create Shippment:
" . print_r($args_arr, 1) . '
', $logData, LOGLEVEL_DEBUG); + $options = \ws_mollie\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); + \ws_mollie\Mollie::JTLMollie()->doLog('Shipment created
' . print_r(['options' => $options, 'shipment' => $shipment], 1) . '
', $logData, LOGLEVEL_NOTICE); + } else { + \ws_mollie\Mollie::JTLMollie()->doLog('181_sync: options don\'t contain lines
' . print_r([$order, $options], 1) . '
', $logData, LOGLEVEL_ERROR); + } + } + } catch (Exception $e) { + \ws_mollie\Mollie::JTLMollie()->doLog('Fehler: ' . $e->getMessage() . '
' . print_r($e->getTrace(), 1) . '
', $logData, LOGLEVEL_ERROR); + } + } +} catch (Exception $e) { + \ws_mollie\Helper::logExc($e); +} diff --git a/version/101/paymentmethod/JTLMollie.php b/version/101/paymentmethod/JTLMollie.php new file mode 100644 index 0000000..7a2f110 --- /dev/null +++ b/version/101/paymentmethod/JTLMollie.php @@ -0,0 +1,572 @@ +setApiKey(\ws_mollie\Helper::getSetting('api_key')); + } + return self::$_mollie; + } + + /** + * @param Bestellung $order + * @param Object $payment (Key, Zahlungsanbieter, Abgeholt, Zeit is set here) + * @return $this + */ + public function addIncomingPayment($order, $payment) + { + $model = (object)array_merge([ + 'kBestellung' => (int)$order->kBestellung, + 'cZahlungsanbieter' => empty($order->cZahlungsartName) ? $this->name : $order->cZahlungsartName, + 'fBetrag' => 0, + 'fZahlungsgebuehr' => 0, + 'cISO' => $_SESSION['Waehrung']->cISO, + 'cEmpfaenger' => '', + 'cZahler' => '', + 'dZeit' => 'now()', + 'cHinweis' => '', + 'cAbgeholt' => 'N' + ], (array)$payment); + if (isset($model->kZahlungseingang) && $model->kZahlungseingang > 0) { + Shop::DB()->update('tzahlungseingang', 'kZahlungseingang', $model->kZahlungseingang, $model); + } else { + Shop::DB()->insert('tzahlungseingang', $model); + } + + return $this; + } + + /** + * @return \ws_mollie\Helper + */ + public static function Helper() + { + if (self::$_helper === null) { + self::$_helper = new ws_mollie\Helper(); + } + return self::$_helper; + } + + /** + * @param Bestellung $order + * @return PaymentMethod|void + */ + public function setOrderStatusToPaid($order) + { + // If paid already, do nothing + if ((int)$order->cStatus >= BESTELLUNG_STATUS_BEZAHLT) { + return; + } + parent::setOrderStatusToPaid($order); + } + + /** + * @param Bestellung $order + * @param $hash + * @return array + */ + protected function getOrderData(Bestellung $order, $hash) + { + $locale = self::getLocale($_SESSION['cISOSprache'], $_SESSION['Kunde']->cLand); + $data = [ + 'locale' => $locale ? : 'de_DE', + 'amount' => (object)[ + 'currency' => $order->Waehrung->cISO, + 'value' => number_format($order->fGesamtsummeKundenwaehrung, 2, '.', ''), + ], + 'orderNumber' => $order->cBestellNr, + 'lines' => [], + 'billingAddress' => new stdClass(), + 'shippingAddress' => new stdClass(), + 'redirectUrl' => (int)$this->duringCheckout ? Shop::getURL() . '/bestellabschluss.php?mollie=' . md5($hash) : $this->getReturnURL($order), + 'webhookUrl' => $this->getNotificationURL($hash) . '&hash=' . md5($hash), + ]; + + if (static::MOLLIE_METHOD !== '') { + $data['method'] = static::MOLLIE_METHOD; + } + $data['billingAddress']->organizationName = utf8_encode($order->oRechnungsadresse->cFirma); + $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 = $order->oRechnungsadresse->cMail; + $data['billingAddress']->streetAndNumber = utf8_encode($order->oRechnungsadresse->cStrasse . ' ' . $order->oRechnungsadresse->cHausnummer); + $data['billingAddress']->postalCode = $order->oRechnungsadresse->cPLZ; + $data['billingAddress']->city = utf8_encode($order->oRechnungsadresse->cOrt); + $data['billingAddress']->country = $order->oRechnungsadresse->cLand; + + //if ((int)$order->kLieferadresse) { + $data['shippingAddress']->organizationName = utf8_encode($order->Lieferadresse->cFirma); + $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 = $order->oRechnungsadresse->cMail; + $data['shippingAddress']->streetAndNumber = utf8_encode($order->Lieferadresse->cStrasse . ' ' . $order->Lieferadresse->cHausnummer); + $data['shippingAddress']->postalCode = $order->Lieferadresse->cPLZ; + $data['shippingAddress']->city = utf8_encode($order->Lieferadresse->cOrt); + $data['shippingAddress']->country = $order->Lieferadresse->cLand; + //} + + /** @var WarenkorbPos $oPosition */ + foreach ($order->Positionen as $oPosition) { + $line = new stdClass(); + switch ((int)$oPosition->nPosTyp) { + case (int)C_WARENKORBPOS_TYP_GRATISGESCHENK: + case (int)C_WARENKORBPOS_TYP_ARTIKEL: + $line->type = \Mollie\Api\Types\OrderLineType::TYPE_PHYSICAL; + $line->name = utf8_encode($oPosition->cName); + $line->quantity = $oPosition->nAnzahl; + $line->unitPrice = (object)[ + 'value' => number_format($order->Waehrung->fFaktor * ($oPosition->fPreis * ((float)$oPosition->fMwSt / 100 + 1)), 2, '.', ''), + 'currency' => $order->Waehrung->cISO, + ]; + $line->totalAmount = (object)[ + 'value' => number_format($oPosition->nAnzahl * (float)$line->unitPrice->value, 2, '.', ''), + 'currency' => $order->Waehrung->cISO, + ]; + $line->vatRate = $oPosition->fMwSt; + $line->vatAmount = (object)[ + 'value' => number_format($line->totalAmount->value - ($line->totalAmount->value / (1 + (float)$oPosition->fMwSt / 100)), 2, '.', ''), + 'currency' => $order->Waehrung->cISO, + ]; + $line->sku = $oPosition->cArtNr; + break; + case (int)C_WARENKORBPOS_TYP_VERSANDPOS: + $line->type = \Mollie\Api\Types\OrderLineType::TYPE_SHIPPING_FEE; + $line->name = utf8_encode($oPosition->cName); + $line->quantity = $oPosition->nAnzahl; + $line->unitPrice = (object)[ + 'value' => number_format($order->Waehrung->fFaktor * ($oPosition->fPreis * ((float)$oPosition->fMwSt / 100 + 1)), 2, '.', ''), + 'currency' => $order->Waehrung->cISO, + ]; + $line->totalAmount = (object)[ + 'value' => number_format($order->Waehrung->fFaktor * ($oPosition->fPreis * $oPosition->nAnzahl * ((float)$oPosition->fMwSt / 100 + 1)), 2, '.', ''), + 'currency' => $order->Waehrung->cISO, + ]; + $line->vatRate = $oPosition->fMwSt; + $line->vatAmount = (object)[ + 'value' => number_format($line->totalAmount->value - ($line->totalAmount->value / (1 + (float)$oPosition->fMwSt / 100)), 2, '.', ''), + 'currency' => $order->Waehrung->cISO, + ]; + 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 = \Mollie\Api\Types\OrderLineType::TYPE_SURCHARGE; + $line->name = utf8_encode($oPosition->cName); + $line->quantity = $oPosition->nAnzahl; + $line->unitPrice = (object)[ + 'value' => number_format($order->Waehrung->fFaktor * ($oPosition->fPreis * ((float)$oPosition->fMwSt / 100 + 1)), 2, '.', ''), + 'currency' => $order->Waehrung->cISO, + ]; + $line->totalAmount = (object)[ + 'value' => number_format($order->Waehrung->fFaktor * ($oPosition->fPreis * $oPosition->nAnzahl * ((float)$oPosition->fMwSt / 100 + 1)), 2, '.', ''), + 'currency' => $order->Waehrung->cISO, + ]; + $line->vatRate = $oPosition->fMwSt; + $line->vatAmount = (object)[ + 'value' => number_format($line->totalAmount->value - ($line->totalAmount->value / (1 + (float)$oPosition->fMwSt / 100)), 2, '.', ''), + 'currency' => $order->Waehrung->cISO, + ]; + break; + case (int)C_WARENKORBPOS_TYP_GUTSCHEIN: + case (int)C_WARENKORBPOS_TYP_KUPON: + case (int)C_WARENKORBPOS_TYP_NEUKUNDENKUPON: + $line->type = \Mollie\Api\Types\OrderLineType::TYPE_DISCOUNT; + $line->name = $oPosition->cName; + $line->quantity = $oPosition->nAnzahl; + $line->unitPrice = (object)[ + 'value' => number_format($order->Waehrung->fFaktor * ($oPosition->fPreis * ((float)$oPosition->fMwSt / 100 + 1)), 2, '.', ''), + 'currency' => $order->Waehrung->cISO, + ]; + $line->totalAmount = (object)[ + 'value' => number_format($order->Waehrung->fFaktor * ($oPosition->fPreis * $oPosition->nAnzahl * ((float)$oPosition->fMwSt / 100 + 1)), 2, '.', ''), + 'currency' => $order->Waehrung->cISO, + ]; + $line->vatRate = $oPosition->fMwSt; + $line->vatAmount = (object)[ + 'value' => number_format($line->totalAmount->value - ($line->totalAmount->value / (1 + (float)$oPosition->fMwSt / 100)), 2, '.', ''), + 'currency' => $order->Waehrung->cISO, + ]; + break; + } + if (isset($line->type)) { + $data['lines'][] = $line; + } + } + + if ((int)$order->GuthabenNutzen === 1 && $order->fGuthaben < 0) { + $line = new stdClass(); + $line->type = \Mollie\Api\Types\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->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 ? \Mollie\Api\Types\OrderLineType::TYPE_SURCHARGE : \Mollie\Api\Types\OrderLineType::TYPE_DISCOUNT; + $line->name = 'Rundungsausgleich'; + $line->quantity = 1; + $line->unitPrice = (object)[ + 'value' => number_format($diff, 2, '.', ''), + 'currency' => $order->Waehrung->cISO, + ]; + $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; + } + + /** + * Prepares everything so that the Customer can start the Payment Process. + * Tells Template Engine. + * + * @param Bestellung $order + */ + public function preparePaymentProcess($order) + { + $logData = '#' . $order->kBestellung . "§" . $order->cBestellNr; + try { + $payment = \ws_mollie\Model\Payment::getPayment($order->kBestellung); + if ($payment && in_array($payment->cStatus, [\Mollie\Api\Types\OrderStatus::STATUS_CREATED]) && $payment->cCheckoutURL) { + $logData .= '$' . $payment->kID; + if (!$this->duringCheckout) { + Session::getInstance()->cleanUp(); + } + header('Location: ' . $payment->cCheckoutURL); + exit(); + } + } catch (\Exception $e) { + $this->doLog("Get Payment Error: " . $e->getMessage() . ". Create new ORDER...", $logData); + } + + try { + $hash = $this->generateHash($order); + $oMolliePayment = self::API()->orders->create($this->getOrderData($order, $hash)); + $_SESSION['oMolliePayment'] = $oMolliePayment; + $logData .= '$' . $oMolliePayment->id; + $this->doLog('Mollie Create Payment Redirect: ' . $oMolliePayment->getCheckoutUrl() . "
" . print_r($oMolliePayment, 1) . "
", $logData, LOGLEVEL_DEBUG); + \ws_mollie\Model\Payment::updateFromPayment($oMolliePayment, $order->kBestellung, md5($hash)); + Shop::Smarty()->assign('oMolliePayment', $oMolliePayment); + if (!$this->duringCheckout) { + Session::getInstance()->cleanUp(); + } + header('Location: ' . $oMolliePayment->getCheckoutUrl()); + exit(); + } catch (\Mollie\Api\Exceptions\ApiException $e) { + Shop::Smarty()->assign('oMollieException', $e); + $this->doLog("Create Payment Error: " . $e->getMessage() . '
' . print_r($e->getTrace(), 1) . '
', $logData); + } + } + + /** + * @param string $msg + * @param null $data + * @param int $level + * @return $this + */ + public function doLog($msg, $data = null, $level = LOGLEVEL_NOTICE) + { + ZahlungsLog::add($this->moduleID, $msg, $data, $level); + + return $this; + } + + /** + * @param Bestellung $order + * @param string $hash + * @param array $args + */ + public function handleNotification($order, $hash, $args) + { + \ws_mollie\Helper::autoload(); + $logData = '#' . $order->kBestellung . "§" . $order->cBestellNr; + $this->doLog('Received Notification
' . print_r([$hash, $args], 1) . '
', $logData, LOGLEVEL_NOTICE); + + try { + $oMolliePayment = self::API()->orders->get($args['id']); + \ws_mollie\Mollie::handleOrder($oMolliePayment, $order->kBestellung); + } catch (\Exception $e) { + $this->doLog('handleNotification: ' . $e->getMessage(), $logData); + } + } + + + /** + * @param Bestellung $order + * @param string $hash + * @param array $args + * + * @return true, if $order should be finalized + */ + public function finalizeOrder($order, $hash, $args) + { + $logData = '#' . $order->kBestellung . "§" . $order->cBestellNr; + try { + \ws_mollie\Helper::autoload(); + $oMolliePayment = self::API()->orders->get($args['id'], ['embed' => 'payments']); + $logData .= '$' . $oMolliePayment->id; + $this->doLog('Received Notification Finalize Order
' . print_r([$hash, $args, $oMolliePayment], 1) . '
', $logData, LOGLEVEL_DEBUG); + \ws_mollie\Model\Payment::updateFromPayment($oMolliePayment, $order->kBestellung); + return in_array($oMolliePayment->status, [\Mollie\Api\Types\OrderStatus::STATUS_PAID, \Mollie\Api\Types\OrderStatus::STATUS_AUTHORIZED, \Mollie\Api\Types\OrderStatus::STATUS_PENDING, \Mollie\Api\Types\OrderStatus::STATUS_COMPLETED]); + } catch (\Exception $e) { + $this->doLog($e->getMessage(), $logData); + } + return false; + } + + /** + * @return bool + */ + public function canPayAgain() + { + return true; + } + + + 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 "eng": + return "en_US"; + 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"; + } + } + + /** + * @var array + */ + protected static $_possiblePaymentMethods = []; + + /** + * @param $method + * @param $locale + * @param $billingCountry + * @param $currency + * @param $amount + * @return mixed|null + * @throws \Mollie\Api\Exceptions\ApiException + * @throws \Mollie\Api\Exceptions\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->all(['amount' => ['currency' => $currency, 'value' => number_format($amount, 2, '.', '')], 'billingCountry' => $_SESSION['Kunde']->cLand, 'locale' => $locale, '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 (ws_mollie\Helper::getSetting('paymentmethod_sync') === 'N') { + return; + } + $size = ws_mollie\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); + } + } + + /** + * determines, if the payment method can be selected in the checkout process + * + * @return bool + */ + public function isSelectable() + { + $locale = self::getLocale($_SESSION['cISOSprache'], $_SESSION['Kunde']->cLand); + if (static::MOLLIE_METHOD !== '') { + try { + /** @var Warenkorb $wk */ + $wk = $_SESSION['Warenkorb']; + $method = self::PossiblePaymentMethods(static::MOLLIE_METHOD, $locale, $_SESSION['Kunde']->cLand, $_SESSION['Waehrung']->cISO, $wk->gibGesamtsummeWaren() * $_SESSION['Waehrung']->fFaktor); + if ($method !== null) { + $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; + } + } + return true; + } + + /** + * + * @param object $customer + * @param Warenkorb $cart + * @return bool - true, if $customer with $cart may use Payment Method + */ + public function isValid($customer, $cart) + { + if (\ws_mollie\Helper::init() && \ws_mollie\Helper::getSetting("api_key")) { + return true; + } + $this->doLog("isValdid failed: init failed or no API Key given. Try clear the Cache."); + return false; + } + + /** + * @param array $args_arr + * @return bool + */ + public function isValidIntern($args_arr = []) + { + if (\ws_mollie\Helper::init() && \ws_mollie\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/101/paymentmethod/JTLMollieBancontact.php b/version/101/paymentmethod/JTLMollieBancontact.php new file mode 100644 index 0000000..0e5eeed --- /dev/null +++ b/version/101/paymentmethod/JTLMollieBancontact.php @@ -0,0 +1,8 @@ + + {$oMollieException->getMessage()} + +{/if} \ No newline at end of file diff --git a/version/101/sql/100.sql b/version/101/sql/100.sql new file mode 100644 index 0000000..a6cf185 --- /dev/null +++ b/version/101/sql/100.sql @@ -0,0 +1,22 @@ +CREATE TABLE `xplugin_ws_mollie_payments` ( + `kID` VARCHAR(32) NOT NULL, + `kBestellung` INT(11) NULL, + `cMode` VARCHAR(16) NULL, + `cStatus` VARCHAR(16) NOT NULL, + `cHash` VARCHAR(32) NULL, + `fAmount` FLOAT NOT NULL, + `cOrderNumber` VARCHAR(32) DEFAULT '' NOT NULL, + `cCurrency` VARCHAR(3) NOT NULL, + `cMethod` VARCHAR(16) NULL, + `cLocale` VARCHAR(5) NOT NULL, + `bCancelable` INT(1) NOT NULL, + `cWebhookURL` VARCHAR(255) DEFAULT '' NOT NULL, + `cRedirectURL` VARCHAR(255) DEFAULT '' NOT NULL, + `cCheckoutURL` VARCHAR(255) DEFAULT '' NOT NULL, + `fAmountCaptured` FLOAT NULL, + `fAmountRefunded` FLOAT NULL, + `dCreatedAt` DATETIME NULL +); + +ALTER TABLE `xplugin_ws_mollie_payments` + ADD PRIMARY KEY `kID` (`kID`); \ No newline at end of file From 0cb61b42fe171bda7e8128d6b991a2cc64406a52 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Mon, 11 Feb 2019 17:52:18 +0100 Subject: [PATCH 036/280] Update README.md --- README.md | 81 +++++++++++++++++++++++++------------------------------ 1 file changed, 36 insertions(+), 45 deletions(-) diff --git a/README.md b/README.md index eea714b..56e3862 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Download the [Mollie](https://www.mollie.com/) module for JTL-Shop. Mollie is a Receive payments from European customers with ease. Mollie provides payment methods at higly competitive rates. Only pay per transaction and no hidden fees. -Choose the best payment provider available for your online PrestaShop store. Create your merchant account at [Mollie.com](https://www.mollie.com/). +Choose the best payment provider available for your online JTL-Shop. Create your merchant account at [Mollie.com](https://www.mollie.com/). Download and install the Mollie PrestaShop payment module and start receiving online payments now! ## Made and maintained by [WebStollen](https://www.webstollen.de/). ## @@ -36,32 +36,23 @@ If you have no experience with this, then leave the installation of this module # Supported payment methods -### iDeal - -[iDEAL](https://www.mollie.com/en/payments/ideal) makes paying for your online purchases safe, secure and easy. -iDEAL is a Dutch payment system which links customers directly to their online banking program when making an online purchase. - -[Mollie](https://www.mollie.com/) makes it easy to connect with iDEAL, without the usual technical and administrative hassle. -Mollie gives you access to your transaction overviews and other statistics at any time. It is also possible to receive a notification by e-mail or SMS after every successful payment. - -[Mollie](https://www.mollie.com/) is the perfect partner for recieving iDEAL payments and it is not surprising that [Mollie](https://www.mollie.com/) provides iDEAL payments -for more than 40,000 websites. - ### Credit card [Credit card](https://www.mollie.com/en/payments/credit-card) is virtually the best-known method for receiving payments with global coverage. Because [Mollie](https://www.mollie.com/) supports the biggest credit card brands like Mastercard, VISA and American Express, your store will attract a lot more potential buyers. -### DirectDebit +### Klarna: Pay later +[Klarna: Pay later](https://www.mollie.com/en/payments/klarna-pay-later). Klarna is a flexible payment solution, which allows your customers various, flexible, ways to pay. -Mollie allows you to quickly and easily collect recurring payments through [SEPA Direct Debit](https://www.mollie.com/en/payments/direct-debit). It only takes 10 minutes to start receiving payments through SEPA Direct Debit and there are no hidden fees involved. +With Mollie you can integrate Klarna: Pay later quickly and start processing payments right away. -Collect recurring payments from over 34 European countries. +### Klarna: Slice it +[Klarna: Slice it](https://www.mollie.com/en/payments/klarna-slice-it). Klarna is a flexible payment solution, which allows your customers various, flexible, ways to pay. -### Bancontact -[Bancontact](https://www.mollie.com/en/payments/bancontact) uses a physical card that is linked to credit on a Belgian bank account. Payments via Bancontact / Mister Cash are guaranteed and strongly resemble the iDEAL payment system for the Netherlands. +With Mollie you can integrate Klarna: Slice it quickly and start processing payments right away. -Because payments are guaranteed, this payment method is a huge surplus for your online store. +### PayPal +[PayPal](https://www.mollie.com/en/payments/paypal) is a very popular payment method which is used worldwide. In a just few clicks, you can receive payments by bank transfer, credit card or PayPal balance. ### SOFORT Banking [SOFORT Banking](https://www.mollie.com/en/payments/sofort) is one of the most popular payment methods in Germany and active in 9 European countries: @@ -70,19 +61,39 @@ Germany, Belgium, the Netherlands, Italy, Austria, Poland, Switzerland, Spain an Payments are direct, non-reversible and this payment method opens up a huge market potential for your online store. -### ING Home’Pay -[ING Home’Pay](https://www.mollie.com/en/payments/ing-homepay). Mollie allows you to quickly and easily accept payments with ING Home'Pay. +### Giropay +[Giropay](https://www.mollie.com/en/payments/giropay). Giropay is a popular bank transfer payment method in Germany. -It only takes 10 minutes to start receiving payments and there are no hidden fees involved, you only pay for successful transactions. +It uses more than 1,500 German banks, which makes it a trusted payment method under German customers. + +### EPS +[EPS](https://www.mollie.com/en/payments/eps). The Electronic Payment Standard (EPS) is a payment method, developed by various Austrian banks. + +This makes EPS the main bank transfer payment method in Austria and highly popular with Austrian shoppers. ### Bank transfers [Bank transfers](https://www.mollie.com/en/payments/bank-transfer) received in the SEPA zone via [Mollie](https://www.mollie.com/). This allows you to receive payments from both individuals and business customers in more than 35 European countries. -### PayPal -[PayPal](https://www.mollie.com/en/payments/paypal) is a very popular payment method which is used worldwide. In a just few clicks, you can receive payments by bank transfer, credit card or PayPal balance. +### iDeal + +[iDEAL](https://www.mollie.com/en/payments/ideal) makes paying for your online purchases safe, secure and easy. +iDEAL is a Dutch payment system which links customers directly to their online banking program when making an online purchase. + +[Mollie](https://www.mollie.com/) makes it easy to connect with iDEAL, without the usual technical and administrative hassle. +Mollie gives you access to your transaction overviews and other statistics at any time. It is also possible to receive a notification by e-mail or SMS after every successful payment. -### Bitcoin -[Bitcoin](https://www.mollie.com/en/payments/bitcoin) is a form of electronic money. The exchange rate is determined at the time of the transaction, so the amount and the payment are guaranteed. +[Mollie](https://www.mollie.com/) is the perfect partner for recieving iDEAL payments and it is not surprising that [Mollie](https://www.mollie.com/) provides iDEAL payments +for more than 40,000 websites. + +### Bancontact +[Bancontact](https://www.mollie.com/en/payments/bancontact) uses a physical card that is linked to credit on a Belgian bank account. Payments via Bancontact / Mister Cash are guaranteed and strongly resemble the iDEAL payment system for the Netherlands. + +Because payments are guaranteed, this payment method is a huge surplus for your online store. + +### ING Home’Pay +[ING Home’Pay](https://www.mollie.com/en/payments/ing-homepay). Mollie allows you to quickly and easily accept payments with ING Home'Pay. + +It only takes 10 minutes to start receiving payments and there are no hidden fees involved, you only pay for successful transactions. ### paysafecard [paysafecard](https://www.mollie.com/en/payments/paysafecard) is the most popular prepaid card for online payments. With paysafecard you can receive prepaid payments from 43 countries. @@ -95,26 +106,6 @@ KBC focuses on Flanders and CBC on Wallonia. ### Belfius Pay Button [Belfius](https://www.mollie.com/en/payments/belfius) is one of the largest banks in Belgium. By introducing the Belfius Pay Button, the bank provides its customers with their own payment solution. -### EPS -[EPS](https://www.mollie.com/en/payments/eps). The Electronic Payment Standard (EPS) is a payment method, developed by various Austrian banks. - -This makes EPS the main bank transfer payment method in Austria and highly popular with Austrian shoppers. - -### Giropay -[Giropay](https://www.mollie.com/en/payments/giropay). Giropay is a popular bank transfer payment method in Germany. - -It uses more than 1,500 German banks, which makes it a trusted payment method under German customers. - -### Klarna: Pay later -[Klarna: Pay later](https://www.mollie.com/en/payments/klarna-pay-later). Klarna is a flexible payment solution, which allows your customers various, flexible, ways to pay. - -With Mollie you can integrate Klarna: Pay later quickly and start processing payments right away. - -### Klarna: Slice it -[Klarna: Slice it](https://www.mollie.com/en/payments/klarna-slice-it). Klarna is a flexible payment solution, which allows your customers various, flexible, ways to pay. - -With Mollie you can integrate Klarna: Slice it quickly and start processing payments right away. - ### Giftcard Smartcards that allow the giver to charge them with a desired amount. From 2477077d79a66071704c5ea52bb1d1a7ea315f95 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Wed, 13 Feb 2019 11:06:55 +0100 Subject: [PATCH 037/280] fix #19 --- version/100/paymentmethod/JTLMollie.php | 78 ++++++------------------- version/101/paymentmethod/JTLMollie.php | 78 ++++++------------------- 2 files changed, 34 insertions(+), 122 deletions(-) diff --git a/version/100/paymentmethod/JTLMollie.php b/version/100/paymentmethod/JTLMollie.php index 7a2f110..38cbc6d 100644 --- a/version/100/paymentmethod/JTLMollie.php +++ b/version/100/paymentmethod/JTLMollie.php @@ -154,44 +154,30 @@ protected function getOrderData(Bestellung $order, $hash) /** @var WarenkorbPos $oPosition */ foreach ($order->Positionen as $oPosition) { $line = new stdClass(); - switch ((int)$oPosition->nPosTyp) { - case (int)C_WARENKORBPOS_TYP_GRATISGESCHENK: - case (int)C_WARENKORBPOS_TYP_ARTIKEL: - $line->type = \Mollie\Api\Types\OrderLineType::TYPE_PHYSICAL; - $line->name = utf8_encode($oPosition->cName); - $line->quantity = $oPosition->nAnzahl; - $line->unitPrice = (object)[ + $line->name = utf8_encode($oPosition->cName); + $line->quantity = $oPosition->nAnzahl; + $line->unitPrice = (object)[ 'value' => number_format($order->Waehrung->fFaktor * ($oPosition->fPreis * ((float)$oPosition->fMwSt / 100 + 1)), 2, '.', ''), 'currency' => $order->Waehrung->cISO, ]; - $line->totalAmount = (object)[ + $line->totalAmount = (object)[ 'value' => number_format($oPosition->nAnzahl * (float)$line->unitPrice->value, 2, '.', ''), 'currency' => $order->Waehrung->cISO, ]; - $line->vatRate = $oPosition->fMwSt; - $line->vatAmount = (object)[ - 'value' => number_format($line->totalAmount->value - ($line->totalAmount->value / (1 + (float)$oPosition->fMwSt / 100)), 2, '.', ''), - 'currency' => $order->Waehrung->cISO, - ]; + $line->vatRate = $oPosition->fMwSt; + $line->vatAmount = (object)[ + 'value' => number_format($line->totalAmount->value - ($line->totalAmount->value / (1 + (float)$oPosition->fMwSt / 100)), 2, '.', ''), + 'currency' => $order->Waehrung->cISO, + ]; + + switch ((int)$oPosition->nPosTyp) { + case (int)C_WARENKORBPOS_TYP_GRATISGESCHENK: + case (int)C_WARENKORBPOS_TYP_ARTIKEL: + $line->type = \Mollie\Api\Types\OrderLineType::TYPE_PHYSICAL; $line->sku = $oPosition->cArtNr; break; case (int)C_WARENKORBPOS_TYP_VERSANDPOS: $line->type = \Mollie\Api\Types\OrderLineType::TYPE_SHIPPING_FEE; - $line->name = utf8_encode($oPosition->cName); - $line->quantity = $oPosition->nAnzahl; - $line->unitPrice = (object)[ - 'value' => number_format($order->Waehrung->fFaktor * ($oPosition->fPreis * ((float)$oPosition->fMwSt / 100 + 1)), 2, '.', ''), - 'currency' => $order->Waehrung->cISO, - ]; - $line->totalAmount = (object)[ - 'value' => number_format($order->Waehrung->fFaktor * ($oPosition->fPreis * $oPosition->nAnzahl * ((float)$oPosition->fMwSt / 100 + 1)), 2, '.', ''), - 'currency' => $order->Waehrung->cISO, - ]; - $line->vatRate = $oPosition->fMwSt; - $line->vatAmount = (object)[ - 'value' => number_format($line->totalAmount->value - ($line->totalAmount->value / (1 + (float)$oPosition->fMwSt / 100)), 2, '.', ''), - 'currency' => $order->Waehrung->cISO, - ]; break; case (int)C_WARENKORBPOS_TYP_VERPACKUNG: case (int)C_WARENKORBPOS_TYP_VERSANDZUSCHLAG: @@ -199,41 +185,11 @@ protected function getOrderData(Bestellung $order, $hash) case (int)C_WARENKORBPOS_TYP_VERSAND_ARTIKELABHAENGIG: case (int)C_WARENKORBPOS_TYP_TRUSTEDSHOPS: $line->type = \Mollie\Api\Types\OrderLineType::TYPE_SURCHARGE; - $line->name = utf8_encode($oPosition->cName); - $line->quantity = $oPosition->nAnzahl; - $line->unitPrice = (object)[ - 'value' => number_format($order->Waehrung->fFaktor * ($oPosition->fPreis * ((float)$oPosition->fMwSt / 100 + 1)), 2, '.', ''), - 'currency' => $order->Waehrung->cISO, - ]; - $line->totalAmount = (object)[ - 'value' => number_format($order->Waehrung->fFaktor * ($oPosition->fPreis * $oPosition->nAnzahl * ((float)$oPosition->fMwSt / 100 + 1)), 2, '.', ''), - 'currency' => $order->Waehrung->cISO, - ]; - $line->vatRate = $oPosition->fMwSt; - $line->vatAmount = (object)[ - 'value' => number_format($line->totalAmount->value - ($line->totalAmount->value / (1 + (float)$oPosition->fMwSt / 100)), 2, '.', ''), - 'currency' => $order->Waehrung->cISO, - ]; break; case (int)C_WARENKORBPOS_TYP_GUTSCHEIN: case (int)C_WARENKORBPOS_TYP_KUPON: case (int)C_WARENKORBPOS_TYP_NEUKUNDENKUPON: $line->type = \Mollie\Api\Types\OrderLineType::TYPE_DISCOUNT; - $line->name = $oPosition->cName; - $line->quantity = $oPosition->nAnzahl; - $line->unitPrice = (object)[ - 'value' => number_format($order->Waehrung->fFaktor * ($oPosition->fPreis * ((float)$oPosition->fMwSt / 100 + 1)), 2, '.', ''), - 'currency' => $order->Waehrung->cISO, - ]; - $line->totalAmount = (object)[ - 'value' => number_format($order->Waehrung->fFaktor * ($oPosition->fPreis * $oPosition->nAnzahl * ((float)$oPosition->fMwSt / 100 + 1)), 2, '.', ''), - 'currency' => $order->Waehrung->cISO, - ]; - $line->vatRate = $oPosition->fMwSt; - $line->vatAmount = (object)[ - 'value' => number_format($line->totalAmount->value - ($line->totalAmount->value / (1 + (float)$oPosition->fMwSt / 100)), 2, '.', ''), - 'currency' => $order->Waehrung->cISO, - ]; break; } if (isset($line->type)) { @@ -310,7 +266,7 @@ protected function getOrderData(Bestellung $order, $hash) */ public function preparePaymentProcess($order) { - $logData = '#' . $order->kBestellung . "§" . $order->cBestellNr; + $logData = '#' . $order->kBestellung . "" . $order->cBestellNr; try { $payment = \ws_mollie\Model\Payment::getPayment($order->kBestellung); if ($payment && in_array($payment->cStatus, [\Mollie\Api\Types\OrderStatus::STATUS_CREATED]) && $payment->cCheckoutURL) { @@ -365,7 +321,7 @@ public function doLog($msg, $data = null, $level = LOGLEVEL_NOTICE) public function handleNotification($order, $hash, $args) { \ws_mollie\Helper::autoload(); - $logData = '#' . $order->kBestellung . "§" . $order->cBestellNr; + $logData = '#' . $order->kBestellung . "" . $order->cBestellNr; $this->doLog('Received Notification
' . print_r([$hash, $args], 1) . '
', $logData, LOGLEVEL_NOTICE); try { @@ -386,7 +342,7 @@ public function handleNotification($order, $hash, $args) */ public function finalizeOrder($order, $hash, $args) { - $logData = '#' . $order->kBestellung . "§" . $order->cBestellNr; + $logData = '#' . $order->kBestellung . "" . $order->cBestellNr; try { \ws_mollie\Helper::autoload(); $oMolliePayment = self::API()->orders->get($args['id'], ['embed' => 'payments']); diff --git a/version/101/paymentmethod/JTLMollie.php b/version/101/paymentmethod/JTLMollie.php index 7a2f110..38cbc6d 100644 --- a/version/101/paymentmethod/JTLMollie.php +++ b/version/101/paymentmethod/JTLMollie.php @@ -154,44 +154,30 @@ protected function getOrderData(Bestellung $order, $hash) /** @var WarenkorbPos $oPosition */ foreach ($order->Positionen as $oPosition) { $line = new stdClass(); - switch ((int)$oPosition->nPosTyp) { - case (int)C_WARENKORBPOS_TYP_GRATISGESCHENK: - case (int)C_WARENKORBPOS_TYP_ARTIKEL: - $line->type = \Mollie\Api\Types\OrderLineType::TYPE_PHYSICAL; - $line->name = utf8_encode($oPosition->cName); - $line->quantity = $oPosition->nAnzahl; - $line->unitPrice = (object)[ + $line->name = utf8_encode($oPosition->cName); + $line->quantity = $oPosition->nAnzahl; + $line->unitPrice = (object)[ 'value' => number_format($order->Waehrung->fFaktor * ($oPosition->fPreis * ((float)$oPosition->fMwSt / 100 + 1)), 2, '.', ''), 'currency' => $order->Waehrung->cISO, ]; - $line->totalAmount = (object)[ + $line->totalAmount = (object)[ 'value' => number_format($oPosition->nAnzahl * (float)$line->unitPrice->value, 2, '.', ''), 'currency' => $order->Waehrung->cISO, ]; - $line->vatRate = $oPosition->fMwSt; - $line->vatAmount = (object)[ - 'value' => number_format($line->totalAmount->value - ($line->totalAmount->value / (1 + (float)$oPosition->fMwSt / 100)), 2, '.', ''), - 'currency' => $order->Waehrung->cISO, - ]; + $line->vatRate = $oPosition->fMwSt; + $line->vatAmount = (object)[ + 'value' => number_format($line->totalAmount->value - ($line->totalAmount->value / (1 + (float)$oPosition->fMwSt / 100)), 2, '.', ''), + 'currency' => $order->Waehrung->cISO, + ]; + + switch ((int)$oPosition->nPosTyp) { + case (int)C_WARENKORBPOS_TYP_GRATISGESCHENK: + case (int)C_WARENKORBPOS_TYP_ARTIKEL: + $line->type = \Mollie\Api\Types\OrderLineType::TYPE_PHYSICAL; $line->sku = $oPosition->cArtNr; break; case (int)C_WARENKORBPOS_TYP_VERSANDPOS: $line->type = \Mollie\Api\Types\OrderLineType::TYPE_SHIPPING_FEE; - $line->name = utf8_encode($oPosition->cName); - $line->quantity = $oPosition->nAnzahl; - $line->unitPrice = (object)[ - 'value' => number_format($order->Waehrung->fFaktor * ($oPosition->fPreis * ((float)$oPosition->fMwSt / 100 + 1)), 2, '.', ''), - 'currency' => $order->Waehrung->cISO, - ]; - $line->totalAmount = (object)[ - 'value' => number_format($order->Waehrung->fFaktor * ($oPosition->fPreis * $oPosition->nAnzahl * ((float)$oPosition->fMwSt / 100 + 1)), 2, '.', ''), - 'currency' => $order->Waehrung->cISO, - ]; - $line->vatRate = $oPosition->fMwSt; - $line->vatAmount = (object)[ - 'value' => number_format($line->totalAmount->value - ($line->totalAmount->value / (1 + (float)$oPosition->fMwSt / 100)), 2, '.', ''), - 'currency' => $order->Waehrung->cISO, - ]; break; case (int)C_WARENKORBPOS_TYP_VERPACKUNG: case (int)C_WARENKORBPOS_TYP_VERSANDZUSCHLAG: @@ -199,41 +185,11 @@ protected function getOrderData(Bestellung $order, $hash) case (int)C_WARENKORBPOS_TYP_VERSAND_ARTIKELABHAENGIG: case (int)C_WARENKORBPOS_TYP_TRUSTEDSHOPS: $line->type = \Mollie\Api\Types\OrderLineType::TYPE_SURCHARGE; - $line->name = utf8_encode($oPosition->cName); - $line->quantity = $oPosition->nAnzahl; - $line->unitPrice = (object)[ - 'value' => number_format($order->Waehrung->fFaktor * ($oPosition->fPreis * ((float)$oPosition->fMwSt / 100 + 1)), 2, '.', ''), - 'currency' => $order->Waehrung->cISO, - ]; - $line->totalAmount = (object)[ - 'value' => number_format($order->Waehrung->fFaktor * ($oPosition->fPreis * $oPosition->nAnzahl * ((float)$oPosition->fMwSt / 100 + 1)), 2, '.', ''), - 'currency' => $order->Waehrung->cISO, - ]; - $line->vatRate = $oPosition->fMwSt; - $line->vatAmount = (object)[ - 'value' => number_format($line->totalAmount->value - ($line->totalAmount->value / (1 + (float)$oPosition->fMwSt / 100)), 2, '.', ''), - 'currency' => $order->Waehrung->cISO, - ]; break; case (int)C_WARENKORBPOS_TYP_GUTSCHEIN: case (int)C_WARENKORBPOS_TYP_KUPON: case (int)C_WARENKORBPOS_TYP_NEUKUNDENKUPON: $line->type = \Mollie\Api\Types\OrderLineType::TYPE_DISCOUNT; - $line->name = $oPosition->cName; - $line->quantity = $oPosition->nAnzahl; - $line->unitPrice = (object)[ - 'value' => number_format($order->Waehrung->fFaktor * ($oPosition->fPreis * ((float)$oPosition->fMwSt / 100 + 1)), 2, '.', ''), - 'currency' => $order->Waehrung->cISO, - ]; - $line->totalAmount = (object)[ - 'value' => number_format($order->Waehrung->fFaktor * ($oPosition->fPreis * $oPosition->nAnzahl * ((float)$oPosition->fMwSt / 100 + 1)), 2, '.', ''), - 'currency' => $order->Waehrung->cISO, - ]; - $line->vatRate = $oPosition->fMwSt; - $line->vatAmount = (object)[ - 'value' => number_format($line->totalAmount->value - ($line->totalAmount->value / (1 + (float)$oPosition->fMwSt / 100)), 2, '.', ''), - 'currency' => $order->Waehrung->cISO, - ]; break; } if (isset($line->type)) { @@ -310,7 +266,7 @@ protected function getOrderData(Bestellung $order, $hash) */ public function preparePaymentProcess($order) { - $logData = '#' . $order->kBestellung . "§" . $order->cBestellNr; + $logData = '#' . $order->kBestellung . "" . $order->cBestellNr; try { $payment = \ws_mollie\Model\Payment::getPayment($order->kBestellung); if ($payment && in_array($payment->cStatus, [\Mollie\Api\Types\OrderStatus::STATUS_CREATED]) && $payment->cCheckoutURL) { @@ -365,7 +321,7 @@ public function doLog($msg, $data = null, $level = LOGLEVEL_NOTICE) public function handleNotification($order, $hash, $args) { \ws_mollie\Helper::autoload(); - $logData = '#' . $order->kBestellung . "§" . $order->cBestellNr; + $logData = '#' . $order->kBestellung . "" . $order->cBestellNr; $this->doLog('Received Notification
' . print_r([$hash, $args], 1) . '
', $logData, LOGLEVEL_NOTICE); try { @@ -386,7 +342,7 @@ public function handleNotification($order, $hash, $args) */ public function finalizeOrder($order, $hash, $args) { - $logData = '#' . $order->kBestellung . "§" . $order->cBestellNr; + $logData = '#' . $order->kBestellung . "" . $order->cBestellNr; try { \ws_mollie\Helper::autoload(); $oMolliePayment = self::API()->orders->get($args['id'], ['embed' => 'payments']); From 466b91020481e801b7889185e2f4229922684fef Mon Sep 17 00:00:00 2001 From: "C. Proske" Date: Tue, 26 Feb 2019 11:01:24 +0100 Subject: [PATCH 038/280] fix #21, #22 --- composer.lock | 97 ++++++- version/101/class/Mollie.php | 109 ++++---- version/101/paymentmethod/JTLMollie.php | 336 ++++++++++++------------ 3 files changed, 310 insertions(+), 232 deletions(-) diff --git a/composer.lock b/composer.lock index e8d8655..a84663a 100644 --- a/composer.lock +++ b/composer.lock @@ -426,12 +426,12 @@ "source": { "type": "git", "url": "https://github.com/Roave/SecurityAdvisories.git", - "reference": "344bf4ed1263c75e7f96b87b80c52e8373561e19" + "reference": "614a9db1df6be4349544311096f8d48ca067ccbb" }, "dist": { "type": "zip", - "url": "https://github.com/gitapi/repos/Roave/SecurityAdvisories/zipball/344bf4ed1263c75e7f96b87b80c52e8373561e19", - "reference": "344bf4ed1263c75e7f96b87b80c52e8373561e19", + "url": "https://github.com/gitapi/repos/Roave/SecurityAdvisories/zipball/614a9db1df6be4349544311096f8d48ca067ccbb", + "reference": "614a9db1df6be4349544311096f8d48ca067ccbb", "shasum": "" }, "conflict": { @@ -466,8 +466,91 @@ "doctrine/mongodb-odm-bundle": ">=2,<3.0.1", "doctrine/orm": ">=2,<2.4.8|>=2.5,<2.5.1", "dompdf/dompdf": ">=0.6,<0.6.2", - "drupal/core": ">=7,<7.62|>=8,<8.5.9|>=8.6,<8.6.6", - "drupal/drupal": ">=7,<7.62|>=8,<8.5.9|>=8.6,<8.6.6", + "drupal/acquia_connector": ">=1,<1.16", + "drupal/autologout": ">=4,<4.5", + "drupal/backup_migrate": ">=3,<3.4", + "drupal/bealestreet": ">=1,<1.2", + "drupal/bible": ">=1,<1.7", + "drupal/bing_autosuggest_api": ">=1,<1.1", + "drupal/bootstrap": ">=3,<3.14", + "drupal/brilliant_gallery": ">=1,<1.10", + "drupal/ckeditor_uploadimage": ">=1,<1.5", + "drupal/cleantalk": ">=2,<2.7", + "drupal/cloud": ">=1,<1.7", + "drupal/commerce": ">=2,<2.9", + "drupal/commerce_custom_order_status": ">=1,<1.1", + "drupal/commerce_klarna_checkout": ">=1,<1.5", + "drupal/config_perms": ">=1,<1.1|>=2,<2.2", + "drupal/config_update": ">=1,<1.5", + "drupal/core": ">=7,<7.62|>=8,<8.5.11|>=8.6,<8.6.10", + "drupal/datereminder": ">=1,<1.15", + "drupal/decoupled_router": ">=1,<1.2", + "drupal/domain_integration": ">=1,<1.2", + "drupal/drupal": ">=7,<7.62|>=8,<8.5.11|>=8.6,<8.6.10", + "drupal/entity": ">=1,<1.9", + "drupal/entity_ref_tab_formatter": ">=1,<1.3", + "drupal/entityqueue_taxonomy": ">=1,<1.1", + "drupal/esign": ">=1,<1.10", + "drupal/eu_cookie_compliance": ">=1,<1.1", + "drupal/exif": ">=1,<1.1", + "drupal/feedback_collect": ">=1,<1.6", + "drupal/filefield_paths": ">=1,<1.1", + "drupal/filefield_sources": ">=1,<1.11", + "drupal/focal_point": ">=1,<1.2", + "drupal/fontawesome": ">=2,<2.12", + "drupal/fraction": ">=1,<1.2", + "drupal/gathercontent": ">=3,<3.5", + "drupal/genpass": ">=1,<1.1", + "drupal/hosting_https": ">=3,<3.170", + "drupal/jsonapi": ">=1,<1.16", + "drupal/lightbox2": ">=2,<2.11", + "drupal/link": ">=1,<1.6", + "drupal/litejazz": ">=2,<2.3", + "drupal/mailhandler": ">=2,<2.11", + "drupal/mass_pwreset": ">=1,<1.1", + "drupal/me": ">=1,<1.3", + "drupal/media": ">=2,<2.19", + "drupal/menu_export": ">=1,<1.2", + "drupal/metatag": ">=1,<1.8", + "drupal/miniorange_oauth_client": ">=1,<1.21", + "drupal/moneysuite": ">=10,<10.4", + "drupal/mosaik": ">=1,<1.2", + "drupal/netforum_authentication": ">=1,<1.1", + "drupal/newsflash": ">=2,<2.6", + "drupal/node_feedback": ">=1,<1.3", + "drupal/node_view_permissions": ">=1,<1.1", + "drupal/nucleus": ">=1,<1.6", + "drupal/nvp": ">=1,<1.1", + "drupal/panels_breadcrumbs": ">=2,<2.4", + "drupal/panopoly_core": ">=1,<1.49", + "drupal/paragraphs": ">=1,<1.6", + "drupal/password_policy": ">=1,<1.16", + "drupal/permissions_by_term": ">=1,<1.35", + "drupal/phonefield": ">=1,<1.1", + "drupal/phpconfig": ">=1,<1.1", + "drupal/preview_link": ">=1,<1.1", + "drupal/print": ">=2,<2.1", + "drupal/provision": ">=3,<3.170", + "drupal/pubdlcnt": ">=1,<1.3", + "drupal/renderkit": ">=1,<1.6", + "drupal/responsive_menus": ">=1,<1.7", + "drupal/restws": ">=2,<2.8", + "drupal/sagepay_payment": ">=1,<1.5", + "drupal/salesforce": ">=3,<3.1", + "drupal/search_api_solr": ">=1,<1.14", + "drupal/search_autocomplete": ">=4,<4.8", + "drupal/services_sso_client": ">=1,<1.6", + "drupal/stacks": ">=1,<1.1", + "drupal/tapestry": ">=2,<2.2", + "drupal/term_reference_tree": ">=1,<1.11", + "drupal/tfa_basic": ">=1,<1.1", + "drupal/tft": ">=1,<1.1", + "drupal/tmgmt": ">=1,<1.7", + "drupal/uuid": ">=1,<1.1", + "drupal/video": ">=1,<1.4", + "drupal/workbench_moderation": ">=1,<1.4", + "drupal/yandex_metrics": ">=3,<3.1", + "drupal/zircon": ">=1,<1.2", "erusev/parsedown": "<1.7", "ezsystems/ezpublish-kernel": ">=5.3,<5.3.12.1|>=5.4,<5.4.13.1|>=6,<6.7.9.1|>=6.8,<6.13.5.1|>=7,<7.2.4.1|>=7.3,<7.3.2.1", "ezsystems/ezpublish-legacy": ">=5.3,<5.3.12.6|>=5.4,<5.4.12.3|>=2011,<2017.12.4.3|>=2018.6,<2018.6.1.4|>=2018.9,<2018.9.1.3", @@ -526,7 +609,7 @@ "shopware/shopware": "<5.3.7", "silverstripe/cms": ">=3,<=3.0.11|>=3.1,<3.1.11", "silverstripe/forum": "<=0.6.1|>=0.7,<=0.7.3", - "silverstripe/framework": ">=3,<3.3", + "silverstripe/framework": ">=3,<3.6.7|>=3.7,<3.7.3|>=4,<4.0.7|>=4.1,<4.1.5|>=4.2,<4.2.4|>=4.3,<4.3.1", "silverstripe/userforms": "<3", "simple-updates/phpwhois": "<=1", "simplesamlphp/saml2": "<1.10.6|>=2,<2.3.8|>=3,<3.1.4", @@ -622,7 +705,7 @@ } ], "description": "Prevents installation of composer packages with known security vulnerabilities: no API, simply require it", - "time": "2019-02-05T19:58:17+00:00" + "time": "2019-02-22T18:40:39+00:00" } ], "packages-dev": [], diff --git a/version/101/class/Mollie.php b/version/101/class/Mollie.php index fd97087..bb41923 100644 --- a/version/101/class/Mollie.php +++ b/version/101/class/Mollie.php @@ -15,6 +15,8 @@ abstract class Mollie { + protected static $_jtlmollie; + /** * @param $kBestellung * @param bool $redirect @@ -40,58 +42,6 @@ public static function getOrderCompletedRedirect($kBestellung, $redirect = true) return $url; } - protected static $_jtlmollie; - - /** - * @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; - } - - /** * @param Order $order * @param $kBestellung @@ -152,6 +102,36 @@ public static function getShipmentOptions(Order $order, $kBestellung, $newStatus return $options; } + /** + * 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; + } /** * @param Order $order @@ -167,16 +147,17 @@ public static function handleOrder(Order $order, $kBestellung) if ($oBestellung->kBestellung) { $order->orderNumber = $oBestellung->cBestellNr; Payment::updateFromPayment($order, $kBestellung); - + $oIncomingPayment = \Shop::DB()->executeQueryPrepared("SELECT * FROM tzahlungseingang WHERE cHinweis = :cHinweis AND kBestellung = :kBestellung", [':cHinweis' => $order->id, ':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: $oIncomingPayment->fBetrag = $order->amount->value; $oIncomingPayment->cISO = $order->amount->curreny; $oIncomingPayment->cHinweis = $order->id; @@ -185,10 +166,9 @@ public static function handleOrder(Order $order, $kBestellung) Mollie::JTLMollie()->doLog('PaymentStatus: ' . $order->status . ' => Zahlungseingang (' . $order->amount->value . ')', $logData, LOGLEVEL_DEBUG); break; case OrderStatus::STATUS_SHIPPING: - case OrderStatus::STATUS_AUTHORIZED: case OrderStatus::STATUS_PENDING: Mollie::JTLMollie()->setOrderStatusToPaid($oBestellung); - Mollie::JTLMollie()->doLog('PaymentStatus: ' . $order->status . ' => Bestellung bezahlt', $logData, LOGLEVEL_NOTICE); + Mollie::JTLMollie()->doLog('PaymentStatus: ' . $order->status . ' => Bestellung bezahlt, KEIN Zahlungseingang', $logData, LOGLEVEL_NOTICE); break; case OrderStatus::STATUS_CANCELED: case OrderStatus::STATUS_EXPIRED: @@ -199,4 +179,21 @@ public static function handleOrder(Order $order, $kBestellung) } return false; } + + /** + * @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; + } } diff --git a/version/101/paymentmethod/JTLMollie.php b/version/101/paymentmethod/JTLMollie.php index 38cbc6d..9b21eff 100644 --- a/version/101/paymentmethod/JTLMollie.php +++ b/version/101/paymentmethod/JTLMollie.php @@ -26,7 +26,10 @@ class JTLMollie extends \PaymentMethod * @var \Mollie\Api\MollieApiClient */ protected static $_mollie; - + /** + * @var array + */ + protected static $_possiblePaymentMethods = []; /** * @var string */ @@ -39,37 +42,34 @@ public function __construct($moduleID, $nAgainCheckout = 0) } /** - * @return \Mollie\Api\MollieApiClient - * @throws \Mollie\Api\Exceptions\ApiException - * @throws \Mollie\Api\Exceptions\IncompatiblePlatform + * @return \ws_mollie\Helper */ - public static function API() + public static function Helper() { - if (self::$_mollie === null) { - self::$_mollie = new \Mollie\Api\MollieApiClient(); - self::$_mollie->setApiKey(\ws_mollie\Helper::getSetting('api_key')); + if (self::$_helper === null) { + self::$_helper = new ws_mollie\Helper(); } - return self::$_mollie; + return self::$_helper; } - + /** - * @param Bestellung $order - * @param Object $payment (Key, Zahlungsanbieter, Abgeholt, Zeit is set here) - * @return $this - */ + * @param Bestellung $order + * @param Object $payment (Key, Zahlungsanbieter, Abgeholt, Zeit is set here) + * @return $this + */ public function addIncomingPayment($order, $payment) { $model = (object)array_merge([ - 'kBestellung' => (int)$order->kBestellung, + 'kBestellung' => (int)$order->kBestellung, 'cZahlungsanbieter' => empty($order->cZahlungsartName) ? $this->name : $order->cZahlungsartName, - 'fBetrag' => 0, - 'fZahlungsgebuehr' => 0, - 'cISO' => $_SESSION['Waehrung']->cISO, - 'cEmpfaenger' => '', - 'cZahler' => '', - 'dZeit' => 'now()', - 'cHinweis' => '', - 'cAbgeholt' => 'N' + 'fBetrag' => 0, + 'fZahlungsgebuehr' => 0, + 'cISO' => $_SESSION['Waehrung']->cISO, + 'cEmpfaenger' => '', + 'cZahler' => '', + 'dZeit' => 'now()', + 'cHinweis' => '', + 'cAbgeholt' => 'N' ], (array)$payment); if (isset($model->kZahlungseingang) && $model->kZahlungseingang > 0) { Shop::DB()->update('tzahlungseingang', 'kZahlungseingang', $model->kZahlungseingang, $model); @@ -80,17 +80,6 @@ public function addIncomingPayment($order, $payment) return $this; } - /** - * @return \ws_mollie\Helper - */ - public static function Helper() - { - if (self::$_helper === null) { - self::$_helper = new ws_mollie\Helper(); - } - return self::$_helper; - } - /** * @param Bestellung $order * @return PaymentMethod|void @@ -104,6 +93,77 @@ public function setOrderStatusToPaid($order) parent::setOrderStatusToPaid($order); } + /** + * Prepares everything so that the Customer can start the Payment Process. + * Tells Template Engine. + * + * @param Bestellung $order + */ + public function preparePaymentProcess($order) + { + $logData = '#' . $order->kBestellung . "" . $order->cBestellNr; + try { + $payment = \ws_mollie\Model\Payment::getPayment($order->kBestellung); + if ($payment && in_array($payment->cStatus, [\Mollie\Api\Types\OrderStatus::STATUS_CREATED]) && $payment->cCheckoutURL) { + $logData .= '$' . $payment->kID; + if (!$this->duringCheckout) { + Session::getInstance()->cleanUp(); + } + header('Location: ' . $payment->cCheckoutURL); + exit(); + } + } catch (\Exception $e) { + $this->doLog("Get Payment Error: " . $e->getMessage() . ". Create new ORDER...", $logData); + } + + try { + $hash = $this->generateHash($order); + $oMolliePayment = self::API()->orders->create($this->getOrderData($order, $hash)); + $_SESSION['oMolliePayment'] = $oMolliePayment; + $logData .= '$' . $oMolliePayment->id; + $this->doLog('Mollie Create Payment Redirect: ' . $oMolliePayment->getCheckoutUrl() . "
" . print_r($oMolliePayment, 1) . "
", $logData, LOGLEVEL_DEBUG); + \ws_mollie\Model\Payment::updateFromPayment($oMolliePayment, $order->kBestellung, md5($hash)); + Shop::Smarty()->assign('oMolliePayment', $oMolliePayment); + if (!$this->duringCheckout) { + Session::getInstance()->cleanUp(); + } + header('Location: ' . $oMolliePayment->getCheckoutUrl()); + exit(); + } catch (\Mollie\Api\Exceptions\ApiException $e) { + Shop::Smarty()->assign('oMollieException', $e); + $this->doLog("Create Payment Error: " . $e->getMessage() . '
' . print_r($e->getTrace(), 1) . '
', $logData); + } + } + + /** + * @param string $msg + * @param null $data + * @param int $level + * @return $this + */ + public function doLog($msg, $data = null, $level = LOGLEVEL_NOTICE) + { + ZahlungsLog::add($this->moduleID, $msg, $data, $level); + + return $this; + } + + /** + * @return \Mollie\Api\MollieApiClient + * @throws \Mollie\Api\Exceptions\ApiException + * @throws \Mollie\Api\Exceptions\IncompatiblePlatform + */ + public static function API() + { + if (self::$_mollie === null) { + self::$_mollie = new \Mollie\Api\MollieApiClient(); + self::$_mollie->setApiKey(\ws_mollie\Helper::getSetting('api_key')); + self::$_mollie->addVersionString("JTL-Shop/" . JTL_VERSION . '.' . JTL_MINOR_VERSION); + self::$_mollie->addVersionString("ws_mollie/" . \ws_mollie\Helper::oPlugin()->nVersion); + } + return self::$_mollie; + } + /** * @param Bestellung $order * @param $hash @@ -113,7 +173,7 @@ protected function getOrderData(Bestellung $order, $hash) { $locale = self::getLocale($_SESSION['cISOSprache'], $_SESSION['Kunde']->cLand); $data = [ - 'locale' => $locale ? : 'de_DE', + 'locale' => $locale ?: 'de_DE', 'amount' => (object)[ 'currency' => $order->Waehrung->cISO, 'value' => number_format($order->fGesamtsummeKundenwaehrung, 2, '.', ''), @@ -157,19 +217,19 @@ protected function getOrderData(Bestellung $order, $hash) $line->name = utf8_encode($oPosition->cName); $line->quantity = $oPosition->nAnzahl; $line->unitPrice = (object)[ - 'value' => number_format($order->Waehrung->fFaktor * ($oPosition->fPreis * ((float)$oPosition->fMwSt / 100 + 1)), 2, '.', ''), - 'currency' => $order->Waehrung->cISO, - ]; + 'value' => number_format($order->Waehrung->fFaktor * ($oPosition->fPreis * ((float)$oPosition->fMwSt / 100 + 1)), 2, '.', ''), + 'currency' => $order->Waehrung->cISO, + ]; $line->totalAmount = (object)[ - 'value' => number_format($oPosition->nAnzahl * (float)$line->unitPrice->value, 2, '.', ''), - 'currency' => $order->Waehrung->cISO, - ]; + 'value' => number_format($oPosition->nAnzahl * (float)$line->unitPrice->value, 2, '.', ''), + 'currency' => $order->Waehrung->cISO, + ]; $line->vatRate = $oPosition->fMwSt; $line->vatAmount = (object)[ 'value' => number_format($line->totalAmount->value - ($line->totalAmount->value / (1 + (float)$oPosition->fMwSt / 100)), 2, '.', ''), 'currency' => $order->Waehrung->cISO, ]; - + switch ((int)$oPosition->nPosTyp) { case (int)C_WARENKORBPOS_TYP_GRATISGESCHENK: case (int)C_WARENKORBPOS_TYP_ARTIKEL: @@ -258,61 +318,54 @@ protected function getOrderData(Bestellung $order, $hash) return $data; } - /** - * Prepares everything so that the Customer can start the Payment Process. - * Tells Template Engine. - * - * @param Bestellung $order - */ - public function preparePaymentProcess($order) + public static function getLocale($cISOSprache, $country = null) { - $logData = '#' . $order->kBestellung . "" . $order->cBestellNr; - try { - $payment = \ws_mollie\Model\Payment::getPayment($order->kBestellung); - if ($payment && in_array($payment->cStatus, [\Mollie\Api\Types\OrderStatus::STATUS_CREATED]) && $payment->cCheckoutURL) { - $logData .= '$' . $payment->kID; - if (!$this->duringCheckout) { - Session::getInstance()->cleanUp(); + switch ($cISOSprache) { + case "ger": + if ($country === "AT") { + return "de_AT"; } - header('Location: ' . $payment->cCheckoutURL); - exit(); - } - } catch (\Exception $e) { - $this->doLog("Get Payment Error: " . $e->getMessage() . ". Create new ORDER...", $logData); - } - - try { - $hash = $this->generateHash($order); - $oMolliePayment = self::API()->orders->create($this->getOrderData($order, $hash)); - $_SESSION['oMolliePayment'] = $oMolliePayment; - $logData .= '$' . $oMolliePayment->id; - $this->doLog('Mollie Create Payment Redirect: ' . $oMolliePayment->getCheckoutUrl() . "
" . print_r($oMolliePayment, 1) . "
", $logData, LOGLEVEL_DEBUG); - \ws_mollie\Model\Payment::updateFromPayment($oMolliePayment, $order->kBestellung, md5($hash)); - Shop::Smarty()->assign('oMolliePayment', $oMolliePayment); - if (!$this->duringCheckout) { - Session::getInstance()->cleanUp(); - } - header('Location: ' . $oMolliePayment->getCheckoutUrl()); - exit(); - } catch (\Mollie\Api\Exceptions\ApiException $e) { - Shop::Smarty()->assign('oMollieException', $e); - $this->doLog("Create Payment Error: " . $e->getMessage() . '
' . print_r($e->getTrace(), 1) . '
', $logData); + if ($country === "CH") { + return "de_CH"; + } + return "de_DE"; + case "eng": + return "en_US"; + 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"; } } - /** - * @param string $msg - * @param null $data - * @param int $level - * @return $this - */ - public function doLog($msg, $data = null, $level = LOGLEVEL_NOTICE) - { - ZahlungsLog::add($this->moduleID, $msg, $data, $level); - - return $this; - } - /** * @param Bestellung $order * @param string $hash @@ -332,7 +385,6 @@ public function handleNotification($order, $hash, $args) } } - /** * @param Bestellung $order * @param string $hash @@ -364,60 +416,33 @@ public function canPayAgain() return true; } - - public static function getLocale($cISOSprache, $country = null) + /** + * determines, if the payment method can be selected in the checkout process + * + * @return bool + */ + public function isSelectable() { - switch ($cISOSprache) { - case "ger": - if ($country === "AT") { - return "de_AT"; - } - if ($country === "CH") { - return "de_CH"; - } - return "de_DE"; - case "eng": - return "en_US"; - case "fre": - if ($country === "BE") { - return "fr_BE"; - } - return "fr_FR"; - case "dut": - if ($country === "BE") { - return "nl_BE"; + $locale = self::getLocale($_SESSION['cISOSprache'], $_SESSION['Kunde']->cLand); + if (static::MOLLIE_METHOD !== '') { + try { + /** @var Warenkorb $wk */ + $wk = $_SESSION['Warenkorb']; + $method = self::PossiblePaymentMethods(static::MOLLIE_METHOD, $locale, $_SESSION['Kunde']->cLand, $_SESSION['Waehrung']->cISO, $wk->gibGesamtsummeWaren() * $_SESSION['Waehrung']->fFaktor); + if ($method !== null) { + $this->updatePaymentMethod($_SESSION['cISOSprache'], $method); + $this->cBild = $method->image->size2x; + return true; } - 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"; + return false; + } catch (Exception $e) { + $this->doLog('Method ' . static::MOLLIE_METHOD . ' not selectable:' . $e->getMessage()); + return false; + } } + return true; } - /** - * @var array - */ - protected static $_possiblePaymentMethods = []; - /** * @param $method * @param $locale @@ -471,33 +496,6 @@ protected function updatePaymentMethod($cISOSprache, $method) } } - /** - * determines, if the payment method can be selected in the checkout process - * - * @return bool - */ - public function isSelectable() - { - $locale = self::getLocale($_SESSION['cISOSprache'], $_SESSION['Kunde']->cLand); - if (static::MOLLIE_METHOD !== '') { - try { - /** @var Warenkorb $wk */ - $wk = $_SESSION['Warenkorb']; - $method = self::PossiblePaymentMethods(static::MOLLIE_METHOD, $locale, $_SESSION['Kunde']->cLand, $_SESSION['Waehrung']->cISO, $wk->gibGesamtsummeWaren() * $_SESSION['Waehrung']->fFaktor); - if ($method !== null) { - $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; - } - } - return true; - } - /** * * @param object $customer From b0b40d0247b42e038c50e0f791f49af804adac47 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Tue, 26 Feb 2019 12:50:33 +0100 Subject: [PATCH 039/280] fix #23 --- composer.lock | 11 ----------- version/101/adminmenu/paymentmethods.php | 13 ++++++++----- version/101/adminmenu/tpl/paymentmethods.tpl | 16 ++++++++-------- 3 files changed, 16 insertions(+), 24 deletions(-) diff --git a/composer.lock b/composer.lock index a84663a..756d525 100644 --- a/composer.lock +++ b/composer.lock @@ -423,17 +423,6 @@ { "name": "roave/security-advisories", "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/Roave/SecurityAdvisories.git", - "reference": "614a9db1df6be4349544311096f8d48ca067ccbb" - }, - "dist": { - "type": "zip", - "url": "https://github.com/gitapi/repos/Roave/SecurityAdvisories/zipball/614a9db1df6be4349544311096f8d48ca067ccbb", - "reference": "614a9db1df6be4349544311096f8d48ca067ccbb", - "shasum": "" - }, "conflict": { "3f/pygmentize": "<1.2", "adodb/adodb-php": "<5.20.12", diff --git a/version/101/adminmenu/paymentmethods.php b/version/101/adminmenu/paymentmethods.php index ac1ec56..8a234f5 100644 --- a/version/101/adminmenu/paymentmethods.php +++ b/version/101/adminmenu/paymentmethods.php @@ -14,13 +14,16 @@ $mollie->setApiKey(\ws_mollie\Helper::getSetting("api_key")); $profile = $mollie->profiles->get('me'); - $methods = $mollie->methods->all([ - 'locale' => 'de_DE', +/* $methods = $mollie->methods->all([ + //'locale' => 'de_DE', 'include' => 'pricing', - ]); + ]);*/ + + $allMethods = $mollie->performHttpCall('GET', 'methods/all?locale=de_DE&include=pricing'); - Shop::Smarty()->assign('methods', $methods) - ->assign('profile', $profile); + Shop::Smarty()->assign('profile', $profile) + //->assign('methods', $methods) + ->assign('allMethods', $allMethods); Shop::Smarty()->display($oPlugin->cAdminmenuPfad . '/tpl/paymentmethods.tpl'); } catch (Exception $e) { echo "
{$e->getMessage()}
"; diff --git a/version/101/adminmenu/tpl/paymentmethods.tpl b/version/101/adminmenu/tpl/paymentmethods.tpl index cf3770e..87fb5c0 100644 --- a/version/101/adminmenu/tpl/paymentmethods.tpl +++ b/version/101/adminmenu/tpl/paymentmethods.tpl @@ -12,7 +12,7 @@
-{if $methods && $methods|count} +{if $allMethods && $allMethods|count} @@ -23,13 +23,13 @@ - {foreach from=$methods item=method} - - + - - - + + - + {/foreach}
{$method->description|utf8_decode}_embedded->methods item=method} +
{$method->description|utf8_decode}{$method->id}{$method->description|utf8_decode} + {$method->id}{$method->description|utf8_decode}
    {foreach from=$method->pricing item=price}
  • {$price->description|utf8_decode}: {$price->fixed->value} {$price->fixed->currency} @@ -40,7 +40,7 @@ {/foreach}
From 93d4164d589186bcdb64d7734744eb948affd463 Mon Sep 17 00:00:00 2001 From: "dash.bar" Date: Tue, 26 Feb 2019 12:51:57 +0100 Subject: [PATCH 040/280] update base files --- version/101/adminmenu/info.php | 3 ++- version/101/class/Helper.php | 18 +++++++++++++----- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/version/101/adminmenu/info.php b/version/101/adminmenu/info.php index 74e4100..6876c3c 100644 --- a/version/101/adminmenu/info.php +++ b/version/101/adminmenu/info.php @@ -47,6 +47,7 @@ if ((int)\ws_mollie\Helper::oPlugin()->nVersion < (int)$latestRelease->version) { Shop::Smarty()->assign('update', $latestRelease); } + } catch (\Exception $e) { } @@ -54,4 +55,4 @@ } catch (Exception $e) { echo "
Fehler: {$e->getMessage()}
"; \ws_mollie\Helper::logExc($e); -} +} \ No newline at end of file diff --git a/version/101/class/Helper.php b/version/101/class/Helper.php index d7a916f..1c8a57a 100644 --- a/version/101/class/Helper.php +++ b/version/101/class/Helper.php @@ -72,7 +72,8 @@ public static function autoload() */ public static function selfupdate() { - if (function_exists('opcache_reset')) { + + if(function_exists('opcache_reset')){ opcache_reset(); } @@ -184,6 +185,7 @@ public static function init() ini_set('xdebug.default_enable', defined('WS_XDEBUG_ENABLED')); self::autoload(); if (null === self::$_licence) { + if (array_key_exists('_licActivate', $_REQUEST) && $_REQUEST['_licActivate'] === __NAMESPACE__) { self::_licActivate(self::_licCache()); } @@ -250,7 +252,7 @@ public static function setSetting($name, $value) $setting->cName = $name; $setting->cWert = $value; - if (array_key_exists($name, self::oPlugin()->oPluginEinstellungAssoc_arr)) { + 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); @@ -270,7 +272,7 @@ public static function oPlugin($force = false) { if ($force === true) { self::$oPlugin = new \Plugin(self::oPlugin(false)->kPlugin, true); - } elseif (null === self::$oPlugin) { + } else if (null === self::$oPlugin) { self::$oPlugin = \Plugin::getPluginById(__NAMESPACE__); } return self::$oPlugin; @@ -292,6 +294,7 @@ private static function _licValid($oL) } } return false; + } /** @@ -347,6 +350,7 @@ private static function licCheck($x) } } return false; + } /** @@ -369,6 +373,7 @@ private static function _licCRC($oL) private static function _licLive($oL) { try { + if (!function_exists('curl_init')) { throw new \Exception(__NAMESPACE__ . ': cURL needs to be installed!'); } @@ -405,6 +410,7 @@ private static function _licLive($oL) } /** @noinspection UnserializeExploitsInspection */ if ($response = json_decode($data)) { + $checksum = md5(base64_encode($response->data->validUntil . $response->data->nextCheck . ($response->data->testLicence ? 'Y' : 'N'))); if (!$response || !isset($response->data) || $response->data === false || !isset($response->checksum) || $response->checksum !== $checksum) { @@ -422,14 +428,15 @@ private static function _licLive($oL) } $oL->fails = 0; self::_licSave($oL, true); + } else { throw new \Exception(__NAMESPACE__ . ': Could not decode licence info: ' . print_r($response, 1)); } + } catch (\Exception $e) { $oL->disabled = (++$oL->fails) >= 3 ? 1 : 0; $oL->nextCheck = date("Y-m-d", strtotime("+1 DAY")); - $oL->validUntil = date("Y-m-d", strtotime("+1 DAY")); - ; + $oL->validUntil = date("Y-m-d", strtotime("+1 DAY"));; self::logExc($e, false); self::_licSave($oL, true); @@ -511,6 +518,7 @@ public static function getAdminmenu($name) } return $kPluginAdminMenu; } + } } From 813c4cfe486b7036f9ba87e8abeb4b890994b329 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Tue, 26 Feb 2019 12:55:41 +0100 Subject: [PATCH 041/280] readme cahnges from github --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 56e3862..6de7e2b 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@

- +

Mollie for JTL-Shop

@@ -22,8 +22,8 @@ If you have no experience with this, then leave the installation of this module 1. Download the latest version of the module (the '.zip' file) via the [Releases page](https://github.com/mollie/mollie-JTL/releases) 2. Go to the administration panel of your JTL-Shop 3. In your administration panel, select the *'Plugins'* menu and then choose *'Pluginverwaltung'* -4. Click the *'Upload'* tab, select *'Auswählen'* and then upload the '.zip' file which you downloaded earlier -5. After the module has been uploaded, go to the *'Verfügbar'* tag, activate the checkbox for 'mollie' and press *'Installieren'* +4. Click the *'Upload'* tab, select *'Auswählen'* and then upload the '.zip' file which you downloaded earlier +5. After the module has been uploaded, go to the *'Verfügbar'* tag, activate the checkbox for 'mollie' and press *'Installieren'* 6. Switching back to the *'Aktiviert'* tab you select the config button ![](https://cdn.webstollen.com/plugin/ws_mollie/cogs.png) 7. Enter your API Key in the Form on the *'Einstellungen'* tab and save the data. @@ -90,8 +90,8 @@ for more than 40,000 websites. Because payments are guaranteed, this payment method is a huge surplus for your online store. -### ING Home’Pay -[ING Home’Pay](https://www.mollie.com/en/payments/ing-homepay). Mollie allows you to quickly and easily accept payments with ING Home'Pay. +### ING Home?Pay +[ING Home?Pay](https://www.mollie.com/en/payments/ing-homepay). Mollie allows you to quickly and easily accept payments with ING Home'Pay. It only takes 10 minutes to start receiving payments and there are no hidden fees involved, you only pay for successful transactions. @@ -126,7 +126,7 @@ There is no need to set a redirect URL or webhook. The module automatically does **Can I only accept Orders where the Payment is made already?** * You can configure each Payment method to "save orders after payment" -* In your administration panel go to *"Storefront > Zahlungsarten > Ãœbersicht"*. Choose the desired payment method +* In your administration panel go to *"Storefront > Zahlungsarten > Übersicht"*. Choose the desired payment method * Set *'Zahlung vor Bestellabschluss'* to *'Ja'* # Support # From 453007e1fd7daec0e0c2b49bf4ec5bcd72213c8e Mon Sep 17 00:00:00 2001 From: "dash.bar" Date: Tue, 26 Feb 2019 12:58:40 +0100 Subject: [PATCH 042/280] prepare finalize --- info.xml | 20 ++++++++++---------- version/101/adminmenu/info.php | 3 +-- version/101/adminmenu/paymentmethods.php | 8 ++++---- version/101/class/Helper.php | 16 ++++------------ version/101/class/Mollie.php | 1 - 5 files changed, 19 insertions(+), 29 deletions(-) diff --git a/info.xml b/info.xml index 3e0fa56..5e12a03 100644 --- a/info.xml +++ b/info.xml @@ -1,7 +1,7 @@ mollie - Zahlungsartplugin für mollie.com + Zahlungsartplugin für mollie.com WebStollen http://www.webstollen.de/ 102 @@ -13,7 +13,7 @@ 2019-02-11 - 2019-02-11 + 2019-02-26 131_globalinclude.php @@ -38,23 +38,23 @@ Einstellungen API Key: - Füge hier deinen mollie API Key ein + Füge hier deinen mollie API Key ein api_key Zahlungsart Daten syncronisiernen - Lädt Name / Bild für die jeweilige Sprache automatisch von mollie, und speichert diese in der Datenbank + Lädt Name / Bild für die jeweilige Sprache automatisch von mollie, und speichert diese in der Datenbank paymentmethod_sync - - + + Checkout Styles laden - Lädt Stylesheets für das Evo Template, um den Checkout zu verschönern. + Lädt Stylesheets für das Evo Template, um den Checkout zu verschönern. load_styles @@ -160,9 +160,9 @@ JTLMollieBanktransfer tpl/bestellabschluss.tpl - SEPA Ãœberweisung + SEPA Ãœberweisung mollie - Bezahlen Sie bequem mit SEPA Ãœberweisung. + Bezahlen Sie bequem mit SEPA Ãœberweisung. @@ -180,7 +180,7 @@ JTLMollieBelfius tpl/bestellabschluss.tpl - SEPA Ãœberweisung + SEPA Ãœberweisung mollie Bezahlen Sie bequem mit Belfius. diff --git a/version/101/adminmenu/info.php b/version/101/adminmenu/info.php index 6876c3c..74e4100 100644 --- a/version/101/adminmenu/info.php +++ b/version/101/adminmenu/info.php @@ -47,7 +47,6 @@ if ((int)\ws_mollie\Helper::oPlugin()->nVersion < (int)$latestRelease->version) { Shop::Smarty()->assign('update', $latestRelease); } - } catch (\Exception $e) { } @@ -55,4 +54,4 @@ } catch (Exception $e) { echo "
Fehler: {$e->getMessage()}
"; \ws_mollie\Helper::logExc($e); -} \ No newline at end of file +} diff --git a/version/101/adminmenu/paymentmethods.php b/version/101/adminmenu/paymentmethods.php index 8a234f5..31c77e7 100644 --- a/version/101/adminmenu/paymentmethods.php +++ b/version/101/adminmenu/paymentmethods.php @@ -14,10 +14,10 @@ $mollie->setApiKey(\ws_mollie\Helper::getSetting("api_key")); $profile = $mollie->profiles->get('me'); -/* $methods = $mollie->methods->all([ - //'locale' => 'de_DE', - 'include' => 'pricing', - ]);*/ + /* $methods = $mollie->methods->all([ + //'locale' => 'de_DE', + 'include' => 'pricing', + ]);*/ $allMethods = $mollie->performHttpCall('GET', 'methods/all?locale=de_DE&include=pricing'); diff --git a/version/101/class/Helper.php b/version/101/class/Helper.php index 1c8a57a..cc13a31 100644 --- a/version/101/class/Helper.php +++ b/version/101/class/Helper.php @@ -72,8 +72,7 @@ public static function autoload() */ public static function selfupdate() { - - if(function_exists('opcache_reset')){ + if (function_exists('opcache_reset')) { opcache_reset(); } @@ -185,7 +184,6 @@ public static function init() ini_set('xdebug.default_enable', defined('WS_XDEBUG_ENABLED')); self::autoload(); if (null === self::$_licence) { - if (array_key_exists('_licActivate', $_REQUEST) && $_REQUEST['_licActivate'] === __NAMESPACE__) { self::_licActivate(self::_licCache()); } @@ -272,7 +270,7 @@ public static function oPlugin($force = false) { if ($force === true) { self::$oPlugin = new \Plugin(self::oPlugin(false)->kPlugin, true); - } else if (null === self::$oPlugin) { + } elseif (null === self::$oPlugin) { self::$oPlugin = \Plugin::getPluginById(__NAMESPACE__); } return self::$oPlugin; @@ -294,7 +292,6 @@ private static function _licValid($oL) } } return false; - } /** @@ -350,7 +347,6 @@ private static function licCheck($x) } } return false; - } /** @@ -373,7 +369,6 @@ private static function _licCRC($oL) private static function _licLive($oL) { try { - if (!function_exists('curl_init')) { throw new \Exception(__NAMESPACE__ . ': cURL needs to be installed!'); } @@ -410,7 +405,6 @@ private static function _licLive($oL) } /** @noinspection UnserializeExploitsInspection */ if ($response = json_decode($data)) { - $checksum = md5(base64_encode($response->data->validUntil . $response->data->nextCheck . ($response->data->testLicence ? 'Y' : 'N'))); if (!$response || !isset($response->data) || $response->data === false || !isset($response->checksum) || $response->checksum !== $checksum) { @@ -428,15 +422,14 @@ private static function _licLive($oL) } $oL->fails = 0; self::_licSave($oL, true); - } else { throw new \Exception(__NAMESPACE__ . ': Could not decode licence info: ' . print_r($response, 1)); } - } catch (\Exception $e) { $oL->disabled = (++$oL->fails) >= 3 ? 1 : 0; $oL->nextCheck = date("Y-m-d", strtotime("+1 DAY")); - $oL->validUntil = date("Y-m-d", strtotime("+1 DAY"));; + $oL->validUntil = date("Y-m-d", strtotime("+1 DAY")); + ; self::logExc($e, false); self::_licSave($oL, true); @@ -518,7 +511,6 @@ public static function getAdminmenu($name) } return $kPluginAdminMenu; } - } } diff --git a/version/101/class/Mollie.php b/version/101/class/Mollie.php index bb41923..82893b6 100644 --- a/version/101/class/Mollie.php +++ b/version/101/class/Mollie.php @@ -14,7 +14,6 @@ abstract class Mollie { - protected static $_jtlmollie; /** From a8ec5506c4376db339fd8f7311493cdb0aa57fc7 Mon Sep 17 00:00:00 2001 From: "dash.bar" Date: Tue, 26 Feb 2019 13:56:42 +0100 Subject: [PATCH 043/280] update base files --- version/101/adminmenu/info.php | 9 +- version/101/class/Helper.php | 237 +-------------------------------- 2 files changed, 9 insertions(+), 237 deletions(-) diff --git a/version/101/adminmenu/info.php b/version/101/adminmenu/info.php index 74e4100..4a3f09a 100644 --- a/version/101/adminmenu/info.php +++ b/version/101/adminmenu/info.php @@ -36,17 +36,12 @@ ' ' . ''; - if (\ws_mollie\Helper::_licCache()->disabled) { - echo "
Die Pluginlizenz und das Plugin wurden deaktiviert. " - . "" - . "Klicke hier um die Lizenz erneut zu überprüfen.
"; - } - try { $latestRelease = \ws_mollie\Helper::getLatestRelease(array_key_exists('update', $_REQUEST)); if ((int)\ws_mollie\Helper::oPlugin()->nVersion < (int)$latestRelease->version) { Shop::Smarty()->assign('update', $latestRelease); } + } catch (\Exception $e) { } @@ -54,4 +49,4 @@ } catch (Exception $e) { echo "
Fehler: {$e->getMessage()}
"; \ws_mollie\Helper::logExc($e); -} +} \ No newline at end of file diff --git a/version/101/class/Helper.php b/version/101/class/Helper.php index cc13a31..7035a09 100644 --- a/version/101/class/Helper.php +++ b/version/101/class/Helper.php @@ -19,18 +19,6 @@ final class Helper */ private static $_autoload; - /** - * Is Licence valid? - * - * @var bool|null - */ - private static $_licence; - - /** - * @var string - */ - private static $_tmpLicence; - /** * @var \Plugin */ @@ -72,7 +60,8 @@ public static function autoload() */ public static function selfupdate() { - if (function_exists('opcache_reset')) { + + if(function_exists('opcache_reset')){ opcache_reset(); } @@ -182,58 +171,7 @@ public static function getLatestRelease($force = false) public static function init() { ini_set('xdebug.default_enable', defined('WS_XDEBUG_ENABLED')); - self::autoload(); - if (null === self::$_licence) { - if (array_key_exists('_licActivate', $_REQUEST) && $_REQUEST['_licActivate'] === __NAMESPACE__) { - self::_licActivate(self::_licCache()); - } - - self::$_licence = false; - self::$_tmpLicence = md5(time()); - if ($_SERVER['HTTP_HOST'] === 'localhost') { - self::$_licence = true; - } else { - self::$_licence = self::licCheck(md5(self::$_tmpLicence)) === md5(self::$_tmpLicence); - } - } - - if (!self::$_licence && self::isAdminBackend()) { - \Shop::Smarty()->assign('defaultTabbertab', self::getAdminmenu('Info')); - } - - - return self::$_autoload && self::$_licence; - } - - /** - * @param $oL - * @return mixed - */ - private static function _licActivate($oL) - { - $oL->nextCheck = 0; - $oL->fails = 0; - $oL->disabled = 0; - self::_licSave($oL); - return $oL; - } - - /** - * @param $oL - * @param bool $checksum - * @return mixed - */ - private static function _licSave($oL, $checksum = false) - { - self::setSetting('lic_validUntil', $oL->validUntil); - self::setSetting('lic_nextCheck', $oL->nextCheck); - self::setSetting('lic_test', $oL->test); - if ($checksum === true) { - self::setSetting('lic_checkSum', base64_encode(sha1($oL->validUntil . $oL->nextCheck . $oL->test . $oL->disabled . $oL->fails . __NAMESPACE__, true))); - } - self::setSetting('lic_disabled', (int)$oL->disabled); - self::setSetting('lic_fails', $oL->fails); - return $oL; + return self::autoload(); } /** @@ -250,7 +188,7 @@ public static function setSetting($name, $value) $setting->cName = $name; $setting->cWert = $value; - if (array_key_exists($name, self::oPlugin()->oPluginEinstellungAssoc_arr?:[])) { + 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); @@ -270,45 +208,12 @@ public static function oPlugin($force = false) { if ($force === true) { self::$oPlugin = new \Plugin(self::oPlugin(false)->kPlugin, true); - } elseif (null === self::$oPlugin) { + } else if (null === self::$oPlugin) { self::$oPlugin = \Plugin::getPluginById(__NAMESPACE__); } return self::$oPlugin; } - /** - * @param $oL - * @return bool|string - */ - private static function _licValid($oL) - { - if ($nextCheck = strtotime($oL->nextCheck)) { - if ($nextCheck > time()) { - if ($validUntil = strtotime($oL->validUntil)) { - if ($validUntil > time() || (int)$oL->test === 0) { - return md5(self::$_tmpLicence); - } - } - } - } - return false; - } - - /** - * @return \stdClass - */ - public static function _licCache() - { - $oL = new \stdClass(); - $oL->validUntil = self::getSetting('lic_validUntil'); - $oL->nextCheck = self::getSetting('lic_nextCheck'); - $oL->test = self::getSetting('lic_test'); - $oL->checksum = self::getSetting('lic_checkSum'); - $oL->disabled = self::getSetting('lic_disabled') === null ? 0 : (int)self::getSetting('lic_disabled'); - $oL->fails = self::getSetting('lic_fails') ?: 0; - return $oL; - } - /** * get a Plugin setting * @@ -317,141 +222,12 @@ public static function _licCache() */ public static function getSetting($name) { - if (array_key_exists($name, self::oPlugin()->oPluginEinstellungAssoc_arr)) { + if (array_key_exists($name, self::oPlugin()->oPluginEinstellungAssoc_arr?:[])) { return self::oPlugin()->oPluginEinstellungAssoc_arr[$name]; } return null; } - /** - * @param $x - * @return bool|string - */ - private static function licCheck($x) - { - if ($x !== md5(self::$_tmpLicence)) { - return false; - } - $oL = self::_licCache(); - if (self::_licCRC($oL) === true) { - // CRC OK? - if (self::_licValid($oL) === md5(self::$_tmpLicence)) { - return md5(self::$_tmpLicence); - } - } - if ($oL->disabled === 0) { - $oL = self::_licLive($oL); - - if ($oL->disabled === 0 && self::_licValid($oL) === md5(self::$_tmpLicence)) { - return md5(self::$_tmpLicence); - } - } - return false; - } - - /** - * @param $oL - * @return bool - */ - private static function _licCRC($oL) - { - $crc_valid = false; - if ($checksum = base64_encode(sha1($oL->validUntil . $oL->nextCheck . $oL->test . $oL->disabled . $oL->fails . __NAMESPACE__, true))) { - $crc_valid = $checksum == $oL->checksum; - } - return $oL->checksum && $crc_valid; - } - - /** - * @param $oL - * @return mixed - */ - private static function _licLive($oL) - { - try { - if (!function_exists('curl_init')) { - throw new \Exception(__NAMESPACE__ . ': cURL needs to be installed!'); - } - - $urlShop = self::getDomain(); - - $params = [ - 'domain' => $urlShop, - 'plugin_version' => (int)self::oPlugin()->nVersion, - 'plugin_id' => self::oPlugin()->cPluginID, - 'email' => self::_masterMail(), - 'shop_version' => (string)(defined('APPLICATION_VERSION') ? APPLICATION_VERSION : JTL_VERSION), - 'shop_build' => defined('APPLICATION_BUILD_SHA') ? APPLICATION_BUILD_SHA : '', - 'php_version' => PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION . '.' . PHP_RELEASE_VERSION, - 'php_extra_version' => PHP_EXTRA_VERSION, - 'php_os' => PHP_OS, - 'server' => array_key_exists('SERVER_SOFTWARE', $_SERVER) ? $_SERVER['SERVER_SOFTWARE'] : '', - ]; - $curl = curl_init('https://lic.dash.bar'); - @curl_setopt($curl, CURLOPT_POST, 1); - @curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($params)); // http_build_query($params, '', '&')); - @curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 3); - @curl_setopt($curl, CURLOPT_TIMEOUT, 3); - @curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); - @curl_setopt($curl, CURLOPT_HEADER, 0); - @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 licence info: ' . $statusCode); - } - /** @noinspection UnserializeExploitsInspection */ - if ($response = json_decode($data)) { - $checksum = md5(base64_encode($response->data->validUntil . $response->data->nextCheck . ($response->data->testLicence ? 'Y' : 'N'))); - - if (!$response || !isset($response->data) || $response->data === false || !isset($response->checksum) || $response->checksum !== $checksum) { - throw new \Exception(__NAMESPACE__ . ': Invalid licence info: ' . print_r($response, 1)); - } - $oLL = $response->data; - if (self::isPresent($oLL->validUntil)) { - $oL->validUntil = date('Y-m-d', $oLL->validUntil); - } - if (self::isPresent($oLL->nextCheck)) { - $oL->nextCheck = date('Y-m-d', $oLL->nextCheck); - } - if (self::isPresent($oLL->testLicence)) { - $oL->test = $oLL->testLicence ? 1 : 0; - } - $oL->fails = 0; - self::_licSave($oL, true); - } else { - throw new \Exception(__NAMESPACE__ . ': Could not decode licence info: ' . print_r($response, 1)); - } - } catch (\Exception $e) { - $oL->disabled = (++$oL->fails) >= 3 ? 1 : 0; - $oL->nextCheck = date("Y-m-d", strtotime("+1 DAY")); - $oL->validUntil = date("Y-m-d", strtotime("+1 DAY")); - ; - - self::logExc($e, false); - self::_licSave($oL, true); - } - return $oL; - } - - - /** - * @param $val - * @return bool - * @throws \Exception - */ - private static function ispresent($val) - { - if (isset($val)) { - return true; - } else { - throw new \Exception(__NAMESPACE__ . ': Could ned find value from license server ' . print_r($val, 1)); - } - } - /** * Get Domain frpm URL_SHOP without www. * @@ -511,6 +287,7 @@ public static function getAdminmenu($name) } return $kPluginAdminMenu; } + } } From 967765b33f99ce6253a309d0f4f0eaa9d46cb4bb Mon Sep 17 00:00:00 2001 From: "dash.bar" Date: Tue, 26 Feb 2019 13:58:54 +0100 Subject: [PATCH 044/280] prepare finalize --- info.xml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/info.xml b/info.xml index 5e12a03..16e3af7 100644 --- a/info.xml +++ b/info.xml @@ -1,7 +1,7 @@ mollie - Zahlungsartplugin für mollie.com + Zahlungsartplugin für mollie.com WebStollen http://www.webstollen.de/ 102 @@ -38,23 +38,23 @@ Einstellungen API Key: - Füge hier deinen mollie API Key ein + Füge hier deinen mollie API Key ein api_key Zahlungsart Daten syncronisiernen - Lädt Name / Bild für die jeweilige Sprache automatisch von mollie, und speichert diese in der Datenbank + Lädt Name / Bild für die jeweilige Sprache automatisch von mollie, und speichert diese in der Datenbank paymentmethod_sync - - + + Checkout Styles laden - Lädt Stylesheets für das Evo Template, um den Checkout zu verschönern. + Lädt Stylesheets für das Evo Template, um den Checkout zu verschönern. load_styles @@ -160,9 +160,9 @@ JTLMollieBanktransfer tpl/bestellabschluss.tpl - SEPA Überweisung + SEPA Ãœberweisung mollie - Bezahlen Sie bequem mit SEPA Überweisung. + Bezahlen Sie bequem mit SEPA Ãœberweisung.
@@ -180,7 +180,7 @@ JTLMollieBelfius tpl/bestellabschluss.tpl - SEPA Überweisung + SEPA Ãœberweisung mollie Bezahlen Sie bequem mit Belfius. From 86e4c8737af5c408212f4d4e920208a906ca0e92 Mon Sep 17 00:00:00 2001 From: "dash.bar" Date: Tue, 26 Feb 2019 13:58:54 +0100 Subject: [PATCH 045/280] init version 102 --- info.xml | 3 + version/102/adminmenu/info.php | 52 ++ version/102/adminmenu/orders.php | 149 +++++ version/102/adminmenu/paymentmethods.php | 31 ++ version/102/adminmenu/tpl/info.tpl | 41 ++ .../tpl/mollie-account-erstellen.png | Bin 0 -> 38998 bytes version/102/adminmenu/tpl/order.tpl | 217 ++++++++ version/102/adminmenu/tpl/orders.tpl | 106 ++++ version/102/adminmenu/tpl/paymentmethods.tpl | 49 ++ version/102/class/Helper.php | 294 ++++++++++ version/102/class/Model/AbstractModel.php | 7 + version/102/class/Model/Payment.php | 73 +++ version/102/class/Mollie.php | 198 +++++++ version/102/frontend/131_globalinclude.php | 67 +++ version/102/frontend/140_smarty.php | 53 ++ version/102/frontend/144_notify.php | 27 + version/102/frontend/181_sync.php | 33 ++ version/102/paymentmethod/JTLMollie.php | 526 ++++++++++++++++++ .../102/paymentmethod/JTLMollieBancontact.php | 8 + .../paymentmethod/JTLMollieBanktransfer.php | 8 + .../102/paymentmethod/JTLMollieBelfius.php | 8 + .../102/paymentmethod/JTLMollieBitcoin.php | 8 + .../102/paymentmethod/JTLMollieCreditCard.php | 8 + .../paymentmethod/JTLMollieDirectDebit.php | 8 + version/102/paymentmethod/JTLMollieEPS.php | 8 + .../102/paymentmethod/JTLMollieGiftcard.php | 8 + .../102/paymentmethod/JTLMollieGiropay.php | 8 + version/102/paymentmethod/JTLMollieIDEAL.php | 8 + .../102/paymentmethod/JTLMollieINGHomePay.php | 8 + version/102/paymentmethod/JTLMollieKBC.php | 8 + .../paymentmethod/JTLMollieKlarnaPayLater.php | 8 + .../paymentmethod/JTLMollieKlarnaSliceIt.php | 8 + version/102/paymentmethod/JTLMolliePayPal.php | 8 + .../paymentmethod/JTLMolliePaysafecard.php | 8 + version/102/paymentmethod/JTLMollieSofort.php | 8 + .../paymentmethod/tpl/bestellabschluss.tpl | 5 + version/102/sql/100.sql | 22 + 37 files changed, 2089 insertions(+) create mode 100644 version/102/adminmenu/info.php create mode 100644 version/102/adminmenu/orders.php create mode 100644 version/102/adminmenu/paymentmethods.php create mode 100644 version/102/adminmenu/tpl/info.tpl create mode 100644 version/102/adminmenu/tpl/mollie-account-erstellen.png create mode 100644 version/102/adminmenu/tpl/order.tpl create mode 100644 version/102/adminmenu/tpl/orders.tpl create mode 100644 version/102/adminmenu/tpl/paymentmethods.tpl create mode 100644 version/102/class/Helper.php create mode 100644 version/102/class/Model/AbstractModel.php create mode 100644 version/102/class/Model/Payment.php create mode 100644 version/102/class/Mollie.php create mode 100644 version/102/frontend/131_globalinclude.php create mode 100644 version/102/frontend/140_smarty.php create mode 100644 version/102/frontend/144_notify.php create mode 100644 version/102/frontend/181_sync.php create mode 100644 version/102/paymentmethod/JTLMollie.php create mode 100644 version/102/paymentmethod/JTLMollieBancontact.php create mode 100644 version/102/paymentmethod/JTLMollieBanktransfer.php create mode 100644 version/102/paymentmethod/JTLMollieBelfius.php create mode 100644 version/102/paymentmethod/JTLMollieBitcoin.php create mode 100644 version/102/paymentmethod/JTLMollieCreditCard.php create mode 100644 version/102/paymentmethod/JTLMollieDirectDebit.php create mode 100644 version/102/paymentmethod/JTLMollieEPS.php create mode 100644 version/102/paymentmethod/JTLMollieGiftcard.php create mode 100644 version/102/paymentmethod/JTLMollieGiropay.php create mode 100644 version/102/paymentmethod/JTLMollieIDEAL.php create mode 100644 version/102/paymentmethod/JTLMollieINGHomePay.php create mode 100644 version/102/paymentmethod/JTLMollieKBC.php create mode 100644 version/102/paymentmethod/JTLMollieKlarnaPayLater.php create mode 100644 version/102/paymentmethod/JTLMollieKlarnaSliceIt.php create mode 100644 version/102/paymentmethod/JTLMolliePayPal.php create mode 100644 version/102/paymentmethod/JTLMolliePaysafecard.php create mode 100644 version/102/paymentmethod/JTLMollieSofort.php create mode 100644 version/102/paymentmethod/tpl/bestellabschluss.tpl create mode 100644 version/102/sql/100.sql diff --git a/info.xml b/info.xml index 16e3af7..e004d24 100644 --- a/info.xml +++ b/info.xml @@ -15,6 +15,9 @@ 2019-02-26 + + 2019-02-26 + 131_globalinclude.php 144_notify.php diff --git a/version/102/adminmenu/info.php b/version/102/adminmenu/info.php new file mode 100644 index 0000000..4a3f09a --- /dev/null +++ b/version/102/adminmenu/info.php @@ -0,0 +1,52 @@ +assign('defaultTabbertab', \ws_mollie\Helper::getAdminmenu('Info')); + \ws_mollie\Helper::selfupdate(); + } + + $svgQuery = http_build_query([ + 'p' => \ws_mollie\Helper::oPlugin()->cPluginID, + 'v' => \ws_mollie\Helper::oPlugin()->nVersion, + 's' => defined('APPLICATION_VERSION') ? APPLICATION_VERSION : JTL_VERSION, + 'd' => \ws_mollie\Helper::getDomain(), + 'php' => PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION . '.' . PHP_RELEASE_VERSION, + ]); + + echo ""; + echo "
" . + "
" . + " " . + " Lizenz Informationen" . + ' ' . + '
' . + "
" . + " " . + " Update Informationen" . + ' ' . + '
' . + "
" . + " " . + " Plugin informationen" . + ' ' . + '
' . + '
'; + + try { + $latestRelease = \ws_mollie\Helper::getLatestRelease(array_key_exists('update', $_REQUEST)); + if ((int)\ws_mollie\Helper::oPlugin()->nVersion < (int)$latestRelease->version) { + Shop::Smarty()->assign('update', $latestRelease); + } + + } catch (\Exception $e) { + } + + Shop::Smarty()->display(\ws_mollie\Helper::oPlugin()->cAdminmenuPfad . '/tpl/info.tpl'); +} catch (Exception $e) { + echo "
Fehler: {$e->getMessage()}
"; + \ws_mollie\Helper::logExc($e); +} \ No newline at end of file diff --git a/version/102/adminmenu/orders.php b/version/102/adminmenu/orders.php new file mode 100644 index 0000000..6d0a67c --- /dev/null +++ b/version/102/adminmenu/orders.php @@ -0,0 +1,149 @@ + 'danger', 'text' => 'Keine ID angeben!']; + break; + } + $payment = \ws_mollie\Model\Payment::getPaymentMollie($_REQUEST['id']); + if (!$payment) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; + break; + } + + $order = JTLMollie::API()->orders->get($_REQUEST['id']); + if ($order->status == \Mollie\Api\Types\OrderStatus::STATUS_CANCELED) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung bereits storniert']; + break; + } + $refund = JTLMollie::API()->orderRefunds->createFor($order, ['lines' => []]); + \ws_mollie\Mollie::JTLMollie()->doLog("Order refunded:
" . print_r($refund, 1) . "
", '$' . $payment->kID . '#' . $payment->kBestellung . '§' . $payment->cOrderNumber, LOGLEVEL_NOTICE); + + goto order; + break; + + case 'cancel': + if (!array_key_exists('id', $_REQUEST)) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; + break; + } + $payment = \ws_mollie\Model\Payment::getPaymentMollie($_REQUEST['id']); + if (!$payment) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; + break; + } + $order = JTLMollie::API()->orders->get($_REQUEST['id']); + if ($order->status == \Mollie\Api\Types\OrderStatus::STATUS_CANCELED) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung bereits storniert']; + break; + } + $cancel = JTLMollie::API()->orders->cancel($order->id); + \ws_mollie\Mollie::JTLMollie()->doLog("Order canceled:
" . print_r($cancel, 1) . "
", '$' . $payment->kID . '#' . $payment->kBestellung . '§' . $payment->cOrderNumber, LOGLEVEL_NOTICE); + goto order; + break; + + case 'capture': + if (!array_key_exists('id', $_REQUEST)) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; + break; + } + $payment = \ws_mollie\Model\Payment::getPaymentMollie($_REQUEST['id']); + if (!$payment) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; + break; + } + $order = JTLMollie::API()->orders->get($_REQUEST['id']); + if ($order->status !== \Mollie\Api\Types\OrderStatus::STATUS_AUTHORIZED && $order->status !== \Mollie\Api\Types\OrderStatus::STATUS_SHIPPING) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Nur autorisierte Zahlungen können erfasst werden!']; + break; + } + + $oBestellung = new Bestellung($payment->kBestellung, true); + if (!$oBestellung->kBestellung) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung konnte nicht geladen werden!']; + break; + } + + $logData = '#' . $payment->kBestellung . '$' . $payment->kID . "§" . $oBestellung->cBestellNr; + + $options = ['lines' => []]; + if ($oBestellung->cTracking) { + $tracking = new stdClass(); + $tracking->carrier = $oBestellung->cVersandartName; + $tracking->url = $oBestellung->cTrackingURL; + $tracking->code = $oBestellung->cTracking; + $options['tracking'] = $tracking; + } + + // CAPTURE ALL + $shipment = JTLMollie::API()->shipments->createFor($order, $options); + $ordersMsgs[] = (object)['type' => 'success', 'text' => 'Zahlung wurde erfolgreich erfasst!']; + \ws_mollie\Mollie::JTLMollie()->doLog('Shipment created
' . print_r(['options' => $options, 'shipment' => $shipment], 1) . '
', $logData); + goto order; + + case 'order': + order: + if (!array_key_exists('id', $_REQUEST)) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; + break; + } + + $order = JTLMollie::API()->orders->get($_REQUEST['id']); + $payment = \ws_mollie\Model\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", [ + ':kBestellung' => '%#' . ($payment->kBestellung ?: '##') . '%', + ':cBestellNr' => '%§' . ($payment->cOrderNumber ?: '§§') . '%', + ':MollieID' => '%$' . ($payment->kID ?: '$$') . '%', + ], 2); + + Shop::Smarty()->assign('payment', $payment) + ->assign('oBestellung', $oBestellung) + ->assign('order', $order) + ->assign('logs', $logs) + ->assign('ordersMsgs', $ordersMsgs); + Shop::Smarty()->display($oPlugin->cAdminmenuPfad . '/tpl/order.tpl'); + return; + } + } + + + $payments = Shop::DB()->executeQueryPrepared("SELECT * FROM xplugin_ws_mollie_payments WHERE kBestellung IS NOT NULL AND cStatus != 'created'", [], 2); + foreach ($payments as $i => $payment) { + $payments[$i]->oBestellung = new Bestellung($payment->kBestellung, false); + } + + Shop::Smarty()->assign('payments', $payments) + ->assign('ordersMsgs', $ordersMsgs) + ->assign('admRoot', str_replace('http:', '', $oPlugin->cAdminmenuPfadURL)) + ->assign('hasAPIKey', trim(\ws_mollie\Helper::getSetting("api_key")) !== ''); + + Shop::Smarty()->display($oPlugin->cAdminmenuPfad . '/tpl/orders.tpl'); +} catch (Exception $e) { + echo "
" . + "{$e->getMessage()}
" . + "
{$e->getFile()}:{$e->getLine()}
{$e->getTraceAsString()}
" . + "
"; + \ws_mollie\Helper::logExc($e); +} diff --git a/version/102/adminmenu/paymentmethods.php b/version/102/adminmenu/paymentmethods.php new file mode 100644 index 0000000..31c77e7 --- /dev/null +++ b/version/102/adminmenu/paymentmethods.php @@ -0,0 +1,31 @@ +setApiKey(\ws_mollie\Helper::getSetting("api_key")); + + $profile = $mollie->profiles->get('me'); + /* $methods = $mollie->methods->all([ + //'locale' => 'de_DE', + 'include' => 'pricing', + ]);*/ + + $allMethods = $mollie->performHttpCall('GET', 'methods/all?locale=de_DE&include=pricing'); + + Shop::Smarty()->assign('profile', $profile) + //->assign('methods', $methods) + ->assign('allMethods', $allMethods); + Shop::Smarty()->display($oPlugin->cAdminmenuPfad . '/tpl/paymentmethods.tpl'); +} catch (Exception $e) { + echo "
{$e->getMessage()}
"; + \ws_mollie\Helper::logExc($e); +} diff --git a/version/102/adminmenu/tpl/info.tpl b/version/102/adminmenu/tpl/info.tpl new file mode 100644 index 0000000..eb5ae3a --- /dev/null +++ b/version/102/adminmenu/tpl/info.tpl @@ -0,0 +1,41 @@ +
+
+
+ {if isset($update)} + +
+

Update auf Version {$update->version} verfügbar!

+
+
+
+
Version:
+
{$update->version}
+
+
+
Erschienen:
+
{$update->create_date}
+
+
+
Changelog:
+
+ +
+
+ +
+
+ +
+
+ {/if} +
+
\ No newline at end of file diff --git a/version/102/adminmenu/tpl/mollie-account-erstellen.png b/version/102/adminmenu/tpl/mollie-account-erstellen.png new file mode 100644 index 0000000000000000000000000000000000000000..fc1819255ef725fa214cf2bf028cf3428794ecee GIT binary patch literal 38998 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 +

+ « + 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} +

+ +{if count($ordersMsgs)} + {foreach from=$ordersMsgs item=alert} +
{$alert->text}
+ {/foreach} +
+{/if} + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Mollie ID:{$payment->kID}Mode:{$order->mode}Status:{$order->status}
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)}
+ +

Positionen:

+ +
+ {if ($order->status === 'authorized' || $order->status === 'shipping') && $oBestellung->cStatus|intval >= 3} + + Zahlung erfassen1 + + {/if} + {if $order->amount->value > $order->amountRefunded->value && $order->amountCaptured->value > 0} + Rckerstatten2 + + {/if} + {if $order->isCancelable} + Stornieren3 + + {/if} +
+ + + + + + + + + + + + + + + + + + {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} + + + + + + + + + + + + + {/foreach} + + + + + + + + + + +
StatusSKUNameTypAnzahlMwStSteuerNettoBrutto 
+ {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*} +
{$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} + + + + + + + {/foreach} +
+ {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}
+ + diff --git a/version/102/adminmenu/tpl/orders.tpl b/version/102/adminmenu/tpl/orders.tpl new file mode 100644 index 0000000..50d5829 --- /dev/null +++ b/version/102/adminmenu/tpl/orders.tpl @@ -0,0 +1,106 @@ + +{if count($ordersMsgs)} + {foreach from=$ordersMsgs item=alert} +
{$alert->text}
+ {/foreach} +
+{/if} + +{if $hasAPIKey == false} + + Jetzt kostenlos Mollie Account eröffnen! + +{else} + + + + + + + + + + + + + + + + {foreach from=$payments item=payment} + + + + + + + + + + + + {/foreach} + +
BestellNr.IDMollie StatusJTL StatusBetragWährungLocaleMethodeErstellt
+ {$payment->cOrderNumber} + {if $payment->cMode == 'test'} + TEST + {/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->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)}
+ + +{/if} \ No newline at end of file diff --git a/version/102/adminmenu/tpl/paymentmethods.tpl b/version/102/adminmenu/tpl/paymentmethods.tpl new file mode 100644 index 0000000..87fb5c0 --- /dev/null +++ b/version/102/adminmenu/tpl/paymentmethods.tpl @@ -0,0 +1,49 @@ +

Account Status

+ + + + + + + + + +
Mode:{$profile->mode}Status:{$profile->status}Review:{$profile->review->status}
+ +
+ +{if $allMethods && $allMethods|count} + + + + + + + + + + + {foreach from=$allMethods->_embedded->methods item=method} + + + + + + + {/foreach} + +
BildIDNamePreise
{$method->description|utf8_decode}{$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} +
+
+{else} +
Es konnten keine Methoden abgerufen werden.
+{/if} \ No newline at end of file diff --git a/version/102/class/Helper.php b/version/102/class/Helper.php new file mode 100644 index 0000000..7035a09 --- /dev/null +++ b/version/102/class/Helper.php @@ -0,0 +1,294 @@ +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); + 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(); + } + + /** + * 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); + } + + /** + * @return mixed + */ + private static function _masterMail() + { + $settings = \Shop::getSettings(array(CONF_EMAILS)); + return $settings['emails']['email_master_absender']; + } + + /** + * @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/102/class/Model/AbstractModel.php b/version/102/class/Model/AbstractModel.php new file mode 100644 index 0000000..5638700 --- /dev/null +++ b/version/102/class/Model/AbstractModel.php @@ -0,0 +1,7 @@ + $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, + ]; + 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; + } + + 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/102/class/Mollie.php b/version/102/class/Mollie.php new file mode 100644 index 0000000..82893b6 --- /dev/null +++ b/version/102/class/Mollie.php @@ -0,0 +1,198 @@ +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) { + header('Location: ' . $url); + 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; + } + + switch ((int)$newStatus) { + case BESTELLUNG_STATUS_VERSANDT: + $options['lines'] = []; + break; + case BESTELLUNG_STATUS_TEILVERSANDT: + $lines = []; + foreach ($order->lines as $i => $line) { + if (($quantity = Mollie::getBestellPosSent($line->sku, $oBestellung)) !== false && ($quantity - $line->quantityShipped) > 0) { + $x = $quantity - $line->quantityShipped; + $lines[] = (object)[ + 'id' => $line->id, + 'quantity' => $x, + 'amount' => (object)[ + 'currency' => $line->totalAmount->currency, + 'value' => number_format($x * $line->unitPrice->value, 2), + ], + ]; + } + } + if (count($lines)) { + $options['lines'] = $lines; + } + break; + case BESTELLUNG_STATUS_STORNO: + $options = null; + break; + } + + return $options; + } + + /** + * 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; + } + + /** + * @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) { + $order->orderNumber = $oBestellung->cBestellNr; + Payment::updateFromPayment($order, $kBestellung); + + $oIncomingPayment = \Shop::DB()->executeQueryPrepared("SELECT * FROM tzahlungseingang WHERE cHinweis = :cHinweis AND kBestellung = :kBestellung", [':cHinweis' => $order->id, ':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: + $oIncomingPayment->fBetrag = $order->amount->value; + $oIncomingPayment->cISO = $order->amount->curreny; + $oIncomingPayment->cHinweis = $order->id; + Mollie::JTLMollie()->addIncomingPayment($oBestellung, $oIncomingPayment); + Mollie::JTLMollie()->setOrderStatusToPaid($oBestellung); + Mollie::JTLMollie()->doLog('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('PaymentStatus: ' . $order->status . ' => Bestellung bezahlt, KEIN Zahlungseingang', $logData, LOGLEVEL_NOTICE); + break; + case OrderStatus::STATUS_CANCELED: + case OrderStatus::STATUS_EXPIRED: + Mollie::JTLMollie()->doLog('PaymentStatus: ' . $order->status, $logData, LOGLEVEL_ERROR); + break; + } + return true; + } + return false; + } + + /** + * @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; + } +} diff --git a/version/102/frontend/131_globalinclude.php b/version/102/frontend/131_globalinclude.php new file mode 100644 index 0000000..118f6b6 --- /dev/null +++ b/version/102/frontend/131_globalinclude.php @@ -0,0 +1,67 @@ +executeQueryPrepared("SELECT * FROM " . \ws_mollie\Model\Payment::TABLE . " WHERE cHash = :cHash", [':cHash' => $_REQUEST['mollie']], 1); + // Bestellung finalized, redirect to status/completion page + if ((int)$payment->kBestellung) { + $logData = '$' . $payment->kID . '#' . $payment->kBestellung . "§" . $payment->cOrderNumber; + \ws_mollie\Mollie::JTLMollie()->doLog('Bestellung finalized => redirect abschluss/status', $logData); + $order = JTLMollie::API()->orders->get($payment->kID, ['embed' => 'payments']); + \ws_mollie\Mollie::handleOrder($order, $payment->kBestellung); + \ws_mollie\Mollie::getOrderCompletedRedirect($payment->kBestellung, true); + } elseif ($payment) { // payment, but no order => finalize it + require_once __DIR__ . '/../paymentmethod/JTLMollie.php'; + $order = JTLMollie::API()->orders->get($payment->kID, ['embed' => 'payments']); + $logData = '$' . $order->id . '#' . $payment->kBestellung . "§" . $payment->cOrderNumber; + + // GET NEWEST PAYMENT: + /** @var \Mollie\Api\Resources\Paymentt $_payment */ + $_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; + } + } + } + + // finalize only, if order is not canceld/expired + if ($order && !$order->isCanceled() && !$order->isExpired()) { + // finalize only if payment is not expired/canceled,failed or open + if ($_payment && !in_array($_payment->status, [\Mollie\Api\Types\PaymentStatus::STATUS_EXPIRED, \Mollie\Api\Types\PaymentStatus::STATUS_CANCELED, \Mollie\Api\Types\PaymentStatus::STATUS_OPEN, \Mollie\Api\Types\PaymentStatus::STATUS_FAILED, \Mollie\Api\Types\PaymentStatus::STATUS_CANCELED])) { + \ws_mollie\Mollie::JTLMollie()->doLog('Bestellung open => finalize', $logData); + $session = Session::getInstance(); + /** @noinspection PhpIncludeInspection */ + require_once PFAD_ROOT . 'includes/bestellabschluss_inc.php'; + /** @noinspection PhpIncludeInspection */ + require_once PFAD_ROOT . 'includes/mailTools.php'; + $oBestellung = fakeBestellung(); + $oBestellung = finalisiereBestellung(); + \ws_mollie\Mollie::JTLMollie()->doLog('Bestellung finalized => redirect
' . print_r($order, 1) . '
', $logData, LOGLEVEL_DEBUG); + \ws_mollie\Mollie::handleOrder($order, $oBestellung->kBestellung); + \ws_mollie\Mollie::getOrderCompletedRedirect($oBestellung->kBestellung, true); + } else { + \ws_mollie\Mollie::JTLMollie()->doLog('Invalid Payment
' . print_r($payment, 1) . '
', $logData, LOGLEVEL_ERROR); + } + } else { + \ws_mollie\Mollie::JTLMollie()->doLog('Invalid Order
' . print_r($order, 1) . '
', $logData, LOGLEVEL_ERROR); + } + } + } + ob_end_flush(); +} catch (Exception $e) { + \ws_mollie\Helper::logExc($e); +} diff --git a/version/102/frontend/140_smarty.php b/version/102/frontend/140_smarty.php new file mode 100644 index 0000000..3f74d4f --- /dev/null +++ b/version/102/frontend/140_smarty.php @@ -0,0 +1,53 @@ +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; + } + +CSS +); +} catch (Exception $e) { + \ws_mollie\Helper::logExc($e); +} diff --git a/version/102/frontend/144_notify.php b/version/102/frontend/144_notify.php new file mode 100644 index 0000000..8856259 --- /dev/null +++ b/version/102/frontend/144_notify.php @@ -0,0 +1,27 @@ + Update Payment, stop skript + * - ELSE weiter mit der notify.php + */ + +if (array_key_exists('hash', $_REQUEST)) { + require_once __DIR__ . '/../class/Helper.php'; + try { + \ws_mollie\Helper::init(); + $payment = \ws_mollie\Model\Payment::getPaymentHash($_REQUEST['hash']); + // If Bestellung already exists, treat as Notification + if ($payment && $payment->kBestellung) { + require_once __DIR__ . '/../paymentmethod/JTLMollie.php'; + $order = JTLMollie::API()->orders->get($payment->kID); + $logData = '#' . $payment->kBestellung . '$' . $payment->kID; + \ws_mollie\Mollie::JTLMollie()->doLog('Received Notification
' . print_r([$order, $payment], 1) . '
', $logData); + \ws_mollie\Mollie::handleOrder($order, $payment->kBestellung); + // exit to stop execution of notify.php + exit(); + } + } catch (Exception $e) { + \ws_mollie\Helper::logExc($e); + } +} diff --git a/version/102/frontend/181_sync.php b/version/102/frontend/181_sync.php new file mode 100644 index 0000000..be2fe16 --- /dev/null +++ b/version/102/frontend/181_sync.php @@ -0,0 +1,33 @@ +kBestellung && $payment = \ws_mollie\Model\Payment::getPayment($oBestellung->kBestellung)) { + $logData = '#' . $payment->kBestellung . '$' . $payment->kID . "§" . $oBestellung->cBestellNr; + \ws_mollie\Mollie::JTLMollie()->doLog("WAWI Abgleich: HOOK_BESTELLUNGEN_XML_BESTELLSTATUS", $logData); + try { + $order = JTLMollie::API()->orders->get($payment->kID); + $order->orderNumber = $oBestellung->cBestellNr; + \ws_mollie\Mollie::handleOrder($order, $oBestellung->kBestellung); + if ($order->isCreated() || $order->isPaid() || $order->isAuthorized() || $order->isShipping() || $order->isPending()) { + \ws_mollie\Mollie::JTLMollie()->doLog("Create Shippment:
" . print_r($args_arr, 1) . '
', $logData, LOGLEVEL_DEBUG); + $options = \ws_mollie\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); + \ws_mollie\Mollie::JTLMollie()->doLog('Shipment created
' . print_r(['options' => $options, 'shipment' => $shipment], 1) . '
', $logData, LOGLEVEL_NOTICE); + } else { + \ws_mollie\Mollie::JTLMollie()->doLog('181_sync: options don\'t contain lines
' . print_r([$order, $options], 1) . '
', $logData, LOGLEVEL_ERROR); + } + } + } catch (Exception $e) { + \ws_mollie\Mollie::JTLMollie()->doLog('Fehler: ' . $e->getMessage() . '
' . print_r($e->getTrace(), 1) . '
', $logData, LOGLEVEL_ERROR); + } + } +} catch (Exception $e) { + \ws_mollie\Helper::logExc($e); +} diff --git a/version/102/paymentmethod/JTLMollie.php b/version/102/paymentmethod/JTLMollie.php new file mode 100644 index 0000000..9b21eff --- /dev/null +++ b/version/102/paymentmethod/JTLMollie.php @@ -0,0 +1,526 @@ + (int)$order->kBestellung, + 'cZahlungsanbieter' => empty($order->cZahlungsartName) ? $this->name : $order->cZahlungsartName, + 'fBetrag' => 0, + 'fZahlungsgebuehr' => 0, + 'cISO' => $_SESSION['Waehrung']->cISO, + 'cEmpfaenger' => '', + 'cZahler' => '', + 'dZeit' => 'now()', + 'cHinweis' => '', + 'cAbgeholt' => 'N' + ], (array)$payment); + if (isset($model->kZahlungseingang) && $model->kZahlungseingang > 0) { + Shop::DB()->update('tzahlungseingang', 'kZahlungseingang', $model->kZahlungseingang, $model); + } else { + Shop::DB()->insert('tzahlungseingang', $model); + } + + 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; + } + parent::setOrderStatusToPaid($order); + } + + /** + * Prepares everything so that the Customer can start the Payment Process. + * Tells Template Engine. + * + * @param Bestellung $order + */ + public function preparePaymentProcess($order) + { + $logData = '#' . $order->kBestellung . "" . $order->cBestellNr; + try { + $payment = \ws_mollie\Model\Payment::getPayment($order->kBestellung); + if ($payment && in_array($payment->cStatus, [\Mollie\Api\Types\OrderStatus::STATUS_CREATED]) && $payment->cCheckoutURL) { + $logData .= '$' . $payment->kID; + if (!$this->duringCheckout) { + Session::getInstance()->cleanUp(); + } + header('Location: ' . $payment->cCheckoutURL); + exit(); + } + } catch (\Exception $e) { + $this->doLog("Get Payment Error: " . $e->getMessage() . ". Create new ORDER...", $logData); + } + + try { + $hash = $this->generateHash($order); + $oMolliePayment = self::API()->orders->create($this->getOrderData($order, $hash)); + $_SESSION['oMolliePayment'] = $oMolliePayment; + $logData .= '$' . $oMolliePayment->id; + $this->doLog('Mollie Create Payment Redirect: ' . $oMolliePayment->getCheckoutUrl() . "
" . print_r($oMolliePayment, 1) . "
", $logData, LOGLEVEL_DEBUG); + \ws_mollie\Model\Payment::updateFromPayment($oMolliePayment, $order->kBestellung, md5($hash)); + Shop::Smarty()->assign('oMolliePayment', $oMolliePayment); + if (!$this->duringCheckout) { + Session::getInstance()->cleanUp(); + } + header('Location: ' . $oMolliePayment->getCheckoutUrl()); + exit(); + } catch (\Mollie\Api\Exceptions\ApiException $e) { + Shop::Smarty()->assign('oMollieException', $e); + $this->doLog("Create Payment Error: " . $e->getMessage() . '
' . print_r($e->getTrace(), 1) . '
', $logData); + } + } + + /** + * @param string $msg + * @param null $data + * @param int $level + * @return $this + */ + public function doLog($msg, $data = null, $level = LOGLEVEL_NOTICE) + { + ZahlungsLog::add($this->moduleID, $msg, $data, $level); + + return $this; + } + + /** + * @return \Mollie\Api\MollieApiClient + * @throws \Mollie\Api\Exceptions\ApiException + * @throws \Mollie\Api\Exceptions\IncompatiblePlatform + */ + public static function API() + { + if (self::$_mollie === null) { + self::$_mollie = new \Mollie\Api\MollieApiClient(); + self::$_mollie->setApiKey(\ws_mollie\Helper::getSetting('api_key')); + self::$_mollie->addVersionString("JTL-Shop/" . JTL_VERSION . '.' . JTL_MINOR_VERSION); + self::$_mollie->addVersionString("ws_mollie/" . \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); + $data = [ + 'locale' => $locale ?: 'de_DE', + 'amount' => (object)[ + 'currency' => $order->Waehrung->cISO, + 'value' => number_format($order->fGesamtsummeKundenwaehrung, 2, '.', ''), + ], + 'orderNumber' => $order->cBestellNr, + 'lines' => [], + 'billingAddress' => new stdClass(), + 'shippingAddress' => new stdClass(), + 'redirectUrl' => (int)$this->duringCheckout ? Shop::getURL() . '/bestellabschluss.php?mollie=' . md5($hash) : $this->getReturnURL($order), + 'webhookUrl' => $this->getNotificationURL($hash) . '&hash=' . md5($hash), + ]; + + if (static::MOLLIE_METHOD !== '') { + $data['method'] = static::MOLLIE_METHOD; + } + $data['billingAddress']->organizationName = utf8_encode($order->oRechnungsadresse->cFirma); + $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 = $order->oRechnungsadresse->cMail; + $data['billingAddress']->streetAndNumber = utf8_encode($order->oRechnungsadresse->cStrasse . ' ' . $order->oRechnungsadresse->cHausnummer); + $data['billingAddress']->postalCode = $order->oRechnungsadresse->cPLZ; + $data['billingAddress']->city = utf8_encode($order->oRechnungsadresse->cOrt); + $data['billingAddress']->country = $order->oRechnungsadresse->cLand; + + //if ((int)$order->kLieferadresse) { + $data['shippingAddress']->organizationName = utf8_encode($order->Lieferadresse->cFirma); + $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 = $order->oRechnungsadresse->cMail; + $data['shippingAddress']->streetAndNumber = utf8_encode($order->Lieferadresse->cStrasse . ' ' . $order->Lieferadresse->cHausnummer); + $data['shippingAddress']->postalCode = $order->Lieferadresse->cPLZ; + $data['shippingAddress']->city = utf8_encode($order->Lieferadresse->cOrt); + $data['shippingAddress']->country = $order->Lieferadresse->cLand; + //} + + /** @var WarenkorbPos $oPosition */ + foreach ($order->Positionen as $oPosition) { + $line = new stdClass(); + $line->name = utf8_encode($oPosition->cName); + $line->quantity = $oPosition->nAnzahl; + $line->unitPrice = (object)[ + 'value' => number_format($order->Waehrung->fFaktor * ($oPosition->fPreis * ((float)$oPosition->fMwSt / 100 + 1)), 2, '.', ''), + 'currency' => $order->Waehrung->cISO, + ]; + $line->totalAmount = (object)[ + 'value' => number_format($oPosition->nAnzahl * (float)$line->unitPrice->value, 2, '.', ''), + 'currency' => $order->Waehrung->cISO, + ]; + $line->vatRate = $oPosition->fMwSt; + $line->vatAmount = (object)[ + 'value' => number_format($line->totalAmount->value - ($line->totalAmount->value / (1 + (float)$oPosition->fMwSt / 100)), 2, '.', ''), + 'currency' => $order->Waehrung->cISO, + ]; + + switch ((int)$oPosition->nPosTyp) { + case (int)C_WARENKORBPOS_TYP_GRATISGESCHENK: + case (int)C_WARENKORBPOS_TYP_ARTIKEL: + $line->type = \Mollie\Api\Types\OrderLineType::TYPE_PHYSICAL; + $line->sku = $oPosition->cArtNr; + break; + case (int)C_WARENKORBPOS_TYP_VERSANDPOS: + $line->type = \Mollie\Api\Types\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 = \Mollie\Api\Types\OrderLineType::TYPE_SURCHARGE; + break; + case (int)C_WARENKORBPOS_TYP_GUTSCHEIN: + case (int)C_WARENKORBPOS_TYP_KUPON: + case (int)C_WARENKORBPOS_TYP_NEUKUNDENKUPON: + $line->type = \Mollie\Api\Types\OrderLineType::TYPE_DISCOUNT; + break; + } + if (isset($line->type)) { + $data['lines'][] = $line; + } + } + + if ((int)$order->GuthabenNutzen === 1 && $order->fGuthaben < 0) { + $line = new stdClass(); + $line->type = \Mollie\Api\Types\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->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 ? \Mollie\Api\Types\OrderLineType::TYPE_SURCHARGE : \Mollie\Api\Types\OrderLineType::TYPE_DISCOUNT; + $line->name = 'Rundungsausgleich'; + $line->quantity = 1; + $line->unitPrice = (object)[ + 'value' => number_format($diff, 2, '.', ''), + 'currency' => $order->Waehrung->cISO, + ]; + $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 "eng": + return "en_US"; + 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"; + } + } + + /** + * @param Bestellung $order + * @param string $hash + * @param array $args + */ + public function handleNotification($order, $hash, $args) + { + \ws_mollie\Helper::autoload(); + $logData = '#' . $order->kBestellung . "" . $order->cBestellNr; + $this->doLog('Received Notification
' . print_r([$hash, $args], 1) . '
', $logData, LOGLEVEL_NOTICE); + + try { + $oMolliePayment = self::API()->orders->get($args['id']); + \ws_mollie\Mollie::handleOrder($oMolliePayment, $order->kBestellung); + } catch (\Exception $e) { + $this->doLog('handleNotification: ' . $e->getMessage(), $logData); + } + } + + /** + * @param Bestellung $order + * @param string $hash + * @param array $args + * + * @return true, if $order should be finalized + */ + public function finalizeOrder($order, $hash, $args) + { + $logData = '#' . $order->kBestellung . "" . $order->cBestellNr; + try { + \ws_mollie\Helper::autoload(); + $oMolliePayment = self::API()->orders->get($args['id'], ['embed' => 'payments']); + $logData .= '$' . $oMolliePayment->id; + $this->doLog('Received Notification Finalize Order
' . print_r([$hash, $args, $oMolliePayment], 1) . '
', $logData, LOGLEVEL_DEBUG); + \ws_mollie\Model\Payment::updateFromPayment($oMolliePayment, $order->kBestellung); + return in_array($oMolliePayment->status, [\Mollie\Api\Types\OrderStatus::STATUS_PAID, \Mollie\Api\Types\OrderStatus::STATUS_AUTHORIZED, \Mollie\Api\Types\OrderStatus::STATUS_PENDING, \Mollie\Api\Types\OrderStatus::STATUS_COMPLETED]); + } catch (\Exception $e) { + $this->doLog($e->getMessage(), $logData); + } + return false; + } + + /** + * @return bool + */ + public function canPayAgain() + { + return true; + } + + /** + * determines, if the payment method can be selected in the checkout process + * + * @return bool + */ + public function isSelectable() + { + $locale = self::getLocale($_SESSION['cISOSprache'], $_SESSION['Kunde']->cLand); + if (static::MOLLIE_METHOD !== '') { + try { + /** @var Warenkorb $wk */ + $wk = $_SESSION['Warenkorb']; + $method = self::PossiblePaymentMethods(static::MOLLIE_METHOD, $locale, $_SESSION['Kunde']->cLand, $_SESSION['Waehrung']->cISO, $wk->gibGesamtsummeWaren() * $_SESSION['Waehrung']->fFaktor); + if ($method !== null) { + $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; + } + } + return true; + } + + /** + * @param $method + * @param $locale + * @param $billingCountry + * @param $currency + * @param $amount + * @return mixed|null + * @throws \Mollie\Api\Exceptions\ApiException + * @throws \Mollie\Api\Exceptions\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->all(['amount' => ['currency' => $currency, 'value' => number_format($amount, 2, '.', '')], 'billingCountry' => $_SESSION['Kunde']->cLand, 'locale' => $locale, '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 (ws_mollie\Helper::getSetting('paymentmethod_sync') === 'N') { + return; + } + $size = ws_mollie\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 object $customer + * @param Warenkorb $cart + * @return bool - true, if $customer with $cart may use Payment Method + */ + public function isValid($customer, $cart) + { + if (\ws_mollie\Helper::init() && \ws_mollie\Helper::getSetting("api_key")) { + return true; + } + $this->doLog("isValdid failed: init failed or no API Key given. Try clear the Cache."); + return false; + } + + /** + * @param array $args_arr + * @return bool + */ + public function isValidIntern($args_arr = []) + { + if (\ws_mollie\Helper::init() && \ws_mollie\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/102/paymentmethod/JTLMollieBancontact.php b/version/102/paymentmethod/JTLMollieBancontact.php new file mode 100644 index 0000000..0e5eeed --- /dev/null +++ b/version/102/paymentmethod/JTLMollieBancontact.php @@ -0,0 +1,8 @@ + + {$oMollieException->getMessage()} + +{/if} \ No newline at end of file diff --git a/version/102/sql/100.sql b/version/102/sql/100.sql new file mode 100644 index 0000000..a6cf185 --- /dev/null +++ b/version/102/sql/100.sql @@ -0,0 +1,22 @@ +CREATE TABLE `xplugin_ws_mollie_payments` ( + `kID` VARCHAR(32) NOT NULL, + `kBestellung` INT(11) NULL, + `cMode` VARCHAR(16) NULL, + `cStatus` VARCHAR(16) NOT NULL, + `cHash` VARCHAR(32) NULL, + `fAmount` FLOAT NOT NULL, + `cOrderNumber` VARCHAR(32) DEFAULT '' NOT NULL, + `cCurrency` VARCHAR(3) NOT NULL, + `cMethod` VARCHAR(16) NULL, + `cLocale` VARCHAR(5) NOT NULL, + `bCancelable` INT(1) NOT NULL, + `cWebhookURL` VARCHAR(255) DEFAULT '' NOT NULL, + `cRedirectURL` VARCHAR(255) DEFAULT '' NOT NULL, + `cCheckoutURL` VARCHAR(255) DEFAULT '' NOT NULL, + `fAmountCaptured` FLOAT NULL, + `fAmountRefunded` FLOAT NULL, + `dCreatedAt` DATETIME NULL +); + +ALTER TABLE `xplugin_ws_mollie_payments` + ADD PRIMARY KEY `kID` (`kID`); \ No newline at end of file From 756f5916529702a980ed97efdca2d013845c1fe5 Mon Sep 17 00:00:00 2001 From: "C. Proske" Date: Tue, 26 Feb 2019 14:21:21 +0100 Subject: [PATCH 046/280] info xml encoding --- info.xml | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/info.xml b/info.xml index e004d24..f6f6621 100644 --- a/info.xml +++ b/info.xml @@ -1,7 +1,7 @@ mollie - Zahlungsartplugin für mollie.com + Zahlungsartplugin für mollie.com WebStollen http://www.webstollen.de/ 102 @@ -15,9 +15,6 @@ 2019-02-26 - - 2019-02-26 - 131_globalinclude.php 144_notify.php @@ -41,23 +38,23 @@ Einstellungen API Key: - Füge hier deinen mollie API Key ein + Füge hier deinen mollie API Key ein api_key Zahlungsart Daten syncronisiernen - Lädt Name / Bild für die jeweilige Sprache automatisch von mollie, und speichert diese in der Datenbank + Lädt Name / Bild für die jeweilige Sprache automatisch von mollie, und speichert diese in der Datenbank paymentmethod_sync - - + + Checkout Styles laden - Lädt Stylesheets für das Evo Template, um den Checkout zu verschönern. + Lädt Stylesheets für das Evo Template, um den Checkout zu verschönern. load_styles @@ -163,9 +160,9 @@ JTLMollieBanktransfer tpl/bestellabschluss.tpl - SEPA Ãœberweisung + SEPA Überweisung mollie - Bezahlen Sie bequem mit SEPA Ãœberweisung. + Bezahlen Sie bequem mit SEPA Überweisung.
@@ -183,7 +180,7 @@ JTLMollieBelfius tpl/bestellabschluss.tpl - SEPA Ãœberweisung + Belfius mollie Bezahlen Sie bequem mit Belfius. From bbd335943e4ef0b4b0d0c9f92ca2b024f5ab0b96 Mon Sep 17 00:00:00 2001 From: "C. Proske" Date: Tue, 19 Mar 2019 16:27:08 +0100 Subject: [PATCH 047/280] cleanup --- version/100/adminmenu/info.php | 6 - version/100/class/Helper.php | 227 +-------------------------------- 2 files changed, 1 insertion(+), 232 deletions(-) diff --git a/version/100/adminmenu/info.php b/version/100/adminmenu/info.php index 74e4100..975d723 100644 --- a/version/100/adminmenu/info.php +++ b/version/100/adminmenu/info.php @@ -36,12 +36,6 @@ ' ' . ''; - if (\ws_mollie\Helper::_licCache()->disabled) { - echo "
Die Pluginlizenz und das Plugin wurden deaktiviert. " - . "" - . "Klicke hier um die Lizenz erneut zu überprüfen.
"; - } - try { $latestRelease = \ws_mollie\Helper::getLatestRelease(array_key_exists('update', $_REQUEST)); if ((int)\ws_mollie\Helper::oPlugin()->nVersion < (int)$latestRelease->version) { diff --git a/version/100/class/Helper.php b/version/100/class/Helper.php index d7a916f..8a6101c 100644 --- a/version/100/class/Helper.php +++ b/version/100/class/Helper.php @@ -19,18 +19,6 @@ final class Helper */ private static $_autoload; - /** - * Is Licence valid? - * - * @var bool|null - */ - private static $_licence; - - /** - * @var string - */ - private static $_tmpLicence; - /** * @var \Plugin */ @@ -182,58 +170,7 @@ public static function getLatestRelease($force = false) public static function init() { ini_set('xdebug.default_enable', defined('WS_XDEBUG_ENABLED')); - self::autoload(); - if (null === self::$_licence) { - if (array_key_exists('_licActivate', $_REQUEST) && $_REQUEST['_licActivate'] === __NAMESPACE__) { - self::_licActivate(self::_licCache()); - } - - self::$_licence = false; - self::$_tmpLicence = md5(time()); - if ($_SERVER['HTTP_HOST'] === 'localhost') { - self::$_licence = true; - } else { - self::$_licence = self::licCheck(md5(self::$_tmpLicence)) === md5(self::$_tmpLicence); - } - } - - if (!self::$_licence && self::isAdminBackend()) { - \Shop::Smarty()->assign('defaultTabbertab', self::getAdminmenu('Info')); - } - - - return self::$_autoload && self::$_licence; - } - - /** - * @param $oL - * @return mixed - */ - private static function _licActivate($oL) - { - $oL->nextCheck = 0; - $oL->fails = 0; - $oL->disabled = 0; - self::_licSave($oL); - return $oL; - } - - /** - * @param $oL - * @param bool $checksum - * @return mixed - */ - private static function _licSave($oL, $checksum = false) - { - self::setSetting('lic_validUntil', $oL->validUntil); - self::setSetting('lic_nextCheck', $oL->nextCheck); - self::setSetting('lic_test', $oL->test); - if ($checksum === true) { - self::setSetting('lic_checkSum', base64_encode(sha1($oL->validUntil . $oL->nextCheck . $oL->test . $oL->disabled . $oL->fails . __NAMESPACE__, true))); - } - self::setSetting('lic_disabled', (int)$oL->disabled); - self::setSetting('lic_fails', $oL->fails); - return $oL; + return self::autoload(); } /** @@ -276,39 +213,6 @@ public static function oPlugin($force = false) return self::$oPlugin; } - /** - * @param $oL - * @return bool|string - */ - private static function _licValid($oL) - { - if ($nextCheck = strtotime($oL->nextCheck)) { - if ($nextCheck > time()) { - if ($validUntil = strtotime($oL->validUntil)) { - if ($validUntil > time() || (int)$oL->test === 0) { - return md5(self::$_tmpLicence); - } - } - } - } - return false; - } - - /** - * @return \stdClass - */ - public static function _licCache() - { - $oL = new \stdClass(); - $oL->validUntil = self::getSetting('lic_validUntil'); - $oL->nextCheck = self::getSetting('lic_nextCheck'); - $oL->test = self::getSetting('lic_test'); - $oL->checksum = self::getSetting('lic_checkSum'); - $oL->disabled = self::getSetting('lic_disabled') === null ? 0 : (int)self::getSetting('lic_disabled'); - $oL->fails = self::getSetting('lic_fails') ?: 0; - return $oL; - } - /** * get a Plugin setting * @@ -323,135 +227,6 @@ public static function getSetting($name) return null; } - /** - * @param $x - * @return bool|string - */ - private static function licCheck($x) - { - if ($x !== md5(self::$_tmpLicence)) { - return false; - } - $oL = self::_licCache(); - if (self::_licCRC($oL) === true) { - // CRC OK? - if (self::_licValid($oL) === md5(self::$_tmpLicence)) { - return md5(self::$_tmpLicence); - } - } - if ($oL->disabled === 0) { - $oL = self::_licLive($oL); - - if ($oL->disabled === 0 && self::_licValid($oL) === md5(self::$_tmpLicence)) { - return md5(self::$_tmpLicence); - } - } - return false; - } - - /** - * @param $oL - * @return bool - */ - private static function _licCRC($oL) - { - $crc_valid = false; - if ($checksum = base64_encode(sha1($oL->validUntil . $oL->nextCheck . $oL->test . $oL->disabled . $oL->fails . __NAMESPACE__, true))) { - $crc_valid = $checksum == $oL->checksum; - } - return $oL->checksum && $crc_valid; - } - - /** - * @param $oL - * @return mixed - */ - private static function _licLive($oL) - { - try { - if (!function_exists('curl_init')) { - throw new \Exception(__NAMESPACE__ . ': cURL needs to be installed!'); - } - - $urlShop = self::getDomain(); - - $params = [ - 'domain' => $urlShop, - 'plugin_version' => (int)self::oPlugin()->nVersion, - 'plugin_id' => self::oPlugin()->cPluginID, - 'email' => self::_masterMail(), - 'shop_version' => (string)(defined('APPLICATION_VERSION') ? APPLICATION_VERSION : JTL_VERSION), - 'shop_build' => defined('APPLICATION_BUILD_SHA') ? APPLICATION_BUILD_SHA : '', - 'php_version' => PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION . '.' . PHP_RELEASE_VERSION, - 'php_extra_version' => PHP_EXTRA_VERSION, - 'php_os' => PHP_OS, - 'server' => array_key_exists('SERVER_SOFTWARE', $_SERVER) ? $_SERVER['SERVER_SOFTWARE'] : '', - ]; - $curl = curl_init('https://lic.dash.bar'); - @curl_setopt($curl, CURLOPT_POST, 1); - @curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($params)); // http_build_query($params, '', '&')); - @curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 3); - @curl_setopt($curl, CURLOPT_TIMEOUT, 3); - @curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); - @curl_setopt($curl, CURLOPT_HEADER, 0); - @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 licence info: ' . $statusCode); - } - /** @noinspection UnserializeExploitsInspection */ - if ($response = json_decode($data)) { - $checksum = md5(base64_encode($response->data->validUntil . $response->data->nextCheck . ($response->data->testLicence ? 'Y' : 'N'))); - - if (!$response || !isset($response->data) || $response->data === false || !isset($response->checksum) || $response->checksum !== $checksum) { - throw new \Exception(__NAMESPACE__ . ': Invalid licence info: ' . print_r($response, 1)); - } - $oLL = $response->data; - if (self::isPresent($oLL->validUntil)) { - $oL->validUntil = date('Y-m-d', $oLL->validUntil); - } - if (self::isPresent($oLL->nextCheck)) { - $oL->nextCheck = date('Y-m-d', $oLL->nextCheck); - } - if (self::isPresent($oLL->testLicence)) { - $oL->test = $oLL->testLicence ? 1 : 0; - } - $oL->fails = 0; - self::_licSave($oL, true); - } else { - throw new \Exception(__NAMESPACE__ . ': Could not decode licence info: ' . print_r($response, 1)); - } - } catch (\Exception $e) { - $oL->disabled = (++$oL->fails) >= 3 ? 1 : 0; - $oL->nextCheck = date("Y-m-d", strtotime("+1 DAY")); - $oL->validUntil = date("Y-m-d", strtotime("+1 DAY")); - ; - - self::logExc($e, false); - self::_licSave($oL, true); - } - return $oL; - } - - - /** - * @param $val - * @return bool - * @throws \Exception - */ - private static function ispresent($val) - { - if (isset($val)) { - return true; - } else { - throw new \Exception(__NAMESPACE__ . ': Could ned find value from license server ' . print_r($val, 1)); - } - } - /** * Get Domain frpm URL_SHOP without www. * From 9494920b1a34f9fbdb7ca0f964c188fbbb9b90ae Mon Sep 17 00:00:00 2001 From: "C. Proske" Date: Mon, 1 Apr 2019 11:32:58 +0200 Subject: [PATCH 048/280] fix #24 --- info.xml | 35 ++++++++++++++----------- version/102/paymentmethod/JTLMollie.php | 20 ++++++++------ 2 files changed, 31 insertions(+), 24 deletions(-) diff --git a/info.xml b/info.xml index f6f6621..fe65604 100644 --- a/info.xml +++ b/info.xml @@ -15,6 +15,9 @@ 2019-02-26 + + 2019-04-01 + 131_globalinclude.php 144_notify.php @@ -92,7 +95,7 @@ 0 mollie.com CREDIT_CARD - 0 + 1 0 1 0 @@ -112,7 +115,7 @@ 0 mollie.com OTHER - 0 + 1 0 1 0 @@ -132,7 +135,7 @@ 0 mollie.com OTHER - 0 + 1 0 1 0 @@ -172,7 +175,7 @@ 0 mollie.com OTHER - 0 + 1 0 1 0 @@ -192,7 +195,7 @@ 0 mollie.com DIRECT_DEBIT - 0 + 1 0 1 0 @@ -212,7 +215,7 @@ 0 mollie.com OTHER - 0 + 1 0 1 0 @@ -232,7 +235,7 @@ 0 mollie.com OTHER - 0 + 1 0 1 0 @@ -252,7 +255,7 @@ 0 mollie.com GIROPAY - 0 + 1 0 1 0 @@ -272,7 +275,7 @@ 0 mollie.com OTHER - 0 + 1 0 1 0 @@ -292,7 +295,7 @@ 0 mollie.com OTHER - 0 + 1 0 1 0 @@ -312,7 +315,7 @@ 0 mollie.com OTHER - 0 + 1 0 1 0 @@ -332,7 +335,7 @@ 0 mollie.com PAYPAL - 0 + 1 0 1 0 @@ -352,7 +355,7 @@ 0 mollie.com OTHER - 0 + 1 0 1 0 @@ -372,7 +375,7 @@ 0 mollie.com DIRECT_E_BANKING - 0 + 1 0 1 0 @@ -392,7 +395,7 @@ 0 mollie.com INVOICE - 0 + 1 0 1 0 @@ -412,7 +415,7 @@ 0 mollie.com FINANCING - 0 + 1 0 1 0 diff --git a/version/102/paymentmethod/JTLMollie.php b/version/102/paymentmethod/JTLMollie.php index 9b21eff..f4ee2e0 100644 --- a/version/102/paymentmethod/JTLMollie.php +++ b/version/102/paymentmethod/JTLMollie.php @@ -1,5 +1,7 @@ name = utf8_encode($oPosition->cName); $line->quantity = $oPosition->nAnzahl; $line->unitPrice = (object)[ - 'value' => number_format($order->Waehrung->fFaktor * ($oPosition->fPreis * ((float)$oPosition->fMwSt / 100 + 1)), 2, '.', ''), + 'value' => number_format(berechneBrutto($order->Waehrung->fFaktor * $oPosition->fPreis, $oPosition->fMwSt), 2, '.', ''), + //'value' => number_format($order->Waehrung->fFaktor * ($oPosition->fPreis * ((float)$oPosition->fMwSt / 100 + 1)), 2, '.', ''), 'currency' => $order->Waehrung->cISO, ]; $line->totalAmount = (object)[ @@ -226,30 +229,31 @@ protected function getOrderData(Bestellung $order, $hash) ]; $line->vatRate = $oPosition->fMwSt; $line->vatAmount = (object)[ - 'value' => number_format($line->totalAmount->value - ($line->totalAmount->value / (1 + (float)$oPosition->fMwSt / 100)), 2, '.', ''), + //'value' => number_format($line->totalAmount->value - berechneNetto($line->totalAmount->value, $oPosition->fMwSt), 2, '.', ''), + 'value' => number_format($line->totalAmount->value - (berechneNetto($line->unitPrice->value, $oPosition->fMwSt) * $oPosition->nAnzahl), 2, '.', ''), 'currency' => $order->Waehrung->cISO, ]; switch ((int)$oPosition->nPosTyp) { case (int)C_WARENKORBPOS_TYP_GRATISGESCHENK: case (int)C_WARENKORBPOS_TYP_ARTIKEL: - $line->type = \Mollie\Api\Types\OrderLineType::TYPE_PHYSICAL; + $line->type = OrderLineType::TYPE_PHYSICAL; $line->sku = $oPosition->cArtNr; break; case (int)C_WARENKORBPOS_TYP_VERSANDPOS: - $line->type = \Mollie\Api\Types\OrderLineType::TYPE_SHIPPING_FEE; + $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 = \Mollie\Api\Types\OrderLineType::TYPE_SURCHARGE; + $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 = \Mollie\Api\Types\OrderLineType::TYPE_DISCOUNT; + $line->type = OrderLineType::TYPE_DISCOUNT; break; } if (isset($line->type)) { @@ -259,7 +263,7 @@ protected function getOrderData(Bestellung $order, $hash) if ((int)$order->GuthabenNutzen === 1 && $order->fGuthaben < 0) { $line = new stdClass(); - $line->type = \Mollie\Api\Types\OrderLineType::TYPE_STORE_CREDIT; + $line->type = OrderLineType::TYPE_STORE_CREDIT; $line->name = 'Guthaben'; $line->quantity = 1; $line->unitPrice = (object)[ @@ -291,7 +295,7 @@ protected function getOrderData(Bestellung $order, $hash) $diff = (round((float)$data['amount']->value - $sum, 2)); if ($diff != 0) { $line = new stdClass(); - $line->type = $diff > 0 ? \Mollie\Api\Types\OrderLineType::TYPE_SURCHARGE : \Mollie\Api\Types\OrderLineType::TYPE_DISCOUNT; + $line->type = $diff > 0 ? OrderLineType::TYPE_SURCHARGE : OrderLineType::TYPE_DISCOUNT; $line->name = 'Rundungsausgleich'; $line->quantity = 1; $line->unitPrice = (object)[ From ca8b0728c539160ff37535f6df63abf986ae6216 Mon Sep 17 00:00:00 2001 From: "C. Proske" Date: Mon, 1 Apr 2019 12:00:48 +0200 Subject: [PATCH 049/280] fix #25 --- version/102/paymentmethod/JTLMollie.php | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/version/102/paymentmethod/JTLMollie.php b/version/102/paymentmethod/JTLMollie.php index f4ee2e0..6f2bfb9 100644 --- a/version/102/paymentmethod/JTLMollie.php +++ b/version/102/paymentmethod/JTLMollie.php @@ -427,11 +427,18 @@ public function canPayAgain() */ public function isSelectable() { + /** @var Warenkorb $wk */ + $wk = $_SESSION['Warenkorb']; + foreach ($wk->PositionenArr as $oPosition) { + if ($oPosition->Artikel->cTeilbar === 'Y' && fmod($oPosition->nAnzahl, 1) !== 0) { + return false; + } + } + $locale = self::getLocale($_SESSION['cISOSprache'], $_SESSION['Kunde']->cLand); if (static::MOLLIE_METHOD !== '') { try { - /** @var Warenkorb $wk */ - $wk = $_SESSION['Warenkorb']; + $method = self::PossiblePaymentMethods(static::MOLLIE_METHOD, $locale, $_SESSION['Kunde']->cLand, $_SESSION['Waehrung']->cISO, $wk->gibGesamtsummeWaren() * $_SESSION['Waehrung']->fFaktor); if ($method !== null) { $this->updatePaymentMethod($_SESSION['cISOSprache'], $method); From 526d5666b24a22494131b3443447e2aef39ecacc Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Mon, 8 Apr 2019 16:35:59 +0200 Subject: [PATCH 050/280] Update .gitattributes --- .gitattributes | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..f752126 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +* text working-tree-encoding=ISO8859-1 \ No newline at end of file From 35dbb97571cbd1b0774fc6e24facc5a990d4c6bf Mon Sep 17 00:00:00 2001 From: "C. Proske" Date: Tue, 16 Apr 2019 11:41:56 +0200 Subject: [PATCH 051/280] Backend Paymentmethods --- composer.lock | 121 +++------- version/102/adminmenu/paymentmethods.php | 37 +++- version/102/adminmenu/tpl/paymentmethods.tpl | 58 ++++- version/102/class/Mollie.php | 218 ++++++++++++++++++- 4 files changed, 323 insertions(+), 111 deletions(-) diff --git a/composer.lock b/composer.lock index 756d525..013b129 100644 --- a/composer.lock +++ b/composer.lock @@ -247,16 +247,16 @@ }, { "name": "mollie/mollie-api-php", - "version": "v2.6.1", + "version": "v2.8.3", "source": { "type": "git", "url": "https://github.com/mollie/mollie-api-php.git", - "reference": "e4ed1ba98ca690585dca613eded3f5ffe6c4ffb2" + "reference": "df6e0cea662f3c9603f245816cc2982e8ae49bcf" }, "dist": { "type": "zip", - "url": "https://github.com/gitapi/repos/mollie/mollie-api-php/zipball/e4ed1ba98ca690585dca613eded3f5ffe6c4ffb2", - "reference": "e4ed1ba98ca690585dca613eded3f5ffe6c4ffb2", + "url": "https://github.com/gitapi/repos/mollie/mollie-api-php/zipball/df6e0cea662f3c9603f245816cc2982e8ae49bcf", + "reference": "df6e0cea662f3c9603f245816cc2982e8ae49bcf", "shasum": "" }, "require": { @@ -328,7 +328,7 @@ "sofortbanking", "subscriptions" ], - "time": "2019-01-31T07:26:26+00:00" + "time": "2019-04-11T12:19:05+00:00" }, { "name": "psr/http-message", @@ -423,6 +423,17 @@ { "name": "roave/security-advisories", "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/Roave/SecurityAdvisories.git", + "reference": "ff41a9a96718245c7160588928e6d217cfb0393c" + }, + "dist": { + "type": "zip", + "url": "https://github.com/gitapi/repos/Roave/SecurityAdvisories/zipball/ff41a9a96718245c7160588928e6d217cfb0393c", + "reference": "ff41a9a96718245c7160588928e6d217cfb0393c", + "shasum": "" + }, "conflict": { "3f/pygmentize": "<1.2", "adodb/adodb-php": "<5.20.12", @@ -440,8 +451,8 @@ "codeigniter/framework": "<=3.0.6", "composer/composer": "<=1.0.0-alpha11", "contao-components/mediaelement": ">=2.14.2,<2.21.1", - "contao/core": ">=2,<3.5.35", - "contao/core-bundle": ">=4,<4.4.18|>=4.5,<4.5.8", + "contao/core": ">=2,<3.5.39", + "contao/core-bundle": ">=4,<4.4.37|>=4.5,<4.7.3", "contao/listing-bundle": ">=4,<4.4.8", "contao/newsletter-bundle": ">=4,<4.1", "david-garcia/phpwhois": "<=4.3.1", @@ -455,92 +466,9 @@ "doctrine/mongodb-odm-bundle": ">=2,<3.0.1", "doctrine/orm": ">=2,<2.4.8|>=2.5,<2.5.1", "dompdf/dompdf": ">=0.6,<0.6.2", - "drupal/acquia_connector": ">=1,<1.16", - "drupal/autologout": ">=4,<4.5", - "drupal/backup_migrate": ">=3,<3.4", - "drupal/bealestreet": ">=1,<1.2", - "drupal/bible": ">=1,<1.7", - "drupal/bing_autosuggest_api": ">=1,<1.1", - "drupal/bootstrap": ">=3,<3.14", - "drupal/brilliant_gallery": ">=1,<1.10", - "drupal/ckeditor_uploadimage": ">=1,<1.5", - "drupal/cleantalk": ">=2,<2.7", - "drupal/cloud": ">=1,<1.7", - "drupal/commerce": ">=2,<2.9", - "drupal/commerce_custom_order_status": ">=1,<1.1", - "drupal/commerce_klarna_checkout": ">=1,<1.5", - "drupal/config_perms": ">=1,<1.1|>=2,<2.2", - "drupal/config_update": ">=1,<1.5", - "drupal/core": ">=7,<7.62|>=8,<8.5.11|>=8.6,<8.6.10", - "drupal/datereminder": ">=1,<1.15", - "drupal/decoupled_router": ">=1,<1.2", - "drupal/domain_integration": ">=1,<1.2", - "drupal/drupal": ">=7,<7.62|>=8,<8.5.11|>=8.6,<8.6.10", - "drupal/entity": ">=1,<1.9", - "drupal/entity_ref_tab_formatter": ">=1,<1.3", - "drupal/entityqueue_taxonomy": ">=1,<1.1", - "drupal/esign": ">=1,<1.10", - "drupal/eu_cookie_compliance": ">=1,<1.1", - "drupal/exif": ">=1,<1.1", - "drupal/feedback_collect": ">=1,<1.6", - "drupal/filefield_paths": ">=1,<1.1", - "drupal/filefield_sources": ">=1,<1.11", - "drupal/focal_point": ">=1,<1.2", - "drupal/fontawesome": ">=2,<2.12", - "drupal/fraction": ">=1,<1.2", - "drupal/gathercontent": ">=3,<3.5", - "drupal/genpass": ">=1,<1.1", - "drupal/hosting_https": ">=3,<3.170", - "drupal/jsonapi": ">=1,<1.16", - "drupal/lightbox2": ">=2,<2.11", - "drupal/link": ">=1,<1.6", - "drupal/litejazz": ">=2,<2.3", - "drupal/mailhandler": ">=2,<2.11", - "drupal/mass_pwreset": ">=1,<1.1", - "drupal/me": ">=1,<1.3", - "drupal/media": ">=2,<2.19", - "drupal/menu_export": ">=1,<1.2", - "drupal/metatag": ">=1,<1.8", - "drupal/miniorange_oauth_client": ">=1,<1.21", - "drupal/moneysuite": ">=10,<10.4", - "drupal/mosaik": ">=1,<1.2", - "drupal/netforum_authentication": ">=1,<1.1", - "drupal/newsflash": ">=2,<2.6", - "drupal/node_feedback": ">=1,<1.3", - "drupal/node_view_permissions": ">=1,<1.1", - "drupal/nucleus": ">=1,<1.6", - "drupal/nvp": ">=1,<1.1", - "drupal/panels_breadcrumbs": ">=2,<2.4", - "drupal/panopoly_core": ">=1,<1.49", - "drupal/paragraphs": ">=1,<1.6", - "drupal/password_policy": ">=1,<1.16", - "drupal/permissions_by_term": ">=1,<1.35", - "drupal/phonefield": ">=1,<1.1", - "drupal/phpconfig": ">=1,<1.1", - "drupal/preview_link": ">=1,<1.1", - "drupal/print": ">=2,<2.1", - "drupal/provision": ">=3,<3.170", - "drupal/pubdlcnt": ">=1,<1.3", - "drupal/renderkit": ">=1,<1.6", - "drupal/responsive_menus": ">=1,<1.7", - "drupal/restws": ">=2,<2.8", - "drupal/sagepay_payment": ">=1,<1.5", - "drupal/salesforce": ">=3,<3.1", - "drupal/search_api_solr": ">=1,<1.14", - "drupal/search_autocomplete": ">=4,<4.8", - "drupal/services_sso_client": ">=1,<1.6", - "drupal/stacks": ">=1,<1.1", - "drupal/tapestry": ">=2,<2.2", - "drupal/term_reference_tree": ">=1,<1.11", - "drupal/tfa_basic": ">=1,<1.1", - "drupal/tft": ">=1,<1.1", - "drupal/tmgmt": ">=1,<1.7", - "drupal/uuid": ">=1,<1.1", - "drupal/video": ">=1,<1.4", - "drupal/workbench_moderation": ">=1,<1.4", - "drupal/yandex_metrics": ">=3,<3.1", - "drupal/zircon": ">=1,<1.2", - "erusev/parsedown": "<1.7", + "drupal/core": ">=7,<7.65|>=8,<8.5.14|>=8.6,<8.6.13", + "drupal/drupal": ">=7,<7.64|>=8,<8.5.13|>=8.6,<8.6.12", + "erusev/parsedown": "<1.7.2", "ezsystems/ezpublish-kernel": ">=5.3,<5.3.12.1|>=5.4,<5.4.13.1|>=6,<6.7.9.1|>=6.8,<6.13.5.1|>=7,<7.2.4.1|>=7.3,<7.3.2.1", "ezsystems/ezpublish-legacy": ">=5.3,<5.3.12.6|>=5.4,<5.4.12.3|>=2011,<2017.12.4.3|>=2018.6,<2018.6.1.4|>=2018.9,<2018.9.1.3", "ezsystems/repository-forms": ">=2.3,<2.3.2.1", @@ -567,7 +495,7 @@ "la-haute-societe/tcpdf": "<6.2.22", "laravel/framework": ">=4,<4.0.99|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.42|>=5.6,<5.6.30", "laravel/socialite": ">=1,<1.0.99|>=2,<2.0.10", - "league/commonmark": ">=0.15.6,<0.18.1", + "league/commonmark": "<0.18.3", "magento/magento1ce": "<1.9.4", "magento/magento1ee": ">=1.9,<1.14.4", "magento/product-community-edition": ">=2,<2.2.7", @@ -640,7 +568,7 @@ "theonedemon/phpwhois": "<=4.2.5", "titon/framework": ">=0,<9.9.99", "truckersmp/phpwhois": "<=4.3.1", - "twig/twig": "<1.20", + "twig/twig": "<1.38|>=2,<2.7", "typo3/cms": ">=6.2,<6.2.30|>=7,<7.6.32|>=8,<8.7.23|>=9,<9.5.4", "typo3/cms-core": ">=8,<8.7.23|>=9,<9.5.4", "typo3/flow": ">=1,<1.0.4|>=1.1,<1.1.1|>=2,<2.0.1|>=2.3,<2.3.16|>=3,<3.0.10|>=3.1,<3.1.7|>=3.2,<3.2.7|>=3.3,<3.3.5", @@ -660,6 +588,7 @@ "zendframework/zend-captcha": ">=2,<2.4.9|>=2.5,<2.5.2", "zendframework/zend-crypt": ">=2,<2.4.9|>=2.5,<2.5.2", "zendframework/zend-db": ">=2,<2.0.99|>=2.1,<2.1.99|>=2.2,<2.2.10|>=2.3,<2.3.5", + "zendframework/zend-developer-tools": ">=1.2.2,<1.2.3", "zendframework/zend-diactoros": ">=1,<1.8.4", "zendframework/zend-feed": ">=1,<2.10.3", "zendframework/zend-form": ">=2,<2.2.7|>=2.3,<2.3.1", @@ -694,7 +623,7 @@ } ], "description": "Prevents installation of composer packages with known security vulnerabilities: no API, simply require it", - "time": "2019-02-22T18:40:39+00:00" + "time": "2019-04-12T16:05:24+00:00" } ], "packages-dev": [], diff --git a/version/102/adminmenu/paymentmethods.php b/version/102/adminmenu/paymentmethods.php index 31c77e7..ebf7ecc 100644 --- a/version/102/adminmenu/paymentmethods.php +++ b/version/102/adminmenu/paymentmethods.php @@ -1,9 +1,11 @@ setApiKey(\ws_mollie\Helper::getSetting("api_key")); + $mollie->setApiKey(Helper::getSetting("api_key")); $profile = $mollie->profiles->get('me'); /* $methods = $mollie->methods->all([ //'locale' => 'de_DE', 'include' => 'pricing', ]);*/ - - $allMethods = $mollie->performHttpCall('GET', '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) { + $allMethods = $mollie->methods->allActive($params); + } else { + $allMethods = $mollie->methods->allAvailable($params); + } Shop::Smarty()->assign('profile', $profile) - //->assign('methods', $methods) + ->assign('currencies', \ws_mollie\Mollie::getCurrencies()) + ->assign('locales', \ws_mollie\Mollie::getLocales()) ->assign('allMethods', $allMethods); Shop::Smarty()->display($oPlugin->cAdminmenuPfad . '/tpl/paymentmethods.tpl'); } catch (Exception $e) { echo "
{$e->getMessage()}
"; - \ws_mollie\Helper::logExc($e); + Helper::logExc($e); } diff --git a/version/102/adminmenu/tpl/paymentmethods.tpl b/version/102/adminmenu/tpl/paymentmethods.tpl index 87fb5c0..945e1ab 100644 --- a/version/102/adminmenu/tpl/paymentmethods.tpl +++ b/version/102/adminmenu/tpl/paymentmethods.tpl @@ -12,6 +12,44 @@
+
+
+ + +
+ Locale: + + + +
+
+ Währung: + +
+
+ Betrag: + +
+
+ Nur aktive ZA +   + + reset +
+
+
+ + {if $allMethods && $allMethods|count} @@ -20,16 +58,17 @@ + - {foreach from=$allMethods->_embedded->methods item=method} - - - - - + + - + + {/foreach}
ID Name PreiseInfos
{$method->description|utf8_decode} + {$method->description|utf8_decode}{$method->id}{$method->description|utf8_decode} + {$method->id}{$method->description|utf8_decode}
    {foreach from=$method->pricing item=price}
  • {$price->description|utf8_decode}: {$price->fixed->value} {$price->fixed->currency} @@ -40,7 +79,12 @@ {/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} +
diff --git a/version/102/class/Mollie.php b/version/102/class/Mollie.php index 82893b6..1bd189f 100644 --- a/version/102/class/Mollie.php +++ b/version/102/class/Mollie.php @@ -140,7 +140,7 @@ public static function getBestellPosSent($sku, \Bestellung $oBestellung) */ public static function handleOrder(Order $order, $kBestellung) { - $logData = '$' . $order->id . '#' . $kBestellung . "§" . $order->orderNumber; + $logData = '$' . $order->id . '#' . $kBestellung . "§" . $order->orderNumber; $oBestellung = new \Bestellung($kBestellung); if ($oBestellung->kBestellung) { @@ -195,4 +195,220 @@ public static function JTLMollie() } return self::$_jtlmollie; } + + 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; + + } } From db18123e57d3b202853024cfc3c9dff79ca6d954 Mon Sep 17 00:00:00 2001 From: "C. Proske" Date: Tue, 16 Apr 2019 12:05:58 +0200 Subject: [PATCH 052/280] cleanup --- .gitattributes | 1 - version/100/adminmenu/info.php | 26 +- version/100/adminmenu/orders.php | 31 +- version/100/adminmenu/paymentmethods.php | 13 +- version/100/adminmenu/tpl/info.tpl | 2 +- version/100/adminmenu/tpl/order.tpl | 6 +- version/100/adminmenu/tpl/orders.tpl | 5 +- version/100/adminmenu/tpl/paymentmethods.tpl | 2 +- version/100/class/Helper.php | 167 ++++---- version/100/class/Model/Payment.php | 20 +- version/100/class/Mollie.php | 140 +++---- version/100/frontend/131_globalinclude.php | 35 +- version/100/frontend/140_smarty.php | 24 +- version/100/frontend/144_notify.php | 14 +- version/100/frontend/181_sync.php | 25 +- version/100/paymentmethod/JTLMollie.php | 393 ++++++++++--------- version/100/sql/100.sql | 36 +- version/101/adminmenu/info.php | 26 +- version/101/adminmenu/orders.php | 31 +- version/101/adminmenu/paymentmethods.php | 13 +- version/101/adminmenu/tpl/info.tpl | 2 +- version/101/adminmenu/tpl/order.tpl | 6 +- version/101/adminmenu/tpl/orders.tpl | 5 +- version/101/adminmenu/tpl/paymentmethods.tpl | 14 +- version/101/class/Helper.php | 173 ++++---- version/101/class/Model/Payment.php | 20 +- version/101/class/Mollie.php | 57 +-- version/101/frontend/131_globalinclude.php | 35 +- version/101/frontend/140_smarty.php | 24 +- version/101/frontend/144_notify.php | 14 +- version/101/frontend/181_sync.php | 25 +- version/101/paymentmethod/JTLMollie.php | 83 ++-- version/101/sql/100.sql | 22 -- version/102/adminmenu/info.php | 26 +- version/102/adminmenu/orders.php | 31 +- version/102/adminmenu/paymentmethods.php | 10 +- version/102/adminmenu/tpl/info.tpl | 18 +- version/102/adminmenu/tpl/order.tpl | 6 +- version/102/adminmenu/tpl/orders.tpl | 5 +- version/102/adminmenu/tpl/paymentmethods.tpl | 19 +- version/102/class/Helper.php | 173 ++++---- version/102/class/Model/Payment.php | 20 +- version/102/class/Mollie.php | 81 ++-- version/102/frontend/131_globalinclude.php | 35 +- version/102/frontend/140_smarty.php | 24 +- version/102/frontend/144_notify.php | 14 +- version/102/frontend/181_sync.php | 25 +- version/102/paymentmethod/JTLMollie.php | 69 ++-- version/102/sql/100.sql | 22 -- 49 files changed, 1092 insertions(+), 976 deletions(-) delete mode 100644 .gitattributes delete mode 100644 version/101/sql/100.sql delete mode 100644 version/102/sql/100.sql diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index f752126..0000000 --- a/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -* text working-tree-encoding=ISO8859-1 \ No newline at end of file diff --git a/version/100/adminmenu/info.php b/version/100/adminmenu/info.php index 975d723..4cfb99b 100644 --- a/version/100/adminmenu/info.php +++ b/version/100/adminmenu/info.php @@ -1,23 +1,25 @@ assign('defaultTabbertab', \ws_mollie\Helper::getAdminmenu('Info')); - \ws_mollie\Helper::selfupdate(); + Shop::Smarty()->assign('defaultTabbertab', Helper::getAdminmenu('Info')); + Helper::selfupdate(); } $svgQuery = http_build_query([ - 'p' => \ws_mollie\Helper::oPlugin()->cPluginID, - 'v' => \ws_mollie\Helper::oPlugin()->nVersion, + 'p' => Helper::oPlugin()->cPluginID, + 'v' => Helper::oPlugin()->nVersion, 's' => defined('APPLICATION_VERSION') ? APPLICATION_VERSION : JTL_VERSION, - 'd' => \ws_mollie\Helper::getDomain(), + 'd' => Helper::getDomain(), 'php' => PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION . '.' . PHP_RELEASE_VERSION, ]); - echo ""; + echo ""; echo "
" . "
" . " " . @@ -37,15 +39,15 @@ ''; try { - $latestRelease = \ws_mollie\Helper::getLatestRelease(array_key_exists('update', $_REQUEST)); - if ((int)\ws_mollie\Helper::oPlugin()->nVersion < (int)$latestRelease->version) { + $latestRelease = Helper::getLatestRelease(array_key_exists('update', $_REQUEST)); + if ((int)Helper::oPlugin()->nVersion < (int)$latestRelease->version) { Shop::Smarty()->assign('update', $latestRelease); } - } catch (\Exception $e) { + } catch (Exception $e) { } - Shop::Smarty()->display(\ws_mollie\Helper::oPlugin()->cAdminmenuPfad . '/tpl/info.tpl'); + Shop::Smarty()->display(Helper::oPlugin()->cAdminmenuPfad . '/tpl/info.tpl'); } catch (Exception $e) { echo "
Fehler: {$e->getMessage()}
"; - \ws_mollie\Helper::logExc($e); + Helper::logExc($e); } diff --git a/version/100/adminmenu/orders.php b/version/100/adminmenu/orders.php index 6d0a67c..891f42a 100644 --- a/version/100/adminmenu/orders.php +++ b/version/100/adminmenu/orders.php @@ -1,8 +1,13 @@ 'danger', 'text' => 'Keine ID angeben!']; break; } - $payment = \ws_mollie\Model\Payment::getPaymentMollie($_REQUEST['id']); + $payment = Payment::getPaymentMollie($_REQUEST['id']); if (!$payment) { $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; break; } $order = JTLMollie::API()->orders->get($_REQUEST['id']); - if ($order->status == \Mollie\Api\Types\OrderStatus::STATUS_CANCELED) { + if ($order->status == OrderStatus::STATUS_CANCELED) { $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung bereits storniert']; break; } $refund = JTLMollie::API()->orderRefunds->createFor($order, ['lines' => []]); - \ws_mollie\Mollie::JTLMollie()->doLog("Order refunded:
" . print_r($refund, 1) . "
", '$' . $payment->kID . '#' . $payment->kBestellung . '§' . $payment->cOrderNumber, LOGLEVEL_NOTICE); + Mollie::JTLMollie()->doLog("Order refunded:
" . print_r($refund, 1) . "
", '$' . $payment->kID . '#' . $payment->kBestellung . '§' . $payment->cOrderNumber, LOGLEVEL_NOTICE); goto order; break; @@ -38,18 +43,18 @@ $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; break; } - $payment = \ws_mollie\Model\Payment::getPaymentMollie($_REQUEST['id']); + $payment = Payment::getPaymentMollie($_REQUEST['id']); if (!$payment) { $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; break; } $order = JTLMollie::API()->orders->get($_REQUEST['id']); - if ($order->status == \Mollie\Api\Types\OrderStatus::STATUS_CANCELED) { + if ($order->status == OrderStatus::STATUS_CANCELED) { $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung bereits storniert']; break; } $cancel = JTLMollie::API()->orders->cancel($order->id); - \ws_mollie\Mollie::JTLMollie()->doLog("Order canceled:
" . print_r($cancel, 1) . "
", '$' . $payment->kID . '#' . $payment->kBestellung . '§' . $payment->cOrderNumber, LOGLEVEL_NOTICE); + Mollie::JTLMollie()->doLog("Order canceled:
" . print_r($cancel, 1) . "
", '$' . $payment->kID . '#' . $payment->kBestellung . '§' . $payment->cOrderNumber, LOGLEVEL_NOTICE); goto order; break; @@ -58,13 +63,13 @@ $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; break; } - $payment = \ws_mollie\Model\Payment::getPaymentMollie($_REQUEST['id']); + $payment = Payment::getPaymentMollie($_REQUEST['id']); if (!$payment) { $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; break; } $order = JTLMollie::API()->orders->get($_REQUEST['id']); - if ($order->status !== \Mollie\Api\Types\OrderStatus::STATUS_AUTHORIZED && $order->status !== \Mollie\Api\Types\OrderStatus::STATUS_SHIPPING) { + if ($order->status !== OrderStatus::STATUS_AUTHORIZED && $order->status !== OrderStatus::STATUS_SHIPPING) { $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Nur autorisierte Zahlungen können erfasst werden!']; break; } @@ -89,7 +94,7 @@ // CAPTURE ALL $shipment = JTLMollie::API()->shipments->createFor($order, $options); $ordersMsgs[] = (object)['type' => 'success', 'text' => 'Zahlung wurde erfolgreich erfasst!']; - \ws_mollie\Mollie::JTLMollie()->doLog('Shipment created
' . print_r(['options' => $options, 'shipment' => $shipment], 1) . '
', $logData); + Mollie::JTLMollie()->doLog('Shipment created
' . print_r(['options' => $options, 'shipment' => $shipment], 1) . '
', $logData); goto order; case 'order': @@ -100,7 +105,7 @@ } $order = JTLMollie::API()->orders->get($_REQUEST['id']); - $payment = \ws_mollie\Model\Payment::getPaymentMollie($_REQUEST['id']); + $payment = Payment::getPaymentMollie($_REQUEST['id']); if ($payment) { $oBestellung = new Bestellung($payment->kBestellung, false); //\ws_mollie\Model\Payment::updateFromPayment($order, $oBestellung->kBestellung); @@ -137,7 +142,7 @@ Shop::Smarty()->assign('payments', $payments) ->assign('ordersMsgs', $ordersMsgs) ->assign('admRoot', str_replace('http:', '', $oPlugin->cAdminmenuPfadURL)) - ->assign('hasAPIKey', trim(\ws_mollie\Helper::getSetting("api_key")) !== ''); + ->assign('hasAPIKey', trim(Helper::getSetting("api_key")) !== ''); Shop::Smarty()->display($oPlugin->cAdminmenuPfad . '/tpl/orders.tpl'); } catch (Exception $e) { @@ -145,5 +150,5 @@ "{$e->getMessage()}
" . "
{$e->getFile()}:{$e->getLine()}
{$e->getTraceAsString()}
" . ""; - \ws_mollie\Helper::logExc($e); + Helper::logExc($e); } diff --git a/version/100/adminmenu/paymentmethods.php b/version/100/adminmenu/paymentmethods.php index ac1ec56..ae01887 100644 --- a/version/100/adminmenu/paymentmethods.php +++ b/version/100/adminmenu/paymentmethods.php @@ -1,8 +1,11 @@ setApiKey(\ws_mollie\Helper::getSetting("api_key")); + $mollie = new MollieApiClient(); + $mollie->setApiKey(Helper::getSetting("api_key")); $profile = $mollie->profiles->get('me'); - $methods = $mollie->methods->all([ + $methods = $mollie->methods->allAvailable([ 'locale' => 'de_DE', 'include' => 'pricing', ]); @@ -24,5 +27,5 @@ Shop::Smarty()->display($oPlugin->cAdminmenuPfad . '/tpl/paymentmethods.tpl'); } catch (Exception $e) { echo "
{$e->getMessage()}
"; - \ws_mollie\Helper::logExc($e); + Helper::logExc($e); } diff --git a/version/100/adminmenu/tpl/info.tpl b/version/100/adminmenu/tpl/info.tpl index eb5ae3a..16afe75 100644 --- a/version/100/adminmenu/tpl/info.tpl +++ b/version/100/adminmenu/tpl/info.tpl @@ -2,7 +2,7 @@
{if isset($update)} -
diff --git a/version/100/adminmenu/tpl/order.tpl b/version/100/adminmenu/tpl/order.tpl index d591bb1..49b4517 100644 --- a/version/100/adminmenu/tpl/order.tpl +++ b/version/100/adminmenu/tpl/order.tpl @@ -26,7 +26,7 @@
{/if} - +
@@ -80,7 +80,7 @@ {/if} -
Mollie ID: {$payment->kID}
+
@@ -177,7 +177,7 @@

Log

-
Status
+
{foreach from=$logs item=log}
diff --git a/version/100/adminmenu/tpl/orders.tpl b/version/100/adminmenu/tpl/orders.tpl index 50d5829..3956ef5 100644 --- a/version/100/adminmenu/tpl/orders.tpl +++ b/version/100/adminmenu/tpl/orders.tpl @@ -8,10 +8,11 @@ {if $hasAPIKey == false} - Jetzt kostenlos Mollie Account eröffnen! + Jetzt kostenlos Mollie Account eröffnen! {else} - +
diff --git a/version/100/adminmenu/tpl/paymentmethods.tpl b/version/100/adminmenu/tpl/paymentmethods.tpl index cf3770e..bf7f607 100644 --- a/version/100/adminmenu/tpl/paymentmethods.tpl +++ b/version/100/adminmenu/tpl/paymentmethods.tpl @@ -1,5 +1,5 @@

Account Status

-
BestellNr.
+
diff --git a/version/100/class/Helper.php b/version/100/class/Helper.php index 8a6101c..cdfcd6a 100644 --- a/version/100/class/Helper.php +++ b/version/100/class/Helper.php @@ -3,31 +3,38 @@ namespace ws_mollie { + use Exception; + use Jtllog; + use PclZip; + use Plugin; + use Shop; + use stdClass; + if (!class_exists('ws_mollie\Helper')) { /** - * Class Helper - * @package ws_mollie - */ + * Class Helper + * @package ws_mollie + */ final class Helper { /** - * Is ::autoload() already called? - * - * @var bool|null - */ + * Is ::autoload() already called? + * + * @var bool|null + */ private static $_autoload; /** - * @var \Plugin - */ + * @var Plugin + */ private static $oPlugin; /** - * Load Vendor Autoloader - * @return bool - */ + * Load Vendor Autoloader + * @return bool + */ public static function autoload() { if (null === self::$_autoload) { @@ -56,14 +63,14 @@ public static function autoload() } /** - * @throws \Exception - */ + * @throws Exception + */ public static function selfupdate() { if (function_exists('opcache_reset')) { opcache_reset(); } - + // 0. GET RELEASE INFO $release = self::getLatestRelease(true); $url = $release->short_url != '' ? $release->short_url : $release->full_url; @@ -73,21 +80,21 @@ public static function selfupdate() // 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!'); + 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!!"); + throw new Exception("cURL ist nicht verf�gbar!!"); } if (!is_writable($tmpDir)) { - throw new \Exception("Tempor�res Verzeichnis_'{$tmpDir}' ist nicht beschreibbar!"); + 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!"); + 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!"); + throw new Exception("Tempor�re Datei '" . $tmpDir . $filename . "' konnte nicht gel�scht werden!"); } } @@ -102,35 +109,35 @@ public static function selfupdate() curl_close($ch); fclose($fp); if ($info['http_code'] !== 200) { - throw new \Exception("Unerwarteter Status Code '" . $info['http_code'] . "'!"); + 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'] . "'!"); + 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); + $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!"); + throw new Exception("Das Zip-Archiv ist leider ung�ltig!"); } else { $unzipPath = PFAD_ROOT . PFAD_PLUGIN; $res = $zip->extract(PCLZIP_OPT_PATH, $unzipPath); if ($res !== 0) { - header('Location: ' . \Shop::getURL() . DIRECTORY_SEPARATOR . PFAD_ADMIN . 'pluginverwaltung.php', true); + header('Location: ' . Shop::getURL() . DIRECTORY_SEPARATOR . PFAD_ADMIN . 'pluginverwaltung.php', true); } else { - throw new \Exception('Entpacken fehlgeschlagen: ' . $zip->errorCode()); + throw new Exception('Entpacken fehlgeschlagen: ' . $zip->errorCode()); } } } /** - * @param bool $force - * @return mixed - * @throws \Exception - */ + * @param bool $force + * @return mixed + * @throws Exception + */ public static function getLatestRelease($force = false) { $lastCheck = (int)self::getSetting(__NAMESPACE__ . '_upd'); @@ -148,11 +155,11 @@ public static function getLatestRelease($force = false) $statusCode = (int)curl_getinfo($curl, CURLINFO_HTTP_CODE); @curl_close($curl); if ($statusCode !== 200) { - throw new \Exception(__NAMESPACE__ . ': Could not fetch release info: ' . $statusCode); + 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); + 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)); @@ -163,10 +170,10 @@ public static function getLatestRelease($force = false) } /** - * Register PSR-4 autoloader - * Licence-Check - * @return bool - */ + * Register PSR-4 autoloader + * Licence-Check + * @return bool + */ public static function init() { ini_set('xdebug.default_enable', defined('WS_XDEBUG_ENABLED')); @@ -174,23 +181,23 @@ public static function init() } /** - * Sets a Plugin Setting and saves it to the DB - * - * @param $name - * @param $value - * @return int - */ + * 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 = 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); + $return = Shop::DB()->updateRow('tplugineinstellungen', ['kPlugin', 'cName'], [$setting->kPlugin, $setting->cName], $setting); } else { - $return = \Shop::DB()->insertRow('tplugineinstellungen', $setting); + $return = Shop::DB()->insertRow('tplugineinstellungen', $setting); } self::oPlugin()->oPluginEinstellungAssoc_arr[$name] = $value; self::oPlugin(true); // invalidate cache @@ -198,27 +205,27 @@ public static function setSetting($name, $value) } /** - * Get Plugin Object - * - * @param bool $force disable Cache - * @return \Plugin|null - */ + * 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); + self::$oPlugin = new Plugin(self::oPlugin(false)->kPlugin, true); } elseif (null === self::$oPlugin) { - self::$oPlugin = \Plugin::getPluginById(__NAMESPACE__); + self::$oPlugin = Plugin::getPluginById(__NAMESPACE__); } return self::$oPlugin; } /** - * get a Plugin setting - * - * @param $name - * @return null|mixed - */ + * get a Plugin setting + * + * @param $name + * @return null|mixed + */ public static function getSetting($name) { if (array_key_exists($name, self::oPlugin()->oPluginEinstellungAssoc_arr)) { @@ -228,11 +235,11 @@ public static function getSetting($name) } /** - * Get Domain frpm URL_SHOP without www. - * - * @param string $url - * @return string - */ + * Get Domain frpm URL_SHOP without www. + * + * @param string $url + * @return string + */ public static function getDomain($url = URL_SHOP) { $matches = array(); @@ -241,40 +248,40 @@ public static function getDomain($url = URL_SHOP) } /** - * @return mixed - */ + * @return mixed + */ private static function _masterMail() { - $settings = \Shop::getSettings(array(CONF_EMAILS)); + $settings = Shop::getSettings(array(CONF_EMAILS)); return $settings['emails']['email_master_absender']; } /** - * @param \Exception $exc - * @param bool $trace - * @return void - */ - public static function logExc(\Exception $exc, $trace = true) + * @param Exception $exc + * @param bool $trace + * @return void + */ + public static function logExc(Exception $exc, $trace = true) { - \Jtllog::writeLog(__NAMESPACE__ . ': ' . $exc->getMessage() . ($trace ? ' - ' . $exc->getTraceAsString() : '')); + Jtllog::writeLog(__NAMESPACE__ . ': ' . $exc->getMessage() . ($trace ? ' - ' . $exc->getTraceAsString() : '')); } /** - * Checks if admin session is loaded - * - * @return bool - */ + * 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 - */ + * Returns kAdminmenu ID for given Title, used for Tabswitching + * + * @param $name string CustomLink Title + * @return int + */ public static function getAdminmenu($name) { $kPluginAdminMenu = 0; diff --git a/version/100/class/Model/Payment.php b/version/100/class/Model/Payment.php index 8dea11d..4317113 100644 --- a/version/100/class/Model/Payment.php +++ b/version/100/class/Model/Payment.php @@ -2,11 +2,15 @@ namespace ws_mollie\Model; +use Bestellung; +use Mollie\Api\Resources\Order; +use Shop; + class Payment extends AbstractModel { const TABLE = 'xplugin_ws_mollie_payments'; - public static function updateFromPayment(\Mollie\Api\Resources\Order $oMolliePayment, $kBestellung = null, $hash = null) + public static function updateFromPayment(Order $oMolliePayment, $kBestellung = null, $hash = null) { $data = [ ':kID' => $oMolliePayment->id, @@ -35,7 +39,7 @@ public static function updateFromPayment(\Mollie\Api\Resources\Order $oMolliePay ':fAmountRefunded1' => $oMolliePayment->amountRefunded ? $oMolliePayment->amountRefunded->value : null, ':dCreatedAt' => $oMolliePayment->createdAt ? date('Y-m-d H:i:s', strtotime($oMolliePayment->createdAt)) : null, ]; - return \Shop::DB()->executeQueryPrepared( + 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', @@ -46,27 +50,27 @@ public static function updateFromPayment(\Mollie\Api\Resources\Order $oMolliePay public static function getPayment($kBestellung) { - $payment = \Shop::DB()->executeQueryPrepared('SELECT * FROM ' . self::TABLE . ' WHERE kBestellung = :kBestellung', [':kBestellung' => $kBestellung], 1); + $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); + $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); + $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); + $payment->oBestellung = new Bestellung($payment->kBestellung, false); } return $payment; } public static function getPaymentHash($cHash) { - $payment = \Shop::DB()->executeQueryPrepared('SELECT * FROM ' . self::TABLE . ' WHERE cHash = :cHash', [':cHash' => $cHash], 1); + $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); + $payment->oBestellung = new Bestellung($payment->kBestellung, false); } return $payment; } diff --git a/version/100/class/Mollie.php b/version/100/class/Mollie.php index fd97087..9a0a88d 100644 --- a/version/100/class/Mollie.php +++ b/version/100/class/Mollie.php @@ -8,13 +8,24 @@ namespace ws_mollie; +use Bestellung; +use Exception; +use JTLMollie; +use Lieferschein; +use Lieferscheinpos; use Mollie\Api\Resources\Order; use Mollie\Api\Types\OrderStatus; +use Shop; +use Shopsetting; +use stdClass; +use WarenkorbPos; use ws_mollie\Model\Payment; abstract class Mollie { + protected static $_jtlmollie; + /** * @param $kBestellung * @param bool $redirect @@ -22,15 +33,15 @@ abstract class Mollie */ public static function getOrderCompletedRedirect($kBestellung, $redirect = true) { - $mode = \Shopsetting::getInstance()->getValue(CONF_KAUFABWICKLUNG, 'bestellabschluss_abschlussseite'); + $mode = Shopsetting::getInstance()->getValue(CONF_KAUFABWICKLUNG, 'bestellabschluss_abschlussseite'); - $bestellid = \Shop::DB()->select("tbestellid ", 'kBestellung', (int)$kBestellung); - $url = \Shop::getURL() . '/bestellabschluss.php?i=' . $bestellid->cId; + $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; + $bestellstatus = Shop::DB()->select('tbestellstatus', 'kBestellung', (int)$kBestellung); + $url = Shop::getURL() . '/status.php?uid=' . $bestellstatus->cUID; } if ($redirect) { @@ -40,73 +51,21 @@ public static function getOrderCompletedRedirect($kBestellung, $redirect = true) return $url; } - protected static $_jtlmollie; - - /** - * @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; - } - - /** * @param Order $order * @param $kBestellung * @param bool $newStatus * @return array - * @throws \Exception + * @throws Exception */ public static function getShipmentOptions(Order $order, $kBestellung, $newStatus = false) { if (!$order || !$kBestellung) { - throw new \Exception('Mollie::getShipmentOptions: order and kBestellung are required!'); + throw new Exception('Mollie::getShipmentOptions: order and kBestellung are required!'); } - $oBestellung = new \Bestellung($kBestellung, true); + $oBestellung = new Bestellung($kBestellung, true); if ($newStatus === false) { $newStatus = $oBestellung->cStatus; } @@ -114,7 +73,7 @@ public static function getShipmentOptions(Order $order, $kBestellung, $newStatus // Tracking Data if ($oBestellung->cTracking) { - $tracking = new \stdClass(); + $tracking = new stdClass(); $tracking->carrier = $oBestellung->cVersandartName; $tracking->url = $oBestellung->cTrackingURL; $tracking->code = $oBestellung->cTracking; @@ -152,27 +111,57 @@ public static function getShipmentOptions(Order $order, $kBestellung, $newStatus return $options; } + /** + * 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; + } /** * @param Order $order * @param null $kBestellung * @return bool - * @throws \Exception + * @throws Exception */ public static function handleOrder(Order $order, $kBestellung) { $logData = '$' . $order->id . '#' . $kBestellung . "§" . $order->orderNumber; - $oBestellung = new \Bestellung($kBestellung); + $oBestellung = new Bestellung($kBestellung); if ($oBestellung->kBestellung) { $order->orderNumber = $oBestellung->cBestellNr; Payment::updateFromPayment($order, $kBestellung); - - $oIncomingPayment = \Shop::DB()->executeQueryPrepared("SELECT * FROM tzahlungseingang WHERE cHinweis = :cHinweis AND kBestellung = :kBestellung", [':cHinweis' => $order->id, ':kBestellung' => $oBestellung->kBestellung], 1); + + $oIncomingPayment = Shop::DB()->executeQueryPrepared("SELECT * FROM tzahlungseingang WHERE cHinweis = :cHinweis AND kBestellung = :kBestellung", [':cHinweis' => $order->id, ':kBestellung' => $oBestellung->kBestellung], 1); if (!$oIncomingPayment) { - $oIncomingPayment = new \stdClass(); + $oIncomingPayment = new stdClass(); } - + // 2. Check PaymentStatus switch ($order->status) { case OrderStatus::STATUS_PAID: @@ -199,4 +188,21 @@ public static function handleOrder(Order $order, $kBestellung) } return false; } + + /** + * @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; + } } diff --git a/version/100/frontend/131_globalinclude.php b/version/100/frontend/131_globalinclude.php index 118f6b6..45d4c6f 100644 --- a/version/100/frontend/131_globalinclude.php +++ b/version/100/frontend/131_globalinclude.php @@ -1,32 +1,37 @@ executeQueryPrepared("SELECT * FROM " . \ws_mollie\Model\Payment::TABLE . " WHERE cHash = :cHash", [':cHash' => $_REQUEST['mollie']], 1); + $payment = Shop::DB()->executeQueryPrepared("SELECT * FROM " . \ws_mollie\Model\Payment::TABLE . " WHERE cHash = :cHash", [':cHash' => $_REQUEST['mollie']], 1); // Bestellung finalized, redirect to status/completion page if ((int)$payment->kBestellung) { $logData = '$' . $payment->kID . '#' . $payment->kBestellung . "§" . $payment->cOrderNumber; - \ws_mollie\Mollie::JTLMollie()->doLog('Bestellung finalized => redirect abschluss/status', $logData); + Mollie::JTLMollie()->doLog('Bestellung finalized => redirect abschluss/status', $logData); $order = JTLMollie::API()->orders->get($payment->kID, ['embed' => 'payments']); - \ws_mollie\Mollie::handleOrder($order, $payment->kBestellung); - \ws_mollie\Mollie::getOrderCompletedRedirect($payment->kBestellung, true); + Mollie::handleOrder($order, $payment->kBestellung); + Mollie::getOrderCompletedRedirect($payment->kBestellung, true); } elseif ($payment) { // payment, but no order => finalize it require_once __DIR__ . '/../paymentmethod/JTLMollie.php'; $order = JTLMollie::API()->orders->get($payment->kID, ['embed' => 'payments']); $logData = '$' . $order->id . '#' . $payment->kBestellung . "§" . $payment->cOrderNumber; // GET NEWEST PAYMENT: - /** @var \Mollie\Api\Resources\Paymentt $_payment */ + /** @var Payment $_payment */ $_payment = null; if ($order->payments()) { - /** @var \Mollie\Api\Resources\Payment $p */ + /** @var Payment $p */ foreach ($order->payments() as $p) { if (!$_payment) { $_payment = $p; @@ -41,8 +46,8 @@ // finalize only, if order is not canceld/expired if ($order && !$order->isCanceled() && !$order->isExpired()) { // finalize only if payment is not expired/canceled,failed or open - if ($_payment && !in_array($_payment->status, [\Mollie\Api\Types\PaymentStatus::STATUS_EXPIRED, \Mollie\Api\Types\PaymentStatus::STATUS_CANCELED, \Mollie\Api\Types\PaymentStatus::STATUS_OPEN, \Mollie\Api\Types\PaymentStatus::STATUS_FAILED, \Mollie\Api\Types\PaymentStatus::STATUS_CANCELED])) { - \ws_mollie\Mollie::JTLMollie()->doLog('Bestellung open => finalize', $logData); + if ($_payment && !in_array($_payment->status, [PaymentStatus::STATUS_EXPIRED, PaymentStatus::STATUS_CANCELED, PaymentStatus::STATUS_OPEN, PaymentStatus::STATUS_FAILED, PaymentStatus::STATUS_CANCELED])) { + Mollie::JTLMollie()->doLog('Bestellung open => finalize', $logData); $session = Session::getInstance(); /** @noinspection PhpIncludeInspection */ require_once PFAD_ROOT . 'includes/bestellabschluss_inc.php'; @@ -50,18 +55,18 @@ require_once PFAD_ROOT . 'includes/mailTools.php'; $oBestellung = fakeBestellung(); $oBestellung = finalisiereBestellung(); - \ws_mollie\Mollie::JTLMollie()->doLog('Bestellung finalized => redirect
' . print_r($order, 1) . '
', $logData, LOGLEVEL_DEBUG); - \ws_mollie\Mollie::handleOrder($order, $oBestellung->kBestellung); - \ws_mollie\Mollie::getOrderCompletedRedirect($oBestellung->kBestellung, true); + Mollie::JTLMollie()->doLog('Bestellung finalized => redirect
' . print_r($order, 1) . '
', $logData, LOGLEVEL_DEBUG); + Mollie::handleOrder($order, $oBestellung->kBestellung); + Mollie::getOrderCompletedRedirect($oBestellung->kBestellung, true); } else { - \ws_mollie\Mollie::JTLMollie()->doLog('Invalid Payment
' . print_r($payment, 1) . '
', $logData, LOGLEVEL_ERROR); + Mollie::JTLMollie()->doLog('Invalid Payment
' . print_r($payment, 1) . '
', $logData, LOGLEVEL_ERROR); } } else { - \ws_mollie\Mollie::JTLMollie()->doLog('Invalid Order
' . print_r($order, 1) . '
', $logData, LOGLEVEL_ERROR); + Mollie::JTLMollie()->doLog('Invalid Order
' . print_r($order, 1) . '
', $logData, LOGLEVEL_ERROR); } } } ob_end_flush(); } catch (Exception $e) { - \ws_mollie\Helper::logExc($e); + Helper::logExc($e); } diff --git a/version/100/frontend/140_smarty.php b/version/100/frontend/140_smarty.php index 3f74d4f..2735ee7 100644 --- a/version/100/frontend/140_smarty.php +++ b/version/100/frontend/140_smarty.php @@ -1,10 +1,12 @@ append( - - <<append(<< /* MOLLIE CHECKOUT STYLES*/ #fieldset-payment .form-group > div:hover, #checkout-shipping-payment .form-group > div:hover { @@ -46,8 +44,8 @@ float: right; } -CSS -); +HTML + ); } catch (Exception $e) { - \ws_mollie\Helper::logExc($e); + Helper::logExc($e); } diff --git a/version/100/frontend/144_notify.php b/version/100/frontend/144_notify.php index 8856259..a2af9f2 100644 --- a/version/100/frontend/144_notify.php +++ b/version/100/frontend/144_notify.php @@ -6,22 +6,26 @@ * - ELSE weiter mit der notify.php */ +use ws_mollie\Helper; +use ws_mollie\Model\Payment; +use ws_mollie\Mollie; + if (array_key_exists('hash', $_REQUEST)) { require_once __DIR__ . '/../class/Helper.php'; try { - \ws_mollie\Helper::init(); - $payment = \ws_mollie\Model\Payment::getPaymentHash($_REQUEST['hash']); + Helper::init(); + $payment = Payment::getPaymentHash($_REQUEST['hash']); // If Bestellung already exists, treat as Notification if ($payment && $payment->kBestellung) { require_once __DIR__ . '/../paymentmethod/JTLMollie.php'; $order = JTLMollie::API()->orders->get($payment->kID); $logData = '#' . $payment->kBestellung . '$' . $payment->kID; - \ws_mollie\Mollie::JTLMollie()->doLog('Received Notification
' . print_r([$order, $payment], 1) . '
', $logData); - \ws_mollie\Mollie::handleOrder($order, $payment->kBestellung); + Mollie::JTLMollie()->doLog('Received Notification
' . print_r([$order, $payment], 1) . '
', $logData); + Mollie::handleOrder($order, $payment->kBestellung); // exit to stop execution of notify.php exit(); } } catch (Exception $e) { - \ws_mollie\Helper::logExc($e); + Helper::logExc($e); } } diff --git a/version/100/frontend/181_sync.php b/version/100/frontend/181_sync.php index be2fe16..5fb008e 100644 --- a/version/100/frontend/181_sync.php +++ b/version/100/frontend/181_sync.php @@ -1,33 +1,38 @@ kBestellung && $payment = \ws_mollie\Model\Payment::getPayment($oBestellung->kBestellung)) { + if ($oBestellung->kBestellung && $payment = Payment::getPayment($oBestellung->kBestellung)) { $logData = '#' . $payment->kBestellung . '$' . $payment->kID . "§" . $oBestellung->cBestellNr; - \ws_mollie\Mollie::JTLMollie()->doLog("WAWI Abgleich: HOOK_BESTELLUNGEN_XML_BESTELLSTATUS", $logData); + Mollie::JTLMollie()->doLog("WAWI Abgleich: HOOK_BESTELLUNGEN_XML_BESTELLSTATUS", $logData); try { $order = JTLMollie::API()->orders->get($payment->kID); $order->orderNumber = $oBestellung->cBestellNr; - \ws_mollie\Mollie::handleOrder($order, $oBestellung->kBestellung); + Mollie::handleOrder($order, $oBestellung->kBestellung); if ($order->isCreated() || $order->isPaid() || $order->isAuthorized() || $order->isShipping() || $order->isPending()) { - \ws_mollie\Mollie::JTLMollie()->doLog("Create Shippment:
" . print_r($args_arr, 1) . '
', $logData, LOGLEVEL_DEBUG); - $options = \ws_mollie\Mollie::getShipmentOptions($order, $oBestellung->kBestellung, $status); + Mollie::JTLMollie()->doLog("Create Shippment:
" . print_r($args_arr, 1) . '
', $logData, LOGLEVEL_DEBUG); + $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); - \ws_mollie\Mollie::JTLMollie()->doLog('Shipment created
' . print_r(['options' => $options, 'shipment' => $shipment], 1) . '
', $logData, LOGLEVEL_NOTICE); + Mollie::JTLMollie()->doLog('Shipment created
' . print_r(['options' => $options, 'shipment' => $shipment], 1) . '
', $logData, LOGLEVEL_NOTICE); } else { - \ws_mollie\Mollie::JTLMollie()->doLog('181_sync: options don\'t contain lines
' . print_r([$order, $options], 1) . '
', $logData, LOGLEVEL_ERROR); + Mollie::JTLMollie()->doLog('181_sync: options don\'t contain lines
' . print_r([$order, $options], 1) . '
', $logData, LOGLEVEL_ERROR); } } } catch (Exception $e) { - \ws_mollie\Mollie::JTLMollie()->doLog('Fehler: ' . $e->getMessage() . '
' . print_r($e->getTrace(), 1) . '
', $logData, LOGLEVEL_ERROR); + Mollie::JTLMollie()->doLog('Fehler: ' . $e->getMessage() . '
' . print_r($e->getTrace(), 1) . '
', $logData, LOGLEVEL_ERROR); } } } catch (Exception $e) { - \ws_mollie\Helper::logExc($e); + Helper::logExc($e); } diff --git a/version/100/paymentmethod/JTLMollie.php b/version/100/paymentmethod/JTLMollie.php index 38cbc6d..89509b6 100644 --- a/version/100/paymentmethod/JTLMollie.php +++ b/version/100/paymentmethod/JTLMollie.php @@ -1,10 +1,19 @@ setApiKey(\ws_mollie\Helper::getSetting('api_key')); + if (self::$_helper === null) { + self::$_helper = new ws_mollie\Helper(); } - return self::$_mollie; + return self::$_helper; } - + /** - * @param Bestellung $order - * @param Object $payment (Key, Zahlungsanbieter, Abgeholt, Zeit is set here) - * @return $this - */ + * @param Bestellung $order + * @param Object $payment (Key, Zahlungsanbieter, Abgeholt, Zeit is set here) + * @return $this + */ public function addIncomingPayment($order, $payment) { $model = (object)array_merge([ - 'kBestellung' => (int)$order->kBestellung, + 'kBestellung' => (int)$order->kBestellung, 'cZahlungsanbieter' => empty($order->cZahlungsartName) ? $this->name : $order->cZahlungsartName, - 'fBetrag' => 0, - 'fZahlungsgebuehr' => 0, - 'cISO' => $_SESSION['Waehrung']->cISO, - 'cEmpfaenger' => '', - 'cZahler' => '', - 'dZeit' => 'now()', - 'cHinweis' => '', - 'cAbgeholt' => 'N' + 'fBetrag' => 0, + 'fZahlungsgebuehr' => 0, + 'cISO' => $_SESSION['Waehrung']->cISO, + 'cEmpfaenger' => '', + 'cZahler' => '', + 'dZeit' => 'now()', + 'cHinweis' => '', + 'cAbgeholt' => 'N' ], (array)$payment); if (isset($model->kZahlungseingang) && $model->kZahlungseingang > 0) { Shop::DB()->update('tzahlungseingang', 'kZahlungseingang', $model->kZahlungseingang, $model); @@ -80,17 +89,6 @@ public function addIncomingPayment($order, $payment) return $this; } - /** - * @return \ws_mollie\Helper - */ - public static function Helper() - { - if (self::$_helper === null) { - self::$_helper = new ws_mollie\Helper(); - } - return self::$_helper; - } - /** * @param Bestellung $order * @return PaymentMethod|void @@ -104,6 +102,75 @@ public function setOrderStatusToPaid($order) parent::setOrderStatusToPaid($order); } + /** + * Prepares everything so that the Customer can start the Payment Process. + * Tells Template Engine. + * + * @param Bestellung $order + */ + public function preparePaymentProcess($order) + { + $logData = '#' . $order->kBestellung . "" . $order->cBestellNr; + try { + $payment = Payment::getPayment($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); + exit(); + } + } catch (Exception $e) { + $this->doLog("Get Payment Error: " . $e->getMessage() . ". Create new ORDER...", $logData); + } + + try { + $hash = $this->generateHash($order); + $oMolliePayment = self::API()->orders->create($this->getOrderData($order, $hash)); + $_SESSION['oMolliePayment'] = $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($hash)); + Shop::Smarty()->assign('oMolliePayment', $oMolliePayment); + if (!$this->duringCheckout) { + Session::getInstance()->cleanUp(); + } + header('Location: ' . $oMolliePayment->getCheckoutUrl()); + exit(); + } catch (ApiException $e) { + Shop::Smarty()->assign('oMollieException', $e); + $this->doLog("Create Payment Error: " . $e->getMessage() . '
' . print_r($e->getTrace(), 1) . '
', $logData); + } + } + + /** + * @param string $msg + * @param null $data + * @param int $level + * @return $this + */ + public function doLog($msg, $data = null, $level = LOGLEVEL_NOTICE) + { + ZahlungsLog::add($this->moduleID, $msg, $data, $level); + + return $this; + } + + /** + * @return MollieApiClient + * @throws ApiException + * @throws IncompatiblePlatform + */ + public static function API() + { + if (self::$_mollie === null) { + self::$_mollie = new MollieApiClient(); + self::$_mollie->setApiKey(Helper::getSetting('api_key')); + } + return self::$_mollie; + } + /** * @param Bestellung $order * @param $hash @@ -113,7 +180,7 @@ protected function getOrderData(Bestellung $order, $hash) { $locale = self::getLocale($_SESSION['cISOSprache'], $_SESSION['Kunde']->cLand); $data = [ - 'locale' => $locale ? : 'de_DE', + 'locale' => $locale ?: 'de_DE', 'amount' => (object)[ 'currency' => $order->Waehrung->cISO, 'value' => number_format($order->fGesamtsummeKundenwaehrung, 2, '.', ''), @@ -157,39 +224,39 @@ protected function getOrderData(Bestellung $order, $hash) $line->name = utf8_encode($oPosition->cName); $line->quantity = $oPosition->nAnzahl; $line->unitPrice = (object)[ - 'value' => number_format($order->Waehrung->fFaktor * ($oPosition->fPreis * ((float)$oPosition->fMwSt / 100 + 1)), 2, '.', ''), - 'currency' => $order->Waehrung->cISO, - ]; + 'value' => number_format($order->Waehrung->fFaktor * ($oPosition->fPreis * ((float)$oPosition->fMwSt / 100 + 1)), 2, '.', ''), + 'currency' => $order->Waehrung->cISO, + ]; $line->totalAmount = (object)[ - 'value' => number_format($oPosition->nAnzahl * (float)$line->unitPrice->value, 2, '.', ''), - 'currency' => $order->Waehrung->cISO, - ]; + 'value' => number_format($oPosition->nAnzahl * (float)$line->unitPrice->value, 2, '.', ''), + 'currency' => $order->Waehrung->cISO, + ]; $line->vatRate = $oPosition->fMwSt; $line->vatAmount = (object)[ 'value' => number_format($line->totalAmount->value - ($line->totalAmount->value / (1 + (float)$oPosition->fMwSt / 100)), 2, '.', ''), 'currency' => $order->Waehrung->cISO, ]; - + switch ((int)$oPosition->nPosTyp) { case (int)C_WARENKORBPOS_TYP_GRATISGESCHENK: case (int)C_WARENKORBPOS_TYP_ARTIKEL: - $line->type = \Mollie\Api\Types\OrderLineType::TYPE_PHYSICAL; + $line->type = OrderLineType::TYPE_PHYSICAL; $line->sku = $oPosition->cArtNr; break; case (int)C_WARENKORBPOS_TYP_VERSANDPOS: - $line->type = \Mollie\Api\Types\OrderLineType::TYPE_SHIPPING_FEE; + $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 = \Mollie\Api\Types\OrderLineType::TYPE_SURCHARGE; + $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 = \Mollie\Api\Types\OrderLineType::TYPE_DISCOUNT; + $line->type = OrderLineType::TYPE_DISCOUNT; break; } if (isset($line->type)) { @@ -199,7 +266,7 @@ protected function getOrderData(Bestellung $order, $hash) if ((int)$order->GuthabenNutzen === 1 && $order->fGuthaben < 0) { $line = new stdClass(); - $line->type = \Mollie\Api\Types\OrderLineType::TYPE_STORE_CREDIT; + $line->type = OrderLineType::TYPE_STORE_CREDIT; $line->name = 'Guthaben'; $line->quantity = 1; $line->unitPrice = (object)[ @@ -231,7 +298,7 @@ protected function getOrderData(Bestellung $order, $hash) $diff = (round((float)$data['amount']->value - $sum, 2)); if ($diff != 0) { $line = new stdClass(); - $line->type = $diff > 0 ? \Mollie\Api\Types\OrderLineType::TYPE_SURCHARGE : \Mollie\Api\Types\OrderLineType::TYPE_DISCOUNT; + $line->type = $diff > 0 ? OrderLineType::TYPE_SURCHARGE : OrderLineType::TYPE_DISCOUNT; $line->name = 'Rundungsausgleich'; $line->quantity = 1; $line->unitPrice = (object)[ @@ -258,61 +325,54 @@ protected function getOrderData(Bestellung $order, $hash) return $data; } - /** - * Prepares everything so that the Customer can start the Payment Process. - * Tells Template Engine. - * - * @param Bestellung $order - */ - public function preparePaymentProcess($order) + public static function getLocale($cISOSprache, $country = null) { - $logData = '#' . $order->kBestellung . "" . $order->cBestellNr; - try { - $payment = \ws_mollie\Model\Payment::getPayment($order->kBestellung); - if ($payment && in_array($payment->cStatus, [\Mollie\Api\Types\OrderStatus::STATUS_CREATED]) && $payment->cCheckoutURL) { - $logData .= '$' . $payment->kID; - if (!$this->duringCheckout) { - Session::getInstance()->cleanUp(); + switch ($cISOSprache) { + case "ger": + if ($country === "AT") { + return "de_AT"; } - header('Location: ' . $payment->cCheckoutURL); - exit(); - } - } catch (\Exception $e) { - $this->doLog("Get Payment Error: " . $e->getMessage() . ". Create new ORDER...", $logData); - } - - try { - $hash = $this->generateHash($order); - $oMolliePayment = self::API()->orders->create($this->getOrderData($order, $hash)); - $_SESSION['oMolliePayment'] = $oMolliePayment; - $logData .= '$' . $oMolliePayment->id; - $this->doLog('Mollie Create Payment Redirect: ' . $oMolliePayment->getCheckoutUrl() . "
" . print_r($oMolliePayment, 1) . "
", $logData, LOGLEVEL_DEBUG); - \ws_mollie\Model\Payment::updateFromPayment($oMolliePayment, $order->kBestellung, md5($hash)); - Shop::Smarty()->assign('oMolliePayment', $oMolliePayment); - if (!$this->duringCheckout) { - Session::getInstance()->cleanUp(); - } - header('Location: ' . $oMolliePayment->getCheckoutUrl()); - exit(); - } catch (\Mollie\Api\Exceptions\ApiException $e) { - Shop::Smarty()->assign('oMollieException', $e); - $this->doLog("Create Payment Error: " . $e->getMessage() . '
' . print_r($e->getTrace(), 1) . '
', $logData); + if ($country === "CH") { + return "de_CH"; + } + return "de_DE"; + case "eng": + return "en_US"; + 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"; } } - /** - * @param string $msg - * @param null $data - * @param int $level - * @return $this - */ - public function doLog($msg, $data = null, $level = LOGLEVEL_NOTICE) - { - ZahlungsLog::add($this->moduleID, $msg, $data, $level); - - return $this; - } - /** * @param Bestellung $order * @param string $hash @@ -320,19 +380,18 @@ public function doLog($msg, $data = null, $level = LOGLEVEL_NOTICE) */ public function handleNotification($order, $hash, $args) { - \ws_mollie\Helper::autoload(); + Helper::autoload(); $logData = '#' . $order->kBestellung . "" . $order->cBestellNr; $this->doLog('Received Notification
' . print_r([$hash, $args], 1) . '
', $logData, LOGLEVEL_NOTICE); try { $oMolliePayment = self::API()->orders->get($args['id']); - \ws_mollie\Mollie::handleOrder($oMolliePayment, $order->kBestellung); - } catch (\Exception $e) { + Mollie::handleOrder($oMolliePayment, $order->kBestellung); + } catch (Exception $e) { $this->doLog('handleNotification: ' . $e->getMessage(), $logData); } } - /** * @param Bestellung $order * @param string $hash @@ -344,13 +403,13 @@ public function finalizeOrder($order, $hash, $args) { $logData = '#' . $order->kBestellung . "" . $order->cBestellNr; try { - \ws_mollie\Helper::autoload(); + Helper::autoload(); $oMolliePayment = self::API()->orders->get($args['id'], ['embed' => 'payments']); $logData .= '$' . $oMolliePayment->id; $this->doLog('Received Notification Finalize Order
' . print_r([$hash, $args, $oMolliePayment], 1) . '
', $logData, LOGLEVEL_DEBUG); - \ws_mollie\Model\Payment::updateFromPayment($oMolliePayment, $order->kBestellung); - return in_array($oMolliePayment->status, [\Mollie\Api\Types\OrderStatus::STATUS_PAID, \Mollie\Api\Types\OrderStatus::STATUS_AUTHORIZED, \Mollie\Api\Types\OrderStatus::STATUS_PENDING, \Mollie\Api\Types\OrderStatus::STATUS_COMPLETED]); - } catch (\Exception $e) { + Payment::updateFromPayment($oMolliePayment, $order->kBestellung); + return in_array($oMolliePayment->status, [OrderStatus::STATUS_PAID, OrderStatus::STATUS_AUTHORIZED, OrderStatus::STATUS_PENDING, OrderStatus::STATUS_COMPLETED]); + } catch (Exception $e) { $this->doLog($e->getMessage(), $logData); } return false; @@ -364,60 +423,33 @@ public function canPayAgain() return true; } - - public static function getLocale($cISOSprache, $country = null) + /** + * determines, if the payment method can be selected in the checkout process + * + * @return bool + */ + public function isSelectable() { - switch ($cISOSprache) { - case "ger": - if ($country === "AT") { - return "de_AT"; - } - if ($country === "CH") { - return "de_CH"; - } - return "de_DE"; - case "eng": - return "en_US"; - case "fre": - if ($country === "BE") { - return "fr_BE"; - } - return "fr_FR"; - case "dut": - if ($country === "BE") { - return "nl_BE"; + $locale = self::getLocale($_SESSION['cISOSprache'], $_SESSION['Kunde']->cLand); + if (static::MOLLIE_METHOD !== '') { + try { + /** @var Warenkorb $wk */ + $wk = $_SESSION['Warenkorb']; + $method = self::PossiblePaymentMethods(static::MOLLIE_METHOD, $locale, $_SESSION['Kunde']->cLand, $_SESSION['Waehrung']->cISO, $wk->gibGesamtsummeWaren() * $_SESSION['Waehrung']->fFaktor); + if ($method !== null) { + $this->updatePaymentMethod($_SESSION['cISOSprache'], $method); + $this->cBild = $method->image->size2x; + return true; } - 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"; + return false; + } catch (Exception $e) { + $this->doLog('Method ' . static::MOLLIE_METHOD . ' not selectable:' . $e->getMessage()); + return false; + } } + return true; } - /** - * @var array - */ - protected static $_possiblePaymentMethods = []; - /** * @param $method * @param $locale @@ -425,14 +457,14 @@ public static function getLocale($cISOSprache, $country = null) * @param $currency * @param $amount * @return mixed|null - * @throws \Mollie\Api\Exceptions\ApiException - * @throws \Mollie\Api\Exceptions\IncompatiblePlatform + * @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->all(['amount' => ['currency' => $currency, 'value' => number_format($amount, 2, '.', '')], 'billingCountry' => $_SESSION['Kunde']->cLand, 'locale' => $locale, 'include' => 'pricing,issuers', 'resource' => 'orders']); + self::$_possiblePaymentMethods[$key] = self::API()->methods->allActive(['amount' => ['currency' => $currency, 'value' => number_format($amount, 2, '.', '')], 'billingCountry' => $_SESSION['Kunde']->cLand, 'locale' => $locale, 'include' => 'pricing,issuers', 'resource' => 'orders']); } if ($method !== null) { foreach (self::$_possiblePaymentMethods[$key] as $m) { @@ -456,10 +488,10 @@ protected function updatePaymentMethod($cISOSprache, $method) } $size = ws_mollie\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); + 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);", [ + 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), @@ -471,33 +503,6 @@ protected function updatePaymentMethod($cISOSprache, $method) } } - /** - * determines, if the payment method can be selected in the checkout process - * - * @return bool - */ - public function isSelectable() - { - $locale = self::getLocale($_SESSION['cISOSprache'], $_SESSION['Kunde']->cLand); - if (static::MOLLIE_METHOD !== '') { - try { - /** @var Warenkorb $wk */ - $wk = $_SESSION['Warenkorb']; - $method = self::PossiblePaymentMethods(static::MOLLIE_METHOD, $locale, $_SESSION['Kunde']->cLand, $_SESSION['Waehrung']->cISO, $wk->gibGesamtsummeWaren() * $_SESSION['Waehrung']->fFaktor); - if ($method !== null) { - $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; - } - } - return true; - } - /** * * @param object $customer @@ -506,7 +511,7 @@ public function isSelectable() */ public function isValid($customer, $cart) { - if (\ws_mollie\Helper::init() && \ws_mollie\Helper::getSetting("api_key")) { + if (Helper::init() && Helper::getSetting("api_key")) { return true; } $this->doLog("isValdid failed: init failed or no API Key given. Try clear the Cache."); @@ -519,7 +524,7 @@ public function isValid($customer, $cart) */ public function isValidIntern($args_arr = []) { - if (\ws_mollie\Helper::init() && \ws_mollie\Helper::getSetting("api_key")) { + if (Helper::init() && Helper::getSetting("api_key")) { return true; } $this->doLog("isValdid failed: init failed or no API Key given. Try clear the Cache."); diff --git a/version/100/sql/100.sql b/version/100/sql/100.sql index a6cf185..6beadfa 100644 --- a/version/100/sql/100.sql +++ b/version/100/sql/100.sql @@ -1,22 +1,22 @@ CREATE TABLE `xplugin_ws_mollie_payments` ( - `kID` VARCHAR(32) NOT NULL, - `kBestellung` INT(11) NULL, - `cMode` VARCHAR(16) NULL, - `cStatus` VARCHAR(16) NOT NULL, - `cHash` VARCHAR(32) NULL, - `fAmount` FLOAT NOT NULL, - `cOrderNumber` VARCHAR(32) DEFAULT '' NOT NULL, - `cCurrency` VARCHAR(3) NOT NULL, - `cMethod` VARCHAR(16) NULL, - `cLocale` VARCHAR(5) NOT NULL, - `bCancelable` INT(1) NOT NULL, - `cWebhookURL` VARCHAR(255) DEFAULT '' NOT NULL, - `cRedirectURL` VARCHAR(255) DEFAULT '' NOT NULL, - `cCheckoutURL` VARCHAR(255) DEFAULT '' NOT NULL, - `fAmountCaptured` FLOAT NULL, - `fAmountRefunded` FLOAT NULL, - `dCreatedAt` DATETIME NULL + `kID` VARCHAR(32) NOT NULL, + `kBestellung` INT(11) NULL, + `cMode` VARCHAR(16) NULL, + `cStatus` VARCHAR(16) NOT NULL, + `cHash` VARCHAR(32) NULL, + `fAmount` FLOAT NOT NULL, + `cOrderNumber` VARCHAR(32) DEFAULT '' NOT NULL, + `cCurrency` VARCHAR(3) NOT NULL, + `cMethod` VARCHAR(16) NULL, + `cLocale` VARCHAR(5) NOT NULL, + `bCancelable` INT(1) NOT NULL, + `cWebhookURL` VARCHAR(255) DEFAULT '' NOT NULL, + `cRedirectURL` VARCHAR(255) DEFAULT '' NOT NULL, + `cCheckoutURL` VARCHAR(255) DEFAULT '' NOT NULL, + `fAmountCaptured` FLOAT NULL, + `fAmountRefunded` FLOAT NULL, + `dCreatedAt` DATETIME NULL ); ALTER TABLE `xplugin_ws_mollie_payments` - ADD PRIMARY KEY `kID` (`kID`); \ No newline at end of file + ADD PRIMARY KEY `kID` (`kID`); \ No newline at end of file diff --git a/version/101/adminmenu/info.php b/version/101/adminmenu/info.php index 4a3f09a..ece4f2b 100644 --- a/version/101/adminmenu/info.php +++ b/version/101/adminmenu/info.php @@ -1,23 +1,25 @@ assign('defaultTabbertab', \ws_mollie\Helper::getAdminmenu('Info')); - \ws_mollie\Helper::selfupdate(); + Shop::Smarty()->assign('defaultTabbertab', Helper::getAdminmenu('Info')); + Helper::selfupdate(); } $svgQuery = http_build_query([ - 'p' => \ws_mollie\Helper::oPlugin()->cPluginID, - 'v' => \ws_mollie\Helper::oPlugin()->nVersion, + 'p' => Helper::oPlugin()->cPluginID, + 'v' => Helper::oPlugin()->nVersion, 's' => defined('APPLICATION_VERSION') ? APPLICATION_VERSION : JTL_VERSION, - 'd' => \ws_mollie\Helper::getDomain(), + 'd' => Helper::getDomain(), 'php' => PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION . '.' . PHP_RELEASE_VERSION, ]); - echo ""; + echo ""; echo "
" . "
" . " " . @@ -37,16 +39,16 @@ ''; try { - $latestRelease = \ws_mollie\Helper::getLatestRelease(array_key_exists('update', $_REQUEST)); - if ((int)\ws_mollie\Helper::oPlugin()->nVersion < (int)$latestRelease->version) { + $latestRelease = Helper::getLatestRelease(array_key_exists('update', $_REQUEST)); + if ((int)Helper::oPlugin()->nVersion < (int)$latestRelease->version) { Shop::Smarty()->assign('update', $latestRelease); } - } catch (\Exception $e) { + } catch (Exception $e) { } - Shop::Smarty()->display(\ws_mollie\Helper::oPlugin()->cAdminmenuPfad . '/tpl/info.tpl'); + Shop::Smarty()->display(Helper::oPlugin()->cAdminmenuPfad . '/tpl/info.tpl'); } catch (Exception $e) { echo "
Fehler: {$e->getMessage()}
"; - \ws_mollie\Helper::logExc($e); + Helper::logExc($e); } \ No newline at end of file diff --git a/version/101/adminmenu/orders.php b/version/101/adminmenu/orders.php index 6d0a67c..891f42a 100644 --- a/version/101/adminmenu/orders.php +++ b/version/101/adminmenu/orders.php @@ -1,8 +1,13 @@ 'danger', 'text' => 'Keine ID angeben!']; break; } - $payment = \ws_mollie\Model\Payment::getPaymentMollie($_REQUEST['id']); + $payment = Payment::getPaymentMollie($_REQUEST['id']); if (!$payment) { $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; break; } $order = JTLMollie::API()->orders->get($_REQUEST['id']); - if ($order->status == \Mollie\Api\Types\OrderStatus::STATUS_CANCELED) { + if ($order->status == OrderStatus::STATUS_CANCELED) { $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung bereits storniert']; break; } $refund = JTLMollie::API()->orderRefunds->createFor($order, ['lines' => []]); - \ws_mollie\Mollie::JTLMollie()->doLog("Order refunded:
" . print_r($refund, 1) . "
", '$' . $payment->kID . '#' . $payment->kBestellung . '§' . $payment->cOrderNumber, LOGLEVEL_NOTICE); + Mollie::JTLMollie()->doLog("Order refunded:
" . print_r($refund, 1) . "
", '$' . $payment->kID . '#' . $payment->kBestellung . '§' . $payment->cOrderNumber, LOGLEVEL_NOTICE); goto order; break; @@ -38,18 +43,18 @@ $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; break; } - $payment = \ws_mollie\Model\Payment::getPaymentMollie($_REQUEST['id']); + $payment = Payment::getPaymentMollie($_REQUEST['id']); if (!$payment) { $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; break; } $order = JTLMollie::API()->orders->get($_REQUEST['id']); - if ($order->status == \Mollie\Api\Types\OrderStatus::STATUS_CANCELED) { + if ($order->status == OrderStatus::STATUS_CANCELED) { $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung bereits storniert']; break; } $cancel = JTLMollie::API()->orders->cancel($order->id); - \ws_mollie\Mollie::JTLMollie()->doLog("Order canceled:
" . print_r($cancel, 1) . "
", '$' . $payment->kID . '#' . $payment->kBestellung . '§' . $payment->cOrderNumber, LOGLEVEL_NOTICE); + Mollie::JTLMollie()->doLog("Order canceled:
" . print_r($cancel, 1) . "
", '$' . $payment->kID . '#' . $payment->kBestellung . '§' . $payment->cOrderNumber, LOGLEVEL_NOTICE); goto order; break; @@ -58,13 +63,13 @@ $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; break; } - $payment = \ws_mollie\Model\Payment::getPaymentMollie($_REQUEST['id']); + $payment = Payment::getPaymentMollie($_REQUEST['id']); if (!$payment) { $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; break; } $order = JTLMollie::API()->orders->get($_REQUEST['id']); - if ($order->status !== \Mollie\Api\Types\OrderStatus::STATUS_AUTHORIZED && $order->status !== \Mollie\Api\Types\OrderStatus::STATUS_SHIPPING) { + if ($order->status !== OrderStatus::STATUS_AUTHORIZED && $order->status !== OrderStatus::STATUS_SHIPPING) { $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Nur autorisierte Zahlungen können erfasst werden!']; break; } @@ -89,7 +94,7 @@ // CAPTURE ALL $shipment = JTLMollie::API()->shipments->createFor($order, $options); $ordersMsgs[] = (object)['type' => 'success', 'text' => 'Zahlung wurde erfolgreich erfasst!']; - \ws_mollie\Mollie::JTLMollie()->doLog('Shipment created
' . print_r(['options' => $options, 'shipment' => $shipment], 1) . '
', $logData); + Mollie::JTLMollie()->doLog('Shipment created
' . print_r(['options' => $options, 'shipment' => $shipment], 1) . '
', $logData); goto order; case 'order': @@ -100,7 +105,7 @@ } $order = JTLMollie::API()->orders->get($_REQUEST['id']); - $payment = \ws_mollie\Model\Payment::getPaymentMollie($_REQUEST['id']); + $payment = Payment::getPaymentMollie($_REQUEST['id']); if ($payment) { $oBestellung = new Bestellung($payment->kBestellung, false); //\ws_mollie\Model\Payment::updateFromPayment($order, $oBestellung->kBestellung); @@ -137,7 +142,7 @@ Shop::Smarty()->assign('payments', $payments) ->assign('ordersMsgs', $ordersMsgs) ->assign('admRoot', str_replace('http:', '', $oPlugin->cAdminmenuPfadURL)) - ->assign('hasAPIKey', trim(\ws_mollie\Helper::getSetting("api_key")) !== ''); + ->assign('hasAPIKey', trim(Helper::getSetting("api_key")) !== ''); Shop::Smarty()->display($oPlugin->cAdminmenuPfad . '/tpl/orders.tpl'); } catch (Exception $e) { @@ -145,5 +150,5 @@ "{$e->getMessage()}
" . "
{$e->getFile()}:{$e->getLine()}
{$e->getTraceAsString()}
" . ""; - \ws_mollie\Helper::logExc($e); + Helper::logExc($e); } diff --git a/version/101/adminmenu/paymentmethods.php b/version/101/adminmenu/paymentmethods.php index 31c77e7..b345dbf 100644 --- a/version/101/adminmenu/paymentmethods.php +++ b/version/101/adminmenu/paymentmethods.php @@ -1,8 +1,11 @@ setApiKey(\ws_mollie\Helper::getSetting("api_key")); + $mollie = new MollieApiClient(); + $mollie->setApiKey(Helper::getSetting("api_key")); $profile = $mollie->profiles->get('me'); /* $methods = $mollie->methods->all([ //'locale' => 'de_DE', 'include' => 'pricing', ]);*/ - + $allMethods = $mollie->performHttpCall('GET', 'methods/all?locale=de_DE&include=pricing'); Shop::Smarty()->assign('profile', $profile) @@ -27,5 +30,5 @@ Shop::Smarty()->display($oPlugin->cAdminmenuPfad . '/tpl/paymentmethods.tpl'); } catch (Exception $e) { echo "
{$e->getMessage()}
"; - \ws_mollie\Helper::logExc($e); + Helper::logExc($e); } diff --git a/version/101/adminmenu/tpl/info.tpl b/version/101/adminmenu/tpl/info.tpl index eb5ae3a..16afe75 100644 --- a/version/101/adminmenu/tpl/info.tpl +++ b/version/101/adminmenu/tpl/info.tpl @@ -2,7 +2,7 @@
{if isset($update)} -
diff --git a/version/101/adminmenu/tpl/order.tpl b/version/101/adminmenu/tpl/order.tpl index d591bb1..49b4517 100644 --- a/version/101/adminmenu/tpl/order.tpl +++ b/version/101/adminmenu/tpl/order.tpl @@ -26,7 +26,7 @@
{/if} -
Mode: {$profile->mode}
+
@@ -80,7 +80,7 @@ {/if} -
Mollie ID: {$payment->kID}
+
@@ -177,7 +177,7 @@

Log

-
Status
+
{foreach from=$logs item=log}
diff --git a/version/101/adminmenu/tpl/orders.tpl b/version/101/adminmenu/tpl/orders.tpl index 50d5829..3956ef5 100644 --- a/version/101/adminmenu/tpl/orders.tpl +++ b/version/101/adminmenu/tpl/orders.tpl @@ -8,10 +8,11 @@ {if $hasAPIKey == false} - Jetzt kostenlos Mollie Account eröffnen! + Jetzt kostenlos Mollie Account eröffnen! {else} - +
diff --git a/version/101/adminmenu/tpl/paymentmethods.tpl b/version/101/adminmenu/tpl/paymentmethods.tpl index 87fb5c0..3daee0e 100644 --- a/version/101/adminmenu/tpl/paymentmethods.tpl +++ b/version/101/adminmenu/tpl/paymentmethods.tpl @@ -1,5 +1,5 @@

Account Status

-
BestellNr.
+
@@ -24,12 +24,12 @@ {foreach from=$allMethods->_embedded->methods item=method} - - - - - + + - + {/foreach}
Mode: {$profile->mode}
{$method->description|utf8_decode} + {$method->description|utf8_decode}{$method->id}{$method->description|utf8_decode} + {$method->id}{$method->description|utf8_decode}
    {foreach from=$method->pricing item=price}
  • {$price->description|utf8_decode}: {$price->fixed->value} {$price->fixed->currency} @@ -40,7 +40,7 @@ {/foreach}
diff --git a/version/101/class/Helper.php b/version/101/class/Helper.php index 7035a09..88bf67c 100644 --- a/version/101/class/Helper.php +++ b/version/101/class/Helper.php @@ -3,31 +3,38 @@ namespace ws_mollie { + use Exception; + use Jtllog; + use PclZip; + use Plugin; + use Shop; + use stdClass; + if (!class_exists('ws_mollie\Helper')) { /** - * Class Helper - * @package ws_mollie - */ + * Class Helper + * @package ws_mollie + */ final class Helper { /** - * Is ::autoload() already called? - * - * @var bool|null - */ + * Is ::autoload() already called? + * + * @var bool|null + */ private static $_autoload; /** - * @var \Plugin - */ + * @var Plugin + */ private static $oPlugin; /** - * Load Vendor Autoloader - * @return bool - */ + * Load Vendor Autoloader + * @return bool + */ public static function autoload() { if (null === self::$_autoload) { @@ -56,15 +63,15 @@ public static function autoload() } /** - * @throws \Exception - */ + * @throws Exception + */ public static function selfupdate() { - - if(function_exists('opcache_reset')){ + + if (function_exists('opcache_reset')) { opcache_reset(); } - + // 0. GET RELEASE INFO $release = self::getLatestRelease(true); $url = $release->short_url != '' ? $release->short_url : $release->full_url; @@ -74,21 +81,21 @@ public static function selfupdate() // 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!'); + 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!!"); + throw new Exception("cURL ist nicht verf�gbar!!"); } if (!is_writable($tmpDir)) { - throw new \Exception("Tempor�res Verzeichnis_'{$tmpDir}' ist nicht beschreibbar!"); + 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!"); + 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!"); + throw new Exception("Tempor�re Datei '" . $tmpDir . $filename . "' konnte nicht gel�scht werden!"); } } @@ -103,35 +110,35 @@ public static function selfupdate() curl_close($ch); fclose($fp); if ($info['http_code'] !== 200) { - throw new \Exception("Unerwarteter Status Code '" . $info['http_code'] . "'!"); + 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'] . "'!"); + 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); + $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!"); + throw new Exception("Das Zip-Archiv ist leider ung�ltig!"); } else { $unzipPath = PFAD_ROOT . PFAD_PLUGIN; $res = $zip->extract(PCLZIP_OPT_PATH, $unzipPath); if ($res !== 0) { - header('Location: ' . \Shop::getURL() . DIRECTORY_SEPARATOR . PFAD_ADMIN . 'pluginverwaltung.php', true); + header('Location: ' . Shop::getURL() . DIRECTORY_SEPARATOR . PFAD_ADMIN . 'pluginverwaltung.php', true); } else { - throw new \Exception('Entpacken fehlgeschlagen: ' . $zip->errorCode()); + throw new Exception('Entpacken fehlgeschlagen: ' . $zip->errorCode()); } } } /** - * @param bool $force - * @return mixed - * @throws \Exception - */ + * @param bool $force + * @return mixed + * @throws Exception + */ public static function getLatestRelease($force = false) { $lastCheck = (int)self::getSetting(__NAMESPACE__ . '_upd'); @@ -149,11 +156,11 @@ public static function getLatestRelease($force = false) $statusCode = (int)curl_getinfo($curl, CURLINFO_HTTP_CODE); @curl_close($curl); if ($statusCode !== 200) { - throw new \Exception(__NAMESPACE__ . ': Could not fetch release info: ' . $statusCode); + 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); + 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)); @@ -164,10 +171,10 @@ public static function getLatestRelease($force = false) } /** - * Register PSR-4 autoloader - * Licence-Check - * @return bool - */ + * Register PSR-4 autoloader + * Licence-Check + * @return bool + */ public static function init() { ini_set('xdebug.default_enable', defined('WS_XDEBUG_ENABLED')); @@ -175,23 +182,23 @@ public static function init() } /** - * Sets a Plugin Setting and saves it to the DB - * - * @param $name - * @param $value - * @return int - */ + * 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 = 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); + $return = Shop::DB()->updateRow('tplugineinstellungen', ['kPlugin', 'cName'], [$setting->kPlugin, $setting->cName], $setting); } else { - $return = \Shop::DB()->insertRow('tplugineinstellungen', $setting); + $return = Shop::DB()->insertRow('tplugineinstellungen', $setting); } self::oPlugin()->oPluginEinstellungAssoc_arr[$name] = $value; self::oPlugin(true); // invalidate cache @@ -199,41 +206,41 @@ public static function setSetting($name, $value) } /** - * Get Plugin Object - * - * @param bool $force disable Cache - * @return \Plugin|null - */ + * 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); + self::$oPlugin = new Plugin(self::oPlugin(false)->kPlugin, true); } else if (null === self::$oPlugin) { - self::$oPlugin = \Plugin::getPluginById(__NAMESPACE__); + self::$oPlugin = Plugin::getPluginById(__NAMESPACE__); } return self::$oPlugin; } /** - * get a Plugin setting - * - * @param $name - * @return null|mixed - */ + * get a Plugin setting + * + * @param $name + * @return null|mixed + */ public static function getSetting($name) { - if (array_key_exists($name, self::oPlugin()->oPluginEinstellungAssoc_arr?:[])) { + 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 - */ + * Get Domain frpm URL_SHOP without www. + * + * @param string $url + * @return string + */ public static function getDomain($url = URL_SHOP) { $matches = array(); @@ -242,40 +249,40 @@ public static function getDomain($url = URL_SHOP) } /** - * @return mixed - */ + * @return mixed + */ private static function _masterMail() { - $settings = \Shop::getSettings(array(CONF_EMAILS)); + $settings = Shop::getSettings(array(CONF_EMAILS)); return $settings['emails']['email_master_absender']; } /** - * @param \Exception $exc - * @param bool $trace - * @return void - */ - public static function logExc(\Exception $exc, $trace = true) + * @param Exception $exc + * @param bool $trace + * @return void + */ + public static function logExc(Exception $exc, $trace = true) { - \Jtllog::writeLog(__NAMESPACE__ . ': ' . $exc->getMessage() . ($trace ? ' - ' . $exc->getTraceAsString() : '')); + Jtllog::writeLog(__NAMESPACE__ . ': ' . $exc->getMessage() . ($trace ? ' - ' . $exc->getTraceAsString() : '')); } /** - * Checks if admin session is loaded - * - * @return bool - */ + * 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 - */ + * Returns kAdminmenu ID for given Title, used for Tabswitching + * + * @param $name string CustomLink Title + * @return int + */ public static function getAdminmenu($name) { $kPluginAdminMenu = 0; diff --git a/version/101/class/Model/Payment.php b/version/101/class/Model/Payment.php index 8dea11d..4317113 100644 --- a/version/101/class/Model/Payment.php +++ b/version/101/class/Model/Payment.php @@ -2,11 +2,15 @@ namespace ws_mollie\Model; +use Bestellung; +use Mollie\Api\Resources\Order; +use Shop; + class Payment extends AbstractModel { const TABLE = 'xplugin_ws_mollie_payments'; - public static function updateFromPayment(\Mollie\Api\Resources\Order $oMolliePayment, $kBestellung = null, $hash = null) + public static function updateFromPayment(Order $oMolliePayment, $kBestellung = null, $hash = null) { $data = [ ':kID' => $oMolliePayment->id, @@ -35,7 +39,7 @@ public static function updateFromPayment(\Mollie\Api\Resources\Order $oMolliePay ':fAmountRefunded1' => $oMolliePayment->amountRefunded ? $oMolliePayment->amountRefunded->value : null, ':dCreatedAt' => $oMolliePayment->createdAt ? date('Y-m-d H:i:s', strtotime($oMolliePayment->createdAt)) : null, ]; - return \Shop::DB()->executeQueryPrepared( + 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', @@ -46,27 +50,27 @@ public static function updateFromPayment(\Mollie\Api\Resources\Order $oMolliePay public static function getPayment($kBestellung) { - $payment = \Shop::DB()->executeQueryPrepared('SELECT * FROM ' . self::TABLE . ' WHERE kBestellung = :kBestellung', [':kBestellung' => $kBestellung], 1); + $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); + $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); + $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); + $payment->oBestellung = new Bestellung($payment->kBestellung, false); } return $payment; } public static function getPaymentHash($cHash) { - $payment = \Shop::DB()->executeQueryPrepared('SELECT * FROM ' . self::TABLE . ' WHERE cHash = :cHash', [':cHash' => $cHash], 1); + $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); + $payment->oBestellung = new Bestellung($payment->kBestellung, false); } return $payment; } diff --git a/version/101/class/Mollie.php b/version/101/class/Mollie.php index 82893b6..e499cee 100644 --- a/version/101/class/Mollie.php +++ b/version/101/class/Mollie.php @@ -8,8 +8,17 @@ namespace ws_mollie; +use Bestellung; +use Exception; +use JTLMollie; +use Lieferschein; +use Lieferscheinpos; use Mollie\Api\Resources\Order; use Mollie\Api\Types\OrderStatus; +use Shop; +use Shopsetting; +use stdClass; +use WarenkorbPos; use ws_mollie\Model\Payment; abstract class Mollie @@ -23,15 +32,15 @@ abstract class Mollie */ public static function getOrderCompletedRedirect($kBestellung, $redirect = true) { - $mode = \Shopsetting::getInstance()->getValue(CONF_KAUFABWICKLUNG, 'bestellabschluss_abschlussseite'); + $mode = Shopsetting::getInstance()->getValue(CONF_KAUFABWICKLUNG, 'bestellabschluss_abschlussseite'); - $bestellid = \Shop::DB()->select("tbestellid ", 'kBestellung', (int)$kBestellung); - $url = \Shop::getURL() . '/bestellabschluss.php?i=' . $bestellid->cId; + $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; + $bestellstatus = Shop::DB()->select('tbestellstatus', 'kBestellung', (int)$kBestellung); + $url = Shop::getURL() . '/status.php?uid=' . $bestellstatus->cUID; } if ($redirect) { @@ -46,16 +55,16 @@ public static function getOrderCompletedRedirect($kBestellung, $redirect = true) * @param $kBestellung * @param bool $newStatus * @return array - * @throws \Exception + * @throws Exception */ public static function getShipmentOptions(Order $order, $kBestellung, $newStatus = false) { if (!$order || !$kBestellung) { - throw new \Exception('Mollie::getShipmentOptions: order and kBestellung are required!'); + throw new Exception('Mollie::getShipmentOptions: order and kBestellung are required!'); } - $oBestellung = new \Bestellung($kBestellung, true); + $oBestellung = new Bestellung($kBestellung, true); if ($newStatus === false) { $newStatus = $oBestellung->cStatus; } @@ -63,7 +72,7 @@ public static function getShipmentOptions(Order $order, $kBestellung, $newStatus // Tracking Data if ($oBestellung->cTracking) { - $tracking = new \stdClass(); + $tracking = new stdClass(); $tracking->carrier = $oBestellung->cVersandartName; $tracking->url = $oBestellung->cTrackingURL; $tracking->code = $oBestellung->cTracking; @@ -104,22 +113,22 @@ public static function getShipmentOptions(Order $order, $kBestellung, $newStatus /** * Returns amount of sent items for SKU * @param $sku - * @param \Bestellung $oBestellung + * @param Bestellung $oBestellung * @return float|int - * @throws \Exception + * @throws Exception */ - public static function getBestellPosSent($sku, \Bestellung $oBestellung) + public static function getBestellPosSent($sku, Bestellung $oBestellung) { if ($sku === null) { return 1; } - /** @var \WarenkorbPos $oPosition */ + /** @var WarenkorbPos $oPosition */ foreach ($oBestellung->Positionen as $oPosition) { if ($oPosition->cArtNr === $sku) { $sent = 0; - /** @var \Lieferschein $oLieferschein */ + /** @var Lieferschein $oLieferschein */ foreach ($oBestellung->oLieferschein_arr as $oLieferschein) { - /** @var \Lieferscheinpos $oLieferscheinPos */ + /** @var Lieferscheinpos $oLieferscheinPos */ foreach ($oLieferschein->oLieferscheinPos_arr as $oLieferscheinPos) { if ($oLieferscheinPos->getBestellPos() == $oPosition->kBestellpos) { $sent += $oLieferscheinPos->getAnzahl(); @@ -136,20 +145,20 @@ public static function getBestellPosSent($sku, \Bestellung $oBestellung) * @param Order $order * @param null $kBestellung * @return bool - * @throws \Exception + * @throws Exception */ public static function handleOrder(Order $order, $kBestellung) { $logData = '$' . $order->id . '#' . $kBestellung . "§" . $order->orderNumber; - $oBestellung = new \Bestellung($kBestellung); + $oBestellung = new Bestellung($kBestellung); if ($oBestellung->kBestellung) { $order->orderNumber = $oBestellung->cBestellNr; Payment::updateFromPayment($order, $kBestellung); - $oIncomingPayment = \Shop::DB()->executeQueryPrepared("SELECT * FROM tzahlungseingang WHERE cHinweis = :cHinweis AND kBestellung = :kBestellung", [':cHinweis' => $order->id, ':kBestellung' => $oBestellung->kBestellung], 1); + $oIncomingPayment = Shop::DB()->executeQueryPrepared("SELECT * FROM tzahlungseingang WHERE cHinweis = :cHinweis AND kBestellung = :kBestellung", [':cHinweis' => $order->id, ':kBestellung' => $oBestellung->kBestellung], 1); if (!$oIncomingPayment) { - $oIncomingPayment = new \stdClass(); + $oIncomingPayment = new stdClass(); } // 2. Check PaymentStatus @@ -180,18 +189,18 @@ public static function handleOrder(Order $order, $kBestellung) } /** - * @return \JTLMollie - * @throws \Exception + * @return JTLMollie + * @throws Exception */ public static function JTLMollie() { if (self::$_jtlmollie === null) { - $pza = \Shop::DB()->select('tpluginzahlungsartklasse', 'cClassName', 'JTLMollie'); + $pza = Shop::DB()->select('tpluginzahlungsartklasse', 'cClassName', 'JTLMollie'); if (!$pza) { - throw new \Exception("Mollie Zahlungsart nicht in DB gefunden!"); + throw new Exception("Mollie Zahlungsart nicht in DB gefunden!"); } require_once __DIR__ . '/../paymentmethod/JTLMollie.php'; - self::$_jtlmollie = new \JTLMollie($pza->cModulId); + self::$_jtlmollie = new JTLMollie($pza->cModulId); } return self::$_jtlmollie; } diff --git a/version/101/frontend/131_globalinclude.php b/version/101/frontend/131_globalinclude.php index 118f6b6..45d4c6f 100644 --- a/version/101/frontend/131_globalinclude.php +++ b/version/101/frontend/131_globalinclude.php @@ -1,32 +1,37 @@ executeQueryPrepared("SELECT * FROM " . \ws_mollie\Model\Payment::TABLE . " WHERE cHash = :cHash", [':cHash' => $_REQUEST['mollie']], 1); + $payment = Shop::DB()->executeQueryPrepared("SELECT * FROM " . \ws_mollie\Model\Payment::TABLE . " WHERE cHash = :cHash", [':cHash' => $_REQUEST['mollie']], 1); // Bestellung finalized, redirect to status/completion page if ((int)$payment->kBestellung) { $logData = '$' . $payment->kID . '#' . $payment->kBestellung . "§" . $payment->cOrderNumber; - \ws_mollie\Mollie::JTLMollie()->doLog('Bestellung finalized => redirect abschluss/status', $logData); + Mollie::JTLMollie()->doLog('Bestellung finalized => redirect abschluss/status', $logData); $order = JTLMollie::API()->orders->get($payment->kID, ['embed' => 'payments']); - \ws_mollie\Mollie::handleOrder($order, $payment->kBestellung); - \ws_mollie\Mollie::getOrderCompletedRedirect($payment->kBestellung, true); + Mollie::handleOrder($order, $payment->kBestellung); + Mollie::getOrderCompletedRedirect($payment->kBestellung, true); } elseif ($payment) { // payment, but no order => finalize it require_once __DIR__ . '/../paymentmethod/JTLMollie.php'; $order = JTLMollie::API()->orders->get($payment->kID, ['embed' => 'payments']); $logData = '$' . $order->id . '#' . $payment->kBestellung . "§" . $payment->cOrderNumber; // GET NEWEST PAYMENT: - /** @var \Mollie\Api\Resources\Paymentt $_payment */ + /** @var Payment $_payment */ $_payment = null; if ($order->payments()) { - /** @var \Mollie\Api\Resources\Payment $p */ + /** @var Payment $p */ foreach ($order->payments() as $p) { if (!$_payment) { $_payment = $p; @@ -41,8 +46,8 @@ // finalize only, if order is not canceld/expired if ($order && !$order->isCanceled() && !$order->isExpired()) { // finalize only if payment is not expired/canceled,failed or open - if ($_payment && !in_array($_payment->status, [\Mollie\Api\Types\PaymentStatus::STATUS_EXPIRED, \Mollie\Api\Types\PaymentStatus::STATUS_CANCELED, \Mollie\Api\Types\PaymentStatus::STATUS_OPEN, \Mollie\Api\Types\PaymentStatus::STATUS_FAILED, \Mollie\Api\Types\PaymentStatus::STATUS_CANCELED])) { - \ws_mollie\Mollie::JTLMollie()->doLog('Bestellung open => finalize', $logData); + if ($_payment && !in_array($_payment->status, [PaymentStatus::STATUS_EXPIRED, PaymentStatus::STATUS_CANCELED, PaymentStatus::STATUS_OPEN, PaymentStatus::STATUS_FAILED, PaymentStatus::STATUS_CANCELED])) { + Mollie::JTLMollie()->doLog('Bestellung open => finalize', $logData); $session = Session::getInstance(); /** @noinspection PhpIncludeInspection */ require_once PFAD_ROOT . 'includes/bestellabschluss_inc.php'; @@ -50,18 +55,18 @@ require_once PFAD_ROOT . 'includes/mailTools.php'; $oBestellung = fakeBestellung(); $oBestellung = finalisiereBestellung(); - \ws_mollie\Mollie::JTLMollie()->doLog('Bestellung finalized => redirect
' . print_r($order, 1) . '
', $logData, LOGLEVEL_DEBUG); - \ws_mollie\Mollie::handleOrder($order, $oBestellung->kBestellung); - \ws_mollie\Mollie::getOrderCompletedRedirect($oBestellung->kBestellung, true); + Mollie::JTLMollie()->doLog('Bestellung finalized => redirect
' . print_r($order, 1) . '
', $logData, LOGLEVEL_DEBUG); + Mollie::handleOrder($order, $oBestellung->kBestellung); + Mollie::getOrderCompletedRedirect($oBestellung->kBestellung, true); } else { - \ws_mollie\Mollie::JTLMollie()->doLog('Invalid Payment
' . print_r($payment, 1) . '
', $logData, LOGLEVEL_ERROR); + Mollie::JTLMollie()->doLog('Invalid Payment
' . print_r($payment, 1) . '
', $logData, LOGLEVEL_ERROR); } } else { - \ws_mollie\Mollie::JTLMollie()->doLog('Invalid Order
' . print_r($order, 1) . '
', $logData, LOGLEVEL_ERROR); + Mollie::JTLMollie()->doLog('Invalid Order
' . print_r($order, 1) . '
', $logData, LOGLEVEL_ERROR); } } } ob_end_flush(); } catch (Exception $e) { - \ws_mollie\Helper::logExc($e); + Helper::logExc($e); } diff --git a/version/101/frontend/140_smarty.php b/version/101/frontend/140_smarty.php index 3f74d4f..2735ee7 100644 --- a/version/101/frontend/140_smarty.php +++ b/version/101/frontend/140_smarty.php @@ -1,10 +1,12 @@ append( - - <<append(<< /* MOLLIE CHECKOUT STYLES*/ #fieldset-payment .form-group > div:hover, #checkout-shipping-payment .form-group > div:hover { @@ -46,8 +44,8 @@ float: right; } -CSS -); +HTML + ); } catch (Exception $e) { - \ws_mollie\Helper::logExc($e); + Helper::logExc($e); } diff --git a/version/101/frontend/144_notify.php b/version/101/frontend/144_notify.php index 8856259..a2af9f2 100644 --- a/version/101/frontend/144_notify.php +++ b/version/101/frontend/144_notify.php @@ -6,22 +6,26 @@ * - ELSE weiter mit der notify.php */ +use ws_mollie\Helper; +use ws_mollie\Model\Payment; +use ws_mollie\Mollie; + if (array_key_exists('hash', $_REQUEST)) { require_once __DIR__ . '/../class/Helper.php'; try { - \ws_mollie\Helper::init(); - $payment = \ws_mollie\Model\Payment::getPaymentHash($_REQUEST['hash']); + Helper::init(); + $payment = Payment::getPaymentHash($_REQUEST['hash']); // If Bestellung already exists, treat as Notification if ($payment && $payment->kBestellung) { require_once __DIR__ . '/../paymentmethod/JTLMollie.php'; $order = JTLMollie::API()->orders->get($payment->kID); $logData = '#' . $payment->kBestellung . '$' . $payment->kID; - \ws_mollie\Mollie::JTLMollie()->doLog('Received Notification
' . print_r([$order, $payment], 1) . '
', $logData); - \ws_mollie\Mollie::handleOrder($order, $payment->kBestellung); + Mollie::JTLMollie()->doLog('Received Notification
' . print_r([$order, $payment], 1) . '
', $logData); + Mollie::handleOrder($order, $payment->kBestellung); // exit to stop execution of notify.php exit(); } } catch (Exception $e) { - \ws_mollie\Helper::logExc($e); + Helper::logExc($e); } } diff --git a/version/101/frontend/181_sync.php b/version/101/frontend/181_sync.php index be2fe16..5fb008e 100644 --- a/version/101/frontend/181_sync.php +++ b/version/101/frontend/181_sync.php @@ -1,33 +1,38 @@ kBestellung && $payment = \ws_mollie\Model\Payment::getPayment($oBestellung->kBestellung)) { + if ($oBestellung->kBestellung && $payment = Payment::getPayment($oBestellung->kBestellung)) { $logData = '#' . $payment->kBestellung . '$' . $payment->kID . "§" . $oBestellung->cBestellNr; - \ws_mollie\Mollie::JTLMollie()->doLog("WAWI Abgleich: HOOK_BESTELLUNGEN_XML_BESTELLSTATUS", $logData); + Mollie::JTLMollie()->doLog("WAWI Abgleich: HOOK_BESTELLUNGEN_XML_BESTELLSTATUS", $logData); try { $order = JTLMollie::API()->orders->get($payment->kID); $order->orderNumber = $oBestellung->cBestellNr; - \ws_mollie\Mollie::handleOrder($order, $oBestellung->kBestellung); + Mollie::handleOrder($order, $oBestellung->kBestellung); if ($order->isCreated() || $order->isPaid() || $order->isAuthorized() || $order->isShipping() || $order->isPending()) { - \ws_mollie\Mollie::JTLMollie()->doLog("Create Shippment:
" . print_r($args_arr, 1) . '
', $logData, LOGLEVEL_DEBUG); - $options = \ws_mollie\Mollie::getShipmentOptions($order, $oBestellung->kBestellung, $status); + Mollie::JTLMollie()->doLog("Create Shippment:
" . print_r($args_arr, 1) . '
', $logData, LOGLEVEL_DEBUG); + $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); - \ws_mollie\Mollie::JTLMollie()->doLog('Shipment created
' . print_r(['options' => $options, 'shipment' => $shipment], 1) . '
', $logData, LOGLEVEL_NOTICE); + Mollie::JTLMollie()->doLog('Shipment created
' . print_r(['options' => $options, 'shipment' => $shipment], 1) . '
', $logData, LOGLEVEL_NOTICE); } else { - \ws_mollie\Mollie::JTLMollie()->doLog('181_sync: options don\'t contain lines
' . print_r([$order, $options], 1) . '
', $logData, LOGLEVEL_ERROR); + Mollie::JTLMollie()->doLog('181_sync: options don\'t contain lines
' . print_r([$order, $options], 1) . '
', $logData, LOGLEVEL_ERROR); } } } catch (Exception $e) { - \ws_mollie\Mollie::JTLMollie()->doLog('Fehler: ' . $e->getMessage() . '
' . print_r($e->getTrace(), 1) . '
', $logData, LOGLEVEL_ERROR); + Mollie::JTLMollie()->doLog('Fehler: ' . $e->getMessage() . '
' . print_r($e->getTrace(), 1) . '
', $logData, LOGLEVEL_ERROR); } } } catch (Exception $e) { - \ws_mollie\Helper::logExc($e); + Helper::logExc($e); } diff --git a/version/101/paymentmethod/JTLMollie.php b/version/101/paymentmethod/JTLMollie.php index 9b21eff..b96f6a0 100644 --- a/version/101/paymentmethod/JTLMollie.php +++ b/version/101/paymentmethod/JTLMollie.php @@ -1,10 +1,19 @@ kBestellung . "" . $order->cBestellNr; try { - $payment = \ws_mollie\Model\Payment::getPayment($order->kBestellung); - if ($payment && in_array($payment->cStatus, [\Mollie\Api\Types\OrderStatus::STATUS_CREATED]) && $payment->cCheckoutURL) { + $payment = Payment::getPayment($order->kBestellung); + if ($payment && in_array($payment->cStatus, [OrderStatus::STATUS_CREATED]) && $payment->cCheckoutURL) { $logData .= '$' . $payment->kID; if (!$this->duringCheckout) { Session::getInstance()->cleanUp(); @@ -112,7 +121,7 @@ public function preparePaymentProcess($order) header('Location: ' . $payment->cCheckoutURL); exit(); } - } catch (\Exception $e) { + } catch (Exception $e) { $this->doLog("Get Payment Error: " . $e->getMessage() . ". Create new ORDER...", $logData); } @@ -122,14 +131,14 @@ public function preparePaymentProcess($order) $_SESSION['oMolliePayment'] = $oMolliePayment; $logData .= '$' . $oMolliePayment->id; $this->doLog('Mollie Create Payment Redirect: ' . $oMolliePayment->getCheckoutUrl() . "
" . print_r($oMolliePayment, 1) . "
", $logData, LOGLEVEL_DEBUG); - \ws_mollie\Model\Payment::updateFromPayment($oMolliePayment, $order->kBestellung, md5($hash)); + Payment::updateFromPayment($oMolliePayment, $order->kBestellung, md5($hash)); Shop::Smarty()->assign('oMolliePayment', $oMolliePayment); if (!$this->duringCheckout) { Session::getInstance()->cleanUp(); } header('Location: ' . $oMolliePayment->getCheckoutUrl()); exit(); - } catch (\Mollie\Api\Exceptions\ApiException $e) { + } catch (ApiException $e) { Shop::Smarty()->assign('oMollieException', $e); $this->doLog("Create Payment Error: " . $e->getMessage() . '
' . print_r($e->getTrace(), 1) . '
', $logData); } @@ -149,17 +158,17 @@ public function doLog($msg, $data = null, $level = LOGLEVEL_NOTICE) } /** - * @return \Mollie\Api\MollieApiClient - * @throws \Mollie\Api\Exceptions\ApiException - * @throws \Mollie\Api\Exceptions\IncompatiblePlatform + * @return MollieApiClient + * @throws ApiException + * @throws IncompatiblePlatform */ public static function API() { if (self::$_mollie === null) { - self::$_mollie = new \Mollie\Api\MollieApiClient(); - self::$_mollie->setApiKey(\ws_mollie\Helper::getSetting('api_key')); + self::$_mollie = new MollieApiClient(); + self::$_mollie->setApiKey(Helper::getSetting('api_key')); self::$_mollie->addVersionString("JTL-Shop/" . JTL_VERSION . '.' . JTL_MINOR_VERSION); - self::$_mollie->addVersionString("ws_mollie/" . \ws_mollie\Helper::oPlugin()->nVersion); + self::$_mollie->addVersionString("ws_mollie/" . Helper::oPlugin()->nVersion); } return self::$_mollie; } @@ -233,23 +242,23 @@ protected function getOrderData(Bestellung $order, $hash) switch ((int)$oPosition->nPosTyp) { case (int)C_WARENKORBPOS_TYP_GRATISGESCHENK: case (int)C_WARENKORBPOS_TYP_ARTIKEL: - $line->type = \Mollie\Api\Types\OrderLineType::TYPE_PHYSICAL; + $line->type = OrderLineType::TYPE_PHYSICAL; $line->sku = $oPosition->cArtNr; break; case (int)C_WARENKORBPOS_TYP_VERSANDPOS: - $line->type = \Mollie\Api\Types\OrderLineType::TYPE_SHIPPING_FEE; + $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 = \Mollie\Api\Types\OrderLineType::TYPE_SURCHARGE; + $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 = \Mollie\Api\Types\OrderLineType::TYPE_DISCOUNT; + $line->type = OrderLineType::TYPE_DISCOUNT; break; } if (isset($line->type)) { @@ -259,7 +268,7 @@ protected function getOrderData(Bestellung $order, $hash) if ((int)$order->GuthabenNutzen === 1 && $order->fGuthaben < 0) { $line = new stdClass(); - $line->type = \Mollie\Api\Types\OrderLineType::TYPE_STORE_CREDIT; + $line->type = OrderLineType::TYPE_STORE_CREDIT; $line->name = 'Guthaben'; $line->quantity = 1; $line->unitPrice = (object)[ @@ -291,7 +300,7 @@ protected function getOrderData(Bestellung $order, $hash) $diff = (round((float)$data['amount']->value - $sum, 2)); if ($diff != 0) { $line = new stdClass(); - $line->type = $diff > 0 ? \Mollie\Api\Types\OrderLineType::TYPE_SURCHARGE : \Mollie\Api\Types\OrderLineType::TYPE_DISCOUNT; + $line->type = $diff > 0 ? OrderLineType::TYPE_SURCHARGE : OrderLineType::TYPE_DISCOUNT; $line->name = 'Rundungsausgleich'; $line->quantity = 1; $line->unitPrice = (object)[ @@ -373,14 +382,14 @@ public static function getLocale($cISOSprache, $country = null) */ public function handleNotification($order, $hash, $args) { - \ws_mollie\Helper::autoload(); + Helper::autoload(); $logData = '#' . $order->kBestellung . "" . $order->cBestellNr; $this->doLog('Received Notification
' . print_r([$hash, $args], 1) . '
', $logData, LOGLEVEL_NOTICE); try { $oMolliePayment = self::API()->orders->get($args['id']); - \ws_mollie\Mollie::handleOrder($oMolliePayment, $order->kBestellung); - } catch (\Exception $e) { + Mollie::handleOrder($oMolliePayment, $order->kBestellung); + } catch (Exception $e) { $this->doLog('handleNotification: ' . $e->getMessage(), $logData); } } @@ -396,13 +405,13 @@ public function finalizeOrder($order, $hash, $args) { $logData = '#' . $order->kBestellung . "" . $order->cBestellNr; try { - \ws_mollie\Helper::autoload(); + Helper::autoload(); $oMolliePayment = self::API()->orders->get($args['id'], ['embed' => 'payments']); $logData .= '$' . $oMolliePayment->id; $this->doLog('Received Notification Finalize Order
' . print_r([$hash, $args, $oMolliePayment], 1) . '
', $logData, LOGLEVEL_DEBUG); - \ws_mollie\Model\Payment::updateFromPayment($oMolliePayment, $order->kBestellung); - return in_array($oMolliePayment->status, [\Mollie\Api\Types\OrderStatus::STATUS_PAID, \Mollie\Api\Types\OrderStatus::STATUS_AUTHORIZED, \Mollie\Api\Types\OrderStatus::STATUS_PENDING, \Mollie\Api\Types\OrderStatus::STATUS_COMPLETED]); - } catch (\Exception $e) { + Payment::updateFromPayment($oMolliePayment, $order->kBestellung); + return in_array($oMolliePayment->status, [OrderStatus::STATUS_PAID, OrderStatus::STATUS_AUTHORIZED, OrderStatus::STATUS_PENDING, OrderStatus::STATUS_COMPLETED]); + } catch (Exception $e) { $this->doLog($e->getMessage(), $logData); } return false; @@ -450,14 +459,14 @@ public function isSelectable() * @param $currency * @param $amount * @return mixed|null - * @throws \Mollie\Api\Exceptions\ApiException - * @throws \Mollie\Api\Exceptions\IncompatiblePlatform + * @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->all(['amount' => ['currency' => $currency, 'value' => number_format($amount, 2, '.', '')], 'billingCountry' => $_SESSION['Kunde']->cLand, 'locale' => $locale, 'include' => 'pricing,issuers', 'resource' => 'orders']); + self::$_possiblePaymentMethods[$key] = self::API()->methods->allActive(['amount' => ['currency' => $currency, 'value' => number_format($amount, 2, '.', '')], 'billingCountry' => $_SESSION['Kunde']->cLand, 'locale' => $locale, 'include' => 'pricing,issuers', 'resource' => 'orders']); } if ($method !== null) { foreach (self::$_possiblePaymentMethods[$key] as $m) { @@ -481,10 +490,10 @@ protected function updatePaymentMethod($cISOSprache, $method) } $size = ws_mollie\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); + 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);", [ + 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), @@ -504,7 +513,7 @@ protected function updatePaymentMethod($cISOSprache, $method) */ public function isValid($customer, $cart) { - if (\ws_mollie\Helper::init() && \ws_mollie\Helper::getSetting("api_key")) { + if (Helper::init() && Helper::getSetting("api_key")) { return true; } $this->doLog("isValdid failed: init failed or no API Key given. Try clear the Cache."); @@ -517,7 +526,7 @@ public function isValid($customer, $cart) */ public function isValidIntern($args_arr = []) { - if (\ws_mollie\Helper::init() && \ws_mollie\Helper::getSetting("api_key")) { + if (Helper::init() && Helper::getSetting("api_key")) { return true; } $this->doLog("isValdid failed: init failed or no API Key given. Try clear the Cache."); diff --git a/version/101/sql/100.sql b/version/101/sql/100.sql deleted file mode 100644 index a6cf185..0000000 --- a/version/101/sql/100.sql +++ /dev/null @@ -1,22 +0,0 @@ -CREATE TABLE `xplugin_ws_mollie_payments` ( - `kID` VARCHAR(32) NOT NULL, - `kBestellung` INT(11) NULL, - `cMode` VARCHAR(16) NULL, - `cStatus` VARCHAR(16) NOT NULL, - `cHash` VARCHAR(32) NULL, - `fAmount` FLOAT NOT NULL, - `cOrderNumber` VARCHAR(32) DEFAULT '' NOT NULL, - `cCurrency` VARCHAR(3) NOT NULL, - `cMethod` VARCHAR(16) NULL, - `cLocale` VARCHAR(5) NOT NULL, - `bCancelable` INT(1) NOT NULL, - `cWebhookURL` VARCHAR(255) DEFAULT '' NOT NULL, - `cRedirectURL` VARCHAR(255) DEFAULT '' NOT NULL, - `cCheckoutURL` VARCHAR(255) DEFAULT '' NOT NULL, - `fAmountCaptured` FLOAT NULL, - `fAmountRefunded` FLOAT NULL, - `dCreatedAt` DATETIME NULL -); - -ALTER TABLE `xplugin_ws_mollie_payments` - ADD PRIMARY KEY `kID` (`kID`); \ No newline at end of file diff --git a/version/102/adminmenu/info.php b/version/102/adminmenu/info.php index 4a3f09a..ece4f2b 100644 --- a/version/102/adminmenu/info.php +++ b/version/102/adminmenu/info.php @@ -1,23 +1,25 @@ assign('defaultTabbertab', \ws_mollie\Helper::getAdminmenu('Info')); - \ws_mollie\Helper::selfupdate(); + Shop::Smarty()->assign('defaultTabbertab', Helper::getAdminmenu('Info')); + Helper::selfupdate(); } $svgQuery = http_build_query([ - 'p' => \ws_mollie\Helper::oPlugin()->cPluginID, - 'v' => \ws_mollie\Helper::oPlugin()->nVersion, + 'p' => Helper::oPlugin()->cPluginID, + 'v' => Helper::oPlugin()->nVersion, 's' => defined('APPLICATION_VERSION') ? APPLICATION_VERSION : JTL_VERSION, - 'd' => \ws_mollie\Helper::getDomain(), + 'd' => Helper::getDomain(), 'php' => PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION . '.' . PHP_RELEASE_VERSION, ]); - echo ""; + echo ""; echo "
" . "
" . " " . @@ -37,16 +39,16 @@ ''; try { - $latestRelease = \ws_mollie\Helper::getLatestRelease(array_key_exists('update', $_REQUEST)); - if ((int)\ws_mollie\Helper::oPlugin()->nVersion < (int)$latestRelease->version) { + $latestRelease = Helper::getLatestRelease(array_key_exists('update', $_REQUEST)); + if ((int)Helper::oPlugin()->nVersion < (int)$latestRelease->version) { Shop::Smarty()->assign('update', $latestRelease); } - } catch (\Exception $e) { + } catch (Exception $e) { } - Shop::Smarty()->display(\ws_mollie\Helper::oPlugin()->cAdminmenuPfad . '/tpl/info.tpl'); + Shop::Smarty()->display(Helper::oPlugin()->cAdminmenuPfad . '/tpl/info.tpl'); } catch (Exception $e) { echo "
Fehler: {$e->getMessage()}
"; - \ws_mollie\Helper::logExc($e); + Helper::logExc($e); } \ No newline at end of file diff --git a/version/102/adminmenu/orders.php b/version/102/adminmenu/orders.php index 6d0a67c..891f42a 100644 --- a/version/102/adminmenu/orders.php +++ b/version/102/adminmenu/orders.php @@ -1,8 +1,13 @@ 'danger', 'text' => 'Keine ID angeben!']; break; } - $payment = \ws_mollie\Model\Payment::getPaymentMollie($_REQUEST['id']); + $payment = Payment::getPaymentMollie($_REQUEST['id']); if (!$payment) { $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; break; } $order = JTLMollie::API()->orders->get($_REQUEST['id']); - if ($order->status == \Mollie\Api\Types\OrderStatus::STATUS_CANCELED) { + if ($order->status == OrderStatus::STATUS_CANCELED) { $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung bereits storniert']; break; } $refund = JTLMollie::API()->orderRefunds->createFor($order, ['lines' => []]); - \ws_mollie\Mollie::JTLMollie()->doLog("Order refunded:
" . print_r($refund, 1) . "
", '$' . $payment->kID . '#' . $payment->kBestellung . '§' . $payment->cOrderNumber, LOGLEVEL_NOTICE); + Mollie::JTLMollie()->doLog("Order refunded:
" . print_r($refund, 1) . "
", '$' . $payment->kID . '#' . $payment->kBestellung . '§' . $payment->cOrderNumber, LOGLEVEL_NOTICE); goto order; break; @@ -38,18 +43,18 @@ $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; break; } - $payment = \ws_mollie\Model\Payment::getPaymentMollie($_REQUEST['id']); + $payment = Payment::getPaymentMollie($_REQUEST['id']); if (!$payment) { $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; break; } $order = JTLMollie::API()->orders->get($_REQUEST['id']); - if ($order->status == \Mollie\Api\Types\OrderStatus::STATUS_CANCELED) { + if ($order->status == OrderStatus::STATUS_CANCELED) { $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung bereits storniert']; break; } $cancel = JTLMollie::API()->orders->cancel($order->id); - \ws_mollie\Mollie::JTLMollie()->doLog("Order canceled:
" . print_r($cancel, 1) . "
", '$' . $payment->kID . '#' . $payment->kBestellung . '§' . $payment->cOrderNumber, LOGLEVEL_NOTICE); + Mollie::JTLMollie()->doLog("Order canceled:
" . print_r($cancel, 1) . "
", '$' . $payment->kID . '#' . $payment->kBestellung . '§' . $payment->cOrderNumber, LOGLEVEL_NOTICE); goto order; break; @@ -58,13 +63,13 @@ $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; break; } - $payment = \ws_mollie\Model\Payment::getPaymentMollie($_REQUEST['id']); + $payment = Payment::getPaymentMollie($_REQUEST['id']); if (!$payment) { $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; break; } $order = JTLMollie::API()->orders->get($_REQUEST['id']); - if ($order->status !== \Mollie\Api\Types\OrderStatus::STATUS_AUTHORIZED && $order->status !== \Mollie\Api\Types\OrderStatus::STATUS_SHIPPING) { + if ($order->status !== OrderStatus::STATUS_AUTHORIZED && $order->status !== OrderStatus::STATUS_SHIPPING) { $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Nur autorisierte Zahlungen können erfasst werden!']; break; } @@ -89,7 +94,7 @@ // CAPTURE ALL $shipment = JTLMollie::API()->shipments->createFor($order, $options); $ordersMsgs[] = (object)['type' => 'success', 'text' => 'Zahlung wurde erfolgreich erfasst!']; - \ws_mollie\Mollie::JTLMollie()->doLog('Shipment created
' . print_r(['options' => $options, 'shipment' => $shipment], 1) . '
', $logData); + Mollie::JTLMollie()->doLog('Shipment created
' . print_r(['options' => $options, 'shipment' => $shipment], 1) . '
', $logData); goto order; case 'order': @@ -100,7 +105,7 @@ } $order = JTLMollie::API()->orders->get($_REQUEST['id']); - $payment = \ws_mollie\Model\Payment::getPaymentMollie($_REQUEST['id']); + $payment = Payment::getPaymentMollie($_REQUEST['id']); if ($payment) { $oBestellung = new Bestellung($payment->kBestellung, false); //\ws_mollie\Model\Payment::updateFromPayment($order, $oBestellung->kBestellung); @@ -137,7 +142,7 @@ Shop::Smarty()->assign('payments', $payments) ->assign('ordersMsgs', $ordersMsgs) ->assign('admRoot', str_replace('http:', '', $oPlugin->cAdminmenuPfadURL)) - ->assign('hasAPIKey', trim(\ws_mollie\Helper::getSetting("api_key")) !== ''); + ->assign('hasAPIKey', trim(Helper::getSetting("api_key")) !== ''); Shop::Smarty()->display($oPlugin->cAdminmenuPfad . '/tpl/orders.tpl'); } catch (Exception $e) { @@ -145,5 +150,5 @@ "{$e->getMessage()}
" . "
{$e->getFile()}:{$e->getLine()}
{$e->getTraceAsString()}
" . ""; - \ws_mollie\Helper::logExc($e); + Helper::logExc($e); } diff --git a/version/102/adminmenu/paymentmethods.php b/version/102/adminmenu/paymentmethods.php index ebf7ecc..b31532b 100644 --- a/version/102/adminmenu/paymentmethods.php +++ b/version/102/adminmenu/paymentmethods.php @@ -1,18 +1,20 @@ setApiKey(Helper::getSetting("api_key")); $profile = $mollie->profiles->get('me'); @@ -44,8 +46,8 @@ } Shop::Smarty()->assign('profile', $profile) - ->assign('currencies', \ws_mollie\Mollie::getCurrencies()) - ->assign('locales', \ws_mollie\Mollie::getLocales()) + ->assign('currencies', Mollie::getCurrencies()) + ->assign('locales', Mollie::getLocales()) ->assign('allMethods', $allMethods); Shop::Smarty()->display($oPlugin->cAdminmenuPfad . '/tpl/paymentmethods.tpl'); } catch (Exception $e) { diff --git a/version/102/adminmenu/tpl/info.tpl b/version/102/adminmenu/tpl/info.tpl index eb5ae3a..0f78b79 100644 --- a/version/102/adminmenu/tpl/info.tpl +++ b/version/102/adminmenu/tpl/info.tpl @@ -1,8 +1,24 @@ +
+
+
X
+
X
+
X
+
+
+
X
+
X
+
+
+
X
+
+
+ +
{if isset($update)} -
diff --git a/version/102/adminmenu/tpl/order.tpl b/version/102/adminmenu/tpl/order.tpl index d591bb1..49b4517 100644 --- a/version/102/adminmenu/tpl/order.tpl +++ b/version/102/adminmenu/tpl/order.tpl @@ -26,7 +26,7 @@
{/if} - +
@@ -80,7 +80,7 @@ {/if} -
Mollie ID: {$payment->kID}
+
@@ -177,7 +177,7 @@

Log

-
Status
+
{foreach from=$logs item=log} - + @@ -42,7 +49,9 @@ - + diff --git a/version/105/adminmenu/tpl/orders.tpl b/version/105/adminmenu/tpl/orders.tpl index 3956ef5..45ea2ee 100644 --- a/version/105/adminmenu/tpl/orders.tpl +++ b/version/105/adminmenu/tpl/orders.tpl @@ -58,6 +58,11 @@ {else} Unbekannt: {$payment->cStatus} {/if} + {if $payment->fAmountRefunded && $payment->fAmountRefunded == $payment->fAmount} + (total refund) + {elseif $payment->fAmountRefunded && $payment->fAmountRefunded > 0} + (partly refund) + {/if} - - - + + + @@ -123,10 +135,10 @@ Zahlung erfassen1 {/if} - {if $order->amount->value > $order->amountRefunded->value && $order->amountCaptured->value > 0} + {if !$order->amountRefunded || ($order->amount->value > $order->amountRefunded->value && $order->amountCaptured->value > 0)} Rckerstatten2 + class="fa fa-thumbs-down"> Rückerstatten2 {/if} {if $order->isCancelable} diff --git a/version/106/adminmenu/tpl/paymentmethods.tpl b/version/106/adminmenu/tpl/paymentmethods.tpl index bd65a11..4c37e02 100644 --- a/version/106/adminmenu/tpl/paymentmethods.tpl +++ b/version/106/adminmenu/tpl/paymentmethods.tpl @@ -5,8 +5,10 @@ - - + {if $profile->review} + + + {/if}
diff --git a/version/102/adminmenu/tpl/orders.tpl b/version/102/adminmenu/tpl/orders.tpl index 50d5829..3956ef5 100644 --- a/version/102/adminmenu/tpl/orders.tpl +++ b/version/102/adminmenu/tpl/orders.tpl @@ -8,10 +8,11 @@ {if $hasAPIKey == false} - Jetzt kostenlos Mollie Account eröffnen! + Jetzt kostenlos Mollie Account eröffnen! {else} - +
diff --git a/version/102/adminmenu/tpl/paymentmethods.tpl b/version/102/adminmenu/tpl/paymentmethods.tpl index 945e1ab..260290f 100644 --- a/version/102/adminmenu/tpl/paymentmethods.tpl +++ b/version/102/adminmenu/tpl/paymentmethods.tpl @@ -1,5 +1,5 @@

Account Status

-
BestellNr.
+
@@ -17,9 +17,8 @@
- Locale: - - {foreach from=$locales item=locale} @@ -28,8 +27,8 @@
- Währung: - {foreach from=$currencies item=currency key=key} @@ -37,12 +36,12 @@
- Betrag: - + +
- Nur aktive ZA -   + reset
diff --git a/version/102/class/Helper.php b/version/102/class/Helper.php index 7035a09..88bf67c 100644 --- a/version/102/class/Helper.php +++ b/version/102/class/Helper.php @@ -3,31 +3,38 @@ namespace ws_mollie { + use Exception; + use Jtllog; + use PclZip; + use Plugin; + use Shop; + use stdClass; + if (!class_exists('ws_mollie\Helper')) { /** - * Class Helper - * @package ws_mollie - */ + * Class Helper + * @package ws_mollie + */ final class Helper { /** - * Is ::autoload() already called? - * - * @var bool|null - */ + * Is ::autoload() already called? + * + * @var bool|null + */ private static $_autoload; /** - * @var \Plugin - */ + * @var Plugin + */ private static $oPlugin; /** - * Load Vendor Autoloader - * @return bool - */ + * Load Vendor Autoloader + * @return bool + */ public static function autoload() { if (null === self::$_autoload) { @@ -56,15 +63,15 @@ public static function autoload() } /** - * @throws \Exception - */ + * @throws Exception + */ public static function selfupdate() { - - if(function_exists('opcache_reset')){ + + if (function_exists('opcache_reset')) { opcache_reset(); } - + // 0. GET RELEASE INFO $release = self::getLatestRelease(true); $url = $release->short_url != '' ? $release->short_url : $release->full_url; @@ -74,21 +81,21 @@ public static function selfupdate() // 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!'); + 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!!"); + throw new Exception("cURL ist nicht verf�gbar!!"); } if (!is_writable($tmpDir)) { - throw new \Exception("Tempor�res Verzeichnis_'{$tmpDir}' ist nicht beschreibbar!"); + 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!"); + 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!"); + throw new Exception("Tempor�re Datei '" . $tmpDir . $filename . "' konnte nicht gel�scht werden!"); } } @@ -103,35 +110,35 @@ public static function selfupdate() curl_close($ch); fclose($fp); if ($info['http_code'] !== 200) { - throw new \Exception("Unerwarteter Status Code '" . $info['http_code'] . "'!"); + 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'] . "'!"); + 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); + $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!"); + throw new Exception("Das Zip-Archiv ist leider ung�ltig!"); } else { $unzipPath = PFAD_ROOT . PFAD_PLUGIN; $res = $zip->extract(PCLZIP_OPT_PATH, $unzipPath); if ($res !== 0) { - header('Location: ' . \Shop::getURL() . DIRECTORY_SEPARATOR . PFAD_ADMIN . 'pluginverwaltung.php', true); + header('Location: ' . Shop::getURL() . DIRECTORY_SEPARATOR . PFAD_ADMIN . 'pluginverwaltung.php', true); } else { - throw new \Exception('Entpacken fehlgeschlagen: ' . $zip->errorCode()); + throw new Exception('Entpacken fehlgeschlagen: ' . $zip->errorCode()); } } } /** - * @param bool $force - * @return mixed - * @throws \Exception - */ + * @param bool $force + * @return mixed + * @throws Exception + */ public static function getLatestRelease($force = false) { $lastCheck = (int)self::getSetting(__NAMESPACE__ . '_upd'); @@ -149,11 +156,11 @@ public static function getLatestRelease($force = false) $statusCode = (int)curl_getinfo($curl, CURLINFO_HTTP_CODE); @curl_close($curl); if ($statusCode !== 200) { - throw new \Exception(__NAMESPACE__ . ': Could not fetch release info: ' . $statusCode); + 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); + 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)); @@ -164,10 +171,10 @@ public static function getLatestRelease($force = false) } /** - * Register PSR-4 autoloader - * Licence-Check - * @return bool - */ + * Register PSR-4 autoloader + * Licence-Check + * @return bool + */ public static function init() { ini_set('xdebug.default_enable', defined('WS_XDEBUG_ENABLED')); @@ -175,23 +182,23 @@ public static function init() } /** - * Sets a Plugin Setting and saves it to the DB - * - * @param $name - * @param $value - * @return int - */ + * 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 = 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); + $return = Shop::DB()->updateRow('tplugineinstellungen', ['kPlugin', 'cName'], [$setting->kPlugin, $setting->cName], $setting); } else { - $return = \Shop::DB()->insertRow('tplugineinstellungen', $setting); + $return = Shop::DB()->insertRow('tplugineinstellungen', $setting); } self::oPlugin()->oPluginEinstellungAssoc_arr[$name] = $value; self::oPlugin(true); // invalidate cache @@ -199,41 +206,41 @@ public static function setSetting($name, $value) } /** - * Get Plugin Object - * - * @param bool $force disable Cache - * @return \Plugin|null - */ + * 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); + self::$oPlugin = new Plugin(self::oPlugin(false)->kPlugin, true); } else if (null === self::$oPlugin) { - self::$oPlugin = \Plugin::getPluginById(__NAMESPACE__); + self::$oPlugin = Plugin::getPluginById(__NAMESPACE__); } return self::$oPlugin; } /** - * get a Plugin setting - * - * @param $name - * @return null|mixed - */ + * get a Plugin setting + * + * @param $name + * @return null|mixed + */ public static function getSetting($name) { - if (array_key_exists($name, self::oPlugin()->oPluginEinstellungAssoc_arr?:[])) { + 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 - */ + * Get Domain frpm URL_SHOP without www. + * + * @param string $url + * @return string + */ public static function getDomain($url = URL_SHOP) { $matches = array(); @@ -242,40 +249,40 @@ public static function getDomain($url = URL_SHOP) } /** - * @return mixed - */ + * @return mixed + */ private static function _masterMail() { - $settings = \Shop::getSettings(array(CONF_EMAILS)); + $settings = Shop::getSettings(array(CONF_EMAILS)); return $settings['emails']['email_master_absender']; } /** - * @param \Exception $exc - * @param bool $trace - * @return void - */ - public static function logExc(\Exception $exc, $trace = true) + * @param Exception $exc + * @param bool $trace + * @return void + */ + public static function logExc(Exception $exc, $trace = true) { - \Jtllog::writeLog(__NAMESPACE__ . ': ' . $exc->getMessage() . ($trace ? ' - ' . $exc->getTraceAsString() : '')); + Jtllog::writeLog(__NAMESPACE__ . ': ' . $exc->getMessage() . ($trace ? ' - ' . $exc->getTraceAsString() : '')); } /** - * Checks if admin session is loaded - * - * @return bool - */ + * 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 - */ + * Returns kAdminmenu ID for given Title, used for Tabswitching + * + * @param $name string CustomLink Title + * @return int + */ public static function getAdminmenu($name) { $kPluginAdminMenu = 0; diff --git a/version/102/class/Model/Payment.php b/version/102/class/Model/Payment.php index 8dea11d..4317113 100644 --- a/version/102/class/Model/Payment.php +++ b/version/102/class/Model/Payment.php @@ -2,11 +2,15 @@ namespace ws_mollie\Model; +use Bestellung; +use Mollie\Api\Resources\Order; +use Shop; + class Payment extends AbstractModel { const TABLE = 'xplugin_ws_mollie_payments'; - public static function updateFromPayment(\Mollie\Api\Resources\Order $oMolliePayment, $kBestellung = null, $hash = null) + public static function updateFromPayment(Order $oMolliePayment, $kBestellung = null, $hash = null) { $data = [ ':kID' => $oMolliePayment->id, @@ -35,7 +39,7 @@ public static function updateFromPayment(\Mollie\Api\Resources\Order $oMolliePay ':fAmountRefunded1' => $oMolliePayment->amountRefunded ? $oMolliePayment->amountRefunded->value : null, ':dCreatedAt' => $oMolliePayment->createdAt ? date('Y-m-d H:i:s', strtotime($oMolliePayment->createdAt)) : null, ]; - return \Shop::DB()->executeQueryPrepared( + 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', @@ -46,27 +50,27 @@ public static function updateFromPayment(\Mollie\Api\Resources\Order $oMolliePay public static function getPayment($kBestellung) { - $payment = \Shop::DB()->executeQueryPrepared('SELECT * FROM ' . self::TABLE . ' WHERE kBestellung = :kBestellung', [':kBestellung' => $kBestellung], 1); + $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); + $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); + $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); + $payment->oBestellung = new Bestellung($payment->kBestellung, false); } return $payment; } public static function getPaymentHash($cHash) { - $payment = \Shop::DB()->executeQueryPrepared('SELECT * FROM ' . self::TABLE . ' WHERE cHash = :cHash', [':cHash' => $cHash], 1); + $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); + $payment->oBestellung = new Bestellung($payment->kBestellung, false); } return $payment; } diff --git a/version/102/class/Mollie.php b/version/102/class/Mollie.php index 1bd189f..da0b97c 100644 --- a/version/102/class/Mollie.php +++ b/version/102/class/Mollie.php @@ -8,8 +8,17 @@ namespace ws_mollie; +use Bestellung; +use Exception; +use JTLMollie; +use Lieferschein; +use Lieferscheinpos; use Mollie\Api\Resources\Order; use Mollie\Api\Types\OrderStatus; +use Shop; +use Shopsetting; +use stdClass; +use WarenkorbPos; use ws_mollie\Model\Payment; abstract class Mollie @@ -23,15 +32,15 @@ abstract class Mollie */ public static function getOrderCompletedRedirect($kBestellung, $redirect = true) { - $mode = \Shopsetting::getInstance()->getValue(CONF_KAUFABWICKLUNG, 'bestellabschluss_abschlussseite'); + $mode = Shopsetting::getInstance()->getValue(CONF_KAUFABWICKLUNG, 'bestellabschluss_abschlussseite'); - $bestellid = \Shop::DB()->select("tbestellid ", 'kBestellung', (int)$kBestellung); - $url = \Shop::getURL() . '/bestellabschluss.php?i=' . $bestellid->cId; + $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; + $bestellstatus = Shop::DB()->select('tbestellstatus', 'kBestellung', (int)$kBestellung); + $url = Shop::getURL() . '/status.php?uid=' . $bestellstatus->cUID; } if ($redirect) { @@ -46,16 +55,16 @@ public static function getOrderCompletedRedirect($kBestellung, $redirect = true) * @param $kBestellung * @param bool $newStatus * @return array - * @throws \Exception + * @throws Exception */ public static function getShipmentOptions(Order $order, $kBestellung, $newStatus = false) { if (!$order || !$kBestellung) { - throw new \Exception('Mollie::getShipmentOptions: order and kBestellung are required!'); + throw new Exception('Mollie::getShipmentOptions: order and kBestellung are required!'); } - $oBestellung = new \Bestellung($kBestellung, true); + $oBestellung = new Bestellung($kBestellung, true); if ($newStatus === false) { $newStatus = $oBestellung->cStatus; } @@ -63,7 +72,7 @@ public static function getShipmentOptions(Order $order, $kBestellung, $newStatus // Tracking Data if ($oBestellung->cTracking) { - $tracking = new \stdClass(); + $tracking = new stdClass(); $tracking->carrier = $oBestellung->cVersandartName; $tracking->url = $oBestellung->cTrackingURL; $tracking->code = $oBestellung->cTracking; @@ -104,22 +113,22 @@ public static function getShipmentOptions(Order $order, $kBestellung, $newStatus /** * Returns amount of sent items for SKU * @param $sku - * @param \Bestellung $oBestellung + * @param Bestellung $oBestellung * @return float|int - * @throws \Exception + * @throws Exception */ - public static function getBestellPosSent($sku, \Bestellung $oBestellung) + public static function getBestellPosSent($sku, Bestellung $oBestellung) { if ($sku === null) { return 1; } - /** @var \WarenkorbPos $oPosition */ + /** @var WarenkorbPos $oPosition */ foreach ($oBestellung->Positionen as $oPosition) { if ($oPosition->cArtNr === $sku) { $sent = 0; - /** @var \Lieferschein $oLieferschein */ + /** @var Lieferschein $oLieferschein */ foreach ($oBestellung->oLieferschein_arr as $oLieferschein) { - /** @var \Lieferscheinpos $oLieferscheinPos */ + /** @var Lieferscheinpos $oLieferscheinPos */ foreach ($oLieferschein->oLieferscheinPos_arr as $oLieferscheinPos) { if ($oLieferscheinPos->getBestellPos() == $oPosition->kBestellpos) { $sent += $oLieferscheinPos->getAnzahl(); @@ -136,20 +145,20 @@ public static function getBestellPosSent($sku, \Bestellung $oBestellung) * @param Order $order * @param null $kBestellung * @return bool - * @throws \Exception + * @throws Exception */ public static function handleOrder(Order $order, $kBestellung) { - $logData = '$' . $order->id . '#' . $kBestellung . "§" . $order->orderNumber; + $logData = '$' . $order->id . '#' . $kBestellung . "§" . $order->orderNumber; - $oBestellung = new \Bestellung($kBestellung); + $oBestellung = new Bestellung($kBestellung); if ($oBestellung->kBestellung) { $order->orderNumber = $oBestellung->cBestellNr; Payment::updateFromPayment($order, $kBestellung); - $oIncomingPayment = \Shop::DB()->executeQueryPrepared("SELECT * FROM tzahlungseingang WHERE cHinweis = :cHinweis AND kBestellung = :kBestellung", [':cHinweis' => $order->id, ':kBestellung' => $oBestellung->kBestellung], 1); + $oIncomingPayment = Shop::DB()->executeQueryPrepared("SELECT * FROM tzahlungseingang WHERE cHinweis = :cHinweis AND kBestellung = :kBestellung", [':cHinweis' => $order->id, ':kBestellung' => $oBestellung->kBestellung], 1); if (!$oIncomingPayment) { - $oIncomingPayment = new \stdClass(); + $oIncomingPayment = new stdClass(); } // 2. Check PaymentStatus @@ -180,18 +189,18 @@ public static function handleOrder(Order $order, $kBestellung) } /** - * @return \JTLMollie - * @throws \Exception + * @return JTLMollie + * @throws Exception */ public static function JTLMollie() { if (self::$_jtlmollie === null) { - $pza = \Shop::DB()->select('tpluginzahlungsartklasse', 'cClassName', 'JTLMollie'); + $pza = Shop::DB()->select('tpluginzahlungsartklasse', 'cClassName', 'JTLMollie'); if (!$pza) { - throw new \Exception("Mollie Zahlungsart nicht in DB gefunden!"); + throw new Exception("Mollie Zahlungsart nicht in DB gefunden!"); } require_once __DIR__ . '/../paymentmethod/JTLMollie.php'; - self::$_jtlmollie = new \JTLMollie($pza->cModulId); + self::$_jtlmollie = new JTLMollie($pza->cModulId); } return self::$_jtlmollie; } @@ -222,17 +231,17 @@ public static function getLocales() 'lt_LT',]; $laender = []; - $shopLaender = \Shop::DB()->executeQuery("SELECT cLaender FROM tversandart", 2); + $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); + $shopSprachen = Shop::DB()->executeQuery("SELECT * FROM tsprache", 2); foreach ($shopSprachen as $sS) { foreach ($laender as $land) { - $result[] = \JTLMollie::getLocale($sS->cISO, $land); + $result[] = JTLMollie::getLocale($sS->cISO, $land); } } return array_unique($result); @@ -305,7 +314,7 @@ public static function getCurrencies() 'INR' => 'INR - Indian rupee', 'IQD' => 'IQD - Iraqi dinar', 'IRR' => 'IRR - Iranian rial', - 'ISK' => 'ISK - Icelandic króna', + 'ISK' => 'ISK - Icelandic króna', 'JMD' => 'JMD - Jamaican dollar', 'JOD' => 'JOD - Jordanian dinar', 'JPY' => 'JPY - Japanese yen', @@ -329,7 +338,7 @@ public static function getCurrencies() 'MGA' => 'MGA - Malagasy ariary', 'MKD' => 'MKD - Macedonian denar', 'MMK' => 'MMK - Myanmar kyat', - 'MNT' => 'MNT - Mongolian tögrög', + 'MNT' => 'MNT - Mongolian tögrög', 'MOP' => 'MOP - Macanese pataca', 'MRU' => 'MRU - Mauritanian ouguiya', 'MUR' => 'MUR - Mauritian rupee', @@ -341,7 +350,7 @@ public static function getCurrencies() 'MZN' => 'MZN - Mozambican metical', 'NAD' => 'NAD - Namibian dollar', 'NGN' => 'NGN - Nigerian naira', - 'NIO' => 'NIO - Nicaraguan córdoba', + 'NIO' => 'NIO - Nicaraguan córdoba', 'NOK' => 'NOK - Norwegian krone', 'NPR' => 'NPR - Nepalese rupee', 'NZD' => 'NZD - New Zealand dollar', @@ -352,7 +361,7 @@ public static function getCurrencies() 'PHP' => 'PHP - Philippine peso', 'PKR' => 'PKR - Pakistani rupee', 'PLN' => 'PLN - Polish z?oty', - 'PYG' => 'PYG - Paraguayan guaraní', + 'PYG' => 'PYG - Paraguayan guaraní', 'QAR' => 'QAR - Qatari riyal', 'RON' => 'RON - Romanian leu', 'RSD' => 'RSD - Serbian dinar', @@ -369,8 +378,8 @@ public static function getCurrencies() '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', + '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', @@ -389,7 +398,7 @@ public static function getCurrencies() 'UYU' => 'UYU - Uruguayan peso', 'UYW' => 'UYW - Unidad previsional', 'UZS' => 'UZS - Uzbekistan som', - 'VES' => 'VES - Venezuelan bolívar soberano', + 'VES' => 'VES - Venezuelan bolívar soberano', 'VND' => 'VND - Vietnamese ??ng', 'VUV' => 'VUV - Vanuatu vatu', 'WST' => 'WST - Samoan tala', @@ -398,7 +407,7 @@ public static function getCurrencies() 'ZMW' => 'ZMW - Zambian kwacha', 'ZWL' => 'ZWL - Zimbabwean dollar']; - $shopCurrencies = \Shop::DB()->executeQuery("SELECT * FROM twaehrung", 2); + $shopCurrencies = Shop::DB()->executeQuery("SELECT * FROM twaehrung", 2); $result = []; diff --git a/version/102/frontend/131_globalinclude.php b/version/102/frontend/131_globalinclude.php index 118f6b6..45d4c6f 100644 --- a/version/102/frontend/131_globalinclude.php +++ b/version/102/frontend/131_globalinclude.php @@ -1,32 +1,37 @@ executeQueryPrepared("SELECT * FROM " . \ws_mollie\Model\Payment::TABLE . " WHERE cHash = :cHash", [':cHash' => $_REQUEST['mollie']], 1); + $payment = Shop::DB()->executeQueryPrepared("SELECT * FROM " . \ws_mollie\Model\Payment::TABLE . " WHERE cHash = :cHash", [':cHash' => $_REQUEST['mollie']], 1); // Bestellung finalized, redirect to status/completion page if ((int)$payment->kBestellung) { $logData = '$' . $payment->kID . '#' . $payment->kBestellung . "§" . $payment->cOrderNumber; - \ws_mollie\Mollie::JTLMollie()->doLog('Bestellung finalized => redirect abschluss/status', $logData); + Mollie::JTLMollie()->doLog('Bestellung finalized => redirect abschluss/status', $logData); $order = JTLMollie::API()->orders->get($payment->kID, ['embed' => 'payments']); - \ws_mollie\Mollie::handleOrder($order, $payment->kBestellung); - \ws_mollie\Mollie::getOrderCompletedRedirect($payment->kBestellung, true); + Mollie::handleOrder($order, $payment->kBestellung); + Mollie::getOrderCompletedRedirect($payment->kBestellung, true); } elseif ($payment) { // payment, but no order => finalize it require_once __DIR__ . '/../paymentmethod/JTLMollie.php'; $order = JTLMollie::API()->orders->get($payment->kID, ['embed' => 'payments']); $logData = '$' . $order->id . '#' . $payment->kBestellung . "§" . $payment->cOrderNumber; // GET NEWEST PAYMENT: - /** @var \Mollie\Api\Resources\Paymentt $_payment */ + /** @var Payment $_payment */ $_payment = null; if ($order->payments()) { - /** @var \Mollie\Api\Resources\Payment $p */ + /** @var Payment $p */ foreach ($order->payments() as $p) { if (!$_payment) { $_payment = $p; @@ -41,8 +46,8 @@ // finalize only, if order is not canceld/expired if ($order && !$order->isCanceled() && !$order->isExpired()) { // finalize only if payment is not expired/canceled,failed or open - if ($_payment && !in_array($_payment->status, [\Mollie\Api\Types\PaymentStatus::STATUS_EXPIRED, \Mollie\Api\Types\PaymentStatus::STATUS_CANCELED, \Mollie\Api\Types\PaymentStatus::STATUS_OPEN, \Mollie\Api\Types\PaymentStatus::STATUS_FAILED, \Mollie\Api\Types\PaymentStatus::STATUS_CANCELED])) { - \ws_mollie\Mollie::JTLMollie()->doLog('Bestellung open => finalize', $logData); + if ($_payment && !in_array($_payment->status, [PaymentStatus::STATUS_EXPIRED, PaymentStatus::STATUS_CANCELED, PaymentStatus::STATUS_OPEN, PaymentStatus::STATUS_FAILED, PaymentStatus::STATUS_CANCELED])) { + Mollie::JTLMollie()->doLog('Bestellung open => finalize', $logData); $session = Session::getInstance(); /** @noinspection PhpIncludeInspection */ require_once PFAD_ROOT . 'includes/bestellabschluss_inc.php'; @@ -50,18 +55,18 @@ require_once PFAD_ROOT . 'includes/mailTools.php'; $oBestellung = fakeBestellung(); $oBestellung = finalisiereBestellung(); - \ws_mollie\Mollie::JTLMollie()->doLog('Bestellung finalized => redirect
' . print_r($order, 1) . '
', $logData, LOGLEVEL_DEBUG); - \ws_mollie\Mollie::handleOrder($order, $oBestellung->kBestellung); - \ws_mollie\Mollie::getOrderCompletedRedirect($oBestellung->kBestellung, true); + Mollie::JTLMollie()->doLog('Bestellung finalized => redirect
' . print_r($order, 1) . '
', $logData, LOGLEVEL_DEBUG); + Mollie::handleOrder($order, $oBestellung->kBestellung); + Mollie::getOrderCompletedRedirect($oBestellung->kBestellung, true); } else { - \ws_mollie\Mollie::JTLMollie()->doLog('Invalid Payment
' . print_r($payment, 1) . '
', $logData, LOGLEVEL_ERROR); + Mollie::JTLMollie()->doLog('Invalid Payment
' . print_r($payment, 1) . '
', $logData, LOGLEVEL_ERROR); } } else { - \ws_mollie\Mollie::JTLMollie()->doLog('Invalid Order
' . print_r($order, 1) . '
', $logData, LOGLEVEL_ERROR); + Mollie::JTLMollie()->doLog('Invalid Order
' . print_r($order, 1) . '
', $logData, LOGLEVEL_ERROR); } } } ob_end_flush(); } catch (Exception $e) { - \ws_mollie\Helper::logExc($e); + Helper::logExc($e); } diff --git a/version/102/frontend/140_smarty.php b/version/102/frontend/140_smarty.php index 3f74d4f..2735ee7 100644 --- a/version/102/frontend/140_smarty.php +++ b/version/102/frontend/140_smarty.php @@ -1,10 +1,12 @@ append( - - <<append(<< /* MOLLIE CHECKOUT STYLES*/ #fieldset-payment .form-group > div:hover, #checkout-shipping-payment .form-group > div:hover { @@ -46,8 +44,8 @@ float: right; } -CSS -); +HTML + ); } catch (Exception $e) { - \ws_mollie\Helper::logExc($e); + Helper::logExc($e); } diff --git a/version/102/frontend/144_notify.php b/version/102/frontend/144_notify.php index 8856259..a2af9f2 100644 --- a/version/102/frontend/144_notify.php +++ b/version/102/frontend/144_notify.php @@ -6,22 +6,26 @@ * - ELSE weiter mit der notify.php */ +use ws_mollie\Helper; +use ws_mollie\Model\Payment; +use ws_mollie\Mollie; + if (array_key_exists('hash', $_REQUEST)) { require_once __DIR__ . '/../class/Helper.php'; try { - \ws_mollie\Helper::init(); - $payment = \ws_mollie\Model\Payment::getPaymentHash($_REQUEST['hash']); + Helper::init(); + $payment = Payment::getPaymentHash($_REQUEST['hash']); // If Bestellung already exists, treat as Notification if ($payment && $payment->kBestellung) { require_once __DIR__ . '/../paymentmethod/JTLMollie.php'; $order = JTLMollie::API()->orders->get($payment->kID); $logData = '#' . $payment->kBestellung . '$' . $payment->kID; - \ws_mollie\Mollie::JTLMollie()->doLog('Received Notification
' . print_r([$order, $payment], 1) . '
', $logData); - \ws_mollie\Mollie::handleOrder($order, $payment->kBestellung); + Mollie::JTLMollie()->doLog('Received Notification
' . print_r([$order, $payment], 1) . '
', $logData); + Mollie::handleOrder($order, $payment->kBestellung); // exit to stop execution of notify.php exit(); } } catch (Exception $e) { - \ws_mollie\Helper::logExc($e); + Helper::logExc($e); } } diff --git a/version/102/frontend/181_sync.php b/version/102/frontend/181_sync.php index be2fe16..5fb008e 100644 --- a/version/102/frontend/181_sync.php +++ b/version/102/frontend/181_sync.php @@ -1,33 +1,38 @@ kBestellung && $payment = \ws_mollie\Model\Payment::getPayment($oBestellung->kBestellung)) { + if ($oBestellung->kBestellung && $payment = Payment::getPayment($oBestellung->kBestellung)) { $logData = '#' . $payment->kBestellung . '$' . $payment->kID . "§" . $oBestellung->cBestellNr; - \ws_mollie\Mollie::JTLMollie()->doLog("WAWI Abgleich: HOOK_BESTELLUNGEN_XML_BESTELLSTATUS", $logData); + Mollie::JTLMollie()->doLog("WAWI Abgleich: HOOK_BESTELLUNGEN_XML_BESTELLSTATUS", $logData); try { $order = JTLMollie::API()->orders->get($payment->kID); $order->orderNumber = $oBestellung->cBestellNr; - \ws_mollie\Mollie::handleOrder($order, $oBestellung->kBestellung); + Mollie::handleOrder($order, $oBestellung->kBestellung); if ($order->isCreated() || $order->isPaid() || $order->isAuthorized() || $order->isShipping() || $order->isPending()) { - \ws_mollie\Mollie::JTLMollie()->doLog("Create Shippment:
" . print_r($args_arr, 1) . '
', $logData, LOGLEVEL_DEBUG); - $options = \ws_mollie\Mollie::getShipmentOptions($order, $oBestellung->kBestellung, $status); + Mollie::JTLMollie()->doLog("Create Shippment:
" . print_r($args_arr, 1) . '
', $logData, LOGLEVEL_DEBUG); + $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); - \ws_mollie\Mollie::JTLMollie()->doLog('Shipment created
' . print_r(['options' => $options, 'shipment' => $shipment], 1) . '
', $logData, LOGLEVEL_NOTICE); + Mollie::JTLMollie()->doLog('Shipment created
' . print_r(['options' => $options, 'shipment' => $shipment], 1) . '
', $logData, LOGLEVEL_NOTICE); } else { - \ws_mollie\Mollie::JTLMollie()->doLog('181_sync: options don\'t contain lines
' . print_r([$order, $options], 1) . '
', $logData, LOGLEVEL_ERROR); + Mollie::JTLMollie()->doLog('181_sync: options don\'t contain lines
' . print_r([$order, $options], 1) . '
', $logData, LOGLEVEL_ERROR); } } } catch (Exception $e) { - \ws_mollie\Mollie::JTLMollie()->doLog('Fehler: ' . $e->getMessage() . '
' . print_r($e->getTrace(), 1) . '
', $logData, LOGLEVEL_ERROR); + Mollie::JTLMollie()->doLog('Fehler: ' . $e->getMessage() . '
' . print_r($e->getTrace(), 1) . '
', $logData, LOGLEVEL_ERROR); } } } catch (Exception $e) { - \ws_mollie\Helper::logExc($e); + Helper::logExc($e); } diff --git a/version/102/paymentmethod/JTLMollie.php b/version/102/paymentmethod/JTLMollie.php index 6f2bfb9..175e8b9 100644 --- a/version/102/paymentmethod/JTLMollie.php +++ b/version/102/paymentmethod/JTLMollie.php @@ -1,12 +1,19 @@ kBestellung . "" . $order->cBestellNr; try { - $payment = \ws_mollie\Model\Payment::getPayment($order->kBestellung); - if ($payment && in_array($payment->cStatus, [\Mollie\Api\Types\OrderStatus::STATUS_CREATED]) && $payment->cCheckoutURL) { + $payment = Payment::getPayment($order->kBestellung); + if ($payment && in_array($payment->cStatus, [OrderStatus::STATUS_CREATED]) && $payment->cCheckoutURL) { $logData .= '$' . $payment->kID; if (!$this->duringCheckout) { Session::getInstance()->cleanUp(); @@ -114,7 +121,7 @@ public function preparePaymentProcess($order) header('Location: ' . $payment->cCheckoutURL); exit(); } - } catch (\Exception $e) { + } catch (Exception $e) { $this->doLog("Get Payment Error: " . $e->getMessage() . ". Create new ORDER...", $logData); } @@ -124,14 +131,14 @@ public function preparePaymentProcess($order) $_SESSION['oMolliePayment'] = $oMolliePayment; $logData .= '$' . $oMolliePayment->id; $this->doLog('Mollie Create Payment Redirect: ' . $oMolliePayment->getCheckoutUrl() . "
" . print_r($oMolliePayment, 1) . "
", $logData, LOGLEVEL_DEBUG); - \ws_mollie\Model\Payment::updateFromPayment($oMolliePayment, $order->kBestellung, md5($hash)); + Payment::updateFromPayment($oMolliePayment, $order->kBestellung, md5($hash)); Shop::Smarty()->assign('oMolliePayment', $oMolliePayment); if (!$this->duringCheckout) { Session::getInstance()->cleanUp(); } header('Location: ' . $oMolliePayment->getCheckoutUrl()); exit(); - } catch (\Mollie\Api\Exceptions\ApiException $e) { + } catch (ApiException $e) { Shop::Smarty()->assign('oMollieException', $e); $this->doLog("Create Payment Error: " . $e->getMessage() . '
' . print_r($e->getTrace(), 1) . '
', $logData); } @@ -151,17 +158,17 @@ public function doLog($msg, $data = null, $level = LOGLEVEL_NOTICE) } /** - * @return \Mollie\Api\MollieApiClient - * @throws \Mollie\Api\Exceptions\ApiException - * @throws \Mollie\Api\Exceptions\IncompatiblePlatform + * @return MollieApiClient + * @throws ApiException + * @throws IncompatiblePlatform */ public static function API() { if (self::$_mollie === null) { - self::$_mollie = new \Mollie\Api\MollieApiClient(); - self::$_mollie->setApiKey(\ws_mollie\Helper::getSetting('api_key')); + self::$_mollie = new MollieApiClient(); + self::$_mollie->setApiKey(Helper::getSetting('api_key')); self::$_mollie->addVersionString("JTL-Shop/" . JTL_VERSION . '.' . JTL_MINOR_VERSION); - self::$_mollie->addVersionString("ws_mollie/" . \ws_mollie\Helper::oPlugin()->nVersion); + self::$_mollie->addVersionString("ws_mollie/" . Helper::oPlugin()->nVersion); } return self::$_mollie; } @@ -377,14 +384,14 @@ public static function getLocale($cISOSprache, $country = null) */ public function handleNotification($order, $hash, $args) { - \ws_mollie\Helper::autoload(); + Helper::autoload(); $logData = '#' . $order->kBestellung . "" . $order->cBestellNr; $this->doLog('Received Notification
' . print_r([$hash, $args], 1) . '
', $logData, LOGLEVEL_NOTICE); try { $oMolliePayment = self::API()->orders->get($args['id']); - \ws_mollie\Mollie::handleOrder($oMolliePayment, $order->kBestellung); - } catch (\Exception $e) { + Mollie::handleOrder($oMolliePayment, $order->kBestellung); + } catch (Exception $e) { $this->doLog('handleNotification: ' . $e->getMessage(), $logData); } } @@ -400,13 +407,13 @@ public function finalizeOrder($order, $hash, $args) { $logData = '#' . $order->kBestellung . "" . $order->cBestellNr; try { - \ws_mollie\Helper::autoload(); + Helper::autoload(); $oMolliePayment = self::API()->orders->get($args['id'], ['embed' => 'payments']); $logData .= '$' . $oMolliePayment->id; $this->doLog('Received Notification Finalize Order
' . print_r([$hash, $args, $oMolliePayment], 1) . '
', $logData, LOGLEVEL_DEBUG); - \ws_mollie\Model\Payment::updateFromPayment($oMolliePayment, $order->kBestellung); - return in_array($oMolliePayment->status, [\Mollie\Api\Types\OrderStatus::STATUS_PAID, \Mollie\Api\Types\OrderStatus::STATUS_AUTHORIZED, \Mollie\Api\Types\OrderStatus::STATUS_PENDING, \Mollie\Api\Types\OrderStatus::STATUS_COMPLETED]); - } catch (\Exception $e) { + Payment::updateFromPayment($oMolliePayment, $order->kBestellung); + return in_array($oMolliePayment->status, [OrderStatus::STATUS_PAID, OrderStatus::STATUS_AUTHORIZED, OrderStatus::STATUS_PENDING, OrderStatus::STATUS_COMPLETED]); + } catch (Exception $e) { $this->doLog($e->getMessage(), $logData); } return false; @@ -461,14 +468,14 @@ public function isSelectable() * @param $currency * @param $amount * @return mixed|null - * @throws \Mollie\Api\Exceptions\ApiException - * @throws \Mollie\Api\Exceptions\IncompatiblePlatform + * @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->all(['amount' => ['currency' => $currency, 'value' => number_format($amount, 2, '.', '')], 'billingCountry' => $_SESSION['Kunde']->cLand, 'locale' => $locale, 'include' => 'pricing,issuers', 'resource' => 'orders']); + self::$_possiblePaymentMethods[$key] = self::API()->methods->allActive(['amount' => ['currency' => $currency, 'value' => number_format($amount, 2, '.', '')], 'billingCountry' => $_SESSION['Kunde']->cLand, 'locale' => $locale, 'include' => 'pricing,issuers', 'resource' => 'orders']); } if ($method !== null) { foreach (self::$_possiblePaymentMethods[$key] as $m) { @@ -492,10 +499,10 @@ protected function updatePaymentMethod($cISOSprache, $method) } $size = ws_mollie\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); + 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);", [ + 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), @@ -515,7 +522,7 @@ protected function updatePaymentMethod($cISOSprache, $method) */ public function isValid($customer, $cart) { - if (\ws_mollie\Helper::init() && \ws_mollie\Helper::getSetting("api_key")) { + if (Helper::init() && Helper::getSetting("api_key")) { return true; } $this->doLog("isValdid failed: init failed or no API Key given. Try clear the Cache."); @@ -528,7 +535,7 @@ public function isValid($customer, $cart) */ public function isValidIntern($args_arr = []) { - if (\ws_mollie\Helper::init() && \ws_mollie\Helper::getSetting("api_key")) { + if (Helper::init() && Helper::getSetting("api_key")) { return true; } $this->doLog("isValdid failed: init failed or no API Key given. Try clear the Cache."); diff --git a/version/102/sql/100.sql b/version/102/sql/100.sql deleted file mode 100644 index a6cf185..0000000 --- a/version/102/sql/100.sql +++ /dev/null @@ -1,22 +0,0 @@ -CREATE TABLE `xplugin_ws_mollie_payments` ( - `kID` VARCHAR(32) NOT NULL, - `kBestellung` INT(11) NULL, - `cMode` VARCHAR(16) NULL, - `cStatus` VARCHAR(16) NOT NULL, - `cHash` VARCHAR(32) NULL, - `fAmount` FLOAT NOT NULL, - `cOrderNumber` VARCHAR(32) DEFAULT '' NOT NULL, - `cCurrency` VARCHAR(3) NOT NULL, - `cMethod` VARCHAR(16) NULL, - `cLocale` VARCHAR(5) NOT NULL, - `bCancelable` INT(1) NOT NULL, - `cWebhookURL` VARCHAR(255) DEFAULT '' NOT NULL, - `cRedirectURL` VARCHAR(255) DEFAULT '' NOT NULL, - `cCheckoutURL` VARCHAR(255) DEFAULT '' NOT NULL, - `fAmountCaptured` FLOAT NULL, - `fAmountRefunded` FLOAT NULL, - `dCreatedAt` DATETIME NULL -); - -ALTER TABLE `xplugin_ws_mollie_payments` - ADD PRIMARY KEY `kID` (`kID`); \ No newline at end of file From 48ad4a1f26ac0359493a1d308945bd3387abe0e7 Mon Sep 17 00:00:00 2001 From: "C. Proske" Date: Tue, 16 Apr 2019 13:45:47 +0200 Subject: [PATCH 053/280] #24 --- version/102/paymentmethod/JTLMollie.php | 38 ++++++++++++++----------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/version/102/paymentmethod/JTLMollie.php b/version/102/paymentmethod/JTLMollie.php index 175e8b9..832f795 100644 --- a/version/102/paymentmethod/JTLMollie.php +++ b/version/102/paymentmethod/JTLMollie.php @@ -190,7 +190,7 @@ protected function getOrderData(Bestellung $order, $hash) 'orderNumber' => $order->cBestellNr, 'lines' => [], 'billingAddress' => new stdClass(), - 'shippingAddress' => new stdClass(), + 'redirectUrl' => (int)$this->duringCheckout ? Shop::getURL() . '/bestellabschluss.php?mollie=' . md5($hash) : $this->getReturnURL($order), 'webhookUrl' => $this->getNotificationURL($hash) . '&hash=' . md5($hash), ]; @@ -208,36 +208,40 @@ protected function getOrderData(Bestellung $order, $hash) $data['billingAddress']->city = utf8_encode($order->oRechnungsadresse->cOrt); $data['billingAddress']->country = $order->oRechnungsadresse->cLand; - //if ((int)$order->kLieferadresse) { - $data['shippingAddress']->organizationName = utf8_encode($order->Lieferadresse->cFirma); - $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 = $order->oRechnungsadresse->cMail; - $data['shippingAddress']->streetAndNumber = utf8_encode($order->Lieferadresse->cStrasse . ' ' . $order->Lieferadresse->cHausnummer); - $data['shippingAddress']->postalCode = $order->Lieferadresse->cPLZ; - $data['shippingAddress']->city = utf8_encode($order->Lieferadresse->cOrt); - $data['shippingAddress']->country = $order->Lieferadresse->cLand; - //} + if ($order->Lieferadresse != null) { + $data['shippingAddress'] = new stdClass(); + $data['shippingAddress']->organizationName = utf8_encode($order->Lieferadresse->cFirma); + $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 = $order->oRechnungsadresse->cMail; + $data['shippingAddress']->streetAndNumber = utf8_encode($order->Lieferadresse->cStrasse . ' ' . $order->Lieferadresse->cHausnummer); + $data['shippingAddress']->postalCode = $order->Lieferadresse->cPLZ; + $data['shippingAddress']->city = utf8_encode($order->Lieferadresse->cOrt); + $data['shippingAddress']->country = $order->Lieferadresse->cLand; + } /** @var WarenkorbPos $oPosition */ foreach ($order->Positionen as $oPosition) { + + $unitPrice = berechneBrutto($order->Waehrung->fFaktor * $oPosition->fPreis, $oPosition->fMwSt, 4); + $totalAmount = $oPosition->nAnzahl * $unitPrice; + $line = new stdClass(); $line->name = utf8_encode($oPosition->cName); $line->quantity = $oPosition->nAnzahl; $line->unitPrice = (object)[ - 'value' => number_format(berechneBrutto($order->Waehrung->fFaktor * $oPosition->fPreis, $oPosition->fMwSt), 2, '.', ''), - //'value' => number_format($order->Waehrung->fFaktor * ($oPosition->fPreis * ((float)$oPosition->fMwSt / 100 + 1)), 2, '.', ''), + 'value' => number_format(round($unitPrice, 2), 2, '.', ''), 'currency' => $order->Waehrung->cISO, ]; $line->totalAmount = (object)[ - 'value' => number_format($oPosition->nAnzahl * (float)$line->unitPrice->value, 2, '.', ''), + 'value' => number_format(round($totalAmount, 2), 2, '.', ''), 'currency' => $order->Waehrung->cISO, ]; $line->vatRate = $oPosition->fMwSt; + $x = $totalAmount - (berechneNetto($unitPrice, $oPosition->fMwSt, 4) * $oPosition->nAnzahl); $line->vatAmount = (object)[ - //'value' => number_format($line->totalAmount->value - berechneNetto($line->totalAmount->value, $oPosition->fMwSt), 2, '.', ''), - 'value' => number_format($line->totalAmount->value - (berechneNetto($line->unitPrice->value, $oPosition->fMwSt) * $oPosition->nAnzahl), 2, '.', ''), + 'value' => number_format(round($x, 2), 2, '.', ''), 'currency' => $order->Waehrung->cISO, ]; From b4f46e9ed24b540e73fb018860b67317c618ef85 Mon Sep 17 00:00:00 2001 From: "C. Proske" Date: Tue, 16 Apr 2019 14:24:27 +0200 Subject: [PATCH 054/280] infoxml --- info.xml | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/info.xml b/info.xml index fe65604..f2dbc03 100644 --- a/info.xml +++ b/info.xml @@ -70,7 +70,7 @@ mollie - + 1 0 mollie.com @@ -90,7 +90,7 @@ mollie Kreditkarte - + 2 0 mollie.com @@ -110,7 +110,7 @@ mollie Bitcoin - + 3 0 mollie.com @@ -130,7 +130,7 @@ mollie Bancontact - + 4 0 mollie.com @@ -150,7 +150,7 @@ mollie Banktransfer - + 5 0 mollie.com @@ -170,7 +170,7 @@ mollie Belfius - + 6 0 mollie.com @@ -190,7 +190,7 @@ mollie DirectDebit - + 7 0 mollie.com @@ -210,7 +210,7 @@ mollie EPS - + 2 0 mollie.com @@ -230,7 +230,7 @@ mollie Giftcard - + 8 0 mollie.com @@ -250,7 +250,7 @@ mollie Giropay - + 9 0 mollie.com @@ -270,7 +270,7 @@ mollie iDEAL - + 10 0 mollie.com @@ -290,7 +290,7 @@ mollie ING HomePay - + 11 0 mollie.com @@ -310,7 +310,7 @@ mollie KBC - + 12 0 mollie.com @@ -330,7 +330,7 @@ mollie PayPal - + 13 0 mollie.com @@ -350,7 +350,7 @@ mollie paysafecard - + 14 0 mollie.com @@ -370,7 +370,7 @@ mollie SOFORT - + 15 0 mollie.com @@ -390,7 +390,7 @@ mollie Klarna Pay Later - + 16 0 mollie.com @@ -410,7 +410,7 @@ mollie Klarna Slice It - + 17 0 mollie.com From efb9a7257e76181ea7925e5489ee284e8e78c6f0 Mon Sep 17 00:00:00 2001 From: "C. Proske" Date: Tue, 16 Apr 2019 15:20:25 +0200 Subject: [PATCH 055/280] handle Order before pay again --- version/102/class/Mollie.php | 2 +- version/102/paymentmethod/JTLMollie.php | 28 +++++++++++++------------ 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/version/102/class/Mollie.php b/version/102/class/Mollie.php index da0b97c..6074f72 100644 --- a/version/102/class/Mollie.php +++ b/version/102/class/Mollie.php @@ -167,7 +167,7 @@ public static function handleOrder(Order $order, $kBestellung) case OrderStatus::STATUS_COMPLETED: case OrderStatus::STATUS_AUTHORIZED: $oIncomingPayment->fBetrag = $order->amount->value; - $oIncomingPayment->cISO = $order->amount->curreny; + $oIncomingPayment->cISO = $order->amount->currency; $oIncomingPayment->cHinweis = $order->id; Mollie::JTLMollie()->addIncomingPayment($oBestellung, $oIncomingPayment); Mollie::JTLMollie()->setOrderStatusToPaid($oBestellung); diff --git a/version/102/paymentmethod/JTLMollie.php b/version/102/paymentmethod/JTLMollie.php index 832f795..1129286 100644 --- a/version/102/paymentmethod/JTLMollie.php +++ b/version/102/paymentmethod/JTLMollie.php @@ -113,6 +113,8 @@ public function preparePaymentProcess($order) $logData = '#' . $order->kBestellung . "" . $order->cBestellNr; try { $payment = Payment::getPayment($order->kBestellung); + $oMolliePayment = self::API()->orders->get($payment->kID); + Mollie::handleOrder($oMolliePayment, $order->kBestellung); if ($payment && in_array($payment->cStatus, [OrderStatus::STATUS_CREATED]) && $payment->cCheckoutURL) { $logData .= '$' . $payment->kID; if (!$this->duringCheckout) { @@ -144,19 +146,6 @@ public function preparePaymentProcess($order) } } - /** - * @param string $msg - * @param null $data - * @param int $level - * @return $this - */ - public function doLog($msg, $data = null, $level = LOGLEVEL_NOTICE) - { - ZahlungsLog::add($this->moduleID, $msg, $data, $level); - - return $this; - } - /** * @return MollieApiClient * @throws ApiException @@ -173,6 +162,19 @@ public static function API() return self::$_mollie; } + /** + * @param string $msg + * @param null $data + * @param int $level + * @return $this + */ + public function doLog($msg, $data = null, $level = LOGLEVEL_NOTICE) + { + ZahlungsLog::add($this->moduleID, $msg, $data, $level); + + return $this; + } + /** * @param Bestellung $order * @param $hash From db914dd29116620700054b3b072463e76c1346ce Mon Sep 17 00:00:00 2001 From: "C. Proske" Date: Tue, 16 Apr 2019 17:23:02 +0200 Subject: [PATCH 056/280] info tab --- version/102/adminmenu/tpl/info.tpl | 124 +++++++++++++++++++---------- 1 file changed, 80 insertions(+), 44 deletions(-) diff --git a/version/102/adminmenu/tpl/info.tpl b/version/102/adminmenu/tpl/info.tpl index 0f78b79..6995522 100644 --- a/version/102/adminmenu/tpl/info.tpl +++ b/version/102/adminmenu/tpl/info.tpl @@ -1,57 +1,93 @@ -
+
-
X
-
X
-
X
-
-
-
X
-
X
-
-
-
X
-
-
- +
+ + + +
+
+ + + +
-
-
-
{if isset($update)} - -
-

Update auf Version {$update->version} verfügbar!

-
-
-
-
Version:
-
{$update->version}
+
+ +
+

Update auf Version {$update->version} verfügbar!

-
-
Erschienen:
-
{$update->create_date}
-
-
-
Changelog:
-
+
+
+
Version:
+
{$update->version}
+
+
+
Erschienen:
+
{$update->create_date}
+
+
+
Changelog:
+
+ style="width: 100%">{$update->changelog|utf8_decode|htmlentities} +
-
-
-
-
- Download - Install +
+
+
+ {else} +
+ + + +
{/if} +
-
\ No newline at end of file +
+
+ + + +
+
+ + + +
+ +
+
+
+ + + +
+
+ + + +
+
+ + + +
+
+
From 4e3f466ab853c4aa34b9001f178ba3165ab72e73 Mon Sep 17 00:00:00 2001 From: "dash.bar" Date: Tue, 23 Apr 2019 11:55:32 +0200 Subject: [PATCH 057/280] update base files --- version/102/adminmenu/info.php | 26 +++-- version/102/class/Helper.php | 173 ++++++++++++++++----------------- 2 files changed, 95 insertions(+), 104 deletions(-) diff --git a/version/102/adminmenu/info.php b/version/102/adminmenu/info.php index ece4f2b..4a3f09a 100644 --- a/version/102/adminmenu/info.php +++ b/version/102/adminmenu/info.php @@ -1,25 +1,23 @@ assign('defaultTabbertab', Helper::getAdminmenu('Info')); - Helper::selfupdate(); + Shop::Smarty()->assign('defaultTabbertab', \ws_mollie\Helper::getAdminmenu('Info')); + \ws_mollie\Helper::selfupdate(); } $svgQuery = http_build_query([ - 'p' => Helper::oPlugin()->cPluginID, - 'v' => Helper::oPlugin()->nVersion, + 'p' => \ws_mollie\Helper::oPlugin()->cPluginID, + 'v' => \ws_mollie\Helper::oPlugin()->nVersion, 's' => defined('APPLICATION_VERSION') ? APPLICATION_VERSION : JTL_VERSION, - 'd' => Helper::getDomain(), + 'd' => \ws_mollie\Helper::getDomain(), 'php' => PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION . '.' . PHP_RELEASE_VERSION, ]); - echo ""; + echo ""; echo "
" . "
" . " " . @@ -39,16 +37,16 @@ ''; try { - $latestRelease = Helper::getLatestRelease(array_key_exists('update', $_REQUEST)); - if ((int)Helper::oPlugin()->nVersion < (int)$latestRelease->version) { + $latestRelease = \ws_mollie\Helper::getLatestRelease(array_key_exists('update', $_REQUEST)); + if ((int)\ws_mollie\Helper::oPlugin()->nVersion < (int)$latestRelease->version) { Shop::Smarty()->assign('update', $latestRelease); } - } catch (Exception $e) { + } catch (\Exception $e) { } - Shop::Smarty()->display(Helper::oPlugin()->cAdminmenuPfad . '/tpl/info.tpl'); + Shop::Smarty()->display(\ws_mollie\Helper::oPlugin()->cAdminmenuPfad . '/tpl/info.tpl'); } catch (Exception $e) { echo "
Fehler: {$e->getMessage()}
"; - Helper::logExc($e); + \ws_mollie\Helper::logExc($e); } \ No newline at end of file diff --git a/version/102/class/Helper.php b/version/102/class/Helper.php index 88bf67c..7035a09 100644 --- a/version/102/class/Helper.php +++ b/version/102/class/Helper.php @@ -3,38 +3,31 @@ namespace ws_mollie { - use Exception; - use Jtllog; - use PclZip; - use Plugin; - use Shop; - use stdClass; - if (!class_exists('ws_mollie\Helper')) { /** - * Class Helper - * @package ws_mollie - */ + * Class Helper + * @package ws_mollie + */ final class Helper { /** - * Is ::autoload() already called? - * - * @var bool|null - */ + * Is ::autoload() already called? + * + * @var bool|null + */ private static $_autoload; /** - * @var Plugin - */ + * @var \Plugin + */ private static $oPlugin; /** - * Load Vendor Autoloader - * @return bool - */ + * Load Vendor Autoloader + * @return bool + */ public static function autoload() { if (null === self::$_autoload) { @@ -63,15 +56,15 @@ public static function autoload() } /** - * @throws Exception - */ + * @throws \Exception + */ public static function selfupdate() { - - if (function_exists('opcache_reset')) { + + if(function_exists('opcache_reset')){ opcache_reset(); } - + // 0. GET RELEASE INFO $release = self::getLatestRelease(true); $url = $release->short_url != '' ? $release->short_url : $release->full_url; @@ -81,21 +74,21 @@ public static function selfupdate() // 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!'); + 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!!"); + throw new \Exception("cURL ist nicht verf�gbar!!"); } if (!is_writable($tmpDir)) { - throw new Exception("Tempor�res Verzeichnis_'{$tmpDir}' ist nicht beschreibbar!"); + 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!"); + 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!"); + throw new \Exception("Tempor�re Datei '" . $tmpDir . $filename . "' konnte nicht gel�scht werden!"); } } @@ -110,35 +103,35 @@ public static function selfupdate() curl_close($ch); fclose($fp); if ($info['http_code'] !== 200) { - throw new Exception("Unerwarteter Status Code '" . $info['http_code'] . "'!"); + 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'] . "'!"); + 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); + $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!"); + throw new \Exception("Das Zip-Archiv ist leider ung�ltig!"); } else { $unzipPath = PFAD_ROOT . PFAD_PLUGIN; $res = $zip->extract(PCLZIP_OPT_PATH, $unzipPath); if ($res !== 0) { - header('Location: ' . Shop::getURL() . DIRECTORY_SEPARATOR . PFAD_ADMIN . 'pluginverwaltung.php', true); + header('Location: ' . \Shop::getURL() . DIRECTORY_SEPARATOR . PFAD_ADMIN . 'pluginverwaltung.php', true); } else { - throw new Exception('Entpacken fehlgeschlagen: ' . $zip->errorCode()); + throw new \Exception('Entpacken fehlgeschlagen: ' . $zip->errorCode()); } } } /** - * @param bool $force - * @return mixed - * @throws Exception - */ + * @param bool $force + * @return mixed + * @throws \Exception + */ public static function getLatestRelease($force = false) { $lastCheck = (int)self::getSetting(__NAMESPACE__ . '_upd'); @@ -156,11 +149,11 @@ public static function getLatestRelease($force = false) $statusCode = (int)curl_getinfo($curl, CURLINFO_HTTP_CODE); @curl_close($curl); if ($statusCode !== 200) { - throw new Exception(__NAMESPACE__ . ': Could not fetch release info: ' . $statusCode); + 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); + 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)); @@ -171,10 +164,10 @@ public static function getLatestRelease($force = false) } /** - * Register PSR-4 autoloader - * Licence-Check - * @return bool - */ + * Register PSR-4 autoloader + * Licence-Check + * @return bool + */ public static function init() { ini_set('xdebug.default_enable', defined('WS_XDEBUG_ENABLED')); @@ -182,23 +175,23 @@ public static function init() } /** - * Sets a Plugin Setting and saves it to the DB - * - * @param $name - * @param $value - * @return int - */ + * 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 = 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); + $return = \Shop::DB()->updateRow('tplugineinstellungen', ['kPlugin', 'cName'], [$setting->kPlugin, $setting->cName], $setting); } else { - $return = Shop::DB()->insertRow('tplugineinstellungen', $setting); + $return = \Shop::DB()->insertRow('tplugineinstellungen', $setting); } self::oPlugin()->oPluginEinstellungAssoc_arr[$name] = $value; self::oPlugin(true); // invalidate cache @@ -206,41 +199,41 @@ public static function setSetting($name, $value) } /** - * Get Plugin Object - * - * @param bool $force disable Cache - * @return Plugin|null - */ + * 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); + self::$oPlugin = new \Plugin(self::oPlugin(false)->kPlugin, true); } else if (null === self::$oPlugin) { - self::$oPlugin = Plugin::getPluginById(__NAMESPACE__); + self::$oPlugin = \Plugin::getPluginById(__NAMESPACE__); } return self::$oPlugin; } /** - * get a Plugin setting - * - * @param $name - * @return null|mixed - */ + * get a Plugin setting + * + * @param $name + * @return null|mixed + */ public static function getSetting($name) { - if (array_key_exists($name, self::oPlugin()->oPluginEinstellungAssoc_arr ?: [])) { + 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 - */ + * Get Domain frpm URL_SHOP without www. + * + * @param string $url + * @return string + */ public static function getDomain($url = URL_SHOP) { $matches = array(); @@ -249,40 +242,40 @@ public static function getDomain($url = URL_SHOP) } /** - * @return mixed - */ + * @return mixed + */ private static function _masterMail() { - $settings = Shop::getSettings(array(CONF_EMAILS)); + $settings = \Shop::getSettings(array(CONF_EMAILS)); return $settings['emails']['email_master_absender']; } /** - * @param Exception $exc - * @param bool $trace - * @return void - */ - public static function logExc(Exception $exc, $trace = true) + * @param \Exception $exc + * @param bool $trace + * @return void + */ + public static function logExc(\Exception $exc, $trace = true) { - Jtllog::writeLog(__NAMESPACE__ . ': ' . $exc->getMessage() . ($trace ? ' - ' . $exc->getTraceAsString() : '')); + \Jtllog::writeLog(__NAMESPACE__ . ': ' . $exc->getMessage() . ($trace ? ' - ' . $exc->getTraceAsString() : '')); } /** - * Checks if admin session is loaded - * - * @return bool - */ + * 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 - */ + * Returns kAdminmenu ID for given Title, used for Tabswitching + * + * @param $name string CustomLink Title + * @return int + */ public static function getAdminmenu($name) { $kPluginAdminMenu = 0; From 42e4b232917c6abb38ff83173714efd9e24c754e Mon Sep 17 00:00:00 2001 From: "dash.bar" Date: Tue, 23 Apr 2019 16:37:03 +0200 Subject: [PATCH 058/280] prepare finalize --- info.xml | 54 ++++++++++++------------- version/100/class/Mollie.php | 1 - version/100/frontend/140_smarty.php | 3 +- version/101/adminmenu/info.php | 3 +- version/101/class/Helper.php | 4 +- version/101/frontend/140_smarty.php | 3 +- version/102/adminmenu/info.php | 3 +- version/102/class/Helper.php | 6 +-- version/102/class/Mollie.php | 2 - version/102/frontend/140_smarty.php | 3 +- version/102/paymentmethod/JTLMollie.php | 2 - 11 files changed, 38 insertions(+), 46 deletions(-) diff --git a/info.xml b/info.xml index f2dbc03..e4fecf7 100644 --- a/info.xml +++ b/info.xml @@ -1,7 +1,7 @@ mollie - Zahlungsartplugin für mollie.com + Zahlungsartplugin für mollie.com WebStollen http://www.webstollen.de/ 102 @@ -16,7 +16,7 @@ 2019-02-26 - 2019-04-01 + 2019-04-23 131_globalinclude.php @@ -41,23 +41,23 @@ Einstellungen API Key: - Füge hier deinen mollie API Key ein + Füge hier deinen mollie API Key ein api_key Zahlungsart Daten syncronisiernen - Lädt Name / Bild für die jeweilige Sprache automatisch von mollie, und speichert diese in der Datenbank + Lädt Name / Bild für die jeweilige Sprache automatisch von mollie, und speichert diese in der Datenbank paymentmethod_sync - - + + Checkout Styles laden - Lädt Stylesheets für das Evo Template, um den Checkout zu verschönern. + Lädt Stylesheets für das Evo Template, um den Checkout zu verschönern. load_styles @@ -70,7 +70,7 @@ mollie - + 1 0 mollie.com @@ -90,7 +90,7 @@ mollie Kreditkarte - + 2 0 mollie.com @@ -110,7 +110,7 @@ mollie Bitcoin - + 3 0 mollie.com @@ -130,7 +130,7 @@ mollie Bancontact - + 4 0 mollie.com @@ -150,7 +150,7 @@ mollie Banktransfer - + 5 0 mollie.com @@ -163,14 +163,14 @@ JTLMollieBanktransfer tpl/bestellabschluss.tpl - SEPA Überweisung + SEPA Ãœberweisung mollie - Bezahlen Sie bequem mit SEPA Überweisung. + Bezahlen Sie bequem mit SEPA Ãœberweisung. mollie Belfius - + 6 0 mollie.com @@ -190,7 +190,7 @@ mollie DirectDebit - + 7 0 mollie.com @@ -210,7 +210,7 @@ mollie EPS - + 2 0 mollie.com @@ -230,7 +230,7 @@ mollie Giftcard - + 8 0 mollie.com @@ -250,7 +250,7 @@ mollie Giropay - + 9 0 mollie.com @@ -270,7 +270,7 @@ mollie iDEAL - + 10 0 mollie.com @@ -290,7 +290,7 @@ mollie ING HomePay - + 11 0 mollie.com @@ -310,7 +310,7 @@ mollie KBC - + 12 0 mollie.com @@ -330,7 +330,7 @@ mollie PayPal - + 13 0 mollie.com @@ -350,7 +350,7 @@ mollie paysafecard - + 14 0 mollie.com @@ -370,7 +370,7 @@ mollie SOFORT - + 15 0 mollie.com @@ -390,7 +390,7 @@ mollie Klarna Pay Later - + 16 0 mollie.com @@ -410,7 +410,7 @@ mollie Klarna Slice It - + 17 0 mollie.com diff --git a/version/100/class/Mollie.php b/version/100/class/Mollie.php index 9a0a88d..6ad4b88 100644 --- a/version/100/class/Mollie.php +++ b/version/100/class/Mollie.php @@ -23,7 +23,6 @@ abstract class Mollie { - protected static $_jtlmollie; /** diff --git a/version/100/frontend/140_smarty.php b/version/100/frontend/140_smarty.php index 2735ee7..56a6400 100644 --- a/version/100/frontend/140_smarty.php +++ b/version/100/frontend/140_smarty.php @@ -26,7 +26,8 @@ } - pq('head')->append(<<append( + << /* MOLLIE CHECKOUT STYLES*/ #fieldset-payment .form-group > div:hover, #checkout-shipping-payment .form-group > div:hover { diff --git a/version/101/adminmenu/info.php b/version/101/adminmenu/info.php index ece4f2b..4cfb99b 100644 --- a/version/101/adminmenu/info.php +++ b/version/101/adminmenu/info.php @@ -43,7 +43,6 @@ if ((int)Helper::oPlugin()->nVersion < (int)$latestRelease->version) { Shop::Smarty()->assign('update', $latestRelease); } - } catch (Exception $e) { } @@ -51,4 +50,4 @@ } catch (Exception $e) { echo "
Fehler: {$e->getMessage()}
"; Helper::logExc($e); -} \ No newline at end of file +} diff --git a/version/101/class/Helper.php b/version/101/class/Helper.php index 88bf67c..b617edf 100644 --- a/version/101/class/Helper.php +++ b/version/101/class/Helper.php @@ -67,7 +67,6 @@ public static function autoload() */ public static function selfupdate() { - if (function_exists('opcache_reset')) { opcache_reset(); } @@ -215,7 +214,7 @@ public static function oPlugin($force = false) { if ($force === true) { self::$oPlugin = new Plugin(self::oPlugin(false)->kPlugin, true); - } else if (null === self::$oPlugin) { + } elseif (null === self::$oPlugin) { self::$oPlugin = Plugin::getPluginById(__NAMESPACE__); } return self::$oPlugin; @@ -294,7 +293,6 @@ public static function getAdminmenu($name) } return $kPluginAdminMenu; } - } } diff --git a/version/101/frontend/140_smarty.php b/version/101/frontend/140_smarty.php index 2735ee7..56a6400 100644 --- a/version/101/frontend/140_smarty.php +++ b/version/101/frontend/140_smarty.php @@ -26,7 +26,8 @@ } - pq('head')->append(<<append( + << /* MOLLIE CHECKOUT STYLES*/ #fieldset-payment .form-group > div:hover, #checkout-shipping-payment .form-group > div:hover { diff --git a/version/102/adminmenu/info.php b/version/102/adminmenu/info.php index 4a3f09a..975d723 100644 --- a/version/102/adminmenu/info.php +++ b/version/102/adminmenu/info.php @@ -41,7 +41,6 @@ if ((int)\ws_mollie\Helper::oPlugin()->nVersion < (int)$latestRelease->version) { Shop::Smarty()->assign('update', $latestRelease); } - } catch (\Exception $e) { } @@ -49,4 +48,4 @@ } catch (Exception $e) { echo "
Fehler: {$e->getMessage()}
"; \ws_mollie\Helper::logExc($e); -} \ No newline at end of file +} diff --git a/version/102/class/Helper.php b/version/102/class/Helper.php index 7035a09..69b0e2e 100644 --- a/version/102/class/Helper.php +++ b/version/102/class/Helper.php @@ -60,8 +60,7 @@ public static function autoload() */ public static function selfupdate() { - - if(function_exists('opcache_reset')){ + if (function_exists('opcache_reset')) { opcache_reset(); } @@ -208,7 +207,7 @@ public static function oPlugin($force = false) { if ($force === true) { self::$oPlugin = new \Plugin(self::oPlugin(false)->kPlugin, true); - } else if (null === self::$oPlugin) { + } elseif (null === self::$oPlugin) { self::$oPlugin = \Plugin::getPluginById(__NAMESPACE__); } return self::$oPlugin; @@ -287,7 +286,6 @@ public static function getAdminmenu($name) } return $kPluginAdminMenu; } - } } diff --git a/version/102/class/Mollie.php b/version/102/class/Mollie.php index 6074f72..48c865f 100644 --- a/version/102/class/Mollie.php +++ b/version/102/class/Mollie.php @@ -207,7 +207,6 @@ public static function JTLMollie() public static function getLocales() { - $locales = ['en_US', 'nl_NL', 'nl_BE', @@ -418,6 +417,5 @@ public static function getCurrencies() } return $result; - } } diff --git a/version/102/frontend/140_smarty.php b/version/102/frontend/140_smarty.php index 2735ee7..56a6400 100644 --- a/version/102/frontend/140_smarty.php +++ b/version/102/frontend/140_smarty.php @@ -26,7 +26,8 @@ } - pq('head')->append(<<append( + << /* MOLLIE CHECKOUT STYLES*/ #fieldset-payment .form-group > div:hover, #checkout-shipping-payment .form-group > div:hover { diff --git a/version/102/paymentmethod/JTLMollie.php b/version/102/paymentmethod/JTLMollie.php index 1129286..f52dbda 100644 --- a/version/102/paymentmethod/JTLMollie.php +++ b/version/102/paymentmethod/JTLMollie.php @@ -225,7 +225,6 @@ protected function getOrderData(Bestellung $order, $hash) /** @var WarenkorbPos $oPosition */ foreach ($order->Positionen as $oPosition) { - $unitPrice = berechneBrutto($order->Waehrung->fFaktor * $oPosition->fPreis, $oPosition->fMwSt, 4); $totalAmount = $oPosition->nAnzahl * $unitPrice; @@ -451,7 +450,6 @@ public function isSelectable() $locale = self::getLocale($_SESSION['cISOSprache'], $_SESSION['Kunde']->cLand); if (static::MOLLIE_METHOD !== '') { try { - $method = self::PossiblePaymentMethods(static::MOLLIE_METHOD, $locale, $_SESSION['Kunde']->cLand, $_SESSION['Waehrung']->cISO, $wk->gibGesamtsummeWaren() * $_SESSION['Waehrung']->fFaktor); if ($method !== null) { $this->updatePaymentMethod($_SESSION['cISOSprache'], $method); From 9f316363d418635aae958a2ca0871cb918ef18d2 Mon Sep 17 00:00:00 2001 From: "dash.bar" Date: Tue, 23 Apr 2019 16:37:04 +0200 Subject: [PATCH 059/280] init version 103 --- info.xml | 3 + version/103/adminmenu/info.php | 51 ++ version/103/adminmenu/orders.php | 154 +++++ version/103/adminmenu/paymentmethods.php | 56 ++ version/103/adminmenu/tpl/info.tpl | 93 +++ .../tpl/mollie-account-erstellen.png | Bin 0 -> 38998 bytes version/103/adminmenu/tpl/order.tpl | 217 +++++++ version/103/adminmenu/tpl/orders.tpl | 107 ++++ version/103/adminmenu/tpl/paymentmethods.tpl | 92 +++ version/103/class/Helper.php | 292 ++++++++++ version/103/class/Model/AbstractModel.php | 7 + version/103/class/Model/Payment.php | 77 +++ version/103/class/Mollie.php | 421 ++++++++++++++ version/103/frontend/131_globalinclude.php | 72 +++ version/103/frontend/140_smarty.php | 52 ++ version/103/frontend/144_notify.php | 31 + version/103/frontend/181_sync.php | 38 ++ version/103/paymentmethod/JTLMollie.php | 548 ++++++++++++++++++ .../103/paymentmethod/JTLMollieBancontact.php | 8 + .../paymentmethod/JTLMollieBanktransfer.php | 8 + .../103/paymentmethod/JTLMollieBelfius.php | 8 + .../103/paymentmethod/JTLMollieBitcoin.php | 8 + .../103/paymentmethod/JTLMollieCreditCard.php | 8 + .../paymentmethod/JTLMollieDirectDebit.php | 8 + version/103/paymentmethod/JTLMollieEPS.php | 8 + .../103/paymentmethod/JTLMollieGiftcard.php | 8 + .../103/paymentmethod/JTLMollieGiropay.php | 8 + version/103/paymentmethod/JTLMollieIDEAL.php | 8 + .../103/paymentmethod/JTLMollieINGHomePay.php | 8 + version/103/paymentmethod/JTLMollieKBC.php | 8 + .../paymentmethod/JTLMollieKlarnaPayLater.php | 8 + .../paymentmethod/JTLMollieKlarnaSliceIt.php | 8 + version/103/paymentmethod/JTLMolliePayPal.php | 8 + .../paymentmethod/JTLMolliePaysafecard.php | 8 + version/103/paymentmethod/JTLMollieSofort.php | 8 + .../paymentmethod/tpl/bestellabschluss.tpl | 5 + 36 files changed, 2452 insertions(+) create mode 100644 version/103/adminmenu/info.php create mode 100644 version/103/adminmenu/orders.php create mode 100644 version/103/adminmenu/paymentmethods.php create mode 100644 version/103/adminmenu/tpl/info.tpl create mode 100644 version/103/adminmenu/tpl/mollie-account-erstellen.png create mode 100644 version/103/adminmenu/tpl/order.tpl create mode 100644 version/103/adminmenu/tpl/orders.tpl create mode 100644 version/103/adminmenu/tpl/paymentmethods.tpl create mode 100644 version/103/class/Helper.php create mode 100644 version/103/class/Model/AbstractModel.php create mode 100644 version/103/class/Model/Payment.php create mode 100644 version/103/class/Mollie.php create mode 100644 version/103/frontend/131_globalinclude.php create mode 100644 version/103/frontend/140_smarty.php create mode 100644 version/103/frontend/144_notify.php create mode 100644 version/103/frontend/181_sync.php create mode 100644 version/103/paymentmethod/JTLMollie.php create mode 100644 version/103/paymentmethod/JTLMollieBancontact.php create mode 100644 version/103/paymentmethod/JTLMollieBanktransfer.php create mode 100644 version/103/paymentmethod/JTLMollieBelfius.php create mode 100644 version/103/paymentmethod/JTLMollieBitcoin.php create mode 100644 version/103/paymentmethod/JTLMollieCreditCard.php create mode 100644 version/103/paymentmethod/JTLMollieDirectDebit.php create mode 100644 version/103/paymentmethod/JTLMollieEPS.php create mode 100644 version/103/paymentmethod/JTLMollieGiftcard.php create mode 100644 version/103/paymentmethod/JTLMollieGiropay.php create mode 100644 version/103/paymentmethod/JTLMollieIDEAL.php create mode 100644 version/103/paymentmethod/JTLMollieINGHomePay.php create mode 100644 version/103/paymentmethod/JTLMollieKBC.php create mode 100644 version/103/paymentmethod/JTLMollieKlarnaPayLater.php create mode 100644 version/103/paymentmethod/JTLMollieKlarnaSliceIt.php create mode 100644 version/103/paymentmethod/JTLMolliePayPal.php create mode 100644 version/103/paymentmethod/JTLMolliePaysafecard.php create mode 100644 version/103/paymentmethod/JTLMollieSofort.php create mode 100644 version/103/paymentmethod/tpl/bestellabschluss.tpl diff --git a/info.xml b/info.xml index e4fecf7..d817391 100644 --- a/info.xml +++ b/info.xml @@ -18,6 +18,9 @@ 2019-04-23 + + 2019-04-23 + 131_globalinclude.php 144_notify.php diff --git a/version/103/adminmenu/info.php b/version/103/adminmenu/info.php new file mode 100644 index 0000000..975d723 --- /dev/null +++ b/version/103/adminmenu/info.php @@ -0,0 +1,51 @@ +assign('defaultTabbertab', \ws_mollie\Helper::getAdminmenu('Info')); + \ws_mollie\Helper::selfupdate(); + } + + $svgQuery = http_build_query([ + 'p' => \ws_mollie\Helper::oPlugin()->cPluginID, + 'v' => \ws_mollie\Helper::oPlugin()->nVersion, + 's' => defined('APPLICATION_VERSION') ? APPLICATION_VERSION : JTL_VERSION, + 'd' => \ws_mollie\Helper::getDomain(), + 'php' => PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION . '.' . PHP_RELEASE_VERSION, + ]); + + echo ""; + echo "
" . + "
" . + " " . + " Lizenz Informationen" . + ' ' . + '
' . + "
" . + " " . + " Update Informationen" . + ' ' . + '
' . + "
" . + " " . + " Plugin informationen" . + ' ' . + '
' . + '
'; + + try { + $latestRelease = \ws_mollie\Helper::getLatestRelease(array_key_exists('update', $_REQUEST)); + if ((int)\ws_mollie\Helper::oPlugin()->nVersion < (int)$latestRelease->version) { + Shop::Smarty()->assign('update', $latestRelease); + } + } catch (\Exception $e) { + } + + Shop::Smarty()->display(\ws_mollie\Helper::oPlugin()->cAdminmenuPfad . '/tpl/info.tpl'); +} catch (Exception $e) { + echo "
Fehler: {$e->getMessage()}
"; + \ws_mollie\Helper::logExc($e); +} diff --git a/version/103/adminmenu/orders.php b/version/103/adminmenu/orders.php new file mode 100644 index 0000000..891f42a --- /dev/null +++ b/version/103/adminmenu/orders.php @@ -0,0 +1,154 @@ + 'danger', 'text' => 'Keine ID angeben!']; + break; + } + $payment = Payment::getPaymentMollie($_REQUEST['id']); + if (!$payment) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; + break; + } + + $order = JTLMollie::API()->orders->get($_REQUEST['id']); + if ($order->status == OrderStatus::STATUS_CANCELED) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung bereits storniert']; + 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; + break; + + case 'cancel': + if (!array_key_exists('id', $_REQUEST)) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; + break; + } + $payment = Payment::getPaymentMollie($_REQUEST['id']); + if (!$payment) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; + break; + } + $order = JTLMollie::API()->orders->get($_REQUEST['id']); + if ($order->status == OrderStatus::STATUS_CANCELED) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung bereits storniert']; + 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; + break; + + case 'capture': + if (!array_key_exists('id', $_REQUEST)) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; + break; + } + $payment = Payment::getPaymentMollie($_REQUEST['id']); + if (!$payment) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; + break; + } + $order = JTLMollie::API()->orders->get($_REQUEST['id']); + if ($order->status !== OrderStatus::STATUS_AUTHORIZED && $order->status !== OrderStatus::STATUS_SHIPPING) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Nur autorisierte Zahlungen können erfasst werden!']; + break; + } + + $oBestellung = new Bestellung($payment->kBestellung, true); + if (!$oBestellung->kBestellung) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung konnte nicht geladen werden!']; + break; + } + + $logData = '#' . $payment->kBestellung . '$' . $payment->kID . "§" . $oBestellung->cBestellNr; + + $options = ['lines' => []]; + if ($oBestellung->cTracking) { + $tracking = new stdClass(); + $tracking->carrier = $oBestellung->cVersandartName; + $tracking->url = $oBestellung->cTrackingURL; + $tracking->code = $oBestellung->cTracking; + $options['tracking'] = $tracking; + } + + // CAPTURE ALL + $shipment = JTLMollie::API()->shipments->createFor($order, $options); + $ordersMsgs[] = (object)['type' => 'success', 'text' => 'Zahlung wurde erfolgreich erfasst!']; + Mollie::JTLMollie()->doLog('Shipment created
' . print_r(['options' => $options, 'shipment' => $shipment], 1) . '
', $logData); + goto order; + + case 'order': + order: + if (!array_key_exists('id', $_REQUEST)) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; + break; + } + + $order = JTLMollie::API()->orders->get($_REQUEST['id']); + $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", [ + ':kBestellung' => '%#' . ($payment->kBestellung ?: '##') . '%', + ':cBestellNr' => '%§' . ($payment->cOrderNumber ?: '§§') . '%', + ':MollieID' => '%$' . ($payment->kID ?: '$$') . '%', + ], 2); + + Shop::Smarty()->assign('payment', $payment) + ->assign('oBestellung', $oBestellung) + ->assign('order', $order) + ->assign('logs', $logs) + ->assign('ordersMsgs', $ordersMsgs); + Shop::Smarty()->display($oPlugin->cAdminmenuPfad . '/tpl/order.tpl'); + return; + } + } + + + $payments = Shop::DB()->executeQueryPrepared("SELECT * FROM xplugin_ws_mollie_payments WHERE kBestellung IS NOT NULL AND cStatus != 'created'", [], 2); + foreach ($payments as $i => $payment) { + $payments[$i]->oBestellung = new Bestellung($payment->kBestellung, false); + } + + Shop::Smarty()->assign('payments', $payments) + ->assign('ordersMsgs', $ordersMsgs) + ->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/103/adminmenu/paymentmethods.php b/version/103/adminmenu/paymentmethods.php new file mode 100644 index 0000000..b31532b --- /dev/null +++ b/version/103/adminmenu/paymentmethods.php @@ -0,0 +1,56 @@ +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) { + $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/103/adminmenu/tpl/info.tpl b/version/103/adminmenu/tpl/info.tpl new file mode 100644 index 0000000..6995522 --- /dev/null +++ b/version/103/adminmenu/tpl/info.tpl @@ -0,0 +1,93 @@ +
+
+
+ + + +
+
+ + + +
+ + {if isset($update)} +
+ +
+

Update auf Version {$update->version} verfügbar!

+
+
+
+
Version:
+
{$update->version}
+
+
+
Erschienen:
+
{$update->create_date}
+
+
+
Changelog:
+
+ +
+
+ +
+
+ +
+
+
+ {else} +
+ + + +
+ {/if} + +
+
+
+ + + +
+
+ + + +
+ +
+
+
+ + + +
+
+ + + +
+
+ + + +
+
+
diff --git a/version/103/adminmenu/tpl/mollie-account-erstellen.png b/version/103/adminmenu/tpl/mollie-account-erstellen.png new file mode 100644 index 0000000000000000000000000000000000000000..fc1819255ef725fa214cf2bf028cf3428794ecee GIT binary patch literal 38998 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 +

+ « + 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} +

+ +{if count($ordersMsgs)} + {foreach from=$ordersMsgs item=alert} +
{$alert->text}
+ {/foreach} +
+{/if} + +
Mode: {$profile->mode}
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Mollie ID:{$payment->kID}Mode:{$order->mode}Status:{$order->status}
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)}
+ +

Positionen:

+ +
+ {if ($order->status === 'authorized' || $order->status === 'shipping') && $oBestellung->cStatus|intval >= 3} + + Zahlung erfassen1 + + {/if} + {if $order->amount->value > $order->amountRefunded->value && $order->amountCaptured->value > 0} + Rckerstatten2 + + {/if} + {if $order->isCancelable} + Stornieren3 + + {/if} +
+ + + + + + + + + + + + + + + + + + {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} + + + + + + + + + + + + + {/foreach} + + + + + + + + + + +
StatusSKUNameTypAnzahlMwStSteuerNettoBrutto 
+ {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*} +
{$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} + + + + + + + {/foreach} +
+ {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}
+ + diff --git a/version/103/adminmenu/tpl/orders.tpl b/version/103/adminmenu/tpl/orders.tpl new file mode 100644 index 0000000..3956ef5 --- /dev/null +++ b/version/103/adminmenu/tpl/orders.tpl @@ -0,0 +1,107 @@ + +{if count($ordersMsgs)} + {foreach from=$ordersMsgs item=alert} +
{$alert->text}
+ {/foreach} +
+{/if} + +{if $hasAPIKey == false} + + Jetzt kostenlos Mollie Account eröffnen! + +{else} + + + + + + + + + + + + + + + + {foreach from=$payments item=payment} + + + + + + + + + + + + {/foreach} + +
BestellNr.IDMollie StatusJTL StatusBetragWährungLocaleMethodeErstellt
+ {$payment->cOrderNumber} + {if $payment->cMode == 'test'} + TEST + {/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->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)}
+ + +{/if} \ No newline at end of file diff --git a/version/103/adminmenu/tpl/paymentmethods.tpl b/version/103/adminmenu/tpl/paymentmethods.tpl new file mode 100644 index 0000000..260290f --- /dev/null +++ b/version/103/adminmenu/tpl/paymentmethods.tpl @@ -0,0 +1,92 @@ +

Account Status

+ + + + + + + + + +
Mode:{$profile->mode}Status:{$profile->status}Review:{$profile->review->status}
+ +
+ +
+
+ + +
+ + + +
+
+ + +
+
+ + +
+
+ + + reset +
+
+
+ + +{if $allMethods && $allMethods|count} + + + + + + + + + + + + {foreach from=$allMethods item=method} + + + + + + + + {/foreach} + +
BildIDNamePreiseInfos
{$method->description|utf8_decode}{$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} +
+{else} +
Es konnten keine Methoden abgerufen werden.
+{/if} \ No newline at end of file diff --git a/version/103/class/Helper.php b/version/103/class/Helper.php new file mode 100644 index 0000000..69b0e2e --- /dev/null +++ b/version/103/class/Helper.php @@ -0,0 +1,292 @@ +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); + 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(); + } + + /** + * 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); + } elseif (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); + } + + /** + * @return mixed + */ + private static function _masterMail() + { + $settings = \Shop::getSettings(array(CONF_EMAILS)); + return $settings['emails']['email_master_absender']; + } + + /** + * @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/103/class/Model/AbstractModel.php b/version/103/class/Model/AbstractModel.php new file mode 100644 index 0000000..5638700 --- /dev/null +++ b/version/103/class/Model/AbstractModel.php @@ -0,0 +1,7 @@ + $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, + ]; + 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; + } + + 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/103/class/Mollie.php b/version/103/class/Mollie.php new file mode 100644 index 0000000..48c865f --- /dev/null +++ b/version/103/class/Mollie.php @@ -0,0 +1,421 @@ +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) { + header('Location: ' . $url); + 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; + } + + switch ((int)$newStatus) { + case BESTELLUNG_STATUS_VERSANDT: + $options['lines'] = []; + break; + case BESTELLUNG_STATUS_TEILVERSANDT: + $lines = []; + foreach ($order->lines as $i => $line) { + if (($quantity = Mollie::getBestellPosSent($line->sku, $oBestellung)) !== false && ($quantity - $line->quantityShipped) > 0) { + $x = $quantity - $line->quantityShipped; + $lines[] = (object)[ + 'id' => $line->id, + 'quantity' => $x, + 'amount' => (object)[ + 'currency' => $line->totalAmount->currency, + 'value' => number_format($x * $line->unitPrice->value, 2), + ], + ]; + } + } + if (count($lines)) { + $options['lines'] = $lines; + } + break; + case BESTELLUNG_STATUS_STORNO: + $options = null; + break; + } + + return $options; + } + + /** + * 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; + } + + /** + * @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) { + $order->orderNumber = $oBestellung->cBestellNr; + Payment::updateFromPayment($order, $kBestellung); + + $oIncomingPayment = Shop::DB()->executeQueryPrepared("SELECT * FROM tzahlungseingang WHERE cHinweis = :cHinweis AND kBestellung = :kBestellung", [':cHinweis' => $order->id, ':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: + $oIncomingPayment->fBetrag = $order->amount->value; + $oIncomingPayment->cISO = $order->amount->currency; + $oIncomingPayment->cHinweis = $order->id; + Mollie::JTLMollie()->addIncomingPayment($oBestellung, $oIncomingPayment); + Mollie::JTLMollie()->setOrderStatusToPaid($oBestellung); + Mollie::JTLMollie()->doLog('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('PaymentStatus: ' . $order->status . ' => Bestellung bezahlt, KEIN Zahlungseingang', $logData, LOGLEVEL_NOTICE); + break; + case OrderStatus::STATUS_CANCELED: + case OrderStatus::STATUS_EXPIRED: + Mollie::JTLMollie()->doLog('PaymentStatus: ' . $order->status, $logData, LOGLEVEL_ERROR); + break; + } + return true; + } + return false; + } + + /** + * @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; + } + + 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/103/frontend/131_globalinclude.php b/version/103/frontend/131_globalinclude.php new file mode 100644 index 0000000..45d4c6f --- /dev/null +++ b/version/103/frontend/131_globalinclude.php @@ -0,0 +1,72 @@ +executeQueryPrepared("SELECT * FROM " . \ws_mollie\Model\Payment::TABLE . " WHERE cHash = :cHash", [':cHash' => $_REQUEST['mollie']], 1); + // Bestellung finalized, redirect to status/completion page + if ((int)$payment->kBestellung) { + $logData = '$' . $payment->kID . '#' . $payment->kBestellung . "§" . $payment->cOrderNumber; + Mollie::JTLMollie()->doLog('Bestellung finalized => redirect abschluss/status', $logData); + $order = JTLMollie::API()->orders->get($payment->kID, ['embed' => 'payments']); + Mollie::handleOrder($order, $payment->kBestellung); + Mollie::getOrderCompletedRedirect($payment->kBestellung, true); + } elseif ($payment) { // payment, but no order => finalize it + require_once __DIR__ . '/../paymentmethod/JTLMollie.php'; + $order = JTLMollie::API()->orders->get($payment->kID, ['embed' => 'payments']); + $logData = '$' . $order->id . '#' . $payment->kBestellung . "§" . $payment->cOrderNumber; + + // GET NEWEST PAYMENT: + /** @var Payment $_payment */ + $_payment = null; + if ($order->payments()) { + /** @var Payment $p */ + foreach ($order->payments() as $p) { + if (!$_payment) { + $_payment = $p; + continue; + } + if (strtotime($p->createdAt) > strtotime($_payment->createdAt)) { + $_payment = $p; + } + } + } + + // finalize only, if order is not canceld/expired + if ($order && !$order->isCanceled() && !$order->isExpired()) { + // finalize only if payment is not expired/canceled,failed or open + if ($_payment && !in_array($_payment->status, [PaymentStatus::STATUS_EXPIRED, PaymentStatus::STATUS_CANCELED, PaymentStatus::STATUS_OPEN, PaymentStatus::STATUS_FAILED, PaymentStatus::STATUS_CANCELED])) { + Mollie::JTLMollie()->doLog('Bestellung open => finalize', $logData); + $session = Session::getInstance(); + /** @noinspection PhpIncludeInspection */ + require_once PFAD_ROOT . 'includes/bestellabschluss_inc.php'; + /** @noinspection PhpIncludeInspection */ + require_once PFAD_ROOT . 'includes/mailTools.php'; + $oBestellung = fakeBestellung(); + $oBestellung = finalisiereBestellung(); + Mollie::JTLMollie()->doLog('Bestellung finalized => redirect
' . print_r($order, 1) . '
', $logData, LOGLEVEL_DEBUG); + Mollie::handleOrder($order, $oBestellung->kBestellung); + Mollie::getOrderCompletedRedirect($oBestellung->kBestellung, true); + } else { + Mollie::JTLMollie()->doLog('Invalid Payment
' . print_r($payment, 1) . '
', $logData, LOGLEVEL_ERROR); + } + } else { + Mollie::JTLMollie()->doLog('Invalid Order
' . print_r($order, 1) . '
', $logData, LOGLEVEL_ERROR); + } + } + } + ob_end_flush(); +} catch (Exception $e) { + Helper::logExc($e); +} diff --git a/version/103/frontend/140_smarty.php b/version/103/frontend/140_smarty.php new file mode 100644 index 0000000..56a6400 --- /dev/null +++ b/version/103/frontend/140_smarty.php @@ -0,0 +1,52 @@ +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/103/frontend/144_notify.php b/version/103/frontend/144_notify.php new file mode 100644 index 0000000..a2af9f2 --- /dev/null +++ b/version/103/frontend/144_notify.php @@ -0,0 +1,31 @@ + Update Payment, stop skript + * - ELSE weiter mit der notify.php + */ + +use ws_mollie\Helper; +use ws_mollie\Model\Payment; +use ws_mollie\Mollie; + +if (array_key_exists('hash', $_REQUEST)) { + require_once __DIR__ . '/../class/Helper.php'; + try { + Helper::init(); + $payment = Payment::getPaymentHash($_REQUEST['hash']); + // If Bestellung already exists, treat as Notification + if ($payment && $payment->kBestellung) { + require_once __DIR__ . '/../paymentmethod/JTLMollie.php'; + $order = JTLMollie::API()->orders->get($payment->kID); + $logData = '#' . $payment->kBestellung . '$' . $payment->kID; + Mollie::JTLMollie()->doLog('Received Notification
' . print_r([$order, $payment], 1) . '
', $logData); + Mollie::handleOrder($order, $payment->kBestellung); + // exit to stop execution of notify.php + exit(); + } + } catch (Exception $e) { + Helper::logExc($e); + } +} diff --git a/version/103/frontend/181_sync.php b/version/103/frontend/181_sync.php new file mode 100644 index 0000000..5fb008e --- /dev/null +++ b/version/103/frontend/181_sync.php @@ -0,0 +1,38 @@ +kBestellung && $payment = Payment::getPayment($oBestellung->kBestellung)) { + $logData = '#' . $payment->kBestellung . '$' . $payment->kID . "§" . $oBestellung->cBestellNr; + Mollie::JTLMollie()->doLog("WAWI Abgleich: HOOK_BESTELLUNGEN_XML_BESTELLSTATUS", $logData); + 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()) { + Mollie::JTLMollie()->doLog("Create Shippment:
" . print_r($args_arr, 1) . '
', $logData, LOGLEVEL_DEBUG); + $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); + } else { + 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/103/paymentmethod/JTLMollie.php b/version/103/paymentmethod/JTLMollie.php new file mode 100644 index 0000000..f52dbda --- /dev/null +++ b/version/103/paymentmethod/JTLMollie.php @@ -0,0 +1,548 @@ + (int)$order->kBestellung, + 'cZahlungsanbieter' => empty($order->cZahlungsartName) ? $this->name : $order->cZahlungsartName, + 'fBetrag' => 0, + 'fZahlungsgebuehr' => 0, + 'cISO' => $_SESSION['Waehrung']->cISO, + 'cEmpfaenger' => '', + 'cZahler' => '', + 'dZeit' => 'now()', + 'cHinweis' => '', + 'cAbgeholt' => 'N' + ], (array)$payment); + if (isset($model->kZahlungseingang) && $model->kZahlungseingang > 0) { + Shop::DB()->update('tzahlungseingang', 'kZahlungseingang', $model->kZahlungseingang, $model); + } else { + Shop::DB()->insert('tzahlungseingang', $model); + } + + 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; + } + parent::setOrderStatusToPaid($order); + } + + /** + * Prepares everything so that the Customer can start the Payment Process. + * Tells Template Engine. + * + * @param Bestellung $order + */ + public function preparePaymentProcess($order) + { + $logData = '#' . $order->kBestellung . "" . $order->cBestellNr; + try { + $payment = Payment::getPayment($order->kBestellung); + $oMolliePayment = self::API()->orders->get($payment->kID); + 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); + exit(); + } + } catch (Exception $e) { + $this->doLog("Get Payment Error: " . $e->getMessage() . ". Create new ORDER...", $logData); + } + + try { + $hash = $this->generateHash($order); + $oMolliePayment = self::API()->orders->create($this->getOrderData($order, $hash)); + $_SESSION['oMolliePayment'] = $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($hash)); + Shop::Smarty()->assign('oMolliePayment', $oMolliePayment); + if (!$this->duringCheckout) { + Session::getInstance()->cleanUp(); + } + header('Location: ' . $oMolliePayment->getCheckoutUrl()); + exit(); + } catch (ApiException $e) { + Shop::Smarty()->assign('oMollieException', $e); + $this->doLog("Create Payment Error: " . $e->getMessage() . '
' . print_r($e->getTrace(), 1) . '
', $logData); + } + } + + /** + * @return MollieApiClient + * @throws ApiException + * @throws IncompatiblePlatform + */ + public static function API() + { + if (self::$_mollie === null) { + self::$_mollie = new MollieApiClient(); + 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 string $msg + * @param null $data + * @param int $level + * @return $this + */ + public function doLog($msg, $data = null, $level = LOGLEVEL_NOTICE) + { + ZahlungsLog::add($this->moduleID, $msg, $data, $level); + + return $this; + } + + /** + * @param Bestellung $order + * @param $hash + * @return array + */ + protected function getOrderData(Bestellung $order, $hash) + { + $locale = self::getLocale($_SESSION['cISOSprache'], $_SESSION['Kunde']->cLand); + $data = [ + 'locale' => $locale ?: 'de_DE', + 'amount' => (object)[ + 'currency' => $order->Waehrung->cISO, + 'value' => number_format($order->fGesamtsummeKundenwaehrung, 2, '.', ''), + ], + 'orderNumber' => $order->cBestellNr, + 'lines' => [], + 'billingAddress' => new stdClass(), + + 'redirectUrl' => (int)$this->duringCheckout ? Shop::getURL() . '/bestellabschluss.php?mollie=' . md5($hash) : $this->getReturnURL($order), + 'webhookUrl' => $this->getNotificationURL($hash) . '&hash=' . md5($hash), + ]; + + if (static::MOLLIE_METHOD !== '') { + $data['method'] = static::MOLLIE_METHOD; + } + $data['billingAddress']->organizationName = utf8_encode($order->oRechnungsadresse->cFirma); + $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 = $order->oRechnungsadresse->cMail; + $data['billingAddress']->streetAndNumber = utf8_encode($order->oRechnungsadresse->cStrasse . ' ' . $order->oRechnungsadresse->cHausnummer); + $data['billingAddress']->postalCode = $order->oRechnungsadresse->cPLZ; + $data['billingAddress']->city = utf8_encode($order->oRechnungsadresse->cOrt); + $data['billingAddress']->country = $order->oRechnungsadresse->cLand; + + if ($order->Lieferadresse != null) { + $data['shippingAddress'] = new stdClass(); + $data['shippingAddress']->organizationName = utf8_encode($order->Lieferadresse->cFirma); + $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 = $order->oRechnungsadresse->cMail; + $data['shippingAddress']->streetAndNumber = utf8_encode($order->Lieferadresse->cStrasse . ' ' . $order->Lieferadresse->cHausnummer); + $data['shippingAddress']->postalCode = $order->Lieferadresse->cPLZ; + $data['shippingAddress']->city = utf8_encode($order->Lieferadresse->cOrt); + $data['shippingAddress']->country = $order->Lieferadresse->cLand; + } + + /** @var WarenkorbPos $oPosition */ + foreach ($order->Positionen as $oPosition) { + $unitPrice = berechneBrutto($order->Waehrung->fFaktor * $oPosition->fPreis, $oPosition->fMwSt, 4); + $totalAmount = $oPosition->nAnzahl * $unitPrice; + + $line = new stdClass(); + $line->name = utf8_encode($oPosition->cName); + $line->quantity = $oPosition->nAnzahl; + $line->unitPrice = (object)[ + 'value' => number_format(round($unitPrice, 2), 2, '.', ''), + 'currency' => $order->Waehrung->cISO, + ]; + $line->totalAmount = (object)[ + 'value' => number_format(round($totalAmount, 2), 2, '.', ''), + 'currency' => $order->Waehrung->cISO, + ]; + $line->vatRate = $oPosition->fMwSt; + $x = $totalAmount - (berechneNetto($unitPrice, $oPosition->fMwSt, 4) * $oPosition->nAnzahl); + $line->vatAmount = (object)[ + 'value' => number_format(round($x, 2), 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 = $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->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->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 "eng": + return "en_US"; + 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"; + } + } + + /** + * @param Bestellung $order + * @param string $hash + * @param array $args + */ + public function handleNotification($order, $hash, $args) + { + Helper::autoload(); + $logData = '#' . $order->kBestellung . "" . $order->cBestellNr; + $this->doLog('Received Notification
' . print_r([$hash, $args], 1) . '
', $logData, LOGLEVEL_NOTICE); + + try { + $oMolliePayment = self::API()->orders->get($args['id']); + Mollie::handleOrder($oMolliePayment, $order->kBestellung); + } catch (Exception $e) { + $this->doLog('handleNotification: ' . $e->getMessage(), $logData); + } + } + + /** + * @param Bestellung $order + * @param string $hash + * @param array $args + * + * @return true, if $order should be finalized + */ + public function finalizeOrder($order, $hash, $args) + { + $logData = '#' . $order->kBestellung . "" . $order->cBestellNr; + try { + Helper::autoload(); + $oMolliePayment = self::API()->orders->get($args['id'], ['embed' => 'payments']); + $logData .= '$' . $oMolliePayment->id; + $this->doLog('Received Notification Finalize Order
' . print_r([$hash, $args, $oMolliePayment], 1) . '
', $logData, LOGLEVEL_DEBUG); + Payment::updateFromPayment($oMolliePayment, $order->kBestellung); + return in_array($oMolliePayment->status, [OrderStatus::STATUS_PAID, OrderStatus::STATUS_AUTHORIZED, OrderStatus::STATUS_PENDING, OrderStatus::STATUS_COMPLETED]); + } catch (Exception $e) { + $this->doLog($e->getMessage(), $logData); + } + return false; + } + + /** + * @return bool + */ + public function canPayAgain() + { + return true; + } + + /** + * determines, if the payment method can be selected in the checkout process + * + * @return bool + */ + public function isSelectable() + { + /** @var Warenkorb $wk */ + $wk = $_SESSION['Warenkorb']; + foreach ($wk->PositionenArr as $oPosition) { + if ($oPosition->Artikel->cTeilbar === 'Y' && fmod($oPosition->nAnzahl, 1) !== 0) { + return false; + } + } + + $locale = self::getLocale($_SESSION['cISOSprache'], $_SESSION['Kunde']->cLand); + if (static::MOLLIE_METHOD !== '') { + try { + $method = self::PossiblePaymentMethods(static::MOLLIE_METHOD, $locale, $_SESSION['Kunde']->cLand, $_SESSION['Waehrung']->cISO, $wk->gibGesamtsummeWaren() * $_SESSION['Waehrung']->fFaktor); + if ($method !== null) { + $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; + } + } + return true; + } + + /** + * @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, '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 (ws_mollie\Helper::getSetting('paymentmethod_sync') === 'N') { + return; + } + $size = ws_mollie\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 object $customer + * @param Warenkorb $cart + * @return bool - true, if $customer with $cart may use Payment Method + */ + public function isValid($customer, $cart) + { + if (Helper::init() && Helper::getSetting("api_key")) { + return true; + } + $this->doLog("isValdid failed: init failed or no API Key given. Try clear the Cache."); + return false; + } + + /** + * @param array $args_arr + * @return bool + */ + public function isValidIntern($args_arr = []) + { + if (Helper::init() && 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/103/paymentmethod/JTLMollieBancontact.php b/version/103/paymentmethod/JTLMollieBancontact.php new file mode 100644 index 0000000..0e5eeed --- /dev/null +++ b/version/103/paymentmethod/JTLMollieBancontact.php @@ -0,0 +1,8 @@ + + {$oMollieException->getMessage()} + +{/if} \ No newline at end of file From 70db2cc6e5b782fe2a0815b0dc8525ca21a7306d Mon Sep 17 00:00:00 2001 From: "C. Proske" Date: Tue, 23 Apr 2019 17:32:06 +0200 Subject: [PATCH 060/280] infoxml encoding --- info.xml | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/info.xml b/info.xml index d817391..d4f6e4a 100644 --- a/info.xml +++ b/info.xml @@ -1,7 +1,7 @@ mollie - Zahlungsartplugin für mollie.com + Zahlungsartplugin für mollie.com WebStollen http://www.webstollen.de/ 102 @@ -44,23 +44,25 @@ Einstellungen API Key: - Füge hier deinen mollie API Key ein + Füge hier deinen mollie API Key ein api_key Zahlungsart Daten syncronisiernen - Lädt Name / Bild für die jeweilige Sprache automatisch von mollie, und speichert diese in der Datenbank + Lädt Name / Bild für die jeweilige Sprache automatisch von mollie, und speichert diese + in der Datenbank + paymentmethod_sync - - + + Checkout Styles laden - Lädt Stylesheets für das Evo Template, um den Checkout zu verschönern. + Lädt Stylesheets für das Evo Template, um den Checkout zu verschönern. load_styles @@ -166,9 +168,9 @@ JTLMollieBanktransfer tpl/bestellabschluss.tpl - SEPA Ãœberweisung + SEPA Überweisung mollie - Bezahlen Sie bequem mit SEPA Ãœberweisung. + Bezahlen Sie bequem mit SEPA Überweisung. From 29d2cfd655f05f02cdfa7d525034f1bf84d6ceba Mon Sep 17 00:00:00 2001 From: "C. Proske" Date: Fri, 10 May 2019 11:23:36 +0200 Subject: [PATCH 061/280] prepare apple pay #31, fix #30 --- composer.lock | 56 ++++++++++--------- info.xml | 10 ++-- .../103/paymentmethod/JTLMollieApplePay.php | 8 +++ .../103/paymentmethod/JTLMollieBitcoin.php | 8 --- 4 files changed, 43 insertions(+), 39 deletions(-) create mode 100644 version/103/paymentmethod/JTLMollieApplePay.php delete mode 100644 version/103/paymentmethod/JTLMollieBitcoin.php diff --git a/composer.lock b/composer.lock index 013b129..ca854bf 100644 --- a/composer.lock +++ b/composer.lock @@ -247,16 +247,16 @@ }, { "name": "mollie/mollie-api-php", - "version": "v2.8.3", + "version": "v2.9.2", "source": { "type": "git", "url": "https://github.com/mollie/mollie-api-php.git", - "reference": "df6e0cea662f3c9603f245816cc2982e8ae49bcf" + "reference": "f108c626e3965a3cf9cce7ccad3044224f8ff2c8" }, "dist": { "type": "zip", - "url": "https://github.com/gitapi/repos/mollie/mollie-api-php/zipball/df6e0cea662f3c9603f245816cc2982e8ae49bcf", - "reference": "df6e0cea662f3c9603f245816cc2982e8ae49bcf", + "url": "https://github.com/gitapi/repos/mollie/mollie-api-php/zipball/f108c626e3965a3cf9cce7ccad3044224f8ff2c8", + "reference": "f108c626e3965a3cf9cce7ccad3044224f8ff2c8", "shasum": "" }, "require": { @@ -294,12 +294,12 @@ "homepage": "https://www.mollie.com/en/developers", "keywords": [ "CBC", + "Przelewy24", "api", "bancontact", "banktransfer", "belfius", "belfius direct net", - "bitcoin", "charges", "creditcard", "direct debit", @@ -328,7 +328,7 @@ "sofortbanking", "subscriptions" ], - "time": "2019-04-11T12:19:05+00:00" + "time": "2019-05-08T12:22:30+00:00" }, { "name": "psr/http-message", @@ -426,12 +426,12 @@ "source": { "type": "git", "url": "https://github.com/Roave/SecurityAdvisories.git", - "reference": "ff41a9a96718245c7160588928e6d217cfb0393c" + "reference": "2149b00d8c04ccbc71f38a261d0129d5b032b5df" }, "dist": { "type": "zip", - "url": "https://github.com/gitapi/repos/Roave/SecurityAdvisories/zipball/ff41a9a96718245c7160588928e6d217cfb0393c", - "reference": "ff41a9a96718245c7160588928e6d217cfb0393c", + "url": "https://github.com/gitapi/repos/Roave/SecurityAdvisories/zipball/2149b00d8c04ccbc71f38a261d0129d5b032b5df", + "reference": "2149b00d8c04ccbc71f38a261d0129d5b032b5df", "shasum": "" }, "conflict": { @@ -445,14 +445,14 @@ "aws/aws-sdk-php": ">=3,<3.2.1", "brightlocal/phpwhois": "<=4.2.5", "bugsnag/bugsnag-laravel": ">=2,<2.0.2", - "cakephp/cakephp": ">=1.3,<1.3.18|>=2,<2.4.99|>=2.5,<2.5.99|>=2.6,<2.6.12|>=2.7,<2.7.6|>=3,<3.0.15|>=3.1,<3.1.4|>=3.4,<3.4.14|>=3.5,<3.5.17|>=3.6,<3.6.4", + "cakephp/cakephp": ">=1.3,<1.3.18|>=2,<2.4.99|>=2.5,<2.5.99|>=2.6,<2.6.12|>=2.7,<2.7.6|>=3,<3.5.18|>=3.6,<3.6.15|>=3.7,<3.7.7", "cart2quote/module-quotation": ">=4.1.6,<=4.4.5|>=5,<5.4.4", "cartalyst/sentry": "<=2.1.6", "codeigniter/framework": "<=3.0.6", "composer/composer": "<=1.0.0-alpha11", "contao-components/mediaelement": ">=2.14.2,<2.21.1", "contao/core": ">=2,<3.5.39", - "contao/core-bundle": ">=4,<4.4.37|>=4.5,<4.7.3", + "contao/core-bundle": ">=4,<4.4.39|>=4.5,<4.7.5", "contao/listing-bundle": ">=4,<4.4.8", "contao/newsletter-bundle": ">=4,<4.1", "david-garcia/phpwhois": "<=4.3.1", @@ -466,8 +466,8 @@ "doctrine/mongodb-odm-bundle": ">=2,<3.0.1", "doctrine/orm": ">=2,<2.4.8|>=2.5,<2.5.1", "dompdf/dompdf": ">=0.6,<0.6.2", - "drupal/core": ">=7,<7.65|>=8,<8.5.14|>=8.6,<8.6.13", - "drupal/drupal": ">=7,<7.64|>=8,<8.5.13|>=8.6,<8.6.12", + "drupal/core": ">=7,<7.65|>=8,<8.5.14|>=8.6,<8.6.14", + "drupal/drupal": ">=7,<7.65|>=8,<8.5.14|>=8.6,<8.6.14", "erusev/parsedown": "<1.7.2", "ezsystems/ezpublish-kernel": ">=5.3,<5.3.12.1|>=5.4,<5.4.13.1|>=6,<6.7.9.1|>=6.8,<6.13.5.1|>=7,<7.2.4.1|>=7.3,<7.3.2.1", "ezsystems/ezpublish-legacy": ">=5.3,<5.3.12.6|>=5.4,<5.4.12.3|>=2011,<2017.12.4.3|>=2018.6,<2018.6.1.4|>=2018.9,<2018.9.1.3", @@ -496,9 +496,9 @@ "laravel/framework": ">=4,<4.0.99|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.42|>=5.6,<5.6.30", "laravel/socialite": ">=1,<1.0.99|>=2,<2.0.10", "league/commonmark": "<0.18.3", - "magento/magento1ce": "<1.9.4", - "magento/magento1ee": ">=1.9,<1.14.4", - "magento/product-community-edition": ">=2,<2.2.7", + "magento/magento1ce": "<1.9.4.1", + "magento/magento1ee": ">=1.9,<1.14.4.1", + "magento/product-community-edition": ">=2,<2.2.8|>=2.3,<2.3.1", "monolog/monolog": ">=1.8,<1.12", "namshi/jose": "<2.2", "onelogin/php-saml": "<2.10.4", @@ -530,7 +530,7 @@ "silverstripe/userforms": "<3", "simple-updates/phpwhois": "<=1", "simplesamlphp/saml2": "<1.10.6|>=2,<2.3.8|>=3,<3.1.4", - "simplesamlphp/simplesamlphp": "<1.16.3", + "simplesamlphp/simplesamlphp": "<1.15.2|>=1.16,<1.16.3", "simplesamlphp/simplesamlphp-module-infocard": "<1.0.1", "slim/slim": "<2.6", "smarty/smarty": "<3.1.33", @@ -541,23 +541,26 @@ "swiftmailer/swiftmailer": ">=4,<5.4.5", "sylius/admin-bundle": ">=1,<1.0.17|>=1.1,<1.1.9|>=1.2,<1.2.2", "sylius/sylius": ">=1,<1.0.17|>=1.1,<1.1.9|>=1.2,<1.2.2", - "symfony/dependency-injection": ">=2,<2.0.17", + "symfony/cache": ">=3.2,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", + "symfony/dependency-injection": ">=2,<2.0.17|>=2.7,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", "symfony/form": ">=2.3,<2.3.35|>=2.4,<2.6.12|>=2.7,<2.7.50|>=2.8,<2.8.49|>=3,<3.4.20|>=4,<4.0.15|>=4.1,<4.1.9|>=4.2,<4.2.1", - "symfony/framework-bundle": ">=2,<2.3.18|>=2.4,<2.4.8|>=2.5,<2.5.2", - "symfony/http-foundation": ">=2,<2.7.49|>=2.8,<2.8.44|>=3,<3.3.18|>=3.4,<3.4.14|>=4,<4.0.14|>=4.1,<4.1.3", + "symfony/framework-bundle": ">=2,<2.3.18|>=2.4,<2.4.8|>=2.5,<2.5.2|>=2.7,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", + "symfony/http-foundation": ">=2,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", "symfony/http-kernel": ">=2,<2.3.29|>=2.4,<2.5.12|>=2.6,<2.6.8", "symfony/intl": ">=2.7,<2.7.38|>=2.8,<2.8.31|>=3,<3.2.14|>=3.3,<3.3.13", + "symfony/phpunit-bridge": ">=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", "symfony/polyfill": ">=1,<1.10", "symfony/polyfill-php55": ">=1,<1.10", + "symfony/proxy-manager-bridge": ">=2.7,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", "symfony/routing": ">=2,<2.0.19", - "symfony/security": ">=2,<2.7.50|>=2.8,<2.8.49|>=3,<3.4.19|>=4,<4.0.15|>=4.1,<4.1.9|>=4.2,<4.2.1", + "symfony/security": ">=2,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", "symfony/security-bundle": ">=2,<2.7.48|>=2.8,<2.8.41|>=3,<3.3.17|>=3.4,<3.4.11|>=4,<4.0.11", "symfony/security-core": ">=2.4,<2.6.13|>=2.7,<2.7.9|>=2.7.30,<2.7.32|>=2.8,<2.8.37|>=3,<3.3.17|>=3.4,<3.4.7|>=4,<4.0.7", "symfony/security-csrf": ">=2.4,<2.7.48|>=2.8,<2.8.41|>=3,<3.3.17|>=3.4,<3.4.11|>=4,<4.0.11", "symfony/security-guard": ">=2.8,<2.8.41|>=3,<3.3.17|>=3.4,<3.4.11|>=4,<4.0.11", - "symfony/security-http": ">=2.3,<2.3.41|>=2.4,<2.7.50|>=2.8,<2.8.49|>=3,<3.4.20|>=4,<4.0.15|>=4.1,<4.1.9|>=4.2,<4.2.1", + "symfony/security-http": ">=2.3,<2.3.41|>=2.4,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", "symfony/serializer": ">=2,<2.0.11", - "symfony/symfony": ">=2,<2.7.50|>=2.8,<2.8.49|>=3,<3.4.20|>=4,<4.0.15|>=4.1,<4.1.9|>=4.2,<4.2.1", + "symfony/symfony": ">=2,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", "symfony/translation": ">=2,<2.0.17", "symfony/validator": ">=2,<2.0.24|>=2.1,<2.1.12|>=2.2,<2.2.5|>=2.3,<2.3.3", "symfony/web-profiler-bundle": ">=2,<2.3.19|>=2.4,<2.4.9|>=2.5,<2.5.4", @@ -569,10 +572,11 @@ "titon/framework": ">=0,<9.9.99", "truckersmp/phpwhois": "<=4.3.1", "twig/twig": "<1.38|>=2,<2.7", - "typo3/cms": ">=6.2,<6.2.30|>=7,<7.6.32|>=8,<8.7.23|>=9,<9.5.4", - "typo3/cms-core": ">=8,<8.7.23|>=9,<9.5.4", + "typo3/cms": ">=6.2,<6.2.30|>=7,<7.6.32|>=8,<8.7.25|>=9,<9.5.6", + "typo3/cms-core": ">=8,<8.7.25|>=9,<9.5.6", "typo3/flow": ">=1,<1.0.4|>=1.1,<1.1.1|>=2,<2.0.1|>=2.3,<2.3.16|>=3,<3.0.10|>=3.1,<3.1.7|>=3.2,<3.2.7|>=3.3,<3.3.5", "typo3/neos": ">=1.1,<1.1.3|>=1.2,<1.2.13|>=2,<2.0.4", + "typo3/phar-stream-wrapper": ">=1,<2.1.1|>=3,<3.1.1", "ua-parser/uap-php": "<3.8", "wallabag/tcpdf": "<6.2.22", "willdurand/js-translation-bundle": "<2.1.1", @@ -623,7 +627,7 @@ } ], "description": "Prevents installation of composer packages with known security vulnerabilities: no API, simply require it", - "time": "2019-04-12T16:05:24+00:00" + "time": "2019-05-08T13:51:25+00:00" } ], "packages-dev": [], diff --git a/info.xml b/info.xml index d4f6e4a..4db7359 100644 --- a/info.xml +++ b/info.xml @@ -114,7 +114,7 @@ - mollie Bitcoin + mollie Apple Pay 3 0 @@ -124,13 +124,13 @@ 0 1 0 - JTLMollieBitcoin.php - JTLMollieBitcoin + JTLMollieApplePay.php + JTLMollieApplePay tpl/bestellabschluss.tpl - Bitcoin + mollie - Bezahlen Sie bequem mit Bitcoins. + diff --git a/version/103/paymentmethod/JTLMollieApplePay.php b/version/103/paymentmethod/JTLMollieApplePay.php new file mode 100644 index 0000000..ecf20a8 --- /dev/null +++ b/version/103/paymentmethod/JTLMollieApplePay.php @@ -0,0 +1,8 @@ + Date: Fri, 10 May 2019 11:33:15 +0200 Subject: [PATCH 062/280] prepare #29 --- version/103/class/Mollie.php | 12 +++++++++++- version/103/paymentmethod/JTLMollie.php | 4 ++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/version/103/class/Mollie.php b/version/103/class/Mollie.php index 48c865f..3597f0c 100644 --- a/version/103/class/Mollie.php +++ b/version/103/class/Mollie.php @@ -15,6 +15,7 @@ use Lieferscheinpos; use Mollie\Api\Resources\Order; use Mollie\Api\Types\OrderStatus; +use Mollie\Api\Types\PaymentStatus; use Shop; use Shopsetting; use stdClass; @@ -166,9 +167,18 @@ public static function handleOrder(Order $order, $kBestellung) case OrderStatus::STATUS_PAID: case OrderStatus::STATUS_COMPLETED: case OrderStatus::STATUS_AUTHORIZED: + $cHinweis = $order->id; + 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])) { + $cHinweis .= ' / ' . $payment->status; + } + } + } $oIncomingPayment->fBetrag = $order->amount->value; $oIncomingPayment->cISO = $order->amount->currency; - $oIncomingPayment->cHinweis = $order->id; + $oIncomingPayment->cHinweis = $cHinweis; Mollie::JTLMollie()->addIncomingPayment($oBestellung, $oIncomingPayment); Mollie::JTLMollie()->setOrderStatusToPaid($oBestellung); Mollie::JTLMollie()->doLog('PaymentStatus: ' . $order->status . ' => Zahlungseingang (' . $order->amount->value . ')', $logData, LOGLEVEL_DEBUG); diff --git a/version/103/paymentmethod/JTLMollie.php b/version/103/paymentmethod/JTLMollie.php index f52dbda..ba2555e 100644 --- a/version/103/paymentmethod/JTLMollie.php +++ b/version/103/paymentmethod/JTLMollie.php @@ -113,7 +113,7 @@ public function preparePaymentProcess($order) $logData = '#' . $order->kBestellung . "" . $order->cBestellNr; try { $payment = Payment::getPayment($order->kBestellung); - $oMolliePayment = self::API()->orders->get($payment->kID); + $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; @@ -394,7 +394,7 @@ public function handleNotification($order, $hash, $args) $this->doLog('Received Notification
' . print_r([$hash, $args], 1) . '
', $logData, LOGLEVEL_NOTICE); try { - $oMolliePayment = self::API()->orders->get($args['id']); + $oMolliePayment = self::API()->orders->get($args['id'], ['embed' => 'payments']); Mollie::handleOrder($oMolliePayment, $order->kBestellung); } catch (Exception $e) { $this->doLog('handleNotification: ' . $e->getMessage(), $logData); From c6386b5b0db1f5e77df5256ffed2de5a0e1881f1 Mon Sep 17 00:00:00 2001 From: "C. Proske" Date: Tue, 21 May 2019 13:28:30 +0200 Subject: [PATCH 063/280] fix klarna organizationName --- version/102/paymentmethod/JTLMollie.php | 8 ++++++-- version/103/paymentmethod/JTLMollie.php | 8 ++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/version/102/paymentmethod/JTLMollie.php b/version/102/paymentmethod/JTLMollie.php index f52dbda..372452c 100644 --- a/version/102/paymentmethod/JTLMollie.php +++ b/version/102/paymentmethod/JTLMollie.php @@ -200,7 +200,9 @@ protected function getOrderData(Bestellung $order, $hash) if (static::MOLLIE_METHOD !== '') { $data['method'] = static::MOLLIE_METHOD; } - $data['billingAddress']->organizationName = utf8_encode($order->oRechnungsadresse->cFirma); + 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); @@ -212,7 +214,9 @@ protected function getOrderData(Bestellung $order, $hash) if ($order->Lieferadresse != null) { $data['shippingAddress'] = new stdClass(); - $data['shippingAddress']->organizationName = utf8_encode($order->Lieferadresse->cFirma); + 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); diff --git a/version/103/paymentmethod/JTLMollie.php b/version/103/paymentmethod/JTLMollie.php index ba2555e..7e73d54 100644 --- a/version/103/paymentmethod/JTLMollie.php +++ b/version/103/paymentmethod/JTLMollie.php @@ -200,7 +200,9 @@ protected function getOrderData(Bestellung $order, $hash) if (static::MOLLIE_METHOD !== '') { $data['method'] = static::MOLLIE_METHOD; } - $data['billingAddress']->organizationName = utf8_encode($order->oRechnungsadresse->cFirma); + 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); @@ -212,7 +214,9 @@ protected function getOrderData(Bestellung $order, $hash) if ($order->Lieferadresse != null) { $data['shippingAddress'] = new stdClass(); - $data['shippingAddress']->organizationName = utf8_encode($order->Lieferadresse->cFirma); + 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); From 530a54d42789fcbaa66371dd5af218db9d10b2ea Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Tue, 21 May 2019 14:43:16 +0200 Subject: [PATCH 064/280] #31 --- composer.json | 5 +++- composer.lock | 35 ++++++++---------------- version/103/adminmenu/paymentmethods.php | 1 + version/103/paymentmethod/JTLMollie.php | 3 +- 4 files changed, 19 insertions(+), 25 deletions(-) diff --git a/composer.json b/composer.json index 9019abc..0a3bf11 100644 --- a/composer.json +++ b/composer.json @@ -12,5 +12,8 @@ "name": "C. Proske", "email": "proske@webstollen.de" } - ] + ], + "config": { + "optimize-autoloader": true + } } diff --git a/composer.lock b/composer.lock index ca854bf..5ac3d88 100644 --- a/composer.lock +++ b/composer.lock @@ -247,16 +247,16 @@ }, { "name": "mollie/mollie-api-php", - "version": "v2.9.2", + "version": "v2.10.0", "source": { "type": "git", "url": "https://github.com/mollie/mollie-api-php.git", - "reference": "f108c626e3965a3cf9cce7ccad3044224f8ff2c8" + "reference": "151bdb85c325f6768452a3d8461930589be85729" }, "dist": { "type": "zip", - "url": "https://github.com/gitapi/repos/mollie/mollie-api-php/zipball/f108c626e3965a3cf9cce7ccad3044224f8ff2c8", - "reference": "f108c626e3965a3cf9cce7ccad3044224f8ff2c8", + "url": "https://github.com/gitapi/repos/mollie/mollie-api-php/zipball/151bdb85c325f6768452a3d8461930589be85729", + "reference": "151bdb85c325f6768452a3d8461930589be85729", "shasum": "" }, "require": { @@ -328,7 +328,7 @@ "sofortbanking", "subscriptions" ], - "time": "2019-05-08T12:22:30+00:00" + "time": "2019-05-20T09:07:29+00:00" }, { "name": "psr/http-message", @@ -423,17 +423,6 @@ { "name": "roave/security-advisories", "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/Roave/SecurityAdvisories.git", - "reference": "2149b00d8c04ccbc71f38a261d0129d5b032b5df" - }, - "dist": { - "type": "zip", - "url": "https://github.com/gitapi/repos/Roave/SecurityAdvisories/zipball/2149b00d8c04ccbc71f38a261d0129d5b032b5df", - "reference": "2149b00d8c04ccbc71f38a261d0129d5b032b5df", - "shasum": "" - }, "conflict": { "3f/pygmentize": "<1.2", "adodb/adodb-php": "<5.20.12", @@ -449,7 +438,7 @@ "cart2quote/module-quotation": ">=4.1.6,<=4.4.5|>=5,<5.4.4", "cartalyst/sentry": "<=2.1.6", "codeigniter/framework": "<=3.0.6", - "composer/composer": "<=1.0.0-alpha11", + "composer/composer": "<=1-alpha.11", "contao-components/mediaelement": ">=2.14.2,<2.21.1", "contao/core": ">=2,<3.5.39", "contao/core-bundle": ">=4,<4.4.39|>=4.5,<4.7.5", @@ -466,8 +455,8 @@ "doctrine/mongodb-odm-bundle": ">=2,<3.0.1", "doctrine/orm": ">=2,<2.4.8|>=2.5,<2.5.1", "dompdf/dompdf": ">=0.6,<0.6.2", - "drupal/core": ">=7,<7.65|>=8,<8.5.14|>=8.6,<8.6.14", - "drupal/drupal": ">=7,<7.65|>=8,<8.5.14|>=8.6,<8.6.14", + "drupal/core": ">=7,<7.67|>=8,<8.6.16|>=8.7,<8.7.1", + "drupal/drupal": ">=7,<7.67|>=8,<8.6.16|>=8.7,<8.7.1", "erusev/parsedown": "<1.7.2", "ezsystems/ezpublish-kernel": ">=5.3,<5.3.12.1|>=5.4,<5.4.13.1|>=6,<6.7.9.1|>=6.8,<6.13.5.1|>=7,<7.2.4.1|>=7.3,<7.3.2.1", "ezsystems/ezpublish-legacy": ">=5.3,<5.3.12.6|>=5.4,<5.4.12.3|>=2011,<2017.12.4.3|>=2018.6,<2018.6.1.4|>=2018.9,<2018.9.1.3", @@ -481,7 +470,7 @@ "fuel/core": "<1.8.1", "gree/jose": "<=2.2", "gregwar/rst": "<1.0.3", - "guzzlehttp/guzzle": ">=6,<6.2.1|>=4.0.0-rc2,<4.2.4|>=5,<5.3.1", + "guzzlehttp/guzzle": ">=4-rc.2,<4.2.4|>=5,<5.3.1|>=6,<6.2.1", "illuminate/auth": ">=4,<4.0.99|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.10", "illuminate/cookie": ">=4,<=4.0.11|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.42|>=5.6,<5.6.30", "illuminate/database": ">=4,<4.0.99|>=4.1,<4.1.29", @@ -516,7 +505,7 @@ "phpunit/phpunit": ">=4.8.19,<4.8.28|>=5.0.10,<5.6.3", "phpwhois/phpwhois": "<=4.2.5", "phpxmlrpc/extras": "<0.6.1", - "propel/propel": ">=2.0.0-alpha1,<=2.0.0-alpha7", + "propel/propel": ">=2-alpha.1,<=2-alpha.7", "propel/propel1": ">=1,<=1.7.1", "pusher/pusher-php-server": "<2.2.1", "robrichards/xmlseclibs": ">=1,<3.0.2", @@ -567,7 +556,7 @@ "symfony/yaml": ">=2,<2.0.22|>=2.1,<2.1.7", "tecnickcom/tcpdf": "<6.2.22", "thelia/backoffice-default-template": ">=2.1,<2.1.2", - "thelia/thelia": ">=2.1,<2.1.2|>=2.1.0-beta1,<2.1.3", + "thelia/thelia": ">=2.1-beta.1,<2.1.3", "theonedemon/phpwhois": "<=4.2.5", "titon/framework": ">=0,<9.9.99", "truckersmp/phpwhois": "<=4.3.1", @@ -627,7 +616,7 @@ } ], "description": "Prevents installation of composer packages with known security vulnerabilities: no API, simply require it", - "time": "2019-05-08T13:51:25+00:00" + "time": "2019-05-17T16:29:20+00:00" } ], "packages-dev": [], diff --git a/version/103/adminmenu/paymentmethods.php b/version/103/adminmenu/paymentmethods.php index b31532b..a40dc23 100644 --- a/version/103/adminmenu/paymentmethods.php +++ b/version/103/adminmenu/paymentmethods.php @@ -37,6 +37,7 @@ if ($amount && $currency && $locale) { $params['amount'] = ['value' => number_format($amount, 2, '.', ''), 'currency' => $currency]; $params['locale'] = $locale; + $params['includeWallets'] = 'applepay'; } if ($active) { diff --git a/version/103/paymentmethod/JTLMollie.php b/version/103/paymentmethod/JTLMollie.php index 7e73d54..4128752 100644 --- a/version/103/paymentmethod/JTLMollie.php +++ b/version/103/paymentmethod/JTLMollie.php @@ -483,8 +483,9 @@ protected static function PossiblePaymentMethods($method, $locale, $billingCount { $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, 'include' => 'pricing,issuers', 'resource' => 'orders']); + 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) { From 8a0260a93f03a55e3790bc20fc9432b46746100c Mon Sep 17 00:00:00 2001 From: "C. Proske" Date: Wed, 22 May 2019 08:47:32 +0200 Subject: [PATCH 065/280] fix #29 --- version/103/class/Mollie.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/version/103/class/Mollie.php b/version/103/class/Mollie.php index 3597f0c..67cff57 100644 --- a/version/103/class/Mollie.php +++ b/version/103/class/Mollie.php @@ -157,7 +157,7 @@ public static function handleOrder(Order $order, $kBestellung) $order->orderNumber = $oBestellung->cBestellNr; Payment::updateFromPayment($order, $kBestellung); - $oIncomingPayment = Shop::DB()->executeQueryPrepared("SELECT * FROM tzahlungseingang WHERE cHinweis = :cHinweis AND kBestellung = :kBestellung", [':cHinweis' => $order->id, ':kBestellung' => $oBestellung->kBestellung], 1); + $oIncomingPayment = Shop::DB()->executeQueryPrepared("SELECT * FROM tzahlungseingang WHERE cHinweis LIKE :cHinweis AND kBestellung = :kBestellung", [':cHinweis' => '%' . $order->id . '%', ':kBestellung' => $oBestellung->kBestellung], 1); if (!$oIncomingPayment) { $oIncomingPayment = new stdClass(); } @@ -171,8 +171,8 @@ public static function handleOrder(Order $order, $kBestellung) 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])) { - $cHinweis .= ' / ' . $payment->status; + if (in_array($payment->status, [PaymentStatus::STATUS_AUTHORIZED, PaymentStatus::STATUS_PAID])) { + $cHinweis .= ' / ' . $payment->id; } } } From 8f613b3f04e77bb52d9d23924cc08164cade03e0 Mon Sep 17 00:00:00 2001 From: "C. Proske" Date: Wed, 22 May 2019 09:49:18 +0200 Subject: [PATCH 066/280] fix #34 --- version/103/class/Mollie.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/version/103/class/Mollie.php b/version/103/class/Mollie.php index 67cff57..b10899b 100644 --- a/version/103/class/Mollie.php +++ b/version/103/class/Mollie.php @@ -154,6 +154,17 @@ public static function handleOrder(Order $order, $kBestellung) $oBestellung = new Bestellung($kBestellung); if ($oBestellung->kBestellung) { + + 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('handleOrder: ' . $e->getMessage(), $logData); + } + + $order->orderNumber = $oBestellung->cBestellNr; Payment::updateFromPayment($order, $kBestellung); From 4730f55ec64ba108389c1cae5923c9574f2ca1b4 Mon Sep 17 00:00:00 2001 From: "C. Proske" Date: Wed, 22 May 2019 10:14:49 +0200 Subject: [PATCH 067/280] fix #32 --- version/103/adminmenu/orders.php | 2 +- version/103/adminmenu/tpl/order.tpl | 50 ++++++++++++++++++++++++++++- 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/version/103/adminmenu/orders.php b/version/103/adminmenu/orders.php index 891f42a..99603ed 100644 --- a/version/103/adminmenu/orders.php +++ b/version/103/adminmenu/orders.php @@ -104,7 +104,7 @@ break; } - $order = JTLMollie::API()->orders->get($_REQUEST['id']); + $order = JTLMollie::API()->orders->get($_REQUEST['id'], ['embed' => 'payments,refunds']); $payment = Payment::getPaymentMollie($_REQUEST['id']); if ($payment) { $oBestellung = new Bestellung($payment->kBestellung, false); diff --git a/version/103/adminmenu/tpl/order.tpl b/version/103/adminmenu/tpl/order.tpl index 49b4517..f165a56 100644 --- a/version/103/adminmenu/tpl/order.tpl +++ b/version/103/adminmenu/tpl/order.tpl @@ -26,7 +26,7 @@
{/if} - +
@@ -53,7 +53,55 @@ + + + + + + + +
Mollie ID: {$payment->kID}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

+ + + + + + + + + + + + + + {foreach from=$order->payments() item=payment} + + + + + + + + + + + {/foreach} +
IDStatusMethodeAmountSettlementRefundedRemainingDetails
{$payment->id}{$payment->status}{$payment->method}{$payment->amount->value} {$payment->amount->currency}{$payment->settlementAmount->value} {$payment->settlementAmount->currency}{$payment->amountRefunded->value} {$payment->amountRefunded->currency}{$payment->amountRemaining->value} {$payment->amountRemaining->currency} +
    + {foreach from=$payment->details item=value key=key} +
  • {$key}: {$value}
  • + {/foreach} +
+
+{/if} +

Positionen:

From 1452ee1da48a9c2c060f0df5736539e9622df7a4 Mon Sep 17 00:00:00 2001 From: "C. Proske" Date: Wed, 22 May 2019 10:18:19 +0200 Subject: [PATCH 068/280] print payment link on checkout, if error/output occours --- version/103/paymentmethod/JTLMollie.php | 38 ++++++++++++++++--------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/version/103/paymentmethod/JTLMollie.php b/version/103/paymentmethod/JTLMollie.php index 4128752..fcb7198 100644 --- a/version/103/paymentmethod/JTLMollie.php +++ b/version/103/paymentmethod/JTLMollie.php @@ -112,25 +112,33 @@ public function preparePaymentProcess($order) { $logData = '#' . $order->kBestellung . "" . $order->cBestellNr; try { - $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(); + if ($order->kBestellung) { + $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(); } - header('Location: ' . $payment->cCheckoutURL); - exit(); } } catch (Exception $e) { $this->doLog("Get Payment Error: " . $e->getMessage() . ". Create new ORDER...", $logData); } try { - $hash = $this->generateHash($order); - $oMolliePayment = self::API()->orders->create($this->getOrderData($order, $hash)); - $_SESSION['oMolliePayment'] = $oMolliePayment; + if (!array_key_exists('oMolliePayment', $_SESSION) || !($_SESSION['oMolliePayment'] instanceof \Mollie\Api\Resources\Order)) { + $hash = $this->generateHash($order); + $orderData = $this->getOrderData($order, $hash); + $oMolliePayment = self::API()->orders->create($orderData); + $_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($hash)); @@ -139,6 +147,8 @@ public function preparePaymentProcess($order) Session::getInstance()->cleanUp(); } header('Location: ' . $oMolliePayment->getCheckoutUrl()); + unset($_SESSION['oMolliePayment']); + echo "redirect to payment ..."; exit(); } catch (ApiException $e) { Shop::Smarty()->assign('oMollieException', $e); @@ -483,9 +493,9 @@ protected static function PossiblePaymentMethods($method, $locale, $billingCount { $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']); + 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) { From b4c89af2d11ac87931f17afef5ea74fbe1903547 Mon Sep 17 00:00:00 2001 From: "dash.bar" Date: Wed, 22 May 2019 10:46:32 +0200 Subject: [PATCH 069/280] update base files --- version/103/adminmenu/info.php | 3 ++- version/103/adminmenu/tpl/info.tpl | 2 +- version/103/class/Helper.php | 6 ++++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/version/103/adminmenu/info.php b/version/103/adminmenu/info.php index 975d723..4a3f09a 100644 --- a/version/103/adminmenu/info.php +++ b/version/103/adminmenu/info.php @@ -41,6 +41,7 @@ if ((int)\ws_mollie\Helper::oPlugin()->nVersion < (int)$latestRelease->version) { Shop::Smarty()->assign('update', $latestRelease); } + } catch (\Exception $e) { } @@ -48,4 +49,4 @@ } catch (Exception $e) { echo "
Fehler: {$e->getMessage()}
"; \ws_mollie\Helper::logExc($e); -} +} \ No newline at end of file diff --git a/version/103/adminmenu/tpl/info.tpl b/version/103/adminmenu/tpl/info.tpl index 6995522..da2a55a 100644 --- a/version/103/adminmenu/tpl/info.tpl +++ b/version/103/adminmenu/tpl/info.tpl @@ -75,7 +75,7 @@
diff --git a/version/103/class/Helper.php b/version/103/class/Helper.php index 69b0e2e..7035a09 100644 --- a/version/103/class/Helper.php +++ b/version/103/class/Helper.php @@ -60,7 +60,8 @@ public static function autoload() */ public static function selfupdate() { - if (function_exists('opcache_reset')) { + + if(function_exists('opcache_reset')){ opcache_reset(); } @@ -207,7 +208,7 @@ public static function oPlugin($force = false) { if ($force === true) { self::$oPlugin = new \Plugin(self::oPlugin(false)->kPlugin, true); - } elseif (null === self::$oPlugin) { + } else if (null === self::$oPlugin) { self::$oPlugin = \Plugin::getPluginById(__NAMESPACE__); } return self::$oPlugin; @@ -286,6 +287,7 @@ public static function getAdminmenu($name) } return $kPluginAdminMenu; } + } } From 430d4b25f645ba83cf441db634b05e0631b8daac Mon Sep 17 00:00:00 2001 From: "dash.bar" Date: Wed, 22 May 2019 10:54:18 +0200 Subject: [PATCH 070/280] prepare finalize --- info.xml | 871 ++++++++++++++++----------------- version/103/adminmenu/info.php | 3 +- version/103/class/Helper.php | 6 +- version/103/class/Mollie.php | 1 - 4 files changed, 437 insertions(+), 444 deletions(-) diff --git a/info.xml b/info.xml index 4db7359..760380f 100644 --- a/info.xml +++ b/info.xml @@ -1,438 +1,435 @@ - - - mollie - Zahlungsartplugin für mollie.com - WebStollen - http://www.webstollen.de/ - 102 - ws_mollie - 405 - - - 100.sql - 2019-02-11 - - - 2019-02-26 - - - 2019-04-23 - - - 2019-04-23 - - - 131_globalinclude.php - 144_notify.php - 181_sync.php - 140_smarty.php - - - - Bestellungen - orders.php - - - Zahlungsarten - paymentmethods.php - - - Info - info.php - - - Einstellungen - - API Key: - Füge hier deinen mollie API Key ein - api_key - - - Zahlungsart Daten syncronisiernen - Lädt Name / Bild für die jeweilige Sprache automatisch von mollie, und speichert diese - in der Datenbank - - paymentmethod_sync - - - - - - - - - Checkout Styles laden - Lädt Stylesheets für das Evo Template, um den Checkout zu verschönern. - load_styles - - - - - - - - - - - mollie - - 1 - 0 - mollie.com - OTHER - 0 - 0 - 1 - 0 - JTLMollie.php - JTLMollie - tpl/bestellabschluss.tpl - - mollie - mollie - Bezahlen Sie bequem mit verschiedenen Zahlungsmethoden. - - - - mollie Kreditkarte - - 2 - 0 - mollie.com - CREDIT_CARD - 1 - 0 - 1 - 0 - JTLMollieCreditCard.php - JTLMollieCreditCard - tpl/bestellabschluss.tpl - - Kreditkarte - mollie - Bezahlen Sie bequem mit Kreditkarte. - - - - mollie Apple Pay - - 3 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMollieApplePay.php - JTLMollieApplePay - tpl/bestellabschluss.tpl - - - mollie - - - - - mollie Bancontact - - 4 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMollieBancontact.php - JTLMollieBancontact - tpl/bestellabschluss.tpl - - Bancontact - mollie - Bezahlen Sie bequem mit Bancontact. - - - - mollie Banktransfer - - 5 - 0 - mollie.com - OTHER - 0 - 0 - 1 - 0 - JTLMollieBanktransfer.php - JTLMollieBanktransfer - tpl/bestellabschluss.tpl - - SEPA Überweisung - mollie - Bezahlen Sie bequem mit SEPA Überweisung. - - - - mollie Belfius - - 6 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMollieBelfius.php - JTLMollieBelfius - tpl/bestellabschluss.tpl - - Belfius - mollie - Bezahlen Sie bequem mit Belfius. - - - - mollie DirectDebit - - 7 - 0 - mollie.com - DIRECT_DEBIT - 1 - 0 - 1 - 0 - JTLMollieDirectDebit.php - JTLMollieDirectDebit - tpl/bestellabschluss.tpl - - SEPA Lastschrift - mollie - Bezahlen Sie bequem mit SEPA Lastschrift. - - - - mollie EPS - - 2 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMollieEPS.php - JTLMollieEPS - tpl/bestellabschluss.tpl - - EPS - mollie - Bezahlen Sie bequem mit EPS. - - - - mollie Giftcard - - 8 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMollieGiftcard.php - JTLMollieGiftcard - tpl/bestellabschluss.tpl - - Gift cards - mollie - Bezahlen Sie bequem mit Gift cards. - - - - mollie Giropay - - 9 - 0 - mollie.com - GIROPAY - 1 - 0 - 1 - 0 - JTLMollieGiropay.php - JTLMollieGiropay - tpl/bestellabschluss.tpl - - Giropay - mollie - Bezahlen Sie bequem mit Giropay. - - - - mollie iDEAL - - 10 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMollieIDEAL.php - JTLMollieIDEAL - tpl/bestellabschluss.tpl - - Giropay - mollie - Bezahlen Sie bequem mit iDEAL. - - - - mollie ING HomePay - - 11 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMollieINGHomePay.php - JTLMollieINGHomePay - tpl/bestellabschluss.tpl - - ING HomePay - mollie - Bezahlen Sie bequem mit ING HomePay. - - - - mollie KBC - - 12 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMollieKBC.php - JTLMollieKBC - tpl/bestellabschluss.tpl - - KBC - mollie - Bezahlen Sie bequem mit KBC. - - - - mollie PayPal - - 13 - 0 - mollie.com - PAYPAL - 1 - 0 - 1 - 0 - JTLMolliePayPal.php - JTLMolliePayPal - tpl/bestellabschluss.tpl - - PayPal - mollie - Bezahlen Sie bequem mit PayPal. - - - - mollie paysafecard - - 14 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMolliePaysafecard.php - JTLMolliePaysafecard - tpl/bestellabschluss.tpl - - paysafecard - mollie - Bezahlen Sie bequem mit paysafecard. - - - - mollie SOFORT - - 15 - 0 - mollie.com - DIRECT_E_BANKING - 1 - 0 - 1 - 0 - JTLMollieSofort.php - JTLMollieSofort - tpl/bestellabschluss.tpl - - SOFORT - mollie - Bezahlen Sie bequem mit SOFORT. - - - - mollie Klarna Pay Later - - 16 - 0 - mollie.com - INVOICE - 1 - 0 - 1 - 0 - JTLMollieKlarnaPayLater.php - JTLMollieKlarnaPayLater - tpl/bestellabschluss.tpl - - Klarna Pay Later - mollie - Bezahlen Sie bequem mit Klarna Pay Later. - - - - mollie Klarna Slice It - - 17 - 0 - mollie.com - FINANCING - 1 - 0 - 1 - 0 - JTLMollieKlarnaSliceIt.php - JTLMollieKlarnaSliceIt - tpl/bestellabschluss.tpl - - Klarna Slice It - mollie - Bezahlen Sie bequem mit Klarna Slice It. - - - - + + mollie + Zahlungsartplugin für mollie.com + WebStollen + http://www.webstollen.de/ + 102 + ws_mollie + 405 + + + 100.sql + 2019-02-11 + + + 2019-02-26 + + + 2019-04-23 + + + 2019-05-22 + + + 131_globalinclude.php + 144_notify.php + 181_sync.php + 140_smarty.php + + + + Bestellungen + orders.php + + + Zahlungsarten + paymentmethods.php + + + Info + info.php + + + Einstellungen + + API Key: + Füge hier deinen mollie API Key ein + api_key + + + Zahlungsart Daten syncronisiernen + Lädt Name / Bild für die jeweilige Sprache automatisch von mollie, und speichert diese in der Datenbank + paymentmethod_sync + + + + + + + + + Checkout Styles laden + Lädt Stylesheets für das Evo Template, um den Checkout zu verschönern. + load_styles + + + + + + + + + + + mollie + + 1 + 0 + mollie.com + OTHER + 0 + 0 + 1 + 0 + JTLMollie.php + JTLMollie + tpl/bestellabschluss.tpl + + mollie + mollie + Bezahlen Sie bequem mit verschiedenen Zahlungsmethoden. + + + + mollie Kreditkarte + + 2 + 0 + mollie.com + CREDIT_CARD + 1 + 0 + 1 + 0 + JTLMollieCreditCard.php + JTLMollieCreditCard + tpl/bestellabschluss.tpl + + Kreditkarte + mollie + Bezahlen Sie bequem mit Kreditkarte. + + + + mollie Apple Pay + + 3 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMollieApplePay.php + JTLMollieApplePay + tpl/bestellabschluss.tpl + + Apple Pay + mollie + Bezahlen Sie bequem mit Apple Pay. + + + + mollie Bancontact + + 4 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMollieBancontact.php + JTLMollieBancontact + tpl/bestellabschluss.tpl + + Bancontact + mollie + Bezahlen Sie bequem mit Bancontact. + + + + mollie Banktransfer + + 5 + 0 + mollie.com + OTHER + 0 + 0 + 1 + 0 + JTLMollieBanktransfer.php + JTLMollieBanktransfer + tpl/bestellabschluss.tpl + + SEPA Überweisung + mollie + Bezahlen Sie bequem mit SEPA Überweisung. + + + + mollie Belfius + + 6 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMollieBelfius.php + JTLMollieBelfius + tpl/bestellabschluss.tpl + + Belfius + mollie + Bezahlen Sie bequem mit Belfius. + + + + mollie DirectDebit + + 7 + 0 + mollie.com + DIRECT_DEBIT + 1 + 0 + 1 + 0 + JTLMollieDirectDebit.php + JTLMollieDirectDebit + tpl/bestellabschluss.tpl + + SEPA Lastschrift + mollie + Bezahlen Sie bequem mit SEPA Lastschrift. + + + + mollie EPS + + 2 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMollieEPS.php + JTLMollieEPS + tpl/bestellabschluss.tpl + + EPS + mollie + Bezahlen Sie bequem mit EPS. + + + + mollie Giftcard + + 8 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMollieGiftcard.php + JTLMollieGiftcard + tpl/bestellabschluss.tpl + + Gift cards + mollie + Bezahlen Sie bequem mit Gift cards. + + + + mollie Giropay + + 9 + 0 + mollie.com + GIROPAY + 1 + 0 + 1 + 0 + JTLMollieGiropay.php + JTLMollieGiropay + tpl/bestellabschluss.tpl + + Giropay + mollie + Bezahlen Sie bequem mit Giropay. + + + + mollie iDEAL + + 10 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMollieIDEAL.php + JTLMollieIDEAL + tpl/bestellabschluss.tpl + + Giropay + mollie + Bezahlen Sie bequem mit iDEAL. + + + + mollie ING HomePay + + 11 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMollieINGHomePay.php + JTLMollieINGHomePay + tpl/bestellabschluss.tpl + + ING HomePay + mollie + Bezahlen Sie bequem mit ING HomePay. + + + + mollie KBC + + 12 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMollieKBC.php + JTLMollieKBC + tpl/bestellabschluss.tpl + + KBC + mollie + Bezahlen Sie bequem mit KBC. + + + + mollie PayPal + + 13 + 0 + mollie.com + PAYPAL + 1 + 0 + 1 + 0 + JTLMolliePayPal.php + JTLMolliePayPal + tpl/bestellabschluss.tpl + + PayPal + mollie + Bezahlen Sie bequem mit PayPal. + + + + mollie paysafecard + + 14 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMolliePaysafecard.php + JTLMolliePaysafecard + tpl/bestellabschluss.tpl + + paysafecard + mollie + Bezahlen Sie bequem mit paysafecard. + + + + mollie SOFORT + + 15 + 0 + mollie.com + DIRECT_E_BANKING + 1 + 0 + 1 + 0 + JTLMollieSofort.php + JTLMollieSofort + tpl/bestellabschluss.tpl + + SOFORT + mollie + Bezahlen Sie bequem mit SOFORT. + + + + mollie Klarna Pay Later + + 16 + 0 + mollie.com + INVOICE + 1 + 0 + 1 + 0 + JTLMollieKlarnaPayLater.php + JTLMollieKlarnaPayLater + tpl/bestellabschluss.tpl + + Klarna Pay Later + mollie + Bezahlen Sie bequem mit Klarna Pay Later. + + + + mollie Klarna Slice It + + 17 + 0 + mollie.com + FINANCING + 1 + 0 + 1 + 0 + JTLMollieKlarnaSliceIt.php + JTLMollieKlarnaSliceIt + tpl/bestellabschluss.tpl + + Klarna Slice It + mollie + Bezahlen Sie bequem mit Klarna Slice It. + + + + \ No newline at end of file diff --git a/version/103/adminmenu/info.php b/version/103/adminmenu/info.php index 4a3f09a..975d723 100644 --- a/version/103/adminmenu/info.php +++ b/version/103/adminmenu/info.php @@ -41,7 +41,6 @@ if ((int)\ws_mollie\Helper::oPlugin()->nVersion < (int)$latestRelease->version) { Shop::Smarty()->assign('update', $latestRelease); } - } catch (\Exception $e) { } @@ -49,4 +48,4 @@ } catch (Exception $e) { echo "
Fehler: {$e->getMessage()}
"; \ws_mollie\Helper::logExc($e); -} \ No newline at end of file +} diff --git a/version/103/class/Helper.php b/version/103/class/Helper.php index 7035a09..69b0e2e 100644 --- a/version/103/class/Helper.php +++ b/version/103/class/Helper.php @@ -60,8 +60,7 @@ public static function autoload() */ public static function selfupdate() { - - if(function_exists('opcache_reset')){ + if (function_exists('opcache_reset')) { opcache_reset(); } @@ -208,7 +207,7 @@ public static function oPlugin($force = false) { if ($force === true) { self::$oPlugin = new \Plugin(self::oPlugin(false)->kPlugin, true); - } else if (null === self::$oPlugin) { + } elseif (null === self::$oPlugin) { self::$oPlugin = \Plugin::getPluginById(__NAMESPACE__); } return self::$oPlugin; @@ -287,7 +286,6 @@ public static function getAdminmenu($name) } return $kPluginAdminMenu; } - } } diff --git a/version/103/class/Mollie.php b/version/103/class/Mollie.php index b10899b..a1fab4c 100644 --- a/version/103/class/Mollie.php +++ b/version/103/class/Mollie.php @@ -154,7 +154,6 @@ public static function handleOrder(Order $order, $kBestellung) $oBestellung = new Bestellung($kBestellung); if ($oBestellung->kBestellung) { - try { // Try to change the orderNumber if ($order->orderNumber !== $oBestellung->cBestellNr) { From 46b15793a1e767b1b8d4579013aef00f41d5305f Mon Sep 17 00:00:00 2001 From: "dash.bar" Date: Wed, 22 May 2019 10:54:19 +0200 Subject: [PATCH 071/280] init version 104 --- info.xml | 3 + version/104/adminmenu/info.php | 51 ++ version/104/adminmenu/orders.php | 154 +++++ version/104/adminmenu/paymentmethods.php | 57 ++ version/104/adminmenu/tpl/info.tpl | 93 +++ .../tpl/mollie-account-erstellen.png | Bin 0 -> 38998 bytes version/104/adminmenu/tpl/order.tpl | 265 +++++++++ version/104/adminmenu/tpl/orders.tpl | 107 ++++ version/104/adminmenu/tpl/paymentmethods.tpl | 92 +++ version/104/class/Helper.php | 292 +++++++++ version/104/class/Model/AbstractModel.php | 7 + version/104/class/Model/Payment.php | 77 +++ version/104/class/Mollie.php | 441 ++++++++++++++ version/104/frontend/131_globalinclude.php | 72 +++ version/104/frontend/140_smarty.php | 52 ++ version/104/frontend/144_notify.php | 31 + version/104/frontend/181_sync.php | 38 ++ version/104/paymentmethod/JTLMollie.php | 563 ++++++++++++++++++ .../104/paymentmethod/JTLMollieApplePay.php | 8 + .../104/paymentmethod/JTLMollieBancontact.php | 8 + .../paymentmethod/JTLMollieBanktransfer.php | 8 + .../104/paymentmethod/JTLMollieBelfius.php | 8 + .../104/paymentmethod/JTLMollieCreditCard.php | 8 + .../paymentmethod/JTLMollieDirectDebit.php | 8 + version/104/paymentmethod/JTLMollieEPS.php | 8 + .../104/paymentmethod/JTLMollieGiftcard.php | 8 + .../104/paymentmethod/JTLMollieGiropay.php | 8 + version/104/paymentmethod/JTLMollieIDEAL.php | 8 + .../104/paymentmethod/JTLMollieINGHomePay.php | 8 + version/104/paymentmethod/JTLMollieKBC.php | 8 + .../paymentmethod/JTLMollieKlarnaPayLater.php | 8 + .../paymentmethod/JTLMollieKlarnaSliceIt.php | 8 + version/104/paymentmethod/JTLMolliePayPal.php | 8 + .../paymentmethod/JTLMolliePaysafecard.php | 8 + version/104/paymentmethod/JTLMollieSofort.php | 8 + .../paymentmethod/tpl/bestellabschluss.tpl | 5 + 36 files changed, 2536 insertions(+) create mode 100644 version/104/adminmenu/info.php create mode 100644 version/104/adminmenu/orders.php create mode 100644 version/104/adminmenu/paymentmethods.php create mode 100644 version/104/adminmenu/tpl/info.tpl create mode 100644 version/104/adminmenu/tpl/mollie-account-erstellen.png create mode 100644 version/104/adminmenu/tpl/order.tpl create mode 100644 version/104/adminmenu/tpl/orders.tpl create mode 100644 version/104/adminmenu/tpl/paymentmethods.tpl create mode 100644 version/104/class/Helper.php create mode 100644 version/104/class/Model/AbstractModel.php create mode 100644 version/104/class/Model/Payment.php create mode 100644 version/104/class/Mollie.php create mode 100644 version/104/frontend/131_globalinclude.php create mode 100644 version/104/frontend/140_smarty.php create mode 100644 version/104/frontend/144_notify.php create mode 100644 version/104/frontend/181_sync.php create mode 100644 version/104/paymentmethod/JTLMollie.php create mode 100644 version/104/paymentmethod/JTLMollieApplePay.php create mode 100644 version/104/paymentmethod/JTLMollieBancontact.php create mode 100644 version/104/paymentmethod/JTLMollieBanktransfer.php create mode 100644 version/104/paymentmethod/JTLMollieBelfius.php create mode 100644 version/104/paymentmethod/JTLMollieCreditCard.php create mode 100644 version/104/paymentmethod/JTLMollieDirectDebit.php create mode 100644 version/104/paymentmethod/JTLMollieEPS.php create mode 100644 version/104/paymentmethod/JTLMollieGiftcard.php create mode 100644 version/104/paymentmethod/JTLMollieGiropay.php create mode 100644 version/104/paymentmethod/JTLMollieIDEAL.php create mode 100644 version/104/paymentmethod/JTLMollieINGHomePay.php create mode 100644 version/104/paymentmethod/JTLMollieKBC.php create mode 100644 version/104/paymentmethod/JTLMollieKlarnaPayLater.php create mode 100644 version/104/paymentmethod/JTLMollieKlarnaSliceIt.php create mode 100644 version/104/paymentmethod/JTLMolliePayPal.php create mode 100644 version/104/paymentmethod/JTLMolliePaysafecard.php create mode 100644 version/104/paymentmethod/JTLMollieSofort.php create mode 100644 version/104/paymentmethod/tpl/bestellabschluss.tpl diff --git a/info.xml b/info.xml index 760380f..2efa2f9 100644 --- a/info.xml +++ b/info.xml @@ -20,6 +20,9 @@ 2019-05-22 + + 2019-05-22 + 131_globalinclude.php 144_notify.php diff --git a/version/104/adminmenu/info.php b/version/104/adminmenu/info.php new file mode 100644 index 0000000..975d723 --- /dev/null +++ b/version/104/adminmenu/info.php @@ -0,0 +1,51 @@ +assign('defaultTabbertab', \ws_mollie\Helper::getAdminmenu('Info')); + \ws_mollie\Helper::selfupdate(); + } + + $svgQuery = http_build_query([ + 'p' => \ws_mollie\Helper::oPlugin()->cPluginID, + 'v' => \ws_mollie\Helper::oPlugin()->nVersion, + 's' => defined('APPLICATION_VERSION') ? APPLICATION_VERSION : JTL_VERSION, + 'd' => \ws_mollie\Helper::getDomain(), + 'php' => PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION . '.' . PHP_RELEASE_VERSION, + ]); + + echo ""; + echo "
" . + "
" . + " " . + " Lizenz Informationen" . + ' ' . + '
' . + "
" . + " " . + " Update Informationen" . + ' ' . + '
' . + "
" . + " " . + " Plugin informationen" . + ' ' . + '
' . + '
'; + + try { + $latestRelease = \ws_mollie\Helper::getLatestRelease(array_key_exists('update', $_REQUEST)); + if ((int)\ws_mollie\Helper::oPlugin()->nVersion < (int)$latestRelease->version) { + Shop::Smarty()->assign('update', $latestRelease); + } + } catch (\Exception $e) { + } + + Shop::Smarty()->display(\ws_mollie\Helper::oPlugin()->cAdminmenuPfad . '/tpl/info.tpl'); +} catch (Exception $e) { + echo "
Fehler: {$e->getMessage()}
"; + \ws_mollie\Helper::logExc($e); +} diff --git a/version/104/adminmenu/orders.php b/version/104/adminmenu/orders.php new file mode 100644 index 0000000..99603ed --- /dev/null +++ b/version/104/adminmenu/orders.php @@ -0,0 +1,154 @@ + 'danger', 'text' => 'Keine ID angeben!']; + break; + } + $payment = Payment::getPaymentMollie($_REQUEST['id']); + if (!$payment) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; + break; + } + + $order = JTLMollie::API()->orders->get($_REQUEST['id']); + if ($order->status == OrderStatus::STATUS_CANCELED) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung bereits storniert']; + 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; + break; + + case 'cancel': + if (!array_key_exists('id', $_REQUEST)) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; + break; + } + $payment = Payment::getPaymentMollie($_REQUEST['id']); + if (!$payment) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; + break; + } + $order = JTLMollie::API()->orders->get($_REQUEST['id']); + if ($order->status == OrderStatus::STATUS_CANCELED) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung bereits storniert']; + 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; + break; + + case 'capture': + if (!array_key_exists('id', $_REQUEST)) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; + break; + } + $payment = Payment::getPaymentMollie($_REQUEST['id']); + if (!$payment) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; + break; + } + $order = JTLMollie::API()->orders->get($_REQUEST['id']); + if ($order->status !== OrderStatus::STATUS_AUTHORIZED && $order->status !== OrderStatus::STATUS_SHIPPING) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Nur autorisierte Zahlungen können erfasst werden!']; + break; + } + + $oBestellung = new Bestellung($payment->kBestellung, true); + if (!$oBestellung->kBestellung) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung konnte nicht geladen werden!']; + break; + } + + $logData = '#' . $payment->kBestellung . '$' . $payment->kID . "§" . $oBestellung->cBestellNr; + + $options = ['lines' => []]; + if ($oBestellung->cTracking) { + $tracking = new stdClass(); + $tracking->carrier = $oBestellung->cVersandartName; + $tracking->url = $oBestellung->cTrackingURL; + $tracking->code = $oBestellung->cTracking; + $options['tracking'] = $tracking; + } + + // CAPTURE ALL + $shipment = JTLMollie::API()->shipments->createFor($order, $options); + $ordersMsgs[] = (object)['type' => 'success', 'text' => 'Zahlung wurde erfolgreich erfasst!']; + Mollie::JTLMollie()->doLog('Shipment created
' . print_r(['options' => $options, 'shipment' => $shipment], 1) . '
', $logData); + goto order; + + case 'order': + order: + if (!array_key_exists('id', $_REQUEST)) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; + 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", [ + ':kBestellung' => '%#' . ($payment->kBestellung ?: '##') . '%', + ':cBestellNr' => '%§' . ($payment->cOrderNumber ?: '§§') . '%', + ':MollieID' => '%$' . ($payment->kID ?: '$$') . '%', + ], 2); + + Shop::Smarty()->assign('payment', $payment) + ->assign('oBestellung', $oBestellung) + ->assign('order', $order) + ->assign('logs', $logs) + ->assign('ordersMsgs', $ordersMsgs); + Shop::Smarty()->display($oPlugin->cAdminmenuPfad . '/tpl/order.tpl'); + return; + } + } + + + $payments = Shop::DB()->executeQueryPrepared("SELECT * FROM xplugin_ws_mollie_payments WHERE kBestellung IS NOT NULL AND cStatus != 'created'", [], 2); + foreach ($payments as $i => $payment) { + $payments[$i]->oBestellung = new Bestellung($payment->kBestellung, false); + } + + Shop::Smarty()->assign('payments', $payments) + ->assign('ordersMsgs', $ordersMsgs) + ->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/104/adminmenu/paymentmethods.php b/version/104/adminmenu/paymentmethods.php new file mode 100644 index 0000000..a40dc23 --- /dev/null +++ b/version/104/adminmenu/paymentmethods.php @@ -0,0 +1,57 @@ +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; + $params['includeWallets'] = 'applepay'; + } + + 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/104/adminmenu/tpl/info.tpl b/version/104/adminmenu/tpl/info.tpl new file mode 100644 index 0000000..da2a55a --- /dev/null +++ b/version/104/adminmenu/tpl/info.tpl @@ -0,0 +1,93 @@ +
+
+
+ + + +
+
+ + + +
+ + {if isset($update)} +
+ +
+

Update auf Version {$update->version} verfügbar!

+
+
+
+
Version:
+
{$update->version}
+
+
+
Erschienen:
+
{$update->create_date}
+
+
+
Changelog:
+
+ +
+
+ +
+
+ +
+
+
+ {else} +
+ + + +
+ {/if} + +
+
+
+ + + +
+
+ + + +
+ +
+
+
+ + + +
+
+ + + +
+
+ + + +
+
+
diff --git a/version/104/adminmenu/tpl/mollie-account-erstellen.png b/version/104/adminmenu/tpl/mollie-account-erstellen.png new file mode 100644 index 0000000000000000000000000000000000000000..fc1819255ef725fa214cf2bf028cf3428794ecee GIT binary patch literal 38998 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 +

+ « + 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} +

+ +{if count($ordersMsgs)} + {foreach from=$ordersMsgs item=alert} +
{$alert->text}
+ {/foreach} +
+{/if} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Mollie ID:{$payment->kID}Mode:{$order->mode}Status:{$order->status}
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

+ + + + + + + + + + + + + + {foreach from=$order->payments() item=payment} + + + + + + + + + + + {/foreach} +
IDStatusMethodeAmountSettlementRefundedRemainingDetails
{$payment->id}{$payment->status}{$payment->method}{$payment->amount->value} {$payment->amount->currency}{$payment->settlementAmount->value} {$payment->settlementAmount->currency}{$payment->amountRefunded->value} {$payment->amountRefunded->currency}{$payment->amountRemaining->value} {$payment->amountRemaining->currency} +
    + {foreach from=$payment->details item=value key=key} +
  • {$key}: {$value}
  • + {/foreach} +
+
+{/if} + + +

Positionen:

+ +
+ {if ($order->status === 'authorized' || $order->status === 'shipping') && $oBestellung->cStatus|intval >= 3} + + Zahlung erfassen1 + + {/if} + {if $order->amount->value > $order->amountRefunded->value && $order->amountCaptured->value > 0} + Rckerstatten2 + + {/if} + {if $order->isCancelable} + Stornieren3 + + {/if} +
+ + + + + + + + + + + + + + + + + + {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} + + + + + + + + + + + + + {/foreach} + + + + + + + + + + +
StatusSKUNameTypAnzahlMwStSteuerNettoBrutto 
+ {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*} +
{$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} + + + + + + + {/foreach} +
+ {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}
+ + diff --git a/version/104/adminmenu/tpl/orders.tpl b/version/104/adminmenu/tpl/orders.tpl new file mode 100644 index 0000000..3956ef5 --- /dev/null +++ b/version/104/adminmenu/tpl/orders.tpl @@ -0,0 +1,107 @@ + +{if count($ordersMsgs)} + {foreach from=$ordersMsgs item=alert} +
{$alert->text}
+ {/foreach} +
+{/if} + +{if $hasAPIKey == false} + + Jetzt kostenlos Mollie Account eröffnen! + +{else} + + + + + + + + + + + + + + + + {foreach from=$payments item=payment} + + + + + + + + + + + + {/foreach} + +
BestellNr.IDMollie StatusJTL StatusBetragWährungLocaleMethodeErstellt
+ {$payment->cOrderNumber} + {if $payment->cMode == 'test'} + TEST + {/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->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)}
+ + +{/if} \ No newline at end of file diff --git a/version/104/adminmenu/tpl/paymentmethods.tpl b/version/104/adminmenu/tpl/paymentmethods.tpl new file mode 100644 index 0000000..260290f --- /dev/null +++ b/version/104/adminmenu/tpl/paymentmethods.tpl @@ -0,0 +1,92 @@ +

Account Status

+ + + + + + + + + +
Mode:{$profile->mode}Status:{$profile->status}Review:{$profile->review->status}
+ +
+ +
+
+ + +
+ + + +
+
+ + +
+
+ + +
+
+ + + reset +
+
+
+ + +{if $allMethods && $allMethods|count} + + + + + + + + + + + + {foreach from=$allMethods item=method} + + + + + + + + {/foreach} + +
BildIDNamePreiseInfos
{$method->description|utf8_decode}{$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} +
+{else} +
Es konnten keine Methoden abgerufen werden.
+{/if} \ No newline at end of file diff --git a/version/104/class/Helper.php b/version/104/class/Helper.php new file mode 100644 index 0000000..69b0e2e --- /dev/null +++ b/version/104/class/Helper.php @@ -0,0 +1,292 @@ +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); + 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(); + } + + /** + * 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); + } elseif (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); + } + + /** + * @return mixed + */ + private static function _masterMail() + { + $settings = \Shop::getSettings(array(CONF_EMAILS)); + return $settings['emails']['email_master_absender']; + } + + /** + * @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/104/class/Model/AbstractModel.php b/version/104/class/Model/AbstractModel.php new file mode 100644 index 0000000..5638700 --- /dev/null +++ b/version/104/class/Model/AbstractModel.php @@ -0,0 +1,7 @@ + $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, + ]; + 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; + } + + 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/104/class/Mollie.php b/version/104/class/Mollie.php new file mode 100644 index 0000000..a1fab4c --- /dev/null +++ b/version/104/class/Mollie.php @@ -0,0 +1,441 @@ +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) { + header('Location: ' . $url); + 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; + } + + switch ((int)$newStatus) { + case BESTELLUNG_STATUS_VERSANDT: + $options['lines'] = []; + break; + case BESTELLUNG_STATUS_TEILVERSANDT: + $lines = []; + foreach ($order->lines as $i => $line) { + if (($quantity = Mollie::getBestellPosSent($line->sku, $oBestellung)) !== false && ($quantity - $line->quantityShipped) > 0) { + $x = $quantity - $line->quantityShipped; + $lines[] = (object)[ + 'id' => $line->id, + 'quantity' => $x, + 'amount' => (object)[ + 'currency' => $line->totalAmount->currency, + 'value' => number_format($x * $line->unitPrice->value, 2), + ], + ]; + } + } + if (count($lines)) { + $options['lines'] = $lines; + } + break; + case BESTELLUNG_STATUS_STORNO: + $options = null; + break; + } + + return $options; + } + + /** + * 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; + } + + /** + * @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) { + 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('handleOrder: ' . $e->getMessage(), $logData); + } + + + $order->orderNumber = $oBestellung->cBestellNr; + Payment::updateFromPayment($order, $kBestellung); + + $oIncomingPayment = Shop::DB()->executeQueryPrepared("SELECT * FROM tzahlungseingang WHERE cHinweis LIKE :cHinweis AND kBestellung = :kBestellung", [':cHinweis' => '%' . $order->id . '%', ':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 ($payments = $order->payments()) { + /** @var \Mollie\Api\Resources\Payment $payment */ + foreach ($payments as $payment) { + if (in_array($payment->status, [PaymentStatus::STATUS_AUTHORIZED, PaymentStatus::STATUS_PAID])) { + $cHinweis .= ' / ' . $payment->id; + } + } + } + $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('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('PaymentStatus: ' . $order->status . ' => Bestellung bezahlt, KEIN Zahlungseingang', $logData, LOGLEVEL_NOTICE); + break; + case OrderStatus::STATUS_CANCELED: + case OrderStatus::STATUS_EXPIRED: + Mollie::JTLMollie()->doLog('PaymentStatus: ' . $order->status, $logData, LOGLEVEL_ERROR); + break; + } + return true; + } + return false; + } + + /** + * @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; + } + + 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/104/frontend/131_globalinclude.php b/version/104/frontend/131_globalinclude.php new file mode 100644 index 0000000..45d4c6f --- /dev/null +++ b/version/104/frontend/131_globalinclude.php @@ -0,0 +1,72 @@ +executeQueryPrepared("SELECT * FROM " . \ws_mollie\Model\Payment::TABLE . " WHERE cHash = :cHash", [':cHash' => $_REQUEST['mollie']], 1); + // Bestellung finalized, redirect to status/completion page + if ((int)$payment->kBestellung) { + $logData = '$' . $payment->kID . '#' . $payment->kBestellung . "§" . $payment->cOrderNumber; + Mollie::JTLMollie()->doLog('Bestellung finalized => redirect abschluss/status', $logData); + $order = JTLMollie::API()->orders->get($payment->kID, ['embed' => 'payments']); + Mollie::handleOrder($order, $payment->kBestellung); + Mollie::getOrderCompletedRedirect($payment->kBestellung, true); + } elseif ($payment) { // payment, but no order => finalize it + require_once __DIR__ . '/../paymentmethod/JTLMollie.php'; + $order = JTLMollie::API()->orders->get($payment->kID, ['embed' => 'payments']); + $logData = '$' . $order->id . '#' . $payment->kBestellung . "§" . $payment->cOrderNumber; + + // GET NEWEST PAYMENT: + /** @var Payment $_payment */ + $_payment = null; + if ($order->payments()) { + /** @var Payment $p */ + foreach ($order->payments() as $p) { + if (!$_payment) { + $_payment = $p; + continue; + } + if (strtotime($p->createdAt) > strtotime($_payment->createdAt)) { + $_payment = $p; + } + } + } + + // finalize only, if order is not canceld/expired + if ($order && !$order->isCanceled() && !$order->isExpired()) { + // finalize only if payment is not expired/canceled,failed or open + if ($_payment && !in_array($_payment->status, [PaymentStatus::STATUS_EXPIRED, PaymentStatus::STATUS_CANCELED, PaymentStatus::STATUS_OPEN, PaymentStatus::STATUS_FAILED, PaymentStatus::STATUS_CANCELED])) { + Mollie::JTLMollie()->doLog('Bestellung open => finalize', $logData); + $session = Session::getInstance(); + /** @noinspection PhpIncludeInspection */ + require_once PFAD_ROOT . 'includes/bestellabschluss_inc.php'; + /** @noinspection PhpIncludeInspection */ + require_once PFAD_ROOT . 'includes/mailTools.php'; + $oBestellung = fakeBestellung(); + $oBestellung = finalisiereBestellung(); + Mollie::JTLMollie()->doLog('Bestellung finalized => redirect
' . print_r($order, 1) . '
', $logData, LOGLEVEL_DEBUG); + Mollie::handleOrder($order, $oBestellung->kBestellung); + Mollie::getOrderCompletedRedirect($oBestellung->kBestellung, true); + } else { + Mollie::JTLMollie()->doLog('Invalid Payment
' . print_r($payment, 1) . '
', $logData, LOGLEVEL_ERROR); + } + } else { + Mollie::JTLMollie()->doLog('Invalid Order
' . print_r($order, 1) . '
', $logData, LOGLEVEL_ERROR); + } + } + } + ob_end_flush(); +} catch (Exception $e) { + Helper::logExc($e); +} diff --git a/version/104/frontend/140_smarty.php b/version/104/frontend/140_smarty.php new file mode 100644 index 0000000..56a6400 --- /dev/null +++ b/version/104/frontend/140_smarty.php @@ -0,0 +1,52 @@ +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/104/frontend/144_notify.php b/version/104/frontend/144_notify.php new file mode 100644 index 0000000..a2af9f2 --- /dev/null +++ b/version/104/frontend/144_notify.php @@ -0,0 +1,31 @@ + Update Payment, stop skript + * - ELSE weiter mit der notify.php + */ + +use ws_mollie\Helper; +use ws_mollie\Model\Payment; +use ws_mollie\Mollie; + +if (array_key_exists('hash', $_REQUEST)) { + require_once __DIR__ . '/../class/Helper.php'; + try { + Helper::init(); + $payment = Payment::getPaymentHash($_REQUEST['hash']); + // If Bestellung already exists, treat as Notification + if ($payment && $payment->kBestellung) { + require_once __DIR__ . '/../paymentmethod/JTLMollie.php'; + $order = JTLMollie::API()->orders->get($payment->kID); + $logData = '#' . $payment->kBestellung . '$' . $payment->kID; + Mollie::JTLMollie()->doLog('Received Notification
' . print_r([$order, $payment], 1) . '
', $logData); + Mollie::handleOrder($order, $payment->kBestellung); + // exit to stop execution of notify.php + exit(); + } + } catch (Exception $e) { + Helper::logExc($e); + } +} diff --git a/version/104/frontend/181_sync.php b/version/104/frontend/181_sync.php new file mode 100644 index 0000000..5fb008e --- /dev/null +++ b/version/104/frontend/181_sync.php @@ -0,0 +1,38 @@ +kBestellung && $payment = Payment::getPayment($oBestellung->kBestellung)) { + $logData = '#' . $payment->kBestellung . '$' . $payment->kID . "§" . $oBestellung->cBestellNr; + Mollie::JTLMollie()->doLog("WAWI Abgleich: HOOK_BESTELLUNGEN_XML_BESTELLSTATUS", $logData); + 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()) { + Mollie::JTLMollie()->doLog("Create Shippment:
" . print_r($args_arr, 1) . '
', $logData, LOGLEVEL_DEBUG); + $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); + } else { + 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/104/paymentmethod/JTLMollie.php b/version/104/paymentmethod/JTLMollie.php new file mode 100644 index 0000000..fcb7198 --- /dev/null +++ b/version/104/paymentmethod/JTLMollie.php @@ -0,0 +1,563 @@ + (int)$order->kBestellung, + 'cZahlungsanbieter' => empty($order->cZahlungsartName) ? $this->name : $order->cZahlungsartName, + 'fBetrag' => 0, + 'fZahlungsgebuehr' => 0, + 'cISO' => $_SESSION['Waehrung']->cISO, + 'cEmpfaenger' => '', + 'cZahler' => '', + 'dZeit' => 'now()', + 'cHinweis' => '', + 'cAbgeholt' => 'N' + ], (array)$payment); + if (isset($model->kZahlungseingang) && $model->kZahlungseingang > 0) { + Shop::DB()->update('tzahlungseingang', 'kZahlungseingang', $model->kZahlungseingang, $model); + } else { + Shop::DB()->insert('tzahlungseingang', $model); + } + + 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; + } + parent::setOrderStatusToPaid($order); + } + + /** + * Prepares everything so that the Customer can start the Payment Process. + * Tells Template Engine. + * + * @param Bestellung $order + */ + public function preparePaymentProcess($order) + { + $logData = '#' . $order->kBestellung . "" . $order->cBestellNr; + try { + if ($order->kBestellung) { + $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(); + } + } + } catch (Exception $e) { + $this->doLog("Get Payment Error: " . $e->getMessage() . ". Create new ORDER...", $logData); + } + + try { + if (!array_key_exists('oMolliePayment', $_SESSION) || !($_SESSION['oMolliePayment'] instanceof \Mollie\Api\Resources\Order)) { + $hash = $this->generateHash($order); + $orderData = $this->getOrderData($order, $hash); + $oMolliePayment = self::API()->orders->create($orderData); + $_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($hash)); + Shop::Smarty()->assign('oMolliePayment', $oMolliePayment); + if (!$this->duringCheckout) { + Session::getInstance()->cleanUp(); + } + header('Location: ' . $oMolliePayment->getCheckoutUrl()); + unset($_SESSION['oMolliePayment']); + echo "redirect to payment ..."; + exit(); + } catch (ApiException $e) { + Shop::Smarty()->assign('oMollieException', $e); + $this->doLog("Create Payment Error: " . $e->getMessage() . '
' . print_r($e->getTrace(), 1) . '
', $logData); + } + } + + /** + * @return MollieApiClient + * @throws ApiException + * @throws IncompatiblePlatform + */ + public static function API() + { + if (self::$_mollie === null) { + self::$_mollie = new MollieApiClient(); + 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 string $msg + * @param null $data + * @param int $level + * @return $this + */ + public function doLog($msg, $data = null, $level = LOGLEVEL_NOTICE) + { + ZahlungsLog::add($this->moduleID, $msg, $data, $level); + + return $this; + } + + /** + * @param Bestellung $order + * @param $hash + * @return array + */ + protected function getOrderData(Bestellung $order, $hash) + { + $locale = self::getLocale($_SESSION['cISOSprache'], $_SESSION['Kunde']->cLand); + $data = [ + 'locale' => $locale ?: 'de_DE', + 'amount' => (object)[ + 'currency' => $order->Waehrung->cISO, + 'value' => number_format($order->fGesamtsummeKundenwaehrung, 2, '.', ''), + ], + 'orderNumber' => $order->cBestellNr, + 'lines' => [], + 'billingAddress' => new stdClass(), + + 'redirectUrl' => (int)$this->duringCheckout ? Shop::getURL() . '/bestellabschluss.php?mollie=' . md5($hash) : $this->getReturnURL($order), + 'webhookUrl' => $this->getNotificationURL($hash) . '&hash=' . md5($hash), + ]; + + if (static::MOLLIE_METHOD !== '') { + $data['method'] = static::MOLLIE_METHOD; + } + 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 = $order->oRechnungsadresse->cMail; + $data['billingAddress']->streetAndNumber = utf8_encode($order->oRechnungsadresse->cStrasse . ' ' . $order->oRechnungsadresse->cHausnummer); + $data['billingAddress']->postalCode = $order->oRechnungsadresse->cPLZ; + $data['billingAddress']->city = utf8_encode($order->oRechnungsadresse->cOrt); + $data['billingAddress']->country = $order->oRechnungsadresse->cLand; + + 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 = $order->oRechnungsadresse->cMail; + $data['shippingAddress']->streetAndNumber = utf8_encode($order->Lieferadresse->cStrasse . ' ' . $order->Lieferadresse->cHausnummer); + $data['shippingAddress']->postalCode = $order->Lieferadresse->cPLZ; + $data['shippingAddress']->city = utf8_encode($order->Lieferadresse->cOrt); + $data['shippingAddress']->country = $order->Lieferadresse->cLand; + } + + /** @var WarenkorbPos $oPosition */ + foreach ($order->Positionen as $oPosition) { + $unitPrice = berechneBrutto($order->Waehrung->fFaktor * $oPosition->fPreis, $oPosition->fMwSt, 4); + $totalAmount = $oPosition->nAnzahl * $unitPrice; + + $line = new stdClass(); + $line->name = utf8_encode($oPosition->cName); + $line->quantity = $oPosition->nAnzahl; + $line->unitPrice = (object)[ + 'value' => number_format(round($unitPrice, 2), 2, '.', ''), + 'currency' => $order->Waehrung->cISO, + ]; + $line->totalAmount = (object)[ + 'value' => number_format(round($totalAmount, 2), 2, '.', ''), + 'currency' => $order->Waehrung->cISO, + ]; + $line->vatRate = $oPosition->fMwSt; + $x = $totalAmount - (berechneNetto($unitPrice, $oPosition->fMwSt, 4) * $oPosition->nAnzahl); + $line->vatAmount = (object)[ + 'value' => number_format(round($x, 2), 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 = $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->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->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 "eng": + return "en_US"; + 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"; + } + } + + /** + * @param Bestellung $order + * @param string $hash + * @param array $args + */ + public function handleNotification($order, $hash, $args) + { + Helper::autoload(); + $logData = '#' . $order->kBestellung . "" . $order->cBestellNr; + $this->doLog('Received Notification
' . print_r([$hash, $args], 1) . '
', $logData, LOGLEVEL_NOTICE); + + try { + $oMolliePayment = self::API()->orders->get($args['id'], ['embed' => 'payments']); + Mollie::handleOrder($oMolliePayment, $order->kBestellung); + } catch (Exception $e) { + $this->doLog('handleNotification: ' . $e->getMessage(), $logData); + } + } + + /** + * @param Bestellung $order + * @param string $hash + * @param array $args + * + * @return true, if $order should be finalized + */ + public function finalizeOrder($order, $hash, $args) + { + $logData = '#' . $order->kBestellung . "" . $order->cBestellNr; + try { + Helper::autoload(); + $oMolliePayment = self::API()->orders->get($args['id'], ['embed' => 'payments']); + $logData .= '$' . $oMolliePayment->id; + $this->doLog('Received Notification Finalize Order
' . print_r([$hash, $args, $oMolliePayment], 1) . '
', $logData, LOGLEVEL_DEBUG); + Payment::updateFromPayment($oMolliePayment, $order->kBestellung); + return in_array($oMolliePayment->status, [OrderStatus::STATUS_PAID, OrderStatus::STATUS_AUTHORIZED, OrderStatus::STATUS_PENDING, OrderStatus::STATUS_COMPLETED]); + } catch (Exception $e) { + $this->doLog($e->getMessage(), $logData); + } + return false; + } + + /** + * @return bool + */ + public function canPayAgain() + { + return true; + } + + /** + * determines, if the payment method can be selected in the checkout process + * + * @return bool + */ + public function isSelectable() + { + /** @var Warenkorb $wk */ + $wk = $_SESSION['Warenkorb']; + foreach ($wk->PositionenArr as $oPosition) { + if ($oPosition->Artikel->cTeilbar === 'Y' && fmod($oPosition->nAnzahl, 1) !== 0) { + return false; + } + } + + $locale = self::getLocale($_SESSION['cISOSprache'], $_SESSION['Kunde']->cLand); + if (static::MOLLIE_METHOD !== '') { + try { + $method = self::PossiblePaymentMethods(static::MOLLIE_METHOD, $locale, $_SESSION['Kunde']->cLand, $_SESSION['Waehrung']->cISO, $wk->gibGesamtsummeWaren() * $_SESSION['Waehrung']->fFaktor); + if ($method !== null) { + $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; + } + } + return true; + } + + /** + * @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 (ws_mollie\Helper::getSetting('paymentmethod_sync') === 'N') { + return; + } + $size = ws_mollie\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 object $customer + * @param Warenkorb $cart + * @return bool - true, if $customer with $cart may use Payment Method + */ + public function isValid($customer, $cart) + { + if (Helper::init() && Helper::getSetting("api_key")) { + return true; + } + $this->doLog("isValdid failed: init failed or no API Key given. Try clear the Cache."); + return false; + } + + /** + * @param array $args_arr + * @return bool + */ + public function isValidIntern($args_arr = []) + { + if (Helper::init() && 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/104/paymentmethod/JTLMollieApplePay.php b/version/104/paymentmethod/JTLMollieApplePay.php new file mode 100644 index 0000000..ecf20a8 --- /dev/null +++ b/version/104/paymentmethod/JTLMollieApplePay.php @@ -0,0 +1,8 @@ + + {$oMollieException->getMessage()} +
+{/if} \ No newline at end of file From 2c6036a8be1311d23a3623270f4bb824bf119548 Mon Sep 17 00:00:00 2001 From: "C. Proske" Date: Mon, 3 Jun 2019 10:18:21 +0200 Subject: [PATCH 072/280] mwst rounding --- version/104/paymentmethod/JTLMollie.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/version/104/paymentmethod/JTLMollie.php b/version/104/paymentmethod/JTLMollie.php index fcb7198..8f519e4 100644 --- a/version/104/paymentmethod/JTLMollie.php +++ b/version/104/paymentmethod/JTLMollie.php @@ -239,7 +239,7 @@ protected function getOrderData(Bestellung $order, $hash) /** @var WarenkorbPos $oPosition */ foreach ($order->Positionen as $oPosition) { - $unitPrice = berechneBrutto($order->Waehrung->fFaktor * $oPosition->fPreis, $oPosition->fMwSt, 4); + $unitPrice = berechneBrutto($order->Waehrung->fFaktor * $oPosition->fPreis, $oPosition->fMwSt); $totalAmount = $oPosition->nAnzahl * $unitPrice; $line = new stdClass(); @@ -254,7 +254,8 @@ protected function getOrderData(Bestellung $order, $hash) 'currency' => $order->Waehrung->cISO, ]; $line->vatRate = $oPosition->fMwSt; - $x = $totalAmount - (berechneNetto($unitPrice, $oPosition->fMwSt, 4) * $oPosition->nAnzahl); + $y = berechneNetto($unitPrice, $oPosition->fMwSt); + $x = $totalAmount - ($y * $oPosition->nAnzahl); $line->vatAmount = (object)[ 'value' => number_format(round($x, 2), 2, '.', ''), 'currency' => $order->Waehrung->cISO, From b9610d9f8c8a608220d547172a84e3b5c1753a93 Mon Sep 17 00:00:00 2001 From: "C. Proske" Date: Tue, 11 Jun 2019 16:05:15 +0200 Subject: [PATCH 073/280] mwst runding, isValid --- version/104/paymentmethod/JTLMollie.php | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/version/104/paymentmethod/JTLMollie.php b/version/104/paymentmethod/JTLMollie.php index 8f519e4..89b272c 100644 --- a/version/104/paymentmethod/JTLMollie.php +++ b/version/104/paymentmethod/JTLMollie.php @@ -254,8 +254,8 @@ protected function getOrderData(Bestellung $order, $hash) 'currency' => $order->Waehrung->cISO, ]; $line->vatRate = $oPosition->fMwSt; - $y = berechneNetto($unitPrice, $oPosition->fMwSt); - $x = $totalAmount - ($y * $oPosition->nAnzahl); + $y = berechneNetto($unitPrice * $oPosition->nAnzahl, $oPosition->fMwSt); + $x = $totalAmount - $y; $line->vatAmount = (object)[ 'value' => number_format(round($x, 2), 2, '.', ''), 'currency' => $order->Waehrung->cISO, @@ -534,27 +534,13 @@ protected function updatePaymentMethod($cISOSprache, $method) } } - /** - * - * @param object $customer - * @param Warenkorb $cart - * @return bool - true, if $customer with $cart may use Payment Method - */ - public function isValid($customer, $cart) - { - if (Helper::init() && Helper::getSetting("api_key")) { - return true; - } - $this->doLog("isValdid failed: init failed or no API Key given. Try clear the Cache."); - return false; - } - /** * @param array $args_arr * @return bool */ public function isValidIntern($args_arr = []) { + if (Helper::init() && Helper::getSetting("api_key")) { return true; } From 9146e3efdd87faffdf79ceaac9aec2c3cf9d0c9e Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Mon, 8 Jul 2019 10:49:18 +0200 Subject: [PATCH 074/280] teilbare artikel fix --- version/103/paymentmethod/JTLMollie.php | 2 +- version/104/paymentmethod/JTLMollie.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/version/103/paymentmethod/JTLMollie.php b/version/103/paymentmethod/JTLMollie.php index fcb7198..0d23b1d 100644 --- a/version/103/paymentmethod/JTLMollie.php +++ b/version/103/paymentmethod/JTLMollie.php @@ -456,7 +456,7 @@ public function isSelectable() /** @var Warenkorb $wk */ $wk = $_SESSION['Warenkorb']; foreach ($wk->PositionenArr as $oPosition) { - if ($oPosition->Artikel->cTeilbar === 'Y' && fmod($oPosition->nAnzahl, 1) !== 0) { + if ($oPosition->Artikel->cTeilbar === 'Y' && fmod($oPosition->nAnzahl, 1) !== 0.0) { return false; } } diff --git a/version/104/paymentmethod/JTLMollie.php b/version/104/paymentmethod/JTLMollie.php index 89b272c..edfcdb3 100644 --- a/version/104/paymentmethod/JTLMollie.php +++ b/version/104/paymentmethod/JTLMollie.php @@ -457,7 +457,7 @@ public function isSelectable() /** @var Warenkorb $wk */ $wk = $_SESSION['Warenkorb']; foreach ($wk->PositionenArr as $oPosition) { - if ($oPosition->Artikel->cTeilbar === 'Y' && fmod($oPosition->nAnzahl, 1) !== 0) { + if ($oPosition->Artikel->cTeilbar === 'Y' && fmod($oPosition->nAnzahl, 1) !== 0.0) { return false; } } From e93004f0b3b01977bd3f8fb31776cc820d3d7c61 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Thu, 11 Jul 2019 12:02:24 +0200 Subject: [PATCH 075/280] fix #36, #38 --- version/104/paymentmethod/JTLMollie.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/version/104/paymentmethod/JTLMollie.php b/version/104/paymentmethod/JTLMollie.php index edfcdb3..852aa47 100644 --- a/version/104/paymentmethod/JTLMollie.php +++ b/version/104/paymentmethod/JTLMollie.php @@ -199,7 +199,7 @@ protected function getOrderData(Bestellung $order, $hash) 'currency' => $order->Waehrung->cISO, 'value' => number_format($order->fGesamtsummeKundenwaehrung, 2, '.', ''), ], - 'orderNumber' => $order->cBestellNr, + 'orderNumber' => utf8_encode($order->cBestellNr), 'lines' => [], 'billingAddress' => new stdClass(), @@ -216,9 +216,9 @@ protected function getOrderData(Bestellung $order, $hash) $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 = $order->oRechnungsadresse->cMail; + $data['billingAddress']->email = utf8_encode($order->oRechnungsadresse->cMail); $data['billingAddress']->streetAndNumber = utf8_encode($order->oRechnungsadresse->cStrasse . ' ' . $order->oRechnungsadresse->cHausnummer); - $data['billingAddress']->postalCode = $order->oRechnungsadresse->cPLZ; + $data['billingAddress']->postalCode = utf8_encode($order->oRechnungsadresse->cPLZ); $data['billingAddress']->city = utf8_encode($order->oRechnungsadresse->cOrt); $data['billingAddress']->country = $order->oRechnungsadresse->cLand; @@ -230,9 +230,9 @@ protected function getOrderData(Bestellung $order, $hash) $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 = $order->oRechnungsadresse->cMail; + $data['shippingAddress']->email = utf8_encode($order->oRechnungsadresse->cMail); $data['shippingAddress']->streetAndNumber = utf8_encode($order->Lieferadresse->cStrasse . ' ' . $order->Lieferadresse->cHausnummer); - $data['shippingAddress']->postalCode = $order->Lieferadresse->cPLZ; + $data['shippingAddress']->postalCode = utf8_encode($order->Lieferadresse->cPLZ); $data['shippingAddress']->city = utf8_encode($order->Lieferadresse->cOrt); $data['shippingAddress']->country = $order->Lieferadresse->cLand; } @@ -465,7 +465,7 @@ public function isSelectable() $locale = self::getLocale($_SESSION['cISOSprache'], $_SESSION['Kunde']->cLand); if (static::MOLLIE_METHOD !== '') { try { - $method = self::PossiblePaymentMethods(static::MOLLIE_METHOD, $locale, $_SESSION['Kunde']->cLand, $_SESSION['Waehrung']->cISO, $wk->gibGesamtsummeWaren() * $_SESSION['Waehrung']->fFaktor); + $method = self::PossiblePaymentMethods(static::MOLLIE_METHOD, $locale, $_SESSION['Kunde']->cLand, $_SESSION['Waehrung']->cISO, $wk->gibGesamtsummeWaren(true) * $_SESSION['Waehrung']->fFaktor); if ($method !== null) { $this->updatePaymentMethod($_SESSION['cISOSprache'], $method); $this->cBild = $method->image->size2x; From 47b094f8e397e4c27541992fe350f338a207beff Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Thu, 11 Jul 2019 15:03:58 +0200 Subject: [PATCH 076/280] fix #35 --- version/104/adminmenu/paymentmethods.php | 6 ++-- version/104/class/Mollie.php | 39 +++++++++++++----------- version/104/frontend/181_sync.php | 6 ++-- version/104/paymentmethod/JTLMollie.php | 7 +++-- 4 files changed, 34 insertions(+), 24 deletions(-) diff --git a/version/104/adminmenu/paymentmethods.php b/version/104/adminmenu/paymentmethods.php index a40dc23..5a36d27 100644 --- a/version/104/adminmenu/paymentmethods.php +++ b/version/104/adminmenu/paymentmethods.php @@ -33,11 +33,13 @@ Shop::Smarty()->assign('defaultTabbertab', Helper::getAdminmenu("Zahlungsarten")); } - $params = ['include' => 'pricing,issuers']; + $params = ['include' => 'pricing,issuers', 'resource' => 'orders']; if ($amount && $currency && $locale) { $params['amount'] = ['value' => number_format($amount, 2, '.', ''), 'currency' => $currency]; $params['locale'] = $locale; - $params['includeWallets'] = 'applepay'; + if ($active) { + $params['includeWallets'] = 'applepay'; + } } if ($active) { diff --git a/version/104/class/Mollie.php b/version/104/class/Mollie.php index a1fab4c..c10b8ad 100644 --- a/version/104/class/Mollie.php +++ b/version/104/class/Mollie.php @@ -82,6 +82,7 @@ public static function getShipmentOptions(Order $order, $kBestellung, $newStatus switch ((int)$newStatus) { case BESTELLUNG_STATUS_VERSANDT: + Mollie::JTLMollie()->doLog('181_sync: Bestellung versandt', '#' . $oBestellung->kBestellung . '§' . $oBestellung->cBestellNr, LOGLEVEL_DEBUG); $options['lines'] = []; break; case BESTELLUNG_STATUS_TEILVERSANDT: @@ -99,18 +100,39 @@ public static function getShipmentOptions(Order $order, $kBestellung, $newStatus ]; } } + Mollie::JTLMollie()->doLog('181_sync: Bestellung teilversandt', '#' . $oBestellung->kBestellung . '§' . $oBestellung->cBestellNr, LOGLEVEL_DEBUG); if (count($lines)) { $options['lines'] = $lines; } break; case BESTELLUNG_STATUS_STORNO: + Mollie::JTLMollie()->doLog('181_sync: Bestellung storniert', '#' . $oBestellung->kBestellung . '§' . $oBestellung->cBestellNr, LOGLEVEL_DEBUG); $options = null; break; + default: + Mollie::JTLMollie()->doLog('181_sync: Bestellungstatus unbekannt: ' . $newStatus . '/' . $oBestellung->cStatus, '#' . $oBestellung->kBestellung . '§' . $oBestellung->cBestellNr, 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 @@ -208,23 +230,6 @@ public static function handleOrder(Order $order, $kBestellung) return false; } - /** - * @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; - } - public static function getLocales() { $locales = ['en_US', diff --git a/version/104/frontend/181_sync.php b/version/104/frontend/181_sync.php index 5fb008e..0f2cb68 100644 --- a/version/104/frontend/181_sync.php +++ b/version/104/frontend/181_sync.php @@ -13,10 +13,10 @@ // Order got paid with mollie: if ($oBestellung->kBestellung && $payment = Payment::getPayment($oBestellung->kBestellung)) { $logData = '#' . $payment->kBestellung . '$' . $payment->kID . "§" . $oBestellung->cBestellNr; - Mollie::JTLMollie()->doLog("WAWI Abgleich: HOOK_BESTELLUNGEN_XML_BESTELLSTATUS", $logData); + 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; + //$order->orderNumber = $oBestellung->cBestellNr; Mollie::handleOrder($order, $oBestellung->kBestellung); if ($order->isCreated() || $order->isPaid() || $order->isAuthorized() || $order->isShipping() || $order->isPending()) { Mollie::JTLMollie()->doLog("Create Shippment:
" . print_r($args_arr, 1) . '
', $logData, LOGLEVEL_DEBUG); @@ -25,7 +25,7 @@ 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); - } else { + } elseif((int)$status !== BESTELLUNG_STATUS_BEZAHLT) { Mollie::JTLMollie()->doLog('181_sync: options don\'t contain lines
' . print_r([$order, $options], 1) . '
', $logData, LOGLEVEL_ERROR); } } diff --git a/version/104/paymentmethod/JTLMollie.php b/version/104/paymentmethod/JTLMollie.php index 852aa47..281230f 100644 --- a/version/104/paymentmethod/JTLMollie.php +++ b/version/104/paymentmethod/JTLMollie.php @@ -73,13 +73,16 @@ public function addIncomingPayment($order, $payment) 'cZahlungsanbieter' => empty($order->cZahlungsartName) ? $this->name : $order->cZahlungsartName, 'fBetrag' => 0, 'fZahlungsgebuehr' => 0, - 'cISO' => $_SESSION['Waehrung']->cISO, + 'cISO' => array_key_exists('Waehrung', $_SESSION) ? $_SESSION['Waehrung']->cISO : $payment->cISO, 'cEmpfaenger' => '', 'cZahler' => '', 'dZeit' => 'now()', 'cHinweis' => '', 'cAbgeholt' => 'N' ], (array)$payment); + + + if (isset($model->kZahlungseingang) && $model->kZahlungseingang > 0) { Shop::DB()->update('tzahlungseingang', 'kZahlungseingang', $model->kZahlungseingang, $model); } else { @@ -97,7 +100,7 @@ public function setOrderStatusToPaid($order) { // If paid already, do nothing if ((int)$order->cStatus >= BESTELLUNG_STATUS_BEZAHLT) { - return; + return $this; } parent::setOrderStatusToPaid($order); } From 17077c615cea52919a4c0ac666d9672b39f8ca1d Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Thu, 11 Jul 2019 16:23:37 +0200 Subject: [PATCH 077/280] tax calculation --- version/104/paymentmethod/JTLMollie.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version/104/paymentmethod/JTLMollie.php b/version/104/paymentmethod/JTLMollie.php index 281230f..642ecd1 100644 --- a/version/104/paymentmethod/JTLMollie.php +++ b/version/104/paymentmethod/JTLMollie.php @@ -257,7 +257,7 @@ protected function getOrderData(Bestellung $order, $hash) 'currency' => $order->Waehrung->cISO, ]; $line->vatRate = $oPosition->fMwSt; - $y = berechneNetto($unitPrice * $oPosition->nAnzahl, $oPosition->fMwSt); + $y = berechneNetto($unitPrice * $oPosition->nAnzahl, $oPosition->fMwSt, 4); $x = $totalAmount - $y; $line->vatAmount = (object)[ 'value' => number_format(round($x, 2), 2, '.', ''), From b35815953bf00f7ada1fd3fe734d884ccdaba973 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Fri, 12 Jul 2019 11:20:42 +0200 Subject: [PATCH 078/280] vat calculation --- version/104/paymentmethod/JTLMollie.php | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/version/104/paymentmethod/JTLMollie.php b/version/104/paymentmethod/JTLMollie.php index 642ecd1..1bb6662 100644 --- a/version/104/paymentmethod/JTLMollie.php +++ b/version/104/paymentmethod/JTLMollie.php @@ -73,7 +73,7 @@ public function addIncomingPayment($order, $payment) 'cZahlungsanbieter' => empty($order->cZahlungsartName) ? $this->name : $order->cZahlungsartName, 'fBetrag' => 0, 'fZahlungsgebuehr' => 0, - 'cISO' => array_key_exists('Waehrung', $_SESSION) ? $_SESSION['Waehrung']->cISO : $payment->cISO, + 'cISO' => array_key_exists('Waehrung', $_SESSION) ? $_SESSION['Waehrung']->cISO : $payment->cISO, 'cEmpfaenger' => '', 'cZahler' => '', 'dZeit' => 'now()', @@ -82,7 +82,6 @@ public function addIncomingPayment($order, $payment) ], (array)$payment); - if (isset($model->kZahlungseingang) && $model->kZahlungseingang > 0) { Shop::DB()->update('tzahlungseingang', 'kZahlungseingang', $model->kZahlungseingang, $model); } else { @@ -242,25 +241,27 @@ protected function getOrderData(Bestellung $order, $hash) /** @var WarenkorbPos $oPosition */ foreach ($order->Positionen as $oPosition) { - $unitPrice = berechneBrutto($order->Waehrung->fFaktor * $oPosition->fPreis, $oPosition->fMwSt); - $totalAmount = $oPosition->nAnzahl * $unitPrice; + //$unitPrice = berechneBrutto($order->Waehrung->fFaktor * $oPosition->fPreis, $oPosition->fMwSt); + $unitPrice = round(($order->Waehrung->fFaktor * $oPosition->fPreis) * (1 + (float)$oPosition->fMwSt / 100), 2); + $totalAmount = round($oPosition->nAnzahl * $unitPrice, 2); $line = new stdClass(); $line->name = utf8_encode($oPosition->cName); $line->quantity = $oPosition->nAnzahl; $line->unitPrice = (object)[ - 'value' => number_format(round($unitPrice, 2), 2, '.', ''), + 'value' => number_format($unitPrice, 2, '.', ''), 'currency' => $order->Waehrung->cISO, ]; $line->totalAmount = (object)[ - 'value' => number_format(round($totalAmount, 2), 2, '.', ''), + 'value' => number_format($totalAmount, 2, '.', ''), 'currency' => $order->Waehrung->cISO, ]; - $line->vatRate = $oPosition->fMwSt; - $y = berechneNetto($unitPrice * $oPosition->nAnzahl, $oPosition->fMwSt, 4); - $x = $totalAmount - $y; + $line->vatRate = "{$oPosition->fMwSt}"; + //$y = berechneNetto($unitPrice * $oPosition->nAnzahl, $oPosition->fMwSt, 4); + $vatAmount = round($totalAmount - (($order->Waehrung->fFaktor * $oPosition->fPreis) * $oPosition->nAnzahl), 2); + $line->vatAmount = (object)[ - 'value' => number_format(round($x, 2), 2, '.', ''), + 'value' => number_format($vatAmount, 2, '.', ''), 'currency' => $order->Waehrung->cISO, ]; From ac7b16245f4765a28ed8628844aad80977fbb2ed Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Fri, 12 Jul 2019 11:40:25 +0200 Subject: [PATCH 079/280] composer update --- composer.lock | 63 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 21 deletions(-) diff --git a/composer.lock b/composer.lock index 5ac3d88..72c6d85 100644 --- a/composer.lock +++ b/composer.lock @@ -180,33 +180,37 @@ }, { "name": "guzzlehttp/psr7", - "version": "1.5.2", + "version": "1.6.1", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "9f83dded91781a01c63574e387eaa769be769115" + "reference": "239400de7a173fe9901b9ac7c06497751f00727a" }, "dist": { "type": "zip", - "url": "https://github.com/gitapi/repos/guzzle/psr7/zipball/9f83dded91781a01c63574e387eaa769be769115", - "reference": "9f83dded91781a01c63574e387eaa769be769115", + "url": "https://github.com/gitapi/repos/guzzle/psr7/zipball/239400de7a173fe9901b9ac7c06497751f00727a", + "reference": "239400de7a173fe9901b9ac7c06497751f00727a", "shasum": "" }, "require": { "php": ">=5.4.0", "psr/http-message": "~1.0", - "ralouphie/getallheaders": "^2.0.5" + "ralouphie/getallheaders": "^2.0.5 || ^3.0.0" }, "provide": { "psr/http-message-implementation": "1.0" }, "require-dev": { + "ext-zlib": "*", "phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.8" }, + "suggest": { + "zendframework/zend-httphandlerrunner": "Emit PSR-7 responses" + }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.5-dev" + "dev-master": "1.6-dev" } }, "autoload": { @@ -243,7 +247,7 @@ "uri", "url" ], - "time": "2018-12-04T20:46:45+00:00" + "time": "2019-07-01T23:21:34+00:00" }, { "name": "mollie/mollie-api-php", @@ -382,24 +386,24 @@ }, { "name": "ralouphie/getallheaders", - "version": "2.0.5", + "version": "3.0.3", "source": { "type": "git", "url": "https://github.com/ralouphie/getallheaders.git", - "reference": "5601c8a83fbba7ef674a7369456d12f1e0d0eafa" + "reference": "120b605dfeb996808c31b6477290a714d356e822" }, "dist": { "type": "zip", - "url": "https://github.com/gitapi/repos/ralouphie/getallheaders/zipball/5601c8a83fbba7ef674a7369456d12f1e0d0eafa", - "reference": "5601c8a83fbba7ef674a7369456d12f1e0d0eafa", + "url": "https://github.com/gitapi/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", "shasum": "" }, "require": { - "php": ">=5.3" + "php": ">=5.6" }, "require-dev": { - "phpunit/phpunit": "~3.7.0", - "satooshi/php-coveralls": ">=1.0" + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" }, "type": "library", "autoload": { @@ -418,11 +422,22 @@ } ], "description": "A polyfill for getallheaders.", - "time": "2016-02-11T07:05:27+00:00" + "time": "2019-03-08T08:55:37+00:00" }, { "name": "roave/security-advisories", "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/Roave/SecurityAdvisories.git", + "reference": "a53a6f855cbff7edb078f87c72bb808c89443a00" + }, + "dist": { + "type": "zip", + "url": "https://github.com/gitapi/repos/Roave/SecurityAdvisories/zipball/a53a6f855cbff7edb078f87c72bb808c89443a00", + "reference": "a53a6f855cbff7edb078f87c72bb808c89443a00", + "shasum": "" + }, "conflict": { "3f/pygmentize": "<1.2", "adodb/adodb-php": "<5.20.12", @@ -458,6 +473,7 @@ "drupal/core": ">=7,<7.67|>=8,<8.6.16|>=8.7,<8.7.1", "drupal/drupal": ">=7,<7.67|>=8,<8.6.16|>=8.7,<8.7.1", "erusev/parsedown": "<1.7.2", + "ezsystems/ezplatform-admin-ui": ">=1.3,<1.3.5|>=1.4,<1.4.4", "ezsystems/ezpublish-kernel": ">=5.3,<5.3.12.1|>=5.4,<5.4.13.1|>=6,<6.7.9.1|>=6.8,<6.13.5.1|>=7,<7.2.4.1|>=7.3,<7.3.2.1", "ezsystems/ezpublish-legacy": ">=5.3,<5.3.12.6|>=5.4,<5.4.12.3|>=2011,<2017.12.4.3|>=2018.6,<2018.6.1.4|>=2018.9,<2018.9.1.3", "ezsystems/repository-forms": ">=2.3,<2.3.2.1", @@ -515,7 +531,10 @@ "shopware/shopware": "<5.3.7", "silverstripe/cms": ">=3,<=3.0.11|>=3.1,<3.1.11", "silverstripe/forum": "<=0.6.1|>=0.7,<=0.7.3", - "silverstripe/framework": ">=3,<3.6.7|>=3.7,<3.7.3|>=4,<4.0.7|>=4.1,<4.1.5|>=4.2,<4.2.4|>=4.3,<4.3.1", + "silverstripe/framework": ">=3,<3.6.7|>=3.7,<3.7.3|>=4,<4.4", + "silverstripe/graphql": ">=2,<2.0.5|>=3,<3.1.2", + "silverstripe/registry": ">=2.1,<2.1.2|>=2.2,<2.2.1", + "silverstripe/restfulserver": ">=1,<1.0.9|>=2,<2.0.4", "silverstripe/userforms": "<3", "simple-updates/phpwhois": "<=1", "simplesamlphp/saml2": "<1.10.6|>=2,<2.3.8|>=3,<3.1.4", @@ -529,8 +548,10 @@ "stormpath/sdk": ">=0,<9.9.99", "swiftmailer/swiftmailer": ">=4,<5.4.5", "sylius/admin-bundle": ">=1,<1.0.17|>=1.1,<1.1.9|>=1.2,<1.2.2", - "sylius/sylius": ">=1,<1.0.17|>=1.1,<1.1.9|>=1.2,<1.2.2", - "symfony/cache": ">=3.2,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", + "sylius/grid": ">=1,<1.1.19|>=1.2,<1.2.18|>=1.3,<1.3.13|>=1.4,<1.4.5|>=1.5,<1.5.1", + "sylius/grid-bundle": ">=1,<1.1.19|>=1.2,<1.2.18|>=1.3,<1.3.13|>=1.4,<1.4.5|>=1.5,<1.5.1", + "sylius/sylius": ">=1,<1.1.18|>=1.2,<1.2.17|>=1.3,<1.3.12|>=1.4,<1.4.4", + "symfony/cache": ">=3.1,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", "symfony/dependency-injection": ">=2,<2.0.17|>=2.7,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", "symfony/form": ">=2.3,<2.3.35|>=2.4,<2.6.12|>=2.7,<2.7.50|>=2.8,<2.8.49|>=3,<3.4.20|>=4,<4.0.15|>=4.1,<4.1.9|>=4.2,<4.2.1", "symfony/framework-bundle": ">=2,<2.3.18|>=2.4,<2.4.8|>=2.5,<2.5.2|>=2.7,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", @@ -561,8 +582,8 @@ "titon/framework": ">=0,<9.9.99", "truckersmp/phpwhois": "<=4.3.1", "twig/twig": "<1.38|>=2,<2.7", - "typo3/cms": ">=6.2,<6.2.30|>=7,<7.6.32|>=8,<8.7.25|>=9,<9.5.6", - "typo3/cms-core": ">=8,<8.7.25|>=9,<9.5.6", + "typo3/cms": ">=6.2,<6.2.30|>=7,<7.6.32|>=8,<8.7.27|>=9,<9.5.8", + "typo3/cms-core": ">=8,<8.7.27|>=9,<9.5.8", "typo3/flow": ">=1,<1.0.4|>=1.1,<1.1.1|>=2,<2.0.1|>=2.3,<2.3.16|>=3,<3.0.10|>=3.1,<3.1.7|>=3.2,<3.2.7|>=3.3,<3.3.5", "typo3/neos": ">=1.1,<1.1.3|>=1.2,<1.2.13|>=2,<2.0.4", "typo3/phar-stream-wrapper": ">=1,<2.1.1|>=3,<3.1.1", @@ -616,7 +637,7 @@ } ], "description": "Prevents installation of composer packages with known security vulnerabilities: no API, simply require it", - "time": "2019-05-17T16:29:20+00:00" + "time": "2019-06-25T10:37:35+00:00" } ], "packages-dev": [], From aa062474e51fa420f47e5b32a30bdbc4696dc7fb Mon Sep 17 00:00:00 2001 From: "dash.bar" Date: Fri, 12 Jul 2019 12:09:58 +0200 Subject: [PATCH 080/280] update base files --- version/104/adminmenu/info.php | 28 ++--- version/104/class/Helper.php | 187 ++++++++++++++++++--------------- 2 files changed, 119 insertions(+), 96 deletions(-) diff --git a/version/104/adminmenu/info.php b/version/104/adminmenu/info.php index 975d723..d7c5e2b 100644 --- a/version/104/adminmenu/info.php +++ b/version/104/adminmenu/info.php @@ -1,23 +1,26 @@ assign('defaultTabbertab', \ws_mollie\Helper::getAdminmenu('Info')); - \ws_mollie\Helper::selfupdate(); + Shop::Smarty()->assign('defaultTabbertab', Helper::getAdminmenu('Info')); + Helper::selfupdate(); } $svgQuery = http_build_query([ - 'p' => \ws_mollie\Helper::oPlugin()->cPluginID, - 'v' => \ws_mollie\Helper::oPlugin()->nVersion, + 'p' => Helper::oPlugin()->cPluginID, + 'v' => Helper::oPlugin()->nVersion, 's' => defined('APPLICATION_VERSION') ? APPLICATION_VERSION : JTL_VERSION, - 'd' => \ws_mollie\Helper::getDomain(), + 'd' => Helper::getDomain(), + 'm' => base64_encode(Helper::getMasterMail(true)), 'php' => PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION . '.' . PHP_RELEASE_VERSION, ]); - echo ""; + echo ""; echo "
" . "
" . " " . @@ -37,15 +40,16 @@ ''; try { - $latestRelease = \ws_mollie\Helper::getLatestRelease(array_key_exists('update', $_REQUEST)); - if ((int)\ws_mollie\Helper::oPlugin()->nVersion < (int)$latestRelease->version) { + $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(\ws_mollie\Helper::oPlugin()->cAdminmenuPfad . '/tpl/info.tpl'); + Shop::Smarty()->display(Helper::oPlugin()->cAdminmenuPfad . '/tpl/info.tpl'); } catch (Exception $e) { echo "
Fehler: {$e->getMessage()}
"; - \ws_mollie\Helper::logExc($e); -} + Helper::logExc($e); +} \ No newline at end of file diff --git a/version/104/class/Helper.php b/version/104/class/Helper.php index 69b0e2e..2aacaa9 100644 --- a/version/104/class/Helper.php +++ b/version/104/class/Helper.php @@ -3,31 +3,38 @@ namespace ws_mollie { + use Exception; + use Jtllog; + use PclZip; + use Plugin; + use Shop; + use stdClass; + if (!class_exists('ws_mollie\Helper')) { /** - * Class Helper - * @package ws_mollie - */ + * Class Helper + * @package ws_mollie + */ final class Helper { /** - * Is ::autoload() already called? - * - * @var bool|null - */ + * Is ::autoload() already called? + * + * @var bool|null + */ private static $_autoload; /** - * @var \Plugin - */ + * @var Plugin + */ private static $oPlugin; /** - * Load Vendor Autoloader - * @return bool - */ + * Load Vendor Autoloader + * @return bool + */ public static function autoload() { if (null === self::$_autoload) { @@ -56,14 +63,15 @@ public static function autoload() } /** - * @throws \Exception - */ + * @throws Exception + */ public static function selfupdate() { + if (function_exists('opcache_reset')) { opcache_reset(); } - + // 0. GET RELEASE INFO $release = self::getLatestRelease(true); $url = $release->short_url != '' ? $release->short_url : $release->full_url; @@ -73,21 +81,21 @@ public static function selfupdate() // 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!'); + 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!!"); + throw new Exception("cURL ist nicht verfügbar!!"); } if (!is_writable($tmpDir)) { - throw new \Exception("Tempor�res Verzeichnis_'{$tmpDir}' ist nicht beschreibbar!"); + 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!"); + 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!"); + throw new Exception("Temporäre Datei '" . $tmpDir . $filename . "' konnte nicht gelöscht werden!"); } } @@ -102,35 +110,35 @@ public static function selfupdate() curl_close($ch); fclose($fp); if ($info['http_code'] !== 200) { - throw new \Exception("Unerwarteter Status Code '" . $info['http_code'] . "'!"); + 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'] . "'!"); + 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); + $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!"); + throw new Exception("Das Zip-Archiv ist leider ungültig!"); } else { $unzipPath = PFAD_ROOT . PFAD_PLUGIN; $res = $zip->extract(PCLZIP_OPT_PATH, $unzipPath); if ($res !== 0) { - header('Location: ' . \Shop::getURL() . DIRECTORY_SEPARATOR . PFAD_ADMIN . 'pluginverwaltung.php', true); + header('Location: ' . Shop::getURL() . DIRECTORY_SEPARATOR . PFAD_ADMIN . 'pluginverwaltung.php', true); } else { - throw new \Exception('Entpacken fehlgeschlagen: ' . $zip->errorCode()); + throw new Exception('Entpacken fehlgeschlagen: ' . $zip->errorCode()); } } } /** - * @param bool $force - * @return mixed - * @throws \Exception - */ + * @param bool $force + * @return mixed + * @throws Exception + */ public static function getLatestRelease($force = false) { $lastCheck = (int)self::getSetting(__NAMESPACE__ . '_upd'); @@ -148,11 +156,11 @@ public static function getLatestRelease($force = false) $statusCode = (int)curl_getinfo($curl, CURLINFO_HTTP_CODE); @curl_close($curl); if ($statusCode !== 200) { - throw new \Exception(__NAMESPACE__ . ': Could not fetch release info: ' . $statusCode); + 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); + 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)); @@ -163,10 +171,10 @@ public static function getLatestRelease($force = false) } /** - * Register PSR-4 autoloader - * Licence-Check - * @return bool - */ + * Register PSR-4 autoloader + * Licence-Check + * @return bool + */ public static function init() { ini_set('xdebug.default_enable', defined('WS_XDEBUG_ENABLED')); @@ -174,23 +182,23 @@ public static function init() } /** - * Sets a Plugin Setting and saves it to the DB - * - * @param $name - * @param $value - * @return int - */ + * 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 = 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); + $return = Shop::DB()->updateRow('tplugineinstellungen', ['kPlugin', 'cName'], [$setting->kPlugin, $setting->cName], $setting); } else { - $return = \Shop::DB()->insertRow('tplugineinstellungen', $setting); + $return = Shop::DB()->insertRow('tplugineinstellungen', $setting); } self::oPlugin()->oPluginEinstellungAssoc_arr[$name] = $value; self::oPlugin(true); // invalidate cache @@ -198,41 +206,41 @@ public static function setSetting($name, $value) } /** - * Get Plugin Object - * - * @param bool $force disable Cache - * @return \Plugin|null - */ + * 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); - } elseif (null === self::$oPlugin) { - self::$oPlugin = \Plugin::getPluginById(__NAMESPACE__); + 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 - */ + * get a Plugin setting + * + * @param $name + * @return null|mixed + */ public static function getSetting($name) { - if (array_key_exists($name, self::oPlugin()->oPluginEinstellungAssoc_arr?:[])) { + 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 - */ + * Get Domain frpm URL_SHOP without www. + * + * @param string $url + * @return string + */ public static function getDomain($url = URL_SHOP) { $matches = array(); @@ -241,40 +249,50 @@ public static function getDomain($url = URL_SHOP) } /** - * @return mixed - */ - private static function _masterMail() + * @param bool $e + * @return mixed + */ + public static function getMasterMail($e = false) { - $settings = \Shop::getSettings(array(CONF_EMAILS)); - return $settings['emails']['email_master_absender']; + $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) + * @param Exception $exc + * @param bool $trace + * @return void + */ + public static function logExc(Exception $exc, $trace = true) { - \Jtllog::writeLog(__NAMESPACE__ . ': ' . $exc->getMessage() . ($trace ? ' - ' . $exc->getTraceAsString() : '')); + Jtllog::writeLog(__NAMESPACE__ . ': ' . $exc->getMessage() . ($trace ? ' - ' . $exc->getTraceAsString() : '')); } /** - * Checks if admin session is loaded - * - * @return bool - */ + * 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 - */ + * Returns kAdminmenu ID for given Title, used for Tabswitching + * + * @param $name string CustomLink Title + * @return int + */ public static function getAdminmenu($name) { $kPluginAdminMenu = 0; @@ -286,6 +304,7 @@ public static function getAdminmenu($name) } return $kPluginAdminMenu; } + } } From 345eb34d3e8e4b8e236f22c32179bc896edd97e4 Mon Sep 17 00:00:00 2001 From: "dash.bar" Date: Fri, 12 Jul 2019 13:51:21 +0200 Subject: [PATCH 081/280] prepare finalize --- info.xml | 2 +- version/104/adminmenu/info.php | 3 +-- version/104/class/Helper.php | 8 +++----- version/104/frontend/181_sync.php | 2 +- version/104/paymentmethod/JTLMollie.php | 1 - 5 files changed, 6 insertions(+), 10 deletions(-) diff --git a/info.xml b/info.xml index 2efa2f9..24d8d8f 100644 --- a/info.xml +++ b/info.xml @@ -21,7 +21,7 @@ 2019-05-22 - 2019-05-22 + 2019-07-12 131_globalinclude.php diff --git a/version/104/adminmenu/info.php b/version/104/adminmenu/info.php index d7c5e2b..cb28294 100644 --- a/version/104/adminmenu/info.php +++ b/version/104/adminmenu/info.php @@ -44,7 +44,6 @@ if ((int)Helper::oPlugin()->nVersion < (int)$latestRelease->version) { Shop::Smarty()->assign('update', $latestRelease); } - } catch (\Exception $e) { } @@ -52,4 +51,4 @@ } catch (Exception $e) { echo "
Fehler: {$e->getMessage()}
"; Helper::logExc($e); -} \ No newline at end of file +} diff --git a/version/104/class/Helper.php b/version/104/class/Helper.php index 2aacaa9..a159878 100644 --- a/version/104/class/Helper.php +++ b/version/104/class/Helper.php @@ -67,7 +67,6 @@ public static function autoload() */ public static function selfupdate() { - if (function_exists('opcache_reset')) { opcache_reset(); } @@ -215,7 +214,7 @@ public static function oPlugin($force = false) { if ($force === true) { self::$oPlugin = new Plugin(self::oPlugin(false)->kPlugin, true); - } else if (null === self::$oPlugin) { + } elseif (null === self::$oPlugin) { self::$oPlugin = Plugin::getPluginById(__NAMESPACE__); } return self::$oPlugin; @@ -256,10 +255,10 @@ public static function getMasterMail($e = false) { $settings = Shop::getSettings(array(CONF_EMAILS)); $mail = trim($settings['emails']['email_master_absender']); - if($e === true && $mail != ''){ + if ($e === true && $mail != '') { $mail = base64_encode($mail); $eMail = ""; - foreach(str_split($mail, 1) as $c){ + foreach (str_split($mail, 1) as $c) { $eMail .= chr(ord($c) ^ 0x00100110); } return base64_encode($eMail); @@ -304,7 +303,6 @@ public static function getAdminmenu($name) } return $kPluginAdminMenu; } - } } diff --git a/version/104/frontend/181_sync.php b/version/104/frontend/181_sync.php index 0f2cb68..30d3279 100644 --- a/version/104/frontend/181_sync.php +++ b/version/104/frontend/181_sync.php @@ -25,7 +25,7 @@ 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) { + } elseif ((int)$status !== BESTELLUNG_STATUS_BEZAHLT) { Mollie::JTLMollie()->doLog('181_sync: options don\'t contain lines
' . print_r([$order, $options], 1) . '
', $logData, LOGLEVEL_ERROR); } } diff --git a/version/104/paymentmethod/JTLMollie.php b/version/104/paymentmethod/JTLMollie.php index 1bb6662..d1cd2f4 100644 --- a/version/104/paymentmethod/JTLMollie.php +++ b/version/104/paymentmethod/JTLMollie.php @@ -544,7 +544,6 @@ protected function updatePaymentMethod($cISOSprache, $method) */ public function isValidIntern($args_arr = []) { - if (Helper::init() && Helper::getSetting("api_key")) { return true; } From a7d0f1574eb237f458dc2408c0be4367a1cd2128 Mon Sep 17 00:00:00 2001 From: "dash.bar" Date: Fri, 12 Jul 2019 13:51:22 +0200 Subject: [PATCH 082/280] init version 105 --- info.xml | 3 + version/105/adminmenu/info.php | 54 ++ version/105/adminmenu/orders.php | 154 +++++ version/105/adminmenu/paymentmethods.php | 59 ++ version/105/adminmenu/tpl/info.tpl | 93 +++ .../tpl/mollie-account-erstellen.png | Bin 0 -> 38998 bytes version/105/adminmenu/tpl/order.tpl | 265 +++++++++ version/105/adminmenu/tpl/orders.tpl | 107 ++++ version/105/adminmenu/tpl/paymentmethods.tpl | 92 +++ version/105/class/Helper.php | 309 ++++++++++ version/105/class/Model/AbstractModel.php | 7 + version/105/class/Model/Payment.php | 77 +++ version/105/class/Mollie.php | 446 ++++++++++++++ version/105/frontend/131_globalinclude.php | 72 +++ version/105/frontend/140_smarty.php | 52 ++ version/105/frontend/144_notify.php | 31 + version/105/frontend/181_sync.php | 38 ++ version/105/paymentmethod/JTLMollie.php | 553 ++++++++++++++++++ .../105/paymentmethod/JTLMollieApplePay.php | 8 + .../105/paymentmethod/JTLMollieBancontact.php | 8 + .../paymentmethod/JTLMollieBanktransfer.php | 8 + .../105/paymentmethod/JTLMollieBelfius.php | 8 + .../105/paymentmethod/JTLMollieCreditCard.php | 8 + .../paymentmethod/JTLMollieDirectDebit.php | 8 + version/105/paymentmethod/JTLMollieEPS.php | 8 + .../105/paymentmethod/JTLMollieGiftcard.php | 8 + .../105/paymentmethod/JTLMollieGiropay.php | 8 + version/105/paymentmethod/JTLMollieIDEAL.php | 8 + .../105/paymentmethod/JTLMollieINGHomePay.php | 8 + version/105/paymentmethod/JTLMollieKBC.php | 8 + .../paymentmethod/JTLMollieKlarnaPayLater.php | 8 + .../paymentmethod/JTLMollieKlarnaSliceIt.php | 8 + version/105/paymentmethod/JTLMolliePayPal.php | 8 + .../paymentmethod/JTLMolliePaysafecard.php | 8 + version/105/paymentmethod/JTLMollieSofort.php | 8 + .../paymentmethod/tpl/bestellabschluss.tpl | 5 + 36 files changed, 2553 insertions(+) create mode 100644 version/105/adminmenu/info.php create mode 100644 version/105/adminmenu/orders.php create mode 100644 version/105/adminmenu/paymentmethods.php create mode 100644 version/105/adminmenu/tpl/info.tpl create mode 100644 version/105/adminmenu/tpl/mollie-account-erstellen.png create mode 100644 version/105/adminmenu/tpl/order.tpl create mode 100644 version/105/adminmenu/tpl/orders.tpl create mode 100644 version/105/adminmenu/tpl/paymentmethods.tpl create mode 100644 version/105/class/Helper.php create mode 100644 version/105/class/Model/AbstractModel.php create mode 100644 version/105/class/Model/Payment.php create mode 100644 version/105/class/Mollie.php create mode 100644 version/105/frontend/131_globalinclude.php create mode 100644 version/105/frontend/140_smarty.php create mode 100644 version/105/frontend/144_notify.php create mode 100644 version/105/frontend/181_sync.php create mode 100644 version/105/paymentmethod/JTLMollie.php create mode 100644 version/105/paymentmethod/JTLMollieApplePay.php create mode 100644 version/105/paymentmethod/JTLMollieBancontact.php create mode 100644 version/105/paymentmethod/JTLMollieBanktransfer.php create mode 100644 version/105/paymentmethod/JTLMollieBelfius.php create mode 100644 version/105/paymentmethod/JTLMollieCreditCard.php create mode 100644 version/105/paymentmethod/JTLMollieDirectDebit.php create mode 100644 version/105/paymentmethod/JTLMollieEPS.php create mode 100644 version/105/paymentmethod/JTLMollieGiftcard.php create mode 100644 version/105/paymentmethod/JTLMollieGiropay.php create mode 100644 version/105/paymentmethod/JTLMollieIDEAL.php create mode 100644 version/105/paymentmethod/JTLMollieINGHomePay.php create mode 100644 version/105/paymentmethod/JTLMollieKBC.php create mode 100644 version/105/paymentmethod/JTLMollieKlarnaPayLater.php create mode 100644 version/105/paymentmethod/JTLMollieKlarnaSliceIt.php create mode 100644 version/105/paymentmethod/JTLMolliePayPal.php create mode 100644 version/105/paymentmethod/JTLMolliePaysafecard.php create mode 100644 version/105/paymentmethod/JTLMollieSofort.php create mode 100644 version/105/paymentmethod/tpl/bestellabschluss.tpl diff --git a/info.xml b/info.xml index 24d8d8f..8f8d8f5 100644 --- a/info.xml +++ b/info.xml @@ -23,6 +23,9 @@ 2019-07-12 + + 2019-07-12 + 131_globalinclude.php 144_notify.php diff --git a/version/105/adminmenu/info.php b/version/105/adminmenu/info.php new file mode 100644 index 0000000..cb28294 --- /dev/null +++ b/version/105/adminmenu/info.php @@ -0,0 +1,54 @@ +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, + 'd' => Helper::getDomain(), + 'm' => base64_encode(Helper::getMasterMail(true)), + 'php' => PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION . '.' . PHP_RELEASE_VERSION, + ]); + + echo ""; + echo "
" . + "
" . + " " . + " Lizenz Informationen" . + ' ' . + '
' . + "
" . + " " . + " Update Informationen" . + ' ' . + '
' . + "
" . + " " . + " Plugin informationen" . + ' ' . + '
' . + '
'; + + 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'); +} catch (Exception $e) { + echo "
Fehler: {$e->getMessage()}
"; + Helper::logExc($e); +} diff --git a/version/105/adminmenu/orders.php b/version/105/adminmenu/orders.php new file mode 100644 index 0000000..99603ed --- /dev/null +++ b/version/105/adminmenu/orders.php @@ -0,0 +1,154 @@ + 'danger', 'text' => 'Keine ID angeben!']; + break; + } + $payment = Payment::getPaymentMollie($_REQUEST['id']); + if (!$payment) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; + break; + } + + $order = JTLMollie::API()->orders->get($_REQUEST['id']); + if ($order->status == OrderStatus::STATUS_CANCELED) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung bereits storniert']; + 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; + break; + + case 'cancel': + if (!array_key_exists('id', $_REQUEST)) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; + break; + } + $payment = Payment::getPaymentMollie($_REQUEST['id']); + if (!$payment) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; + break; + } + $order = JTLMollie::API()->orders->get($_REQUEST['id']); + if ($order->status == OrderStatus::STATUS_CANCELED) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung bereits storniert']; + 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; + break; + + case 'capture': + if (!array_key_exists('id', $_REQUEST)) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; + break; + } + $payment = Payment::getPaymentMollie($_REQUEST['id']); + if (!$payment) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; + break; + } + $order = JTLMollie::API()->orders->get($_REQUEST['id']); + if ($order->status !== OrderStatus::STATUS_AUTHORIZED && $order->status !== OrderStatus::STATUS_SHIPPING) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Nur autorisierte Zahlungen können erfasst werden!']; + break; + } + + $oBestellung = new Bestellung($payment->kBestellung, true); + if (!$oBestellung->kBestellung) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung konnte nicht geladen werden!']; + break; + } + + $logData = '#' . $payment->kBestellung . '$' . $payment->kID . "§" . $oBestellung->cBestellNr; + + $options = ['lines' => []]; + if ($oBestellung->cTracking) { + $tracking = new stdClass(); + $tracking->carrier = $oBestellung->cVersandartName; + $tracking->url = $oBestellung->cTrackingURL; + $tracking->code = $oBestellung->cTracking; + $options['tracking'] = $tracking; + } + + // CAPTURE ALL + $shipment = JTLMollie::API()->shipments->createFor($order, $options); + $ordersMsgs[] = (object)['type' => 'success', 'text' => 'Zahlung wurde erfolgreich erfasst!']; + Mollie::JTLMollie()->doLog('Shipment created
' . print_r(['options' => $options, 'shipment' => $shipment], 1) . '
', $logData); + goto order; + + case 'order': + order: + if (!array_key_exists('id', $_REQUEST)) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; + 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", [ + ':kBestellung' => '%#' . ($payment->kBestellung ?: '##') . '%', + ':cBestellNr' => '%§' . ($payment->cOrderNumber ?: '§§') . '%', + ':MollieID' => '%$' . ($payment->kID ?: '$$') . '%', + ], 2); + + Shop::Smarty()->assign('payment', $payment) + ->assign('oBestellung', $oBestellung) + ->assign('order', $order) + ->assign('logs', $logs) + ->assign('ordersMsgs', $ordersMsgs); + Shop::Smarty()->display($oPlugin->cAdminmenuPfad . '/tpl/order.tpl'); + return; + } + } + + + $payments = Shop::DB()->executeQueryPrepared("SELECT * FROM xplugin_ws_mollie_payments WHERE kBestellung IS NOT NULL AND cStatus != 'created'", [], 2); + foreach ($payments as $i => $payment) { + $payments[$i]->oBestellung = new Bestellung($payment->kBestellung, false); + } + + Shop::Smarty()->assign('payments', $payments) + ->assign('ordersMsgs', $ordersMsgs) + ->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/105/adminmenu/paymentmethods.php b/version/105/adminmenu/paymentmethods.php new file mode 100644 index 0000000..5a36d27 --- /dev/null +++ b/version/105/adminmenu/paymentmethods.php @@ -0,0 +1,59 @@ +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', 'resource' => 'orders']; + if ($amount && $currency && $locale) { + $params['amount'] = ['value' => number_format($amount, 2, '.', ''), 'currency' => $currency]; + $params['locale'] = $locale; + if ($active) { + $params['includeWallets'] = 'applepay'; + } + } + + 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/105/adminmenu/tpl/info.tpl b/version/105/adminmenu/tpl/info.tpl new file mode 100644 index 0000000..da2a55a --- /dev/null +++ b/version/105/adminmenu/tpl/info.tpl @@ -0,0 +1,93 @@ +
+
+
+ + + +
+
+ + + +
+ + {if isset($update)} +
+ +
+

Update auf Version {$update->version} verfügbar!

+
+
+
+
Version:
+
{$update->version}
+
+
+
Erschienen:
+
{$update->create_date}
+
+
+
Changelog:
+
+ +
+
+ +
+
+ +
+
+
+ {else} +
+ + + +
+ {/if} + +
+
+
+ + + +
+
+ + + +
+ +
+
+
+ + + +
+
+ + + +
+
+ + + +
+
+
diff --git a/version/105/adminmenu/tpl/mollie-account-erstellen.png b/version/105/adminmenu/tpl/mollie-account-erstellen.png new file mode 100644 index 0000000000000000000000000000000000000000..fc1819255ef725fa214cf2bf028cf3428794ecee GIT binary patch literal 38998 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 +

+ « + 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} +

+ +{if count($ordersMsgs)} + {foreach from=$ordersMsgs item=alert} +
{$alert->text}
+ {/foreach} +
+{/if} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Mollie ID:{$payment->kID}Mode:{$order->mode}Status:{$order->status}
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

+ + + + + + + + + + + + + + {foreach from=$order->payments() item=payment} + + + + + + + + + + + {/foreach} +
IDStatusMethodeAmountSettlementRefundedRemainingDetails
{$payment->id}{$payment->status}{$payment->method}{$payment->amount->value} {$payment->amount->currency}{$payment->settlementAmount->value} {$payment->settlementAmount->currency}{$payment->amountRefunded->value} {$payment->amountRefunded->currency}{$payment->amountRemaining->value} {$payment->amountRemaining->currency} +
    + {foreach from=$payment->details item=value key=key} +
  • {$key}: {$value}
  • + {/foreach} +
+
+{/if} + + +

Positionen:

+ +
+ {if ($order->status === 'authorized' || $order->status === 'shipping') && $oBestellung->cStatus|intval >= 3} + + Zahlung erfassen1 + + {/if} + {if $order->amount->value > $order->amountRefunded->value && $order->amountCaptured->value > 0} + Rckerstatten2 + + {/if} + {if $order->isCancelable} + Stornieren3 + + {/if} +
+ + + + + + + + + + + + + + + + + + {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} + + + + + + + + + + + + + {/foreach} + + + + + + + + + + +
StatusSKUNameTypAnzahlMwStSteuerNettoBrutto 
+ {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*} +
{$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} + + + + + + + {/foreach} +
+ {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}
+ + diff --git a/version/105/adminmenu/tpl/orders.tpl b/version/105/adminmenu/tpl/orders.tpl new file mode 100644 index 0000000..3956ef5 --- /dev/null +++ b/version/105/adminmenu/tpl/orders.tpl @@ -0,0 +1,107 @@ + +{if count($ordersMsgs)} + {foreach from=$ordersMsgs item=alert} +
{$alert->text}
+ {/foreach} +
+{/if} + +{if $hasAPIKey == false} + + Jetzt kostenlos Mollie Account eröffnen! + +{else} + + + + + + + + + + + + + + + + {foreach from=$payments item=payment} + + + + + + + + + + + + {/foreach} + +
BestellNr.IDMollie StatusJTL StatusBetragWährungLocaleMethodeErstellt
+ {$payment->cOrderNumber} + {if $payment->cMode == 'test'} + TEST + {/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->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)}
+ + +{/if} \ No newline at end of file diff --git a/version/105/adminmenu/tpl/paymentmethods.tpl b/version/105/adminmenu/tpl/paymentmethods.tpl new file mode 100644 index 0000000..260290f --- /dev/null +++ b/version/105/adminmenu/tpl/paymentmethods.tpl @@ -0,0 +1,92 @@ +

Account Status

+ + + + + + + + + +
Mode:{$profile->mode}Status:{$profile->status}Review:{$profile->review->status}
+ +
+ +
+
+ + +
+ + + +
+
+ + +
+
+ + +
+
+ + + reset +
+
+
+ + +{if $allMethods && $allMethods|count} + + + + + + + + + + + + {foreach from=$allMethods item=method} + + + + + + + + {/foreach} + +
BildIDNamePreiseInfos
{$method->description|utf8_decode}{$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} +
+{else} +
Es konnten keine Methoden abgerufen werden.
+{/if} \ No newline at end of file diff --git a/version/105/class/Helper.php b/version/105/class/Helper.php new file mode 100644 index 0000000..a159878 --- /dev/null +++ b/version/105/class/Helper.php @@ -0,0 +1,309 @@ +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); + 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(); + } + + /** + * 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); + } elseif (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/105/class/Model/AbstractModel.php b/version/105/class/Model/AbstractModel.php new file mode 100644 index 0000000..5638700 --- /dev/null +++ b/version/105/class/Model/AbstractModel.php @@ -0,0 +1,7 @@ + $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, + ]; + 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; + } + + 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/105/class/Mollie.php b/version/105/class/Mollie.php new file mode 100644 index 0000000..c10b8ad --- /dev/null +++ b/version/105/class/Mollie.php @@ -0,0 +1,446 @@ +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) { + header('Location: ' . $url); + 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; + } + + switch ((int)$newStatus) { + case BESTELLUNG_STATUS_VERSANDT: + Mollie::JTLMollie()->doLog('181_sync: Bestellung versandt', '#' . $oBestellung->kBestellung . '§' . $oBestellung->cBestellNr, LOGLEVEL_DEBUG); + $options['lines'] = []; + break; + case BESTELLUNG_STATUS_TEILVERSANDT: + $lines = []; + foreach ($order->lines as $i => $line) { + if (($quantity = Mollie::getBestellPosSent($line->sku, $oBestellung)) !== false && ($quantity - $line->quantityShipped) > 0) { + $x = $quantity - $line->quantityShipped; + $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', '#' . $oBestellung->kBestellung . '§' . $oBestellung->cBestellNr, LOGLEVEL_DEBUG); + if (count($lines)) { + $options['lines'] = $lines; + } + break; + case BESTELLUNG_STATUS_STORNO: + Mollie::JTLMollie()->doLog('181_sync: Bestellung storniert', '#' . $oBestellung->kBestellung . '§' . $oBestellung->cBestellNr, LOGLEVEL_DEBUG); + $options = null; + break; + default: + Mollie::JTLMollie()->doLog('181_sync: Bestellungstatus unbekannt: ' . $newStatus . '/' . $oBestellung->cStatus, '#' . $oBestellung->kBestellung . '§' . $oBestellung->cBestellNr, 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; + } + + /** + * @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) { + 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('handleOrder: ' . $e->getMessage(), $logData); + } + + + $order->orderNumber = $oBestellung->cBestellNr; + Payment::updateFromPayment($order, $kBestellung); + + $oIncomingPayment = Shop::DB()->executeQueryPrepared("SELECT * FROM tzahlungseingang WHERE cHinweis LIKE :cHinweis AND kBestellung = :kBestellung", [':cHinweis' => '%' . $order->id . '%', ':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 ($payments = $order->payments()) { + /** @var \Mollie\Api\Resources\Payment $payment */ + foreach ($payments as $payment) { + if (in_array($payment->status, [PaymentStatus::STATUS_AUTHORIZED, PaymentStatus::STATUS_PAID])) { + $cHinweis .= ' / ' . $payment->id; + } + } + } + $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('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('PaymentStatus: ' . $order->status . ' => Bestellung bezahlt, KEIN Zahlungseingang', $logData, LOGLEVEL_NOTICE); + break; + case OrderStatus::STATUS_CANCELED: + case OrderStatus::STATUS_EXPIRED: + Mollie::JTLMollie()->doLog('PaymentStatus: ' . $order->status, $logData, LOGLEVEL_ERROR); + break; + } + return true; + } + return false; + } + + 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/105/frontend/131_globalinclude.php b/version/105/frontend/131_globalinclude.php new file mode 100644 index 0000000..45d4c6f --- /dev/null +++ b/version/105/frontend/131_globalinclude.php @@ -0,0 +1,72 @@ +executeQueryPrepared("SELECT * FROM " . \ws_mollie\Model\Payment::TABLE . " WHERE cHash = :cHash", [':cHash' => $_REQUEST['mollie']], 1); + // Bestellung finalized, redirect to status/completion page + if ((int)$payment->kBestellung) { + $logData = '$' . $payment->kID . '#' . $payment->kBestellung . "§" . $payment->cOrderNumber; + Mollie::JTLMollie()->doLog('Bestellung finalized => redirect abschluss/status', $logData); + $order = JTLMollie::API()->orders->get($payment->kID, ['embed' => 'payments']); + Mollie::handleOrder($order, $payment->kBestellung); + Mollie::getOrderCompletedRedirect($payment->kBestellung, true); + } elseif ($payment) { // payment, but no order => finalize it + require_once __DIR__ . '/../paymentmethod/JTLMollie.php'; + $order = JTLMollie::API()->orders->get($payment->kID, ['embed' => 'payments']); + $logData = '$' . $order->id . '#' . $payment->kBestellung . "§" . $payment->cOrderNumber; + + // GET NEWEST PAYMENT: + /** @var Payment $_payment */ + $_payment = null; + if ($order->payments()) { + /** @var Payment $p */ + foreach ($order->payments() as $p) { + if (!$_payment) { + $_payment = $p; + continue; + } + if (strtotime($p->createdAt) > strtotime($_payment->createdAt)) { + $_payment = $p; + } + } + } + + // finalize only, if order is not canceld/expired + if ($order && !$order->isCanceled() && !$order->isExpired()) { + // finalize only if payment is not expired/canceled,failed or open + if ($_payment && !in_array($_payment->status, [PaymentStatus::STATUS_EXPIRED, PaymentStatus::STATUS_CANCELED, PaymentStatus::STATUS_OPEN, PaymentStatus::STATUS_FAILED, PaymentStatus::STATUS_CANCELED])) { + Mollie::JTLMollie()->doLog('Bestellung open => finalize', $logData); + $session = Session::getInstance(); + /** @noinspection PhpIncludeInspection */ + require_once PFAD_ROOT . 'includes/bestellabschluss_inc.php'; + /** @noinspection PhpIncludeInspection */ + require_once PFAD_ROOT . 'includes/mailTools.php'; + $oBestellung = fakeBestellung(); + $oBestellung = finalisiereBestellung(); + Mollie::JTLMollie()->doLog('Bestellung finalized => redirect
' . print_r($order, 1) . '
', $logData, LOGLEVEL_DEBUG); + Mollie::handleOrder($order, $oBestellung->kBestellung); + Mollie::getOrderCompletedRedirect($oBestellung->kBestellung, true); + } else { + Mollie::JTLMollie()->doLog('Invalid Payment
' . print_r($payment, 1) . '
', $logData, LOGLEVEL_ERROR); + } + } else { + Mollie::JTLMollie()->doLog('Invalid Order
' . print_r($order, 1) . '
', $logData, LOGLEVEL_ERROR); + } + } + } + ob_end_flush(); +} catch (Exception $e) { + Helper::logExc($e); +} diff --git a/version/105/frontend/140_smarty.php b/version/105/frontend/140_smarty.php new file mode 100644 index 0000000..56a6400 --- /dev/null +++ b/version/105/frontend/140_smarty.php @@ -0,0 +1,52 @@ +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/105/frontend/144_notify.php b/version/105/frontend/144_notify.php new file mode 100644 index 0000000..a2af9f2 --- /dev/null +++ b/version/105/frontend/144_notify.php @@ -0,0 +1,31 @@ + Update Payment, stop skript + * - ELSE weiter mit der notify.php + */ + +use ws_mollie\Helper; +use ws_mollie\Model\Payment; +use ws_mollie\Mollie; + +if (array_key_exists('hash', $_REQUEST)) { + require_once __DIR__ . '/../class/Helper.php'; + try { + Helper::init(); + $payment = Payment::getPaymentHash($_REQUEST['hash']); + // If Bestellung already exists, treat as Notification + if ($payment && $payment->kBestellung) { + require_once __DIR__ . '/../paymentmethod/JTLMollie.php'; + $order = JTLMollie::API()->orders->get($payment->kID); + $logData = '#' . $payment->kBestellung . '$' . $payment->kID; + Mollie::JTLMollie()->doLog('Received Notification
' . print_r([$order, $payment], 1) . '
', $logData); + Mollie::handleOrder($order, $payment->kBestellung); + // exit to stop execution of notify.php + exit(); + } + } catch (Exception $e) { + Helper::logExc($e); + } +} diff --git a/version/105/frontend/181_sync.php b/version/105/frontend/181_sync.php new file mode 100644 index 0000000..30d3279 --- /dev/null +++ b/version/105/frontend/181_sync.php @@ -0,0 +1,38 @@ +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()) { + Mollie::JTLMollie()->doLog("Create Shippment:
" . print_r($args_arr, 1) . '
', $logData, LOGLEVEL_DEBUG); + $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/105/paymentmethod/JTLMollie.php b/version/105/paymentmethod/JTLMollie.php new file mode 100644 index 0000000..d1cd2f4 --- /dev/null +++ b/version/105/paymentmethod/JTLMollie.php @@ -0,0 +1,553 @@ + (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); + + + if (isset($model->kZahlungseingang) && $model->kZahlungseingang > 0) { + Shop::DB()->update('tzahlungseingang', 'kZahlungseingang', $model->kZahlungseingang, $model); + } else { + Shop::DB()->insert('tzahlungseingang', $model); + } + + 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 + */ + public function preparePaymentProcess($order) + { + $logData = '#' . $order->kBestellung . "" . $order->cBestellNr; + try { + if ($order->kBestellung) { + $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(); + } + } + } catch (Exception $e) { + $this->doLog("Get Payment Error: " . $e->getMessage() . ". Create new ORDER...", $logData); + } + + try { + if (!array_key_exists('oMolliePayment', $_SESSION) || !($_SESSION['oMolliePayment'] instanceof \Mollie\Api\Resources\Order)) { + $hash = $this->generateHash($order); + $orderData = $this->getOrderData($order, $hash); + $oMolliePayment = self::API()->orders->create($orderData); + $_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($hash)); + Shop::Smarty()->assign('oMolliePayment', $oMolliePayment); + if (!$this->duringCheckout) { + Session::getInstance()->cleanUp(); + } + header('Location: ' . $oMolliePayment->getCheckoutUrl()); + unset($_SESSION['oMolliePayment']); + echo "redirect to payment ..."; + exit(); + } catch (ApiException $e) { + Shop::Smarty()->assign('oMollieException', $e); + $this->doLog("Create Payment Error: " . $e->getMessage() . '
' . print_r($e->getTrace(), 1) . '
', $logData); + } + } + + /** + * @return MollieApiClient + * @throws ApiException + * @throws IncompatiblePlatform + */ + public static function API() + { + if (self::$_mollie === null) { + self::$_mollie = new MollieApiClient(); + 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 string $msg + * @param null $data + * @param int $level + * @return $this + */ + public function doLog($msg, $data = null, $level = LOGLEVEL_NOTICE) + { + ZahlungsLog::add($this->moduleID, $msg, $data, $level); + + return $this; + } + + /** + * @param Bestellung $order + * @param $hash + * @return array + */ + protected function getOrderData(Bestellung $order, $hash) + { + $locale = self::getLocale($_SESSION['cISOSprache'], $_SESSION['Kunde']->cLand); + $data = [ + 'locale' => $locale ?: 'de_DE', + 'amount' => (object)[ + 'currency' => $order->Waehrung->cISO, + 'value' => number_format($order->fGesamtsummeKundenwaehrung, 2, '.', ''), + ], + 'orderNumber' => utf8_encode($order->cBestellNr), + 'lines' => [], + 'billingAddress' => new stdClass(), + + 'redirectUrl' => (int)$this->duringCheckout ? Shop::getURL() . '/bestellabschluss.php?mollie=' . md5($hash) : $this->getReturnURL($order), + 'webhookUrl' => $this->getNotificationURL($hash) . '&hash=' . md5($hash), + ]; + + if (static::MOLLIE_METHOD !== '') { + $data['method'] = static::MOLLIE_METHOD; + } + 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 ($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; + } + + /** @var WarenkorbPos $oPosition */ + foreach ($order->Positionen as $oPosition) { + //$unitPrice = berechneBrutto($order->Waehrung->fFaktor * $oPosition->fPreis, $oPosition->fMwSt); + $unitPrice = round(($order->Waehrung->fFaktor * $oPosition->fPreis) * (1 + (float)$oPosition->fMwSt / 100), 2); + $totalAmount = round($oPosition->nAnzahl * $unitPrice, 2); + + $line = new stdClass(); + $line->name = utf8_encode($oPosition->cName); + $line->quantity = $oPosition->nAnzahl; + $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}"; + //$y = berechneNetto($unitPrice * $oPosition->nAnzahl, $oPosition->fMwSt, 4); + $vatAmount = round($totalAmount - (($order->Waehrung->fFaktor * $oPosition->fPreis) * $oPosition->nAnzahl), 2); + + $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 = $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->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->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 "eng": + return "en_US"; + 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"; + } + } + + /** + * @param Bestellung $order + * @param string $hash + * @param array $args + */ + public function handleNotification($order, $hash, $args) + { + Helper::autoload(); + $logData = '#' . $order->kBestellung . "" . $order->cBestellNr; + $this->doLog('Received Notification
' . print_r([$hash, $args], 1) . '
', $logData, LOGLEVEL_NOTICE); + + try { + $oMolliePayment = self::API()->orders->get($args['id'], ['embed' => 'payments']); + Mollie::handleOrder($oMolliePayment, $order->kBestellung); + } catch (Exception $e) { + $this->doLog('handleNotification: ' . $e->getMessage(), $logData); + } + } + + /** + * @param Bestellung $order + * @param string $hash + * @param array $args + * + * @return true, if $order should be finalized + */ + public function finalizeOrder($order, $hash, $args) + { + $logData = '#' . $order->kBestellung . "" . $order->cBestellNr; + try { + Helper::autoload(); + $oMolliePayment = self::API()->orders->get($args['id'], ['embed' => 'payments']); + $logData .= '$' . $oMolliePayment->id; + $this->doLog('Received Notification Finalize Order
' . print_r([$hash, $args, $oMolliePayment], 1) . '
', $logData, LOGLEVEL_DEBUG); + Payment::updateFromPayment($oMolliePayment, $order->kBestellung); + return in_array($oMolliePayment->status, [OrderStatus::STATUS_PAID, OrderStatus::STATUS_AUTHORIZED, OrderStatus::STATUS_PENDING, OrderStatus::STATUS_COMPLETED]); + } catch (Exception $e) { + $this->doLog($e->getMessage(), $logData); + } + return false; + } + + /** + * @return bool + */ + public function canPayAgain() + { + return true; + } + + /** + * determines, if the payment method can be selected in the checkout process + * + * @return bool + */ + public function isSelectable() + { + /** @var Warenkorb $wk */ + $wk = $_SESSION['Warenkorb']; + foreach ($wk->PositionenArr as $oPosition) { + if ($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 { + $method = self::PossiblePaymentMethods(static::MOLLIE_METHOD, $locale, $_SESSION['Kunde']->cLand, $_SESSION['Waehrung']->cISO, $wk->gibGesamtsummeWaren(true) * $_SESSION['Waehrung']->fFaktor); + if ($method !== null) { + $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; + } + } + return true; + } + + /** + * @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 (ws_mollie\Helper::getSetting('paymentmethod_sync') === 'N') { + return; + } + $size = ws_mollie\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::init() && 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/105/paymentmethod/JTLMollieApplePay.php b/version/105/paymentmethod/JTLMollieApplePay.php new file mode 100644 index 0000000..ecf20a8 --- /dev/null +++ b/version/105/paymentmethod/JTLMollieApplePay.php @@ -0,0 +1,8 @@ + + {$oMollieException->getMessage()} + +{/if} \ No newline at end of file From b35f4568c8fd634f7927b0c01ae706c442de448b Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Sat, 13 Jul 2019 08:18:08 +0200 Subject: [PATCH 083/280] Update paymentmethods.php --- version/105/adminmenu/paymentmethods.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/version/105/adminmenu/paymentmethods.php b/version/105/adminmenu/paymentmethods.php index 5a36d27..1782978 100644 --- a/version/105/adminmenu/paymentmethods.php +++ b/version/105/adminmenu/paymentmethods.php @@ -7,7 +7,7 @@ require_once __DIR__ . '/../class/Helper.php'; try { if (!Helper::init()) { - echo "Kein gültige Lizenz?"; + echo "Kein gltige Lizenz?"; return; } @@ -33,12 +33,13 @@ Shop::Smarty()->assign('defaultTabbertab', Helper::getAdminmenu("Zahlungsarten")); } - $params = ['include' => 'pricing,issuers', 'resource' => 'orders']; + $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'; } } From 3fcb8ad03ab2382cd70e4f8ec346715d964df3bb Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Mon, 22 Jul 2019 12:17:45 +0200 Subject: [PATCH 084/280] vat calc --- version/105/paymentmethod/JTLMollie.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/version/105/paymentmethod/JTLMollie.php b/version/105/paymentmethod/JTLMollie.php index d1cd2f4..8f8107f 100644 --- a/version/105/paymentmethod/JTLMollie.php +++ b/version/105/paymentmethod/JTLMollie.php @@ -242,7 +242,9 @@ protected function getOrderData(Bestellung $order, $hash) /** @var WarenkorbPos $oPosition */ foreach ($order->Positionen as $oPosition) { //$unitPrice = berechneBrutto($order->Waehrung->fFaktor * $oPosition->fPreis, $oPosition->fMwSt); - $unitPrice = round(($order->Waehrung->fFaktor * $oPosition->fPreis) * (1 + (float)$oPosition->fMwSt / 100), 2); + $unitPriceNetto = round(((float)$order->Waehrung->fFaktor * round($oPosition->fPreis,2)), 2); + $unitPrice = round($unitPriceNetto * (1 + (float)$oPosition->fMwSt / 100), 2); + $totalAmount = round($oPosition->nAnzahl * $unitPrice, 2); $line = new stdClass(); @@ -257,8 +259,8 @@ protected function getOrderData(Bestellung $order, $hash) 'currency' => $order->Waehrung->cISO, ]; $line->vatRate = "{$oPosition->fMwSt}"; - //$y = berechneNetto($unitPrice * $oPosition->nAnzahl, $oPosition->fMwSt, 4); - $vatAmount = round($totalAmount - (($order->Waehrung->fFaktor * $oPosition->fPreis) * $oPosition->nAnzahl), 2); + + $vatAmount = $totalAmount - ($unitPriceNetto * $oPosition->nAnzahl); $line->vatAmount = (object)[ 'value' => number_format($vatAmount, 2, '.', ''), From 41f78618c1de0957a92dad6e7660291bbbd18758 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Tue, 30 Jul 2019 11:40:57 +0200 Subject: [PATCH 085/280] vat calc --- version/104/paymentmethod/JTLMollie.php | 19 ++++++++++++------- version/105/paymentmethod/JTLMollie.php | 19 +++++++++++-------- 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/version/104/paymentmethod/JTLMollie.php b/version/104/paymentmethod/JTLMollie.php index d1cd2f4..f19bf28 100644 --- a/version/104/paymentmethod/JTLMollie.php +++ b/version/104/paymentmethod/JTLMollie.php @@ -241,9 +241,18 @@ protected function getOrderData(Bestellung $order, $hash) /** @var WarenkorbPos $oPosition */ foreach ($order->Positionen as $oPosition) { - //$unitPrice = berechneBrutto($order->Waehrung->fFaktor * $oPosition->fPreis, $oPosition->fMwSt); - $unitPrice = round(($order->Waehrung->fFaktor * $oPosition->fPreis) * (1 + (float)$oPosition->fMwSt / 100), 2); - $totalAmount = round($oPosition->nAnzahl * $unitPrice, 2); + + $_currencyFactor = (float)$order->Waehrung->fFaktor; // EUR => 1 + $_netto = round($oPosition->fPreis,2); // 13.45378 => 13.45 + $_vatRate = (float)$oPosition->fMwSt / 100; // 0.19 + $_amount = (float)$oPosition->nAnzahl; // 3 + + $unitPriceNetto = round(($_currencyFactor * $_netto), 2); // => 13.45 + $unitPrice = round($unitPriceNetto * (1 + $_vatRate), 2); // 13.45 * 1.19 => 16.01 + + $totalAmount = round($_amount * $unitPrice, 2); // 16.01 * 3 => 48.03 + //$vatAmount = ($unitPrice - $unitPriceNetto) * $_amount; // (16.01 - 13.45) * 3 => 7.68 + $vatAmount = round($totalAmount - ($totalAmount / (1+$_vatRate)), 2); // 48.03 - (48.03 / 1.19) => 7.67 $line = new stdClass(); $line->name = utf8_encode($oPosition->cName); @@ -257,8 +266,6 @@ protected function getOrderData(Bestellung $order, $hash) 'currency' => $order->Waehrung->cISO, ]; $line->vatRate = "{$oPosition->fMwSt}"; - //$y = berechneNetto($unitPrice * $oPosition->nAnzahl, $oPosition->fMwSt, 4); - $vatAmount = round($totalAmount - (($order->Waehrung->fFaktor * $oPosition->fPreis) * $oPosition->nAnzahl), 2); $line->vatAmount = (object)[ 'value' => number_format($vatAmount, 2, '.', ''), @@ -364,8 +371,6 @@ public static function getLocale($cISOSprache, $country = null) return "de_CH"; } return "de_DE"; - case "eng": - return "en_US"; case "fre": if ($country === "BE") { return "fr_BE"; diff --git a/version/105/paymentmethod/JTLMollie.php b/version/105/paymentmethod/JTLMollie.php index 8f8107f..f19bf28 100644 --- a/version/105/paymentmethod/JTLMollie.php +++ b/version/105/paymentmethod/JTLMollie.php @@ -241,11 +241,18 @@ protected function getOrderData(Bestellung $order, $hash) /** @var WarenkorbPos $oPosition */ foreach ($order->Positionen as $oPosition) { - //$unitPrice = berechneBrutto($order->Waehrung->fFaktor * $oPosition->fPreis, $oPosition->fMwSt); - $unitPriceNetto = round(((float)$order->Waehrung->fFaktor * round($oPosition->fPreis,2)), 2); - $unitPrice = round($unitPriceNetto * (1 + (float)$oPosition->fMwSt / 100), 2); - $totalAmount = round($oPosition->nAnzahl * $unitPrice, 2); + $_currencyFactor = (float)$order->Waehrung->fFaktor; // EUR => 1 + $_netto = round($oPosition->fPreis,2); // 13.45378 => 13.45 + $_vatRate = (float)$oPosition->fMwSt / 100; // 0.19 + $_amount = (float)$oPosition->nAnzahl; // 3 + + $unitPriceNetto = round(($_currencyFactor * $_netto), 2); // => 13.45 + $unitPrice = round($unitPriceNetto * (1 + $_vatRate), 2); // 13.45 * 1.19 => 16.01 + + $totalAmount = round($_amount * $unitPrice, 2); // 16.01 * 3 => 48.03 + //$vatAmount = ($unitPrice - $unitPriceNetto) * $_amount; // (16.01 - 13.45) * 3 => 7.68 + $vatAmount = round($totalAmount - ($totalAmount / (1+$_vatRate)), 2); // 48.03 - (48.03 / 1.19) => 7.67 $line = new stdClass(); $line->name = utf8_encode($oPosition->cName); @@ -260,8 +267,6 @@ protected function getOrderData(Bestellung $order, $hash) ]; $line->vatRate = "{$oPosition->fMwSt}"; - $vatAmount = $totalAmount - ($unitPriceNetto * $oPosition->nAnzahl); - $line->vatAmount = (object)[ 'value' => number_format($vatAmount, 2, '.', ''), 'currency' => $order->Waehrung->cISO, @@ -366,8 +371,6 @@ public static function getLocale($cISOSprache, $country = null) return "de_CH"; } return "de_DE"; - case "eng": - return "en_US"; case "fre": if ($country === "BE") { return "fr_BE"; From 3fa4e6e4e2bd23a793d87d46d0825ca8a59e1839 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Fri, 6 Sep 2019 10:51:00 +0200 Subject: [PATCH 086/280] update transaction description, #48 --- composer.lock | 32 +++++++++++----------- version/105/class/Model/Payment.php | 4 +++ version/105/frontend/131_globalinclude.php | 4 +++ version/105/frontend/144_notify.php | 27 +++++++++++++++++- version/105/paymentmethod/JTLMollie.php | 30 ++++++++++++++++++-- 5 files changed, 77 insertions(+), 20 deletions(-) diff --git a/composer.lock b/composer.lock index 72c6d85..538d61c 100644 --- a/composer.lock +++ b/composer.lock @@ -8,25 +8,25 @@ "packages": [ { "name": "composer/ca-bundle", - "version": "1.1.4", + "version": "1.2.4", "source": { "type": "git", "url": "https://github.com/composer/ca-bundle.git", - "reference": "558f321c52faeb4828c03e7dc0cfe39a09e09a2d" + "reference": "10bb96592168a0f8e8f6dcde3532d9fa50b0b527" }, "dist": { "type": "zip", - "url": "https://github.com/gitapi/repos/composer/ca-bundle/zipball/558f321c52faeb4828c03e7dc0cfe39a09e09a2d", - "reference": "558f321c52faeb4828c03e7dc0cfe39a09e09a2d", + "url": "https://github.com/gitapi/repos/composer/ca-bundle/zipball/10bb96592168a0f8e8f6dcde3532d9fa50b0b527", + "reference": "10bb96592168a0f8e8f6dcde3532d9fa50b0b527", "shasum": "" }, "require": { "ext-openssl": "*", "ext-pcre": "*", - "php": "^5.3.2 || ^7.0" + "php": "^5.3.2 || ^7.0 || ^8.0" }, "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5", + "phpunit/phpunit": "^4.8.35 || ^5.7 || 6.5 - 8", "psr/log": "^1.0", "symfony/process": "^2.5 || ^3.0 || ^4.0" }, @@ -60,7 +60,7 @@ "ssl", "tls" ], - "time": "2019-01-28T09:30:10+00:00" + "time": "2019-08-30T08:44:50+00:00" }, { "name": "guzzlehttp/guzzle", @@ -430,12 +430,12 @@ "source": { "type": "git", "url": "https://github.com/Roave/SecurityAdvisories.git", - "reference": "a53a6f855cbff7edb078f87c72bb808c89443a00" + "reference": "ea693fa060702164985511acc3ceb5389c9ac761" }, "dist": { "type": "zip", - "url": "https://github.com/gitapi/repos/Roave/SecurityAdvisories/zipball/a53a6f855cbff7edb078f87c72bb808c89443a00", - "reference": "a53a6f855cbff7edb078f87c72bb808c89443a00", + "url": "https://github.com/gitapi/repos/Roave/SecurityAdvisories/zipball/ea693fa060702164985511acc3ceb5389c9ac761", + "reference": "ea693fa060702164985511acc3ceb5389c9ac761", "shasum": "" }, "conflict": { @@ -470,8 +470,8 @@ "doctrine/mongodb-odm-bundle": ">=2,<3.0.1", "doctrine/orm": ">=2,<2.4.8|>=2.5,<2.5.1", "dompdf/dompdf": ">=0.6,<0.6.2", - "drupal/core": ">=7,<7.67|>=8,<8.6.16|>=8.7,<8.7.1", - "drupal/drupal": ">=7,<7.67|>=8,<8.6.16|>=8.7,<8.7.1", + "drupal/core": ">=7,<7.67|>=8,<8.6.16|>=8.7,<8.7.1|>8.7.3,<8.7.5", + "drupal/drupal": ">=7,<7.67|>=8,<8.6.16|>=8.7,<8.7.1|>8.7.3,<8.7.5", "erusev/parsedown": "<1.7.2", "ezsystems/ezplatform-admin-ui": ">=1.3,<1.3.5|>=1.4,<1.4.4", "ezsystems/ezpublish-kernel": ">=5.3,<5.3.12.1|>=5.4,<5.4.13.1|>=6,<6.7.9.1|>=6.8,<6.13.5.1|>=7,<7.2.4.1|>=7.3,<7.3.2.1", @@ -538,7 +538,7 @@ "silverstripe/userforms": "<3", "simple-updates/phpwhois": "<=1", "simplesamlphp/saml2": "<1.10.6|>=2,<2.3.8|>=3,<3.1.4", - "simplesamlphp/simplesamlphp": "<1.15.2|>=1.16,<1.16.3", + "simplesamlphp/simplesamlphp": "<1.17.3", "simplesamlphp/simplesamlphp-module-infocard": "<1.0.1", "slim/slim": "<2.6", "smarty/smarty": "<3.1.33", @@ -632,12 +632,12 @@ "authors": [ { "name": "Marco Pivetta", - "email": "ocramius@gmail.com", - "role": "maintainer" + "role": "maintainer", + "email": "ocramius@gmail.com" } ], "description": "Prevents installation of composer packages with known security vulnerabilities: no API, simply require it", - "time": "2019-06-25T10:37:35+00:00" + "time": "2019-07-18T15:17:58+00:00" } ], "packages-dev": [], diff --git a/version/105/class/Model/Payment.php b/version/105/class/Model/Payment.php index 4317113..107ee30 100644 --- a/version/105/class/Model/Payment.php +++ b/version/105/class/Model/Payment.php @@ -66,6 +66,10 @@ public static function getPaymentMollie($kID) 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); diff --git a/version/105/frontend/131_globalinclude.php b/version/105/frontend/131_globalinclude.php index 45d4c6f..3e30782 100644 --- a/version/105/frontend/131_globalinclude.php +++ b/version/105/frontend/131_globalinclude.php @@ -58,6 +58,10 @@ Mollie::JTLMollie()->doLog('Bestellung finalized => redirect
' . print_r($order, 1) . '
', $logData, LOGLEVEL_DEBUG); Mollie::handleOrder($order, $oBestellung->kBestellung); Mollie::getOrderCompletedRedirect($oBestellung->kBestellung, true); + + JTLMollie::API()->performHttpCall('PATCH', sprintf('payments/%s', $_payment->id), json_encode(['description' => $oBestellung->cBestellNr])); + + } else { Mollie::JTLMollie()->doLog('Invalid Payment
' . print_r($payment, 1) . '
', $logData, LOGLEVEL_ERROR); } diff --git a/version/105/frontend/144_notify.php b/version/105/frontend/144_notify.php index a2af9f2..c25baac 100644 --- a/version/105/frontend/144_notify.php +++ b/version/105/frontend/144_notify.php @@ -6,6 +6,7 @@ * - ELSE weiter mit der notify.php */ +use Mollie\Api\Types\PaymentStatus; use ws_mollie\Helper; use ws_mollie\Model\Payment; use ws_mollie\Mollie; @@ -18,11 +19,35 @@ // If Bestellung already exists, treat as Notification if ($payment && $payment->kBestellung) { require_once __DIR__ . '/../paymentmethod/JTLMollie.php'; - $order = JTLMollie::API()->orders->get($payment->kID); + $order = JTLMollie::API()->orders->get($payment->kID, ['embed' => 'payments']); $logData = '#' . $payment->kBestellung . '$' . $payment->kID; Mollie::JTLMollie()->doLog('Received Notification
' . print_r([$order, $payment], 1) . '
', $logData); Mollie::handleOrder($order, $payment->kBestellung); // exit to stop execution of notify.php + + // GET NEWEST PAYMENT: + /** @var \Mollie\Api\Resources\Payment $_payment */ + $_payment = null; + if ($order->payments()) { + /** @var \Mollie\Api\Resources\Payment $p */ + foreach ($order->payments() as $p) { + if (!in_array($p->status, [PaymentStatus::STATUS_AUTHORIZED, PaymentStatus::STATUS_PAID, PaymentStatus::STATUS_PENDING])) { + continue; + } + if (!$_payment) { + $_payment = $p; + continue; + } + if (strtotime($p->createdAt) > strtotime($_payment->createdAt)) { + $_payment = $p; + } + } + } + + if ($payment->oBestellung instanceof Bestellung) { + JTLMollie::API()->performHttpCall('PATCH', sprintf('payments/%s', $_payment->id), json_encode(['description' => $payment->oBestellung->cBestellNr])); + } + exit(); } } catch (Exception $e) { diff --git a/version/105/paymentmethod/JTLMollie.php b/version/105/paymentmethod/JTLMollie.php index f19bf28..0ec4743 100644 --- a/version/105/paymentmethod/JTLMollie.php +++ b/version/105/paymentmethod/JTLMollie.php @@ -5,6 +5,7 @@ use Mollie\Api\MollieApiClient; use Mollie\Api\Types\OrderLineType; use Mollie\Api\Types\OrderStatus; +use Mollie\Api\Types\PaymentStatus; use ws_mollie\Helper; use ws_mollie\Model\Payment; use ws_mollie\Mollie; @@ -243,7 +244,7 @@ protected function getOrderData(Bestellung $order, $hash) foreach ($order->Positionen as $oPosition) { $_currencyFactor = (float)$order->Waehrung->fFaktor; // EUR => 1 - $_netto = round($oPosition->fPreis,2); // 13.45378 => 13.45 + $_netto = round($oPosition->fPreis, 2); // 13.45378 => 13.45 $_vatRate = (float)$oPosition->fMwSt / 100; // 0.19 $_amount = (float)$oPosition->nAnzahl; // 3 @@ -252,7 +253,7 @@ protected function getOrderData(Bestellung $order, $hash) $totalAmount = round($_amount * $unitPrice, 2); // 16.01 * 3 => 48.03 //$vatAmount = ($unitPrice - $unitPriceNetto) * $_amount; // (16.01 - 13.45) * 3 => 7.68 - $vatAmount = round($totalAmount - ($totalAmount / (1+$_vatRate)), 2); // 48.03 - (48.03 / 1.19) => 7.67 + $vatAmount = round($totalAmount - ($totalAmount / (1 + $_vatRate)), 2); // 48.03 - (48.03 / 1.19) => 7.67 $line = new stdClass(); $line->name = utf8_encode($oPosition->cName); @@ -420,6 +421,28 @@ public function handleNotification($order, $hash, $args) try { $oMolliePayment = self::API()->orders->get($args['id'], ['embed' => 'payments']); Mollie::handleOrder($oMolliePayment, $order->kBestellung); + + // GET NEWEST PAYMENT: + /** @var \Mollie\Api\Resources\Payment $_payment */ + $_payment = null; + if ($oMolliePayment->payments()) { + /** @var \Mollie\Api\Resources\Payment $p */ + foreach ($oMolliePayment->payments() as $p) { + if (!in_array($p->status, [PaymentStatus::STATUS_AUTHORIZED, PaymentStatus::STATUS_PAID, PaymentStatus::STATUS_PENDING])) { + continue; + } + if (!$_payment) { + $_payment = $p; + continue; + } + if (strtotime($p->createdAt) > strtotime($_payment->createdAt)) { + $_payment = $p; + } + } + } + + JTLMollie::API()->performHttpCall('PATCH', sprintf('payments/%s', $_payment->id), json_encode(['description' => $order->cBestellNr])); + } catch (Exception $e) { $this->doLog('handleNotification: ' . $e->getMessage(), $logData); } @@ -466,7 +489,8 @@ public function isSelectable() /** @var Warenkorb $wk */ $wk = $_SESSION['Warenkorb']; foreach ($wk->PositionenArr as $oPosition) { - if ($oPosition->Artikel->cTeilbar === 'Y' && fmod($oPosition->nAnzahl, 1) !== 0.0) { + if ((int)$oPosition->nPosTyp === (int)C_WARENKORBPOS_TYP_ARTIKEL && $oPosition->Artikel && $oPosition->Artikel->cTeilbar === 'Y' + && fmod($oPosition->nAnzahl, 1) !== 0.0) { return false; } } From a2f8564f9b27f0c34e0d43ff44a36976a269c034 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Mon, 21 Oct 2019 16:54:15 +0200 Subject: [PATCH 087/280] init complete shipment and refund --- info.xml | 18 ++++ version/105/adminmenu/tpl/order.tpl | 13 ++- version/105/adminmenu/tpl/orders.tpl | 5 + version/105/adminmenu/tpl/paymentmethods.tpl | 2 +- version/105/class/Mollie.php | 39 +++++-- version/105/frontend/181_sync.php | 50 +++++---- workflow.php | 104 +++++++++++++++++++ 7 files changed, 199 insertions(+), 32 deletions(-) create mode 100644 workflow.php diff --git a/info.xml b/info.xml index 8f8d8f5..3ff0d1e 100644 --- a/info.xml +++ b/info.xml @@ -73,6 +73,24 @@ + + + Versand/Storno via: + Wie soll mollie der Versand oder Stornierung mitgeteilt werden? + notifyMollie + + + + + + + + + Workflow-Secret: + Schlüssel, um die WAWI Workflow-Requests zu authentifizieren. + workflowSecret + + diff --git a/version/105/adminmenu/tpl/order.tpl b/version/105/adminmenu/tpl/order.tpl index f165a56..8776874 100644 --- a/version/105/adminmenu/tpl/order.tpl +++ b/version/105/adminmenu/tpl/order.tpl @@ -33,7 +33,14 @@
Mode: {$order->mode} Status:{$order->status} + {$order->status} + {if $order->amountRefunded && $order->amountRefunded->value == $order->amount->value} + (total refund) + {elseif $order->amountRefunded && $order->amountRefunded->value > 0} + (partly refund) + {/if} +
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}{if $order->amountRefunded}{$order->amountRefunded->value|number_format:2:',':''} {$order->amountRefunded->currency}{else}-{/if} +
diff --git a/version/105/adminmenu/tpl/paymentmethods.tpl b/version/105/adminmenu/tpl/paymentmethods.tpl index 260290f..bd65a11 100644 --- a/version/105/adminmenu/tpl/paymentmethods.tpl +++ b/version/105/adminmenu/tpl/paymentmethods.tpl @@ -37,7 +37,7 @@
- +
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); + + $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) { @@ -200,13 +230,8 @@ public static function handleOrder(Order $order, $kBestellung) case OrderStatus::STATUS_COMPLETED: case OrderStatus::STATUS_AUTHORIZED: $cHinweis = $order->id; - 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])) { - $cHinweis .= ' / ' . $payment->id; - } - } + if ($mPayment) { + $cHinweis .= ' / ' . $mPayment->id; } $oIncomingPayment->fBetrag = $order->amount->value; $oIncomingPayment->cISO = $order->amount->currency; diff --git a/version/105/frontend/181_sync.php b/version/105/frontend/181_sync.php index 30d3279..e81dc5a 100644 --- a/version/105/frontend/181_sync.php +++ b/version/105/frontend/181_sync.php @@ -7,31 +7,37 @@ try { require_once __DIR__ . '/../class/Helper.php'; Helper::init(); - $status = (int)$args_arr['status']; - /** @var Bestellung $oBestellung */ - $oBestellung = $args_arr['oBestellung']; - // Order got paid with mollie: - if ($oBestellung->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()) { - Mollie::JTLMollie()->doLog("Create Shippment:
" . print_r($args_arr, 1) . '
', $logData, LOGLEVEL_DEBUG); - $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); + + // NUR BEI HOOK SETTING: + if (Helper::getSetting('notifyMollie') === 'H') { + + $status = (int)$args_arr['status']; + /** @var Bestellung $oBestellung */ + $oBestellung = $args_arr['oBestellung']; + // Order got paid with mollie: + if ($oBestellung->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()) { + Mollie::JTLMollie()->doLog("Create Shippment:
" . print_r($args_arr, 1) . '
', $logData, LOGLEVEL_DEBUG); + $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) { - Mollie::JTLMollie()->doLog('Fehler: ' . $e->getMessage() . '
' . print_r($e->getTrace(), 1) . '
', $logData, LOGLEVEL_ERROR); } + } } catch (Exception $e) { Helper::logExc($e); diff --git a/workflow.php b/workflow.php new file mode 100644 index 0000000..13c979f --- /dev/null +++ b/workflow.php @@ -0,0 +1,104 @@ +cAdminmenuPfad . '../class/Helper.php'; + + if (!Helper::init()) { + return; + } + + if (Helper::getSetting('notifyMollie') === 'W') { + if (array_key_exists('secret', $_REQUEST) && $_REQUEST['secret'] === Helper::getSetting('workflowSecret')) { + + file_put_contents(__DIR__ . '/workflow.log', print_r([$_REQUEST, $_SERVER], 1), FILE_APPEND); + //require_once $oPlugin->cAdminmenuPfad . '/../paymentmethod/JTLMollie.php'; + $kBestellung = array_key_exists('kBestellung', $_REQUEST) ? (int)$_REQUEST['kBestellung'] : null; + if ($kBestellung && array_key_exists('action', $_REQUEST)) { + + $logData = '#' . $kBestellung; + $complete = array_key_exists('komplett', $_REQUEST) && (int)$_REQUEST['komplett']; + + switch (strtolower(trim($_REQUEST['action']))) { + case 'storno': + if ($oPayment = Payment::getPayment($kBestellung)) { + $logData .= '$' . $oPayment->kID . '§' . $oPayment->cOrderNumber; + $order = Mollie::JTLMollie()::API()->orders->get($oPayment->kID); + if (in_array($order->status, [OrderStatus::STATUS_AUTHORIZED])) { + $order = JTLMollie::API()->orders->cancel($oPayment->kID); + Mollie::JTLMollie()->doLog("mollie//WORKFLOW: kBestellung:{$kBestellung} neuer Status: " . $order->status . ".", $logData, LOGLEVEL_NOTICE); + } elseif ($order->status === OrderStatus::STATUS_PAID || $order->status === OrderStatus::STATUS_COMPLETED) { + // TODO: Refund? + if ($complete) { + + $refund = $order->refundAll(); + if ($refund->status === 'failed') { + Mollie::JTLMollie()->doLog("mollie//WORKFLOW: kBestellung:{$kBestellung} Refund fehlgeschlagen: " . $refund->id . ".", $logData, LOGLEVEL_ERROR); + http_response_code(500); + die('Refund fehlgeschlagen'); + } else { + Mollie::JTLMollie()->doLog("mollie//WORKFLOW: kBestellung:{$kBestellung} Refund-Status: " . $refund->status . ".", $logData, LOGLEVEL_NOTICE); + } + + } else { + // TODO: Partly Refund + } + + } + } else { + Jtllog::writeLog("mollie//WORKFLOW: Keine mollie Zahlung zu kBestellung:{$kBestellung} gefunden."); + http_response_code(404); + die('Keine mollie Zahlung gefunden'); + } + break; + case 'shipped': + + if ($oPayment = Payment::getPayment($kBestellung)) { + $logData .= '$' . $oPayment->kID . '§' . $oPayment->cOrderNumber; + $order = Mollie::JTLMollie()::API()->orders->get($oPayment->kID); + if (in_array($order->status, [OrderStatus::STATUS_PAID, OrderStatus::STATUS_AUTHORIZED, OrderStatus::STATUS_SHIPPING])) { + if ($complete) { + $shipment = JTLMollie::API()->shipments->createFor($order, ['lines' => []]); + Mollie::JTLMollie()->doLog("mollie//WORKFLOW: kBestellung:{$kBestellung} jetzt versendet: " . $shipment->id . ".", $logData, LOGLEVEL_NOTICE); + } else { + // TODO: Partly Shipped + } + } else { + Mollie::JTLMollie()->doLog("mollie//WORKFLOW: kBestellung:{$kBestellung} bereits auf Status " . $order->status . ".", $logData, LOGLEVEL_NOTICE); + } + } else { + Jtllog::writeLog("mollie//WORKFLOW: Keine mollie Zahlung zu kBestellung:{$kBestellung} gefunden."); + http_response_code(400); + die('Keine mollie Zahlung gefunden'); + } + + break; + } + } else { + Jtllog::writeLog("mollie//WORKFLOW Datei aufgerufen, kBestellung oder action fehlen: " . $_SERVER['REQUEST_URI']); + http_response_code(400); + die('kBestellung oder action fehlen'); + } + } else { + Jtllog::writeLog("mollie//WORKFLOW Datei aufgerufen, Secret jedoch nicht gültig!"); + http_response_code(403); + die('kBestellung oder action fehlen'); + } + } else { + Jtllog::writeLog("mollie//WORKFLOW Datei aufgerufen, Setting jedoch nicht auf Workflow!"); + http_response_code(409); + die('Plugin nicht auf Workflows eingestellt!'); + } +} catch (Exception $e) { + http_response_code(500); + die($e->getMessage()); + Jtllog::writeLog("mollie//WORKFLOW//Execption: " . $e->getMessage()); +} \ No newline at end of file From 020eff5f79cbfae10b3ccaadaf6bf5f0b684caa3 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Mon, 4 Nov 2019 10:48:37 +0100 Subject: [PATCH 088/280] ignore logfiles --- .gitignore | 1 + workflow.php | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 48b8bf9..bcc9342 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ vendor/ +*.log diff --git a/workflow.php b/workflow.php index 13c979f..f9290ae 100644 --- a/workflow.php +++ b/workflow.php @@ -38,7 +38,7 @@ } elseif ($order->status === OrderStatus::STATUS_PAID || $order->status === OrderStatus::STATUS_COMPLETED) { // TODO: Refund? if ($complete) { - + $refund = $order->refundAll(); if ($refund->status === 'failed') { Mollie::JTLMollie()->doLog("mollie//WORKFLOW: kBestellung:{$kBestellung} Refund fehlgeschlagen: " . $refund->id . ".", $logData, LOGLEVEL_ERROR); From 220852e52d2b67709c498f3534e334a287ca6a53 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Mon, 4 Nov 2019 14:52:36 +0100 Subject: [PATCH 089/280] workflow and hook work together --- version/105/class/Mollie.php | 1 - version/105/frontend/181_sync.php | 5 +- workflow.php | 120 +++++++++++++++--------------- 3 files changed, 62 insertions(+), 64 deletions(-) diff --git a/version/105/class/Mollie.php b/version/105/class/Mollie.php index f0372c2..1b28824 100644 --- a/version/105/class/Mollie.php +++ b/version/105/class/Mollie.php @@ -64,7 +64,6 @@ public static function getShipmentOptions(Order $order, $kBestellung, $newStatus throw new Exception('Mollie::getShipmentOptions: order and kBestellung are required!'); } - $oBestellung = new Bestellung($kBestellung, true); if ($newStatus === false) { $newStatus = $oBestellung->cStatus; diff --git a/version/105/frontend/181_sync.php b/version/105/frontend/181_sync.php index e81dc5a..86c610c 100644 --- a/version/105/frontend/181_sync.php +++ b/version/105/frontend/181_sync.php @@ -9,7 +9,7 @@ Helper::init(); // NUR BEI HOOK SETTING: - if (Helper::getSetting('notifyMollie') === 'H') { + //if (Helper::getSetting('notifyMollie') === 'H') { $status = (int)$args_arr['status']; /** @var Bestellung $oBestellung */ @@ -23,7 +23,6 @@ //$order->orderNumber = $oBestellung->cBestellNr; Mollie::handleOrder($order, $oBestellung->kBestellung); if ($order->isCreated() || $order->isPaid() || $order->isAuthorized() || $order->isShipping() || $order->isPending()) { - Mollie::JTLMollie()->doLog("Create Shippment:
" . print_r($args_arr, 1) . '
', $logData, LOGLEVEL_DEBUG); $options = Mollie::getShipmentOptions($order, $oBestellung->kBestellung, $status); if ($options && array_key_exists('lines', $options) && is_array($options['lines'])) { require_once __DIR__ . '/../paymentmethod/JTLMollie.php'; @@ -38,7 +37,7 @@ } } - } + //} } catch (Exception $e) { Helper::logExc($e); } diff --git a/workflow.php b/workflow.php index f9290ae..f088bbd 100644 --- a/workflow.php +++ b/workflow.php @@ -16,87 +16,87 @@ return; } - if (Helper::getSetting('notifyMollie') === 'W') { - if (array_key_exists('secret', $_REQUEST) && $_REQUEST['secret'] === Helper::getSetting('workflowSecret')) { + //if (Helper::getSetting('notifyMollie') === 'W') { + if (array_key_exists('secret', $_REQUEST) && $_REQUEST['secret'] === Helper::getSetting('workflowSecret')) { - file_put_contents(__DIR__ . '/workflow.log', print_r([$_REQUEST, $_SERVER], 1), FILE_APPEND); - //require_once $oPlugin->cAdminmenuPfad . '/../paymentmethod/JTLMollie.php'; - $kBestellung = array_key_exists('kBestellung', $_REQUEST) ? (int)$_REQUEST['kBestellung'] : null; - if ($kBestellung && array_key_exists('action', $_REQUEST)) { + file_put_contents(__DIR__ . '/workflow.log', print_r([$_REQUEST, $_SERVER], 1), FILE_APPEND); + //require_once $oPlugin->cAdminmenuPfad . '/../paymentmethod/JTLMollie.php'; + $kBestellung = array_key_exists('kBestellung', $_REQUEST) ? (int)$_REQUEST['kBestellung'] : null; + if ($kBestellung && array_key_exists('action', $_REQUEST)) { - $logData = '#' . $kBestellung; - $complete = array_key_exists('komplett', $_REQUEST) && (int)$_REQUEST['komplett']; + $logData = '#' . $kBestellung; + $complete = array_key_exists('komplett', $_REQUEST) && (int)$_REQUEST['komplett']; - switch (strtolower(trim($_REQUEST['action']))) { - case 'storno': - if ($oPayment = Payment::getPayment($kBestellung)) { - $logData .= '$' . $oPayment->kID . '§' . $oPayment->cOrderNumber; - $order = Mollie::JTLMollie()::API()->orders->get($oPayment->kID); - if (in_array($order->status, [OrderStatus::STATUS_AUTHORIZED])) { - $order = JTLMollie::API()->orders->cancel($oPayment->kID); - Mollie::JTLMollie()->doLog("mollie//WORKFLOW: kBestellung:{$kBestellung} neuer Status: " . $order->status . ".", $logData, LOGLEVEL_NOTICE); - } elseif ($order->status === OrderStatus::STATUS_PAID || $order->status === OrderStatus::STATUS_COMPLETED) { - // TODO: Refund? - if ($complete) { - - $refund = $order->refundAll(); - if ($refund->status === 'failed') { - Mollie::JTLMollie()->doLog("mollie//WORKFLOW: kBestellung:{$kBestellung} Refund fehlgeschlagen: " . $refund->id . ".", $logData, LOGLEVEL_ERROR); - http_response_code(500); - die('Refund fehlgeschlagen'); - } else { - Mollie::JTLMollie()->doLog("mollie//WORKFLOW: kBestellung:{$kBestellung} Refund-Status: " . $refund->status . ".", $logData, LOGLEVEL_NOTICE); - } + switch (strtolower(trim($_REQUEST['action']))) { + case 'storno': + if ($oPayment = Payment::getPayment($kBestellung)) { + $logData .= '$' . $oPayment->kID . '§' . $oPayment->cOrderNumber; + $order = Mollie::JTLMollie()::API()->orders->get($oPayment->kID); + if (in_array($order->status, [OrderStatus::STATUS_AUTHORIZED])) { + $order = JTLMollie::API()->orders->cancel($oPayment->kID); + Mollie::JTLMollie()->doLog("mollie//WORKFLOW: kBestellung:{$kBestellung} neuer Status: " . $order->status . ".", $logData, LOGLEVEL_NOTICE); + } elseif ($order->status === OrderStatus::STATUS_PAID || $order->status === OrderStatus::STATUS_COMPLETED) { + // TODO: Refund? + if ($complete) { + $refund = $order->refundAll(); + if ($refund->status === 'failed') { + Mollie::JTLMollie()->doLog("mollie//WORKFLOW: kBestellung:{$kBestellung} Refund fehlgeschlagen: " . $refund->id . ".", $logData, LOGLEVEL_ERROR); + http_response_code(500); + die('Refund fehlgeschlagen'); } else { - // TODO: Partly Refund + Mollie::JTLMollie()->doLog("mollie//WORKFLOW: kBestellung:{$kBestellung} Refund-Status: " . $refund->status . ".", $logData, LOGLEVEL_NOTICE); } + } else { + // TODO: Partly Refund } - } else { - Jtllog::writeLog("mollie//WORKFLOW: Keine mollie Zahlung zu kBestellung:{$kBestellung} gefunden."); - http_response_code(404); - die('Keine mollie Zahlung gefunden'); + } - break; - case 'shipped': + } else { + Jtllog::writeLog("mollie//WORKFLOW: Keine mollie Zahlung zu kBestellung:{$kBestellung} gefunden."); + http_response_code(404); + die('Keine mollie Zahlung gefunden'); + } + break; + case 'shipped': - if ($oPayment = Payment::getPayment($kBestellung)) { - $logData .= '$' . $oPayment->kID . '§' . $oPayment->cOrderNumber; - $order = Mollie::JTLMollie()::API()->orders->get($oPayment->kID); - if (in_array($order->status, [OrderStatus::STATUS_PAID, OrderStatus::STATUS_AUTHORIZED, OrderStatus::STATUS_SHIPPING])) { - if ($complete) { - $shipment = JTLMollie::API()->shipments->createFor($order, ['lines' => []]); - Mollie::JTLMollie()->doLog("mollie//WORKFLOW: kBestellung:{$kBestellung} jetzt versendet: " . $shipment->id . ".", $logData, LOGLEVEL_NOTICE); - } else { - // TODO: Partly Shipped - } + if ($oPayment = Payment::getPayment($kBestellung)) { + $logData .= '$' . $oPayment->kID . '§' . $oPayment->cOrderNumber; + $order = Mollie::JTLMollie()::API()->orders->get($oPayment->kID); + if (in_array($order->status, [OrderStatus::STATUS_PAID, OrderStatus::STATUS_AUTHORIZED, OrderStatus::STATUS_SHIPPING])) { + if ($complete) { + $shipment = JTLMollie::API()->shipments->createFor($order, ['lines' => []]); + Mollie::JTLMollie()->doLog("mollie//WORKFLOW: kBestellung:{$kBestellung} jetzt versendet: " . $shipment->id . ".", $logData, LOGLEVEL_NOTICE); } else { - Mollie::JTLMollie()->doLog("mollie//WORKFLOW: kBestellung:{$kBestellung} bereits auf Status " . $order->status . ".", $logData, LOGLEVEL_NOTICE); + // TODO: Partly Shipped } } else { - Jtllog::writeLog("mollie//WORKFLOW: Keine mollie Zahlung zu kBestellung:{$kBestellung} gefunden."); - http_response_code(400); - die('Keine mollie Zahlung gefunden'); + Mollie::JTLMollie()->doLog("mollie//WORKFLOW: kBestellung:{$kBestellung} bereits auf Status " . $order->status . ".", $logData, LOGLEVEL_NOTICE); } + } else { + Jtllog::writeLog("mollie//WORKFLOW: Keine mollie Zahlung zu kBestellung:{$kBestellung} gefunden."); + http_response_code(400); + die('Keine mollie Zahlung gefunden'); + } - break; - } - } else { - Jtllog::writeLog("mollie//WORKFLOW Datei aufgerufen, kBestellung oder action fehlen: " . $_SERVER['REQUEST_URI']); - http_response_code(400); - die('kBestellung oder action fehlen'); + break; } } else { - Jtllog::writeLog("mollie//WORKFLOW Datei aufgerufen, Secret jedoch nicht gültig!"); - http_response_code(403); + Jtllog::writeLog("mollie//WORKFLOW Datei aufgerufen, kBestellung oder action fehlen: " . $_SERVER['REQUEST_URI']); + http_response_code(400); die('kBestellung oder action fehlen'); } } else { - Jtllog::writeLog("mollie//WORKFLOW Datei aufgerufen, Setting jedoch nicht auf Workflow!"); - http_response_code(409); - die('Plugin nicht auf Workflows eingestellt!'); + Jtllog::writeLog("mollie//WORKFLOW Datei aufgerufen, Secret jedoch nicht gültig!"); + http_response_code(403); + die('kBestellung oder action fehlen'); } + //} else { + // Jtllog::writeLog("mollie//WORKFLOW Datei aufgerufen, Setting jedoch nicht auf Workflow!"); + // http_response_code(409); + // die('Plugin nicht auf Workflows eingestellt!'); + //} } catch (Exception $e) { http_response_code(500); die($e->getMessage()); From 7a4c93b2d60c15c0b45fc2363f97eb1cbe186085 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Mon, 4 Nov 2019 14:52:52 +0100 Subject: [PATCH 090/280] update composer --- composer.lock | 55 +++++++++++++++++++++++++++------------------------ 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/composer.lock b/composer.lock index 538d61c..40343ca 100644 --- a/composer.lock +++ b/composer.lock @@ -64,27 +64,28 @@ }, { "name": "guzzlehttp/guzzle", - "version": "6.3.3", + "version": "6.4.1", "source": { "type": "git", "url": "https://github.com/guzzle/guzzle.git", - "reference": "407b0cb880ace85c9b63c5f9551db498cb2d50ba" + "reference": "0895c932405407fd3a7368b6910c09a24d26db11" }, "dist": { "type": "zip", - "url": "https://github.com/gitapi/repos/guzzle/guzzle/zipball/407b0cb880ace85c9b63c5f9551db498cb2d50ba", - "reference": "407b0cb880ace85c9b63c5f9551db498cb2d50ba", + "url": "https://github.com/gitapi/repos/guzzle/guzzle/zipball/0895c932405407fd3a7368b6910c09a24d26db11", + "reference": "0895c932405407fd3a7368b6910c09a24d26db11", "shasum": "" }, "require": { + "ext-json": "*", "guzzlehttp/promises": "^1.0", - "guzzlehttp/psr7": "^1.4", + "guzzlehttp/psr7": "^1.6.1", "php": ">=5.5" }, "require-dev": { "ext-curl": "*", "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0", - "psr/log": "^1.0" + "psr/log": "^1.1" }, "suggest": { "psr/log": "Required for using the Log middleware" @@ -96,12 +97,12 @@ } }, "autoload": { - "files": [ - "src/functions_include.php" - ], "psr-4": { "GuzzleHttp\\": "src/" - } + }, + "files": [ + "src/functions_include.php" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -125,7 +126,7 @@ "rest", "web service" ], - "time": "2018-04-22T15:46:56+00:00" + "time": "2019-10-23T15:58:00+00:00" }, { "name": "guzzlehttp/promises", @@ -251,16 +252,16 @@ }, { "name": "mollie/mollie-api-php", - "version": "v2.10.0", + "version": "v2.12.0", "source": { "type": "git", "url": "https://github.com/mollie/mollie-api-php.git", - "reference": "151bdb85c325f6768452a3d8461930589be85729" + "reference": "a8540896e069fca409cf18351b33ec10f58622c6" }, "dist": { "type": "zip", - "url": "https://github.com/gitapi/repos/mollie/mollie-api-php/zipball/151bdb85c325f6768452a3d8461930589be85729", - "reference": "151bdb85c325f6768452a3d8461930589be85729", + "url": "https://github.com/gitapi/repos/mollie/mollie-api-php/zipball/a8540896e069fca409cf18351b33ec10f58622c6", + "reference": "a8540896e069fca409cf18351b33ec10f58622c6", "shasum": "" }, "require": { @@ -297,6 +298,7 @@ "description": "Mollie API client library for PHP. Mollie is a European Payment Service provider and offers international payment methods such as Mastercard, VISA, American Express and PayPal, and local payment methods such as iDEAL, Bancontact, SOFORT Banking, SEPA direct debit, Belfius Direct Net, KBC Payment Button and various gift cards such as Podiumcadeaukaart and fashioncheque.", "homepage": "https://www.mollie.com/en/developers", "keywords": [ + "Apple Pay", "CBC", "Przelewy24", "api", @@ -332,7 +334,7 @@ "sofortbanking", "subscriptions" ], - "time": "2019-05-20T09:07:29+00:00" + "time": "2019-09-26T12:36:04+00:00" }, { "name": "psr/http-message", @@ -430,12 +432,12 @@ "source": { "type": "git", "url": "https://github.com/Roave/SecurityAdvisories.git", - "reference": "ea693fa060702164985511acc3ceb5389c9ac761" + "reference": "f8c8349a4b12a26edfa8b21d07d3dbeb6dcedcfa" }, "dist": { "type": "zip", - "url": "https://github.com/gitapi/repos/Roave/SecurityAdvisories/zipball/ea693fa060702164985511acc3ceb5389c9ac761", - "reference": "ea693fa060702164985511acc3ceb5389c9ac761", + "url": "https://github.com/gitapi/repos/Roave/SecurityAdvisories/zipball/f8c8349a4b12a26edfa8b21d07d3dbeb6dcedcfa", + "reference": "f8c8349a4b12a26edfa8b21d07d3dbeb6dcedcfa", "shasum": "" }, "conflict": { @@ -458,7 +460,7 @@ "contao/core": ">=2,<3.5.39", "contao/core-bundle": ">=4,<4.4.39|>=4.5,<4.7.5", "contao/listing-bundle": ">=4,<4.4.8", - "contao/newsletter-bundle": ">=4,<4.1", + "datadog/dd-trace": ">=0.30,<0.30.2", "david-garcia/phpwhois": "<=4.3.1", "doctrine/annotations": ">=1,<1.2.7", "doctrine/cache": ">=1,<1.3.2|>=1.4,<1.4.2", @@ -501,9 +503,9 @@ "laravel/framework": ">=4,<4.0.99|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.42|>=5.6,<5.6.30", "laravel/socialite": ">=1,<1.0.99|>=2,<2.0.10", "league/commonmark": "<0.18.3", - "magento/magento1ce": "<1.9.4.1", - "magento/magento1ee": ">=1.9,<1.14.4.1", - "magento/product-community-edition": ">=2,<2.2.8|>=2.3,<2.3.1", + "magento/magento1ce": "<1.9.4.3", + "magento/magento1ee": ">=1,<1.14.4.3", + "magento/product-community-edition": ">=2,<2.2.10|>=2.3,<2.3.3", "monolog/monolog": ">=1.8,<1.12", "namshi/jose": "<2.2", "onelogin/php-saml": "<2.10.4", @@ -546,6 +548,7 @@ "spoonity/tcpdf": "<6.2.22", "squizlabs/php_codesniffer": ">=1,<2.8.1|>=3,<3.0.1", "stormpath/sdk": ">=0,<9.9.99", + "studio-42/elfinder": "<2.1.48", "swiftmailer/swiftmailer": ">=4,<5.4.5", "sylius/admin-bundle": ">=1,<1.0.17|>=1.1,<1.1.9|>=1.2,<1.2.2", "sylius/grid": ">=1,<1.1.19|>=1.2,<1.2.18|>=1.3,<1.3.13|>=1.4,<1.4.5|>=1.5,<1.5.1", @@ -632,12 +635,12 @@ "authors": [ { "name": "Marco Pivetta", - "role": "maintainer", - "email": "ocramius@gmail.com" + "email": "ocramius@gmail.com", + "role": "maintainer" } ], "description": "Prevents installation of composer packages with known security vulnerabilities: no API, simply require it", - "time": "2019-07-18T15:17:58+00:00" + "time": "2019-10-29T22:11:03+00:00" } ], "packages-dev": [], From 945c3ea40852a708b9cefafb35269a28a9a78c20 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Mon, 18 Nov 2019 11:49:43 +0100 Subject: [PATCH 091/280] fix #42 --- info.xml | 918 ++++++++++++------------ version/100/paymentmethod/JTLMollie.php | 1 - version/105/adminmenu/tpl/orders.tpl | 3 +- version/105/class/Mollie.php | 7 + 4 files changed, 472 insertions(+), 457 deletions(-) diff --git a/info.xml b/info.xml index 3ff0d1e..c9dcdf6 100644 --- a/info.xml +++ b/info.xml @@ -1,459 +1,467 @@ - - mollie - Zahlungsartplugin für mollie.com - WebStollen - http://www.webstollen.de/ - 102 - ws_mollie - 405 - - - 100.sql - 2019-02-11 - - - 2019-02-26 - - - 2019-04-23 - - - 2019-05-22 - - - 2019-07-12 - - - 2019-07-12 - - - 131_globalinclude.php - 144_notify.php - 181_sync.php - 140_smarty.php - - - - Bestellungen - orders.php - - - Zahlungsarten - paymentmethods.php - - - Info - info.php - - - Einstellungen - - API Key: - Füge hier deinen mollie API Key ein - api_key - - - Zahlungsart Daten syncronisiernen - Lädt Name / Bild für die jeweilige Sprache automatisch von mollie, und speichert diese in der Datenbank - paymentmethod_sync - - - - - - - - - Checkout Styles laden - Lädt Stylesheets für das Evo Template, um den Checkout zu verschönern. - load_styles - - - - - - + + + mollie + Zahlungsartplugin für mollie.com + WebStollen + http://www.webstollen.de/ + 102 + ws_mollie + 405 + + + 100.sql + 2019-02-11 + + + 2019-02-26 + + + 2019-04-23 + + + 2019-05-22 + + + 2019-07-12 + + + 2019-07-12 + + + 131_globalinclude.php + 144_notify.php + 181_sync.php + 140_smarty.php + + + + Bestellungen + orders.php + + + Zahlungsarten + paymentmethods.php + + + Info + info.php + + + Einstellungen + + API Key: + Füge hier deinen mollie API Key ein + api_key + + + Profile ID: + Füge hier deinen mollie Profil ID ein. Wird benötigt für mollie Components + profileId + + + Zahlungsart Daten syncronisiernen + Lädt Name / Bild für die jeweilige Sprache automatisch von mollie, und speichert diese + in der Datenbank + + paymentmethod_sync + + + + + + + + + Checkout Styles laden + Lädt Stylesheets für das Evo Template, um den Checkout zu verschönern. + load_styles + + + + + + - - Versand/Storno via: - Wie soll mollie der Versand oder Stornierung mitgeteilt werden? - notifyMollie - - - - - - + + TransaktionsID des Zahlungseingangs: + Welche ID soll an die WAWI übetragen werden? + wawiPaymentID + + + + + + - - Workflow-Secret: - Schlüssel, um die WAWI Workflow-Requests zu authentifizieren. - workflowSecret - + + Workflow-Secret: + Schlüssel, um die WAWI Workflow-Requests zu authentifizieren. + workflowSecret + - - - - - mollie - - 1 - 0 - mollie.com - OTHER - 0 - 0 - 1 - 0 - JTLMollie.php - JTLMollie - tpl/bestellabschluss.tpl - - mollie - mollie - Bezahlen Sie bequem mit verschiedenen Zahlungsmethoden. - - - - mollie Kreditkarte - - 2 - 0 - mollie.com - CREDIT_CARD - 1 - 0 - 1 - 0 - JTLMollieCreditCard.php - JTLMollieCreditCard - tpl/bestellabschluss.tpl - - Kreditkarte - mollie - Bezahlen Sie bequem mit Kreditkarte. - - - - mollie Apple Pay - - 3 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMollieApplePay.php - JTLMollieApplePay - tpl/bestellabschluss.tpl - - Apple Pay - mollie - Bezahlen Sie bequem mit Apple Pay. - - - - mollie Bancontact - - 4 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMollieBancontact.php - JTLMollieBancontact - tpl/bestellabschluss.tpl - - Bancontact - mollie - Bezahlen Sie bequem mit Bancontact. - - - - mollie Banktransfer - - 5 - 0 - mollie.com - OTHER - 0 - 0 - 1 - 0 - JTLMollieBanktransfer.php - JTLMollieBanktransfer - tpl/bestellabschluss.tpl - - SEPA Überweisung - mollie - Bezahlen Sie bequem mit SEPA Überweisung. - - - - mollie Belfius - - 6 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMollieBelfius.php - JTLMollieBelfius - tpl/bestellabschluss.tpl - - Belfius - mollie - Bezahlen Sie bequem mit Belfius. - - - - mollie DirectDebit - - 7 - 0 - mollie.com - DIRECT_DEBIT - 1 - 0 - 1 - 0 - JTLMollieDirectDebit.php - JTLMollieDirectDebit - tpl/bestellabschluss.tpl - - SEPA Lastschrift - mollie - Bezahlen Sie bequem mit SEPA Lastschrift. - - - - mollie EPS - - 2 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMollieEPS.php - JTLMollieEPS - tpl/bestellabschluss.tpl - - EPS - mollie - Bezahlen Sie bequem mit EPS. - - - - mollie Giftcard - - 8 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMollieGiftcard.php - JTLMollieGiftcard - tpl/bestellabschluss.tpl - - Gift cards - mollie - Bezahlen Sie bequem mit Gift cards. - - - - mollie Giropay - - 9 - 0 - mollie.com - GIROPAY - 1 - 0 - 1 - 0 - JTLMollieGiropay.php - JTLMollieGiropay - tpl/bestellabschluss.tpl - - Giropay - mollie - Bezahlen Sie bequem mit Giropay. - - - - mollie iDEAL - - 10 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMollieIDEAL.php - JTLMollieIDEAL - tpl/bestellabschluss.tpl - - Giropay - mollie - Bezahlen Sie bequem mit iDEAL. - - - - mollie ING HomePay - - 11 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMollieINGHomePay.php - JTLMollieINGHomePay - tpl/bestellabschluss.tpl - - ING HomePay - mollie - Bezahlen Sie bequem mit ING HomePay. - - - - mollie KBC - - 12 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMollieKBC.php - JTLMollieKBC - tpl/bestellabschluss.tpl - - KBC - mollie - Bezahlen Sie bequem mit KBC. - - - - mollie PayPal - - 13 - 0 - mollie.com - PAYPAL - 1 - 0 - 1 - 0 - JTLMolliePayPal.php - JTLMolliePayPal - tpl/bestellabschluss.tpl - - PayPal - mollie - Bezahlen Sie bequem mit PayPal. - - - - mollie paysafecard - - 14 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMolliePaysafecard.php - JTLMolliePaysafecard - tpl/bestellabschluss.tpl - - paysafecard - mollie - Bezahlen Sie bequem mit paysafecard. - - - - mollie SOFORT - - 15 - 0 - mollie.com - DIRECT_E_BANKING - 1 - 0 - 1 - 0 - JTLMollieSofort.php - JTLMollieSofort - tpl/bestellabschluss.tpl - - SOFORT - mollie - Bezahlen Sie bequem mit SOFORT. - - - - mollie Klarna Pay Later - - 16 - 0 - mollie.com - INVOICE - 1 - 0 - 1 - 0 - JTLMollieKlarnaPayLater.php - JTLMollieKlarnaPayLater - tpl/bestellabschluss.tpl - - Klarna Pay Later - mollie - Bezahlen Sie bequem mit Klarna Pay Later. - - - - mollie Klarna Slice It - - 17 - 0 - mollie.com - FINANCING - 1 - 0 - 1 - 0 - JTLMollieKlarnaSliceIt.php - JTLMollieKlarnaSliceIt - tpl/bestellabschluss.tpl - - Klarna Slice It - mollie - Bezahlen Sie bequem mit Klarna Slice It. - - - - + + + + + mollie + + 1 + 0 + mollie.com + OTHER + 0 + 0 + 1 + 0 + JTLMollie.php + JTLMollie + tpl/bestellabschluss.tpl + + mollie + mollie + Bezahlen Sie bequem mit verschiedenen Zahlungsmethoden. + + + + mollie Kreditkarte + + 2 + 0 + mollie.com + CREDIT_CARD + 1 + 0 + 1 + 0 + JTLMollieCreditCard.php + JTLMollieCreditCard + tpl/bestellabschluss.tpl + + Kreditkarte + mollie + Bezahlen Sie bequem mit Kreditkarte. + + + + mollie Apple Pay + + 3 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMollieApplePay.php + JTLMollieApplePay + tpl/bestellabschluss.tpl + + Apple Pay + mollie + Bezahlen Sie bequem mit Apple Pay. + + + + mollie Bancontact + + 4 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMollieBancontact.php + JTLMollieBancontact + tpl/bestellabschluss.tpl + + Bancontact + mollie + Bezahlen Sie bequem mit Bancontact. + + + + mollie Banktransfer + + 5 + 0 + mollie.com + OTHER + 0 + 0 + 1 + 0 + JTLMollieBanktransfer.php + JTLMollieBanktransfer + tpl/bestellabschluss.tpl + + SEPA Überweisung + mollie + Bezahlen Sie bequem mit SEPA Überweisung. + + + + mollie Belfius + + 6 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMollieBelfius.php + JTLMollieBelfius + tpl/bestellabschluss.tpl + + Belfius + mollie + Bezahlen Sie bequem mit Belfius. + + + + mollie DirectDebit + + 7 + 0 + mollie.com + DIRECT_DEBIT + 1 + 0 + 1 + 0 + JTLMollieDirectDebit.php + JTLMollieDirectDebit + tpl/bestellabschluss.tpl + + SEPA Lastschrift + mollie + Bezahlen Sie bequem mit SEPA Lastschrift. + + + + mollie EPS + + 2 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMollieEPS.php + JTLMollieEPS + tpl/bestellabschluss.tpl + + EPS + mollie + Bezahlen Sie bequem mit EPS. + + + + mollie Giftcard + + 8 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMollieGiftcard.php + JTLMollieGiftcard + tpl/bestellabschluss.tpl + + Gift cards + mollie + Bezahlen Sie bequem mit Gift cards. + + + + mollie Giropay + + 9 + 0 + mollie.com + GIROPAY + 1 + 0 + 1 + 0 + JTLMollieGiropay.php + JTLMollieGiropay + tpl/bestellabschluss.tpl + + Giropay + mollie + Bezahlen Sie bequem mit Giropay. + + + + mollie iDEAL + + 10 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMollieIDEAL.php + JTLMollieIDEAL + tpl/bestellabschluss.tpl + + Giropay + mollie + Bezahlen Sie bequem mit iDEAL. + + + + mollie ING HomePay + + 11 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMollieINGHomePay.php + JTLMollieINGHomePay + tpl/bestellabschluss.tpl + + ING HomePay + mollie + Bezahlen Sie bequem mit ING HomePay. + + + + mollie KBC + + 12 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMollieKBC.php + JTLMollieKBC + tpl/bestellabschluss.tpl + + KBC + mollie + Bezahlen Sie bequem mit KBC. + + + + mollie PayPal + + 13 + 0 + mollie.com + PAYPAL + 1 + 0 + 1 + 0 + JTLMolliePayPal.php + JTLMolliePayPal + tpl/bestellabschluss.tpl + + PayPal + mollie + Bezahlen Sie bequem mit PayPal. + + + + mollie paysafecard + + 14 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMolliePaysafecard.php + JTLMolliePaysafecard + tpl/bestellabschluss.tpl + + paysafecard + mollie + Bezahlen Sie bequem mit paysafecard. + + + + mollie SOFORT + + 15 + 0 + mollie.com + DIRECT_E_BANKING + 1 + 0 + 1 + 0 + JTLMollieSofort.php + JTLMollieSofort + tpl/bestellabschluss.tpl + + SOFORT + mollie + Bezahlen Sie bequem mit SOFORT. + + + + mollie Klarna Pay Later + + 16 + 0 + mollie.com + INVOICE + 1 + 0 + 1 + 0 + JTLMollieKlarnaPayLater.php + JTLMollieKlarnaPayLater + tpl/bestellabschluss.tpl + + Klarna Pay Later + mollie + Bezahlen Sie bequem mit Klarna Pay Later. + + + + mollie Klarna Slice It + + 17 + 0 + mollie.com + FINANCING + 1 + 0 + 1 + 0 + JTLMollieKlarnaSliceIt.php + JTLMollieKlarnaSliceIt + tpl/bestellabschluss.tpl + + Klarna Slice It + mollie + Bezahlen Sie bequem mit Klarna Slice It. + + + + \ No newline at end of file diff --git a/version/100/paymentmethod/JTLMollie.php b/version/100/paymentmethod/JTLMollie.php index 89509b6..dd85c3e 100644 --- a/version/100/paymentmethod/JTLMollie.php +++ b/version/100/paymentmethod/JTLMollie.php @@ -153,7 +153,6 @@ public function preparePaymentProcess($order) public function doLog($msg, $data = null, $level = LOGLEVEL_NOTICE) { ZahlungsLog::add($this->moduleID, $msg, $data, $level); - return $this; } diff --git a/version/105/adminmenu/tpl/orders.tpl b/version/105/adminmenu/tpl/orders.tpl index 45ea2ee..df024b4 100644 --- a/version/105/adminmenu/tpl/orders.tpl +++ b/version/105/adminmenu/tpl/orders.tpl @@ -109,4 +109,5 @@ $('.datatable').DataTable(); }); -{/if} \ No newline at end of file +{/if} + diff --git a/version/105/class/Mollie.php b/version/105/class/Mollie.php index 1b28824..7bf8244 100644 --- a/version/105/class/Mollie.php +++ b/version/105/class/Mollie.php @@ -228,10 +228,17 @@ public static function handleOrder(Order $order, $kBestellung) 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; + } + $oIncomingPayment->fBetrag = $order->amount->value; $oIncomingPayment->cISO = $order->amount->currency; $oIncomingPayment->cHinweis = $cHinweis; From b40a63081fc01e711b539c00c0e35919162c33a0 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Mon, 18 Nov 2019 15:29:42 +0100 Subject: [PATCH 092/280] mollie components #53, #46, fix #50 --- README.md => _README.md | 0 info.xml | 80 +++++++++++++++++++ version/105/frontend/131_globalinclude.php | 9 ++- version/105/frontend/140_smarty.php | 7 ++ version/105/paymentmethod/JTLMollie.php | 6 ++ .../105/paymentmethod/JTLMollieCreditCard.php | 28 +++++++ .../paymentmethod/tpl/mollieComponents.tpl | 79 ++++++++++++++++++ workflow.php | 6 +- 8 files changed, 208 insertions(+), 7 deletions(-) rename README.md => _README.md (100%) create mode 100644 version/105/paymentmethod/tpl/mollieComponents.tpl diff --git a/README.md b/_README.md similarity index 100% rename from README.md rename to _README.md diff --git a/info.xml b/info.xml index c9dcdf6..7a6e36a 100644 --- a/info.xml +++ b/info.xml @@ -33,6 +33,56 @@ 181_sync.php 140_smarty.php + + + error_canceled + + Die Zahlung wurde von Ihnen abgebrochen. Wählen Sie ggf. eine andere Zahlart aus. + You canceled the payment. Please select a different payment method if necessary. + + + error_expired + + Ihre Zahlungssession ist abgelaufen, bitte versuchen Sie es erneut. + Your payment session has expired, please try again. + + + error_open + + Bei der Zahlung ist ein Fehler aufgetreten. Bitte versuchen Sie es erneut, oder wählen Sie eine andere Zahlungsart. + The payment process failed. Please try again or choose a different payment method. + + + error_failed + + Bei der Zahlung ist ein Fehler aufgetreten. Bitte versuchen Sie es erneut, oder wählen Sie eine andere Zahlungsart. + The payment process failed. Please try again or choose a different payment method. + + + lbl_cardHolder + + Karteninhaber: + Card holder: + + + lbl_cardNumber + + Kartennummer: + Card number: + + + lbl_expiryDate + + Ablaufdatum: + Expiry date: + + + lbl_varificationCode + + CVC: + CVC: + + Bestellungen @@ -58,6 +108,15 @@ Füge hier deinen mollie Profil ID ein. Wird benötigt für mollie Components profileId + + mollie Components verwenden: + Bei Kreditkarte mollie Components verwenden + useMollieComponents + + + + + Zahlungsart Daten syncronisiernen Lädt Name / Bild für die jeweilige Sprache automatisch von mollie, und speichert diese @@ -142,6 +201,27 @@ Bezahlen Sie bequem mit Kreditkarte. + + mollie Kreditkarte (MC) + + 3 + tpl/mollieComponents.tpl + 0 + mollie.com + CREDIT_CARD + 1 + 0 + 1 + 0 + JTLMollieCreditCard.php + JTLMollieCreditCard + tpl/bestellabschluss.tpl + + Kreditkarte + mollie + Bezahlen Sie bequem mit Kreditkarte. + + mollie Apple Pay diff --git a/version/105/frontend/131_globalinclude.php b/version/105/frontend/131_globalinclude.php index 3e30782..1320363 100644 --- a/version/105/frontend/131_globalinclude.php +++ b/version/105/frontend/131_globalinclude.php @@ -46,7 +46,7 @@ // finalize only, if order is not canceld/expired if ($order && !$order->isCanceled() && !$order->isExpired()) { // finalize only if payment is not expired/canceled,failed or open - if ($_payment && !in_array($_payment->status, [PaymentStatus::STATUS_EXPIRED, PaymentStatus::STATUS_CANCELED, PaymentStatus::STATUS_OPEN, PaymentStatus::STATUS_FAILED, PaymentStatus::STATUS_CANCELED])) { + if ($_payment && !in_array($_payment->status, [PaymentStatus::STATUS_EXPIRED, PaymentStatus::STATUS_CANCELED, PaymentStatus::STATUS_OPEN, PaymentStatus::STATUS_FAILED])) { Mollie::JTLMollie()->doLog('Bestellung open => finalize', $logData); $session = Session::getInstance(); /** @noinspection PhpIncludeInspection */ @@ -58,15 +58,16 @@ Mollie::JTLMollie()->doLog('Bestellung finalized => redirect
' . print_r($order, 1) . '
', $logData, LOGLEVEL_DEBUG); Mollie::handleOrder($order, $oBestellung->kBestellung); Mollie::getOrderCompletedRedirect($oBestellung->kBestellung, true); - JTLMollie::API()->performHttpCall('PATCH', sprintf('payments/%s', $_payment->id), json_encode(['description' => $oBestellung->cBestellNr])); - - } else { Mollie::JTLMollie()->doLog('Invalid Payment
' . print_r($payment, 1) . '
', $logData, LOGLEVEL_ERROR); + header('Location: ' . Shop::getURL() . '/bestellvorgang.php?editZahlungsart=1&mollieStatus=' . $_payment->status); + exit(); } } else { Mollie::JTLMollie()->doLog('Invalid Order
' . print_r($order, 1) . '
', $logData, LOGLEVEL_ERROR); + header('Location: ' . Shop::getURL() . '/bestellvorgang.php?editZahlungsart=1&mollieStatus=' . $order->status); + exit(); } } } diff --git a/version/105/frontend/140_smarty.php b/version/105/frontend/140_smarty.php index 56a6400..53360d6 100644 --- a/version/105/frontend/140_smarty.php +++ b/version/105/frontend/140_smarty.php @@ -6,6 +6,13 @@ require_once __DIR__ . '/../class/Helper.php'; Helper::init(); + + if (array_key_exists('mollieStatus', $_REQUEST)) { + $status = $_REQUEST['mollieStatus']; + $text = Helper::oPlugin()->oPluginSprachvariableAssoc_arr['error_' . $status]; + pq('#fieldset-payment')->prepend('
' . $text . '
'); + } + switch (Helper::getSetting('load_styles')) { case 'Y': $selector = '#fieldset-payment [id*="_mollie"]'; diff --git a/version/105/paymentmethod/JTLMollie.php b/version/105/paymentmethod/JTLMollie.php index 0ec4743..0066067 100644 --- a/version/105/paymentmethod/JTLMollie.php +++ b/version/105/paymentmethod/JTLMollie.php @@ -213,6 +213,12 @@ protected function getOrderData(Bestellung $order, $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 ($organizationName = utf8_encode(trim($order->oRechnungsadresse->cFirma))) { $data['billingAddress']->organizationName = $organizationName; } diff --git a/version/105/paymentmethod/JTLMollieCreditCard.php b/version/105/paymentmethod/JTLMollieCreditCard.php index 4364105..46066a2 100644 --- a/version/105/paymentmethod/JTLMollieCreditCard.php +++ b/version/105/paymentmethod/JTLMollieCreditCard.php @@ -1,8 +1,36 @@ assign('profileId', trim(Helper::getSetting('profileId'))) + ->assign('locale', self::getLocale($_SESSION['cISOSprache'], $_SESSION['Kunde']->cLand)) + ->assign('testmode', strpos(Helper::getSetting('api_key'), 'test_') === 0) + ->assign('mollieLang', Helper::oPlugin()->oPluginSprachvariableAssoc_arr); + + + return false; + } + + } diff --git a/version/105/paymentmethod/tpl/mollieComponents.tpl b/version/105/paymentmethod/tpl/mollieComponents.tpl new file mode 100644 index 0000000..cea628f --- /dev/null +++ b/version/105/paymentmethod/tpl/mollieComponents.tpl @@ -0,0 +1,79 @@ +

Zahlungsinformationen

+
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/workflow.php b/workflow.php index f088bbd..192c8d4 100644 --- a/workflow.php +++ b/workflow.php @@ -17,9 +17,9 @@ } //if (Helper::getSetting('notifyMollie') === 'W') { - if (array_key_exists('secret', $_REQUEST) && $_REQUEST['secret'] === Helper::getSetting('workflowSecret')) { + if (array_key_exists('secret', $_REQUEST) && trim($_REQUEST['secret']) !== '' && $_REQUEST['secret'] === Helper::getSetting('workflowSecret')) { - file_put_contents(__DIR__ . '/workflow.log', print_r([$_REQUEST, $_SERVER], 1), FILE_APPEND); + //file_put_contents(__DIR__ . '/workflow.log', print_r([$_REQUEST, $_SERVER], 1), FILE_APPEND); //require_once $oPlugin->cAdminmenuPfad . '/../paymentmethod/JTLMollie.php'; $kBestellung = array_key_exists('kBestellung', $_REQUEST) ? (int)$_REQUEST['kBestellung'] : null; if ($kBestellung && array_key_exists('action', $_REQUEST)) { @@ -99,6 +99,6 @@ //} } catch (Exception $e) { http_response_code(500); - die($e->getMessage()); Jtllog::writeLog("mollie//WORKFLOW//Execption: " . $e->getMessage()); + die($e->getMessage()); } \ No newline at end of file From 9f4995df097ed401e0d1809fcb423c931c265454 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Tue, 19 Nov 2019 10:47:22 +0100 Subject: [PATCH 093/280] #46 --- version/105/paymentmethod/JTLMollie.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/version/105/paymentmethod/JTLMollie.php b/version/105/paymentmethod/JTLMollie.php index 0066067..aa2d456 100644 --- a/version/105/paymentmethod/JTLMollie.php +++ b/version/105/paymentmethod/JTLMollie.php @@ -130,7 +130,7 @@ public function preparePaymentProcess($order) } } } catch (Exception $e) { - $this->doLog("Get Payment Error: " . $e->getMessage() . ". Create new ORDER...", $logData); + $this->doLog("Get Payment Error: " . $e->getMessage() . ". Create new ORDER...", $logData, LOGLEVEL_ERROR); } try { @@ -154,8 +154,9 @@ public function preparePaymentProcess($order) echo "redirect to payment ..."; exit(); } catch (ApiException $e) { - Shop::Smarty()->assign('oMollieException', $e); - $this->doLog("Create Payment Error: " . $e->getMessage() . '
' . print_r($e->getTrace(), 1) . '
', $logData); + $this->doLog("Create Payment Error: " . $e->getMessage() . '
' . print_r($orderData, 1) . '
', $logData, LOGLEVEL_ERROR); + header('Location: ' . Shop::getURL() . '/bestellvorgang.php?editZahlungsart=1&mollieStatus=failed'); + exit(); } } From e28a13892f5e5245f5476c688f16f9b792e7a50a Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Tue, 19 Nov 2019 12:03:21 +0100 Subject: [PATCH 094/280] fix #52 --- version/105/paymentmethod/JTLMollie.php | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/version/105/paymentmethod/JTLMollie.php b/version/105/paymentmethod/JTLMollie.php index aa2d456..bfe9423 100644 --- a/version/105/paymentmethod/JTLMollie.php +++ b/version/105/paymentmethod/JTLMollie.php @@ -201,7 +201,9 @@ protected function getOrderData(Bestellung $order, $hash) 'locale' => $locale ?: 'de_DE', 'amount' => (object)[ 'currency' => $order->Waehrung->cISO, - 'value' => number_format($order->fGesamtsummeKundenwaehrung, 2, '.', ''), + //'value' => number_format($order->fGesamtsummeKundenwaehrung, 2, '.', ''), + // runden auf 5 Rappen berücksichtigt + 'value' => number_format($this->optionaleRundung($order->fWarensummeKundenwaehrung), 2, '.', ''), ], 'orderNumber' => utf8_encode($order->cBestellNr), 'lines' => [], @@ -364,10 +366,28 @@ protected function getOrderData(Bestellung $order, $hash) $data['lines'][] = $line; } } - return $data; } + public function optionaleRundung($gesamtsumme) + { + $conf = Shop::getSettings([CONF_KAUFABWICKLUNG]); + if (isset($conf['kaufabwicklung']['bestellabschluss_runden5']) && $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 getLocale($cISOSprache, $country = null) { switch ($cISOSprache) { From 0a659fd3497b8184cab2f9f09bec504f5b6a9a90 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Tue, 19 Nov 2019 14:50:11 +0100 Subject: [PATCH 095/280] trust badge, fix #52 --- info.xml | 10 ++++++---- version/105/class/Mollie.php | 2 +- version/105/frontend/img/trust_eng.png | Bin 0 -> 15299 bytes version/105/frontend/img/trust_fre.png | Bin 0 -> 17319 bytes version/105/frontend/img/trust_ger.png | Bin 0 -> 15352 bytes version/105/paymentmethod/JTLMollie.php | 8 ++++++-- .../105/paymentmethod/JTLMollieCreditCard.php | 4 ++-- .../105/paymentmethod/tpl/mollieComponents.tpl | 16 +++++++++++----- 8 files changed, 26 insertions(+), 14 deletions(-) create mode 100644 version/105/frontend/img/trust_eng.png create mode 100644 version/105/frontend/img/trust_fre.png create mode 100644 version/105/frontend/img/trust_ger.png diff --git a/info.xml b/info.xml index 7a6e36a..3bba6df 100644 --- a/info.xml +++ b/info.xml @@ -108,15 +108,17 @@ Füge hier deinen mollie Profil ID ein. Wird benötigt für mollie Components profileId
- - mollie Components verwenden: - Bei Kreditkarte mollie Components verwenden - useMollieComponents + + + Trust-Grafik bei mollie Components anzeigen: + Bindet eine Trust-Grafik unterhalb des Kreditkartenformulars ein. + loadTrust + Zahlungsart Daten syncronisiernen Lädt Name / Bild für die jeweilige Sprache automatisch von mollie, und speichert diese diff --git a/version/105/class/Mollie.php b/version/105/class/Mollie.php index 7bf8244..abbc6d6 100644 --- a/version/105/class/Mollie.php +++ b/version/105/class/Mollie.php @@ -218,7 +218,7 @@ public static function handleOrder(Order $order, $kBestellung) $order->orderNumber = $oBestellung->cBestellNr; Payment::updateFromPayment($order, $kBestellung); - $oIncomingPayment = Shop::DB()->executeQueryPrepared("SELECT * FROM tzahlungseingang WHERE cHinweis LIKE :cHinweis AND kBestellung = :kBestellung", [':cHinweis' => '%' . $order->id . '%', ':kBestellung' => $oBestellung->kBestellung], 1); + $oIncomingPayment = Shop::DB()->executeQueryPrepared("SELECT * FROM tzahlungseingang WHERE kBestellung = :kBestellung", [':kBestellung' => $oBestellung->kBestellung], 1); if (!$oIncomingPayment) { $oIncomingPayment = new stdClass(); } diff --git a/version/105/frontend/img/trust_eng.png b/version/105/frontend/img/trust_eng.png new file mode 100644 index 0000000000000000000000000000000000000000..3d0177359de7fa93833765ac05d8b218fa1550f2 GIT binary patch literal 15299 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 Rmns)TMnX}%M${5 literal 0 HcmV?d00001 diff --git a/version/105/frontend/img/trust_fre.png b/version/105/frontend/img/trust_fre.png new file mode 100644 index 0000000000000000000000000000000000000000..ed1a2f6f03c56f6748aac8af0352de7fc0afd3a4 GIT binary patch literal 17319 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 Mu#8ZJpsxS_1AJc%;s5{u literal 0 HcmV?d00001 diff --git a/version/105/frontend/img/trust_ger.png b/version/105/frontend/img/trust_ger.png new file mode 100644 index 0000000000000000000000000000000000000000..e42821b06709e8f4371c66cfb5759d00df0e1afd GIT binary patch literal 15352 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 + + $_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->fWarensummeKundenwaehrung), 2, '.', ''), + 'value' => number_format($this->optionaleRundung($order->fGesamtsumme * $_currencyFactor), 2, '.', ''), ], 'orderNumber' => utf8_encode($order->cBestellNr), 'lines' => [], @@ -249,10 +252,11 @@ protected function getOrderData(Bestellung $order, $hash) $data['shippingAddress']->country = $order->Lieferadresse->cLand; } + /** @var WarenkorbPos $oPosition */ foreach ($order->Positionen as $oPosition) { - $_currencyFactor = (float)$order->Waehrung->fFaktor; // EUR => 1 + // EUR => 1 $_netto = round($oPosition->fPreis, 2); // 13.45378 => 13.45 $_vatRate = (float)$oPosition->fMwSt / 100; // 0.19 $_amount = (float)$oPosition->nAnzahl; // 3 diff --git a/version/105/paymentmethod/JTLMollieCreditCard.php b/version/105/paymentmethod/JTLMollieCreditCard.php index 46066a2..18d00d4 100644 --- a/version/105/paymentmethod/JTLMollieCreditCard.php +++ b/version/105/paymentmethod/JTLMollieCreditCard.php @@ -26,8 +26,8 @@ public function handleAdditional($aPost_arr) Shop::Smarty()->assign('profileId', trim(Helper::getSetting('profileId'))) ->assign('locale', self::getLocale($_SESSION['cISOSprache'], $_SESSION['Kunde']->cLand)) ->assign('testmode', strpos(Helper::getSetting('api_key'), 'test_') === 0) - ->assign('mollieLang', Helper::oPlugin()->oPluginSprachvariableAssoc_arr); - + ->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/105/paymentmethod/tpl/mollieComponents.tpl b/version/105/paymentmethod/tpl/mollieComponents.tpl index cea628f..07ea927 100644 --- a/version/105/paymentmethod/tpl/mollieComponents.tpl +++ b/version/105/paymentmethod/tpl/mollieComponents.tpl @@ -25,6 +25,12 @@
+ {if $trustBadge} +
+ PCI-DSS SAQ-A compliant +
+ {/if} @@ -32,8 +38,6 @@ "; + echo "
" . + "
" . + " " . + " Lizenz Informationen" . + ' ' . + '
' . + "
" . + " " . + " Update Informationen" . + ' ' . + '
' . + "
" . + " " . + " Plugin informationen" . + ' ' . + '
' . + '
'; + + 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'); +} catch (Exception $e) { + echo "
Fehler: {$e->getMessage()}
"; + Helper::logExc($e); +} \ No newline at end of file diff --git a/version/106/adminmenu/orders.php b/version/106/adminmenu/orders.php new file mode 100644 index 0000000..99603ed --- /dev/null +++ b/version/106/adminmenu/orders.php @@ -0,0 +1,154 @@ + 'danger', 'text' => 'Keine ID angeben!']; + break; + } + $payment = Payment::getPaymentMollie($_REQUEST['id']); + if (!$payment) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; + break; + } + + $order = JTLMollie::API()->orders->get($_REQUEST['id']); + if ($order->status == OrderStatus::STATUS_CANCELED) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung bereits storniert']; + 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; + break; + + case 'cancel': + if (!array_key_exists('id', $_REQUEST)) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; + break; + } + $payment = Payment::getPaymentMollie($_REQUEST['id']); + if (!$payment) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; + break; + } + $order = JTLMollie::API()->orders->get($_REQUEST['id']); + if ($order->status == OrderStatus::STATUS_CANCELED) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung bereits storniert']; + 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; + break; + + case 'capture': + if (!array_key_exists('id', $_REQUEST)) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; + break; + } + $payment = Payment::getPaymentMollie($_REQUEST['id']); + if (!$payment) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; + break; + } + $order = JTLMollie::API()->orders->get($_REQUEST['id']); + if ($order->status !== OrderStatus::STATUS_AUTHORIZED && $order->status !== OrderStatus::STATUS_SHIPPING) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Nur autorisierte Zahlungen können erfasst werden!']; + break; + } + + $oBestellung = new Bestellung($payment->kBestellung, true); + if (!$oBestellung->kBestellung) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung konnte nicht geladen werden!']; + break; + } + + $logData = '#' . $payment->kBestellung . '$' . $payment->kID . "§" . $oBestellung->cBestellNr; + + $options = ['lines' => []]; + if ($oBestellung->cTracking) { + $tracking = new stdClass(); + $tracking->carrier = $oBestellung->cVersandartName; + $tracking->url = $oBestellung->cTrackingURL; + $tracking->code = $oBestellung->cTracking; + $options['tracking'] = $tracking; + } + + // CAPTURE ALL + $shipment = JTLMollie::API()->shipments->createFor($order, $options); + $ordersMsgs[] = (object)['type' => 'success', 'text' => 'Zahlung wurde erfolgreich erfasst!']; + Mollie::JTLMollie()->doLog('Shipment created
' . print_r(['options' => $options, 'shipment' => $shipment], 1) . '
', $logData); + goto order; + + case 'order': + order: + if (!array_key_exists('id', $_REQUEST)) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; + 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", [ + ':kBestellung' => '%#' . ($payment->kBestellung ?: '##') . '%', + ':cBestellNr' => '%§' . ($payment->cOrderNumber ?: '§§') . '%', + ':MollieID' => '%$' . ($payment->kID ?: '$$') . '%', + ], 2); + + Shop::Smarty()->assign('payment', $payment) + ->assign('oBestellung', $oBestellung) + ->assign('order', $order) + ->assign('logs', $logs) + ->assign('ordersMsgs', $ordersMsgs); + Shop::Smarty()->display($oPlugin->cAdminmenuPfad . '/tpl/order.tpl'); + return; + } + } + + + $payments = Shop::DB()->executeQueryPrepared("SELECT * FROM xplugin_ws_mollie_payments WHERE kBestellung IS NOT NULL AND cStatus != 'created'", [], 2); + foreach ($payments as $i => $payment) { + $payments[$i]->oBestellung = new Bestellung($payment->kBestellung, false); + } + + Shop::Smarty()->assign('payments', $payments) + ->assign('ordersMsgs', $ordersMsgs) + ->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/106/adminmenu/paymentmethods.php b/version/106/adminmenu/paymentmethods.php new file mode 100644 index 0000000..1782978 --- /dev/null +++ b/version/106/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/106/adminmenu/tpl/info.tpl b/version/106/adminmenu/tpl/info.tpl new file mode 100644 index 0000000..da2a55a --- /dev/null +++ b/version/106/adminmenu/tpl/info.tpl @@ -0,0 +1,93 @@ +
+
+
+ + + +
+
+ + + +
+ + {if isset($update)} +
+ +
+

Update auf Version {$update->version} verfügbar!

+
+
+
+
Version:
+
{$update->version}
+
+
+
Erschienen:
+
{$update->create_date}
+
+
+
Changelog:
+
+ +
+
+ +
+
+ +
+
+
+ {else} +
+ + + +
+ {/if} + +
+
+
+ + + +
+
+ + + +
+ +
+
+
+ + + +
+
+ + + +
+
+ + + +
+
+
diff --git a/version/106/adminmenu/tpl/mollie-account-erstellen.png b/version/106/adminmenu/tpl/mollie-account-erstellen.png new file mode 100644 index 0000000000000000000000000000000000000000..fc1819255ef725fa214cf2bf028cf3428794ecee GIT binary patch literal 38998 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 +

+ « + 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} +

+ +{if count($ordersMsgs)} + {foreach from=$ordersMsgs item=alert} +
{$alert->text}
+ {/foreach} +
+{/if} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
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

+ + + + + + + + + + + + + + {foreach from=$order->payments() item=payment} + + + + + + + + + + + {/foreach} +
IDStatusMethodeAmountSettlementRefundedRemainingDetails
{$payment->id}{$payment->status}{$payment->method}{$payment->amount->value} {$payment->amount->currency}{$payment->settlementAmount->value} {$payment->settlementAmount->currency}{$payment->amountRefunded->value} {$payment->amountRefunded->currency}{$payment->amountRemaining->value} {$payment->amountRemaining->currency} +
    + {foreach from=$payment->details item=value key=key} +
  • {$key}: {$value}
  • + {/foreach} +
+
+{/if} + + +

Positionen:

+ +
+ {if ($order->status === 'authorized' || $order->status === 'shipping') && $oBestellung->cStatus|intval >= 3} + + Zahlung erfassen1 + + {/if} + {if $order->amount->value > $order->amountRefunded->value && $order->amountCaptured->value > 0} + Rckerstatten2 + + {/if} + {if $order->isCancelable} + Stornieren3 + + {/if} +
+ + + + + + + + + + + + + + + + + + {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} + + + + + + + + + + + + + {/foreach} + + + + + + + + + + +
StatusSKUNameTypAnzahlMwStSteuerNettoBrutto 
+ {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*} +
{$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} + + + + + + + {/foreach} +
+ {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}
+ + diff --git a/version/106/adminmenu/tpl/orders.tpl b/version/106/adminmenu/tpl/orders.tpl new file mode 100644 index 0000000..df024b4 --- /dev/null +++ b/version/106/adminmenu/tpl/orders.tpl @@ -0,0 +1,113 @@ + +{if count($ordersMsgs)} + {foreach from=$ordersMsgs item=alert} +
{$alert->text}
+ {/foreach} +
+{/if} + +{if $hasAPIKey == false} + + Jetzt kostenlos Mollie Account eröffnen! + +{else} + + + + + + + + + + + + + + + + {foreach from=$payments item=payment} + + + + + + + + + + + + {/foreach} + +
BestellNr.IDMollie StatusJTL StatusBetragWährungLocaleMethodeErstellt
+ {$payment->cOrderNumber} + {if $payment->cMode == 'test'} + TEST + {/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)}
+ + +{/if} + diff --git a/version/106/adminmenu/tpl/paymentmethods.tpl b/version/106/adminmenu/tpl/paymentmethods.tpl new file mode 100644 index 0000000..bd65a11 --- /dev/null +++ b/version/106/adminmenu/tpl/paymentmethods.tpl @@ -0,0 +1,92 @@ +

Account Status

+ + + + + + + + + +
Mode:{$profile->mode}Status:{$profile->status}Review:{$profile->review->status}
+ +
+ +
+
+ + +
+ + + +
+
+ + +
+
+ + +
+
+ + + reset +
+
+
+ + +{if $allMethods && $allMethods|count} + + + + + + + + + + + + {foreach from=$allMethods item=method} + + + + + + + + {/foreach} + +
BildIDNamePreiseInfos
{$method->description|utf8_decode}{$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} +
+{else} +
Es konnten keine Methoden abgerufen werden.
+{/if} \ No newline at end of file diff --git a/version/106/class/Helper.php b/version/106/class/Helper.php new file mode 100644 index 0000000..8f4772c --- /dev/null +++ b/version/106/class/Helper.php @@ -0,0 +1,311 @@ +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(); + } + + /** + * 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/106/class/Model/AbstractModel.php b/version/106/class/Model/AbstractModel.php new file mode 100644 index 0000000..5638700 --- /dev/null +++ b/version/106/class/Model/AbstractModel.php @@ -0,0 +1,7 @@ + $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, + ]; + 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/106/class/Mollie.php b/version/106/class/Mollie.php new file mode 100644 index 0000000..7b96c3b --- /dev/null +++ b/version/106/class/Mollie.php @@ -0,0 +1,477 @@ +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) { + header('Location: ' . $url); + 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; + } + + switch ((int)$newStatus) { + case BESTELLUNG_STATUS_VERSANDT: + Mollie::JTLMollie()->doLog('181_sync: Bestellung versandt', '#' . $oBestellung->kBestellung . '§' . $oBestellung->cBestellNr, LOGLEVEL_DEBUG); + $options['lines'] = []; + break; + case BESTELLUNG_STATUS_TEILVERSANDT: + $lines = []; + foreach ($order->lines as $i => $line) { + if (($quantity = Mollie::getBestellPosSent($line->sku, $oBestellung)) !== false && ($quantity - $line->quantityShipped) > 0) { + $x = $quantity - $line->quantityShipped; + $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', '#' . $oBestellung->kBestellung . '§' . $oBestellung->cBestellNr, LOGLEVEL_DEBUG); + if (count($lines)) { + $options['lines'] = $lines; + } + break; + case BESTELLUNG_STATUS_STORNO: + Mollie::JTLMollie()->doLog('181_sync: Bestellung storniert', '#' . $oBestellung->kBestellung . '§' . $oBestellung->cBestellNr, LOGLEVEL_DEBUG); + $options = null; + break; + default: + Mollie::JTLMollie()->doLog('181_sync: Bestellungstatus unbekannt: ' . $newStatus . '/' . $oBestellung->cStatus, '#' . $oBestellung->kBestellung . '§' . $oBestellung->cBestellNr, 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; + } + + /** + * @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); + + $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); + } + + + $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; + } + + $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; + } + + 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/106/frontend/131_globalinclude.php b/version/106/frontend/131_globalinclude.php new file mode 100644 index 0000000..c125319 --- /dev/null +++ b/version/106/frontend/131_globalinclude.php @@ -0,0 +1,82 @@ +executeQueryPrepared("SELECT * FROM " . \ws_mollie\Model\Payment::TABLE . " WHERE cHash = :cHash", [':cHash' => $_REQUEST['mollie']], 1); + // Bestellung finalized, redirect to status/completion page + if ((int)$payment->kBestellung) { + $logData = '$' . $payment->kID . '#' . $payment->kBestellung . "§" . $payment->cOrderNumber; + Mollie::JTLMollie()->doLog('Hook 131/kBestellung => bestellabschluss', $logData); + $order = JTLMollie::API()->orders->get($payment->kID, ['embed' => 'payments']); + Mollie::handleOrder($order, $payment->kBestellung); + Mollie::getOrderCompletedRedirect($payment->kBestellung, true); + } elseif ($payment) { // payment, but no order => finalize it + require_once __DIR__ . '/../paymentmethod/JTLMollie.php'; + $order = JTLMollie::API()->orders->get($payment->kID, ['embed' => 'payments']); + $logData = '$' . $order->id . '#' . $payment->kBestellung . "§" . $payment->cOrderNumber; + + // GET NEWEST PAYMENT: + /** @var Payment $_payment */ + $_payment = null; + if ($order->payments()) { + /** @var Payment $p */ + foreach ($order->payments() as $p) { + if (!$_payment) { + $_payment = $p; + continue; + } + if (strtotime($p->createdAt) > strtotime($_payment->createdAt)) { + $_payment = $p; + } + } + } + + // finalize only, if order is not canceld/expired + if ($order && !$order->isCanceled() && !$order->isExpired()) { + // finalize only if payment is not expired/canceled,failed or open + if ($_payment && !in_array($_payment->status, [PaymentStatus::STATUS_EXPIRED, PaymentStatus::STATUS_CANCELED, PaymentStatus::STATUS_OPEN, PaymentStatus::STATUS_FAILED])) { + + Mollie::JTLMollie()->doLog('Hook 131/open => finalize', $logData, LOGLEVEL_DEBUG); + /** @noinspection PhpIncludeInspection */ + require_once PFAD_ROOT . 'includes/bestellabschluss_inc.php'; + /** @noinspection PhpIncludeInspection */ + require_once PFAD_ROOT . 'includes/mailTools.php'; + $session = Session::getInstance(); + $oBestellung = fakeBestellung(); + $oBestellung = finalisiereBestellung(); + $session->cleanUp(); + + Mollie::JTLMollie()->doLog('Hook 131/finalized => bestellabschluss
' . print_r($order, 1) . '
', $logData); + Mollie::handleOrder($order, $oBestellung->kBestellung); + JTLMollie::API()->performHttpCall('PATCH', sprintf('payments/%s', $_payment->id), json_encode(['description' => $oBestellung->cBestellNr])); + + return Mollie::getOrderCompletedRedirect($oBestellung->kBestellung, true); + + } else { + Mollie::JTLMollie()->doLog('Hook 131/Invalid Payment
' . print_r($payment, 1) . '
', $logData, LOGLEVEL_ERROR); + header('Location: ' . Shop::getURL() . '/bestellvorgang.php?editZahlungsart=1&mollieStatus=' . $_payment->status); + exit(); + } + } else { + Mollie::JTLMollie()->doLog('Hook 131/Invalid Order
' . print_r($order, 1) . '
', $logData, LOGLEVEL_ERROR); + header('Location: ' . Shop::getURL() . '/bestellvorgang.php?editZahlungsart=1&mollieStatus=' . $order->status); + exit(); + } + } + } + ob_end_flush(); +} catch (Exception $e) { + Helper::logExc($e); +} diff --git a/version/106/frontend/140_smarty.php b/version/106/frontend/140_smarty.php new file mode 100644 index 0000000..53360d6 --- /dev/null +++ b/version/106/frontend/140_smarty.php @@ -0,0 +1,59 @@ +oPluginSprachvariableAssoc_arr['error_' . $status]; + pq('#fieldset-payment')->prepend('
' . $text . '
'); + } + + 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/106/frontend/144_notify.php b/version/106/frontend/144_notify.php new file mode 100644 index 0000000..fe19c10 --- /dev/null +++ b/version/106/frontend/144_notify.php @@ -0,0 +1,59 @@ + Update Payment, stop skript + * - ELSE weiter mit der notify.php + */ + +use Mollie\Api\Types\PaymentStatus; +use ws_mollie\Helper; +use ws_mollie\Model\Payment; +use ws_mollie\Mollie; + +if (array_key_exists('hash', $_REQUEST)) { + require_once __DIR__ . '/../class/Helper.php'; + try { + Helper::init(); + $payment = Payment::getPaymentHash($_REQUEST['hash']); + // If Bestellung already exists, treat as Notification + if ($payment && $payment->kBestellung) { + require_once __DIR__ . '/../paymentmethod/JTLMollie.php'; + $order = JTLMollie::API()->orders->get($payment->kID, ['embed' => 'payments']); + $logData = '#' . $payment->kBestellung . '$' . $payment->kID; + Mollie::JTLMollie()->doLog('Notify/Hook 144/kBestellung>0
' . print_r([$order, $payment], 1) . '
', $logData); + Mollie::handleOrder($order, $payment->kBestellung); + // exit to stop execution of notify.php + + // GET NEWEST PAYMENT: + /** @var \Mollie\Api\Resources\Payment $_payment */ + $_payment = null; + if ($order->payments()) { + /** @var \Mollie\Api\Resources\Payment $p */ + foreach ($order->payments() as $p) { + if (!in_array($p->status, [PaymentStatus::STATUS_AUTHORIZED, PaymentStatus::STATUS_PAID, PaymentStatus::STATUS_PENDING])) { + continue; + } + if (!$_payment) { + $_payment = $p; + continue; + } + if (strtotime($p->createdAt) > strtotime($_payment->createdAt)) { + $_payment = $p; + } + } + } + + if ($payment->oBestellung instanceof Bestellung) { + JTLMollie::API()->performHttpCall('PATCH', sprintf('payments/%s', $_payment->id), json_encode(['description' => $payment->oBestellung->cBestellNr])); + } + + exit(); + }else if($payment){ + $logData = '$' . $payment->kID; + Mollie::JTLMollie()->doLog('Notify/Hook 144/continue
' . print_r([$order, $payment], 1) . '
', $logData); + } + } catch (Exception $e) { + Helper::logExc($e); + } +} diff --git a/version/106/frontend/181_sync.php b/version/106/frontend/181_sync.php new file mode 100644 index 0000000..86c610c --- /dev/null +++ b/version/106/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/106/frontend/img/trust_eng.png b/version/106/frontend/img/trust_eng.png new file mode 100644 index 0000000000000000000000000000000000000000..3d0177359de7fa93833765ac05d8b218fa1550f2 GIT binary patch literal 15299 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 Rmns)TMnX}%M${5 literal 0 HcmV?d00001 diff --git a/version/106/frontend/img/trust_fre.png b/version/106/frontend/img/trust_fre.png new file mode 100644 index 0000000000000000000000000000000000000000..ed1a2f6f03c56f6748aac8af0352de7fc0afd3a4 GIT binary patch literal 17319 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 Mu#8ZJpsxS_1AJc%;s5{u literal 0 HcmV?d00001 diff --git a/version/106/frontend/img/trust_ger.png b/version/106/frontend/img/trust_ger.png new file mode 100644 index 0000000000000000000000000000000000000000..e42821b06709e8f4371c66cfb5759d00df0e1afd GIT binary patch literal 15352 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 (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); + + + if (isset($model->kZahlungseingang) && $model->kZahlungseingang > 0) { + Shop::DB()->update('tzahlungseingang', 'kZahlungseingang', $model->kZahlungseingang, $model); + } else { + Shop::DB()->insert('tzahlungseingang', $model); + } + + 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 + */ + public function preparePaymentProcess($order) + { + $logData = '#' . $order->kBestellung . "" . $order->cBestellNr; + try { + if ($order->kBestellung) { + $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(); + } + } + } catch (Exception $e) { + $this->doLog("Get Payment Error: " . $e->getMessage() . ". Create new ORDER...", $logData, LOGLEVEL_ERROR); + } + + try { + if (!array_key_exists('oMolliePayment', $_SESSION) || !($_SESSION['oMolliePayment'] instanceof \Mollie\Api\Resources\Order)) { + $hash = $this->generateHash($order); + $orderData = $this->getOrderData($order, $hash); + $oMolliePayment = self::API()->orders->create($orderData); + $_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($hash)); + Shop::Smarty()->assign('oMolliePayment', $oMolliePayment); + if (!$this->duringCheckout) { + Session::getInstance()->cleanUp(); + } + header('Location: ' . $oMolliePayment->getCheckoutUrl()); + unset($_SESSION['oMolliePayment']); + echo "redirect to payment ..."; + 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'); + exit(); + } + } + + /** + * @return MollieApiClient + * @throws ApiException + * @throws IncompatiblePlatform + */ + public static function API() + { + if (self::$_mollie === null) { + self::$_mollie = new MollieApiClient(); + 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 string $msg + * @param null $data + * @param int $level + * @return $this + */ + public function doLog($msg, $data = null, $level = LOGLEVEL_NOTICE) + { + ZahlungsLog::add($this->moduleID, $msg, $data, $level); + + return $this; + } + + /** + * @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(), + + 'redirectUrl' => (int)$this->duringCheckout ? Shop::getURL() . '/bestellabschluss.php?mollie=' . md5($hash) : $this->getReturnURL($order), + 'webhookUrl' => $this->getNotificationURL($hash) . '&hash=' . md5($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 ($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 ($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; + } + + + /** @var WarenkorbPos $oPosition */ + foreach ($order->Positionen as $oPosition) { + + // EUR => 1 + $_netto = round($oPosition->fPreis, 2); // 13.45378 => 13.45 + $_vatRate = (float)$oPosition->fMwSt / 100; // 0.19 + $_amount = (float)$oPosition->nAnzahl; // 3 + + $unitPriceNetto = round(($_currencyFactor * $_netto), 2); // => 13.45 + $unitPrice = round($unitPriceNetto * (1 + $_vatRate), 2); // 13.45 * 1.19 => 16.01 + + $totalAmount = round($_amount * $unitPrice, 2); // 16.01 * 3 => 48.03 + //$vatAmount = ($unitPrice - $unitPriceNetto) * $_amount; // (16.01 - 13.45) * 3 => 7.68 + $vatAmount = round($totalAmount - ($totalAmount / (1 + $_vatRate)), 2); // 48.03 - (48.03 / 1.19) => 7.67 + + $line = new stdClass(); + $line->name = utf8_encode($oPosition->cName); + $line->quantity = $oPosition->nAnzahl; + $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 = $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->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->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 function optionaleRundung($gesamtsumme) + { + $conf = Shop::getSettings([CONF_KAUFABWICKLUNG]); + if (isset($conf['kaufabwicklung']['bestellabschluss_runden5']) && $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 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"; + } + } + + /** + * @param Bestellung $order + * @param string $hash + * @param array $args + */ + public function handleNotification($order, $hash, $args) + { + Helper::autoload(); + $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); + + // GET NEWEST PAYMENT: + /** @var \Mollie\Api\Resources\Payment $_payment */ + $_payment = null; + if ($oMolliePayment->payments()) { + /** @var \Mollie\Api\Resources\Payment $p */ + foreach ($oMolliePayment->payments() as $p) { + if (!in_array($p->status, [PaymentStatus::STATUS_AUTHORIZED, PaymentStatus::STATUS_PAID, PaymentStatus::STATUS_PENDING])) { + continue; + } + if (!$_payment) { + $_payment = $p; + continue; + } + if (strtotime($p->createdAt) > strtotime($_payment->createdAt)) { + $_payment = $p; + } + } + } + + JTLMollie::API()->performHttpCall('PATCH', sprintf('payments/%s', $_payment->id), json_encode(['description' => $order->cBestellNr])); + + } catch (Exception $e) { + $this->doLog('JTLMollie::handleNotification: ' . $e->getMessage(), $logData); + } + } + + /** + * @param Bestellung $order + * @param string $hash + * @param array $args + * + * @return true, if $order should be finalized + */ + public function finalizeOrder($order, $hash, $args) + { + $logData = '#' . $order->kBestellung . "" . $order->cBestellNr; + try { + Helper::autoload(); + $oMolliePayment = self::API()->orders->get($args['id'], ['embed' => 'payments']); + $logData .= '$' . $oMolliePayment->id; + $this->doLog('JTLMollie::finalizeOrder
' . print_r([$hash, $args, $oMolliePayment], 1) . '
', $logData, LOGLEVEL_DEBUG); + Payment::updateFromPayment($oMolliePayment, $order->kBestellung); + return in_array($oMolliePayment->status, [OrderStatus::STATUS_PAID, OrderStatus::STATUS_AUTHORIZED, OrderStatus::STATUS_PENDING, OrderStatus::STATUS_COMPLETED]); + } catch (Exception $e) { + $this->doLog('JTLMollie::finalizeOrder: ' . $e->getMessage(), $logData); + } + return false; + } + + /** + * @return bool + */ + public function canPayAgain() + { + return true; + } + + /** + * determines, if the payment method can be selected in the checkout process + * + * @return bool + */ + public function isSelectable() + { + /** @var Warenkorb $wk */ + $wk = $_SESSION['Warenkorb']; + 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 { + $method = self::PossiblePaymentMethods(static::MOLLIE_METHOD, $locale, $_SESSION['Kunde']->cLand, $_SESSION['Waehrung']->cISO, $wk->gibGesamtsummeWaren(true) * $_SESSION['Waehrung']->fFaktor); + if ($method !== null) { + $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; + } + } + return true; + } + + /** + * @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 (ws_mollie\Helper::getSetting('paymentmethod_sync') === 'N') { + return; + } + $size = ws_mollie\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::init() && 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/106/paymentmethod/JTLMollieApplePay.php b/version/106/paymentmethod/JTLMollieApplePay.php new file mode 100644 index 0000000..ecf20a8 --- /dev/null +++ b/version/106/paymentmethod/JTLMollieApplePay.php @@ -0,0 +1,8 @@ +assign('profileId', trim(Helper::getSetting('profileId'))) + ->assign('locale', self::getLocale($_SESSION['cISOSprache'], $_SESSION['Kunde']->cLand)) + ->assign('testmode', strpos(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/106/paymentmethod/JTLMollieDirectDebit.php b/version/106/paymentmethod/JTLMollieDirectDebit.php new file mode 100644 index 0000000..ce0441d --- /dev/null +++ b/version/106/paymentmethod/JTLMollieDirectDebit.php @@ -0,0 +1,8 @@ + + {$oMollieException->getMessage()} + +{/if} \ No newline at end of file diff --git a/version/106/paymentmethod/tpl/mollieComponents.tpl b/version/106/paymentmethod/tpl/mollieComponents.tpl new file mode 100644 index 0000000..6b7693f --- /dev/null +++ b/version/106/paymentmethod/tpl/mollieComponents.tpl @@ -0,0 +1,101 @@ +

{$mollieLang.cctitle}

+
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+ +
+
+ + +
+ +
+ {if $trustBadge} +
+ PCI-DSS SAQ-A compliant +
+ {/if} +
+ + + + + \ No newline at end of file From 7995974eccc2d383ad97f18ca084e6dca0d54d18 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Tue, 26 Nov 2019 15:29:39 +0100 Subject: [PATCH 104/280] infox.ml --- info.xml | 1104 +++++++++++++++++++++++++++--------------------------- 1 file changed, 555 insertions(+), 549 deletions(-) diff --git a/info.xml b/info.xml index 789f25d..1d36003 100644 --- a/info.xml +++ b/info.xml @@ -1,558 +1,564 @@ - - mollie - Zahlungsartplugin für mollie.com - WebStollen - http://www.webstollen.de/ - 102 - ws_mollie - 405 - - - 100.sql - 2019-02-11 - - - 2019-02-26 - - - 2019-04-23 - - - 2019-05-22 - - - 2019-07-12 - - - 2019-11-26 - - - 2019-11-26 - - - 131_globalinclude.php - 144_notify.php - 181_sync.php - 140_smarty.php - - - - Bestellungen - orders.php - - - Zahlungsarten - paymentmethods.php - - - Info - info.php - - - Einstellungen - - API Key: - Füge hier deinen mollie API Key ein - api_key - - - Profile ID: - Füge hier deinen mollie Profil ID ein. Wird benötigt um mollie Components zu aktivieren - profileId - - - Trust-Grafik bei mollie Components anzeigen: - Bindet eine Trust-Grafik unterhalb des Kreditkartenformulars ein. - loadTrust - - - - - - - Zahlungsart Daten syncronisiernen - Lädt Name / Bild für die jeweilige Sprache automatisch von mollie, und speichert diese in der Datenbank - paymentmethod_sync - - - - - - - - - Checkout Styles laden - Lädt Stylesheets für das Evo Template, um den Checkout zu verschönern. - load_styles - - - - - - - - TransaktionsID des Zahlungseingangs: - Welche ID soll an die WAWI übetragen werden? - wawiPaymentID - - - - - - - - Workflow-Secret: - Schlüssel, um die WAWI Workflow-Requests zu authentifizieren. - workflowSecret - - - - - - cctitle - - - - - - error_canceled - - + + mollie + Zahlungsartplugin für mollie.com + WebStollen + http://www.webstollen.de/ + 102 + ws_mollie + 405 + + + 100.sql + 2019-02-11 + + + 2019-02-26 + + + 2019-04-23 + + + 2019-05-22 + + + 2019-07-12 + + + 2019-07-12 + + + 131_globalinclude.php + 144_notify.php + 181_sync.php + 140_smarty.php + + + + cctitle + + Zahlungsinformationen + Enter your payment information + + + error_canceled + + Die Zahlung wurde von Ihnen abgebrochen. Wählen Sie ggf. eine andere Zahlart aus. - ]]> - + You canceled the payment. Please select a different payment method if necessary. - ]]> - - - error_expired - - - - - - error_open - - + + + error_expired + + Ihre Zahlungssession ist abgelaufen, bitte versuchen Sie es erneut. + + Your payment session has expired, please try again. + + + error_open + + Bei der Zahlung ist ein Fehler aufgetreten. Bitte versuchen Sie es erneut, oder wählen Sie eine andere Zahlungsart. - ]]> - + The payment process failed. Please try again or choose a different payment method. - ]]> - - - error_failed - - + + + error_failed + + Bei der Zahlung ist ein Fehler aufgetreten. Bitte versuchen Sie es erneut, oder wählen Sie eine andere Zahlungsart. - ]]> - + The payment process failed. Please try again or choose a different payment method. - ]]> - - - lbl_cardHolder - - - - - - lbl_cardNumber - - - - - - lbl_expiryDate - - - - - - lbl_varificationCode - - - - - - cvchint_1 - - - - - - cvchint_2 - - + + + lbl_cardHolder + + Karteninhaber: + Card holder: + + + lbl_cardNumber + + Kartennummer: + Card number: + + + lbl_expiryDate + + Ablaufdatum: + Expiry date: + + + lbl_varificationCode + + CVC: + CVC: + + + + cvchint_1 + + So findet man die CVV Nummer + How to find the CVV number + + + cvchint_2 + + Die dreistellige CVV Nummer wird bei Visa und Mastercard auf der Rückseite, bei American Express auf der Vorderseite der Karte abgebildet. - ]]> - + The three-digit CVV number is shown on the reverse for Visa and Mastercard, and on the front of the card for American Express. - ]]> - - - - - mollie - - 1 - 0 - mollie.com - OTHER - 0 - 0 - 1 - 0 - JTLMollie.php - JTLMollie - tpl/bestellabschluss.tpl - - mollie - mollie - Bezahlen Sie bequem mit verschiedenen Zahlungsmethoden. - - - - mollie Kreditkarte - - 3 - 0 - mollie.com - CREDIT_CARD - 1 - 0 - 1 - 0 - JTLMollieCreditCard.php - JTLMollieCreditCard - tpl/bestellabschluss.tpl - - Kreditkarte - mollie - Bezahlen Sie bequem mit Kreditkarte. - - - - mollie Apple Pay - - 3 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMollieApplePay.php - JTLMollieApplePay - tpl/bestellabschluss.tpl - - Apple Pay - mollie - Bezahlen Sie bequem mit Apple Pay. - - - - mollie Bancontact - - 4 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMollieBancontact.php - JTLMollieBancontact - tpl/bestellabschluss.tpl - - Bancontact - mollie - Bezahlen Sie bequem mit Bancontact. - - - - mollie Banktransfer - - 5 - 0 - mollie.com - OTHER - 0 - 0 - 1 - 0 - JTLMollieBanktransfer.php - JTLMollieBanktransfer - tpl/bestellabschluss.tpl - - SEPA Überweisung - mollie - Bezahlen Sie bequem mit SEPA Überweisung. - - - - mollie Belfius - - 6 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMollieBelfius.php - JTLMollieBelfius - tpl/bestellabschluss.tpl - - Belfius - mollie - Bezahlen Sie bequem mit Belfius. - - - - mollie DirectDebit - - 7 - 0 - mollie.com - DIRECT_DEBIT - 1 - 0 - 1 - 0 - JTLMollieDirectDebit.php - JTLMollieDirectDebit - tpl/bestellabschluss.tpl - - SEPA Lastschrift - mollie - Bezahlen Sie bequem mit SEPA Lastschrift. - - - - mollie EPS - - 2 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMollieEPS.php - JTLMollieEPS - tpl/bestellabschluss.tpl - - EPS - mollie - Bezahlen Sie bequem mit EPS. - - - - mollie Giftcard - - 8 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMollieGiftcard.php - JTLMollieGiftcard - tpl/bestellabschluss.tpl - - Gift cards - mollie - Bezahlen Sie bequem mit Gift cards. - - - - mollie Giropay - - 9 - 0 - mollie.com - GIROPAY - 1 - 0 - 1 - 0 - JTLMollieGiropay.php - JTLMollieGiropay - tpl/bestellabschluss.tpl - - Giropay - mollie - Bezahlen Sie bequem mit Giropay. - - - - mollie iDEAL - - 10 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMollieIDEAL.php - JTLMollieIDEAL - tpl/bestellabschluss.tpl - - Giropay - mollie - Bezahlen Sie bequem mit iDEAL. - - - - mollie ING HomePay - - 11 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMollieINGHomePay.php - JTLMollieINGHomePay - tpl/bestellabschluss.tpl - - ING HomePay - mollie - Bezahlen Sie bequem mit ING HomePay. - - - - mollie KBC - - 12 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMollieKBC.php - JTLMollieKBC - tpl/bestellabschluss.tpl - - KBC - mollie - Bezahlen Sie bequem mit KBC. - - - - mollie PayPal - - 13 - 0 - mollie.com - PAYPAL - 1 - 0 - 1 - 0 - JTLMolliePayPal.php - JTLMolliePayPal - tpl/bestellabschluss.tpl - - PayPal - mollie - Bezahlen Sie bequem mit PayPal. - - - - mollie paysafecard - - 14 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMolliePaysafecard.php - JTLMolliePaysafecard - tpl/bestellabschluss.tpl - - paysafecard - mollie - Bezahlen Sie bequem mit paysafecard. - - - - mollie SOFORT - - 15 - 0 - mollie.com - DIRECT_E_BANKING - 1 - 0 - 1 - 0 - JTLMollieSofort.php - JTLMollieSofort - tpl/bestellabschluss.tpl - - SOFORT - mollie - Bezahlen Sie bequem mit SOFORT. - - - - mollie Klarna Pay Later - - 16 - 0 - mollie.com - INVOICE - 1 - 0 - 1 - 0 - JTLMollieKlarnaPayLater.php - JTLMollieKlarnaPayLater - tpl/bestellabschluss.tpl - - Klarna Pay Later - mollie - Bezahlen Sie bequem mit Klarna Pay Later. - - - - mollie Klarna Slice It - - 17 - 0 - mollie.com - FINANCING - 1 - 0 - 1 - 0 - JTLMollieKlarnaSliceIt.php - JTLMollieKlarnaSliceIt - tpl/bestellabschluss.tpl - - Klarna Slice It - mollie - Bezahlen Sie bequem mit Klarna Slice It. - - - - + + + + + + Bestellungen + orders.php + + + Zahlungsarten + paymentmethods.php + + + Info + info.php + + + Einstellungen + + API Key: + Füge hier deinen mollie API Key ein + api_key + + + Profile ID: + Füge hier deinen mollie Profil ID ein. Wird benötigt um mollie Components zu aktivieren + profileId + + + + Trust-Grafik bei mollie Components anzeigen: + Bindet eine Trust-Grafik unterhalb des Kreditkartenformulars ein. + loadTrust + + + + + + + Zahlungsart Daten syncronisiernen + Lädt Name / Bild für die jeweilige Sprache automatisch von mollie, und speichert diese + in der Datenbank + + paymentmethod_sync + + + + + + + + + Checkout Styles laden + Lädt Stylesheets für das Evo Template, um den Checkout zu verschönern. + load_styles + + + + + + + + + TransaktionsID des Zahlungseingangs: + Welche ID soll an die WAWI übetragen werden? + wawiPaymentID + + + + + + + + + Workflow-Secret: + Schlüssel, um die WAWI Workflow-Requests zu authentifizieren. + workflowSecret + + + + + + + mollie + + 1 + 0 + mollie.com + OTHER + 0 + 0 + 1 + 0 + JTLMollie.php + JTLMollie + tpl/bestellabschluss.tpl + + mollie + mollie + Bezahlen Sie bequem mit verschiedenen Zahlungsmethoden. + + + + mollie Kreditkarte + + 3 + tpl/mollieComponents.tpl + 0 + mollie.com + CREDIT_CARD + 1 + 0 + 1 + 0 + JTLMollieCreditCard.php + JTLMollieCreditCard + tpl/bestellabschluss.tpl + + Kreditkarte + mollie + Bezahlen Sie bequem mit Kreditkarte. + + + + mollie Apple Pay + + 3 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMollieApplePay.php + JTLMollieApplePay + tpl/bestellabschluss.tpl + + Apple Pay + mollie + Bezahlen Sie bequem mit Apple Pay. + + + + mollie Bancontact + + 4 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMollieBancontact.php + JTLMollieBancontact + tpl/bestellabschluss.tpl + + Bancontact + mollie + Bezahlen Sie bequem mit Bancontact. + + + + mollie Banktransfer + + 5 + 0 + mollie.com + OTHER + 0 + 0 + 1 + 0 + JTLMollieBanktransfer.php + JTLMollieBanktransfer + tpl/bestellabschluss.tpl + + SEPA Überweisung + mollie + Bezahlen Sie bequem mit SEPA Überweisung. + + + + mollie Belfius + + 6 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMollieBelfius.php + JTLMollieBelfius + tpl/bestellabschluss.tpl + + Belfius + mollie + Bezahlen Sie bequem mit Belfius. + + + + mollie DirectDebit + + 7 + 0 + mollie.com + DIRECT_DEBIT + 1 + 0 + 1 + 0 + JTLMollieDirectDebit.php + JTLMollieDirectDebit + tpl/bestellabschluss.tpl + + SEPA Lastschrift + mollie + Bezahlen Sie bequem mit SEPA Lastschrift. + + + + mollie EPS + + 2 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMollieEPS.php + JTLMollieEPS + tpl/bestellabschluss.tpl + + EPS + mollie + Bezahlen Sie bequem mit EPS. + + + + mollie Giftcard + + 8 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMollieGiftcard.php + JTLMollieGiftcard + tpl/bestellabschluss.tpl + + Gift cards + mollie + Bezahlen Sie bequem mit Gift cards. + + + + mollie Giropay + + 9 + 0 + mollie.com + GIROPAY + 1 + 0 + 1 + 0 + JTLMollieGiropay.php + JTLMollieGiropay + tpl/bestellabschluss.tpl + + Giropay + mollie + Bezahlen Sie bequem mit Giropay. + + + + mollie iDEAL + + 10 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMollieIDEAL.php + JTLMollieIDEAL + tpl/bestellabschluss.tpl + + Giropay + mollie + Bezahlen Sie bequem mit iDEAL. + + + + mollie ING HomePay + + 11 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMollieINGHomePay.php + JTLMollieINGHomePay + tpl/bestellabschluss.tpl + + ING HomePay + mollie + Bezahlen Sie bequem mit ING HomePay. + + + + mollie KBC + + 12 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMollieKBC.php + JTLMollieKBC + tpl/bestellabschluss.tpl + + KBC + mollie + Bezahlen Sie bequem mit KBC. + + + + mollie PayPal + + 13 + 0 + mollie.com + PAYPAL + 1 + 0 + 1 + 0 + JTLMolliePayPal.php + JTLMolliePayPal + tpl/bestellabschluss.tpl + + PayPal + mollie + Bezahlen Sie bequem mit PayPal. + + + + mollie paysafecard + + 14 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMolliePaysafecard.php + JTLMolliePaysafecard + tpl/bestellabschluss.tpl + + paysafecard + mollie + Bezahlen Sie bequem mit paysafecard. + + + + mollie SOFORT + + 15 + 0 + mollie.com + DIRECT_E_BANKING + 1 + 0 + 1 + 0 + JTLMollieSofort.php + JTLMollieSofort + tpl/bestellabschluss.tpl + + SOFORT + mollie + Bezahlen Sie bequem mit SOFORT. + + + + mollie Klarna Pay Later + + 16 + 0 + mollie.com + INVOICE + 1 + 0 + 1 + 0 + JTLMollieKlarnaPayLater.php + JTLMollieKlarnaPayLater + tpl/bestellabschluss.tpl + + Klarna Pay Later + mollie + Bezahlen Sie bequem mit Klarna Pay Later. + + + + mollie Klarna Slice It + + 17 + 0 + mollie.com + FINANCING + 1 + 0 + 1 + 0 + JTLMollieKlarnaSliceIt.php + JTLMollieKlarnaSliceIt + tpl/bestellabschluss.tpl + + Klarna Slice It + mollie + Bezahlen Sie bequem mit Klarna Slice It. + + + + \ No newline at end of file From dea54906f2eea9e7fb1a2f6f0f777af7e86fc740 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Tue, 3 Dec 2019 11:40:06 +0100 Subject: [PATCH 105/280] Update info.xml --- info.xml | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/info.xml b/info.xml index 1d36003..17be9bd 100644 --- a/info.xml +++ b/info.xml @@ -1,7 +1,7 @@ mollie - Zahlungsartplugin für mollie.com + Zahlungsartplugin fr mollie.com WebStollen http://www.webstollen.de/ 102 @@ -25,8 +25,12 @@ 2019-07-12 - 2019-07-12 + 2019-11-26 + + 2019-11-26 + + 131_globalinclude.php 144_notify.php @@ -43,7 +47,7 @@ error_canceled - Die Zahlung wurde von Ihnen abgebrochen. Wählen Sie ggf. eine andere + Die Zahlung wurde von Ihnen abgebrochen. Whlen Sie ggf. eine andere Zahlart aus. You canceled the payment. Please select a different payment method if @@ -61,7 +65,7 @@ error_open Bei der Zahlung ist ein Fehler aufgetreten. Bitte versuchen Sie es erneut, - oder wählen Sie eine andere Zahlungsart. + oder whlen Sie eine andere Zahlungsart. The payment process failed. Please try again or choose a different payment method. @@ -71,7 +75,7 @@ error_failed Bei der Zahlung ist ein Fehler aufgetreten. Bitte versuchen Sie es erneut, - oder wählen Sie eine andere Zahlungsart. + oder whlen Sie eine andere Zahlungsart. The payment process failed. Please try again or choose a different payment method. @@ -111,7 +115,7 @@ cvchint_2 - Die dreistellige CVV Nummer wird bei Visa und Mastercard auf der Rückseite, + Die dreistellige CVV Nummer wird bei Visa und Mastercard auf der Rckseite, bei American Express auf der Vorderseite der Karte abgebildet. The three-digit CVV number is shown on the reverse for Visa and Mastercard, @@ -136,12 +140,12 @@ Einstellungen API Key: - Füge hier deinen mollie API Key ein + Fge hier deinen mollie API Key ein api_key Profile ID: - Füge hier deinen mollie Profil ID ein. Wird benötigt um mollie Components zu aktivieren + Fge hier deinen mollie Profil ID ein. Wird bentigt um mollie Components zu aktivieren profileId @@ -156,20 +160,20 @@ Zahlungsart Daten syncronisiernen - Lädt Name / Bild für die jeweilige Sprache automatisch von mollie, und speichert diese + Ldt Name / Bild fr die jeweilige Sprache automatisch von mollie, und speichert diese in der Datenbank paymentmethod_sync - - + + Checkout Styles laden - Lädt Stylesheets für das Evo Template, um den Checkout zu verschönern. + Ldt Stylesheets fr das Evo Template, um den Checkout zu verschnern. load_styles @@ -180,7 +184,7 @@ TransaktionsID des Zahlungseingangs: - Welche ID soll an die WAWI übetragen werden? + Welche ID soll an die WAWI betragen werden? wawiPaymentID @@ -191,7 +195,7 @@ Workflow-Secret: - Schlüssel, um die WAWI Workflow-Requests zu authentifizieren. + Schlssel, um die WAWI Workflow-Requests zu authentifizieren. workflowSecret @@ -294,9 +298,9 @@ JTLMollieBanktransfer tpl/bestellabschluss.tpl - SEPA Überweisung + SEPA berweisung mollie - Bezahlen Sie bequem mit SEPA Überweisung. + Bezahlen Sie bequem mit SEPA berweisung. From f43e1c5a4f0eaa13386cfdd872fcbb93b881f047 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Thu, 12 Dec 2019 13:50:02 +0100 Subject: [PATCH 106/280] 105 patches --- version/106/adminmenu/tpl/order.tpl | 24 +++-- version/106/adminmenu/tpl/paymentmethods.tpl | 17 +-- version/106/class/Model/Payment.php | 3 + version/106/frontend/131_globalinclude.php | 16 ++- version/106/paymentmethod/JTLMollie.php | 108 ++++++++++--------- 5 files changed, 105 insertions(+), 63 deletions(-) diff --git a/version/106/adminmenu/tpl/order.tpl b/version/106/adminmenu/tpl/order.tpl index 8776874..5b3d172 100644 --- a/version/106/adminmenu/tpl/order.tpl +++ b/version/106/adminmenu/tpl/order.tpl @@ -96,13 +96,25 @@
{$payment->status} {$payment->method} {$payment->amount->value} {$payment->amount->currency}{$payment->settlementAmount->value} {$payment->settlementAmount->currency}{$payment->amountRefunded->value} {$payment->amountRefunded->currency}{$payment->amountRemaining->value} {$payment->amountRemaining->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}: {$value}
  • +
  • {$key}: {if $value|is_scalar}{$value}{else}{$value|json_encode}{/if}
  • {/foreach}
{$profile->mode} Status: {$profile->status}Review:{$profile->review->status}Review:{$profile->review->status}
@@ -20,7 +22,7 @@ @@ -30,18 +32,21 @@
- +
+ {if "active"|array_key_exists:$smarty.get}checked="checked"{/if}> reset
diff --git a/version/106/class/Model/Payment.php b/version/106/class/Model/Payment.php index 107ee30..6abe1d5 100644 --- a/version/106/class/Model/Payment.php +++ b/version/106/class/Model/Payment.php @@ -5,6 +5,7 @@ use Bestellung; use Mollie\Api\Resources\Order; use Shop; +use ws_mollie\Mollie; class Payment extends AbstractModel { @@ -12,6 +13,7 @@ class Payment extends AbstractModel public static function updateFromPayment(Order $oMolliePayment, $kBestellung = null, $hash = null) { + $logData = '#' . $kBestellung . '$' . $oMolliePayment->id; $data = [ ':kID' => $oMolliePayment->id, ':kBestellung' => (int)$kBestellung ?: null, @@ -39,6 +41,7 @@ public static function updateFromPayment(Order $oMolliePayment, $kBestellung = n ':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) ' diff --git a/version/106/frontend/131_globalinclude.php b/version/106/frontend/131_globalinclude.php index c125319..ed3ed6f 100644 --- a/version/106/frontend/131_globalinclude.php +++ b/version/106/frontend/131_globalinclude.php @@ -25,7 +25,9 @@ } elseif ($payment) { // payment, but no order => finalize it require_once __DIR__ . '/../paymentmethod/JTLMollie.php'; $order = JTLMollie::API()->orders->get($payment->kID, ['embed' => 'payments']); - $logData = '$' . $order->id . '#' . $payment->kBestellung . "§" . $payment->cOrderNumber; + $logData = '$' . $order->id . "§" . $payment->cOrderNumber; + Mollie::JTLMollie()->doLog('Hook 131/open => finalize?', $logData); + // GET NEWEST PAYMENT: /** @var Payment $_payment */ @@ -48,7 +50,7 @@ // finalize only if payment is not expired/canceled,failed or open if ($_payment && !in_array($_payment->status, [PaymentStatus::STATUS_EXPIRED, PaymentStatus::STATUS_CANCELED, PaymentStatus::STATUS_OPEN, PaymentStatus::STATUS_FAILED])) { - Mollie::JTLMollie()->doLog('Hook 131/open => finalize', $logData, LOGLEVEL_DEBUG); + Mollie::JTLMollie()->doLog('Hook 131/open => finalize!', $logData, LOGLEVEL_DEBUG); /** @noinspection PhpIncludeInspection */ require_once PFAD_ROOT . 'includes/bestellabschluss_inc.php'; /** @noinspection PhpIncludeInspection */ @@ -58,6 +60,16 @@ $oBestellung = finalisiereBestellung(); $session->cleanUp(); + if ($oBestellung->kBestellung > 0 && array_key_exists('cMollieHash', $_SESSION)) { + $_upd = new stdClass(); + $_upd->nBezahlt = 1; + $_upd->dZeitBezahlt = 'now()'; + $_upd->kBestellung = (int)$oBestellung->kBestellung; + Shop::DB()->update('tzahlungsession', 'cZahlungsID', $_SESSION['cMollieHash'], $_upd); + unset($_SESSION['cMollieHash']); + Jtllog::writeLog('tzahlungsession aktualisiert.', JTLLOG_LEVEL_DEBUG, false, 'Notify'); + } + Mollie::JTLMollie()->doLog('Hook 131/finalized => bestellabschluss
' . print_r($order, 1) . '
', $logData); Mollie::handleOrder($order, $oBestellung->kBestellung); JTLMollie::API()->performHttpCall('PATCH', sprintf('payments/%s', $_payment->id), json_encode(['description' => $oBestellung->cBestellNr])); diff --git a/version/106/paymentmethod/JTLMollie.php b/version/106/paymentmethod/JTLMollie.php index f3d38a2..28bc353 100644 --- a/version/106/paymentmethod/JTLMollie.php +++ b/version/106/paymentmethod/JTLMollie.php @@ -66,9 +66,11 @@ public static function Helper() * @param Bestellung $order * @param Object $payment (Key, Zahlungsanbieter, Abgeholt, Zeit is set here) * @return $this + * @throws Exception */ public function addIncomingPayment($order, $payment) { + Helper::init(); $model = (object)array_merge([ 'kBestellung' => (int)$order->kBestellung, 'cZahlungsanbieter' => empty($order->cZahlungsartName) ? $this->name : $order->cZahlungsartName, @@ -82,16 +84,32 @@ public function addIncomingPayment($order, $payment) 'cAbgeholt' => 'N' ], (array)$payment); + $logData = '#' . $order->kBestellung . '$' . $payment->id; 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, $msg, $data, $level); + + return $this; + } + /** * @param Bestellung $order * @return PaymentMethod|void @@ -113,7 +131,8 @@ public function setOrderStatusToPaid($order) */ public function preparePaymentProcess($order) { - $logData = '#' . $order->kBestellung . "" . $order->cBestellNr; + Helper::init(); + $logData = '#' . $order->kBestellung . "§" . $order->cBestellNr; try { if ($order->kBestellung) { $payment = Payment::getPayment($order->kBestellung); @@ -136,6 +155,7 @@ public function preparePaymentProcess($order) try { if (!array_key_exists('oMolliePayment', $_SESSION) || !($_SESSION['oMolliePayment'] instanceof \Mollie\Api\Resources\Order)) { $hash = $this->generateHash($order); + $_SESSION['cMollieHash'] = $hash; $orderData = $this->getOrderData($order, $hash); $oMolliePayment = self::API()->orders->create($orderData); $_SESSION['oMolliePayment'] = $oMolliePayment; @@ -156,6 +176,7 @@ public function preparePaymentProcess($order) } 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(); } } @@ -167,6 +188,7 @@ public function preparePaymentProcess($order) */ public static function API() { + Helper::init(); if (self::$_mollie === null) { self::$_mollie = new MollieApiClient(); self::$_mollie->setApiKey(Helper::getSetting('api_key')); @@ -176,19 +198,6 @@ public static function API() return self::$_mollie; } - /** - * @param string $msg - * @param null $data - * @param int $level - * @return $this - */ - public function doLog($msg, $data = null, $level = LOGLEVEL_NOTICE) - { - ZahlungsLog::add($this->moduleID, $msg, $data, $level); - - return $this; - } - /** * @param Bestellung $order * @param $hash @@ -256,17 +265,15 @@ protected function getOrderData(Bestellung $order, $hash) /** @var WarenkorbPos $oPosition */ foreach ($order->Positionen as $oPosition) { - // EUR => 1 - $_netto = round($oPosition->fPreis, 2); // 13.45378 => 13.45 - $_vatRate = (float)$oPosition->fMwSt / 100; // 0.19 - $_amount = (float)$oPosition->nAnzahl; // 3 + // EUR => 1 + $_netto = round($oPosition->fPreis, 2); + $_vatRate = (float)$oPosition->fMwSt / 100; + $_amount = (float)$oPosition->nAnzahl; - $unitPriceNetto = round(($_currencyFactor * $_netto), 2); // => 13.45 - $unitPrice = round($unitPriceNetto * (1 + $_vatRate), 2); // 13.45 * 1.19 => 16.01 - - $totalAmount = round($_amount * $unitPrice, 2); // 16.01 * 3 => 48.03 - //$vatAmount = ($unitPrice - $unitPriceNetto) * $_amount; // (16.01 - 13.45) * 3 => 7.68 - $vatAmount = round($totalAmount - ($totalAmount / (1 + $_vatRate)), 2); // 48.03 - (48.03 / 1.19) => 7.67 + $unitPriceNetto = round(($_currencyFactor * $_netto), 2); + $unitPrice = round($unitPriceNetto * (1 + $_vatRate), 2); + $totalAmount = round($_amount * $unitPrice, 2); + $vatAmount = round($totalAmount - ($totalAmount / (1 + $_vatRate)), 2); $line = new stdClass(); $line->name = utf8_encode($oPosition->cName); @@ -373,25 +380,6 @@ protected function getOrderData(Bestellung $order, $hash) return $data; } - public function optionaleRundung($gesamtsumme) - { - $conf = Shop::getSettings([CONF_KAUFABWICKLUNG]); - if (isset($conf['kaufabwicklung']['bestellabschluss_runden5']) && $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 getLocale($cISOSprache, $country = null) { switch ($cISOSprache) { @@ -438,6 +426,25 @@ public static function getLocale($cISOSprache, $country = null) } } + public function optionaleRundung($gesamtsumme) + { + $conf = Shop::getSettings([CONF_KAUFABWICKLUNG]); + if (isset($conf['kaufabwicklung']['bestellabschluss_runden5']) && $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; + } + /** * @param Bestellung $order * @param string $hash @@ -445,11 +452,12 @@ public static function getLocale($cISOSprache, $country = null) */ public function handleNotification($order, $hash, $args) { - Helper::autoload(); - $logData = '#' . $order->kBestellung . "" . $order->cBestellNr; + + $logData = '#' . $order->kBestellung . "§" . $order->cBestellNr; $this->doLog('JTLMollie::handleNotification
' . print_r([$hash, $args], 1) . '
', $logData, LOGLEVEL_DEBUG); try { + Helper::init(); $oMolliePayment = self::API()->orders->get($args['id'], ['embed' => 'payments']); Mollie::handleOrder($oMolliePayment, $order->kBestellung); @@ -488,14 +496,16 @@ public function handleNotification($order, $hash, $args) */ public function finalizeOrder($order, $hash, $args) { - $logData = '#' . $order->kBestellung . "" . $order->cBestellNr; + $logData = '#' . $order->kBestellung . "§" . $order->cBestellNr; try { - Helper::autoload(); + Helper::init(); $oMolliePayment = self::API()->orders->get($args['id'], ['embed' => 'payments']); $logData .= '$' . $oMolliePayment->id; - $this->doLog('JTLMollie::finalizeOrder
' . print_r([$hash, $args, $oMolliePayment], 1) . '
', $logData, LOGLEVEL_DEBUG); + + $result = in_array($oMolliePayment->status, [OrderStatus::STATUS_PAID, OrderStatus::STATUS_AUTHORIZED, OrderStatus::STATUS_PENDING, OrderStatus::STATUS_COMPLETED]); Payment::updateFromPayment($oMolliePayment, $order->kBestellung); - return in_array($oMolliePayment->status, [OrderStatus::STATUS_PAID, OrderStatus::STATUS_AUTHORIZED, OrderStatus::STATUS_PENDING, OrderStatus::STATUS_COMPLETED]); + $this->doLog('JTLMollie::finalizeOrder (' . ($result ? 'true' : 'false') . ')
' . print_r([$hash, $args, $oMolliePayment], 1) . '
', $logData, LOGLEVEL_DEBUG); + return $result; } catch (Exception $e) { $this->doLog('JTLMollie::finalizeOrder: ' . $e->getMessage(), $logData); } From 0ee98e1b9f46943dd4b3a45c235fbab7b9e10594 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Mon, 16 Dec 2019 15:35:02 +0100 Subject: [PATCH 107/280] close #60, #59, infoXML umlaute --- info.xml | 18 +++++++++--------- version/106/paymentmethod/JTLMollie.php | 12 +++++++++++- .../paymentmethod/JTLMollieBanktransfer.php | 2 ++ 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/info.xml b/info.xml index 17be9bd..c7f96e5 100644 --- a/info.xml +++ b/info.xml @@ -47,7 +47,7 @@ error_canceled - Die Zahlung wurde von Ihnen abgebrochen. Whlen Sie ggf. eine andere + Die Zahlung wurde von Ihnen abgebrochen. Wählen Sie ggf. eine andere Zahlart aus. You canceled the payment. Please select a different payment method if @@ -65,7 +65,7 @@ error_open Bei der Zahlung ist ein Fehler aufgetreten. Bitte versuchen Sie es erneut, - oder whlen Sie eine andere Zahlungsart. + oder whälen Sie eine andere Zahlungsart. The payment process failed. Please try again or choose a different payment method. @@ -109,16 +109,16 @@ cvchint_1 - So findet man die CVV Nummer - How to find the CVV number + So findet man die CVV/CVC Nummer + How to find the CVV/CVC number cvchint_2 - Die dreistellige CVV Nummer wird bei Visa und Mastercard auf der Rckseite, + Die dreistellige CVV/CVC Nummer wird bei Visa und Mastercard auf der Rückseite, bei American Express auf der Vorderseite der Karte abgebildet. - The three-digit CVV number is shown on the reverse for Visa and Mastercard, + The three-digit CVV/CVC number is shown on the reverse for Visa and Mastercard, and on the front of the card for American Express. @@ -195,7 +195,7 @@ Workflow-Secret: - Schlssel, um die WAWI Workflow-Requests zu authentifizieren. + Schlüssel, um die WAWI Workflow-Requests zu authentifizieren. workflowSecret @@ -298,9 +298,9 @@ JTLMollieBanktransfer tpl/bestellabschluss.tpl - SEPA berweisung + SEPA Überweisung mollie - Bezahlen Sie bequem mit SEPA berweisung. + Bezahlen Sie bequem mit SEPA Überweisung. diff --git a/version/106/paymentmethod/JTLMollie.php b/version/106/paymentmethod/JTLMollie.php index 28bc353..1d59e04 100644 --- a/version/106/paymentmethod/JTLMollie.php +++ b/version/106/paymentmethod/JTLMollie.php @@ -17,6 +17,8 @@ class JTLMollie extends PaymentMethod { + const ALLOW_PAYMENT_BEFORE_ORDER = true; + /** * PaymentMethod identifier */ @@ -541,6 +543,12 @@ public function isSelectable() try { $method = self::PossiblePaymentMethods(static::MOLLIE_METHOD, $locale, $_SESSION['Kunde']->cLand, $_SESSION['Waehrung']->cISO, $wk->gibGesamtsummeWaren(true) * $_SESSION['Waehrung']->fFaktor); 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; @@ -550,8 +558,10 @@ public function isSelectable() $this->doLog('Method ' . static::MOLLIE_METHOD . ' not selectable:' . $e->getMessage()); return false; } + } else { + $this->doLog("Global mollie PaymentMethod cannot be used for payments directly."); } - return true; + return false; } /** diff --git a/version/106/paymentmethod/JTLMollieBanktransfer.php b/version/106/paymentmethod/JTLMollieBanktransfer.php index 478988a..0e93425 100644 --- a/version/106/paymentmethod/JTLMollieBanktransfer.php +++ b/version/106/paymentmethod/JTLMollieBanktransfer.php @@ -5,4 +5,6 @@ class JTLMollieBanktransfer extends JTLMollie { const MOLLIE_METHOD = \Mollie\Api\Types\PaymentMethod::BANKTRANSFER; + + const ALLOW_PAYMENT_BEFORE_ORDER = false; } From 0a43cc1cd239b6b624279c9f61efb7e9cdcf968f Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Mon, 16 Dec 2019 15:37:45 +0100 Subject: [PATCH 108/280] fix #57 --- version/106/paymentmethod/tpl/mollieComponents.tpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version/106/paymentmethod/tpl/mollieComponents.tpl b/version/106/paymentmethod/tpl/mollieComponents.tpl index 6b7693f..9ad70bc 100644 --- a/version/106/paymentmethod/tpl/mollieComponents.tpl +++ b/version/106/paymentmethod/tpl/mollieComponents.tpl @@ -85,7 +85,7 @@ if (error) { var alert = document.createElement('div'); alert.className = 'alert alert-danger'; - alert.id = 'mollieError'; + alert.id = 'mollieErrorContent'; alert.textContent = error.message; errorDiv.append(alert); } else { From 0a9705b351b8e7b1411e58ee6a475a695b4a9d3c Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Mon, 16 Dec 2019 17:44:34 +0100 Subject: [PATCH 109/280] fix #45, #61 --- version/103/paymentmethod/JTLMollie.php | 2 +- version/106/class/Mollie.php | 33 +++++- version/106/frontend/131_globalinclude.php | 122 ++++++++++----------- version/106/frontend/144_notify.php | 82 +++++++------- version/106/paymentmethod/JTLMollie.php | 121 +++++++++++--------- 5 files changed, 196 insertions(+), 164 deletions(-) diff --git a/version/103/paymentmethod/JTLMollie.php b/version/103/paymentmethod/JTLMollie.php index 0d23b1d..7733a27 100644 --- a/version/103/paymentmethod/JTLMollie.php +++ b/version/103/paymentmethod/JTLMollie.php @@ -141,7 +141,7 @@ public function preparePaymentProcess($order) } $logData .= '$' . $oMolliePayment->id; $this->doLog('Mollie Create Payment Redirect: ' . $oMolliePayment->getCheckoutUrl() . "
" . print_r($oMolliePayment, 1) . "
", $logData, LOGLEVEL_DEBUG); - Payment::updateFromPayment($oMolliePayment, $order->kBestellung, md5($hash)); + Payment::updateFromPayment($oMolliePayment, $order->kBestellung, md5(trim($hash, '_'))); Shop::Smarty()->assign('oMolliePayment', $oMolliePayment); if (!$this->duringCheckout) { Session::getInstance()->cleanUp(); diff --git a/version/106/class/Mollie.php b/version/106/class/Mollie.php index 7b96c3b..9e5520e 100644 --- a/version/106/class/Mollie.php +++ b/version/106/class/Mollie.php @@ -45,7 +45,10 @@ public static function getOrderCompletedRedirect($kBestellung, $redirect = true) } if ($redirect) { - header('Location: ' . $url); + if (!headers_sent()) { + header('Location: ' . $url); + } + echo "redirect ..."; exit(); } return $url; @@ -214,6 +217,12 @@ public static function handleOrder(Order $order, $kBestellung) 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); @@ -261,6 +270,28 @@ public static function handleOrder(Order $order, $kBestellung) 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', diff --git a/version/106/frontend/131_globalinclude.php b/version/106/frontend/131_globalinclude.php index ed3ed6f..514cbea 100644 --- a/version/106/frontend/131_globalinclude.php +++ b/version/106/frontend/131_globalinclude.php @@ -1,6 +1,6 @@ executeQueryPrepared("SELECT * FROM " . \ws_mollie\Model\Payment::TABLE . " WHERE cHash = :cHash", [':cHash' => $_REQUEST['mollie']], 1); - // Bestellung finalized, redirect to status/completion page - if ((int)$payment->kBestellung) { - $logData = '$' . $payment->kID . '#' . $payment->kBestellung . "§" . $payment->cOrderNumber; - Mollie::JTLMollie()->doLog('Hook 131/kBestellung => bestellabschluss', $logData); - $order = JTLMollie::API()->orders->get($payment->kID, ['embed' => 'payments']); - Mollie::handleOrder($order, $payment->kBestellung); - Mollie::getOrderCompletedRedirect($payment->kBestellung, true); - } elseif ($payment) { // payment, but no order => finalize it - require_once __DIR__ . '/../paymentmethod/JTLMollie.php'; - $order = JTLMollie::API()->orders->get($payment->kID, ['embed' => 'payments']); - $logData = '$' . $order->id . "§" . $payment->cOrderNumber; - Mollie::JTLMollie()->doLog('Hook 131/open => finalize?', $logData); - - - // GET NEWEST PAYMENT: - /** @var Payment $_payment */ - $_payment = null; - if ($order->payments()) { - /** @var Payment $p */ - foreach ($order->payments() as $p) { - if (!$_payment) { - $_payment = $p; - continue; - } - if (strtotime($p->createdAt) > strtotime($_payment->createdAt)) { - $_payment = $p; - } - } - } - // finalize only, if order is not canceld/expired - if ($order && !$order->isCanceled() && !$order->isExpired()) { - // finalize only if payment is not expired/canceled,failed or open - if ($_payment && !in_array($_payment->status, [PaymentStatus::STATUS_EXPIRED, PaymentStatus::STATUS_CANCELED, PaymentStatus::STATUS_OPEN, PaymentStatus::STATUS_FAILED])) { - - Mollie::JTLMollie()->doLog('Hook 131/open => finalize!', $logData, LOGLEVEL_DEBUG); - /** @noinspection PhpIncludeInspection */ - require_once PFAD_ROOT . 'includes/bestellabschluss_inc.php'; - /** @noinspection PhpIncludeInspection */ - require_once PFAD_ROOT . 'includes/mailTools.php'; - $session = Session::getInstance(); - $oBestellung = fakeBestellung(); - $oBestellung = finalisiereBestellung(); - $session->cleanUp(); - - if ($oBestellung->kBestellung > 0 && array_key_exists('cMollieHash', $_SESSION)) { - $_upd = new stdClass(); - $_upd->nBezahlt = 1; - $_upd->dZeitBezahlt = 'now()'; - $_upd->kBestellung = (int)$oBestellung->kBestellung; - Shop::DB()->update('tzahlungsession', 'cZahlungsID', $_SESSION['cMollieHash'], $_upd); - unset($_SESSION['cMollieHash']); - Jtllog::writeLog('tzahlungsession aktualisiert.', JTLLOG_LEVEL_DEBUG, false, 'Notify'); - } + require_once __DIR__ . '/../paymentmethod/JTLMollie.php'; + + if ($oZahlungSession = JTLMollie::getZahlungSession($_REQUEST['mollie'])) { - Mollie::JTLMollie()->doLog('Hook 131/finalized => bestellabschluss
' . print_r($order, 1) . '
', $logData); - Mollie::handleOrder($order, $oBestellung->kBestellung); - JTLMollie::API()->performHttpCall('PATCH', sprintf('payments/%s', $_payment->id), json_encode(['description' => $oBestellung->cBestellNr])); + $logData = '$' . $oZahlungSession->cNotifyID; - return Mollie::getOrderCompletedRedirect($oBestellung->kBestellung, true); + if (!(int)$oZahlungSession->kBestellung && $oZahlungSession->cNotifyID) { + // Bestellung noch nicht finalisiert + $mOrder = JTLMollie::API()->orders->get($oZahlungSession->cNotifyID, ['embed' => 'payments']); + if ($mOrder && $mOrder->id === $oZahlungSession->cNotifyID) { + 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) { + session_destroy(); + session_id($oZahlungSession->cSID); + $session = Session::getInstance(true, true); + } else { + $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(); + + if ($order->kBestellung > 0) { + $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: 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/Invalid Payment
' . print_r($payment, 1) . '
', $logData, LOGLEVEL_ERROR); - header('Location: ' . Shop::getURL() . '/bestellvorgang.php?editZahlungsart=1&mollieStatus=' . $_payment->status); + 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/Invalid Order
' . print_r($order, 1) . '
', $logData, LOGLEVEL_ERROR); - header('Location: ' . Shop::getURL() . '/bestellvorgang.php?editZahlungsart=1&mollieStatus=' . $order->status); - exit(); } + return Mollie::getOrderCompletedRedirect((int)$oZahlungSession->kBestellung, true); } } ob_end_flush(); } catch (Exception $e) { Helper::logExc($e); } + diff --git a/version/106/frontend/144_notify.php b/version/106/frontend/144_notify.php index fe19c10..35ed26a 100644 --- a/version/106/frontend/144_notify.php +++ b/version/106/frontend/144_notify.php @@ -6,54 +6,52 @@ * - ELSE weiter mit der notify.php */ -use Mollie\Api\Types\PaymentStatus; + use ws_mollie\Helper; -use ws_mollie\Model\Payment; use ws_mollie\Mollie; -if (array_key_exists('hash', $_REQUEST)) { +try { + require_once __DIR__ . '/../class/Helper.php'; - try { - Helper::init(); - $payment = Payment::getPaymentHash($_REQUEST['hash']); - // If Bestellung already exists, treat as Notification - if ($payment && $payment->kBestellung) { - require_once __DIR__ . '/../paymentmethod/JTLMollie.php'; - $order = JTLMollie::API()->orders->get($payment->kID, ['embed' => 'payments']); - $logData = '#' . $payment->kBestellung . '$' . $payment->kID; - Mollie::JTLMollie()->doLog('Notify/Hook 144/kBestellung>0
' . print_r([$order, $payment], 1) . '
', $logData); - Mollie::handleOrder($order, $payment->kBestellung); - // exit to stop execution of notify.php - - // GET NEWEST PAYMENT: - /** @var \Mollie\Api\Resources\Payment $_payment */ - $_payment = null; - if ($order->payments()) { - /** @var \Mollie\Api\Resources\Payment $p */ - foreach ($order->payments() as $p) { - if (!in_array($p->status, [PaymentStatus::STATUS_AUTHORIZED, PaymentStatus::STATUS_PAID, PaymentStatus::STATUS_PENDING])) { - continue; - } - if (!$_payment) { - $_payment = $p; - continue; - } - if (strtotime($p->createdAt) > strtotime($_payment->createdAt)) { - $_payment = $p; - } - } - } - - if ($payment->oBestellung instanceof Bestellung) { - JTLMollie::API()->performHttpCall('PATCH', sprintf('payments/%s', $_payment->id), json_encode(['description' => $payment->oBestellung->cBestellNr])); - } + 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 ((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 if($payment){ - $logData = '$' . $payment->kID; - Mollie::JTLMollie()->doLog('Notify/Hook 144/continue
' . print_r([$order, $payment], 1) . '
', $logData); + } else { + Mollie::JTLMollie()->doLog("Hook 144: orderId invalid: {$orderId} / {$oZahlungSession->cNotifyID}", $logData, LOGLEVEL_ERROR); } - } catch (Exception $e) { - Helper::logExc($e); + } else { + Mollie::JTLMollie()->doLog("Hook 144: couldn't load ZahlungSession => {$sh}", $logData, LOGLEVEL_DEBUG); } + +} catch (Exception $e) { + Helper::logExc($e); } diff --git a/version/106/paymentmethod/JTLMollie.php b/version/106/paymentmethod/JTLMollie.php index 1d59e04..c5a642b 100644 --- a/version/106/paymentmethod/JTLMollie.php +++ b/version/106/paymentmethod/JTLMollie.php @@ -5,7 +5,6 @@ use Mollie\Api\MollieApiClient; use Mollie\Api\Types\OrderLineType; use Mollie\Api\Types\OrderStatus; -use Mollie\Api\Types\PaymentStatus; use ws_mollie\Helper; use ws_mollie\Model\Payment; use ws_mollie\Mollie; @@ -72,7 +71,6 @@ public static function Helper() */ public function addIncomingPayment($order, $payment) { - Helper::init(); $model = (object)array_merge([ 'kBestellung' => (int)$order->kBestellung, 'cZahlungsanbieter' => empty($order->cZahlungsartName) ? $this->name : $order->cZahlungsartName, @@ -107,7 +105,8 @@ public function addIncomingPayment($order, $payment) */ public function doLog($msg, $data = null, $level = LOGLEVEL_NOTICE) { - ZahlungsLog::add($this->moduleID, $msg, $data, $level); + //ZahlungsLog::add($this->moduleID, $msg, $data, $level); + ZahlungsLog::add($this->moduleID, "[" . $_SERVER['PHP_SELF'] . "] " . $msg, $data, $level); return $this; } @@ -130,43 +129,64 @@ public function setOrderStatusToPaid($order) * Tells Template Engine. * * @param Bestellung $order + * @return bool|string */ public function preparePaymentProcess($order) { - Helper::init(); $logData = '#' . $order->kBestellung . "§" . $order->cBestellNr; + + $payable = (float)$order->fGesamtsumme > 0; + try { if ($order->kBestellung) { - $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(); + 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(); } - 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 \Mollie\Api\Resources\Order)) { $hash = $this->generateHash($order); - $_SESSION['cMollieHash'] = $hash; + //$_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($hash)); + Payment::updateFromPayment($oMolliePayment, $order->kBestellung, md5(trim($hash, '_'))); Shop::Smarty()->assign('oMolliePayment', $oMolliePayment); if (!$this->duringCheckout) { Session::getInstance()->cleanUp(); @@ -223,8 +243,8 @@ protected function getOrderData(Bestellung $order, $hash) 'lines' => [], 'billingAddress' => new stdClass(), - 'redirectUrl' => (int)$this->duringCheckout ? Shop::getURL() . '/bestellabschluss.php?mollie=' . md5($hash) : $this->getReturnURL($order), - 'webhookUrl' => $this->getNotificationURL($hash) . '&hash=' . md5($hash), + '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 !== '') { @@ -447,6 +467,14 @@ public function optionaleRundung($gesamtsumme) return $gesamtsumme; } + 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 @@ -459,31 +487,10 @@ public function handleNotification($order, $hash, $args) $this->doLog('JTLMollie::handleNotification
' . print_r([$hash, $args], 1) . '
', $logData, LOGLEVEL_DEBUG); try { - Helper::init(); + $oMolliePayment = self::API()->orders->get($args['id'], ['embed' => 'payments']); Mollie::handleOrder($oMolliePayment, $order->kBestellung); - // GET NEWEST PAYMENT: - /** @var \Mollie\Api\Resources\Payment $_payment */ - $_payment = null; - if ($oMolliePayment->payments()) { - /** @var \Mollie\Api\Resources\Payment $p */ - foreach ($oMolliePayment->payments() as $p) { - if (!in_array($p->status, [PaymentStatus::STATUS_AUTHORIZED, PaymentStatus::STATUS_PAID, PaymentStatus::STATUS_PENDING])) { - continue; - } - if (!$_payment) { - $_payment = $p; - continue; - } - if (strtotime($p->createdAt) > strtotime($_payment->createdAt)) { - $_payment = $p; - } - } - } - - JTLMollie::API()->performHttpCall('PATCH', sprintf('payments/%s', $_payment->id), json_encode(['description' => $order->cBestellNr])); - } catch (Exception $e) { $this->doLog('JTLMollie::handleNotification: ' . $e->getMessage(), $logData); } @@ -498,20 +505,26 @@ public function handleNotification($order, $hash, $args) */ public function finalizeOrder($order, $hash, $args) { - $logData = '#' . $order->kBestellung . "§" . $order->cBestellNr; + $result = false; try { - Helper::init(); - $oMolliePayment = self::API()->orders->get($args['id'], ['embed' => 'payments']); - $logData .= '$' . $oMolliePayment->id; - - $result = in_array($oMolliePayment->status, [OrderStatus::STATUS_PAID, OrderStatus::STATUS_AUTHORIZED, OrderStatus::STATUS_PENDING, OrderStatus::STATUS_COMPLETED]); - Payment::updateFromPayment($oMolliePayment, $order->kBestellung); - $this->doLog('JTLMollie::finalizeOrder (' . ($result ? 'true' : 'false') . ')
' . print_r([$hash, $args, $oMolliePayment], 1) . '
', $logData, LOGLEVEL_DEBUG); - return $result; + if ($oZahlungSession = self::getZahlungSession(md5($hash))) { + if ((int)$oZahlungSession->kBestellung <= 0) { + $oOrder = self::API()->orders->get($args['id'], ['embed' => 'payments']); + $logData = '$' . $oOrder->id; + $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(), $logData); + $this->doLog('JTLMollie::finalizeOrder: ' . $e->getMessage(), "#" . $hash); } - return false; + return $result; + } + + public static function getZahlungSession($hash) + { + return Shop::DB()->executeQueryPrepared("SELECT * FROM tzahlungsession WHERE MD5(cZahlungsID) = :cZahlungsID", [':cZahlungsID' => trim($hash, '_')], 1); } /** @@ -598,10 +611,10 @@ protected static function PossiblePaymentMethods($method, $locale, $billingCount */ protected function updatePaymentMethod($cISOSprache, $method) { - if (ws_mollie\Helper::getSetting('paymentmethod_sync') === 'N') { + if (Helper::getSetting('paymentmethod_sync') === 'N') { return; } - $size = ws_mollie\Helper::getSetting('paymentmethod_sync'); + $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); } @@ -624,7 +637,7 @@ protected function updatePaymentMethod($cISOSprache, $method) */ public function isValidIntern($args_arr = []) { - if (Helper::init() && Helper::getSetting("api_key")) { + if (Helper::getSetting("api_key")) { return true; } $this->doLog("isValdid failed: init failed or no API Key given. Try clear the Cache."); From 4f90174c5761047abbc4e00b46c5849c9c36dd57 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Mon, 16 Dec 2019 17:48:15 +0100 Subject: [PATCH 110/280] fix notices --- version/106/frontend/144_notify.php | 2 +- version/106/paymentmethod/JTLMollie.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/version/106/frontend/144_notify.php b/version/106/frontend/144_notify.php index 35ed26a..65e24e3 100644 --- a/version/106/frontend/144_notify.php +++ b/version/106/frontend/144_notify.php @@ -18,7 +18,7 @@ require_once __DIR__ . '/../paymentmethod/JTLMollie.php'; - $orderID = array_key_exists('id', $_REQUEST) ? $_REQUEST['id'] : false; + $orderId = array_key_exists('id', $_REQUEST) ? $_REQUEST['id'] : false; if (!$orderId) { // NOT A MOLLIE NOTIFICATION! return; diff --git a/version/106/paymentmethod/JTLMollie.php b/version/106/paymentmethod/JTLMollie.php index c5a642b..ec80516 100644 --- a/version/106/paymentmethod/JTLMollie.php +++ b/version/106/paymentmethod/JTLMollie.php @@ -84,7 +84,7 @@ public function addIncomingPayment($order, $payment) 'cAbgeholt' => 'N' ], (array)$payment); - $logData = '#' . $order->kBestellung . '$' . $payment->id; + $logData = '#' . $order->kBestellung; if (isset($model->kZahlungseingang) && $model->kZahlungseingang > 0) { Mollie::JTLMollie()->doLog('JTLMollie::addIncomingPayment (update)
' . print_r([$model, $payment], 1) . '
', $logData); From 0c8863b5cbe09e529adc40d63d4d12098cf5875b Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Tue, 17 Dec 2019 16:37:49 +0100 Subject: [PATCH 111/280] fix #58 --- info.xml | 20 +++++++++---------- version/106/frontend/140_smarty.php | 14 ++++++++++++- .../106/paymentmethod/JTLMollieCreditCard.php | 6 +++--- 3 files changed, 26 insertions(+), 14 deletions(-) diff --git a/info.xml b/info.xml index c7f96e5..7af3fc8 100644 --- a/info.xml +++ b/info.xml @@ -1,9 +1,9 @@ mollie - Zahlungsartplugin fr mollie.com + Zahlungsartplugin für mollie.com WebStollen - http://www.webstollen.de/ + https://www.webstollen.de/ 102 ws_mollie 405 @@ -75,7 +75,7 @@ error_failed Bei der Zahlung ist ein Fehler aufgetreten. Bitte versuchen Sie es erneut, - oder whlen Sie eine andere Zahlungsart. + oder wählen Sie eine andere Zahlungsart. The payment process failed. Please try again or choose a different payment method. @@ -140,12 +140,12 @@ Einstellungen API Key: - Fge hier deinen mollie API Key ein + Füge hier deinen mollie API Key ein api_key Profile ID: - Fge hier deinen mollie Profil ID ein. Wird bentigt um mollie Components zu aktivieren + Füge hier deinen mollie Profil ID (pfl_) ein. Wird benötigt um mollie Components zu aktivieren profileId @@ -160,20 +160,20 @@ Zahlungsart Daten syncronisiernen - Ldt Name / Bild fr die jeweilige Sprache automatisch von mollie, und speichert diese + Lädt Name / Bild für die jeweilige Sprache automatisch von mollie, und speichert diese in der Datenbank paymentmethod_sync - - + + Checkout Styles laden - Ldt Stylesheets fr das Evo Template, um den Checkout zu verschnern. + Lädt Stylesheets für das Evo Template, um den Checkout zu verschönern. load_styles @@ -184,7 +184,7 @@ TransaktionsID des Zahlungseingangs: - Welche ID soll an die WAWI betragen werden? + Welche ID soll an die WAWI übetragen werden? wawiPaymentID diff --git a/version/106/frontend/140_smarty.php b/version/106/frontend/140_smarty.php index 53360d6..0213117 100644 --- a/version/106/frontend/140_smarty.php +++ b/version/106/frontend/140_smarty.php @@ -12,6 +12,19 @@ $text = Helper::oPlugin()->oPluginSprachvariableAssoc_arr['error_' . $status]; pq('#fieldset-payment')->prepend('
' . $text . '
'); } + + $applePayId = "kPlugin_".Helper::oPlugin()->kPlugin."_mollieapplepay"; +pq('body')->append(<< +// +HTML +); switch (Helper::getSetting('load_styles')) { case 'Y': @@ -32,7 +45,6 @@ $lh = "40px"; } - pq('head')->append( << diff --git a/version/106/paymentmethod/JTLMollieCreditCard.php b/version/106/paymentmethod/JTLMollieCreditCard.php index 18d00d4..ebae27b 100644 --- a/version/106/paymentmethod/JTLMollieCreditCard.php +++ b/version/106/paymentmethod/JTLMollieCreditCard.php @@ -11,8 +11,8 @@ class JTLMollieCreditCard extends JTLMollie public function handleAdditional($aPost_arr) { - - if (trim(Helper::getSetting('profileId')) === '') { + $profileId = trim(Helper::getSetting('profileId')); + if ($profileId === '' || strpos($profileId, 'pfl_') !== 0) { return true; } @@ -23,7 +23,7 @@ public function handleAdditional($aPost_arr) return true; } - Shop::Smarty()->assign('profileId', trim(Helper::getSetting('profileId'))) + Shop::Smarty()->assign('profileId',$profileId) ->assign('locale', self::getLocale($_SESSION['cISOSprache'], $_SESSION['Kunde']->cLand)) ->assign('testmode', strpos(Helper::getSetting('api_key'), 'test_') === 0) ->assign('mollieLang', Helper::oPlugin()->oPluginSprachvariableAssoc_arr) From ac5529b5e61a632e7d4284eb97bab48e4fc837d5 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Tue, 17 Dec 2019 16:56:28 +0100 Subject: [PATCH 112/280] limit orders, webstollen CDN --- version/106/adminmenu/orders.php | 2 +- version/106/adminmenu/tpl/orders.tpl | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/version/106/adminmenu/orders.php b/version/106/adminmenu/orders.php index 99603ed..3d24bb0 100644 --- a/version/106/adminmenu/orders.php +++ b/version/106/adminmenu/orders.php @@ -134,7 +134,7 @@ } - $payments = Shop::DB()->executeQueryPrepared("SELECT * FROM xplugin_ws_mollie_payments WHERE kBestellung IS NOT NULL AND cStatus != 'created'", [], 2); + $payments = Shop::DB()->executeQueryPrepared("SELECT * FROM xplugin_ws_mollie_payments WHERE kBestellung IS NOT NULL AND cStatus != 'created' LIMIT 1000;", [], 2); foreach ($payments as $i => $payment) { $payments[$i]->oBestellung = new Bestellung($payment->kBestellung, false); } diff --git a/version/106/adminmenu/tpl/orders.tpl b/version/106/adminmenu/tpl/orders.tpl index df024b4..fd1c5a8 100644 --- a/version/106/adminmenu/tpl/orders.tpl +++ b/version/106/adminmenu/tpl/orders.tpl @@ -92,7 +92,10 @@ {/foreach}
- + {if $payments|count > 900} +
Hier werden nur die letzten 1000 Ergebnisse angezeigt.
+ {/if} + "; @@ -49,6 +50,14 @@ } 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); diff --git a/version/106/adminmenu/tpl/info.tpl b/version/106/adminmenu/tpl/info.tpl index da2a55a..77a48dc 100644 --- a/version/106/adminmenu/tpl/info.tpl +++ b/version/106/adminmenu/tpl/info.tpl @@ -91,3 +91,6 @@ +{if file_exists("{$smarty['current_dir']}/_addon.tpl")} + {include file="{$smarty['current_dir']}/_addon.tpl"} +{/if} \ No newline at end of file From 056f463726fda7b209a5623850b7c078b8d1d145 Mon Sep 17 00:00:00 2001 From: "dash.bar" Date: Wed, 18 Dec 2019 08:30:03 +0000 Subject: [PATCH 115/280] prepare finalize --- info.xml | 1104 +++++++++++++++++++++++++++--------------------------- 1 file changed, 547 insertions(+), 557 deletions(-) diff --git a/info.xml b/info.xml index 7af3fc8..046f379 100644 --- a/info.xml +++ b/info.xml @@ -1,568 +1,558 @@ - - - mollie - Zahlungsartplugin für mollie.com - WebStollen - https://www.webstollen.de/ - 102 - ws_mollie - 405 - - - 100.sql - 2019-02-11 - - - 2019-02-26 - - - 2019-04-23 - - - 2019-05-22 - - - 2019-07-12 - - - 2019-11-26 - - + + mollie + Zahlungsartplugin für mollie.com + WebStollen + https://www.webstollen.de/ + 102 + ws_mollie + 405 + + + 100.sql + 2019-02-11 + + + 2019-02-26 + + + 2019-04-23 + + + 2019-05-22 + + + 2019-07-12 + + 2019-11-26 - - - 131_globalinclude.php - 144_notify.php - 181_sync.php - 140_smarty.php - - - - cctitle - - Zahlungsinformationen - Enter your payment information - - - error_canceled - - Die Zahlung wurde von Ihnen abgebrochen. Wählen Sie ggf. eine andere + + 2019-12-18 + + + 131_globalinclude.php + 144_notify.php + 181_sync.php + 140_smarty.php + + + + Bestellungen + orders.php + + + Zahlungsarten + paymentmethods.php + + + Info + info.php + + + Einstellungen + + API Key: + Füge hier deinen mollie API Key ein + api_key + + + Profile ID: + Füge hier deinen mollie Profil ID (pfl_) ein. Wird benötigt um mollie Components zu aktivieren + profileId + + + Trust-Grafik bei mollie Components anzeigen: + Bindet eine Trust-Grafik unterhalb des Kreditkartenformulars ein. + loadTrust + + + + + + + Zahlungsart Daten syncronisiernen + Lädt Name / Bild für die jeweilige Sprache automatisch von mollie, und speichert diese in der Datenbank + paymentmethod_sync + + + + + + + + + Checkout Styles laden + Lädt Stylesheets für das Evo Template, um den Checkout zu verschönern. + load_styles + + + + + + + + TransaktionsID des Zahlungseingangs: + Welche ID soll an die WAWI übetragen werden? + wawiPaymentID + + + + + + + + Workflow-Secret: + Schlüssel, um die WAWI Workflow-Requests zu authentifizieren. + workflowSecret + + + + + + cctitle + + + + + + error_canceled + + - You canceled the payment. Please select a different payment method if + ]]> + - - - error_expired - - Ihre Zahlungssession ist abgelaufen, bitte versuchen Sie es erneut. - - Your payment session has expired, please try again. - - - error_open - - Bei der Zahlung ist ein Fehler aufgetreten. Bitte versuchen Sie es erneut, + ]]> + + + error_expired + + + + + + error_open + + - The payment process failed. Please try again or choose a different payment + ]]> + - - - error_failed - - Bei der Zahlung ist ein Fehler aufgetreten. Bitte versuchen Sie es erneut, + ]]> + + + error_failed + + - The payment process failed. Please try again or choose a different payment + ]]> + - - - lbl_cardHolder - - Karteninhaber: - Card holder: - - - lbl_cardNumber - - Kartennummer: - Card number: - - - lbl_expiryDate - - Ablaufdatum: - Expiry date: - - - lbl_varificationCode - - CVC: - CVC: - - - - cvchint_1 - - So findet man die CVV/CVC Nummer - How to find the CVV/CVC number - - - cvchint_2 - - Die dreistellige CVV/CVC Nummer wird bei Visa und Mastercard auf der Rückseite, + ]]> + + + lbl_cardHolder + + + + + + lbl_cardNumber + + + + + + lbl_expiryDate + + + + + + lbl_varificationCode + + + + + + cvchint_1 + + + + + + cvchint_2 + + - The three-digit CVV/CVC number is shown on the reverse for Visa and Mastercard, + ]]> + - - - - - Bestellungen - orders.php - - - Zahlungsarten - paymentmethods.php - - - Info - info.php - - - Einstellungen - - API Key: - Füge hier deinen mollie API Key ein - api_key - - - Profile ID: - Füge hier deinen mollie Profil ID (pfl_) ein. Wird benötigt um mollie Components zu aktivieren - profileId - - - - Trust-Grafik bei mollie Components anzeigen: - Bindet eine Trust-Grafik unterhalb des Kreditkartenformulars ein. - loadTrust - - - - - - - Zahlungsart Daten syncronisiernen - Lädt Name / Bild für die jeweilige Sprache automatisch von mollie, und speichert diese - in der Datenbank - - paymentmethod_sync - - - - - - - - - Checkout Styles laden - Lädt Stylesheets für das Evo Template, um den Checkout zu verschönern. - load_styles - - - - - - - - - TransaktionsID des Zahlungseingangs: - Welche ID soll an die WAWI übetragen werden? - wawiPaymentID - - - - - - - - - Workflow-Secret: - Schlüssel, um die WAWI Workflow-Requests zu authentifizieren. - workflowSecret - - - - - - - mollie - - 1 - 0 - mollie.com - OTHER - 0 - 0 - 1 - 0 - JTLMollie.php - JTLMollie - tpl/bestellabschluss.tpl - - mollie - mollie - Bezahlen Sie bequem mit verschiedenen Zahlungsmethoden. - - - - mollie Kreditkarte - - 3 - tpl/mollieComponents.tpl - 0 - mollie.com - CREDIT_CARD - 1 - 0 - 1 - 0 - JTLMollieCreditCard.php - JTLMollieCreditCard - tpl/bestellabschluss.tpl - - Kreditkarte - mollie - Bezahlen Sie bequem mit Kreditkarte. - - - - mollie Apple Pay - - 3 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMollieApplePay.php - JTLMollieApplePay - tpl/bestellabschluss.tpl - - Apple Pay - mollie - Bezahlen Sie bequem mit Apple Pay. - - - - mollie Bancontact - - 4 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMollieBancontact.php - JTLMollieBancontact - tpl/bestellabschluss.tpl - - Bancontact - mollie - Bezahlen Sie bequem mit Bancontact. - - - - mollie Banktransfer - - 5 - 0 - mollie.com - OTHER - 0 - 0 - 1 - 0 - JTLMollieBanktransfer.php - JTLMollieBanktransfer - tpl/bestellabschluss.tpl - - SEPA Überweisung - mollie - Bezahlen Sie bequem mit SEPA Überweisung. - - - - mollie Belfius - - 6 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMollieBelfius.php - JTLMollieBelfius - tpl/bestellabschluss.tpl - - Belfius - mollie - Bezahlen Sie bequem mit Belfius. - - - - mollie DirectDebit - - 7 - 0 - mollie.com - DIRECT_DEBIT - 1 - 0 - 1 - 0 - JTLMollieDirectDebit.php - JTLMollieDirectDebit - tpl/bestellabschluss.tpl - - SEPA Lastschrift - mollie - Bezahlen Sie bequem mit SEPA Lastschrift. - - - - mollie EPS - - 2 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMollieEPS.php - JTLMollieEPS - tpl/bestellabschluss.tpl - - EPS - mollie - Bezahlen Sie bequem mit EPS. - - - - mollie Giftcard - - 8 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMollieGiftcard.php - JTLMollieGiftcard - tpl/bestellabschluss.tpl - - Gift cards - mollie - Bezahlen Sie bequem mit Gift cards. - - - - mollie Giropay - - 9 - 0 - mollie.com - GIROPAY - 1 - 0 - 1 - 0 - JTLMollieGiropay.php - JTLMollieGiropay - tpl/bestellabschluss.tpl - - Giropay - mollie - Bezahlen Sie bequem mit Giropay. - - - - mollie iDEAL - - 10 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMollieIDEAL.php - JTLMollieIDEAL - tpl/bestellabschluss.tpl - - Giropay - mollie - Bezahlen Sie bequem mit iDEAL. - - - - mollie ING HomePay - - 11 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMollieINGHomePay.php - JTLMollieINGHomePay - tpl/bestellabschluss.tpl - - ING HomePay - mollie - Bezahlen Sie bequem mit ING HomePay. - - - - mollie KBC - - 12 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMollieKBC.php - JTLMollieKBC - tpl/bestellabschluss.tpl - - KBC - mollie - Bezahlen Sie bequem mit KBC. - - - - mollie PayPal - - 13 - 0 - mollie.com - PAYPAL - 1 - 0 - 1 - 0 - JTLMolliePayPal.php - JTLMolliePayPal - tpl/bestellabschluss.tpl - - PayPal - mollie - Bezahlen Sie bequem mit PayPal. - - - - mollie paysafecard - - 14 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMolliePaysafecard.php - JTLMolliePaysafecard - tpl/bestellabschluss.tpl - - paysafecard - mollie - Bezahlen Sie bequem mit paysafecard. - - - - mollie SOFORT - - 15 - 0 - mollie.com - DIRECT_E_BANKING - 1 - 0 - 1 - 0 - JTLMollieSofort.php - JTLMollieSofort - tpl/bestellabschluss.tpl - - SOFORT - mollie - Bezahlen Sie bequem mit SOFORT. - - - - mollie Klarna Pay Later - - 16 - 0 - mollie.com - INVOICE - 1 - 0 - 1 - 0 - JTLMollieKlarnaPayLater.php - JTLMollieKlarnaPayLater - tpl/bestellabschluss.tpl - - Klarna Pay Later - mollie - Bezahlen Sie bequem mit Klarna Pay Later. - - - - mollie Klarna Slice It - - 17 - 0 - mollie.com - FINANCING - 1 - 0 - 1 - 0 - JTLMollieKlarnaSliceIt.php - JTLMollieKlarnaSliceIt - tpl/bestellabschluss.tpl - - Klarna Slice It - mollie - Bezahlen Sie bequem mit Klarna Slice It. - - - - + ]]> + + + + + mollie + + 1 + 0 + mollie.com + OTHER + 0 + 0 + 1 + 0 + JTLMollie.php + JTLMollie + tpl/bestellabschluss.tpl + + mollie + mollie + Bezahlen Sie bequem mit verschiedenen Zahlungsmethoden. + + + + mollie Kreditkarte + + 3 + 0 + mollie.com + CREDIT_CARD + 1 + 0 + 1 + 0 + JTLMollieCreditCard.php + JTLMollieCreditCard + tpl/bestellabschluss.tpl + + Kreditkarte + mollie + Bezahlen Sie bequem mit Kreditkarte. + + + + mollie Apple Pay + + 3 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMollieApplePay.php + JTLMollieApplePay + tpl/bestellabschluss.tpl + + Apple Pay + mollie + Bezahlen Sie bequem mit Apple Pay. + + + + mollie Bancontact + + 4 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMollieBancontact.php + JTLMollieBancontact + tpl/bestellabschluss.tpl + + Bancontact + mollie + Bezahlen Sie bequem mit Bancontact. + + + + mollie Banktransfer + + 5 + 0 + mollie.com + OTHER + 0 + 0 + 1 + 0 + JTLMollieBanktransfer.php + JTLMollieBanktransfer + tpl/bestellabschluss.tpl + + SEPA Überweisung + mollie + Bezahlen Sie bequem mit SEPA Überweisung. + + + + mollie Belfius + + 6 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMollieBelfius.php + JTLMollieBelfius + tpl/bestellabschluss.tpl + + Belfius + mollie + Bezahlen Sie bequem mit Belfius. + + + + mollie DirectDebit + + 7 + 0 + mollie.com + DIRECT_DEBIT + 1 + 0 + 1 + 0 + JTLMollieDirectDebit.php + JTLMollieDirectDebit + tpl/bestellabschluss.tpl + + SEPA Lastschrift + mollie + Bezahlen Sie bequem mit SEPA Lastschrift. + + + + mollie EPS + + 2 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMollieEPS.php + JTLMollieEPS + tpl/bestellabschluss.tpl + + EPS + mollie + Bezahlen Sie bequem mit EPS. + + + + mollie Giftcard + + 8 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMollieGiftcard.php + JTLMollieGiftcard + tpl/bestellabschluss.tpl + + Gift cards + mollie + Bezahlen Sie bequem mit Gift cards. + + + + mollie Giropay + + 9 + 0 + mollie.com + GIROPAY + 1 + 0 + 1 + 0 + JTLMollieGiropay.php + JTLMollieGiropay + tpl/bestellabschluss.tpl + + Giropay + mollie + Bezahlen Sie bequem mit Giropay. + + + + mollie iDEAL + + 10 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMollieIDEAL.php + JTLMollieIDEAL + tpl/bestellabschluss.tpl + + Giropay + mollie + Bezahlen Sie bequem mit iDEAL. + + + + mollie ING HomePay + + 11 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMollieINGHomePay.php + JTLMollieINGHomePay + tpl/bestellabschluss.tpl + + ING HomePay + mollie + Bezahlen Sie bequem mit ING HomePay. + + + + mollie KBC + + 12 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMollieKBC.php + JTLMollieKBC + tpl/bestellabschluss.tpl + + KBC + mollie + Bezahlen Sie bequem mit KBC. + + + + mollie PayPal + + 13 + 0 + mollie.com + PAYPAL + 1 + 0 + 1 + 0 + JTLMolliePayPal.php + JTLMolliePayPal + tpl/bestellabschluss.tpl + + PayPal + mollie + Bezahlen Sie bequem mit PayPal. + + + + mollie paysafecard + + 14 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMolliePaysafecard.php + JTLMolliePaysafecard + tpl/bestellabschluss.tpl + + paysafecard + mollie + Bezahlen Sie bequem mit paysafecard. + + + + mollie SOFORT + + 15 + 0 + mollie.com + DIRECT_E_BANKING + 1 + 0 + 1 + 0 + JTLMollieSofort.php + JTLMollieSofort + tpl/bestellabschluss.tpl + + SOFORT + mollie + Bezahlen Sie bequem mit SOFORT. + + + + mollie Klarna Pay Later + + 16 + 0 + mollie.com + INVOICE + 1 + 0 + 1 + 0 + JTLMollieKlarnaPayLater.php + JTLMollieKlarnaPayLater + tpl/bestellabschluss.tpl + + Klarna Pay Later + mollie + Bezahlen Sie bequem mit Klarna Pay Later. + + + + mollie Klarna Slice It + + 17 + 0 + mollie.com + FINANCING + 1 + 0 + 1 + 0 + JTLMollieKlarnaSliceIt.php + JTLMollieKlarnaSliceIt + tpl/bestellabschluss.tpl + + Klarna Slice It + mollie + Bezahlen Sie bequem mit Klarna Slice It. + + + + \ No newline at end of file From 946caf9ca8a77e1a507b065b0cb3159ceba51f57 Mon Sep 17 00:00:00 2001 From: "dash.bar" Date: Wed, 18 Dec 2019 08:30:04 +0000 Subject: [PATCH 116/280] init version 107 --- info.xml | 3 + version/107/adminmenu/info.php | 64 ++ version/107/adminmenu/orders.php | 154 +++++ version/107/adminmenu/paymentmethods.php | 60 ++ version/107/adminmenu/tpl/info.tpl | 96 +++ .../tpl/mollie-account-erstellen.png | Bin 0 -> 38998 bytes version/107/adminmenu/tpl/order.tpl | 286 ++++++++ version/107/adminmenu/tpl/orders.tpl | 116 ++++ version/107/adminmenu/tpl/paymentmethods.tpl | 97 +++ version/107/class/Helper.php | 311 +++++++++ version/107/class/Model/AbstractModel.php | 7 + version/107/class/Model/Payment.php | 84 +++ version/107/class/Mollie.php | 508 ++++++++++++++ version/107/frontend/131_globalinclude.php | 84 +++ version/107/frontend/140_smarty.php | 71 ++ version/107/frontend/144_notify.php | 57 ++ version/107/frontend/181_sync.php | 43 ++ version/107/frontend/img/trust_eng.png | Bin 0 -> 15299 bytes version/107/frontend/img/trust_fre.png | Bin 0 -> 17319 bytes version/107/frontend/img/trust_ger.png | Bin 0 -> 15352 bytes version/107/paymentmethod/JTLMollie.php | 646 ++++++++++++++++++ .../107/paymentmethod/JTLMollieApplePay.php | 8 + .../107/paymentmethod/JTLMollieBancontact.php | 8 + .../paymentmethod/JTLMollieBanktransfer.php | 10 + .../107/paymentmethod/JTLMollieBelfius.php | 8 + .../107/paymentmethod/JTLMollieCreditCard.php | 36 + .../paymentmethod/JTLMollieDirectDebit.php | 8 + version/107/paymentmethod/JTLMollieEPS.php | 8 + .../107/paymentmethod/JTLMollieGiftcard.php | 8 + .../107/paymentmethod/JTLMollieGiropay.php | 8 + version/107/paymentmethod/JTLMollieIDEAL.php | 8 + .../107/paymentmethod/JTLMollieINGHomePay.php | 8 + version/107/paymentmethod/JTLMollieKBC.php | 8 + .../paymentmethod/JTLMollieKlarnaPayLater.php | 8 + .../paymentmethod/JTLMollieKlarnaSliceIt.php | 8 + version/107/paymentmethod/JTLMolliePayPal.php | 8 + .../paymentmethod/JTLMolliePaysafecard.php | 8 + version/107/paymentmethod/JTLMollieSofort.php | 8 + .../paymentmethod/tpl/bestellabschluss.tpl | 5 + .../paymentmethod/tpl/mollieComponents.tpl | 101 +++ 40 files changed, 2959 insertions(+) create mode 100644 version/107/adminmenu/info.php create mode 100644 version/107/adminmenu/orders.php create mode 100644 version/107/adminmenu/paymentmethods.php create mode 100644 version/107/adminmenu/tpl/info.tpl create mode 100644 version/107/adminmenu/tpl/mollie-account-erstellen.png create mode 100644 version/107/adminmenu/tpl/order.tpl create mode 100644 version/107/adminmenu/tpl/orders.tpl create mode 100644 version/107/adminmenu/tpl/paymentmethods.tpl create mode 100644 version/107/class/Helper.php create mode 100644 version/107/class/Model/AbstractModel.php create mode 100644 version/107/class/Model/Payment.php create mode 100644 version/107/class/Mollie.php create mode 100644 version/107/frontend/131_globalinclude.php create mode 100644 version/107/frontend/140_smarty.php create mode 100644 version/107/frontend/144_notify.php create mode 100644 version/107/frontend/181_sync.php create mode 100644 version/107/frontend/img/trust_eng.png create mode 100644 version/107/frontend/img/trust_fre.png create mode 100644 version/107/frontend/img/trust_ger.png create mode 100644 version/107/paymentmethod/JTLMollie.php create mode 100644 version/107/paymentmethod/JTLMollieApplePay.php create mode 100644 version/107/paymentmethod/JTLMollieBancontact.php create mode 100644 version/107/paymentmethod/JTLMollieBanktransfer.php create mode 100644 version/107/paymentmethod/JTLMollieBelfius.php create mode 100644 version/107/paymentmethod/JTLMollieCreditCard.php create mode 100644 version/107/paymentmethod/JTLMollieDirectDebit.php create mode 100644 version/107/paymentmethod/JTLMollieEPS.php create mode 100644 version/107/paymentmethod/JTLMollieGiftcard.php create mode 100644 version/107/paymentmethod/JTLMollieGiropay.php create mode 100644 version/107/paymentmethod/JTLMollieIDEAL.php create mode 100644 version/107/paymentmethod/JTLMollieINGHomePay.php create mode 100644 version/107/paymentmethod/JTLMollieKBC.php create mode 100644 version/107/paymentmethod/JTLMollieKlarnaPayLater.php create mode 100644 version/107/paymentmethod/JTLMollieKlarnaSliceIt.php create mode 100644 version/107/paymentmethod/JTLMolliePayPal.php create mode 100644 version/107/paymentmethod/JTLMolliePaysafecard.php create mode 100644 version/107/paymentmethod/JTLMollieSofort.php create mode 100644 version/107/paymentmethod/tpl/bestellabschluss.tpl create mode 100644 version/107/paymentmethod/tpl/mollieComponents.tpl diff --git a/info.xml b/info.xml index 046f379..367b90c 100644 --- a/info.xml +++ b/info.xml @@ -29,6 +29,9 @@ 2019-12-18 + + 2019-12-18 + 131_globalinclude.php 144_notify.php diff --git a/version/107/adminmenu/info.php b/version/107/adminmenu/info.php new file mode 100644 index 0000000..292064e --- /dev/null +++ b/version/107/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 "
" . + "
" . + " " . + " Lizenz Informationen" . + ' ' . + '
' . + "
" . + " " . + " Update Informationen" . + ' ' . + '
' . + "
" . + " " . + " Plugin informationen" . + ' ' . + '
' . + '
'; + + 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/107/adminmenu/orders.php b/version/107/adminmenu/orders.php new file mode 100644 index 0000000..e34ac14 --- /dev/null +++ b/version/107/adminmenu/orders.php @@ -0,0 +1,154 @@ + 'danger', 'text' => 'Keine ID angeben!']; + break; + } + $payment = Payment::getPaymentMollie($_REQUEST['id']); + if (!$payment) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; + break; + } + + $order = JTLMollie::API()->orders->get($_REQUEST['id']); + if ($order->status == OrderStatus::STATUS_CANCELED) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung bereits storniert']; + 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; + break; + + case 'cancel': + if (!array_key_exists('id', $_REQUEST)) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; + break; + } + $payment = Payment::getPaymentMollie($_REQUEST['id']); + if (!$payment) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; + break; + } + $order = JTLMollie::API()->orders->get($_REQUEST['id']); + if ($order->status == OrderStatus::STATUS_CANCELED) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung bereits storniert']; + 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; + break; + + case 'capture': + if (!array_key_exists('id', $_REQUEST)) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; + break; + } + $payment = Payment::getPaymentMollie($_REQUEST['id']); + if (!$payment) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; + break; + } + $order = JTLMollie::API()->orders->get($_REQUEST['id']); + if ($order->status !== OrderStatus::STATUS_AUTHORIZED && $order->status !== OrderStatus::STATUS_SHIPPING) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Nur autorisierte Zahlungen können erfasst werden!']; + break; + } + + $oBestellung = new Bestellung($payment->kBestellung, true); + if (!$oBestellung->kBestellung) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung konnte nicht geladen werden!']; + break; + } + + $logData = '#' . $payment->kBestellung . '$' . $payment->kID . "§" . $oBestellung->cBestellNr; + + $options = ['lines' => []]; + if ($oBestellung->cTracking) { + $tracking = new stdClass(); + $tracking->carrier = $oBestellung->cVersandartName; + $tracking->url = $oBestellung->cTrackingURL; + $tracking->code = $oBestellung->cTracking; + $options['tracking'] = $tracking; + } + + // CAPTURE ALL + $shipment = JTLMollie::API()->shipments->createFor($order, $options); + $ordersMsgs[] = (object)['type' => 'success', 'text' => 'Zahlung wurde erfolgreich erfasst!']; + Mollie::JTLMollie()->doLog('Shipment created
' . print_r(['options' => $options, 'shipment' => $shipment], 1) . '
', $logData); + goto order; + + case 'order': + order: + if (!array_key_exists('id', $_REQUEST)) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; + 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", [ + ':kBestellung' => '%#' . ($payment->kBestellung ?: '##') . '%', + ':cBestellNr' => '%§' . ($payment->cOrderNumber ?: '§§') . '%', + ':MollieID' => '%$' . ($payment->kID ?: '$$') . '%', + ], 2); + + Shop::Smarty()->assign('payment', $payment) + ->assign('oBestellung', $oBestellung) + ->assign('order', $order) + ->assign('logs', $logs) + ->assign('ordersMsgs', $ordersMsgs); + Shop::Smarty()->display($oPlugin->cAdminmenuPfad . '/tpl/order.tpl'); + return; + } + } + + + $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('ordersMsgs', $ordersMsgs) + ->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/107/adminmenu/paymentmethods.php b/version/107/adminmenu/paymentmethods.php new file mode 100644 index 0000000..1782978 --- /dev/null +++ b/version/107/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/107/adminmenu/tpl/info.tpl b/version/107/adminmenu/tpl/info.tpl new file mode 100644 index 0000000..77a48dc --- /dev/null +++ b/version/107/adminmenu/tpl/info.tpl @@ -0,0 +1,96 @@ +
+
+
+ + + +
+
+ + + +
+ + {if isset($update)} +
+ +
+

Update auf Version {$update->version} verfügbar!

+
+
+
+
Version:
+
{$update->version}
+
+
+
Erschienen:
+
{$update->create_date}
+
+
+
Changelog:
+
+ +
+
+ +
+
+ +
+
+
+ {else} +
+ + + +
+ {/if} + +
+
+
+ + + +
+
+ + + +
+ +
+
+
+ + + +
+
+ + + +
+
+ + + +
+
+
+{if file_exists("{$smarty['current_dir']}/_addon.tpl")} + {include file="{$smarty['current_dir']}/_addon.tpl"} +{/if} \ No newline at end of file diff --git a/version/107/adminmenu/tpl/mollie-account-erstellen.png b/version/107/adminmenu/tpl/mollie-account-erstellen.png new file mode 100644 index 0000000000000000000000000000000000000000..fc1819255ef725fa214cf2bf028cf3428794ecee GIT binary patch literal 38998 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 +

+ « + 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} +

+ +{if count($ordersMsgs)} + {foreach from=$ordersMsgs item=alert} +
{$alert->text}
+ {/foreach} +
+{/if} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
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

+ + + + + + + + + + + + + + {foreach from=$order->payments() item=payment} + + + + + + + + + + + {/foreach} +
IDStatusMethodeAmountSettlementRefundedRemainingDetails
{$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} +
+
+{/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} +
+ + + + + + + + + + + + + + + + + + {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} + + + + + + + + + + + + + {/foreach} + + + + + + + + + + +
StatusSKUNameTypAnzahlMwStSteuerNettoBrutto 
+ {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*} +
{$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} + + + + + + + {/foreach} +
+ {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}
+ + diff --git a/version/107/adminmenu/tpl/orders.tpl b/version/107/adminmenu/tpl/orders.tpl new file mode 100644 index 0000000..fd1c5a8 --- /dev/null +++ b/version/107/adminmenu/tpl/orders.tpl @@ -0,0 +1,116 @@ + +{if count($ordersMsgs)} + {foreach from=$ordersMsgs item=alert} +
{$alert->text}
+ {/foreach} +
+{/if} + +{if $hasAPIKey == false} + + Jetzt kostenlos Mollie Account eröffnen! + +{else} + + + + + + + + + + + + + + + + {foreach from=$payments item=payment} + + + + + + + + + + + + {/foreach} + +
BestellNr.IDMollie StatusJTL StatusBetragWährungLocaleMethodeErstellt
+ {$payment->cOrderNumber} + {if $payment->cMode == 'test'} + TEST + {/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)}
+ {if $payments|count > 900} +
Hier werden nur die letzten 1000 Ergebnisse angezeigt.
+ {/if} + + +{/if} + diff --git a/version/107/adminmenu/tpl/paymentmethods.tpl b/version/107/adminmenu/tpl/paymentmethods.tpl new file mode 100644 index 0000000..4c37e02 --- /dev/null +++ b/version/107/adminmenu/tpl/paymentmethods.tpl @@ -0,0 +1,97 @@ +

Account Status

+ + + + + + + {if $profile->review} + + + {/if} + +
Mode:{$profile->mode}Status:{$profile->status}Review:{$profile->review->status}
+ +
+ +
+
+ + +
+ + + +
+
+ + +
+
+ + +
+
+ + + reset +
+
+
+ + +{if $allMethods && $allMethods|count} + + + + + + + + + + + + {foreach from=$allMethods item=method} + + + + + + + + {/foreach} + +
BildIDNamePreiseInfos
{$method->description|utf8_decode}{$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} +
+{else} +
Es konnten keine Methoden abgerufen werden.
+{/if} \ No newline at end of file diff --git a/version/107/class/Helper.php b/version/107/class/Helper.php new file mode 100644 index 0000000..8f4772c --- /dev/null +++ b/version/107/class/Helper.php @@ -0,0 +1,311 @@ +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(); + } + + /** + * 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/107/class/Model/AbstractModel.php b/version/107/class/Model/AbstractModel.php new file mode 100644 index 0000000..5638700 --- /dev/null +++ b/version/107/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/107/class/Mollie.php b/version/107/class/Mollie.php new file mode 100644 index 0000000..9e5520e --- /dev/null +++ b/version/107/class/Mollie.php @@ -0,0 +1,508 @@ +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; + } + + switch ((int)$newStatus) { + case BESTELLUNG_STATUS_VERSANDT: + Mollie::JTLMollie()->doLog('181_sync: Bestellung versandt', '#' . $oBestellung->kBestellung . '§' . $oBestellung->cBestellNr, LOGLEVEL_DEBUG); + $options['lines'] = []; + break; + case BESTELLUNG_STATUS_TEILVERSANDT: + $lines = []; + foreach ($order->lines as $i => $line) { + if (($quantity = Mollie::getBestellPosSent($line->sku, $oBestellung)) !== false && ($quantity - $line->quantityShipped) > 0) { + $x = $quantity - $line->quantityShipped; + $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', '#' . $oBestellung->kBestellung . '§' . $oBestellung->cBestellNr, LOGLEVEL_DEBUG); + if (count($lines)) { + $options['lines'] = $lines; + } + break; + case BESTELLUNG_STATUS_STORNO: + Mollie::JTLMollie()->doLog('181_sync: Bestellung storniert', '#' . $oBestellung->kBestellung . '§' . $oBestellung->cBestellNr, LOGLEVEL_DEBUG); + $options = null; + break; + default: + Mollie::JTLMollie()->doLog('181_sync: Bestellungstatus unbekannt: ' . $newStatus . '/' . $oBestellung->cStatus, '#' . $oBestellung->kBestellung . '§' . $oBestellung->cBestellNr, 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; + } + + /** + * @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); + + $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; + } + + $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/107/frontend/131_globalinclude.php b/version/107/frontend/131_globalinclude.php new file mode 100644 index 0000000..514cbea --- /dev/null +++ b/version/107/frontend/131_globalinclude.php @@ -0,0 +1,84 @@ +cNotifyID; + + if (!(int)$oZahlungSession->kBestellung && $oZahlungSession->cNotifyID) { + // Bestellung noch nicht finalisiert + $mOrder = JTLMollie::API()->orders->get($oZahlungSession->cNotifyID, ['embed' => 'payments']); + if ($mOrder && $mOrder->id === $oZahlungSession->cNotifyID) { + + 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) { + session_destroy(); + session_id($oZahlungSession->cSID); + $session = Session::getInstance(true, true); + } else { + $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(); + + if ($order->kBestellung > 0) { + $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: 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(); + } + } + return Mollie::getOrderCompletedRedirect((int)$oZahlungSession->kBestellung, true); + } + } + ob_end_flush(); +} catch (Exception $e) { + Helper::logExc($e); +} + diff --git a/version/107/frontend/140_smarty.php b/version/107/frontend/140_smarty.php new file mode 100644 index 0000000..0213117 --- /dev/null +++ b/version/107/frontend/140_smarty.php @@ -0,0 +1,71 @@ +oPluginSprachvariableAssoc_arr['error_' . $status]; + pq('#fieldset-payment')->prepend('
' . $text . '
'); + } + + $applePayId = "kPlugin_".Helper::oPlugin()->kPlugin."_mollieapplepay"; +pq('body')->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/107/frontend/144_notify.php b/version/107/frontend/144_notify.php new file mode 100644 index 0000000..65e24e3 --- /dev/null +++ b/version/107/frontend/144_notify.php @@ -0,0 +1,57 @@ + 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 ((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/107/frontend/181_sync.php b/version/107/frontend/181_sync.php new file mode 100644 index 0000000..86c610c --- /dev/null +++ b/version/107/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/107/frontend/img/trust_eng.png b/version/107/frontend/img/trust_eng.png new file mode 100644 index 0000000000000000000000000000000000000000..3d0177359de7fa93833765ac05d8b218fa1550f2 GIT binary patch literal 15299 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 Rmns)TMnX}%M${5 literal 0 HcmV?d00001 diff --git a/version/107/frontend/img/trust_fre.png b/version/107/frontend/img/trust_fre.png new file mode 100644 index 0000000000000000000000000000000000000000..ed1a2f6f03c56f6748aac8af0352de7fc0afd3a4 GIT binary patch literal 17319 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 Mu#8ZJpsxS_1AJc%;s5{u literal 0 HcmV?d00001 diff --git a/version/107/frontend/img/trust_ger.png b/version/107/frontend/img/trust_ger.png new file mode 100644 index 0000000000000000000000000000000000000000..e42821b06709e8f4371c66cfb5759d00df0e1afd GIT binary patch literal 15352 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 (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, $msg, $data, $level); + ZahlungsLog::add($this->moduleID, "[" . $_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; + + 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 \Mollie\Api\Resources\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(); + } + header('Location: ' . $oMolliePayment->getCheckoutUrl()); + unset($_SESSION['oMolliePayment']); + echo "redirect to payment ..."; + 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(); + } + } + + /** + * @return MollieApiClient + * @throws ApiException + * @throws IncompatiblePlatform + */ + public static function API() + { + Helper::init(); + if (self::$_mollie === null) { + self::$_mollie = new MollieApiClient(); + 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(), + + '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 ($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 ($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; + } + + + /** @var WarenkorbPos $oPosition */ + foreach ($order->Positionen as $oPosition) { + + // EUR => 1 + $_netto = round($oPosition->fPreis, 2); + $_vatRate = (float)$oPosition->fMwSt / 100; + $_amount = (float)$oPosition->nAnzahl; + + $unitPriceNetto = round(($_currencyFactor * $_netto), 2); + $unitPrice = round($unitPriceNetto * (1 + $_vatRate), 2); + $totalAmount = round($_amount * $unitPrice, 2); + $vatAmount = round($totalAmount - ($totalAmount / (1 + $_vatRate)), 2); + + $line = new stdClass(); + $line->name = utf8_encode($oPosition->cName); + $line->quantity = $oPosition->nAnzahl; + $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 = $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->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->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']) && $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 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 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) { + $oOrder = self::API()->orders->get($args['id'], ['embed' => 'payments']); + $logData = '$' . $oOrder->id; + $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() + { + /** @var Warenkorb $wk */ + $wk = $_SESSION['Warenkorb']; + 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 { + $method = self::PossiblePaymentMethods(static::MOLLIE_METHOD, $locale, $_SESSION['Kunde']->cLand, $_SESSION['Waehrung']->cISO, $wk->gibGesamtsummeWaren(true) * $_SESSION['Waehrung']->fFaktor); + 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 { + $this->doLog("Global mollie PaymentMethod cannot be used for payments directly."); + } + 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/107/paymentmethod/JTLMollieApplePay.php b/version/107/paymentmethod/JTLMollieApplePay.php new file mode 100644 index 0000000..ecf20a8 --- /dev/null +++ b/version/107/paymentmethod/JTLMollieApplePay.php @@ -0,0 +1,8 @@ +assign('profileId',$profileId) + ->assign('locale', self::getLocale($_SESSION['cISOSprache'], $_SESSION['Kunde']->cLand)) + ->assign('testmode', strpos(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/107/paymentmethod/JTLMollieDirectDebit.php b/version/107/paymentmethod/JTLMollieDirectDebit.php new file mode 100644 index 0000000..ce0441d --- /dev/null +++ b/version/107/paymentmethod/JTLMollieDirectDebit.php @@ -0,0 +1,8 @@ + + {$oMollieException->getMessage()} + +{/if} \ No newline at end of file diff --git a/version/107/paymentmethod/tpl/mollieComponents.tpl b/version/107/paymentmethod/tpl/mollieComponents.tpl new file mode 100644 index 0000000..9ad70bc --- /dev/null +++ b/version/107/paymentmethod/tpl/mollieComponents.tpl @@ -0,0 +1,101 @@ +

{$mollieLang.cctitle}

+
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+ +
+
+ + +
+ +
+ {if $trustBadge} +
+ PCI-DSS SAQ-A compliant +
+ {/if} +
+ + + + + \ No newline at end of file From ccc0f9fcc3778711525e36a77c000e9a385e03af Mon Sep 17 00:00:00 2001 From: "C. Proske" Date: Tue, 25 Feb 2020 11:35:52 +0100 Subject: [PATCH 117/280] fix #69 --- version/107/adminmenu/orders.php | 3 +- version/107/class/ExclusiveLock.php | 76 ++++++++++++++++++++++ version/107/frontend/131_globalinclude.php | 36 ++++++++++ version/107/paymentmethod/JTLMollie.php | 14 ++-- 4 files changed, 123 insertions(+), 6 deletions(-) create mode 100644 version/107/class/ExclusiveLock.php diff --git a/version/107/adminmenu/orders.php b/version/107/adminmenu/orders.php index e34ac14..0db0cd2 100644 --- a/version/107/adminmenu/orders.php +++ b/version/107/adminmenu/orders.php @@ -116,8 +116,7 @@ ], 3); } } - - $logs = Shop::DB()->executeQueryPrepared("SELECT * FROM tzahlungslog WHERE cLogData LIKE :kBestellung OR cLogData LIKE :cBestellNr OR cLogData LIKE :MollieID ORDER BY dDatum DESC", [ + $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 ?: '$$') . '%', diff --git a/version/107/class/ExclusiveLock.php b/version/107/class/ExclusiveLock.php new file mode 100644 index 0000000..834e00f --- /dev/null +++ b/version/107/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/107/frontend/131_globalinclude.php b/version/107/frontend/131_globalinclude.php index 514cbea..916a7f9 100644 --- a/version/107/frontend/131_globalinclude.php +++ b/version/107/frontend/131_globalinclude.php @@ -24,20 +24,48 @@ $logData = '$' . $oZahlungSession->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 = 300; + while (!$lock->lock() && $maxWait > 0) { + if (!$logged) { + Mollie::JTLMollie()->doLog("Hook 131: Order currently locked ({$oZahlungSession->cNotifyID})", $logData, LOGLEVEL_DEBUG); + $logged = microtime(true); + } + usleep(100000); + $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); } @@ -47,8 +75,11 @@ $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; @@ -56,6 +87,8 @@ 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); @@ -73,6 +106,8 @@ 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); } @@ -82,3 +117,4 @@ Helper::logExc($e); } + diff --git a/version/107/paymentmethod/JTLMollie.php b/version/107/paymentmethod/JTLMollie.php index ec80516..81eec85 100644 --- a/version/107/paymentmethod/JTLMollie.php +++ b/version/107/paymentmethod/JTLMollie.php @@ -105,9 +105,7 @@ public function addIncomingPayment($order, $payment) */ public function doLog($msg, $data = null, $level = LOGLEVEL_NOTICE) { - //ZahlungsLog::add($this->moduleID, $msg, $data, $level); - ZahlungsLog::add($this->moduleID, "[" . $_SERVER['PHP_SELF'] . "] " . $msg, $data, $level); - + ZahlungsLog::add($this->moduleID, "[" . microtime(true) . " - " . $_SERVER['PHP_SELF'] . "] " . $msg, $data, $level); return $this; } @@ -509,8 +507,16 @@ public function finalizeOrder($order, $hash, $args) 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); + } + $oOrder = self::API()->orders->get($args['id'], ['embed' => 'payments']); - $logData = '$' . $oOrder->id; $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); From 5ad8617d6cdbe04992170f3154d1dc9814f5731b Mon Sep 17 00:00:00 2001 From: "C. Proske" Date: Wed, 26 Feb 2020 17:03:52 +0100 Subject: [PATCH 118/280] fix #72, #71, #66 --- info.xml | 33 +++++++++++---------- version/107/paymentmethod/JTLMollie.php | 39 +++++++++++++++++++------ 2 files changed, 48 insertions(+), 24 deletions(-) diff --git a/info.xml b/info.xml index 367b90c..612b5d6 100644 --- a/info.xml +++ b/info.xml @@ -116,6 +116,7 @@ + error_canceled @@ -123,9 +124,8 @@ - + + error_expired @@ -133,16 +133,16 @@ + error_open - + + error_failed @@ -150,39 +150,43 @@ - + + lbl_cardHolder + lbl_cardNumber + lbl_expiryDate + lbl_varificationCode - - + + + cvchint_1 + cvchint_2 @@ -190,9 +194,8 @@ - + + diff --git a/version/107/paymentmethod/JTLMollie.php b/version/107/paymentmethod/JTLMollie.php index 81eec85..a545c2c 100644 --- a/version/107/paymentmethod/JTLMollie.php +++ b/version/107/paymentmethod/JTLMollie.php @@ -240,7 +240,7 @@ protected function getOrderData(Bestellung $order, $hash) '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, '_')), ]; @@ -266,6 +266,15 @@ protected function getOrderData(Bestellung $order, $hash) $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) && 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))) { @@ -279,25 +288,36 @@ protected function getOrderData(Bestellung $order, $hash) $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)); + } + } /** @var WarenkorbPos $oPosition */ foreach ($order->Positionen as $oPosition) { - // EUR => 1 + $line = new stdClass(); + $line->name = utf8_encode($oPosition->cName); + $_netto = round($oPosition->fPreis, 2); $_vatRate = (float)$oPosition->fMwSt / 100; $_amount = (float)$oPosition->nAnzahl; + // TODO: Setting for Teilbar + 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 = new stdClass(); - $line->name = utf8_encode($oPosition->cName); - $line->quantity = $oPosition->nAnzahl; + $line->quantity = (int)$_amount; $line->unitPrice = (object)[ 'value' => number_format($unitPrice, 2, '.', ''), 'currency' => $order->Waehrung->cISO, @@ -317,7 +337,7 @@ protected function getOrderData(Bestellung $order, $hash) case (int)C_WARENKORBPOS_TYP_GRATISGESCHENK: case (int)C_WARENKORBPOS_TYP_ARTIKEL: $line->type = OrderLineType::TYPE_PHYSICAL; - $line->sku = $oPosition->cArtNr; + $line->sku = utf8_encode($oPosition->cArtNr); break; case (int)C_WARENKORBPOS_TYP_VERSANDPOS: $line->type = OrderLineType::TYPE_SHIPPING_FEE; @@ -548,14 +568,15 @@ public function canPayAgain() */ public function isSelectable() { + // TODO: Setting for Teilbar /** @var Warenkorb $wk */ $wk = $_SESSION['Warenkorb']; - foreach ($wk->PositionenArr as $oPosition) { + /*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 !== '') { From bbe93c77f00dac5729c966f0186bfd1c55cc7c01 Mon Sep 17 00:00:00 2001 From: "C. Proske" Date: Wed, 26 Feb 2020 17:46:04 +0100 Subject: [PATCH 119/280] fix #64 --- info.xml | 22 +++++++++++++++++++ .../107/paymentmethod/JTLMolliePrzelewy24.php | 8 +++++++ 2 files changed, 30 insertions(+) create mode 100644 version/107/paymentmethod/JTLMolliePrzelewy24.php diff --git a/info.xml b/info.xml index 612b5d6..1bb780b 100644 --- a/info.xml +++ b/info.xml @@ -559,6 +559,28 @@ Bezahlen Sie bequem mit Klarna Slice It. + + + mollie Przelewy24 + + 17 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMolliePrzelewy24.php + JTLMolliePrzelewy24 + tpl/bestellabschluss.tpl + + Przelewy24 + mollie + Bezahlen Sie bequem mit Przelewy24. + + + \ No newline at end of file diff --git a/version/107/paymentmethod/JTLMolliePrzelewy24.php b/version/107/paymentmethod/JTLMolliePrzelewy24.php new file mode 100644 index 0000000..eaa8099 --- /dev/null +++ b/version/107/paymentmethod/JTLMolliePrzelewy24.php @@ -0,0 +1,8 @@ + Date: Fri, 28 Feb 2020 11:37:30 +0100 Subject: [PATCH 120/280] adds MyBank, fix #65 --- info.xml | 20 +++++++++++++++++++ version/107/paymentmethod/JTLMollieMyBank.php | 8 ++++++++ 2 files changed, 28 insertions(+) create mode 100644 version/107/paymentmethod/JTLMollieMyBank.php diff --git a/info.xml b/info.xml index 1bb780b..249cdcd 100644 --- a/info.xml +++ b/info.xml @@ -580,6 +580,26 @@ Bezahlen Sie bequem mit Przelewy24. + + mollie MyBank + + 17 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMollieMyBank.php + JTLMollieMyBank + tpl/bestellabschluss.tpl + + MyBank + mollie + Bezahlen Sie bequem mit MyBank. + + diff --git a/version/107/paymentmethod/JTLMollieMyBank.php b/version/107/paymentmethod/JTLMollieMyBank.php new file mode 100644 index 0000000..16051ad --- /dev/null +++ b/version/107/paymentmethod/JTLMollieMyBank.php @@ -0,0 +1,8 @@ + Date: Fri, 28 Feb 2020 14:55:54 +0100 Subject: [PATCH 121/280] fix #63, #75 --- info.xml | 11 +++++ version/107/adminmenu/orders.php | 3 ++ version/107/class/Mollie.php | 62 +++++++++++++++++++------ version/107/paymentmethod/JTLMollie.php | 28 ++++++----- 4 files changed, 77 insertions(+), 27 deletions(-) diff --git a/info.xml b/info.xml index 249cdcd..c5b05e4 100644 --- a/info.xml +++ b/info.xml @@ -93,6 +93,17 @@ + + + Artikel mit rationalen Stückzahlen + Artikel mit rationalen Stückzahlen werden dann unterstützt, jedoch als ein Artikel behandelt. KEIN Teilversand hierfür möglich! + supportQ + + + + + + TransaktionsID des Zahlungseingangs: Welche ID soll an die WAWI übetragen werden? diff --git a/version/107/adminmenu/orders.php b/version/107/adminmenu/orders.php index 0db0cd2..fb22302 100644 --- a/version/107/adminmenu/orders.php +++ b/version/107/adminmenu/orders.php @@ -133,6 +133,9 @@ } + 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); diff --git a/version/107/class/Mollie.php b/version/107/class/Mollie.php index 9e5520e..96f6ca9 100644 --- a/version/107/class/Mollie.php +++ b/version/107/class/Mollie.php @@ -82,37 +82,47 @@ public static function getShipmentOptions(Order $order, $kBestellung, $newStatus $options['tracking'] = $tracking; } + $logData = '#' . $oBestellung->kBestellung . '§' . $oBestellung->cBestellNr . '$' . $order->id; + switch ((int)$newStatus) { case BESTELLUNG_STATUS_VERSANDT: - Mollie::JTLMollie()->doLog('181_sync: Bestellung versandt', '#' . $oBestellung->kBestellung . '§' . $oBestellung->cBestellNr, LOGLEVEL_DEBUG); + 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 (($quantity = Mollie::getBestellPosSent($line->sku, $oBestellung)) !== false && ($quantity - $line->quantityShipped) > 0) { - $x = $quantity - $line->quantityShipped; - $lines[] = (object)[ - 'id' => $line->id, - 'quantity' => $x, - 'amount' => (object)[ - 'currency' => $line->totalAmount->currency, - 'value' => number_format($x * $line->unitPrice->value, 2), - ], - ]; - } + 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', '#' . $oBestellung->kBestellung . '§' . $oBestellung->cBestellNr, LOGLEVEL_DEBUG); + 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', '#' . $oBestellung->kBestellung . '§' . $oBestellung->cBestellNr, LOGLEVEL_DEBUG); + 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, '#' . $oBestellung->kBestellung . '§' . $oBestellung->cBestellNr, LOGLEVEL_DEBUG); + Mollie::JTLMollie()->doLog('181_sync: Bestellungstatus unbekannt: ' . $newStatus . '/' . $oBestellung->cStatus, $logData, LOGLEVEL_DEBUG); } return $options; @@ -166,6 +176,28 @@ public static function getBestellPosSent($sku, Bestellung $oBestellung) return false; } + /** + * + */ + public static function fixZahlungsarten() + { + $kPlugin = Helper::oPlugin()->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 diff --git a/version/107/paymentmethod/JTLMollie.php b/version/107/paymentmethod/JTLMollie.php index a545c2c..4e35169 100644 --- a/version/107/paymentmethod/JTLMollie.php +++ b/version/107/paymentmethod/JTLMollie.php @@ -304,12 +304,14 @@ protected function getOrderData(Bestellung $order, $hash) $_vatRate = (float)$oPosition->fMwSt / 100; $_amount = (float)$oPosition->nAnzahl; - // TODO: Setting for Teilbar - 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); + 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); @@ -568,15 +570,17 @@ public function canPayAgain() */ public function isSelectable() { - // TODO: Setting for Teilbar /** @var Warenkorb $wk */ $wk = $_SESSION['Warenkorb']; - /*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; + 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 !== '') { From 9e8fe68db6006ae0875b2114e995558daa1ca934 Mon Sep 17 00:00:00 2001 From: "C. Proske" Date: Fri, 28 Feb 2020 16:11:44 +0100 Subject: [PATCH 122/280] fix #73 --- info.xml | 1 + version/107/paymentmethod/JTLMollie.php | 161 +++++++++++++++++------- version/107/sql/107.sql | 4 + 3 files changed, 120 insertions(+), 46 deletions(-) create mode 100644 version/107/sql/107.sql diff --git a/info.xml b/info.xml index c5b05e4..b2ac0dd 100644 --- a/info.xml +++ b/info.xml @@ -30,6 +30,7 @@ 2019-12-18 + 107.sql 2019-12-18 diff --git a/version/107/paymentmethod/JTLMollie.php b/version/107/paymentmethod/JTLMollie.php index 4e35169..7ff428f 100644 --- a/version/107/paymentmethod/JTLMollie.php +++ b/version/107/paymentmethod/JTLMollie.php @@ -3,6 +3,7 @@ use Mollie\Api\Exceptions\ApiException; use Mollie\Api\Exceptions\IncompatiblePlatform; use Mollie\Api\MollieApiClient; +use Mollie\Api\Resources\Customer; use Mollie\Api\Types\OrderLineType; use Mollie\Api\Types\OrderStatus; use ws_mollie\Helper; @@ -16,6 +17,8 @@ class JTLMollie extends PaymentMethod { + const KUNDENATTRIBUT_CUSTOMERID = 'ws_mollie_customer_id'; + const ALLOW_PAYMENT_BEFORE_ORDER = true; /** @@ -135,7 +138,12 @@ public function preparePaymentProcess($order) $payable = (float)$order->fGesamtsumme > 0; + if ($payable) { + $this->updateMollieCustomer($_SESSION['Kunde']); + } + try { + if ($order->kBestellung) { if ($payable) { $payment = Payment::getPayment($order->kBestellung); @@ -201,6 +209,52 @@ public function preparePaymentProcess($order) } } + /** + * @param $oKunde Kunde + */ + public function updateMollieCustomer($oKunde) + { + 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' => $oKunde->kKunde, + 'kKundengruppe' => $oKunde->kKundengruppe, + 'cKundenNr' => $oKunde->cKundenNr, + ]; + + if ($customer instanceof Customer) { + $customer->update(); + } else { + if ($customer = $api->customers->create((array)$customer)) { + Shop::DB()->insert('xplugin_ws_mollie_kunde', (object)[ + 'kKunde' => $oKunde->kKunde, + 'customerId' => $customer->id, + ]); + } + } + + } catch (Exception $e) { + Helper::logExc($e); + } + } + /** * @return MollieApiClient * @throws ApiException @@ -218,6 +272,52 @@ public static function API() return self::$_mollie; } + 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"; + } + } + /** * @param Bestellung $order * @param $hash @@ -254,6 +354,13 @@ protected function getOrderData(Bestellung $order, $hash) $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; } @@ -422,52 +529,6 @@ protected function getOrderData(Bestellung $order, $hash) 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]); @@ -487,6 +548,14 @@ public function optionaleRundung($gesamtsumme) 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, '_'); diff --git a/version/107/sql/107.sql b/version/107/sql/107.sql new file mode 100644 index 0000000..debecf2 --- /dev/null +++ b/version/107/sql/107.sql @@ -0,0 +1,4 @@ +CREATE TABLE `xplugin_ws_mollie_kunde` ( + `kKunde` int NOT NULL PRIMARY KEY, + `customerId` varchar(32) NOT NULL +); \ No newline at end of file From 9603fd4c16f00c42ff734f1f935b6e9939e0a971 Mon Sep 17 00:00:00 2001 From: "C. Proske" Date: Fri, 28 Feb 2020 16:42:42 +0100 Subject: [PATCH 123/280] webstollen/zapier-jtl-shop-webstollen-sevdesk#10 --- version/107/class/Mollie.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/version/107/class/Mollie.php b/version/107/class/Mollie.php index 96f6ca9..6d0fd4c 100644 --- a/version/107/class/Mollie.php +++ b/version/107/class/Mollie.php @@ -223,6 +223,14 @@ public static function handleOrder(Order $order, $kBestellung) ':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 */ From 30adaedb23a4868246207cd87e5ab7afcf9c1bc5 Mon Sep 17 00:00:00 2001 From: "C. Proske" Date: Mon, 2 Mar 2020 10:37:22 +0100 Subject: [PATCH 124/280] fix #43 --- version/107/adminmenu/orders.php | 84 ++++++++++++++++++++++++++++ version/107/adminmenu/tpl/orders.tpl | 21 ++++++- 2 files changed, 104 insertions(+), 1 deletion(-) diff --git a/version/107/adminmenu/orders.php b/version/107/adminmenu/orders.php index fb22302..9a584d7 100644 --- a/version/107/adminmenu/orders.php +++ b/version/107/adminmenu/orders.php @@ -16,6 +16,90 @@ $ordersMsgs = []; 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) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Fehler:' . $e->getMessage()]; + } + break; + case 'refund': if (!array_key_exists('id', $_REQUEST)) { $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; diff --git a/version/107/adminmenu/tpl/orders.tpl b/version/107/adminmenu/tpl/orders.tpl index fd1c5a8..4ec7af3 100644 --- a/version/107/adminmenu/tpl/orders.tpl +++ b/version/107/adminmenu/tpl/orders.tpl @@ -93,7 +93,7 @@
{if $payments|count > 900} -
Hier werden nur die letzten 1000 Ergebnisse angezeigt.
+
Hier werden nur die letzten 1000 Ergebnisse angezeigt.
{/if} +
+
+

Export:

+
+ +
+ + + + + +
+
+ {/if} From 1d72ec3bb97e4f53f52b59be9e7961c166c94dd9 Mon Sep 17 00:00:00 2001 From: "dash.bar" Date: Mon, 2 Mar 2020 09:58:27 +0000 Subject: [PATCH 125/280] prepare finalize --- info.xml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/info.xml b/info.xml index b2ac0dd..0c78201 100644 --- a/info.xml +++ b/info.xml @@ -31,7 +31,7 @@ 107.sql - 2019-12-18 + 2020-03-02 131_globalinclude.php @@ -94,7 +94,6 @@ - Artikel mit rationalen Stückzahlen Artikel mit rationalen Stückzahlen werden dann unterstützt, jedoch als ein Artikel behandelt. KEIN Teilversand hierfür möglich! @@ -104,7 +103,6 @@ - TransaktionsID des Zahlungseingangs: Welche ID soll an die WAWI übetragen werden? @@ -571,7 +569,6 @@ Bezahlen Sie bequem mit Klarna Slice It. - mollie Przelewy24 @@ -612,7 +609,6 @@ Bezahlen Sie bequem mit MyBank. - \ No newline at end of file From f8e2ac79672e39a5d8de4ddd2a5cdf9f06ffdae3 Mon Sep 17 00:00:00 2001 From: "dash.bar" Date: Mon, 2 Mar 2020 09:58:28 +0000 Subject: [PATCH 126/280] init version 108 --- info.xml | 3 + version/108/adminmenu/info.php | 64 ++ version/108/adminmenu/orders.php | 240 ++++++ version/108/adminmenu/paymentmethods.php | 60 ++ version/108/adminmenu/tpl/info.tpl | 96 +++ .../tpl/mollie-account-erstellen.png | Bin 0 -> 38998 bytes version/108/adminmenu/tpl/order.tpl | 286 +++++++ version/108/adminmenu/tpl/orders.tpl | 135 ++++ version/108/adminmenu/tpl/paymentmethods.tpl | 97 +++ version/108/class/ExclusiveLock.php | 76 ++ version/108/class/Helper.php | 311 ++++++++ version/108/class/Model/AbstractModel.php | 7 + version/108/class/Model/Payment.php | 84 ++ version/108/class/Mollie.php | 548 +++++++++++++ version/108/frontend/131_globalinclude.php | 120 +++ version/108/frontend/140_smarty.php | 71 ++ version/108/frontend/144_notify.php | 57 ++ version/108/frontend/181_sync.php | 43 + version/108/frontend/img/trust_eng.png | Bin 0 -> 15299 bytes version/108/frontend/img/trust_fre.png | Bin 0 -> 17319 bytes version/108/frontend/img/trust_ger.png | Bin 0 -> 15352 bytes version/108/paymentmethod/JTLMollie.php | 746 ++++++++++++++++++ .../108/paymentmethod/JTLMollieApplePay.php | 8 + .../108/paymentmethod/JTLMollieBancontact.php | 8 + .../paymentmethod/JTLMollieBanktransfer.php | 10 + .../108/paymentmethod/JTLMollieBelfius.php | 8 + .../108/paymentmethod/JTLMollieCreditCard.php | 36 + .../paymentmethod/JTLMollieDirectDebit.php | 8 + version/108/paymentmethod/JTLMollieEPS.php | 8 + .../108/paymentmethod/JTLMollieGiftcard.php | 8 + .../108/paymentmethod/JTLMollieGiropay.php | 8 + version/108/paymentmethod/JTLMollieIDEAL.php | 8 + .../108/paymentmethod/JTLMollieINGHomePay.php | 8 + version/108/paymentmethod/JTLMollieKBC.php | 8 + .../paymentmethod/JTLMollieKlarnaPayLater.php | 8 + .../paymentmethod/JTLMollieKlarnaSliceIt.php | 8 + version/108/paymentmethod/JTLMollieMyBank.php | 8 + version/108/paymentmethod/JTLMolliePayPal.php | 8 + .../paymentmethod/JTLMolliePaysafecard.php | 8 + .../108/paymentmethod/JTLMolliePrzelewy24.php | 8 + version/108/paymentmethod/JTLMollieSofort.php | 8 + .../paymentmethod/tpl/bestellabschluss.tpl | 5 + .../paymentmethod/tpl/mollieComponents.tpl | 101 +++ version/108/sql/107.sql | 4 + 44 files changed, 3336 insertions(+) create mode 100644 version/108/adminmenu/info.php create mode 100644 version/108/adminmenu/orders.php create mode 100644 version/108/adminmenu/paymentmethods.php create mode 100644 version/108/adminmenu/tpl/info.tpl create mode 100644 version/108/adminmenu/tpl/mollie-account-erstellen.png create mode 100644 version/108/adminmenu/tpl/order.tpl create mode 100644 version/108/adminmenu/tpl/orders.tpl create mode 100644 version/108/adminmenu/tpl/paymentmethods.tpl create mode 100644 version/108/class/ExclusiveLock.php create mode 100644 version/108/class/Helper.php create mode 100644 version/108/class/Model/AbstractModel.php create mode 100644 version/108/class/Model/Payment.php create mode 100644 version/108/class/Mollie.php create mode 100644 version/108/frontend/131_globalinclude.php create mode 100644 version/108/frontend/140_smarty.php create mode 100644 version/108/frontend/144_notify.php create mode 100644 version/108/frontend/181_sync.php create mode 100644 version/108/frontend/img/trust_eng.png create mode 100644 version/108/frontend/img/trust_fre.png create mode 100644 version/108/frontend/img/trust_ger.png create mode 100644 version/108/paymentmethod/JTLMollie.php create mode 100644 version/108/paymentmethod/JTLMollieApplePay.php create mode 100644 version/108/paymentmethod/JTLMollieBancontact.php create mode 100644 version/108/paymentmethod/JTLMollieBanktransfer.php create mode 100644 version/108/paymentmethod/JTLMollieBelfius.php create mode 100644 version/108/paymentmethod/JTLMollieCreditCard.php create mode 100644 version/108/paymentmethod/JTLMollieDirectDebit.php create mode 100644 version/108/paymentmethod/JTLMollieEPS.php create mode 100644 version/108/paymentmethod/JTLMollieGiftcard.php create mode 100644 version/108/paymentmethod/JTLMollieGiropay.php create mode 100644 version/108/paymentmethod/JTLMollieIDEAL.php create mode 100644 version/108/paymentmethod/JTLMollieINGHomePay.php create mode 100644 version/108/paymentmethod/JTLMollieKBC.php create mode 100644 version/108/paymentmethod/JTLMollieKlarnaPayLater.php create mode 100644 version/108/paymentmethod/JTLMollieKlarnaSliceIt.php create mode 100644 version/108/paymentmethod/JTLMollieMyBank.php create mode 100644 version/108/paymentmethod/JTLMolliePayPal.php create mode 100644 version/108/paymentmethod/JTLMolliePaysafecard.php create mode 100644 version/108/paymentmethod/JTLMolliePrzelewy24.php create mode 100644 version/108/paymentmethod/JTLMollieSofort.php create mode 100644 version/108/paymentmethod/tpl/bestellabschluss.tpl create mode 100644 version/108/paymentmethod/tpl/mollieComponents.tpl create mode 100644 version/108/sql/107.sql diff --git a/info.xml b/info.xml index 0c78201..4a397ef 100644 --- a/info.xml +++ b/info.xml @@ -33,6 +33,9 @@ 107.sql 2020-03-02 + + 2020-03-02 + 131_globalinclude.php 144_notify.php diff --git a/version/108/adminmenu/info.php b/version/108/adminmenu/info.php new file mode 100644 index 0000000..292064e --- /dev/null +++ b/version/108/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 "
" . + "
" . + " " . + " Lizenz Informationen" . + ' ' . + '
' . + "
" . + " " . + " Update Informationen" . + ' ' . + '
' . + "
" . + " " . + " Plugin informationen" . + ' ' . + '
' . + '
'; + + 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/108/adminmenu/orders.php b/version/108/adminmenu/orders.php new file mode 100644 index 0000000..9a584d7 --- /dev/null +++ b/version/108/adminmenu/orders.php @@ -0,0 +1,240 @@ +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) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Fehler:' . $e->getMessage()]; + } + break; + + case 'refund': + if (!array_key_exists('id', $_REQUEST)) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; + break; + } + $payment = Payment::getPaymentMollie($_REQUEST['id']); + if (!$payment) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; + break; + } + + $order = JTLMollie::API()->orders->get($_REQUEST['id']); + if ($order->status == OrderStatus::STATUS_CANCELED) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung bereits storniert']; + 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; + break; + + case 'cancel': + if (!array_key_exists('id', $_REQUEST)) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; + break; + } + $payment = Payment::getPaymentMollie($_REQUEST['id']); + if (!$payment) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; + break; + } + $order = JTLMollie::API()->orders->get($_REQUEST['id']); + if ($order->status == OrderStatus::STATUS_CANCELED) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung bereits storniert']; + 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; + break; + + case 'capture': + if (!array_key_exists('id', $_REQUEST)) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; + break; + } + $payment = Payment::getPaymentMollie($_REQUEST['id']); + if (!$payment) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; + break; + } + $order = JTLMollie::API()->orders->get($_REQUEST['id']); + if ($order->status !== OrderStatus::STATUS_AUTHORIZED && $order->status !== OrderStatus::STATUS_SHIPPING) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Nur autorisierte Zahlungen können erfasst werden!']; + break; + } + + $oBestellung = new Bestellung($payment->kBestellung, true); + if (!$oBestellung->kBestellung) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung konnte nicht geladen werden!']; + break; + } + + $logData = '#' . $payment->kBestellung . '$' . $payment->kID . "§" . $oBestellung->cBestellNr; + + $options = ['lines' => []]; + if ($oBestellung->cTracking) { + $tracking = new stdClass(); + $tracking->carrier = $oBestellung->cVersandartName; + $tracking->url = $oBestellung->cTrackingURL; + $tracking->code = $oBestellung->cTracking; + $options['tracking'] = $tracking; + } + + // CAPTURE ALL + $shipment = JTLMollie::API()->shipments->createFor($order, $options); + $ordersMsgs[] = (object)['type' => 'success', 'text' => 'Zahlung wurde erfolgreich erfasst!']; + Mollie::JTLMollie()->doLog('Shipment created
' . print_r(['options' => $options, 'shipment' => $shipment], 1) . '
', $logData); + goto order; + + case 'order': + order: + if (!array_key_exists('id', $_REQUEST)) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; + 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) + ->assign('ordersMsgs', $ordersMsgs); + 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('ordersMsgs', $ordersMsgs) + ->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/108/adminmenu/paymentmethods.php b/version/108/adminmenu/paymentmethods.php new file mode 100644 index 0000000..1782978 --- /dev/null +++ b/version/108/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/108/adminmenu/tpl/info.tpl b/version/108/adminmenu/tpl/info.tpl new file mode 100644 index 0000000..77a48dc --- /dev/null +++ b/version/108/adminmenu/tpl/info.tpl @@ -0,0 +1,96 @@ +
+
+
+ + + +
+
+ + + +
+ + {if isset($update)} +
+ +
+

Update auf Version {$update->version} verfügbar!

+
+
+
+
Version:
+
{$update->version}
+
+
+
Erschienen:
+
{$update->create_date}
+
+
+
Changelog:
+
+ +
+
+ +
+
+ +
+
+
+ {else} +
+ + + +
+ {/if} + +
+
+
+ + + +
+
+ + + +
+ +
+
+
+ + + +
+
+ + + +
+
+ + + +
+
+
+{if file_exists("{$smarty['current_dir']}/_addon.tpl")} + {include file="{$smarty['current_dir']}/_addon.tpl"} +{/if} \ No newline at end of file diff --git a/version/108/adminmenu/tpl/mollie-account-erstellen.png b/version/108/adminmenu/tpl/mollie-account-erstellen.png new file mode 100644 index 0000000000000000000000000000000000000000..fc1819255ef725fa214cf2bf028cf3428794ecee GIT binary patch literal 38998 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 +

+ « + 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} +

+ +{if count($ordersMsgs)} + {foreach from=$ordersMsgs item=alert} +
{$alert->text}
+ {/foreach} +
+{/if} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
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

+ + + + + + + + + + + + + + {foreach from=$order->payments() item=payment} + + + + + + + + + + + {/foreach} +
IDStatusMethodeAmountSettlementRefundedRemainingDetails
{$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} +
+
+{/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} +
+ + + + + + + + + + + + + + + + + + {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} + + + + + + + + + + + + + {/foreach} + + + + + + + + + + +
StatusSKUNameTypAnzahlMwStSteuerNettoBrutto 
+ {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*} +
{$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} + + + + + + + {/foreach} +
+ {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}
+ + diff --git a/version/108/adminmenu/tpl/orders.tpl b/version/108/adminmenu/tpl/orders.tpl new file mode 100644 index 0000000..4ec7af3 --- /dev/null +++ b/version/108/adminmenu/tpl/orders.tpl @@ -0,0 +1,135 @@ + +{if count($ordersMsgs)} + {foreach from=$ordersMsgs item=alert} +
{$alert->text}
+ {/foreach} +
+{/if} + +{if $hasAPIKey == false} + + Jetzt kostenlos Mollie Account eröffnen! + +{else} + + + + + + + + + + + + + + + + {foreach from=$payments item=payment} + + + + + + + + + + + + {/foreach} + +
BestellNr.IDMollie StatusJTL StatusBetragWährungLocaleMethodeErstellt
+ {$payment->cOrderNumber} + {if $payment->cMode == 'test'} + TEST + {/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)}
+ {if $payments|count > 900} +
Hier werden nur die letzten 1000 Ergebnisse angezeigt.
+ {/if} + + +
+
+

Export:

+
+ +
+ + + + + +
+
+ +{/if} + diff --git a/version/108/adminmenu/tpl/paymentmethods.tpl b/version/108/adminmenu/tpl/paymentmethods.tpl new file mode 100644 index 0000000..4c37e02 --- /dev/null +++ b/version/108/adminmenu/tpl/paymentmethods.tpl @@ -0,0 +1,97 @@ +

Account Status

+ + + + + + + {if $profile->review} + + + {/if} + +
Mode:{$profile->mode}Status:{$profile->status}Review:{$profile->review->status}
+ +
+ +
+
+ + +
+ + + +
+
+ + +
+
+ + +
+
+ + + reset +
+
+
+ + +{if $allMethods && $allMethods|count} + + + + + + + + + + + + {foreach from=$allMethods item=method} + + + + + + + + {/foreach} + +
BildIDNamePreiseInfos
{$method->description|utf8_decode}{$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} +
+{else} +
Es konnten keine Methoden abgerufen werden.
+{/if} \ No newline at end of file diff --git a/version/108/class/ExclusiveLock.php b/version/108/class/ExclusiveLock.php new file mode 100644 index 0000000..834e00f --- /dev/null +++ b/version/108/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/108/class/Helper.php b/version/108/class/Helper.php new file mode 100644 index 0000000..8f4772c --- /dev/null +++ b/version/108/class/Helper.php @@ -0,0 +1,311 @@ +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(); + } + + /** + * 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/108/class/Model/AbstractModel.php b/version/108/class/Model/AbstractModel.php new file mode 100644 index 0000000..5638700 --- /dev/null +++ b/version/108/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/108/class/Mollie.php b/version/108/class/Mollie.php new file mode 100644 index 0000000..6d0fd4c --- /dev/null +++ b/version/108/class/Mollie.php @@ -0,0 +1,548 @@ +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; + $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; + } + + $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/108/frontend/131_globalinclude.php b/version/108/frontend/131_globalinclude.php new file mode 100644 index 0000000..916a7f9 --- /dev/null +++ b/version/108/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 = 300; + while (!$lock->lock() && $maxWait > 0) { + if (!$logged) { + Mollie::JTLMollie()->doLog("Hook 131: Order currently locked ({$oZahlungSession->cNotifyID})", $logData, LOGLEVEL_DEBUG); + $logged = microtime(true); + } + usleep(100000); + $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/108/frontend/140_smarty.php b/version/108/frontend/140_smarty.php new file mode 100644 index 0000000..0213117 --- /dev/null +++ b/version/108/frontend/140_smarty.php @@ -0,0 +1,71 @@ +oPluginSprachvariableAssoc_arr['error_' . $status]; + pq('#fieldset-payment')->prepend('
' . $text . '
'); + } + + $applePayId = "kPlugin_".Helper::oPlugin()->kPlugin."_mollieapplepay"; +pq('body')->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/108/frontend/144_notify.php b/version/108/frontend/144_notify.php new file mode 100644 index 0000000..65e24e3 --- /dev/null +++ b/version/108/frontend/144_notify.php @@ -0,0 +1,57 @@ + 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 ((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/108/frontend/181_sync.php b/version/108/frontend/181_sync.php new file mode 100644 index 0000000..86c610c --- /dev/null +++ b/version/108/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/108/frontend/img/trust_eng.png b/version/108/frontend/img/trust_eng.png new file mode 100644 index 0000000000000000000000000000000000000000..3d0177359de7fa93833765ac05d8b218fa1550f2 GIT binary patch literal 15299 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 Rmns)TMnX}%M${5 literal 0 HcmV?d00001 diff --git a/version/108/frontend/img/trust_fre.png b/version/108/frontend/img/trust_fre.png new file mode 100644 index 0000000000000000000000000000000000000000..ed1a2f6f03c56f6748aac8af0352de7fc0afd3a4 GIT binary patch literal 17319 zcmeIaWm{d#(l&}rVB!{B1Hml>cM0wg+}+*XC3tZ6;O_1g+}+*X{miwVy`H`IIp+tw zAKovs$2G4pYIIlC=&tJft`3!x5k-WXlNj7k?iufmqH+8N*koC2! zvmJh3R`?W79|~N)N*|nxgjgE3JwO7U=U3pbw+W9c8DnD;7ZcVr!_NoYvfr2*H(bug z+a6XOCi>*CzgaEUJ>H+KJWNbXboLzF}|hnF@qh`<|_#%8k)v)1A?a+efU31|zB7h0(C?H&)T#+b}Ums`C@ExH{AkB_brVq(PUJJEPK z?~b?}aDP4fw+Q|teqRi%Kt63Hd7n`nN(Khm3=2RqlcBBW1sn!-*}R@#)Mr>Y3u%$v z{r&ZlBpZIQ;drXNKjPVfWSajT0|1;DEH*YHLzj<`7UKLGvM`1sv;ot}TG@9)Mol3zw9iiG-4*B2wM%1Pz}vMjB8 z2>mng$#heDh&0d>pFUGK|Jqgmcb9tv!QhZ>;cXEp1-m%9cus?!%;Z4EO7b%zkd`qN zA4E#gg#Wje^iaEEC*I#)67=X2J%*DQY%Kc(mM{_F5cKQE#GCE+`qqC}9ZGutZP5Se zkq{UhiY+3r35NYAM^27Fx3d2Fb1hn{Q{R3cLQML9h?f7HZKdG4H!w&qnR-n3Cm1>i zlEN=tw=oL44|C4ymp#<~xCuyVR|FV43`iib>1WgrK+qiZSsgm7sjSf7FZ`E3QPKmL zAHcBmWTv6-sQr6_sm<45WET4<8=9;`W=a3YY5r0-KiDcHKAP&zR=H{QdARX@isyI-XZhbZRwyrf)tUFFL(if6_S|Opj-aMOKwmw1gw^ z*pwHRmX>Ze1CXa5Hhg5uH5v;(-Y$F;+ufZ=t?JT0!3!)^8^E+bAD1#44S!OvHI6*? z$P2<{k2khz1LnWq#UYTwZbyQM{nZ!buqH=0+x_9NK9z0P zaFMtyVf3x1-z3{K|E)&;UDU^|5F*+jnJnIn>+9>>aiUbc0DUv7Kze=|`p#E-VVP{Y zr>BD~vyb<;W8?!K_ggtTv4A>~|4?-u(D8V7NI{_0`7AdoJ=;%MM6Rj~atu~ud%8-m z*YtXKXtrE~jasE5{kfMT(KFNg*(?FtEQUf;Z{sZt+#f3SL(bqBs#>iN<#jzoaXTeSgsN$tM#jdbBAuH()en#mLSffN zb$x$2DAwup9&X!CcNov9HW(B!QVF*Vg<+*oo%h?{eSf(?UUVx9>P|i=t?W>6rk3Tt z66&h!Cg}pIRBE3kePLvbNo6(@B;a!X{qfTIkvE(`^OA3e2Nv*KAON~}*R=@|pMBCw zSzHAIh|lTx^YXi42%q`c-EnCpy`OSZX^m_auleh?%grE>kB}uRBx$pb&zlkpgh8Y8 z+44EABYr{4L8ixH`@=eudtzduh)KF#aLYjLPO3#kj#8;|u?07i_sba@>DiSt$XZ!zXEXkK?0Y+)A z43Th5I=EK2n+S`EOdh=?2X4baXjldXY*pdXF5u~2l8!Qy@f%6lK!YGtNWSc!?f@8A z16H)yloas*7~}#}QW45nOzGXEQq;>_nt-sxf~V7LlI!n$yI%o-Y$^8l2y(yJA}djl zqulI|k+#izwXRaa;?f^|=ahp6k}E^9S}ta9PtVL8#s84GlEfcw89%`g=mB&e2PUJz00Krdb6K&S6sg}is;&lXkV(7y-Kq)o zK>UKXM|q|3SSqhKBZfiw)DMgok;}OfrIEo@2qFuk+(NyN29V*9J1J*fy{`JP-l`t2 z28kj~AZ7Vqx5H_&*}sO~+sSLHwibtkhDN^yJgV*#tjoHJ9`TVQ^3D&J>Ms`lj26$T z)b9@yX_Hx~()&)d!WC2&^%nEEh|tZzH>{^{_Hy2Ofj@G%(b-9c97jq@z+j`Xot%tk zM=9HgI=Iyvf@ilMm*xFDG`NqRSjS1U+^-QgHbm-N;U?af-!>L z9*kIkbBbJR3%n*~82(x3c)ptQ7?dB@KOHExg`(S|(gYF4{_t|qS$Ti|0Gj%KT7->n z%W@ul>9LF;5_0T;r4Z601=;s-DK~EalgOQV`nHp%JW)7goGB5OaAft$wS&F=Ed7sU zB7O^9EYnZf!XFbp@83-_oG^K=|ByfJm|8N)vRbTKIuUN2e4xnkoF>GmKKaRTwd%SPDPe?b z4R5z25ADn%q@FDi(q*auPpJ77^LanbW)=yKJu<)#e|fS*i6%pepth#w5F|?J09z4c z_v*epTI?-7akIVQ1OO>FH;OKd?!&YRJ^Vl`cKV|E+d-BOnqq)!wYKAwaLMb_%|U6# zcX&)%;@cd_Bzi!!pI;(`+(0s;0q}@1Tcg2J9Q1k7-<_|mOlxa;zTGV_yPRusKJCWM zAz#-oXp^!(c1NSV4I;yzP4(1D?=^~C&HC%0RDm5npo*}ZW@{5ZfYotVL^-X`Xn@un<*R_C|;!S~aNE<&c9<6}^03;hYpR%WK(KL#`*J)7+qpd-6_y@+W93cmAG;VyUmxSh^spu$ z-WiB=_>sPxGr0T-0@K(pk{n@Y4R{G=*HvA#2U<2+*PUAEDRC~xyW8jd?>C<&mPuL8 z9bNmP)DzIC))3f68>s%7v*-$>-iEB7o&QBgV)jTlG4(5)mpy!I9x90 z%-c)H8)z_dxHcKA+fE$pnXcQRybY<1zuA)Rdf*uzUE8M^E*`ITyxQ`YLK>1sdO1E+ zy+*I;jJEw@S{1~XXLeF`ICp+J1{uDSYE_|E8o8cv9gCz*i5BwesrkazP6=rTuuNaUPXHGvxK|Xe7PMS4 zkQ78C8CUq8Tnm57Lo2qZJK~ZHbBYnP>ux$B2(pYZ5$Ew3BP?PL45mU!YCveY7B8GV z!YX3*tgV}P4{_d)txoVCNXgMj+iDbY#I02CVaCx^Gzs2?xbUWy${$G4M|RNbbgZIX z?7b5kd>H`QYXHzQ$f_&y!o08QZ!~RWMnk`dIdZk+=lM9c=;QI+h<^I8ry~9fEYtAu z(a6#*`f7JPWP`+JP-&#VZ{4JfPM#cK8DH+LvF|uEG{l?vh{Ljzp&K>GvC>dvf+m~n zb?V$Tc%R~JmduW0^r;^W*+PWY>Dy<;0(48Pyknz1zi5iXMCLNLTTq5JWU8Vk%gg{? z8(D-HMsR6c+3qZd9v?#JE_NsS5T4Q$U60Faym<`MlM1mzHl_~57)V9Bn}obn{V~IU zx_-C$0{Va>3X**sjs5-WC6t4TYpS$Ey8COt5uIwgvX=E+K?-}*?bq=0>vHwBMtYWs zUsbDUCBQH^)PXw#EEi992$;;J711%*^K-+0h?dc8i$=JzhTZD5yDilibu_NKkGS$z zagN7|el*2Io4oV>BAIWav=6@f5ol13>J^wxP$qnRg=vu&*)%}py@;~NeW{QUc2J(d z%T4Tubt)*QJyRg<)8!)6cpjQAf`nlo=3uBK8FvXYJ0i{A05PGWFKwFRBa^5 z`-P*wj3lvXJ?{0?j=o#>GA+=$T5mqt$gtV(ijjt{HS8p6STknUa-t4bHNs37&qzS>96^?DoPkpclE`cUc4) z%=b!uqfTEyinR6e4}l!+D+^Lu_^pDZZ#_p`$AjTGXMm;YFG7tNLKt?BGkv9104Sp?XJw)nlc_muQ7@uV zKtDY6R)hdgRHoZLP96a}_|+bnOx{MK*orXwUG7iaok8UwJDhQ^`II}GjJX}oKkViZ z{x1fEm0~C|8Cwx_vlwu3wm=E?2MV;Eo>$KR=q2u{?>bjf0nT8_2KL!ONd-#SnRE9C zgg~(AG@Z#mg+5%}-a0LwY@*KMx^3AxcbjC0otDXtDWNc#Z?5wzP;oL2oG73y|EqyOCWtu*XkrAoBHFE>GMX#Xo#XjYr13QoZrib8VwJzo& z&L&MP%GuWu{Ah=={?s6yQ*#fTo=rOyJk%3r_qP=BSR|79c*+%`TXsDy{ni z!jH{h(-_k-XCJE(muXP}8&=@MZT{RnycG+f2PdG#b8#H(J6)B{HcsiXL~$Wa1H>I^`U`rfot`yv1lN@m6MUwbZ90tKSf;ngCI{jR`s36$ zz6X>E2J-~oNv5Tf3rURqOJoht`mgf#b$8#J8q9>$$@QYfG1N-)!WBfxt&jhV*kb0X zVXvf)Fq!n+>-1UZq4EFG`Q%?dTg5jGp&^G2$@SK41QTbM5#QEE8X@&rhQ#^{UTz0T zbTINKo=bTggc5$VbimeEq#!?H1jVfoC^jIWZT;n_dKNTy4=O%@{&LG|p58sl_a4z8 zx)E=MMB8UejcClx5gTEn?vPdYvL|^|d{Yf$d)EfK!}RoJb88Vki`+LR)!Uan!2;PJ zGN$Go`YGT8vF)(_ilS6xj;H#dTE~NmG`-^l>zgOS<>{bydrNSR zD-KSwh>2#e(cN2LE;CdU_+GuCf3;=b0>{hb^=jF<|K@?yG|vV2dIMBq6B8B`^v_S` z4_Jx)M<%ts+Hbu;`B;hj>dkg6zYwMBn>8cQ1Yx`1uiSsJ*&m0-d9oTYmSlNRJdhzW zWZ4-{roH zwndbYbGyozNB(N|^dcO;kUXF}&vSOmIqA2~*ZoTg$cYP*=~^>Tr;^j~4|bw*tLq4+ z=$CW^+9wJc_m{s|ZG8G!*&F@K?RB3Y_4GW{#eZgA`4e~36sSz2AF+Pdg0+J61mh6$*uIdxA%F@lL@vspBu zk4)_n#d23%2xCbhf>@y~z>pl2eOWY?k$ybHWL7aunr3@PP)P2L+m zp?-B>{srDDe%BfR=%@A7uFFOdzHWK)6)R|ym)`-2NCG7pu$j4-<-J$g&=?8B`aR$KCq}D)VWrmwg7YwQOi=~Dv z;WG_B^>@}IKnF)~5g$SN1BUCekS&fZZC2 z8OwFE*9>uZ65sq~%o^kns7H51>uvJjc|DuIIJBS$_4MmC~HnQ$-jX@pH_h4ZiHz(Vu6u&% zsi|v$%lFgEwyJj-ifF=nR#_7tHKcuAeN^LMbR`0{vhn6Ka;cKnsJ+*#lA;oHkLx7V zZGb)l{GJ{><8`$tpQd`?+$A;Ais4ufGIgE|YunuwJ^tQAJMU|!DpcDc1jvt2qb4FA{DnIm+QVR{qWVQ1 zZ)W-9qTmK_#%ns#kVL<)dU@I9ZcYV{*S4;bATWjO(|}m%OmZWRM?c5{hIr_C42$DP zKE&>$`mbF?QFvGC48sVl-u`o-kVV9;sj+E7yAg-fhTSQcsR3jItFqT=g*V?y()F=I zZxw8pOK|_Mw=qewQ#~L<+(q9T@JhGKV)Z@2&^RL zhQGpRd|3O_MFC1E4sncSPWIDv1}YlHulxGNU*>8^=tTZeS581-0#`;0PKPGt?>Q* z?bVbHTOZavB100aVSrfL70$4CJ4ixua^s-gT(8Tf;*+m&M32(Vx6_i5>>1Duy2i`* z#_ZZ2biEcE@>I1xM3ry2<2jC80#*Eg48Ys0p=4pm4do+L7fWTDMomx;cBm6BlYl^z z3PM|iKs>UErLkb}{SKS%dlmL{5L)G3Zkz57g{s%q>Ol|6r#iB9&R!gioUeW}-%!wb z&TadIf>@A(NtxKc*M=|rJ+XRsba#It_gQZIv^=^@LWJ*84L!fENR*!Pd3{y%mx*>F zTaW8d?_Uw)Ac=qg#iQiV@QQ1d3rYHHcWpuR9k|I%@?S}OxWH`Tfnh=QO1>4(l!dTa`B{YRnS?-*Qk1*lWq&HNf%mVT`DMz zjn$&z_IXrlo>^~=*|>dFPzOu7;>h%>(K^eh52D$kttpqzANgS44I z&IfhS+A~;#blGzajnIFIg}~sghkBa42?J&@P<)Z|yhpZ91FbzkJp26B(D2~Luo$wz zeB1p+eunn(+#WO@A7|tYWBSXfVpLLJ>)!={J*3;XKe*vkyORxmv5^d7Mc@se-qAzIiGX4QE}4TSe= zS(K0?bjB-ev;jwZ4$j|75?7qGRCE2fV1b^#Tk7zZXOl#&o6V7X7M>2k)~{Qn2qG<} zShDJ6GB0lUxHuoA^Av2^s=`Go&Q zv@WB3Q9fNHizEH}FG_vDc6gH~mG=L@J=yV}!MM;LdHp}tdnr=|G$=Z$SjtJvoh6R{ zFWxv6>ARRM^zarl5Bm?emX8ZwEkHHbsKd$d4?HDA0U;=td($CS`oD0ALZmNByn@$D z{>?wI1ivE*F@TKoBD_xGAGC>b4ha0eqWu0()fK;I@wr#L^LnEb-k$dj%id_ZG>1=F z_A8>sP?AI7_H>DY;0U?m{w-3x>s9}!w8Z^INS%4-VGX{7>yOm$qRvLYE++YeI=I8= zeq`uVv*tCW5>Qr5J$=&X$TaYV{qzr{D1qyj3_=&4CVxsKP$xKQNO-+Ht+-6)U}l`myrV?KG9d?1K+zoRAEmeKKs^jY~mw^Gq+p&i7oG@72kI9RhL%(^7nYc9uphU1gCR+EO)o8vP zt+#X7QlSl<7qbnT0Lm-c++;Y>wxpQGq#B=7S#g4_yvJLb_Je5Ks1Kww{%}m2e4JXg zsR_Qy{C1DG!7;Xt^4ttA(t)qCu!U36H_v=XIpMjB?0SyH6r+#mA=y7FXS1^Hw(4zM03 z=Dh|#2@IJy-_1u@dB1&yY2)(J;P=;;IdJSCW=bMwSe9;IQFIP#2#ieK`p9kkvKdZ% zgXb~*YoR!lF+TN^Xz9I%_zfFgt?6Zv6SKPp-@ZC z4yIK%UG~5igMcLYjeT82+Sfx{N&?(CuFmIJZLN;g&#bPKv1O2Tf#PF7UR^}P9o;)b zWy2zO(GNC`L+I3`=t@-zKhmekT?4|{mCa;&zEGH|doF+&DhEeT&fa1JSC$p&tuO)Y z8XOL;#gzF-{c|Ul(bV%NySqZ1JGbt~7wcSH(=Hp8`7t)*c~azGjGy#}!+Zfo(@8X= z;&V?%Nd-S>Cnm3Iv>JMzV*|(w%;FSDC&DX7L5T6%Sc^u13e$CpEUWeMj+o3Z>y~Oaw$+X0g4MRu_i9 z0BNPPJdPNgaJ5=vf*U};nyB_4uFLn=C%qVSk9r2Wk?iVl%*6mw=ePGD&7@6D%`NAOgvbGos@bhGcU&<#^0S66nkJGtby*YH@6EU~%x38lp&up3KF@CL7WV$n>IEu;-Lm9T2vXw? z4%en@&zFf*Z`9PmzKw+;gy`H9IgGVseG`&1-p?l}W2)5*ripf)M$a*TLIl4%9GT*P z5WTr#rL~&dr7n^9?QAMHH*Ipntk)!+&qNdJ0&HA?Nuf7WP2iD5y`keHdfre8HNJEj z4UlfLn$OSK1!Pdvx0Nx=qvER-;6TKA*rYN)-|?6qAZ8d-v{lSo3U zn5V-LwxR1`0Rm+zY3L4!;#$esmyoiOQoI&G=V!`>V5BSOz&E%EOY~OmJvsx_LhE_v zgyWjA!F{@Uti|KG6h*T7vi$oYopJ?rG>6S*6SnOXAsmc4=H3so)b-qw7|+|}pn+yy zj%Fvs{BpDDrm$(x*S868?e!%AzSpM2X${4xp$Jk-*{X<7Qi*o&1CfFZW&oNz_U%L~ z4xy~dr3)3M2lt`dw*p$p$JWlXY%Yc(@u9XaXi;s$%fU=(9Hj@DszRrMAnz3*WmNU%1<^t$PfP-79p1CY-RC+8n0C9B0q@a6nTAxmd4$$ z<6!5Og(;G1WXYzVbc-qa(&FPoU#__)tDfa^&t0OLqg&>CT4$=AK;K!Gt?7`mab5EX z!Lpt|01^>0(W#DBqa(w;TF<&}q_y*L2g?5XbkFJN1*=@rEDdRY=HSLHbj%~lE;bmEkk{`9T7`AqR? zAgfNZn5hRP>B0S(pGNq=s)*WXKlnvf*^$h(pc7QNlOBamZmjChm6a(%v0O(cne<{| zPn(jvNfL+neM9T8(wu0r8Loa`i}v7ZIz(&zxj!RuXZ4xNQGv`SuW!NIp4Hc9FlY5d z#@;znH!ERfMK$>(ZM;|jIaBRx=BSa@)0TUS=Pd5BPv6G_+v_SWb5WWDuLI7M?fV4Z z$0WKew*ZLrL_NR1%T$`iPv-y0RP@_-b5*-#%V**VBOJv zlk!}%7|p?Cf>AQQhzlZYCev*5oV=boD;>mi`WS@RzG>#uRS4bFbrrevo1aLo53x5~ z7#)eA*Vf*cp0#KVu*m4fYjnQLCwRyWUNiG&xCWa8bgksV^rzN>9S9fMZNQZGm z^6Fd${IIsz7AMo)rKmU)4DEIYSo4-jff(wU^zUSa(w(eqr6`suR|OjP?-1; zg;e49nw$B21uf}dVl$%L@Wn6D+;JPgdfwD5>4baTk4f-5Dlh4@;KgNE)w!{3@7rKS z6+M%li?q-DY+L)HkA}CePEbDKEnO&!M$T{Le!#JJtP@2adeVH(nTNws2AOheP=IBY z_oQF?>Pj)(noBibHjg23krxn^R3=uAqpA+TW)s@jIsIS{pG0jq9d>K!)xB> z<*czTVS`LuT>LLen!7oqr7F2>rWA;`LSs>LeY6`VTd>~lF#{qD8BioOJda8J#-qFHHlKn_|C`)4ZmNM!%dQ`zqW(wM z9Vj|dl!nginxp+uAeHlE$+cW#BzX+t4RA;-0V1&(1?MtiV+D_njvQC48s$MgLwgjq zO|lIzN*TJOR6x{juk1=Lt}-gfl1qGUFcoNY<_w@txXS{^Z18M+a(D+?=b@COt9r{< zv9S&scC4xv(7)Cp{J3_ZLuN9WGJ<3@b=5agZ*1_@wOsGh_`S5ACzS$NZco#RU}96n z{S_N4v^K#r1>|b+7zo2jG{22_2}DObe7(VavXb9VAnj?`u_>&`IjP_XdVa9z7aCBr z;@P?}67gcE(&3Gfxljyglr$;*=J+MigWs_3UL-_x0pAsi4t23+1_+ zgs{X5NffK0+Tb!*8|^317D$$gbD3bY&xkt1%sDpgQX7jE9^#3{gs=Xs6b-6yAL3cb z<;8*yWB@x`+Pn4hv_!NIvWNsL8K!noGQ;XK+E z)wgbe>uv`G@Si4sZz5|1x1+>^mdhAIpI5scXAL?KFPIVZ`ww~=U!L#s_DQPZS0CLVa zP#}>`qu^RPjaAwzWPSpVw6=HX_Gku!qXk5J#IVC-vrdnJ>pOXS*eI0cdsECWR;H^n zwtl%k6VbWoc(La5_kR|NCM<8zNP~rQ=F}6#{F#{;1doNbd;=orEg=LLlCViO%H zSfN*B_g@gYi%z;0{;5{cmR=mdkJ4?mmw;W)NM1pBxC@F&CUzM=*du3W?s1{K#-#}{ z=Z2~0s!t5c_GK?qYt?Aq?R+-Q&)VPF4p05&Mg?Ym^zCC0hD)Gn=RT?~B1vbSgMGC3 zJd15Tb#S2C;&AUni+`?^Oye0W_I5|sf=>EQf!^E<#uZoxd>VNrrL^4n^WTtwei#+RCVquXqBv%wJ>)A{*41`-c( zue5j-A?Uz@y5YZ|cqy<`>{Z7ZX$d^A@*b~;wZh!$vcRMxHIoeC#c%1!$)*#Sx6ghs zgxSG}c+~!r{uH@*td`kH+U}wJ3WRREsODqu^_(u}_;sM&!0J8h-QR9E`?r(dk&Acs z$I@U^13{E7ahy3puGrLLn;(I^0jnUhh9D7e3K4lfe)a+p>;Pz&Acp9SQIZyBowvho zAT0W)B|)`G2=M6QABEI{Fc2`(!6|LYH<_w&Gp$waPi#Jj(6(cpql}6%7>i;Q8=pD!z}!&p|si*TIaeX%@VZ|9=ZZ$txqJayAz0CV)7oDAPY zFhek2t-4?cNp28t)lhc6+;pYE>K4Q+{)>A18rEZvv|ZW!=UW36)gIxukdJ1Ge6QUX8?&(r2$s%LhiF{_pu-(Z-$z};kuinb@pQ0?xRFDL1uX0S)_$P^Px;c|FJS6A$ znmHBIx7M?bOe35~5!kuIL~{_FDr6FPBfW8&)LxUr3+g9XSw_5^7X>*!WMn9Q!tat! zHe`t^SE|LISd7vyPVc^QKH^&v5tf9$*bNm?t9tj{z|^mEcn*G>z3nFRmL8y2XjQo3 znRj3HkT3tmWprFXK6O`4Go^7VK2KZ8B+z_RhI@OC;1dCzg`w|xeUn>cM1hC$;AX}0 zR?St_a_!}8s}e)d{C08t3|3!6nEQkNd=2UqtI=ic4 zuYmEy6bWxMb?hq};>bbv(sbqFPKkM8p4EZtjsw40i5^Q9 z`KDpt6l3)CDz_G1Tk75xJHQ>4wz7!@;ZDIiyH2&o4$YLO&i9M%6U8rDEq6u9@I8!0 z-9;#M$e#pw8RMa}{Be*|&QzRMMWoATLIv4QoOiQ7l<;)%eteoPQ)9|6?~cVhb>GZ` z7U@y7Zn_u$>YD|n>*Rz1q1y(fW!%QvBTvmA7^E?=y=x%{+*LzWE4o74FM=)f?TY!8 zW1<9&K0dbJtsDp|4-5vQlv0U)q0?IE6(YZDd)+D3M;Nhwx>s*VyR|0AvmR!gt}DfR zN)a671f_+fZrAG(ie82H#rw3(?}XE9I*S;hhN<4qtVr$Z$q|r<4cV;LB^?f|uEJf= ze^rl4RIKh&4Ko|K4o0l`sW;sT^nUefZVf5K+m6xZ&2-OHr!sValPym#?HVWdB(@#q zq=^wUxAb^V?_9b$VnJLg=;7mAU60N{*LqNItU<8B?+VxYI7<4)OvEWg6#fG*cjaKO z$^FiJaMzfwHIGMb!YX?;9jF8TNcyg|cbu4w55(TTtgQQ{ytvIvP`$Wrg2J0@0A`nXvv zA=F-Cdd|yI9hVHbIk0B^R^@Zck->Wj>FGRg%yx;oxCAXZN|5SysO-u2>b>%17`8L2 z3TBF0X;FM1^u3<}ov?M?uWJMjY3cZN`Gr`c=Yz7EB5~vldEw(Wxy-nCCrWa>3im{R zayTr*uLm^V4IAFfM28+-SLXE{+H=OQgm+C*O<~qEcVu_R%jAPo7Z7+H-cKji>Q)9K zuM&1D#>yM`W!`u?m7vU%QpIipJmYPFFVf<+>JHUdhdt1HSK=C!pWJSrN_7Um-a1Cv=^quq>@6N(?Kqu}$SzDORL;oj1z&;-AdCLZ9~to1&3qo%uUIO3KRJ<4bTm06OnpRE)xv3hEY*Y#SKUSPHF7A2 zUYsvx6bsA*miHQWbCtQ(Lij`Eg5kwZ8DJLkIj9#pJW4g!*hp&s7~hd?sI2+YJs!!w zvGnwk1zG3g(>*Q6j5F+g^+L~=MSi&Wvvel@Kvj~0fPUC}RD<)tSY4lY3mI&_7=L*H zIvMduJ!8Li#Fe5r5#{^a;#LZtUAHW-;j=X$>WE*C5W6#FUDK3hSJ>NBlJ_)8#N=w6 zgs!S}sf8lxGLo=Xw@_h&(c-A}v$WvyRPqhM$N>%xj(L(yHt%MTNuqkadGXRS+lFTz z5DXZE)jfi>3*Pagt^sCzo>`zfDp}6IyneAIe2sB2HG+WIy_E?F$xJgzyh)~o4-pH1 z)F@vPShLNB(FboE^_GOFFSOqqZZpfK*DGZnh6tS*aoQP-HsMovH^6H`B;wV?A#gcc zPB34nC=Xj0zqQq4BSBL1Y1%@ipfvqsRhT6Zr(BWE$Ahc5#5Dy133!&;4-@g|EwpO} zvKhH`6-3)5xLS2gE?P=YNKc~VMm^tkH_cvm!}S&(=G4*@fM?<<^p!&O_d)>>jSqf6 z38IjTolVjJV+CJ(T-Kt#lMyHe844n*7TyV6-P0psFh1;qSn>P zoD!NmEN*pg#R*E6vr|K1sf}ntek59BjM@ATy(ZLTZxrxm4bpa^p zb^|yie8dvOUc?ktPTi~~(#(SOP(mjIcs7QSm-s>bRE6oe4e$n%EU(R*+R2?k05kv* zJ+TmI(C2itchXtBT1r7{62@avMbEvVChtUU;&f?Joe0=Mvh`M#i5_k9lM#s3BF?;V z#%t_>C0{{75J#uFQ%m_wim-fL;kTU$t|aPqzVtsqElb6lZ8*)2t{fW!ir&;o4?a~~ zdvP2ohe)V9?xY;6X$O8?Hu3z?F2YIGhC750Bj0;) z6l=-)RDQwSs05!u(DfspGW3^U9(-FPM@+HiiOYxat}+*NELd3dYG1O;KpI3Hftb)y zi>}zNBwm5?)}r?^z$jliw;o-(!MbD7Oa?KZAC84}W}TKsVElZcA)OgfTvP5y7FhzZ zXq-p*AtCJjYc^dGC0VVlMC72;W4b#adHH-{{=lBoFk{-b?eG2`lhj!I9h3--i-dw< zYO|RJ*abWQ-;S1Q3)A!!aZfwk&YKTrV-cOL1tg*DArKM&VE0*u`@iR8f%5$y_ffV8 zF!)ui@ETPD>tX8pt{LJujDhM&@Qt5C+75ne>Yd89G!kDR%^RmKgUE|#BZSg3W~J6Z84E$-Mbpk z0O6RgYmtU`ciRWZax(P0^4WT9O7#Wd@bnORnm#sx&GaWm9Jvf0kq4vn(f*z@xF)sAUao zt|;smg=bGg^AnNJwI=SV@}OC+Y2c%lr?WKnv7+eu?n>}k%thSliQZ-yr1c;(c?&st zCTn%I_~hKwEW5mpekw6L-3WAkDXbYATllaNVWDP^#^^-IrvzJWQ=HY?!=LGYZfFF?+={U6?LA*>3)0<@Mgxl5GuI8?BIm+@{s z3U`HO<9D{-U8Imx3hM`K>tqBr2@n^EI8i_J+{BL_H)tw%?v18OH%qEa#@uNPxll%L zdSN21Z+?ebi8oL?Gf7O|HIHB1qmnS?ioc$hCG$+cCVKy|F|YS} ztEx@-Zuv`*oQy1AE?8)gKw|pye=uN_0acQ)t)YuAR;(ZW)D%!vshFt$5D`Gcf$ZNX ze-$ZzNt~m^G5xtDASuow^un)0ZR_g3-b^1K8l4VL(LLGB&SzIVTt8st z1~29KfTY$xlp0@R+t<%v=Q(Gx$#JV;grNHI4N&@0Pcf{D`TivQ4-ew6di4J-Gp_-= z!`0c{amre6JKyQWMd?tcB>9KN1FAvhmnQ`q2R{c#f}qbmVFF47!C@%hsE~@1KuAG{ z{2|W!g0AVF?s(!VL%81+!h|4V+rY8k6}SJz#ri8a9%!& z8^5Q?&!U+`r;!*N8*5AbUwvN$cI^u>oV=Ezn2k$vwVpyfo5}qGgH0Km4H<@7pae>Z zHV{K1qW;?(F2j7arx|17j5cv)b^%6Q=5nJ6#zsbwf5yhz6Oud?)!7|reiTG_J}n}| z{>KpjzN8SU<3r=)tgoQ5e*aYnr=qf!{`FL6s=`eEAIo;6 zh91!b(#@Fvc2RhUvL^N(F8_m@4Y~Q$(MBQYX4^Ue*my#yUcPq_7jdL&>XhGD@W+zO z9>aX5;ddi+%B;YDA79XQ6%Ez|#tz;D&JNK8!4BCJfMpNy`<-aOnojJ>Qg94(@&=f= Mu#8ZJpsxS_1AJc%;s5{u literal 0 HcmV?d00001 diff --git a/version/108/frontend/img/trust_ger.png b/version/108/frontend/img/trust_ger.png new file mode 100644 index 0000000000000000000000000000000000000000..e42821b06709e8f4371c66cfb5759d00df0e1afd GIT binary patch literal 15352 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 (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 \Mollie\Api\Resources\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(); + } + header('Location: ' . $oMolliePayment->getCheckoutUrl()); + unset($_SESSION['oMolliePayment']); + echo "redirect to payment ..."; + 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) + { + 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' => $oKunde->kKunde, + 'kKundengruppe' => $oKunde->kKundengruppe, + 'cKundenNr' => $oKunde->cKundenNr, + ]; + + if ($customer instanceof Customer) { + $customer->update(); + } else { + if ($customer = $api->customers->create((array)$customer)) { + Shop::DB()->insert('xplugin_ws_mollie_kunde', (object)[ + 'kKunde' => $oKunde->kKunde, + '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(); + 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; + } + + 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"; + } + } + + /** + * @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) && 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)); + } + } + + /** @var WarenkorbPos $oPosition */ + 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->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->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 function optionaleRundung($gesamtsumme) + { + $conf = Shop::getSettings([CONF_KAUFABWICKLUNG]); + if (isset($conf['kaufabwicklung']['bestellabschluss_runden5']) && $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 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); + } + + $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() + { + /** @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 { + $method = self::PossiblePaymentMethods(static::MOLLIE_METHOD, $locale, $_SESSION['Kunde']->cLand, $_SESSION['Waehrung']->cISO, $wk->gibGesamtsummeWaren(true) * $_SESSION['Waehrung']->fFaktor); + 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 { + $this->doLog("Global mollie PaymentMethod cannot be used for payments directly."); + } + 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/108/paymentmethod/JTLMollieApplePay.php b/version/108/paymentmethod/JTLMollieApplePay.php new file mode 100644 index 0000000..ecf20a8 --- /dev/null +++ b/version/108/paymentmethod/JTLMollieApplePay.php @@ -0,0 +1,8 @@ +assign('profileId',$profileId) + ->assign('locale', self::getLocale($_SESSION['cISOSprache'], $_SESSION['Kunde']->cLand)) + ->assign('testmode', strpos(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/108/paymentmethod/JTLMollieDirectDebit.php b/version/108/paymentmethod/JTLMollieDirectDebit.php new file mode 100644 index 0000000..ce0441d --- /dev/null +++ b/version/108/paymentmethod/JTLMollieDirectDebit.php @@ -0,0 +1,8 @@ + + {$oMollieException->getMessage()} +
+{/if} \ No newline at end of file diff --git a/version/108/paymentmethod/tpl/mollieComponents.tpl b/version/108/paymentmethod/tpl/mollieComponents.tpl new file mode 100644 index 0000000..9ad70bc --- /dev/null +++ b/version/108/paymentmethod/tpl/mollieComponents.tpl @@ -0,0 +1,101 @@ +

{$mollieLang.cctitle}

+
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+ +
+
+ + +
+ +
+ {if $trustBadge} +
+ PCI-DSS SAQ-A compliant +
+ {/if} +
+ + + + + \ No newline at end of file diff --git a/version/108/sql/107.sql b/version/108/sql/107.sql new file mode 100644 index 0000000..debecf2 --- /dev/null +++ b/version/108/sql/107.sql @@ -0,0 +1,4 @@ +CREATE TABLE `xplugin_ws_mollie_kunde` ( + `kKunde` int NOT NULL PRIMARY KEY, + `customerId` varchar(32) NOT NULL +); \ No newline at end of file From be0f800d2fcc6c1bd0ab7cccbf4744447e01fcd8 Mon Sep 17 00:00:00 2001 From: "C. Proske" Date: Tue, 3 Mar 2020 15:25:16 +0100 Subject: [PATCH 127/280] fix Creditcard additional template --- info.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/info.xml b/info.xml index 4a397ef..ce3e5ec 100644 --- a/info.xml +++ b/info.xml @@ -239,6 +239,7 @@ 0 mollie.com CREDIT_CARD + tpl/mollieComponents.tpl 1 0 1 From 9315da8ad45b90fe268e00720ae220ef01e4acd6 Mon Sep 17 00:00:00 2001 From: "C. Proske" Date: Thu, 26 Mar 2020 11:11:17 +0100 Subject: [PATCH 128/280] fix #81 --- info.xml | 2 +- version/108/frontend/144_notify.php | 6 +++++ version/108/paymentmethod/JTLMollie.php | 22 +++++++++++++++---- .../108/paymentmethod/JTLMollieCreditCard.php | 4 ++-- 4 files changed, 27 insertions(+), 7 deletions(-) diff --git a/info.xml b/info.xml index ce3e5ec..cde767c 100644 --- a/info.xml +++ b/info.xml @@ -428,7 +428,7 @@ JTLMollieIDEAL tpl/bestellabschluss.tpl - Giropay + iDEAL mollie Bezahlen Sie bequem mit iDEAL. diff --git a/version/108/frontend/144_notify.php b/version/108/frontend/144_notify.php index 65e24e3..d1826a4 100644 --- a/version/108/frontend/144_notify.php +++ b/version/108/frontend/144_notify.php @@ -32,6 +32,12 @@ $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); diff --git a/version/108/paymentmethod/JTLMollie.php b/version/108/paymentmethod/JTLMollie.php index 7ff428f..22a30f2 100644 --- a/version/108/paymentmethod/JTLMollie.php +++ b/version/108/paymentmethod/JTLMollie.php @@ -1,5 +1,8 @@ duringCheckout) { Session::getInstance()->cleanUp(); } - header('Location: ' . $oMolliePayment->getCheckoutUrl()); + + 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']); - echo "redirect to payment ..."; + exit(); } catch (ApiException $e) { $this->doLog("Create Payment Error: " . $e->getMessage() . '
' . print_r($orderData, 1) . '
', $logData, LOGLEVEL_ERROR); @@ -264,7 +274,10 @@ public static function API() { Helper::init(); if (self::$_mollie === null) { - self::$_mollie = new MollieApiClient(); + 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); @@ -374,7 +387,8 @@ protected function getOrderData(Bestellung $order, $hash) $data['billingAddress']->country = $order->oRechnungsadresse->cLand; if (array_key_exists('Kunde', $_SESSION)) { - if (isset($_SESSION['Kunde']->dGeburtstag) && preg_match('/^\d{4}-\d{2}-\d{2}/$', trim($_SESSION['Kunde']->dGeburtstag))) { + if (isset($_SESSION['Kunde']->dGeburtstag) && preg_match('/^\d{4}-\d{2}-\d{2}$/', trim($_SESSION['Kunde']->dGeburtstag)) && trim($_SESSION['Kunde']->dGeburtstag) !== '0000-00-00') { + $data['consumerDateOfBirth'] = trim($_SESSION['Kunde']->dGeburtstag); } if (isset($_SESSION['Kunde']->cAdressZusatz) && trim($_SESSION['Kunde']->cAdressZusatz) !== '') { diff --git a/version/108/paymentmethod/JTLMollieCreditCard.php b/version/108/paymentmethod/JTLMollieCreditCard.php index ebae27b..4415f00 100644 --- a/version/108/paymentmethod/JTLMollieCreditCard.php +++ b/version/108/paymentmethod/JTLMollieCreditCard.php @@ -23,9 +23,9 @@ public function handleAdditional($aPost_arr) return true; } - Shop::Smarty()->assign('profileId',$profileId) + Shop::Smarty()->assign('profileId', $profileId) ->assign('locale', self::getLocale($_SESSION['cISOSprache'], $_SESSION['Kunde']->cLand)) - ->assign('testmode', strpos(Helper::getSetting('api_key'), 'test_') === 0) + ->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); From d809ed2c50d53fb0c74c319fc0c5ba89d1cb529a Mon Sep 17 00:00:00 2001 From: "C. Proske" Date: Wed, 15 Apr 2020 11:20:00 +0200 Subject: [PATCH 129/280] Tracking encoding, fix #84 --- version/108/adminmenu/orders.php | 6 +++--- version/108/paymentmethod/JTLMollie.php | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/version/108/adminmenu/orders.php b/version/108/adminmenu/orders.php index 9a584d7..1704bf2 100644 --- a/version/108/adminmenu/orders.php +++ b/version/108/adminmenu/orders.php @@ -169,9 +169,9 @@ $options = ['lines' => []]; if ($oBestellung->cTracking) { $tracking = new stdClass(); - $tracking->carrier = $oBestellung->cVersandartName; - $tracking->url = $oBestellung->cTrackingURL; - $tracking->code = $oBestellung->cTracking; + $tracking->carrier = utf8_encode($oBestellung->cVersandartName); + $tracking->url = utf8_encode($oBestellung->cTrackingURL); + $tracking->code = utf8_encode($oBestellung->cTracking); $options['tracking'] = $tracking; } diff --git a/version/108/paymentmethod/JTLMollie.php b/version/108/paymentmethod/JTLMollie.php index 22a30f2..6e58c1f 100644 --- a/version/108/paymentmethod/JTLMollie.php +++ b/version/108/paymentmethod/JTLMollie.php @@ -387,7 +387,7 @@ protected function getOrderData(Bestellung $order, $hash) $data['billingAddress']->country = $order->oRechnungsadresse->cLand; if (array_key_exists('Kunde', $_SESSION)) { - if (isset($_SESSION['Kunde']->dGeburtstag) && preg_match('/^\d{4}-\d{2}-\d{2}$/', trim($_SESSION['Kunde']->dGeburtstag)) && trim($_SESSION['Kunde']->dGeburtstag) !== '0000-00-00') { + 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); } From 3f43fab504179be5dd711ee2e11d641e82323b29 Mon Sep 17 00:00:00 2001 From: "C. Proske" Date: Wed, 15 Apr 2020 11:51:46 +0200 Subject: [PATCH 130/280] ApplePay Method, fix #77 --- version/108/frontend/140_smarty.php | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/version/108/frontend/140_smarty.php b/version/108/frontend/140_smarty.php index 0213117..ac119c6 100644 --- a/version/108/frontend/140_smarty.php +++ b/version/108/frontend/140_smarty.php @@ -12,9 +12,15 @@ $text = Helper::oPlugin()->oPluginSprachvariableAssoc_arr['error_' . $status]; pq('#fieldset-payment')->prepend('
' . $text . '
'); } - - $applePayId = "kPlugin_".Helper::oPlugin()->kPlugin."_mollieapplepay"; -pq('body')->append(<<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': From cab6f7a0ab227c35a8dff347188283527add8eae Mon Sep 17 00:00:00 2001 From: "C. Proske" Date: Wed, 15 Apr 2020 12:10:46 +0200 Subject: [PATCH 131/280] DB Exception, fix #83 --- version/108/paymentmethod/JTLMollie.php | 34 +++++++++++++++---------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/version/108/paymentmethod/JTLMollie.php b/version/108/paymentmethod/JTLMollie.php index 6e58c1f..2fd4e51 100644 --- a/version/108/paymentmethod/JTLMollie.php +++ b/version/108/paymentmethod/JTLMollie.php @@ -7,6 +7,7 @@ use Mollie\Api\Exceptions\IncompatiblePlatform; use Mollie\Api\MollieApiClient; use Mollie\Api\Resources\Customer; +use Mollie\Api\Resources\Order; use Mollie\Api\Types\OrderLineType; use Mollie\Api\Types\OrderStatus; use ws_mollie\Helper; @@ -183,7 +184,7 @@ public function preparePaymentProcess($order) exit(); } - if (!array_key_exists('oMolliePayment', $_SESSION) || !($_SESSION['oMolliePayment'] instanceof \Mollie\Api\Resources\Order)) { + if (!array_key_exists('oMolliePayment', $_SESSION) || !($_SESSION['oMolliePayment'] instanceof Order)) { $hash = $this->generateHash($order); //$_SESSION['cMollieHash'] = $hash; $orderData = $this->getOrderData($order, $hash); @@ -253,10 +254,17 @@ public function updateMollieCustomer($oKunde) $customer->update(); } else { if ($customer = $api->customers->create((array)$customer)) { - Shop::DB()->insert('xplugin_ws_mollie_kunde', (object)[ - 'kKunde' => $oKunde->kKunde, - 'customerId' => $customer->id, - ]); + if (self::getMollieCustomerId($oKunde->kKunde) === false) { + Shop::DB()->insert('xplugin_ws_mollie_kunde', (object)[ + 'kKunde' => $oKunde->kKunde, + 'customerId' => $customer->id, + ]); + } else { + Shop::DB()->update('xplugin_ws_mollie_kunde', 'kKunde', (int)$oKunde->kKunde, (object)[ + 'customerId' => $customer->id, + ]); + } + } } @@ -331,6 +339,14 @@ public static function getLocale($cISOSprache, $country = null) } } + public static function getMollieCustomerId($kKunde) + { + if ($row = Shop::DB()->select('xplugin_ws_mollie_kunde', 'kKunde', (int)$kKunde)) { + return $row->customerId; + } + return false; + } + /** * @param Bestellung $order * @param $hash @@ -562,14 +578,6 @@ public function optionaleRundung($gesamtsumme) 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, '_'); From cb4f33e2f78b8ad2c8f58f0f4154adc7f6f28030 Mon Sep 17 00:00:00 2001 From: "C. Proske" Date: Wed, 15 Apr 2020 13:16:01 +0200 Subject: [PATCH 132/280] reuse cardToken, fix #78 --- version/108/frontend/131_globalinclude.php | 4 ++-- version/108/paymentmethod/JTLMollie.php | 10 ++++++---- version/108/paymentmethod/JTLMollieCreditCard.php | 6 ++++++ 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/version/108/frontend/131_globalinclude.php b/version/108/frontend/131_globalinclude.php index 916a7f9..5778e21 100644 --- a/version/108/frontend/131_globalinclude.php +++ b/version/108/frontend/131_globalinclude.php @@ -31,13 +31,13 @@ $lock = new \ws_mollie\ExclusiveLock('mollie_' . $mOrder->id, PFAD_ROOT . PFAD_COMPILEDIR); $logged = false; - $maxWait = 300; + $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(100000); + usleep(1000000); $maxWait--; } diff --git a/version/108/paymentmethod/JTLMollie.php b/version/108/paymentmethod/JTLMollie.php index 2fd4e51..133a2f9 100644 --- a/version/108/paymentmethod/JTLMollie.php +++ b/version/108/paymentmethod/JTLMollie.php @@ -245,9 +245,9 @@ public function updateMollieCustomer($oKunde) $customer->email = utf8_encode($oKunde->cMail); $customer->locale = self::getLocale($_SESSION['cISOSprache'], $_SESSION['Kunde']->cLand); $customer->metadata = [ - 'kKunde' => $oKunde->kKunde, - 'kKundengruppe' => $oKunde->kKundengruppe, - 'cKundenNr' => $oKunde->cKundenNr, + 'kKunde' => (int)$oKunde->kKunde, + 'kKundengruppe' => (int)$oKunde->kKundengruppe, + 'cKundenNr' => utf8_encode($oKunde->cKundenNr), ]; if ($customer instanceof Customer) { @@ -256,7 +256,7 @@ public function updateMollieCustomer($oKunde) if ($customer = $api->customers->create((array)$customer)) { if (self::getMollieCustomerId($oKunde->kKunde) === false) { Shop::DB()->insert('xplugin_ws_mollie_kunde', (object)[ - 'kKunde' => $oKunde->kKunde, + 'kKunde' => (int)$oKunde->kKunde, 'customerId' => $customer->id, ]); } else { @@ -599,6 +599,8 @@ public function handleNotification($order, $hash, $args) try { + + $oMolliePayment = self::API()->orders->get($args['id'], ['embed' => 'payments']); Mollie::handleOrder($oMolliePayment, $order->kBestellung); diff --git a/version/108/paymentmethod/JTLMollieCreditCard.php b/version/108/paymentmethod/JTLMollieCreditCard.php index 4415f00..7724798 100644 --- a/version/108/paymentmethod/JTLMollieCreditCard.php +++ b/version/108/paymentmethod/JTLMollieCreditCard.php @@ -15,11 +15,17 @@ public function handleAdditional($aPost_arr) if ($profileId === '' || strpos($profileId, 'pfl_') !== 0) { return true; } + if (array_key_exists('mollieCardTokenTS', $_SESSION) && (int)$_SESSION['mollieCardTokenTS'] > 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; } From f32c53e962b652f4fc39dd3e18d8697b88912203 Mon Sep 17 00:00:00 2001 From: "C. Proske" Date: Wed, 15 Apr 2020 13:54:59 +0200 Subject: [PATCH 133/280] kupon 0 EUR, fix #82 --- version/108/paymentmethod/JTLMollie.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/version/108/paymentmethod/JTLMollie.php b/version/108/paymentmethod/JTLMollie.php index 133a2f9..9476d5e 100644 --- a/version/108/paymentmethod/JTLMollie.php +++ b/version/108/paymentmethod/JTLMollie.php @@ -600,7 +600,6 @@ public function handleNotification($order, $hash, $args) try { - $oMolliePayment = self::API()->orders->get($args['id'], ['embed' => 'payments']); Mollie::handleOrder($oMolliePayment, $order->kBestellung); @@ -678,7 +677,11 @@ public function isSelectable() $locale = self::getLocale($_SESSION['cISOSprache'], $_SESSION['Kunde']->cLand); if (static::MOLLIE_METHOD !== '') { try { - $method = self::PossiblePaymentMethods(static::MOLLIE_METHOD, $locale, $_SESSION['Kunde']->cLand, $_SESSION['Waehrung']->cISO, $wk->gibGesamtsummeWaren(true) * $_SESSION['Waehrung']->fFaktor); + $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) { From 4e493e7fa700d94f44414e58a2541d4d7c0ad2cd Mon Sep 17 00:00:00 2001 From: "C. Proske" Date: Wed, 15 Apr 2020 14:38:15 +0200 Subject: [PATCH 134/280] mollie Components Error messages, fix #79 --- info.xml | 9 +++++++++ version/108/paymentmethod/JTLMollieCreditCard.php | 1 + version/108/paymentmethod/tpl/mollieComponents.tpl | 4 +++- 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/info.xml b/info.xml index cde767c..5595c4c 100644 --- a/info.xml +++ b/info.xml @@ -210,6 +210,15 @@ + + + mcErrorMessage + Ein oder mehrere Felder sind ungültig. + + + + + diff --git a/version/108/paymentmethod/JTLMollieCreditCard.php b/version/108/paymentmethod/JTLMollieCreditCard.php index 7724798..b7bc092 100644 --- a/version/108/paymentmethod/JTLMollieCreditCard.php +++ b/version/108/paymentmethod/JTLMollieCreditCard.php @@ -30,6 +30,7 @@ public function handleAdditional($aPost_arr) } 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) diff --git a/version/108/paymentmethod/tpl/mollieComponents.tpl b/version/108/paymentmethod/tpl/mollieComponents.tpl index 9ad70bc..825bc9f 100644 --- a/version/108/paymentmethod/tpl/mollieComponents.tpl +++ b/version/108/paymentmethod/tpl/mollieComponents.tpl @@ -55,6 +55,8 @@ "; + echo "
" . + "
" . + " " . + " Lizenz Informationen" . + ' ' . + '
' . + "
" . + " " . + " Update Informationen" . + ' ' . + '
' . + "
" . + " " . + " Plugin informationen" . + ' ' . + '
' . + '
'; + + 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..1704bf2 --- /dev/null +++ b/version/109/adminmenu/orders.php @@ -0,0 +1,240 @@ +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) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Fehler:' . $e->getMessage()]; + } + break; + + case 'refund': + if (!array_key_exists('id', $_REQUEST)) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; + break; + } + $payment = Payment::getPaymentMollie($_REQUEST['id']); + if (!$payment) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; + break; + } + + $order = JTLMollie::API()->orders->get($_REQUEST['id']); + if ($order->status == OrderStatus::STATUS_CANCELED) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung bereits storniert']; + 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; + break; + + case 'cancel': + if (!array_key_exists('id', $_REQUEST)) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; + break; + } + $payment = Payment::getPaymentMollie($_REQUEST['id']); + if (!$payment) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; + break; + } + $order = JTLMollie::API()->orders->get($_REQUEST['id']); + if ($order->status == OrderStatus::STATUS_CANCELED) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung bereits storniert']; + 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; + break; + + case 'capture': + if (!array_key_exists('id', $_REQUEST)) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; + break; + } + $payment = Payment::getPaymentMollie($_REQUEST['id']); + if (!$payment) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; + break; + } + $order = JTLMollie::API()->orders->get($_REQUEST['id']); + if ($order->status !== OrderStatus::STATUS_AUTHORIZED && $order->status !== OrderStatus::STATUS_SHIPPING) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Nur autorisierte Zahlungen können erfasst werden!']; + break; + } + + $oBestellung = new Bestellung($payment->kBestellung, true); + if (!$oBestellung->kBestellung) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung konnte nicht geladen werden!']; + 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); + $ordersMsgs[] = (object)['type' => 'success', 'text' => 'Zahlung wurde erfolgreich erfasst!']; + Mollie::JTLMollie()->doLog('Shipment created
' . print_r(['options' => $options, 'shipment' => $shipment], 1) . '
', $logData); + goto order; + + case 'order': + order: + if (!array_key_exists('id', $_REQUEST)) { + $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; + 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) + ->assign('ordersMsgs', $ordersMsgs); + 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('ordersMsgs', $ordersMsgs) + ->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..77a48dc --- /dev/null +++ b/version/109/adminmenu/tpl/info.tpl @@ -0,0 +1,96 @@ +
+
+
+ + + +
+
+ + + +
+ + {if isset($update)} +
+ +
+

Update auf Version {$update->version} verfügbar!

+
+
+
+
Version:
+
{$update->version}
+
+
+
Erschienen:
+
{$update->create_date}
+
+
+
Changelog:
+
+ +
+
+ +
+
+ +
+
+
+ {else} +
+ + + +
+ {/if} + +
+
+
+ + + +
+
+ + + +
+ +
+
+
+ + + +
+
+ + + +
+
+ + + +
+
+
+{if file_exists("{$smarty['current_dir']}/_addon.tpl")} + {include file="{$smarty['current_dir']}/_addon.tpl"} +{/if} \ No newline at end of file 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 0000000000000000000000000000000000000000..fc1819255ef725fa214cf2bf028cf3428794ecee GIT binary patch literal 38998 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 +

+ « + 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} +

+ +{if count($ordersMsgs)} + {foreach from=$ordersMsgs item=alert} +
{$alert->text}
+ {/foreach} +
+{/if} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
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

+ + + + + + + + + + + + + + {foreach from=$order->payments() item=payment} + + + + + + + + + + + {/foreach} +
IDStatusMethodeAmountSettlementRefundedRemainingDetails
{$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} +
+
+{/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} +
+ + + + + + + + + + + + + + + + + + {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} + + + + + + + + + + + + + {/foreach} + + + + + + + + + + +
StatusSKUNameTypAnzahlMwStSteuerNettoBrutto 
+ {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*} +
{$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} + + + + + + + {/foreach} +
+ {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}
+ + diff --git a/version/109/adminmenu/tpl/orders.tpl b/version/109/adminmenu/tpl/orders.tpl new file mode 100644 index 0000000..4ec7af3 --- /dev/null +++ b/version/109/adminmenu/tpl/orders.tpl @@ -0,0 +1,135 @@ + +{if count($ordersMsgs)} + {foreach from=$ordersMsgs item=alert} +
{$alert->text}
+ {/foreach} +
+{/if} + +{if $hasAPIKey == false} + + Jetzt kostenlos Mollie Account eröffnen! + +{else} + + + + + + + + + + + + + + + + {foreach from=$payments item=payment} + + + + + + + + + + + + {/foreach} + +
BestellNr.IDMollie StatusJTL StatusBetragWährungLocaleMethodeErstellt
+ {$payment->cOrderNumber} + {if $payment->cMode == 'test'} + TEST + {/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)}
+ {if $payments|count > 900} +
Hier werden nur die letzten 1000 Ergebnisse angezeigt.
+ {/if} + + +
+
+

Export:

+
+ +
+ + + + + +
+
+ +{/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

+ + + + + + + {if $profile->review} + + + {/if} + +
Mode:{$profile->mode}Status:{$profile->status}Review:{$profile->review->status}
+ +
+ +
+
+ + +
+ + + +
+
+ + +
+
+ + +
+
+ + + reset +
+
+
+ + +{if $allMethods && $allMethods|count} + + + + + + + + + + + + {foreach from=$allMethods item=method} + + + + + + + + {/foreach} + +
BildIDNamePreiseInfos
{$method->description|utf8_decode}{$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} +
+{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..8f4772c --- /dev/null +++ b/version/109/class/Helper.php @@ -0,0 +1,311 @@ +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(); + } + + /** + * 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..6d0fd4c --- /dev/null +++ b/version/109/class/Mollie.php @@ -0,0 +1,548 @@ +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; + $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; + } + + $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 0000000000000000000000000000000000000000..3d0177359de7fa93833765ac05d8b218fa1550f2 GIT binary patch literal 15299 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 Rmns)TMnX}%M${5 literal 0 HcmV?d00001 diff --git a/version/109/frontend/img/trust_fre.png b/version/109/frontend/img/trust_fre.png new file mode 100644 index 0000000000000000000000000000000000000000..ed1a2f6f03c56f6748aac8af0352de7fc0afd3a4 GIT binary patch literal 17319 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 Mu#8ZJpsxS_1AJc%;s5{u literal 0 HcmV?d00001 diff --git a/version/109/frontend/img/trust_ger.png b/version/109/frontend/img/trust_ger.png new file mode 100644 index 0000000000000000000000000000000000000000..e42821b06709e8f4371c66cfb5759d00df0e1afd GIT binary patch literal 15352 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 (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) + { + 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; + } + + 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 static function getMollieCustomerId($kKunde) + { + if ($row = Shop::DB()->select('xplugin_ws_mollie_kunde', 'kKunde', (int)$kKunde)) { + return $row->customerId; + } + return false; + } + + /** + * @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)); + } + } + + /** @var WarenkorbPos $oPosition */ + 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->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->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 function optionaleRundung($gesamtsumme) + { + $conf = Shop::getSettings([CONF_KAUFABWICKLUNG]); + if (isset($conf['kaufabwicklung']['bestellabschluss_runden5']) && $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 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 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); + } + + $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}

+
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+ +
+
+ + +
+ +
+ {if $trustBadge} +
+ PCI-DSS SAQ-A compliant +
+ {/if} +
+ + + + + \ No newline at end of file diff --git a/version/109/sql/107.sql b/version/109/sql/107.sql new file mode 100644 index 0000000..debecf2 --- /dev/null +++ b/version/109/sql/107.sql @@ -0,0 +1,4 @@ +CREATE TABLE `xplugin_ws_mollie_kunde` ( + `kKunde` int NOT NULL PRIMARY KEY, + `customerId` varchar(32) NOT NULL +); \ No newline at end of file From c63b91c767f7eefc8a8f60a4644cc132a0c7d561 Mon Sep 17 00:00:00 2001 From: "C. Proske" Date: Thu, 30 Apr 2020 13:31:34 +0200 Subject: [PATCH 140/280] prevents modulID update, if no kPlugin --- version/109/class/Mollie.php | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/version/109/class/Mollie.php b/version/109/class/Mollie.php index 6d0fd4c..39e76e0 100644 --- a/version/109/class/Mollie.php +++ b/version/109/class/Mollie.php @@ -182,18 +182,20 @@ public static function getBestellPosSent($sku, Bestellung $oBestellung) public static function fixZahlungsarten() { $kPlugin = Helper::oPlugin()->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); + 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); + } } } } @@ -223,7 +225,7 @@ public static function handleOrder(Order $order, $kBestellung) ':orderId2' => $oBestellung->cBestellNr, ], 3); - if(isset($order->metadata->originalOrderNumber)){ + 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, From 8f2d13f894e6970d8caa7d499c56692dd0189cf8 Mon Sep 17 00:00:00 2001 From: "C. Proske" Date: Fri, 10 Jul 2020 14:00:04 +0200 Subject: [PATCH 141/280] cancel finalize if locked --- version/108/paymentmethod/JTLMollie.php | 1 + version/109/paymentmethod/JTLMollie.php | 1 + 2 files changed, 2 insertions(+) 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/paymentmethod/JTLMollie.php b/version/109/paymentmethod/JTLMollie.php index 4f71142..11511bc 100644 --- a/version/109/paymentmethod/JTLMollie.php +++ b/version/109/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']); From caf70c4932b7ada4a1631947822a2f2aae8f6253 Mon Sep 17 00:00:00 2001 From: "C. Proske" Date: Fri, 14 Aug 2020 15:17:48 +0200 Subject: [PATCH 142/280] PayPal Reference, close #90 --- version/109/class/Mollie.php | 6 ++++++ version/109/paymentmethod/JTLMollie.php | 16 ++++------------ 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/version/109/class/Mollie.php b/version/109/class/Mollie.php index 39e76e0..1f87dbe 100644 --- a/version/109/class/Mollie.php +++ b/version/109/class/Mollie.php @@ -15,6 +15,7 @@ use Lieferscheinpos; use Mollie\Api\Resources\Order; use Mollie\Api\Types\OrderStatus; +use Mollie\Api\Types\PaymentMethod; use Mollie\Api\Types\PaymentStatus; use Shop; use Shopsetting; @@ -290,6 +291,11 @@ public static function handleOrder(Order $order, $kBestellung) $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; diff --git a/version/109/paymentmethod/JTLMollie.php b/version/109/paymentmethod/JTLMollie.php index 11511bc..1160997 100644 --- a/version/109/paymentmethod/JTLMollie.php +++ b/version/109/paymentmethod/JTLMollie.php @@ -412,7 +412,7 @@ protected function getOrderData(Bestellung $order, $hash) } } - if ($order->Lieferadresse != null) { + if ($order->Lieferadresse !== null) { $data['shippingAddress'] = new stdClass(); if ($organizationName = utf8_encode(trim($order->Lieferadresse->cFirma))) { $data['shippingAddress']->organizationName = $organizationName; @@ -431,7 +431,7 @@ protected function getOrderData(Bestellung $order, $hash) } } - /** @var WarenkorbPos $oPosition */ + foreach ($order->Positionen as $oPosition) { $line = new stdClass(); @@ -508,10 +508,6 @@ protected function getOrderData(Bestellung $order, $hash) 'value' => number_format($order->Waehrung->fFaktor * $order->fGuthaben, 2, '.', ''), 'currency' => $order->Waehrung->cISO, ]; - $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, @@ -531,7 +527,7 @@ protected function getOrderData(Bestellung $order, $hash) } if (abs($sum - (float)$data['amount']->value) > 0) { $diff = (round((float)$data['amount']->value - $sum, 2)); - if ($diff != 0) { + if ($diff !== 0) { $line = new stdClass(); $line->type = $diff > 0 ? OrderLineType::TYPE_SURCHARGE : OrderLineType::TYPE_DISCOUNT; $line->name = 'Rundungsausgleich'; @@ -540,10 +536,6 @@ protected function getOrderData(Bestellung $order, $hash) 'value' => number_format($diff, 2, '.', ''), 'currency' => $order->Waehrung->cISO, ]; - $line->unitPrice = (object)[ - 'value' => number_format($diff, 2, '.', ''), - 'currency' => $order->Waehrung->cISO, - ]; $line->totalAmount = (object)[ 'value' => number_format($diff, 2, '.', ''), 'currency' => $order->Waehrung->cISO, @@ -562,7 +554,7 @@ protected function getOrderData(Bestellung $order, $hash) public function optionaleRundung($gesamtsumme) { $conf = Shop::getSettings([CONF_KAUFABWICKLUNG]); - if (isset($conf['kaufabwicklung']['bestellabschluss_runden5']) && $conf['kaufabwicklung']['bestellabschluss_runden5'] == 1) { + 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'); From 24150b968f283aca247796e4897395deef88bac7 Mon Sep 17 00:00:00 2001 From: "C. Proske" Date: Mon, 17 Aug 2020 09:46:47 +0200 Subject: [PATCH 143/280] deactivate customer id #93 --- version/109/paymentmethod/JTLMollie.php | 100 ++++++++++++------------ 1 file changed, 51 insertions(+), 49 deletions(-) diff --git a/version/109/paymentmethod/JTLMollie.php b/version/109/paymentmethod/JTLMollie.php index 1160997..8ee5675 100644 --- a/version/109/paymentmethod/JTLMollie.php +++ b/version/109/paymentmethod/JTLMollie.php @@ -6,7 +6,6 @@ use Mollie\Api\Exceptions\ApiException; use Mollie\Api\Exceptions\IncompatiblePlatform; use Mollie\Api\MollieApiClient; -use Mollie\Api\Resources\Customer; use Mollie\Api\Resources\Order; use Mollie\Api\Types\OrderLineType; use Mollie\Api\Types\OrderStatus; @@ -225,52 +224,55 @@ public function preparePaymentProcess($order) */ public function updateMollieCustomer($oKunde) { - 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; + +// 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); +// } } /** @@ -341,9 +343,9 @@ public static function getLocale($cISOSprache, $country = null) public static function getMollieCustomerId($kKunde) { - if ($row = Shop::DB()->select('xplugin_ws_mollie_kunde', 'kKunde', (int)$kKunde)) { - return $row->customerId; - } + //if ($row = Shop::DB()->select('xplugin_ws_mollie_kunde', 'kKunde', (int)$kKunde)) { + // return $row->customerId; + //} return false; } From c229a4eb3a387bc1e42c8b1d57e3b55c7b73dfcc Mon Sep 17 00:00:00 2001 From: "C. Proske" Date: Mon, 17 Aug 2020 10:43:37 +0200 Subject: [PATCH 144/280] fix #92 --- info.xml | 40 +++++++++--------- .../img/method/Przelewy24@2x.png | Bin 0 -> 859 bytes .../paymentmethod/img/method/applepay@2x.png | Bin 0 -> 656 bytes .../img/method/bancontact@2x.png | Bin 0 -> 582 bytes .../img/method/banktransfer@2x.png | Bin 0 -> 801 bytes .../paymentmethod/img/method/belfius@2x.png | Bin 0 -> 377 bytes .../img/method/creditcard@2x.png | Bin 0 -> 3125 bytes .../img/method/directdebit@2x.png | Bin 0 -> 801 bytes .../109/paymentmethod/img/method/eps@2x.png | Bin 0 -> 536 bytes .../paymentmethod/img/method/giftcard@2x.png | Bin 0 -> 2218 bytes .../paymentmethod/img/method/giropay@2x.png | Bin 0 -> 602 bytes .../109/paymentmethod/img/method/ideal@2x.png | Bin 0 -> 845 bytes .../img/method/inghomepay@2x.png | Bin 0 -> 1118 bytes .../109/paymentmethod/img/method/kbc@2x.png | Bin 0 -> 799 bytes .../paymentmethod/img/method/klarna@2x.png | Bin 0 -> 896 bytes .../paymentmethod/img/method/mollie@2x.png | Bin 0 -> 5366 bytes .../paymentmethod/img/method/mybank@2x.png | Bin 0 -> 2111 bytes .../paymentmethod/img/method/paypal@2x.png | Bin 0 -> 626 bytes .../img/method/paysafecard@2x.png | Bin 0 -> 420 bytes .../paymentmethod/img/method/sofort@2x.png | Bin 0 -> 453 bytes 20 files changed, 20 insertions(+), 20 deletions(-) create mode 100644 version/109/paymentmethod/img/method/Przelewy24@2x.png create mode 100755 version/109/paymentmethod/img/method/applepay@2x.png create mode 100755 version/109/paymentmethod/img/method/bancontact@2x.png create mode 100755 version/109/paymentmethod/img/method/banktransfer@2x.png create mode 100755 version/109/paymentmethod/img/method/belfius@2x.png create mode 100755 version/109/paymentmethod/img/method/creditcard@2x.png create mode 100755 version/109/paymentmethod/img/method/directdebit@2x.png create mode 100755 version/109/paymentmethod/img/method/eps@2x.png create mode 100755 version/109/paymentmethod/img/method/giftcard@2x.png create mode 100755 version/109/paymentmethod/img/method/giropay@2x.png create mode 100755 version/109/paymentmethod/img/method/ideal@2x.png create mode 100755 version/109/paymentmethod/img/method/inghomepay@2x.png create mode 100755 version/109/paymentmethod/img/method/kbc@2x.png create mode 100644 version/109/paymentmethod/img/method/klarna@2x.png create mode 100644 version/109/paymentmethod/img/method/mollie@2x.png create mode 100644 version/109/paymentmethod/img/method/mybank@2x.png create mode 100755 version/109/paymentmethod/img/method/paypal@2x.png create mode 100755 version/109/paymentmethod/img/method/paysafecard@2x.png create mode 100755 version/109/paymentmethod/img/method/sofort@2x.png diff --git a/info.xml b/info.xml index 3aec5ef..88fee91 100644 --- a/info.xml +++ b/info.xml @@ -224,7 +224,7 @@ mollie - + img/method/mollie@2x.png 1 0 mollie.com @@ -244,7 +244,7 @@ mollie Kreditkarte - + img/method/creditcard@2x.png 3 0 mollie.com @@ -265,7 +265,7 @@ mollie Apple Pay - + img/method/applepay@2x.png 3 0 mollie.com @@ -285,7 +285,7 @@ mollie Bancontact - + img/method/bancontact@2x.png 4 0 mollie.com @@ -305,7 +305,7 @@ mollie Banktransfer - + img/method/banktransfer@2x.png 5 0 mollie.com @@ -325,7 +325,7 @@ mollie Belfius - + img/method/belfius@2x.png 6 0 mollie.com @@ -345,7 +345,7 @@ mollie DirectDebit - + img/method/directdebit@2x.png 7 0 mollie.com @@ -365,7 +365,7 @@ mollie EPS - + img/method/eps@2x.png 2 0 mollie.com @@ -385,7 +385,7 @@ mollie Giftcard - + img/method/giftcard@2x.png 8 0 mollie.com @@ -405,7 +405,7 @@ mollie Giropay - + img/method/giropay@2x.png 9 0 mollie.com @@ -425,7 +425,7 @@ mollie iDEAL - + img/method/ideal@2x.png 10 0 mollie.com @@ -445,7 +445,7 @@ mollie ING HomePay - + img/method/inghomepay@2x.png 11 0 mollie.com @@ -465,7 +465,7 @@ mollie KBC - + img/method/kbc@2x.png 12 0 mollie.com @@ -485,7 +485,7 @@ mollie PayPal - + img/method/paypal@2x.png 13 0 mollie.com @@ -505,7 +505,7 @@ mollie paysafecard - + img/method/paysafecard@2x.png 14 0 mollie.com @@ -525,7 +525,7 @@ mollie SOFORT - + img/method/sofort@2x.png 15 0 mollie.com @@ -545,7 +545,7 @@ mollie Klarna Pay Later - + img/method/klarna@2x.png 16 0 mollie.com @@ -565,7 +565,7 @@ mollie Klarna Slice It - + img/method/klarna@2x.png 17 0 mollie.com @@ -585,7 +585,7 @@ mollie Przelewy24 - + img/method/Przelewy24@2x.png 17 0 mollie.com @@ -605,7 +605,7 @@ mollie MyBank - + img/method/mybank@2x.png 17 0 mollie.com diff --git a/version/109/paymentmethod/img/method/Przelewy24@2x.png b/version/109/paymentmethod/img/method/Przelewy24@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..e4e0cd50d180856115f7a0b30a1583bd1a4913b1 GIT binary patch literal 859 zcmV-h1ElOH(NI>=T42<+x9g>;*Gy9DrKtJl=F((p(~XhRMojR(!TROq)4##x zi;wfn&C+>%^UTiFKSt7JYSXp1>ZPgDP*&5InbUcF<%^K^*xKlsoYHP{(wCajZ*$Ra zbJNPo(OY2BWNFmE!S~qO{POeCTVT|{z|(GX;Bt54e}mdsUi8b(sL>`X0000JbW%=J z01%HLkU-Cn-_OsV&!6AlpP5D4UE1#Sax&aZg(%L>z8x33MOZZ8H?WJ;;n51dMe)(}9UH1j29 ze@0RGfq`^s0!X#X7!_srsUP@btltZoyHfrIVq@*+2f)Ge+&BuBcbdrjKu5}NuE;){Yi3#o7gOK=v6Y0{rAbqNgQSz}}0I~5?ej{GsP%?vN z=_l4!?VPOmM>R@!2oOAkd1t|Pb#@H>-d=$PnbBs7=u%Z>9N;0iml z2#guk2rk-V%mMEvxQCZ1@+-_*(mao=fPWKs%h@Mp0)~gcfgO7j{4M(n<{@x^Z^Hk! ze1;0X32xx)(NPC3aetZbtnBss>W2NT-v%Bch%He^5RXIyLDWRp5;o{lcPr>qmkRZj lpHDtfd;A2~X0zTP_aA;i{an>LN7rz#m}I!{TEUogY_hW!fX z1?mg>C*-erx%(so1LG!77srr_xVP7C<}EQ0XbW_HZ(Bb#ysRpA(wRN~nf+#OlTe%( zXkfncL^KKCCrg-Lh=kEnU|a;ZB9QaR>Td+?i96wEUURmd^*;_;}q*?JtCN zs9v0_oUIYrJ>{ItUF)Suj=nY*E;y-_bg}zQ;ZT|@FU4Qeut^B)WfWUjV9g-3v@K+f-ik;kV{MOr_6wK;GGik>mTp$V%-RtP)+CPEi`n!UgTe~DWM4fFWeR( literal 0 HcmV?d00001 diff --git a/version/109/paymentmethod/img/method/bancontact@2x.png b/version/109/paymentmethod/img/method/bancontact@2x.png new file mode 100755 index 0000000000000000000000000000000000000000..a87af77d20330ab4ee197fd750d0bd39a5b10f90 GIT binary patch literal 582 zcmV-M0=fN(P)lk!lq%lq?@9+Qr z|M>X$=jZ1jWQqR%{`vX&|JVTk=U{-T&j0$~pTFAg&hoWPVjpU$|LlN(mQMfcfPbmZpr$+j>2Uw#P;ZV{AZe)(UZem0@6X@u|MkEB z;XwWU{r~1*Ky`MXzS=N!uW*i8kF?YfT$A7F^MIC5pQk%!Gip%)000nlQchC<&w%eB zkRX4bpb&7+Z;x=Vl85vF00AONL_t(|UhS6GZp0uI1+V+IBnNQY-qL&T?f<_j%Vs4k zWi4ZPi#+c$LIR;fk}z^m8)w(24LdL-qBSjmiImqQ6%1%eKSC_H5hBJOQ3wcbh=A9j z0E`>M;F1Gj9uRN{NX-L}@Ce`*0RKJE1nw{TTbXGF`gs|rT7l!dln0%_EVm0RbGyKB zqJ*zRaiSTxE%@_=;_x?lSs8dz{y6#LPln}z>8GT40dLB`KB#<1qlM(E;D0OsM*0?TeIhg`dn6;Q{6Fh2l%qOS4K%wo8-q7AUD{?yGF(55vm4C&H_FzBH+J=d4+57}kr Up-!czfB*mh07*qoM6N<$g3OCHTL1t6 literal 0 HcmV?d00001 diff --git a/version/109/paymentmethod/img/method/banktransfer@2x.png b/version/109/paymentmethod/img/method/banktransfer@2x.png new file mode 100755 index 0000000000000000000000000000000000000000..c70206bef4893f23fcd59d436273108d2f2eebc7 GIT binary patch literal 801 zcmV++1K#|JP)lk!lq*=;-9+mkX z{{U2_ztrjP@9%)A(*D5?-|6)J(MtZwET6yKpugSt`1lZBsz86cAZf7q`T3Bv*Z%(g z-|F=K#U1|5JO0^dAZoDx_u=pL`RC{7_xJZ;l*j-3@c!I)@AdkSwAlXDS^mf@aG%W2 z;O`J$tN-Md>+9=KiNUYR<6xA=@AUcq@WXGP%>DiS|LnB>%sc+*q+gWBFm$#4l$oJ=bMJL) zN$}UM z^EEI7D0q#*=`w@Mb&#yX6$WP@x&}s<8JvJ@pvqecQO^sez9^Xbs$t>(|Nn0Y_`k@X z`u+Uv`wm6F?mz#2{?4!aFGTBV&I9cbE(!7rW)PTg{{H;_^9ubA3J&Kd+&@2If#l5V zkwEFKo-U3d6>)E`o#Z>Lz~g$+{n^fDUKQE@|Mgd!a9=T#&e{4(sr-HO1o4KQ>uv;= zWX2_)yrQzk;QY@iN0x35n7oK-g-2+63_H(@QU|u6Z>|Z!r6lZ1zes9a?+x$E9%YhzX@O1Ta JS?83{1OT9Jm%RW0 literal 0 HcmV?d00001 diff --git a/version/109/paymentmethod/img/method/creditcard@2x.png b/version/109/paymentmethod/img/method/creditcard@2x.png new file mode 100755 index 0000000000000000000000000000000000000000..b08be792753326b65345c752a6f350182a9393d2 GIT binary patch literal 3125 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 P00000NkvXXu0mjf3Vis# literal 0 HcmV?d00001 diff --git a/version/109/paymentmethod/img/method/directdebit@2x.png b/version/109/paymentmethod/img/method/directdebit@2x.png new file mode 100755 index 0000000000000000000000000000000000000000..514ff845b84d38cd8eb97b9e2c53e5c117967944 GIT binary patch literal 801 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 literal 0 HcmV?d00001 diff --git a/version/109/paymentmethod/img/method/giropay@2x.png b/version/109/paymentmethod/img/method/giropay@2x.png new file mode 100755 index 0000000000000000000000000000000000000000..b787e1fee50c9bcca112f734ef4bcbd4ecfb6d6b GIT binary patch literal 602 zcmV-g0;T5Kx~EOrH!)pASu;4ojd8OQ8=; zpbt!;!_w#B>GK{}r)iJG@bvggdAR@o{+6-TrM%mCn#w$GvMpk*ho#Tb-RaC5+y)hho537JnGBqPA~G@Ik#rt1jWCNmt_X5yY-;OM4Sm|;L0fCz(H!a59C z!6FQJ1`O=K0(U?&WmHmQ%ovl1g=xY%=0>sX7T{!DDr3#1AfT>{>*NQdp;XxeDnn^6 z;Fg|~18)oh=#B%J574HG=ZK=b0(2)=ZWs@6u|Psp2S`Ms-aSCKNc4dZ3ml0Y1JpF0 zACT7(WFOdH$J={=+}Kh?t@=QTh`Y)S;{lL4q2$K&0aK;&(@GqDK&DI^R~^tLy#OA$ z1Nay30gQkc{Q&0jzz(SpmbnlhVhfzVhaBhB0($}wh1S_^$N7}lg}e4p3Ic|F4;Z~b zTY@72isxg1#8BrSfnxv^S{6kiGl4E$H2v|f@*S9m0aJJk172Vm21F3Hg)IO)g#GGT oVe}rh6KIQG--ZM8)e@S10aM=ZI#^TblmGw#07*qoM6N<$f@FIOx&QzG literal 0 HcmV?d00001 diff --git a/version/109/paymentmethod/img/method/ideal@2x.png b/version/109/paymentmethod/img/method/ideal@2x.png new file mode 100755 index 0000000000000000000000000000000000000000..efc4315a96a6b2d9b160578a65fe52206783f2ca GIT binary patch literal 845 zcmV-T1G4;yP)lk!ZZ65OMGC?}UYf;o;!m;NZf-!qXsn`1tsvqob6RlsGvz=jZ45_xJw({`vX& z+CYuwfU@xL?-Nv%`QPmApT=fqW&i*F(b3WK zzuD%1v(zAZ>+9>Xv$F87&$F|$@bK^%8W`-K#nT^p^1s=^!okAA!Tj&_DJdxZ{r%~X zz3Gp=&=7F!pvK@}pYN~F>5#mWl#|_1mb0_6g@uIHFobn>b?J}1M@UB*8yIC~W#VwE zc6N2$P?z9fpjKB^=ker~0000HbW%=J0PlbhkiUP=Adhe$&v1`#zea&7rvLx}*GWV{ zRCr#^*2j+9Fc5%YO7?ntl9{1;aqqou@0;Fxd;j;y*jNN`HV2Bl>~|3_{4oLqkzy%V z*t96C%}2Z9&SQ)86vWClksDVqqe|=&Z3|YQQjA*4CE6Eai>Qp6VzP3=CKt6Gk}WnU zMr|=|2#YGH?I~G;2n`TD#K5)puk^^z67b+ZZd-naz)7$!d_QRdc|mw#b1~<{2k2)FEaYF&OT-`GX$RPM#Nt`QAi#wXJk>zhFTO>59`Wo^#}<>sMjOed(+{-3ru0A7D$0jI558$ z)N0PF!RsCe2|{A+{jU4@5&uc>v9T(>X>= zpc$wJPDAG6XudKWan^4w_bUdHVBPG<>jQiVOn&QMzg?RgEbW=`(e{u7#up5;D^8W3 z2%8R3n@hIHS^6WCiFSq9p;8&OR7*Sn%M-cP>{s2YOOzKYHtDf;#GS4DUiRI4c22NA XzpeJ7+7%dW00000NkvXXu0mjfybi$$ literal 0 HcmV?d00001 diff --git a/version/109/paymentmethod/img/method/inghomepay@2x.png b/version/109/paymentmethod/img/method/inghomepay@2x.png new file mode 100755 index 0000000000000000000000000000000000000000..538f219588886db215757eafd5c5151241f18b5a GIT binary patch literal 1118 zcmV-k1flzhP)`_0RK|}|55<|Q2_r?0RL0~|5E_}r-1)w9RKX&|5E_}=Gy;L z0RR90|6UOPlVJbp-~WC<|J1+#zn}l9fd6P9|A|olb1?tk&;RxB|Mc(wo^bzkF#pQ0 z|Fn<)>fisgkpF2Q|G%LBsek{okpG@<|H-fazM%hUAODC@|H-ibs(=5~!2gtB|K894 zs(@(VAMyYI01|XkPE!C7&ySx#AdugXK#$)bkdUC?LT6GX000A7Nkl+_F4;G0`t->#NE zT;V&r`f!+EySiCj<6V7Pt?{mYTH&4jj{)gM0TN(F3?6st+kjw6 z>LApXPB>Unt8V~;Cik9f49AhQ!$i7^fuL#4vW=&{86JR|lTsG~BRymzfEs|JX9J1K z03Dw$1C&G3WKK=%kB`J1r1*<~s2`z=k6T78&3xGOL&RV&0xXfJ0Ql@xfEn*A1CX9E zQ!WBD5?VbTK7XTsCp`U6crw}TsH%60W z2hoh@0nLYSxRBab{+9<3C+^Mz9xYb&ZxhMVDb+cqriY2<9AG-<8gN)^Cix5?)@kAU z;?6$;-SN`NKvD-cR@w%n?9AWi0I~xRElDnK5^Rh@FtDVHX8@ZJfJl->N&_A{l2bso z2x`kJr-3lmJ%9)DK@>~Q{7brt3fNKr^rbrq+|{-iAekxBG;uoyGqur4Ei0S?0=Yll zF_SR>W}x;7ttLalDFCI-OXsp?(S;*|rkk|uOcTs~fUR;0m?79z>!T@dSC<#zVpen3 zDj@L*GoMZY$tw7C*m%o|vLvel!qz~FMPzph=x6{KTjppdC7aC#VVdHg)$wl$bf*AC z1-Rnnz*LgVO4|B5HX#U@PXUn*;sq_sC5u*2fG7j7o&o~>%Wn3WWcg~#QmPptG|8+k2H7XW|=xVi9nUeg`1*I2IB*YJ(+JNL|VD24JQDXa_~} zqMBf8fF~Vbz5wvk*3xb81`yK5AZAEW$9)?Qt+BO>C3E@1Aktu4fz|6HW^Y;1@lk!lq%mkX z{~%3y0h-K!%;mq#+4%VQ5J7OCv&KMYjPLUG@9*#T_xE6cpCPBxaK_?)nX{kS?7!yn zfSI!2=Is9d{_pwx05oR#`T5`T`RC{7L9^Llzu!=FmQcCekkjew>+3LDf{>=XK(pDe zzt4c0vd`J#Fs;_V%-D~nykNlKAg9yc^7t^U)_~3BfX(J`#^Vv8&k>-{-}3p8(&?|? z?{JN&{r&x)v&FFA?=V_}aEz&7z~7M5=+D{X&+PS}+3awQs351(ptHqzpNxV4000qm zQchCIy&+X> z=*5Ul;OaQ@NK`Vzy8t_g2?_Jis)3C$i910Xw$PIU9&Uk!LpkskEkL9-LfkOWJAbaP zUroip18r(eg}^hN*BXg{sb1!Yfc6S#iGXvxN(6jb7x=sau0_D;#S-`?0_b=FJSG`H zPqbnfvWg$g}i**@5@#v5NT=$lzqSQdXDg|8f zIHlhJQN%Mfm~#2YP9b1YgB(!GAN!r?CIjA)sTANZfG||7{JhG5H)Vm3e?0>E>_vVi zq!;d4SOSQYxt#%m;F70Lx8o{r!Tt9&c8CI14(M}40nf9jzsNQAmkVA7gAM$Z|1+@m z0b{)*&IIp+jVE#-MjL9Dd6xv65#{P&<3u77*DDnbtf@m157r`vbG^_r?Ff8 d>Rr1A+%FMH_Q$8Zwr>Cc002ovPDHLkV1oT`waEYg literal 0 HcmV?d00001 diff --git a/version/109/paymentmethod/img/method/klarna@2x.png b/version/109/paymentmethod/img/method/klarna@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..e28a187b81e7c5a6256fea7382a643762746dd1e GIT binary patch literal 896 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 literal 0 HcmV?d00001 diff --git a/version/109/paymentmethod/img/method/paypal@2x.png b/version/109/paymentmethod/img/method/paypal@2x.png new file mode 100755 index 0000000000000000000000000000000000000000..a816d7201f59ea7cef713f5e7895e66dcd6ee9a7 GIT binary patch literal 626 zcmV-&0*(ENP)zW{Q;0CK+oaK8X?zW{Q<0CB+pa=`#_!2of;na1S+alrro z|IFg@&*bxRu-m`e?~lRb-|hDbcETox$#AdRv()Q`yWm5X&|s$5P@dDD$>-eb_JFwG zpUUS$m(j@K@sPpeFpSLa_WMAU&p?#W{Qdsu^7&w=*MGR*^7#DO>Gd#+%P@?~P@U7S z((9ba=CIQ0sn6-_^!k0a-V=Mp)8_OXfyX(K&a%|&;_mkldc-e_%lZ5LgSp`#gUC6M z&erGk#LeN$0000GbW%=J0M8)rfN+qXfDoX6Z;yYFN6jxl0003wNklC4+MXiktqCYwRgSg6)KJbf z5Lj1?Y5+oU@|#dstX9C|0Ujt`J{M4b8Wr^cdi(ak0iFt>ORE}Nts8qh=FWCkI)}aEnE&{1?2hI?PIY68@ zbOdbw0PvXrf5i!Szy>sZ79ap>ye%)UHj^sMYbqagD6U zaJzaI>n$ypF23oVdS#o6|W|*DFT6j;X_Pjl^+{$7FxcM`F8{J!B6QqfZ6J=?T z0Z*i4z#}$g7~II(N7`*?T& O0000+D{~L?`zkmGy`PKgqj{m>0 z^Z&xI|35zdzp(26fxiDA9{<0v`v1;`{~L<_uT1&>;_Ck$4fn+3S%6jwlmz(&Gn{vr zARutRf5Q2Gh4~8e7rbanOaaP$^>lFzsfc?!?c};<10L727Z_ycPF(r9`v3o4QC^`f zNy*irThr_Lx8*f4F=sBE;Is9vL&{b+wWF_Q`cLpRlDMX^fZ@i14v}pdO3hrZ8V-u{ z6@GBmNPp@1=O;WPYJWl57EYgv)6tK(j<>!KX1Tkg-1yN7-6M=yr*jX!QWr1lo!e&; zepvX8JR>o1saCg`3ZOWgj;^L2z+zGho&3IENy|Lc5*g&izjA{*O9T;DjDIk7S9e6n)( p;e>?q6P^m(l+{vMe5&Mx9fO|m{vZE%WkG?%;OXk;vd$@?2>_eS)Oi2^ literal 0 HcmV?d00001 From e3a41d1b2329c4207f112771842e2668d307c0f6 Mon Sep 17 00:00:00 2001 From: "dash.bar" Date: Mon, 17 Aug 2020 08:47:05 +0000 Subject: [PATCH 145/280] update base files --- version/109/adminmenu/tpl/info.tpl | 20 ++++++++++++++- version/109/class/Helper.php | 41 ++++++++++++++++++++++++++++++ version/109/tpl/_alerts.tpl | 10 ++++++++ 3 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 version/109/tpl/_alerts.tpl diff --git a/version/109/adminmenu/tpl/info.tpl b/version/109/adminmenu/tpl/info.tpl index 77a48dc..2952fc6 100644 --- a/version/109/adminmenu/tpl/info.tpl +++ b/version/109/adminmenu/tpl/info.tpl @@ -93,4 +93,22 @@ {if file_exists("{$smarty['current_dir']}/_addon.tpl")} {include file="{$smarty['current_dir']}/_addon.tpl"} -{/if} \ No newline at end of file +{/if} +{if isset($oPlugin)} + +{/if} diff --git a/version/109/class/Helper.php b/version/109/class/Helper.php index 8f4772c..5f2a8be 100644 --- a/version/109/class/Helper.php +++ b/version/109/class/Helper.php @@ -181,6 +181,47 @@ public static function init() 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 * 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} From b23858286c24233838dea946243465c05efa008e Mon Sep 17 00:00:00 2001 From: "C. Proske" Date: Mon, 17 Aug 2020 11:16:41 +0200 Subject: [PATCH 146/280] fix #89 --- version/109/adminmenu/orders.php | 45 +++++++++++++++------------- version/109/adminmenu/tpl/order.tpl | 7 +---- version/109/adminmenu/tpl/orders.tpl | 8 +---- 3 files changed, 27 insertions(+), 33 deletions(-) diff --git a/version/109/adminmenu/orders.php b/version/109/adminmenu/orders.php index 1704bf2..ff35df5 100644 --- a/version/109/adminmenu/orders.php +++ b/version/109/adminmenu/orders.php @@ -13,7 +13,16 @@ } require_once __DIR__ . '/../paymentmethod/JTLMollie.php'; global $oPlugin; - $ordersMsgs = []; + + if (ini_get('session.gc_maxlifetime') < 172800) { + Helper::addAlert(sprintf('Session Laufzeit ist derzeit %d Sekunden. Bei Zahlung vor Bestellabschluss sind ' + . 'die Zahlungslinks jedoch bis zu 48h gültig (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']) { @@ -96,71 +105,69 @@ exit(); } catch (Exception $e) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Fehler:' . $e->getMessage()]; + Helper::addAlert('Fehler:' . $e->getMessage(), 'danger', 'orders'); } break; case 'refund': if (!array_key_exists('id', $_REQUEST)) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; + Helper::addAlert('Keine ID angegeben!', 'danger', 'orders'); break; } $payment = Payment::getPaymentMollie($_REQUEST['id']); if (!$payment) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; + Helper::addAlert('Order nicht gefunden!', 'danger', 'orders'); break; } $order = JTLMollie::API()->orders->get($_REQUEST['id']); - if ($order->status == OrderStatus::STATUS_CANCELED) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung bereits storniert']; + 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; - break; case 'cancel': if (!array_key_exists('id', $_REQUEST)) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; + Helper::addAlert('Keine ID angeben!', 'danger', 'orders'); break; } $payment = Payment::getPaymentMollie($_REQUEST['id']); if (!$payment) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; + Helper::addAlert('Order nicht gefunden!', 'danger', 'orders'); break; } $order = JTLMollie::API()->orders->get($_REQUEST['id']); if ($order->status == OrderStatus::STATUS_CANCELED) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung bereits storniert']; + 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; - break; case 'capture': if (!array_key_exists('id', $_REQUEST)) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; + Helper::addAlert('Keine ID angeben!', 'danger', 'orders'); break; } $payment = Payment::getPaymentMollie($_REQUEST['id']); if (!$payment) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; + 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) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Nur autorisierte Zahlungen können erfasst werden!']; + Helper::addAlert('Nur autorisierte Zahlungen können erfasst werden!', 'danger', 'orders'); break; } $oBestellung = new Bestellung($payment->kBestellung, true); if (!$oBestellung->kBestellung) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung konnte nicht geladen werden!']; + Helper::addAlert('Bestellung konnte nicht geladen werden!', 'danger', 'orders'); break; } @@ -177,14 +184,14 @@ // CAPTURE ALL $shipment = JTLMollie::API()->shipments->createFor($order, $options); - $ordersMsgs[] = (object)['type' => 'success', 'text' => 'Zahlung wurde erfolgreich erfasst!']; + 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)) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; + Helper::addAlert('Keine ID angeben!', 'danger', 'orders'); break; } @@ -209,8 +216,7 @@ Shop::Smarty()->assign('payment', $payment) ->assign('oBestellung', $oBestellung) ->assign('order', $order) - ->assign('logs', $logs) - ->assign('ordersMsgs', $ordersMsgs); + ->assign('logs', $logs); Shop::Smarty()->display($oPlugin->cAdminmenuPfad . '/tpl/order.tpl'); return; } @@ -226,7 +232,6 @@ } Shop::Smarty()->assign('payments', $payments) - ->assign('ordersMsgs', $ordersMsgs) ->assign('admRoot', str_replace('http:', '', $oPlugin->cAdminmenuPfadURL)) ->assign('hasAPIKey', trim(Helper::getSetting("api_key")) !== ''); diff --git a/version/109/adminmenu/tpl/order.tpl b/version/109/adminmenu/tpl/order.tpl index 5b3d172..4cc896f 100644 --- a/version/109/adminmenu/tpl/order.tpl +++ b/version/109/adminmenu/tpl/order.tpl @@ -19,12 +19,7 @@ {/if} -{if count($ordersMsgs)} - {foreach from=$ordersMsgs item=alert} -
{$alert->text}
- {/foreach} -
-{/if} +{ws_mollie\Helper::showAlerts('orders')} diff --git a/version/109/adminmenu/tpl/orders.tpl b/version/109/adminmenu/tpl/orders.tpl index 4ec7af3..d556026 100644 --- a/version/109/adminmenu/tpl/orders.tpl +++ b/version/109/adminmenu/tpl/orders.tpl @@ -1,10 +1,4 @@ - -{if count($ordersMsgs)} - {foreach from=$ordersMsgs item=alert} -
{$alert->text}
- {/foreach} -
-{/if} +{ws_mollie\Helper::showAlerts('orders')} {if $hasAPIKey == false} From 124fe9652947d871e10452c21f037023cd30811e Mon Sep 17 00:00:00 2001 From: "C. Proske" Date: Mon, 17 Aug 2020 14:27:39 +0200 Subject: [PATCH 147/280] fix #87 --- info.xml | 1 + version/109/adminmenu/tpl/orders.tpl | 3 + version/109/paymentmethod/JTLMollie.php | 118 ++++++++++++------------ version/109/sql/107.sql | 4 - version/109/sql/109.sql | 2 + 5 files changed, 65 insertions(+), 63 deletions(-) delete mode 100644 version/109/sql/107.sql create mode 100644 version/109/sql/109.sql diff --git a/info.xml b/info.xml index 88fee91..277ea46 100644 --- a/info.xml +++ b/info.xml @@ -38,6 +38,7 @@ 2020-04-24 + 109.sql 131_globalinclude.php diff --git a/version/109/adminmenu/tpl/orders.tpl b/version/109/adminmenu/tpl/orders.tpl index d556026..669015a 100644 --- a/version/109/adminmenu/tpl/orders.tpl +++ b/version/109/adminmenu/tpl/orders.tpl @@ -28,6 +28,9 @@ {if $payment->cMode == 'test'} TEST {/if} + {if $payment->bLockTimeout} + LOCK TIMEOUT + {/if} - - + + - + {foreach from=$allMethods item=method} - - - + + + {/foreach} diff --git a/version/110/paymentmethod/JTLMollie.php b/version/110/paymentmethod/JTLMollie.php index fa85b17..ba208be 100644 --- a/version/110/paymentmethod/JTLMollie.php +++ b/version/110/paymentmethod/JTLMollie.php @@ -58,6 +58,7 @@ public function __construct($moduleID, $nAgainCheckout = 0) { parent::__construct($moduleID, $nAgainCheckout); Helper::init(); + $this->cModulId = "kPlugin_" . Helper::oPlugin()->kPlugin . "_mollie{$moduleID}"; } /** @@ -139,7 +140,7 @@ public function setOrderStatusToPaid($order) */ public function preparePaymentProcess($order) { - $logData = '#' . $order->kBestellung . "§" . $order->cBestellNr; + $logData = '#' . $order->kBestellung . "?" . $order->cBestellNr; $payable = (float)$order->fGesamtsumme > 0; @@ -162,7 +163,7 @@ public function preparePaymentProcess($order) $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) { + if ($payment && $payment->cStatus === OrderStatus::STATUS_CREATED && $payment->cCheckoutURL) { $logData .= '$' . $payment->kID; if (!$this->duringCheckout) { Session::getInstance()->cleanUp(); @@ -314,7 +315,7 @@ public static function API() protected function getOrderData(Bestellung $order, $hash) { $locale = self::getLocale($_SESSION['cISOSprache'], $_SESSION['Kunde']->cLand); - $expiryDays = (int)Helper::getSetting('expiryDays') && (int)Helper::getSetting('expiryDays') <= static::MAX_EXPIRY_DAYS ? (int)(int)Helper::getSetting('expiryDays') : static::MAX_EXPIRY_DAYS; + $expiryDays = $this->getExpiryDays(); $_currencyFactor = (float)$order->Waehrung->fFaktor; $data = [ @@ -561,6 +562,18 @@ public static function getLocale($cISOSprache, $country = null) } } + /** + * @return int + */ + public function getExpiryDays() + { + $max = static::MAX_EXPIRY_DAYS; + $global = (int)Helper::getSetting('expiryDays'); + $local = (int)Helper::oPlugin()->oPluginEinstellungAssoc_arr[$this->cModulId . '_expiryDays']; + + return (int)min($local > 0 ? $local : $global, $global, $max); + } + public function optionaleRundung($gesamtsumme) { $conf = Shop::getSettings([CONF_KAUFABWICKLUNG]); @@ -624,7 +637,7 @@ public function handleNotification($order, $hash, $args) */ public function finalizeOrder($order, $hash, $args) { - if(array_key_exists('MOLLIE_CHECKBOXES', $_SESSION) && is_array($_SESSION['MOLLIE_CHECKBOXES'])){ + if (array_key_exists('MOLLIE_CHECKBOXES', $_SESSION) && is_array($_SESSION['MOLLIE_CHECKBOXES'])) { $_POST = array_merge($_POST, $_SESSION['MOLLIE_CHECKBOXES']); } $result = false; From e1cf2eb8812bc209ef6b86b71362e0880524dc79 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Thu, 19 Nov 2020 16:46:10 +0100 Subject: [PATCH 159/280] composer update --- composer.lock | 368 ++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 283 insertions(+), 85 deletions(-) diff --git a/composer.lock b/composer.lock index 937ee68..6073b23 100644 --- a/composer.lock +++ b/composer.lock @@ -8,16 +8,16 @@ "packages": [ { "name": "composer/ca-bundle", - "version": "1.2.7", + "version": "1.2.8", "source": { "type": "git", "url": "https://github.com/composer/ca-bundle.git", - "reference": "95c63ab2117a72f48f5a55da9740a3273d45b7fd" + "reference": "8a7ecad675253e4654ea05505233285377405215" }, "dist": { "type": "zip", - "url": "https://github.com/gitapi/repos/composer/ca-bundle/zipball/95c63ab2117a72f48f5a55da9740a3273d45b7fd", - "reference": "95c63ab2117a72f48f5a55da9740a3273d45b7fd", + "url": "https://github.com/gitapi/repos/composer/ca-bundle/zipball/8a7ecad675253e4654ea05505233285377405215", + "reference": "8a7ecad675253e4654ea05505233285377405215", "shasum": "" }, "require": { @@ -65,25 +65,29 @@ "url": "https://packagist.com", "type": "custom" }, + { + "url": "https://github.com/composer", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/composer/composer", "type": "tidelift" } ], - "time": "2020-04-08T08:27:21+00:00" + "time": "2020-08-23T12:54:47+00:00" }, { "name": "guzzlehttp/guzzle", - "version": "6.5.3", + "version": "6.5.5", "source": { "type": "git", "url": "https://github.com/guzzle/guzzle.git", - "reference": "aab4ebd862aa7d04f01a4b51849d657db56d882e" + "reference": "9d4290de1cfd701f38099ef7e183b64b4b7b0c5e" }, "dist": { "type": "zip", - "url": "https://github.com/gitapi/repos/guzzle/guzzle/zipball/aab4ebd862aa7d04f01a4b51849d657db56d882e", - "reference": "aab4ebd862aa7d04f01a4b51849d657db56d882e", + "url": "https://github.com/gitapi/repos/guzzle/guzzle/zipball/9d4290de1cfd701f38099ef7e183b64b4b7b0c5e", + "reference": "9d4290de1cfd701f38099ef7e183b64b4b7b0c5e", "shasum": "" }, "require": { @@ -91,7 +95,7 @@ "guzzlehttp/promises": "^1.0", "guzzlehttp/psr7": "^1.6.1", "php": ">=5.5", - "symfony/polyfill-intl-idn": "^1.11" + "symfony/polyfill-intl-idn": "^1.17.0" }, "require-dev": { "ext-curl": "*", @@ -137,27 +141,27 @@ "rest", "web service" ], - "time": "2020-04-18T10:38:46+00:00" + "time": "2020-06-16T21:01:06+00:00" }, { "name": "guzzlehttp/promises", - "version": "v1.3.1", + "version": "1.4.0", "source": { "type": "git", "url": "https://github.com/guzzle/promises.git", - "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646" + "reference": "60d379c243457e073cff02bc323a2a86cb355631" }, "dist": { "type": "zip", - "url": "https://github.com/gitapi/repos/guzzle/promises/zipball/a59da6cf61d80060647ff4d3eb2c03a2bc694646", - "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646", + "url": "https://github.com/gitapi/repos/guzzle/promises/zipball/60d379c243457e073cff02bc323a2a86cb355631", + "reference": "60d379c243457e073cff02bc323a2a86cb355631", "shasum": "" }, "require": { - "php": ">=5.5.0" + "php": ">=5.5" }, "require-dev": { - "phpunit/phpunit": "^4.0" + "symfony/phpunit-bridge": "^4.4 || ^5.1" }, "type": "library", "extra": { @@ -188,20 +192,20 @@ "keywords": [ "promise" ], - "time": "2016-12-20T10:07:11+00:00" + "time": "2020-09-30T07:37:28+00:00" }, { "name": "guzzlehttp/psr7", - "version": "1.6.1", + "version": "1.7.0", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "239400de7a173fe9901b9ac7c06497751f00727a" + "reference": "53330f47520498c0ae1f61f7e2c90f55690c06a3" }, "dist": { "type": "zip", - "url": "https://github.com/gitapi/repos/guzzle/psr7/zipball/239400de7a173fe9901b9ac7c06497751f00727a", - "reference": "239400de7a173fe9901b9ac7c06497751f00727a", + "url": "https://github.com/gitapi/repos/guzzle/psr7/zipball/53330f47520498c0ae1f61f7e2c90f55690c06a3", + "reference": "53330f47520498c0ae1f61f7e2c90f55690c06a3", "shasum": "" }, "require": { @@ -214,15 +218,15 @@ }, "require-dev": { "ext-zlib": "*", - "phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.8" + "phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.8 || ^9.3.10" }, "suggest": { - "zendframework/zend-httphandlerrunner": "Emit PSR-7 responses" + "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.6-dev" + "dev-master": "1.7-dev" } }, "autoload": { @@ -259,20 +263,20 @@ "uri", "url" ], - "time": "2019-07-01T23:21:34+00:00" + "time": "2020-09-30T07:37:11+00:00" }, { "name": "mollie/mollie-api-php", - "version": "v2.17.0", + "version": "v2.24.0", "source": { "type": "git", "url": "https://github.com/mollie/mollie-api-php.git", - "reference": "ee22d0301aee55a41ef2e7d201ef29f86550d1f7" + "reference": "52bd606724109906d61226698c8b031ccae9e637" }, "dist": { "type": "zip", - "url": "https://github.com/gitapi/repos/mollie/mollie-api-php/zipball/ee22d0301aee55a41ef2e7d201ef29f86550d1f7", - "reference": "ee22d0301aee55a41ef2e7d201ef29f86550d1f7", + "url": "https://github.com/gitapi/repos/mollie/mollie-api-php/zipball/52bd606724109906d61226698c8b031ccae9e637", + "reference": "52bd606724109906d61226698c8b031ccae9e637", "shasum": "" }, "require": { @@ -280,7 +284,7 @@ "ext-curl": "*", "ext-json": "*", "ext-openssl": "*", - "guzzlehttp/guzzle": "^6.3", + "guzzlehttp/guzzle": "^6.3 || ^7.0", "php": ">=5.6" }, "require-dev": { @@ -345,7 +349,56 @@ "sofortbanking", "subscriptions" ], - "time": "2020-02-25T12:19:37+00:00" + "time": "2020-10-15T12:55:48+00:00" + }, + { + "name": "paragonie/random_compat", + "version": "v2.0.19", + "source": { + "type": "git", + "url": "https://github.com/paragonie/random_compat.git", + "reference": "446fc9faa5c2a9ddf65eb7121c0af7e857295241" + }, + "dist": { + "type": "zip", + "url": "https://github.com/gitapi/repos/paragonie/random_compat/zipball/446fc9faa5c2a9ddf65eb7121c0af7e857295241", + "reference": "446fc9faa5c2a9ddf65eb7121c0af7e857295241", + "shasum": "" + }, + "require": { + "php": ">=5.2.0" + }, + "require-dev": { + "phpunit/phpunit": "4.*|5.*" + }, + "suggest": { + "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." + }, + "type": "library", + "autoload": { + "files": [ + "lib/random.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com" + } + ], + "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", + "keywords": [ + "csprng", + "polyfill", + "pseudorandom", + "random" + ], + "time": "2020-10-15T10:06:57+00:00" }, { "name": "psr/http-message", @@ -443,12 +496,12 @@ "source": { "type": "git", "url": "https://github.com/Roave/SecurityAdvisories.git", - "reference": "2bdae3cc8428d637d5c86c8c33d0a3354ce93f7f" + "reference": "d50c04efe771797b10510188c4fbd11ee9fb1bdc" }, "dist": { "type": "zip", - "url": "https://github.com/gitapi/repos/Roave/SecurityAdvisories/zipball/2bdae3cc8428d637d5c86c8c33d0a3354ce93f7f", - "reference": "2bdae3cc8428d637d5c86c8c33d0a3354ce93f7f", + "url": "https://github.com/gitapi/repos/Roave/SecurityAdvisories/zipball/d50c04efe771797b10510188c4fbd11ee9fb1bdc", + "reference": "d50c04efe771797b10510188c4fbd11ee9fb1bdc", "shasum": "" }, "conflict": { @@ -457,11 +510,15 @@ "alterphp/easyadmin-extension-bundle": ">=1.2,<1.2.11|>=1.3,<1.3.1", "amphp/artax": "<1.0.6|>=2,<2.0.6", "amphp/http": "<1.0.1", + "amphp/http-client": ">=4,<4.4", "api-platform/core": ">=2.2,<2.2.10|>=2.3,<2.3.6", "asymmetricrypt/asymmetricrypt": ">=0,<9.9.99", "aws/aws-sdk-php": ">=3,<3.2.1", "bagisto/bagisto": "<0.1.5", - "bolt/bolt": "<3.6.10", + "barrelstrength/sprout-base-email": "<1.2.7", + "barrelstrength/sprout-forms": "<3.9", + "baserproject/basercms": ">=4,<=4.3.6|>=4.4,<4.4.1", + "bolt/bolt": "<3.7.1", "brightlocal/phpwhois": "<=4.2.5", "buddypress/buddypress": "<5.1.2", "bugsnag/bugsnag-laravel": ">=2,<2.0.2", @@ -474,10 +531,11 @@ "composer/composer": "<=1-alpha.11", "contao-components/mediaelement": ">=2.14.2,<2.21.1", "contao/core": ">=2,<3.5.39", - "contao/core-bundle": ">=4,<4.4.46|>=4.5,<4.8.6", + "contao/core-bundle": "= 4.10.0|>=4,<4.4.52|>=4.5,<4.9.6", "contao/listing-bundle": ">=4,<4.4.8", "datadog/dd-trace": ">=0.30,<0.30.2", "david-garcia/phpwhois": "<=4.3.1", + "derhansen/sf_event_mgt": "<4.3.1|>=5,<5.1.1", "doctrine/annotations": ">=1,<1.2.7", "doctrine/cache": ">=1,<1.3.2|>=1.4,<1.4.2", "doctrine/common": ">=2,<2.4.3|>=2.5,<2.5.1", @@ -487,10 +545,10 @@ "doctrine/mongodb-odm": ">=1,<1.0.2", "doctrine/mongodb-odm-bundle": ">=2,<3.0.1", "doctrine/orm": ">=2,<2.4.8|>=2.5,<2.5.1", - "dolibarr/dolibarr": "<=10.0.6", + "dolibarr/dolibarr": "<11.0.4", "dompdf/dompdf": ">=0.6,<0.6.2", - "drupal/core": ">=7,<7.69|>=8,<8.7.12|>=8.8,<8.8.4", - "drupal/drupal": ">=7,<7.69|>=8,<8.7.12|>=8.8,<8.8.4", + "drupal/core": ">=7,<7.74|>=8,<8.8.11|>=8.9,<8.9.9|>=9,<9.0.8", + "drupal/drupal": ">=7,<7.74|>=8,<8.8.11|>=8.9,<8.9.9|>=9,<9.0.8", "endroid/qr-code-bundle": "<3.4.2", "enshrined/svg-sanitize": "<0.13.1", "erusev/parsedown": "<1.7.2", @@ -499,10 +557,12 @@ "ezsystems/ezfind-ls": ">=5.3,<5.3.6.1|>=5.4,<5.4.11.1|>=2017.12,<2017.12.0.1", "ezsystems/ezplatform": ">=1.7,<1.7.9.1|>=1.13,<1.13.5.1|>=2.5,<2.5.4", "ezsystems/ezplatform-admin-ui": ">=1.3,<1.3.5|>=1.4,<1.4.6", - "ezsystems/ezplatform-admin-ui-assets": ">=4,<4.2", + "ezsystems/ezplatform-admin-ui-assets": ">=4,<4.2.1|>=5,<5.0.1|>=5.1,<5.1.1", + "ezsystems/ezplatform-kernel": ">=1,<1.0.2.1", "ezsystems/ezplatform-user": ">=1,<1.0.1", - "ezsystems/ezpublish-kernel": ">=5.3,<5.3.12.1|>=5.4,<5.4.14.1|>=6,<6.7.9.1|>=6.8,<6.13.6.2|>=7,<7.2.4.1|>=7.3,<7.3.2.1|>=7.5,<7.5.6.2", - "ezsystems/ezpublish-legacy": ">=5.3,<5.3.12.6|>=5.4,<5.4.14.1|>=2011,<2017.12.7.2|>=2018.6,<2018.6.1.4|>=2018.9,<2018.9.1.3|>=2019.3,<2019.3.4.2", + "ezsystems/ezpublish-kernel": ">=5.3,<5.3.12.1|>=5.4,<5.4.14.2|>=6,<6.7.9.1|>=6.8,<6.13.6.3|>=7,<7.2.4.1|>=7.3,<7.3.2.1|>=7.5,<7.5.7.1", + "ezsystems/ezpublish-legacy": ">=5.3,<5.3.12.6|>=5.4,<5.4.14.2|>=2011,<2017.12.7.3|>=2018.6,<2018.6.1.4|>=2018.9,<2018.9.1.3|>=2019.3,<2019.3.5.1", + "ezsystems/platform-ui-assets-bundle": ">=4.2,<4.2.3", "ezsystems/repository-forms": ">=2.3,<2.3.2.1", "ezyang/htmlpurifier": "<4.1.1", "firebase/php-jwt": "<2", @@ -511,14 +571,16 @@ "friendsofsymfony/oauth2-php": "<1.3", "friendsofsymfony/rest-bundle": ">=1.2,<1.2.2", "friendsofsymfony/user-bundle": ">=1.2,<1.3.5", + "friendsoftypo3/mediace": ">=7.6.2,<7.6.5", "fuel/core": "<1.8.1", "getgrav/grav": "<1.7-beta.8", + "gos/web-socket-bundle": "<1.10.4|>=2,<2.6.1|>=3,<3.3", "gree/jose": "<=2.2", "gregwar/rst": "<1.0.3", "guzzlehttp/guzzle": ">=4-rc.2,<4.2.4|>=5,<5.3.1|>=6,<6.2.1", "illuminate/auth": ">=4,<4.0.99|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.10", - "illuminate/cookie": ">=4,<=4.0.11|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.42|>=5.6,<5.6.30", - "illuminate/database": ">=4,<4.0.99|>=4.1,<4.1.29", + "illuminate/cookie": ">=4,<=4.0.11|>=4.1,<=4.1.99999|>=4.2,<=4.2.99999|>=5,<=5.0.99999|>=5.1,<=5.1.99999|>=5.2,<=5.2.99999|>=5.3,<=5.3.99999|>=5.4,<=5.4.99999|>=5.5,<=5.5.49|>=5.6,<=5.6.99999|>=5.7,<=5.7.99999|>=5.8,<=5.8.99999|>=6,<6.18.31|>=7,<7.22.4", + "illuminate/database": ">=4,<4.0.99|>=4.1,<4.1.29|>=5.5,<=5.5.44|>=6,<6.18.34|>=7,<7.23.2", "illuminate/encryption": ">=4,<=4.0.11|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.40|>=5.6,<5.6.15", "illuminate/view": ">=7,<7.1.2", "ivankristianto/phpwhois": "<=4.3", @@ -526,21 +588,36 @@ "joomla/session": "<1.3.1", "jsmitty12/phpwhois": "<5.1", "kazist/phpwhois": "<=4.2.6", + "kitodo/presentation": "<3.1.2", "kreait/firebase-php": ">=3.2,<3.8.1", "la-haute-societe/tcpdf": "<6.2.22", - "laravel/framework": ">=4,<4.0.99|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.42|>=5.6,<5.6.30|>=7,<7.1.2", + "laravel/framework": ">=4,<4.0.99|>=4.1,<=4.1.99999|>=4.2,<=4.2.99999|>=5,<=5.0.99999|>=5.1,<=5.1.99999|>=5.2,<=5.2.99999|>=5.3,<=5.3.99999|>=5.4,<=5.4.99999|>=5.5,<=5.5.49|>=5.6,<=5.6.99999|>=5.7,<=5.7.99999|>=5.8,<=5.8.99999|>=6,<6.18.34|>=7,<7.23.2", "laravel/socialite": ">=1,<1.0.99|>=2,<2.0.10", "league/commonmark": "<0.18.3", "librenms/librenms": "<1.53", + "livewire/livewire": ">2.2.4,<2.2.6", "magento/community-edition": ">=2,<2.2.10|>=2.3,<2.3.3", "magento/magento1ce": "<1.9.4.3", "magento/magento1ee": ">=1,<1.14.4.3", "magento/product-community-edition": ">=2,<2.2.10|>=2.3,<2.3.2-p.2", + "marcwillmann/turn": "<0.3.3", + "mediawiki/core": ">=1.27,<1.27.6|>=1.29,<1.29.3|>=1.30,<1.30.2|>=1.31,<1.31.9|>=1.32,<1.32.6|>=1.32.99,<1.33.3|>=1.33.99,<1.34.3|>=1.34.99,<1.35", + "mittwald/typo3_forum": "<1.2.1", "monolog/monolog": ">=1.8,<1.12", "namshi/jose": "<2.2", + "nette/application": ">=2,<2.0.19|>=2.1,<2.1.13|>=2.2,<2.2.10|>=2.3,<2.3.14|>=2.4,<2.4.16|>=3,<3.0.6", + "nette/nette": ">=2,<2.0.19|>=2.1,<2.1.13", + "nystudio107/craft-seomatic": "<3.3", + "nzo/url-encryptor-bundle": ">=4,<4.3.2|>=5,<5.0.1", + "october/backend": ">=1.0.319,<1.0.467", + "october/cms": ">=1.0.319,<1.0.466", + "october/october": ">=1.0.319,<1.0.466", + "october/rain": ">=1.0.319,<1.0.468", "onelogin/php-saml": "<2.10.4", "oneup/uploader-bundle": "<1.9.3|>=2,<2.1.5", "openid/php-openid": "<2.3", + "openmage/magento-lts": "<19.4.8|>=20,<20.0.4", + "orchid/platform": ">=9,<9.4.4", "oro/crm": ">=1.7,<1.7.4", "oro/platform": ">=1.7,<1.7.4", "padraic/humbug_get_contents": "<1.1.2", @@ -548,8 +625,10 @@ "paragonie/random_compat": "<2", "paypal/merchant-sdk-php": "<3.12", "pear/archive_tar": "<1.4.4", + "personnummer/personnummer": "<3.0.2", "phpfastcache/phpfastcache": ">=5,<5.0.13", - "phpmailer/phpmailer": ">=5,<5.2.27|>=6,<6.0.6", + "phpmailer/phpmailer": "<6.1.6", + "phpmussel/phpmussel": ">=1,<1.6", "phpmyadmin/phpmyadmin": "<4.9.2", "phpoffice/phpexcel": "<1.8.2", "phpoffice/phpspreadsheet": "<1.8", @@ -557,26 +636,34 @@ "phpwhois/phpwhois": "<=4.2.5", "phpxmlrpc/extras": "<0.6.1", "pimcore/pimcore": "<6.3", + "pocketmine/pocketmine-mp": "<3.15.4", "prestashop/autoupgrade": ">=4,<4.10.1", + "prestashop/contactform": ">1.0.1,<4.3", "prestashop/gamification": "<2.3.2", + "prestashop/productcomments": ">=4,<4.2", "prestashop/ps_facetedsearch": "<3.4.1", "privatebin/privatebin": "<1.2.2|>=1.3,<1.3.2", "propel/propel": ">=2-alpha.1,<=2-alpha.7", "propel/propel1": ">=1,<=1.7.1", + "pterodactyl/panel": "<0.7.19|>=1-rc.0,<=1-rc.6", "pusher/pusher-php-server": "<2.2.1", + "rainlab/debugbar-plugin": "<3.1", "robrichards/xmlseclibs": "<3.0.4", + "sabberworm/php-css-parser": ">=1,<1.0.1|>=2,<2.0.1|>=3,<3.0.1|>=4,<4.0.1|>=5,<5.0.9|>=5.1,<5.1.3|>=5.2,<5.2.1|>=6,<6.0.2|>=7,<7.0.4|>=8,<8.0.1|>=8.1,<8.1.1|>=8.2,<8.2.1|>=8.3,<8.3.1", "sabre/dav": ">=1.6,<1.6.99|>=1.7,<1.7.11|>=1.8,<1.8.9", "scheb/two-factor-bundle": ">=0,<3.26|>=4,<4.11", "sensiolabs/connect": "<4.2.3", "serluck/phpwhois": "<=4.2.6", - "shopware/shopware": "<5.3.7", + "shopware/core": "<=6.3.2", + "shopware/platform": "<=6.3.2", + "shopware/shopware": "<5.6.9", "silverstripe/admin": ">=1.0.3,<1.0.4|>=1.1,<1.1.1", "silverstripe/assets": ">=1,<1.4.7|>=1.5,<1.5.2", "silverstripe/cms": "<4.3.6|>=4.4,<4.4.4", "silverstripe/comments": ">=1.3,<1.9.99|>=2,<2.9.99|>=3,<3.1.1", "silverstripe/forum": "<=0.6.1|>=0.7,<=0.7.3", - "silverstripe/framework": "<4.4.5|>=4.5,<4.5.2", - "silverstripe/graphql": ">=2,<2.0.5|>=3,<3.1.2", + "silverstripe/framework": "<4.4.7|>=4.5,<4.5.4", + "silverstripe/graphql": ">=2,<2.0.5|>=3,<3.1.2|>=3.2,<3.2.4", "silverstripe/registry": ">=2.1,<2.1.2|>=2.2,<2.2.1", "silverstripe/restfulserver": ">=1,<1.0.9|>=2,<2.0.4", "silverstripe/subsites": ">=2,<2.1.1", @@ -584,7 +671,7 @@ "silverstripe/userforms": "<3", "simple-updates/phpwhois": "<=1", "simplesamlphp/saml2": "<1.10.6|>=2,<2.3.8|>=3,<3.1.4", - "simplesamlphp/simplesamlphp": "<1.18.4", + "simplesamlphp/simplesamlphp": "<1.18.6", "simplesamlphp/simplesamlphp-module-infocard": "<1.0.1", "simplito/elliptic-php": "<1.0.6", "slim/slim": "<2.6", @@ -592,15 +679,16 @@ "socalnick/scn-social-auth": "<1.15.2", "spoonity/tcpdf": "<6.2.22", "squizlabs/php_codesniffer": ">=1,<2.8.1|>=3,<3.0.1", - "ssddanbrown/bookstack": "<0.25.3", + "ssddanbrown/bookstack": "<0.29.2", "stormpath/sdk": ">=0,<9.9.99", "studio-42/elfinder": "<2.1.49", + "sulu/sulu": "<1.6.34|>=2,<2.0.10|>=2.1,<2.1.1", "swiftmailer/swiftmailer": ">=4,<5.4.5", "sylius/admin-bundle": ">=1,<1.0.17|>=1.1,<1.1.9|>=1.2,<1.2.2", "sylius/grid": ">=1,<1.1.19|>=1.2,<1.2.18|>=1.3,<1.3.13|>=1.4,<1.4.5|>=1.5,<1.5.1", "sylius/grid-bundle": ">=1,<1.1.19|>=1.2,<1.2.18|>=1.3,<1.3.13|>=1.4,<1.4.5|>=1.5,<1.5.1", - "sylius/resource-bundle": "<1.3.13|>=1.4,<1.4.6|>=1.5,<1.5.1|>=1.6,<1.6.3", - "sylius/sylius": "<1.3.16|>=1.4,<1.4.12|>=1.5,<1.5.9|>=1.6,<1.6.5", + "sylius/resource-bundle": "<1.3.14|>=1.4,<1.4.7|>=1.5,<1.5.2|>=1.6,<1.6.4", + "sylius/sylius": "<1.6.9|>=1.7,<1.7.9|>=1.8,<1.8.3", "symbiote/silverstripe-multivaluefield": ">=3,<3.0.99", "symbiote/silverstripe-versionedfiles": "<=2.0.3", "symfony/cache": ">=3.1,<3.4.35|>=4,<4.2.12|>=4.3,<4.3.8", @@ -609,7 +697,7 @@ "symfony/form": ">=2.3,<2.3.35|>=2.4,<2.6.12|>=2.7,<2.7.50|>=2.8,<2.8.49|>=3,<3.4.20|>=4,<4.0.15|>=4.1,<4.1.9|>=4.2,<4.2.1", "symfony/framework-bundle": ">=2,<2.3.18|>=2.4,<2.4.8|>=2.5,<2.5.2|>=2.7,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", "symfony/http-foundation": ">=2,<2.8.52|>=3,<3.4.35|>=4,<4.2.12|>=4.3,<4.3.8|>=4.4,<4.4.7|>=5,<5.0.7", - "symfony/http-kernel": ">=2,<2.8.52|>=3,<3.4.35|>=4,<4.2.12|>=4.3,<4.3.8", + "symfony/http-kernel": ">=2,<2.8.52|>=3,<3.4.35|>=4,<4.2.12|>=4.3,<4.4.13|>=5,<5.1.5", "symfony/intl": ">=2.7,<2.7.38|>=2.8,<2.8.31|>=3,<3.2.14|>=3.3,<3.3.13", "symfony/mime": ">=4.3,<4.3.8", "symfony/phpunit-bridge": ">=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", @@ -624,12 +712,13 @@ "symfony/security-guard": ">=2.8,<2.8.41|>=3,<3.3.17|>=3.4,<3.4.11|>=4,<4.0.11", "symfony/security-http": ">=2.3,<2.3.41|>=2.4,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.2.12|>=4.3,<4.3.8|>=4.4,<4.4.7|>=5,<5.0.7", "symfony/serializer": ">=2,<2.0.11", - "symfony/symfony": ">=2,<2.8.52|>=3,<3.4.35|>=4,<4.2.12|>=4.3,<4.3.8|>=4.4,<4.4.7|>=5,<5.0.7", + "symfony/symfony": ">=2,<2.8.52|>=3,<3.4.35|>=4,<4.2.12|>=4.3,<4.4.13|>=5,<5.1.5", "symfony/translation": ">=2,<2.0.17", "symfony/validator": ">=2,<2.0.24|>=2.1,<2.1.12|>=2.2,<2.2.5|>=2.3,<2.3.3", "symfony/var-exporter": ">=4.2,<4.2.12|>=4.3,<4.3.8", "symfony/web-profiler-bundle": ">=2,<2.3.19|>=2.4,<2.4.9|>=2.5,<2.5.4", "symfony/yaml": ">=2,<2.0.22|>=2.1,<2.1.7", + "t3g/svg-sanitizer": "<1.0.3", "tecnickcom/tcpdf": "<6.2.22", "thelia/backoffice-default-template": ">=2.1,<2.1.2", "thelia/thelia": ">=2.1-beta.1,<2.1.3", @@ -637,11 +726,12 @@ "titon/framework": ">=0,<9.9.99", "truckersmp/phpwhois": "<=4.3.1", "twig/twig": "<1.38|>=2,<2.7", - "typo3/cms": ">=6.2,<6.2.30|>=7,<7.6.32|>=8,<8.7.30|>=9,<9.5.12|>=10,<10.2.1", - "typo3/cms-core": ">=8,<8.7.30|>=9,<9.5.12|>=10,<10.2.1", + "typo3/cms": ">=6.2,<6.2.30|>=7,<7.6.32|>=8,<8.7.30|>=9,<9.5.20|>=10,<10.4.6", + "typo3/cms-core": ">=8,<8.7.30|>=9,<9.5.20|>=10,<10.4.6", "typo3/flow": ">=1,<1.0.4|>=1.1,<1.1.1|>=2,<2.0.1|>=2.3,<2.3.16|>=3,<3.0.10|>=3.1,<3.1.7|>=3.2,<3.2.7|>=3.3,<3.3.5", "typo3/neos": ">=1.1,<1.1.3|>=1.2,<1.2.13|>=2,<2.0.4", "typo3/phar-stream-wrapper": ">=1,<2.1.1|>=3,<3.1.1", + "typo3fluid/fluid": ">=2,<2.0.8|>=2.1,<2.1.7|>=2.2,<2.2.4|>=2.3,<2.3.7|>=2.4,<2.4.4|>=2.5,<2.5.11|>=2.6,<2.6.10", "ua-parser/uap-php": "<3.8", "usmanhalalit/pixie": "<1.0.3|>=2,<2.0.2", "verot/class.upload.php": "<=1.0.3|>=2,<=2.0.4", @@ -649,7 +739,7 @@ "willdurand/js-translation-bundle": "<2.1.1", "yii2mod/yii2-cms": "<1.9.2", "yiisoft/yii": ">=1.1.14,<1.1.15", - "yiisoft/yii2": "<2.0.15", + "yiisoft/yii2": "<2.0.38", "yiisoft/yii2-bootstrap": "<2.0.4", "yiisoft/yii2-dev": "<2.0.15", "yiisoft/yii2-elasticsearch": "<2.0.5", @@ -701,25 +791,36 @@ } ], "description": "Prevents installation of composer packages with known security vulnerabilities: no API, simply require it", - "time": "2020-04-21T14:24:08+00:00" + "funding": [ + { + "url": "https://github.com/Ocramius", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/roave/security-advisories", + "type": "tidelift" + } + ], + "time": "2020-11-19T14:02:08+00:00" }, { "name": "symfony/polyfill-intl-idn", - "version": "v1.15.0", + "version": "v1.19.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-idn.git", - "reference": "47bd6aa45beb1cd7c6a16b7d1810133b728bdfcf" + "reference": "4ad5115c0f5d5172a9fe8147675ec6de266d8826" }, "dist": { "type": "zip", - "url": "https://github.com/gitapi/repos/symfony/polyfill-intl-idn/zipball/47bd6aa45beb1cd7c6a16b7d1810133b728bdfcf", - "reference": "47bd6aa45beb1cd7c6a16b7d1810133b728bdfcf", + "url": "https://github.com/gitapi/repos/symfony/polyfill-intl-idn/zipball/4ad5115c0f5d5172a9fe8147675ec6de266d8826", + "reference": "4ad5115c0f5d5172a9fe8147675ec6de266d8826", "shasum": "" }, "require": { "php": ">=5.3.3", - "symfony/polyfill-mbstring": "^1.3", + "symfony/polyfill-intl-normalizer": "^1.10", + "symfony/polyfill-php70": "^1.10", "symfony/polyfill-php72": "^1.10" }, "suggest": { @@ -728,7 +829,11 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.15-dev" + "dev-main": "1.19-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" } }, "autoload": { @@ -748,6 +853,10 @@ "name": "Laurent Bassin", "email": "laurent@bassin.info" }, + { + "name": "Trevor Rowbotham", + "email": "trevor.rowbotham@pm.me" + }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" @@ -777,40 +886,47 @@ "type": "tidelift" } ], - "time": "2020-03-09T19:04:49+00:00" + "time": "2020-10-21T09:57:48+00:00" }, { - "name": "symfony/polyfill-mbstring", - "version": "v1.15.0", + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.19.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "81ffd3a9c6d707be22e3012b827de1c9775fc5ac" + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "8db0ae7936b42feb370840cf24de1a144fb0ef27" }, "dist": { "type": "zip", - "url": "https://github.com/gitapi/repos/symfony/polyfill-mbstring/zipball/81ffd3a9c6d707be22e3012b827de1c9775fc5ac", - "reference": "81ffd3a9c6d707be22e3012b827de1c9775fc5ac", + "url": "https://github.com/gitapi/repos/symfony/polyfill-intl-normalizer/zipball/8db0ae7936b42feb370840cf24de1a144fb0ef27", + "reference": "8db0ae7936b42feb370840cf24de1a144fb0ef27", "shasum": "" }, "require": { "php": ">=5.3.3" }, "suggest": { - "ext-mbstring": "For best performance" + "ext-intl": "For best performance" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.15-dev" + "dev-main": "1.19-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" } }, "autoload": { "psr-4": { - "Symfony\\Polyfill\\Mbstring\\": "" + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" }, "files": [ "bootstrap.php" + ], + "classmap": [ + "Resources/stubs" ] }, "notification-url": "https://packagist.org/downloads/", @@ -827,11 +943,12 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill for the Mbstring extension", + "description": "Symfony polyfill for intl's Normalizer class and related functions", "homepage": "https://symfony.com", "keywords": [ "compatibility", - "mbstring", + "intl", + "normalizer", "polyfill", "portable", "shim" @@ -850,20 +967,97 @@ "type": "tidelift" } ], - "time": "2020-03-09T19:04:49+00:00" + "time": "2020-10-23T09:01:57+00:00" + }, + { + "name": "symfony/polyfill-php70", + "version": "v1.19.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php70.git", + "reference": "3fe414077251a81a1b15b1c709faf5c2fbae3d4e" + }, + "dist": { + "type": "zip", + "url": "https://github.com/gitapi/repos/symfony/polyfill-php70/zipball/3fe414077251a81a1b15b1c709faf5c2fbae3d4e", + "reference": "3fe414077251a81a1b15b1c709faf5c2fbae3d4e", + "shasum": "" + }, + "require": { + "paragonie/random_compat": "~1.0|~2.0|~9.99", + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.19-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php70\\": "" + }, + "files": [ + "bootstrap.php" + ], + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-10-23T09:01:57+00:00" }, { "name": "symfony/polyfill-php72", - "version": "v1.15.0", + "version": "v1.19.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php72.git", - "reference": "37b0976c78b94856543260ce09b460a7bc852747" + "reference": "beecef6b463b06954638f02378f52496cb84bacc" }, "dist": { "type": "zip", - "url": "https://github.com/gitapi/repos/symfony/polyfill-php72/zipball/37b0976c78b94856543260ce09b460a7bc852747", - "reference": "37b0976c78b94856543260ce09b460a7bc852747", + "url": "https://github.com/gitapi/repos/symfony/polyfill-php72/zipball/beecef6b463b06954638f02378f52496cb84bacc", + "reference": "beecef6b463b06954638f02378f52496cb84bacc", "shasum": "" }, "require": { @@ -872,7 +1066,11 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.15-dev" + "dev-main": "1.19-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" } }, "autoload": { @@ -919,7 +1117,7 @@ "type": "tidelift" } ], - "time": "2020-02-27T09:26:54+00:00" + "time": "2020-10-23T09:01:57+00:00" } ], "packages-dev": [], From 11099f6e653ca37e9ab4c2e9eae2d1e0f12866cf Mon Sep 17 00:00:00 2001 From: "dash.bar" Date: Thu, 19 Nov 2020 16:47:19 +0100 Subject: [PATCH 160/280] prepare finalize --- info.xml | 1564 ++++++++++++++++++++++++++---------------------------- 1 file changed, 755 insertions(+), 809 deletions(-) diff --git a/info.xml b/info.xml index 529b9da..e4acb00 100644 --- a/info.xml +++ b/info.xml @@ -1,819 +1,765 @@ - - - mollie - Zahlungsartplugin für mollie.com - WebStollen - https://www.webstollen.de/ - 102 - ws_mollie - 405 - - - 100.sql - 2019-02-11 - - - 2019-02-26 - - - 2019-04-23 - - - 2019-05-22 - - - 2019-07-12 - - - 2019-11-26 - - - 2019-12-18 - - - 107.sql - 2020-03-02 - - - 2020-04-24 - - - 109.sql - 2020-08-17 - - - 2020-08-17 - - - 131_globalinclude.php - 144_notify.php - 181_sync.php - 140_smarty.php - - - - Bestellungen - orders.php - - - Zahlungsarten - paymentmethods.php - - - Info - info.php - - - Einstellungen - - API Key: - Füge hier deinen mollie API Key ein - api_key - - - Profile ID: - Füge hier deinen mollie Profil ID (pfl_) ein. Wird benötigt um mollie Components zu - aktivieren - - profileId - - - Trust-Grafik bei mollie Components anzeigen: - Bindet eine Trust-Grafik unterhalb des Kreditkartenformulars ein. - loadTrust - - - - - - - Zahlungsart Daten syncronisiernen - Lädt Name / Bild für die jeweilige Sprache automatisch von mollie, und speichert diese - in der Datenbank - - paymentmethod_sync - - - - - - - - - Checkout Styles laden - Lädt Stylesheets für das Evo Template, um den Checkout zu verschönern. - load_styles - - - - - - - - Artikel mit rationalen Stückzahlen - Artikel mit rationalen Stückzahlen werden dann unterstützt, jedoch als ein Artikel - behandelt. KEIN Teilversand hierfür möglich! - - supportQ - - - - - - - TransaktionsID des Zahlungseingangs: - Welche ID soll an die WAWI übetragen werden? Bei PayPal wird immer die PayPal Referenz - angegeben. - - wawiPaymentID - - - - - - - - Workflow-Secret: - Schlüssel, um die WAWI Workflow-Requests zu authentifizieren. - workflowSecret - - - Max. Gültigenkeit in Tagen: - Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status - führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. - - expiryDays - - - - mollie Components überspringbar: - Wenn diese Einstellung aktiv ist, erscheint beim Zahlungszusatzschritt (Kreditkarte) - ein Link, um diesen Schritt zu überspringen. - - skipComponents - - - - - - - - - - skipComponentsLink - - - - - - - - - cctitle - - - - - - - error_canceled - - + mollie + Zahlungsartplugin für mollie.com + WebStollen + https://www.webstollen.de/ + 102 + ws_mollie + 405 + + + 100.sql + 2019-02-11 + + + 2019-02-26 + + + 2019-04-23 + + + 2019-05-22 + + + 2019-07-12 + + + 2019-11-26 + + + 2019-12-18 + + + 107.sql + 2020-03-02 + + + 2020-04-24 + + + 109.sql + 2020-08-17 + + + 2020-11-19 + + + 131_globalinclude.php + 144_notify.php + 181_sync.php + 140_smarty.php + + + + Bestellungen + orders.php + + + Zahlungsarten + paymentmethods.php + + + Info + info.php + + + Einstellungen + + API Key: + Füge hier deinen mollie API Key ein + api_key + + + Profile ID: + Füge hier deinen mollie Profil ID (pfl_) ein. Wird benötigt um mollie Components zu aktivieren + profileId + + + Trust-Grafik bei mollie Components anzeigen: + Bindet eine Trust-Grafik unterhalb des Kreditkartenformulars ein. + loadTrust + + + + + + + Zahlungsart Daten syncronisiernen + Lädt Name / Bild für die jeweilige Sprache automatisch von mollie, und speichert diese in der Datenbank + paymentmethod_sync + + + + + + + + + Checkout Styles laden + Lädt Stylesheets für das Evo Template, um den Checkout zu verschönern. + load_styles + + + + + + + + Artikel mit rationalen Stückzahlen + Artikel mit rationalen Stückzahlen werden dann unterstützt, jedoch als ein Artikel behandelt. KEIN Teilversand hierfür möglich! + supportQ + + + + + + + TransaktionsID des Zahlungseingangs: + Welche ID soll an die WAWI übetragen werden? Bei PayPal wird immer die PayPal Referenz angegeben. + wawiPaymentID + + + + + + + + Workflow-Secret: + Schlüssel, um die WAWI Workflow-Requests zu authentifizieren. + workflowSecret + + + Max. Gültigenkeit in Tagen: + Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. + expiryDays + + + mollie Components überspringbar: + Wenn diese Einstellung aktiv ist, erscheint beim Zahlungszusatzschritt (Kreditkarte) ein Link, um diesen Schritt zu überspringen. + skipComponents + + + + + + + + + + skipComponentsLink + + + + + + + cctitle + + + + + + + error_canceled + + - - - - - - - error_expired - - + + + + error_expired + + - - - - - - - error_open - - + + + + error_open + + - - - - - - - error_failed - - + + + + error_failed + + - - - - - - - lbl_cardHolder - - - - - - - lbl_cardNumber - - - - - - - lbl_expiryDate - - - - - - - lbl_varificationCode - - - - - - - cvchint_1 - - - - - - - cvchint_2 - - + + + + lbl_cardHolder + + + + + + + lbl_cardNumber + + + + + + + lbl_expiryDate + + + + + + + lbl_varificationCode + + + + + + + cvchint_1 + + + + + + + cvchint_2 + + - - - - - - - mcErrorMessage - Ein oder mehrere Felder sind ungültig. - - - - - - - - mollie - img/method/mollie@2x.png - 1 - 0 - mollie.com - OTHER - 0 - 0 - 1 - 0 - JTLMollie.php - JTLMollie - tpl/bestellabschluss.tpl - - mollie - mollie - Bezahlen Sie bequem mit verschiedenen Zahlungsmethoden. - - - Max. Gültigenkeit in Tagen: - Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status - führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. - - expiryDays - - - - mollie Kreditkarte - img/method/creditcard@2x.png - 3 - 0 - mollie.com - CREDIT_CARD - 1 - 0 - 1 - 0 - JTLMollieCreditCard.php - JTLMollieCreditCard - tpl/bestellabschluss.tpl - tpl/mollieComponents.tpl - - Kreditkarte - mollie - Bezahlen Sie bequem mit Kreditkarte. - - - Max. Gültigenkeit in Tagen: - Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status - führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. - - expiryDays - - - - mollie Apple Pay - img/method/applepay@2x.png - 3 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMollieApplePay.php - JTLMollieApplePay - tpl/bestellabschluss.tpl - - Apple Pay - mollie - Bezahlen Sie bequem mit Apple Pay. - - - Max. Gültigenkeit in Tagen: - Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status - führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. - - expiryDays - - - - mollie Bancontact - img/method/bancontact@2x.png - 4 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMollieBancontact.php - JTLMollieBancontact - tpl/bestellabschluss.tpl - - Bancontact - mollie - Bezahlen Sie bequem mit Bancontact. - - - Max. Gültigenkeit in Tagen: - Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status - führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. - - expiryDays - - - - mollie Banktransfer - img/method/banktransfer@2x.png - 5 - 0 - mollie.com - OTHER - 0 - 0 - 1 - 0 - JTLMollieBanktransfer.php - JTLMollieBanktransfer - tpl/bestellabschluss.tpl - - SEPA Überweisung - mollie - Bezahlen Sie bequem mit SEPA Überweisung. - - - Max. Gültigenkeit in Tagen: - Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status - führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. - - expiryDays - - - - mollie Belfius - img/method/belfius@2x.png - 6 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMollieBelfius.php - JTLMollieBelfius - tpl/bestellabschluss.tpl - - Belfius - mollie - Bezahlen Sie bequem mit Belfius. - - - Max. Gültigenkeit in Tagen: - Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status - führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. - - expiryDays - - - - mollie DirectDebit - img/method/directdebit@2x.png - 7 - 0 - mollie.com - DIRECT_DEBIT - 1 - 0 - 1 - 0 - JTLMollieDirectDebit.php - JTLMollieDirectDebit - tpl/bestellabschluss.tpl - - SEPA Lastschrift - mollie - Bezahlen Sie bequem mit SEPA Lastschrift. - - - Max. Gültigenkeit in Tagen: - Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status - führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. - - expiryDays - - - - mollie EPS - img/method/eps@2x.png - 2 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMollieEPS.php - JTLMollieEPS - tpl/bestellabschluss.tpl - - EPS - mollie - Bezahlen Sie bequem mit EPS. - - - Max. Gültigenkeit in Tagen: - Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status - führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. - - expiryDays - - - - mollie Giftcard - img/method/giftcard@2x.png - 8 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMollieGiftcard.php - JTLMollieGiftcard - tpl/bestellabschluss.tpl - - Gift cards - mollie - Bezahlen Sie bequem mit Gift cards. - - - Max. Gültigenkeit in Tagen: - Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status - führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. - - expiryDays - - - - mollie Giropay - img/method/giropay@2x.png - 9 - 0 - mollie.com - GIROPAY - 1 - 0 - 1 - 0 - JTLMollieGiropay.php - JTLMollieGiropay - tpl/bestellabschluss.tpl - - Giropay - mollie - Bezahlen Sie bequem mit Giropay. - - - Max. Gültigenkeit in Tagen: - Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status - führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. - - expiryDays - - - - mollie iDEAL - img/method/ideal@2x.png - 10 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMollieIDEAL.php - JTLMollieIDEAL - tpl/bestellabschluss.tpl - - iDEAL - mollie - Bezahlen Sie bequem mit iDEAL. - - - Max. Gültigenkeit in Tagen: - Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status - führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. - - expiryDays - - - - mollie ING HomePay - img/method/inghomepay@2x.png - 11 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMollieINGHomePay.php - JTLMollieINGHomePay - tpl/bestellabschluss.tpl - - ING HomePay - mollie - Bezahlen Sie bequem mit ING HomePay. - - - Max. Gültigenkeit in Tagen: - Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status - führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. - - expiryDays - - - - mollie KBC - img/method/kbc@2x.png - 12 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMollieKBC.php - JTLMollieKBC - tpl/bestellabschluss.tpl - - KBC - mollie - Bezahlen Sie bequem mit KBC. - - - Max. Gültigenkeit in Tagen: - Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status - führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. - - expiryDays - - - - mollie PayPal - img/method/paypal@2x.png - 13 - 0 - mollie.com - PAYPAL - 1 - 0 - 1 - 0 - JTLMolliePayPal.php - JTLMolliePayPal - tpl/bestellabschluss.tpl - - PayPal - mollie - Bezahlen Sie bequem mit PayPal. - - - Max. Gültigenkeit in Tagen: - Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status - führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. - - expiryDays - - - - mollie paysafecard - img/method/paysafecard@2x.png - 14 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMolliePaysafecard.php - JTLMolliePaysafecard - tpl/bestellabschluss.tpl - - paysafecard - mollie - Bezahlen Sie bequem mit paysafecard. - - - Max. Gültigenkeit in Tagen: - Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status - führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. - - expiryDays - - - - mollie SOFORT - img/method/sofort@2x.png - 15 - 0 - mollie.com - DIRECT_E_BANKING - 1 - 0 - 1 - 0 - JTLMollieSofort.php - JTLMollieSofort - tpl/bestellabschluss.tpl - - SOFORT - mollie - Bezahlen Sie bequem mit SOFORT. - - - Max. Gültigenkeit in Tagen: - Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status - führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. - - expiryDays - - - - mollie Klarna Pay Later - img/method/klarna@2x.png - 16 - 0 - mollie.com - INVOICE - 1 - 0 - 1 - 0 - JTLMollieKlarnaPayLater.php - JTLMollieKlarnaPayLater - tpl/bestellabschluss.tpl - - Klarna Pay Later - mollie - Bezahlen Sie bequem mit Klarna Pay Later. - - - Max. Gültigenkeit in Tagen: - Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status - führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. - - expiryDays - - - - mollie Klarna Slice It - img/method/klarna@2x.png - 17 - 0 - mollie.com - FINANCING - 1 - 0 - 1 - 0 - JTLMollieKlarnaSliceIt.php - JTLMollieKlarnaSliceIt - tpl/bestellabschluss.tpl - - Klarna Slice It - mollie - Bezahlen Sie bequem mit Klarna Slice It. - - - Max. Gültigenkeit in Tagen: - Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status - führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. - - expiryDays - - - - mollie Przelewy24 - img/method/Przelewy24@2x.png - 17 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMolliePrzelewy24.php - JTLMolliePrzelewy24 - tpl/bestellabschluss.tpl - - Przelewy24 - mollie - Bezahlen Sie bequem mit Przelewy24. - - - Max. Gültigenkeit in Tagen: - Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status - führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. - - expiryDays - - - - mollie MyBank - img/method/mybank@2x.png - 17 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMollieMyBank.php - JTLMollieMyBank - tpl/bestellabschluss.tpl - - MyBank - mollie - Bezahlen Sie bequem mit MyBank. - - - Max. Gültigenkeit in Tagen: - Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status - führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. - - expiryDays - - - - + + + + + mcErrorMessage + Ein oder mehrere Felder sind ungültig. + + + + + + + + mollie + img/method/mollie@2x.png + 1 + 0 + mollie.com + OTHER + 0 + 0 + 1 + 0 + JTLMollie.php + JTLMollie + tpl/bestellabschluss.tpl + + mollie + mollie + Bezahlen Sie bequem mit verschiedenen Zahlungsmethoden. + + + Max. Gültigenkeit in Tagen: + Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. + expiryDays + + + + mollie Kreditkarte + img/method/creditcard@2x.png + 3 + 0 + mollie.com + CREDIT_CARD + 1 + 0 + 1 + 0 + JTLMollieCreditCard.php + JTLMollieCreditCard + tpl/bestellabschluss.tpl + tpl/mollieComponents.tpl + + Kreditkarte + mollie + Bezahlen Sie bequem mit Kreditkarte. + + + Max. Gültigenkeit in Tagen: + Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. + expiryDays + + + + mollie Apple Pay + img/method/applepay@2x.png + 3 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMollieApplePay.php + JTLMollieApplePay + tpl/bestellabschluss.tpl + + Apple Pay + mollie + Bezahlen Sie bequem mit Apple Pay. + + + Max. Gültigenkeit in Tagen: + Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. + expiryDays + + + + mollie Bancontact + img/method/bancontact@2x.png + 4 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMollieBancontact.php + JTLMollieBancontact + tpl/bestellabschluss.tpl + + Bancontact + mollie + Bezahlen Sie bequem mit Bancontact. + + + Max. Gültigenkeit in Tagen: + Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. + expiryDays + + + + mollie Banktransfer + img/method/banktransfer@2x.png + 5 + 0 + mollie.com + OTHER + 0 + 0 + 1 + 0 + JTLMollieBanktransfer.php + JTLMollieBanktransfer + tpl/bestellabschluss.tpl + + SEPA Überweisung + mollie + Bezahlen Sie bequem mit SEPA Überweisung. + + + Max. Gültigenkeit in Tagen: + Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. + expiryDays + + + + mollie Belfius + img/method/belfius@2x.png + 6 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMollieBelfius.php + JTLMollieBelfius + tpl/bestellabschluss.tpl + + Belfius + mollie + Bezahlen Sie bequem mit Belfius. + + + Max. Gültigenkeit in Tagen: + Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. + expiryDays + + + + mollie DirectDebit + img/method/directdebit@2x.png + 7 + 0 + mollie.com + DIRECT_DEBIT + 1 + 0 + 1 + 0 + JTLMollieDirectDebit.php + JTLMollieDirectDebit + tpl/bestellabschluss.tpl + + SEPA Lastschrift + mollie + Bezahlen Sie bequem mit SEPA Lastschrift. + + + Max. Gültigenkeit in Tagen: + Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. + expiryDays + + + + mollie EPS + img/method/eps@2x.png + 2 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMollieEPS.php + JTLMollieEPS + tpl/bestellabschluss.tpl + + EPS + mollie + Bezahlen Sie bequem mit EPS. + + + Max. Gültigenkeit in Tagen: + Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. + expiryDays + + + + mollie Giftcard + img/method/giftcard@2x.png + 8 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMollieGiftcard.php + JTLMollieGiftcard + tpl/bestellabschluss.tpl + + Gift cards + mollie + Bezahlen Sie bequem mit Gift cards. + + + Max. Gültigenkeit in Tagen: + Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. + expiryDays + + + + mollie Giropay + img/method/giropay@2x.png + 9 + 0 + mollie.com + GIROPAY + 1 + 0 + 1 + 0 + JTLMollieGiropay.php + JTLMollieGiropay + tpl/bestellabschluss.tpl + + Giropay + mollie + Bezahlen Sie bequem mit Giropay. + + + Max. Gültigenkeit in Tagen: + Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. + expiryDays + + + + mollie iDEAL + img/method/ideal@2x.png + 10 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMollieIDEAL.php + JTLMollieIDEAL + tpl/bestellabschluss.tpl + + iDEAL + mollie + Bezahlen Sie bequem mit iDEAL. + + + Max. Gültigenkeit in Tagen: + Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. + expiryDays + + + + mollie ING HomePay + img/method/inghomepay@2x.png + 11 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMollieINGHomePay.php + JTLMollieINGHomePay + tpl/bestellabschluss.tpl + + ING HomePay + mollie + Bezahlen Sie bequem mit ING HomePay. + + + Max. Gültigenkeit in Tagen: + Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. + expiryDays + + + + mollie KBC + img/method/kbc@2x.png + 12 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMollieKBC.php + JTLMollieKBC + tpl/bestellabschluss.tpl + + KBC + mollie + Bezahlen Sie bequem mit KBC. + + + Max. Gültigenkeit in Tagen: + Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. + expiryDays + + + + mollie PayPal + img/method/paypal@2x.png + 13 + 0 + mollie.com + PAYPAL + 1 + 0 + 1 + 0 + JTLMolliePayPal.php + JTLMolliePayPal + tpl/bestellabschluss.tpl + + PayPal + mollie + Bezahlen Sie bequem mit PayPal. + + + Max. Gültigenkeit in Tagen: + Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. + expiryDays + + + + mollie paysafecard + img/method/paysafecard@2x.png + 14 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMolliePaysafecard.php + JTLMolliePaysafecard + tpl/bestellabschluss.tpl + + paysafecard + mollie + Bezahlen Sie bequem mit paysafecard. + + + Max. Gültigenkeit in Tagen: + Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. + expiryDays + + + + mollie SOFORT + img/method/sofort@2x.png + 15 + 0 + mollie.com + DIRECT_E_BANKING + 1 + 0 + 1 + 0 + JTLMollieSofort.php + JTLMollieSofort + tpl/bestellabschluss.tpl + + SOFORT + mollie + Bezahlen Sie bequem mit SOFORT. + + + Max. Gültigenkeit in Tagen: + Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. + expiryDays + + + + mollie Klarna Pay Later + img/method/klarna@2x.png + 16 + 0 + mollie.com + INVOICE + 1 + 0 + 1 + 0 + JTLMollieKlarnaPayLater.php + JTLMollieKlarnaPayLater + tpl/bestellabschluss.tpl + + Klarna Pay Later + mollie + Bezahlen Sie bequem mit Klarna Pay Later. + + + Max. Gültigenkeit in Tagen: + Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. + expiryDays + + + + mollie Klarna Slice It + img/method/klarna@2x.png + 17 + 0 + mollie.com + FINANCING + 1 + 0 + 1 + 0 + JTLMollieKlarnaSliceIt.php + JTLMollieKlarnaSliceIt + tpl/bestellabschluss.tpl + + Klarna Slice It + mollie + Bezahlen Sie bequem mit Klarna Slice It. + + + Max. Gültigenkeit in Tagen: + Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. + expiryDays + + + + mollie Przelewy24 + img/method/Przelewy24@2x.png + 17 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMolliePrzelewy24.php + JTLMolliePrzelewy24 + tpl/bestellabschluss.tpl + + Przelewy24 + mollie + Bezahlen Sie bequem mit Przelewy24. + + + Max. Gültigenkeit in Tagen: + Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. + expiryDays + + + + mollie MyBank + img/method/mybank@2x.png + 17 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMollieMyBank.php + JTLMollieMyBank + tpl/bestellabschluss.tpl + + MyBank + mollie + Bezahlen Sie bequem mit MyBank. + + + Max. Gültigenkeit in Tagen: + Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. + expiryDays + + + + \ No newline at end of file From 9a4700ec3cd3b29ca63c35c995cc48cc88d93bd9 Mon Sep 17 00:00:00 2001 From: "dash.bar" Date: Thu, 19 Nov 2020 16:47:20 +0100 Subject: [PATCH 161/280] init version 111 --- info.xml | 3 + version/111/adminmenu/info.php | 64 ++ version/111/adminmenu/orders.php | 236 +++++ version/111/adminmenu/paymentmethods.php | 97 +++ version/111/adminmenu/tpl/info.tpl | 114 +++ .../tpl/mollie-account-erstellen.png | Bin 0 -> 38998 bytes version/111/adminmenu/tpl/order.tpl | 281 ++++++ version/111/adminmenu/tpl/orders.tpl | 132 +++ version/111/adminmenu/tpl/paymentmethods.tpl | 127 +++ version/111/class/ExclusiveLock.php | 76 ++ version/111/class/Helper.php | 352 ++++++++ version/111/class/Model/AbstractModel.php | 7 + version/111/class/Model/Payment.php | 84 ++ version/111/class/Mollie.php | 564 ++++++++++++ version/111/frontend/131_globalinclude.php | 120 +++ version/111/frontend/140_smarty.php | 78 ++ version/111/frontend/144_notify.php | 63 ++ version/111/frontend/181_sync.php | 43 + version/111/frontend/img/trust_eng.png | Bin 0 -> 15299 bytes version/111/frontend/img/trust_fre.png | Bin 0 -> 17319 bytes version/111/frontend/img/trust_ger.png | Bin 0 -> 15352 bytes version/111/paymentmethod/JTLMollie.php | 806 ++++++++++++++++++ .../111/paymentmethod/JTLMollieApplePay.php | 8 + .../111/paymentmethod/JTLMollieBancontact.php | 8 + .../paymentmethod/JTLMollieBanktransfer.php | 10 + .../111/paymentmethod/JTLMollieBelfius.php | 8 + .../111/paymentmethod/JTLMollieCreditCard.php | 47 + .../paymentmethod/JTLMollieDirectDebit.php | 8 + version/111/paymentmethod/JTLMollieEPS.php | 8 + .../111/paymentmethod/JTLMollieGiftcard.php | 8 + .../111/paymentmethod/JTLMollieGiropay.php | 8 + version/111/paymentmethod/JTLMollieIDEAL.php | 8 + .../111/paymentmethod/JTLMollieINGHomePay.php | 8 + version/111/paymentmethod/JTLMollieKBC.php | 8 + .../paymentmethod/JTLMollieKlarnaPayLater.php | 10 + .../paymentmethod/JTLMollieKlarnaSliceIt.php | 10 + version/111/paymentmethod/JTLMollieMyBank.php | 8 + version/111/paymentmethod/JTLMolliePayPal.php | 8 + .../paymentmethod/JTLMolliePaysafecard.php | 8 + .../111/paymentmethod/JTLMolliePrzelewy24.php | 8 + version/111/paymentmethod/JTLMollieSofort.php | 8 + .../img/method/Przelewy24@2x.png | Bin 0 -> 859 bytes .../paymentmethod/img/method/applepay@2x.png | Bin 0 -> 656 bytes .../img/method/bancontact@2x.png | Bin 0 -> 582 bytes .../img/method/banktransfer@2x.png | Bin 0 -> 801 bytes .../paymentmethod/img/method/belfius@2x.png | Bin 0 -> 377 bytes .../img/method/creditcard@2x.png | Bin 0 -> 3125 bytes .../img/method/directdebit@2x.png | Bin 0 -> 801 bytes .../111/paymentmethod/img/method/eps@2x.png | Bin 0 -> 536 bytes .../paymentmethod/img/method/giftcard@2x.png | Bin 0 -> 2218 bytes .../paymentmethod/img/method/giropay@2x.png | Bin 0 -> 602 bytes .../111/paymentmethod/img/method/ideal@2x.png | Bin 0 -> 845 bytes .../img/method/inghomepay@2x.png | Bin 0 -> 1118 bytes .../111/paymentmethod/img/method/kbc@2x.png | Bin 0 -> 799 bytes .../paymentmethod/img/method/klarna@2x.png | Bin 0 -> 896 bytes .../paymentmethod/img/method/mollie@2x.png | Bin 0 -> 5366 bytes .../paymentmethod/img/method/mybank@2x.png | Bin 0 -> 2111 bytes .../paymentmethod/img/method/paypal@2x.png | Bin 0 -> 626 bytes .../img/method/paysafecard@2x.png | Bin 0 -> 420 bytes .../paymentmethod/img/method/sofort@2x.png | Bin 0 -> 453 bytes .../paymentmethod/tpl/bestellabschluss.tpl | 5 + .../paymentmethod/tpl/mollieComponents.tpl | 130 +++ version/111/sql/109.sql | 2 + version/111/tpl/_alerts.tpl | 10 + 64 files changed, 3591 insertions(+) create mode 100644 version/111/adminmenu/info.php create mode 100644 version/111/adminmenu/orders.php create mode 100644 version/111/adminmenu/paymentmethods.php create mode 100644 version/111/adminmenu/tpl/info.tpl create mode 100644 version/111/adminmenu/tpl/mollie-account-erstellen.png create mode 100644 version/111/adminmenu/tpl/order.tpl create mode 100644 version/111/adminmenu/tpl/orders.tpl create mode 100644 version/111/adminmenu/tpl/paymentmethods.tpl create mode 100644 version/111/class/ExclusiveLock.php create mode 100644 version/111/class/Helper.php create mode 100644 version/111/class/Model/AbstractModel.php create mode 100644 version/111/class/Model/Payment.php create mode 100644 version/111/class/Mollie.php create mode 100644 version/111/frontend/131_globalinclude.php create mode 100644 version/111/frontend/140_smarty.php create mode 100644 version/111/frontend/144_notify.php create mode 100644 version/111/frontend/181_sync.php create mode 100644 version/111/frontend/img/trust_eng.png create mode 100644 version/111/frontend/img/trust_fre.png create mode 100644 version/111/frontend/img/trust_ger.png create mode 100644 version/111/paymentmethod/JTLMollie.php create mode 100644 version/111/paymentmethod/JTLMollieApplePay.php create mode 100644 version/111/paymentmethod/JTLMollieBancontact.php create mode 100644 version/111/paymentmethod/JTLMollieBanktransfer.php create mode 100644 version/111/paymentmethod/JTLMollieBelfius.php create mode 100644 version/111/paymentmethod/JTLMollieCreditCard.php create mode 100644 version/111/paymentmethod/JTLMollieDirectDebit.php create mode 100644 version/111/paymentmethod/JTLMollieEPS.php create mode 100644 version/111/paymentmethod/JTLMollieGiftcard.php create mode 100644 version/111/paymentmethod/JTLMollieGiropay.php create mode 100644 version/111/paymentmethod/JTLMollieIDEAL.php create mode 100644 version/111/paymentmethod/JTLMollieINGHomePay.php create mode 100644 version/111/paymentmethod/JTLMollieKBC.php create mode 100644 version/111/paymentmethod/JTLMollieKlarnaPayLater.php create mode 100644 version/111/paymentmethod/JTLMollieKlarnaSliceIt.php create mode 100644 version/111/paymentmethod/JTLMollieMyBank.php create mode 100644 version/111/paymentmethod/JTLMolliePayPal.php create mode 100644 version/111/paymentmethod/JTLMolliePaysafecard.php create mode 100644 version/111/paymentmethod/JTLMolliePrzelewy24.php create mode 100644 version/111/paymentmethod/JTLMollieSofort.php create mode 100644 version/111/paymentmethod/img/method/Przelewy24@2x.png create mode 100644 version/111/paymentmethod/img/method/applepay@2x.png create mode 100644 version/111/paymentmethod/img/method/bancontact@2x.png create mode 100644 version/111/paymentmethod/img/method/banktransfer@2x.png create mode 100644 version/111/paymentmethod/img/method/belfius@2x.png create mode 100644 version/111/paymentmethod/img/method/creditcard@2x.png create mode 100644 version/111/paymentmethod/img/method/directdebit@2x.png create mode 100644 version/111/paymentmethod/img/method/eps@2x.png create mode 100644 version/111/paymentmethod/img/method/giftcard@2x.png create mode 100644 version/111/paymentmethod/img/method/giropay@2x.png create mode 100644 version/111/paymentmethod/img/method/ideal@2x.png create mode 100644 version/111/paymentmethod/img/method/inghomepay@2x.png create mode 100644 version/111/paymentmethod/img/method/kbc@2x.png create mode 100644 version/111/paymentmethod/img/method/klarna@2x.png create mode 100644 version/111/paymentmethod/img/method/mollie@2x.png create mode 100644 version/111/paymentmethod/img/method/mybank@2x.png create mode 100644 version/111/paymentmethod/img/method/paypal@2x.png create mode 100644 version/111/paymentmethod/img/method/paysafecard@2x.png create mode 100644 version/111/paymentmethod/img/method/sofort@2x.png create mode 100644 version/111/paymentmethod/tpl/bestellabschluss.tpl create mode 100644 version/111/paymentmethod/tpl/mollieComponents.tpl create mode 100644 version/111/sql/109.sql create mode 100644 version/111/tpl/_alerts.tpl diff --git a/info.xml b/info.xml index e4acb00..6b8f1db 100644 --- a/info.xml +++ b/info.xml @@ -43,6 +43,9 @@ 2020-11-19 + + 2020-11-19 + 131_globalinclude.php 144_notify.php diff --git a/version/111/adminmenu/info.php b/version/111/adminmenu/info.php new file mode 100644 index 0000000..817c5db --- /dev/null +++ b/version/111/adminmenu/info.php @@ -0,0 +1,64 @@ +assign('defaultTabbertab', Helper::getAdminmenu('Info') + Helper::getAdminmenu('Support')); + 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 "
" . + "
" . + " " . + " Lizenz Informationen" . + ' ' . + '
' . + "
" . + " " . + " Update Informationen" . + ' ' . + '
' . + "
" . + " " . + " Plugin informationen" . + ' ' . + '
' . + '
'; + + 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/111/adminmenu/orders.php b/version/111/adminmenu/orders.php new file mode 100644 index 0000000..f5bfc25 --- /dev/null +++ b/version/111/adminmenu/orders.php @@ -0,0 +1,236 @@ +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/111/adminmenu/paymentmethods.php b/version/111/adminmenu/paymentmethods.php new file mode 100644 index 0000000..df3bace --- /dev/null +++ b/version/111/adminmenu/paymentmethods.php @@ -0,0 +1,97 @@ +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'; + } + } + + $allMethods = []; + if ($active) { + $_allMethods = $mollie->methods->allActive($params); + } else { + $_allMethods = $mollie->methods->allAvailable($params); + } + + $sessionLife = (int)ini_get('session.gc_maxlifetime'); + + /** @var \Mollie\Api\Resources\Method $method */ + foreach ($_allMethods as $method) { + + $id = $method->id === 'creditcard' ? 'kreditkarte' : $method->id; + $key = "kPlugin_{$oPlugin->kPlugin}_mollie{$id}"; + + $class = null; + $shop = null; + $oClass = null; + + if (array_key_exists($key, $oPlugin->oPluginZahlungsKlasseAssoc_arr)) { + $class = $oPlugin->oPluginZahlungsKlasseAssoc_arr[$key]; + include_once($oPlugin->cPluginPfad . 'paymentmethod/' . $class->cClassPfad); + /** @var JTLMollie $oClass */ + $oClass = new $class->cClassName($id); + } + if (array_key_exists($key, $oPlugin->oPluginZahlungsmethodeAssoc_arr)) { + $shop = $oPlugin->oPluginZahlungsmethodeAssoc_arr[$key]; + } + + + $maxExpiryDays = $oClass ? $oClass->getExpiryDays() : null; + $allMethods[$method->id] = (object)[ + 'mollie' => $method, + 'class' => $class, + 'oClass' => $oClass, + 'shop' => $shop, + 'maxExpiryDays' => $oClass ? $maxExpiryDays : null, + 'warning' => $oClass && ($maxExpiryDays * 24 * 60 * 60) > $sessionLife, + 'session' => round($sessionLife / 60 / 60, 2) . 'h' + ]; + + } + + 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/111/adminmenu/tpl/info.tpl b/version/111/adminmenu/tpl/info.tpl new file mode 100644 index 0000000..2952fc6 --- /dev/null +++ b/version/111/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}
+
+
+
Changelog:
+
+ +
+
+ +
+
+ +
+
+
+ {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/111/adminmenu/tpl/mollie-account-erstellen.png b/version/111/adminmenu/tpl/mollie-account-erstellen.png new file mode 100644 index 0000000000000000000000000000000000000000..fc1819255ef725fa214cf2bf028cf3428794ecee GIT binary patch literal 38998 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 +

+ « + 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')} + +
{$payment->kID} diff --git a/version/109/paymentmethod/JTLMollie.php b/version/109/paymentmethod/JTLMollie.php index 8ee5675..214a5e8 100644 --- a/version/109/paymentmethod/JTLMollie.php +++ b/version/109/paymentmethod/JTLMollie.php @@ -226,7 +226,7 @@ public function updateMollieCustomer($oKunde) { return; - + // if (!$oKunde->kKunde || (int)$oKunde->nRegistriert <= 0) { // return; // } @@ -295,60 +295,6 @@ public static function API() return self::$_mollie; } - 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 static function getMollieCustomerId($kKunde) - { - //if ($row = Shop::DB()->select('xplugin_ws_mollie_kunde', 'kKunde', (int)$kKunde)) { - // return $row->customerId; - //} - return false; - } - /** * @param Bestellung $order * @param $hash @@ -553,6 +499,52 @@ protected function getOrderData(Bestellung $order, $hash) 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]); @@ -572,6 +564,14 @@ public function optionaleRundung($gesamtsumme) 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, '_'); @@ -592,11 +592,8 @@ public function handleNotification($order, $hash, $args) $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); } @@ -607,7 +604,7 @@ public function handleNotification($order, $hash, $args) * @param string $hash * @param array $args * - * @return true, if $order should be finalized + * @return boolean, true, if $order should be finalized */ public function finalizeOrder($order, $hash, $args) { @@ -622,6 +619,9 @@ 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); + Shop::DB()->executeQueryPrepared("UPDATE xplugin_ws_mollie_payments SET bLockTimeout = 1 WHERE kID = :kID;", [ + ':kID' => $args['id'] + ], 3); return false; } diff --git a/version/109/sql/107.sql b/version/109/sql/107.sql deleted file mode 100644 index debecf2..0000000 --- a/version/109/sql/107.sql +++ /dev/null @@ -1,4 +0,0 @@ -CREATE TABLE `xplugin_ws_mollie_kunde` ( - `kKunde` int NOT NULL PRIMARY KEY, - `customerId` varchar(32) NOT NULL -); \ 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 From 3a79b3105c11a4f06ef2b940b0adf14aa69f3c29 Mon Sep 17 00:00:00 2001 From: "dash.bar" Date: Mon, 17 Aug 2020 12:43:06 +0000 Subject: [PATCH 148/280] prepare finalize --- info.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/info.xml b/info.xml index 277ea46..01fa713 100644 --- a/info.xml +++ b/info.xml @@ -37,8 +37,8 @@ 2020-04-24 - 2020-04-24 109.sql + 2020-08-17 131_globalinclude.php From a800ef757de32c58cecea49065f7bf0e1147493e Mon Sep 17 00:00:00 2001 From: "dash.bar" Date: Mon, 17 Aug 2020 12:43:07 +0000 Subject: [PATCH 149/280] init version 110 --- info.xml | 3 + version/110/adminmenu/info.php | 64 ++ version/110/adminmenu/orders.php | 245 ++++++ version/110/adminmenu/paymentmethods.php | 60 ++ version/110/adminmenu/tpl/info.tpl | 114 +++ .../tpl/mollie-account-erstellen.png | Bin 0 -> 38998 bytes version/110/adminmenu/tpl/order.tpl | 281 +++++++ version/110/adminmenu/tpl/orders.tpl | 132 +++ version/110/adminmenu/tpl/paymentmethods.tpl | 97 +++ version/110/class/ExclusiveLock.php | 76 ++ version/110/class/Helper.php | 352 ++++++++ version/110/class/Model/AbstractModel.php | 7 + version/110/class/Model/Payment.php | 84 ++ version/110/class/Mollie.php | 556 +++++++++++++ version/110/frontend/131_globalinclude.php | 120 +++ version/110/frontend/140_smarty.php | 78 ++ version/110/frontend/144_notify.php | 63 ++ version/110/frontend/181_sync.php | 43 + version/110/frontend/img/trust_eng.png | Bin 0 -> 15299 bytes version/110/frontend/img/trust_fre.png | Bin 0 -> 17319 bytes version/110/frontend/img/trust_ger.png | Bin 0 -> 15352 bytes version/110/paymentmethod/JTLMollie.php | 774 ++++++++++++++++++ .../110/paymentmethod/JTLMollieApplePay.php | 8 + .../110/paymentmethod/JTLMollieBancontact.php | 8 + .../paymentmethod/JTLMollieBanktransfer.php | 10 + .../110/paymentmethod/JTLMollieBelfius.php | 8 + .../110/paymentmethod/JTLMollieCreditCard.php | 43 + .../paymentmethod/JTLMollieDirectDebit.php | 8 + version/110/paymentmethod/JTLMollieEPS.php | 8 + .../110/paymentmethod/JTLMollieGiftcard.php | 8 + .../110/paymentmethod/JTLMollieGiropay.php | 8 + version/110/paymentmethod/JTLMollieIDEAL.php | 8 + .../110/paymentmethod/JTLMollieINGHomePay.php | 8 + version/110/paymentmethod/JTLMollieKBC.php | 8 + .../paymentmethod/JTLMollieKlarnaPayLater.php | 8 + .../paymentmethod/JTLMollieKlarnaSliceIt.php | 8 + version/110/paymentmethod/JTLMollieMyBank.php | 8 + version/110/paymentmethod/JTLMolliePayPal.php | 8 + .../paymentmethod/JTLMolliePaysafecard.php | 8 + .../110/paymentmethod/JTLMolliePrzelewy24.php | 8 + version/110/paymentmethod/JTLMollieSofort.php | 8 + .../img/method/Przelewy24@2x.png | Bin 0 -> 859 bytes .../paymentmethod/img/method/applepay@2x.png | Bin 0 -> 656 bytes .../img/method/bancontact@2x.png | Bin 0 -> 582 bytes .../img/method/banktransfer@2x.png | Bin 0 -> 801 bytes .../paymentmethod/img/method/belfius@2x.png | Bin 0 -> 377 bytes .../img/method/creditcard@2x.png | Bin 0 -> 3125 bytes .../img/method/directdebit@2x.png | Bin 0 -> 801 bytes .../110/paymentmethod/img/method/eps@2x.png | Bin 0 -> 536 bytes .../paymentmethod/img/method/giftcard@2x.png | Bin 0 -> 2218 bytes .../paymentmethod/img/method/giropay@2x.png | Bin 0 -> 602 bytes .../110/paymentmethod/img/method/ideal@2x.png | Bin 0 -> 845 bytes .../img/method/inghomepay@2x.png | Bin 0 -> 1118 bytes .../110/paymentmethod/img/method/kbc@2x.png | Bin 0 -> 799 bytes .../paymentmethod/img/method/klarna@2x.png | Bin 0 -> 896 bytes .../paymentmethod/img/method/mollie@2x.png | Bin 0 -> 5366 bytes .../paymentmethod/img/method/mybank@2x.png | Bin 0 -> 2111 bytes .../paymentmethod/img/method/paypal@2x.png | Bin 0 -> 626 bytes .../img/method/paysafecard@2x.png | Bin 0 -> 420 bytes .../paymentmethod/img/method/sofort@2x.png | Bin 0 -> 453 bytes .../paymentmethod/tpl/bestellabschluss.tpl | 5 + .../paymentmethod/tpl/mollieComponents.tpl | 103 +++ version/110/sql/109.sql | 2 + version/110/tpl/_alerts.tpl | 10 + 64 files changed, 3458 insertions(+) create mode 100644 version/110/adminmenu/info.php create mode 100644 version/110/adminmenu/orders.php create mode 100644 version/110/adminmenu/paymentmethods.php create mode 100644 version/110/adminmenu/tpl/info.tpl create mode 100644 version/110/adminmenu/tpl/mollie-account-erstellen.png create mode 100644 version/110/adminmenu/tpl/order.tpl create mode 100644 version/110/adminmenu/tpl/orders.tpl create mode 100644 version/110/adminmenu/tpl/paymentmethods.tpl create mode 100644 version/110/class/ExclusiveLock.php create mode 100644 version/110/class/Helper.php create mode 100644 version/110/class/Model/AbstractModel.php create mode 100644 version/110/class/Model/Payment.php create mode 100644 version/110/class/Mollie.php create mode 100644 version/110/frontend/131_globalinclude.php create mode 100644 version/110/frontend/140_smarty.php create mode 100644 version/110/frontend/144_notify.php create mode 100644 version/110/frontend/181_sync.php create mode 100644 version/110/frontend/img/trust_eng.png create mode 100644 version/110/frontend/img/trust_fre.png create mode 100644 version/110/frontend/img/trust_ger.png create mode 100644 version/110/paymentmethod/JTLMollie.php create mode 100644 version/110/paymentmethod/JTLMollieApplePay.php create mode 100644 version/110/paymentmethod/JTLMollieBancontact.php create mode 100644 version/110/paymentmethod/JTLMollieBanktransfer.php create mode 100644 version/110/paymentmethod/JTLMollieBelfius.php create mode 100644 version/110/paymentmethod/JTLMollieCreditCard.php create mode 100644 version/110/paymentmethod/JTLMollieDirectDebit.php create mode 100644 version/110/paymentmethod/JTLMollieEPS.php create mode 100644 version/110/paymentmethod/JTLMollieGiftcard.php create mode 100644 version/110/paymentmethod/JTLMollieGiropay.php create mode 100644 version/110/paymentmethod/JTLMollieIDEAL.php create mode 100644 version/110/paymentmethod/JTLMollieINGHomePay.php create mode 100644 version/110/paymentmethod/JTLMollieKBC.php create mode 100644 version/110/paymentmethod/JTLMollieKlarnaPayLater.php create mode 100644 version/110/paymentmethod/JTLMollieKlarnaSliceIt.php create mode 100644 version/110/paymentmethod/JTLMollieMyBank.php create mode 100644 version/110/paymentmethod/JTLMolliePayPal.php create mode 100644 version/110/paymentmethod/JTLMolliePaysafecard.php create mode 100644 version/110/paymentmethod/JTLMolliePrzelewy24.php create mode 100644 version/110/paymentmethod/JTLMollieSofort.php create mode 100644 version/110/paymentmethod/img/method/Przelewy24@2x.png create mode 100644 version/110/paymentmethod/img/method/applepay@2x.png create mode 100644 version/110/paymentmethod/img/method/bancontact@2x.png create mode 100644 version/110/paymentmethod/img/method/banktransfer@2x.png create mode 100644 version/110/paymentmethod/img/method/belfius@2x.png create mode 100644 version/110/paymentmethod/img/method/creditcard@2x.png create mode 100644 version/110/paymentmethod/img/method/directdebit@2x.png create mode 100644 version/110/paymentmethod/img/method/eps@2x.png create mode 100644 version/110/paymentmethod/img/method/giftcard@2x.png create mode 100644 version/110/paymentmethod/img/method/giropay@2x.png create mode 100644 version/110/paymentmethod/img/method/ideal@2x.png create mode 100644 version/110/paymentmethod/img/method/inghomepay@2x.png create mode 100644 version/110/paymentmethod/img/method/kbc@2x.png create mode 100644 version/110/paymentmethod/img/method/klarna@2x.png create mode 100644 version/110/paymentmethod/img/method/mollie@2x.png create mode 100644 version/110/paymentmethod/img/method/mybank@2x.png create mode 100644 version/110/paymentmethod/img/method/paypal@2x.png create mode 100644 version/110/paymentmethod/img/method/paysafecard@2x.png create mode 100644 version/110/paymentmethod/img/method/sofort@2x.png create mode 100644 version/110/paymentmethod/tpl/bestellabschluss.tpl create mode 100644 version/110/paymentmethod/tpl/mollieComponents.tpl create mode 100644 version/110/sql/109.sql create mode 100644 version/110/tpl/_alerts.tpl diff --git a/info.xml b/info.xml index 01fa713..ca21821 100644 --- a/info.xml +++ b/info.xml @@ -40,6 +40,9 @@ 109.sql 2020-08-17 + + 2020-08-17 + 131_globalinclude.php 144_notify.php diff --git a/version/110/adminmenu/info.php b/version/110/adminmenu/info.php new file mode 100644 index 0000000..292064e --- /dev/null +++ b/version/110/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 "
" . + "
" . + " " . + " Lizenz Informationen" . + ' ' . + '
' . + "
" . + " " . + " Update Informationen" . + ' ' . + '
' . + "
" . + " " . + " Plugin informationen" . + ' ' . + '
' . + '
'; + + 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/110/adminmenu/orders.php b/version/110/adminmenu/orders.php new file mode 100644 index 0000000..ff35df5 --- /dev/null +++ b/version/110/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/110/adminmenu/paymentmethods.php b/version/110/adminmenu/paymentmethods.php new file mode 100644 index 0000000..1782978 --- /dev/null +++ b/version/110/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/110/adminmenu/tpl/info.tpl b/version/110/adminmenu/tpl/info.tpl new file mode 100644 index 0000000..2952fc6 --- /dev/null +++ b/version/110/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}
+
+
+
Changelog:
+
+ +
+
+ +
+
+ +
+
+
+ {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/110/adminmenu/tpl/mollie-account-erstellen.png b/version/110/adminmenu/tpl/mollie-account-erstellen.png new file mode 100644 index 0000000000000000000000000000000000000000..fc1819255ef725fa214cf2bf028cf3428794ecee GIT binary patch literal 38998 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 +

+ « + 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

+ + + + + + + + + + + + + + {foreach from=$order->payments() item=payment} + + + + + + + + + + + {/foreach} +
IDStatusMethodeAmountSettlementRefundedRemainingDetails
{$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} +
+
+{/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} +
+ + + + + + + + + + + + + + + + + + {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} + + + + + + + + + + + + + {/foreach} + + + + + + + + + + +
StatusSKUNameTypAnzahlMwStSteuerNettoBrutto 
+ {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*} +
{$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} + + + + + + + {/foreach} +
+ {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}
+ + diff --git a/version/110/adminmenu/tpl/orders.tpl b/version/110/adminmenu/tpl/orders.tpl new file mode 100644 index 0000000..669015a --- /dev/null +++ b/version/110/adminmenu/tpl/orders.tpl @@ -0,0 +1,132 @@ +{ws_mollie\Helper::showAlerts('orders')} + +{if $hasAPIKey == false} + + Jetzt kostenlos Mollie Account eröffnen! + +{else} + + + + + + + + + + + + + + + + {foreach from=$payments item=payment} + + + + + + + + + + + + {/foreach} + +
BestellNr.IDMollie StatusJTL StatusBetragWährungLocaleMethodeErstellt
+ {$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)}
+ {if $payments|count > 900} +
Hier werden nur die letzten 1000 Ergebnisse angezeigt.
+ {/if} + + +
+
+

Export:

+
+ +
+ + + + + +
+
+ +{/if} + diff --git a/version/110/adminmenu/tpl/paymentmethods.tpl b/version/110/adminmenu/tpl/paymentmethods.tpl new file mode 100644 index 0000000..4c37e02 --- /dev/null +++ b/version/110/adminmenu/tpl/paymentmethods.tpl @@ -0,0 +1,97 @@ +

Account Status

+ + + + + + + {if $profile->review} + + + {/if} + +
Mode:{$profile->mode}Status:{$profile->status}Review:{$profile->review->status}
+ +
+ +
+
+ + +
+ + + +
+
+ + +
+
+ + +
+
+ + + reset +
+
+
+ + +{if $allMethods && $allMethods|count} + + + + + + + + + + + + {foreach from=$allMethods item=method} + + + + + + + + {/foreach} + +
BildIDNamePreiseInfos
{$method->description|utf8_decode}{$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} +
+{else} +
Es konnten keine Methoden abgerufen werden.
+{/if} \ No newline at end of file diff --git a/version/110/class/ExclusiveLock.php b/version/110/class/ExclusiveLock.php new file mode 100644 index 0000000..834e00f --- /dev/null +++ b/version/110/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/110/class/Helper.php b/version/110/class/Helper.php new file mode 100644 index 0000000..5f2a8be --- /dev/null +++ b/version/110/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/110/class/Model/AbstractModel.php b/version/110/class/Model/AbstractModel.php new file mode 100644 index 0000000..5638700 --- /dev/null +++ b/version/110/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/110/class/Mollie.php b/version/110/class/Mollie.php new file mode 100644 index 0000000..1f87dbe --- /dev/null +++ b/version/110/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/110/frontend/131_globalinclude.php b/version/110/frontend/131_globalinclude.php new file mode 100644 index 0000000..5778e21 --- /dev/null +++ b/version/110/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/110/frontend/140_smarty.php b/version/110/frontend/140_smarty.php new file mode 100644 index 0000000..ac119c6 --- /dev/null +++ b/version/110/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/110/frontend/144_notify.php b/version/110/frontend/144_notify.php new file mode 100644 index 0000000..d1826a4 --- /dev/null +++ b/version/110/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/110/frontend/181_sync.php b/version/110/frontend/181_sync.php new file mode 100644 index 0000000..86c610c --- /dev/null +++ b/version/110/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/110/frontend/img/trust_eng.png b/version/110/frontend/img/trust_eng.png new file mode 100644 index 0000000000000000000000000000000000000000..3d0177359de7fa93833765ac05d8b218fa1550f2 GIT binary patch literal 15299 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 Rmns)TMnX}%M${5 literal 0 HcmV?d00001 diff --git a/version/110/frontend/img/trust_fre.png b/version/110/frontend/img/trust_fre.png new file mode 100644 index 0000000000000000000000000000000000000000..ed1a2f6f03c56f6748aac8af0352de7fc0afd3a4 GIT binary patch literal 17319 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 Mu#8ZJpsxS_1AJc%;s5{u literal 0 HcmV?d00001 diff --git a/version/110/frontend/img/trust_ger.png b/version/110/frontend/img/trust_ger.png new file mode 100644 index 0000000000000000000000000000000000000000..e42821b06709e8f4371c66cfb5759d00df0e1afd GIT binary patch literal 15352 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 (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/110/paymentmethod/JTLMollieApplePay.php b/version/110/paymentmethod/JTLMollieApplePay.php new file mode 100644 index 0000000..ecf20a8 --- /dev/null +++ b/version/110/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/110/paymentmethod/JTLMollieDirectDebit.php b/version/110/paymentmethod/JTLMollieDirectDebit.php new file mode 100644 index 0000000..ce0441d --- /dev/null +++ b/version/110/paymentmethod/JTLMollieDirectDebit.php @@ -0,0 +1,8 @@ +OH(NI>=T42<+x9g>;*Gy9DrKtJl=F((p(~XhRMojR(!TROq)4##x zi;wfn&C+>%^UTiFKSt7JYSXp1>ZPgDP*&5InbUcF<%^K^*xKlsoYHP{(wCajZ*$Ra zbJNPo(OY2BWNFmE!S~qO{POeCTVT|{z|(GX;Bt54e}mdsUi8b(sL>`X0000JbW%=J z01%HLkU-Cn-_OsV&!6AlpP5D4UE1#Sax&aZg(%L>z8x33MOZZ8H?WJ;;n51dMe)(}9UH1j29 ze@0RGfq`^s0!X#X7!_srsUP@btltZoyHfrIVq@*+2f)Ge+&BuBcbdrjKu5}NuE;){Yi3#o7gOK=v6Y0{rAbqNgQSz}}0I~5?ej{GsP%?vN z=_l4!?VPOmM>R@!2oOAkd1t|Pb#@H>-d=$PnbBs7=u%Z>9N;0iml z2#guk2rk-V%mMEvxQCZ1@+-_*(mao=fPWKs%h@Mp0)~gcfgO7j{4M(n<{@x^Z^Hk! ze1;0X32xx)(NPC3aetZbtnBss>W2NT-v%Bch%He^5RXIyLDWRp5;o{lcPr>qmkRZj lpHDtfd;A2~X0zTP_aA;i{an>LN7rz#m}I!{TEUogY_hW!fX z1?mg>C*-erx%(so1LG!77srr_xVP7C<}EQ0XbW_HZ(Bb#ysRpA(wRN~nf+#OlTe%( zXkfncL^KKCCrg-Lh=kEnU|a;ZB9QaR>Td+?i96wEUURmd^*;_;}q*?JtCN zs9v0_oUIYrJ>{ItUF)Suj=nY*E;y-_bg}zQ;ZT|@FU4Qeut^B)WfWUjV9g-3v@K+f-ik;kV{MOr_6wK;GGik>mTp$V%-RtP)+CPEi`n!UgTe~DWM4fFWeR( literal 0 HcmV?d00001 diff --git a/version/110/paymentmethod/img/method/bancontact@2x.png b/version/110/paymentmethod/img/method/bancontact@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..a87af77d20330ab4ee197fd750d0bd39a5b10f90 GIT binary patch literal 582 zcmV-M0=fN(P)lk!lq%lq?@9+Qr z|M>X$=jZ1jWQqR%{`vX&|JVTk=U{-T&j0$~pTFAg&hoWPVjpU$|LlN(mQMfcfPbmZpr$+j>2Uw#P;ZV{AZe)(UZem0@6X@u|MkEB z;XwWU{r~1*Ky`MXzS=N!uW*i8kF?YfT$A7F^MIC5pQk%!Gip%)000nlQchC<&w%eB zkRX4bpb&7+Z;x=Vl85vF00AONL_t(|UhS6GZp0uI1+V+IBnNQY-qL&T?f<_j%Vs4k zWi4ZPi#+c$LIR;fk}z^m8)w(24LdL-qBSjmiImqQ6%1%eKSC_H5hBJOQ3wcbh=A9j z0E`>M;F1Gj9uRN{NX-L}@Ce`*0RKJE1nw{TTbXGF`gs|rT7l!dln0%_EVm0RbGyKB zqJ*zRaiSTxE%@_=;_x?lSs8dz{y6#LPln}z>8GT40dLB`KB#<1qlM(E;D0OsM*0?TeIhg`dn6;Q{6Fh2l%qOS4K%wo8-q7AUD{?yGF(55vm4C&H_FzBH+J=d4+57}kr Up-!czfB*mh07*qoM6N<$g3OCHTL1t6 literal 0 HcmV?d00001 diff --git a/version/110/paymentmethod/img/method/banktransfer@2x.png b/version/110/paymentmethod/img/method/banktransfer@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..c70206bef4893f23fcd59d436273108d2f2eebc7 GIT binary patch literal 801 zcmV++1K#|JP)lk!lq*=;-9+mkX z{{U2_ztrjP@9%)A(*D5?-|6)J(MtZwET6yKpugSt`1lZBsz86cAZf7q`T3Bv*Z%(g z-|F=K#U1|5JO0^dAZoDx_u=pL`RC{7_xJZ;l*j-3@c!I)@AdkSwAlXDS^mf@aG%W2 z;O`J$tN-Md>+9=KiNUYR<6xA=@AUcq@WXGP%>DiS|LnB>%sc+*q+gWBFm$#4l$oJ=bMJL) zN$}UM z^EEI7D0q#*=`w@Mb&#yX6$WP@x&}s<8JvJ@pvqecQO^sez9^Xbs$t>(|Nn0Y_`k@X z`u+Uv`wm6F?mz#2{?4!aFGTBV&I9cbE(!7rW)PTg{{H;_^9ubA3J&Kd+&@2If#l5V zkwEFKo-U3d6>)E`o#Z>Lz~g$+{n^fDUKQE@|Mgd!a9=T#&e{4(sr-HO1o4KQ>uv;= zWX2_)yrQzk;QY@iN0x35n7oK-g-2+63_H(@QU|u6Z>|Z!r6lZ1zes9a?+x$E9%YhzX@O1Ta JS?83{1OT9Jm%RW0 literal 0 HcmV?d00001 diff --git a/version/110/paymentmethod/img/method/creditcard@2x.png b/version/110/paymentmethod/img/method/creditcard@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..b08be792753326b65345c752a6f350182a9393d2 GIT binary patch literal 3125 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 P00000NkvXXu0mjf3Vis# literal 0 HcmV?d00001 diff --git a/version/110/paymentmethod/img/method/directdebit@2x.png b/version/110/paymentmethod/img/method/directdebit@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..514ff845b84d38cd8eb97b9e2c53e5c117967944 GIT binary patch literal 801 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 literal 0 HcmV?d00001 diff --git a/version/110/paymentmethod/img/method/giropay@2x.png b/version/110/paymentmethod/img/method/giropay@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..b787e1fee50c9bcca112f734ef4bcbd4ecfb6d6b GIT binary patch literal 602 zcmV-g0;T5Kx~EOrH!)pASu;4ojd8OQ8=; zpbt!;!_w#B>GK{}r)iJG@bvggdAR@o{+6-TrM%mCn#w$GvMpk*ho#Tb-RaC5+y)hho537JnGBqPA~G@Ik#rt1jWCNmt_X5yY-;OM4Sm|;L0fCz(H!a59C z!6FQJ1`O=K0(U?&WmHmQ%ovl1g=xY%=0>sX7T{!DDr3#1AfT>{>*NQdp;XxeDnn^6 z;Fg|~18)oh=#B%J574HG=ZK=b0(2)=ZWs@6u|Psp2S`Ms-aSCKNc4dZ3ml0Y1JpF0 zACT7(WFOdH$J={=+}Kh?t@=QTh`Y)S;{lL4q2$K&0aK;&(@GqDK&DI^R~^tLy#OA$ z1Nay30gQkc{Q&0jzz(SpmbnlhVhfzVhaBhB0($}wh1S_^$N7}lg}e4p3Ic|F4;Z~b zTY@72isxg1#8BrSfnxv^S{6kiGl4E$H2v|f@*S9m0aJJk172Vm21F3Hg)IO)g#GGT oVe}rh6KIQG--ZM8)e@S10aM=ZI#^TblmGw#07*qoM6N<$f@FIOx&QzG literal 0 HcmV?d00001 diff --git a/version/110/paymentmethod/img/method/ideal@2x.png b/version/110/paymentmethod/img/method/ideal@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..efc4315a96a6b2d9b160578a65fe52206783f2ca GIT binary patch literal 845 zcmV-T1G4;yP)lk!ZZ65OMGC?}UYf;o;!m;NZf-!qXsn`1tsvqob6RlsGvz=jZ45_xJw({`vX& z+CYuwfU@xL?-Nv%`QPmApT=fqW&i*F(b3WK zzuD%1v(zAZ>+9>Xv$F87&$F|$@bK^%8W`-K#nT^p^1s=^!okAA!Tj&_DJdxZ{r%~X zz3Gp=&=7F!pvK@}pYN~F>5#mWl#|_1mb0_6g@uIHFobn>b?J}1M@UB*8yIC~W#VwE zc6N2$P?z9fpjKB^=ker~0000HbW%=J0PlbhkiUP=Adhe$&v1`#zea&7rvLx}*GWV{ zRCr#^*2j+9Fc5%YO7?ntl9{1;aqqou@0;Fxd;j;y*jNN`HV2Bl>~|3_{4oLqkzy%V z*t96C%}2Z9&SQ)86vWClksDVqqe|=&Z3|YQQjA*4CE6Eai>Qp6VzP3=CKt6Gk}WnU zMr|=|2#YGH?I~G;2n`TD#K5)puk^^z67b+ZZd-naz)7$!d_QRdc|mw#b1~<{2k2)FEaYF&OT-`GX$RPM#Nt`QAi#wXJk>zhFTO>59`Wo^#}<>sMjOed(+{-3ru0A7D$0jI558$ z)N0PF!RsCe2|{A+{jU4@5&uc>v9T(>X>= zpc$wJPDAG6XudKWan^4w_bUdHVBPG<>jQiVOn&QMzg?RgEbW=`(e{u7#up5;D^8W3 z2%8R3n@hIHS^6WCiFSq9p;8&OR7*Sn%M-cP>{s2YOOzKYHtDf;#GS4DUiRI4c22NA XzpeJ7+7%dW00000NkvXXu0mjfybi$$ literal 0 HcmV?d00001 diff --git a/version/110/paymentmethod/img/method/inghomepay@2x.png b/version/110/paymentmethod/img/method/inghomepay@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..538f219588886db215757eafd5c5151241f18b5a GIT binary patch literal 1118 zcmV-k1flzhP)`_0RK|}|55<|Q2_r?0RL0~|5E_}r-1)w9RKX&|5E_}=Gy;L z0RR90|6UOPlVJbp-~WC<|J1+#zn}l9fd6P9|A|olb1?tk&;RxB|Mc(wo^bzkF#pQ0 z|Fn<)>fisgkpF2Q|G%LBsek{okpG@<|H-fazM%hUAODC@|H-ibs(=5~!2gtB|K894 zs(@(VAMyYI01|XkPE!C7&ySx#AdugXK#$)bkdUC?LT6GX000A7Nkl+_F4;G0`t->#NE zT;V&r`f!+EySiCj<6V7Pt?{mYTH&4jj{)gM0TN(F3?6st+kjw6 z>LApXPB>Unt8V~;Cik9f49AhQ!$i7^fuL#4vW=&{86JR|lTsG~BRymzfEs|JX9J1K z03Dw$1C&G3WKK=%kB`J1r1*<~s2`z=k6T78&3xGOL&RV&0xXfJ0Ql@xfEn*A1CX9E zQ!WBD5?VbTK7XTsCp`U6crw}TsH%60W z2hoh@0nLYSxRBab{+9<3C+^Mz9xYb&ZxhMVDb+cqriY2<9AG-<8gN)^Cix5?)@kAU z;?6$;-SN`NKvD-cR@w%n?9AWi0I~xRElDnK5^Rh@FtDVHX8@ZJfJl->N&_A{l2bso z2x`kJr-3lmJ%9)DK@>~Q{7brt3fNKr^rbrq+|{-iAekxBG;uoyGqur4Ei0S?0=Yll zF_SR>W}x;7ttLalDFCI-OXsp?(S;*|rkk|uOcTs~fUR;0m?79z>!T@dSC<#zVpen3 zDj@L*GoMZY$tw7C*m%o|vLvel!qz~FMPzph=x6{KTjppdC7aC#VVdHg)$wl$bf*AC z1-Rnnz*LgVO4|B5HX#U@PXUn*;sq_sC5u*2fG7j7o&o~>%Wn3WWcg~#QmPptG|8+k2H7XW|=xVi9nUeg`1*I2IB*YJ(+JNL|VD24JQDXa_~} zqMBf8fF~Vbz5wvk*3xb81`yK5AZAEW$9)?Qt+BO>C3E@1Aktu4fz|6HW^Y;1@lk!lq%mkX z{~%3y0h-K!%;mq#+4%VQ5J7OCv&KMYjPLUG@9*#T_xE6cpCPBxaK_?)nX{kS?7!yn zfSI!2=Is9d{_pwx05oR#`T5`T`RC{7L9^Llzu!=FmQcCekkjew>+3LDf{>=XK(pDe zzt4c0vd`J#Fs;_V%-D~nykNlKAg9yc^7t^U)_~3BfX(J`#^Vv8&k>-{-}3p8(&?|? z?{JN&{r&x)v&FFA?=V_}aEz&7z~7M5=+D{X&+PS}+3awQs351(ptHqzpNxV4000qm zQchCIy&+X> z=*5Ul;OaQ@NK`Vzy8t_g2?_Jis)3C$i910Xw$PIU9&Uk!LpkskEkL9-LfkOWJAbaP zUroip18r(eg}^hN*BXg{sb1!Yfc6S#iGXvxN(6jb7x=sau0_D;#S-`?0_b=FJSG`H zPqbnfvWg$g}i**@5@#v5NT=$lzqSQdXDg|8f zIHlhJQN%Mfm~#2YP9b1YgB(!GAN!r?CIjA)sTANZfG||7{JhG5H)Vm3e?0>E>_vVi zq!;d4SOSQYxt#%m;F70Lx8o{r!Tt9&c8CI14(M}40nf9jzsNQAmkVA7gAM$Z|1+@m z0b{)*&IIp+jVE#-MjL9Dd6xv65#{P&<3u77*DDnbtf@m157r`vbG^_r?Ff8 d>Rr1A+%FMH_Q$8Zwr>Cc002ovPDHLkV1oT`waEYg literal 0 HcmV?d00001 diff --git a/version/110/paymentmethod/img/method/klarna@2x.png b/version/110/paymentmethod/img/method/klarna@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..e28a187b81e7c5a6256fea7382a643762746dd1e GIT binary patch literal 896 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 literal 0 HcmV?d00001 diff --git a/version/110/paymentmethod/img/method/paypal@2x.png b/version/110/paymentmethod/img/method/paypal@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..a816d7201f59ea7cef713f5e7895e66dcd6ee9a7 GIT binary patch literal 626 zcmV-&0*(ENP)zW{Q;0CK+oaK8X?zW{Q<0CB+pa=`#_!2of;na1S+alrro z|IFg@&*bxRu-m`e?~lRb-|hDbcETox$#AdRv()Q`yWm5X&|s$5P@dDD$>-eb_JFwG zpUUS$m(j@K@sPpeFpSLa_WMAU&p?#W{Qdsu^7&w=*MGR*^7#DO>Gd#+%P@?~P@U7S z((9ba=CIQ0sn6-_^!k0a-V=Mp)8_OXfyX(K&a%|&;_mkldc-e_%lZ5LgSp`#gUC6M z&erGk#LeN$0000GbW%=J0M8)rfN+qXfDoX6Z;yYFN6jxl0003wNklC4+MXiktqCYwRgSg6)KJbf z5Lj1?Y5+oU@|#dstX9C|0Ujt`J{M4b8Wr^cdi(ak0iFt>ORE}Nts8qh=FWCkI)}aEnE&{1?2hI?PIY68@ zbOdbw0PvXrf5i!Szy>sZ79ap>ye%)UHj^sMYbqagD6U zaJzaI>n$ypF23oVdS#o6|W|*DFT6j;X_Pjl^+{$7FxcM`F8{J!B6QqfZ6J=?T z0Z*i4z#}$g7~II(N7`*?T& O0000+D{~L?`zkmGy`PKgqj{m>0 z^Z&xI|35zdzp(26fxiDA9{<0v`v1;`{~L<_uT1&>;_Ck$4fn+3S%6jwlmz(&Gn{vr zARutRf5Q2Gh4~8e7rbanOaaP$^>lFzsfc?!?c};<10L727Z_ycPF(r9`v3o4QC^`f zNy*irThr_Lx8*f4F=sBE;Is9vL&{b+wWF_Q`cLpRlDMX^fZ@i14v}pdO3hrZ8V-u{ z6@GBmNPp@1=O;WPYJWl57EYgv)6tK(j<>!KX1Tkg-1yN7-6M=yr*jX!QWr1lo!e&; zepvX8JR>o1saCg`3ZOWgj;^L2z+zGho&3IENy|Lc5*g&izjA{*O9T;DjDIk7S9e6n)( p;e>?q6P^m(l+{vMe5&Mx9fO|m{vZE%WkG?%;OXk;vd$@?2>_eS)Oi2^ literal 0 HcmV?d00001 diff --git a/version/110/paymentmethod/tpl/bestellabschluss.tpl b/version/110/paymentmethod/tpl/bestellabschluss.tpl new file mode 100644 index 0000000..f7680f0 --- /dev/null +++ b/version/110/paymentmethod/tpl/bestellabschluss.tpl @@ -0,0 +1,5 @@ +{if isset($oMollieException)} +
+ {$oMollieException->getMessage()} +
+{/if} \ No newline at end of file diff --git a/version/110/paymentmethod/tpl/mollieComponents.tpl b/version/110/paymentmethod/tpl/mollieComponents.tpl new file mode 100644 index 0000000..825bc9f --- /dev/null +++ b/version/110/paymentmethod/tpl/mollieComponents.tpl @@ -0,0 +1,103 @@ +

{$mollieLang.cctitle}

+
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+ +
+
+ + +
+ +
+ {if $trustBadge} +
+ PCI-DSS SAQ-A compliant +
+ {/if} +
+ + + + + \ No newline at end of file diff --git a/version/110/sql/109.sql b/version/110/sql/109.sql new file mode 100644 index 0000000..41cda01 --- /dev/null +++ b/version/110/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/110/tpl/_alerts.tpl b/version/110/tpl/_alerts.tpl new file mode 100644 index 0000000..5279fa3 --- /dev/null +++ b/version/110/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} From cadfccc4afe8c05bfb07fb6d4e99f24f18403a27 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Mon, 16 Nov 2020 15:49:46 +0100 Subject: [PATCH 150/280] fix #114 --- workflow.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/workflow.php b/workflow.php index 08b9d73..8e900d0 100644 --- a/workflow.php +++ b/workflow.php @@ -19,7 +19,7 @@ //if (Helper::getSetting('notifyMollie') === 'W') { if (array_key_exists('secret', $_REQUEST) && trim($_REQUEST['secret']) !== '' && $_REQUEST['secret'] === Helper::getSetting('workflowSecret')) { - if(defined('MOLLIE_WORKFLOW_LOG') && MOLLIE_WORKFLOW_LOG){ + if (defined('MOLLIE_WORKFLOW_LOG') && MOLLIE_WORKFLOW_LOG) { file_put_contents(__DIR__ . '/workflow.log', print_r([$_REQUEST, $_SERVER], 1), FILE_APPEND); } @@ -33,8 +33,8 @@ switch (strtolower(trim($_REQUEST['action']))) { case 'storno': if ($oPayment = Payment::getPayment($kBestellung)) { - $logData .= '$' . $oPayment->kID . '§' . $oPayment->cOrderNumber; - $order = Mollie::JTLMollie()::API()->orders->get($oPayment->kID); + $logData .= '$' . $oPayment->kID . '�' . $oPayment->cOrderNumber; + $order = JTLMollie::API()->orders->get($oPayment->kID); if (in_array($order->status, [OrderStatus::STATUS_AUTHORIZED])) { $order = JTLMollie::API()->orders->cancel($oPayment->kID); Mollie::JTLMollie()->doLog("mollie//WORKFLOW: kBestellung:{$kBestellung} neuer Status: " . $order->status . ".", $logData, LOGLEVEL_NOTICE); @@ -65,8 +65,8 @@ case 'shipped': if ($oPayment = Payment::getPayment($kBestellung)) { - $logData .= '$' . $oPayment->kID . '§' . $oPayment->cOrderNumber; - $order = Mollie::JTLMollie()::API()->orders->get($oPayment->kID); + $logData .= '$' . $oPayment->kID . '�' . $oPayment->cOrderNumber; + $order = JTLMollie::API()->orders->get($oPayment->kID); if (in_array($order->status, [OrderStatus::STATUS_PAID, OrderStatus::STATUS_AUTHORIZED, OrderStatus::STATUS_SHIPPING])) { if ($complete) { $shipment = JTLMollie::API()->shipments->createFor($order, ['lines' => []]); @@ -91,9 +91,9 @@ die('kBestellung oder action fehlen'); } } else { - Jtllog::writeLog("mollie//WORKFLOW Datei aufgerufen, Secret jedoch nicht gültig!"); + Jtllog::writeLog("mollie//WORKFLOW Datei aufgerufen, Secret jedoch nicht g�ltig!"); http_response_code(403); - die('kBestellung oder action fehlen'); + die('Secret ungültig'); } //} else { // Jtllog::writeLog("mollie//WORKFLOW Datei aufgerufen, Setting jedoch nicht auf Workflow!"); From f559bdb40dcdde5f5141692ddef0a8ee5f56ef66 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Mon, 16 Nov 2020 16:32:57 +0100 Subject: [PATCH 151/280] fix #106 --- info.xml | 7 ++++++- version/110/paymentmethod/JTLMollie.php | 5 ++++- version/110/paymentmethod/JTLMollieKlarnaPayLater.php | 2 ++ version/110/paymentmethod/JTLMollieKlarnaSliceIt.php | 2 ++ 4 files changed, 14 insertions(+), 2 deletions(-) diff --git a/info.xml b/info.xml index ca21821..c374466 100644 --- a/info.xml +++ b/info.xml @@ -115,7 +115,7 @@ TransaktionsID des Zahlungseingangs: - Welche ID soll an die WAWI übetragen werden? + Welche ID soll an die WAWI übetragen werden? Bei PayPal wird immer die PayPal Referenz angegeben. wawiPaymentID @@ -128,6 +128,11 @@ Schlüssel, um die WAWI Workflow-Requests zu authentifizieren. workflowSecret + + Max. Gültigenkeit in Tagen: + Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. + expiryDays + diff --git a/version/110/paymentmethod/JTLMollie.php b/version/110/paymentmethod/JTLMollie.php index 214a5e8..d78471f 100644 --- a/version/110/paymentmethod/JTLMollie.php +++ b/version/110/paymentmethod/JTLMollie.php @@ -20,6 +20,8 @@ class JTLMollie extends PaymentMethod { + const MAX_EXPIRY_DAYS = 100; + const KUNDENATTRIBUT_CUSTOMERID = 'ws_mollie_customer_id'; const ALLOW_PAYMENT_BEFORE_ORDER = true; @@ -303,7 +305,7 @@ public static function API() protected function getOrderData(Bestellung $order, $hash) { $locale = self::getLocale($_SESSION['cISOSprache'], $_SESSION['Kunde']->cLand); - + $expiryDays = (int)Helper::getSetting('expiryDays') && (int)Helper::getSetting('expiryDays') <= static::MAX_EXPIRY_DAYS ? (int)(int)Helper::getSetting('expiryDays') : static::MAX_EXPIRY_DAYS; $_currencyFactor = (float)$order->Waehrung->fFaktor; $data = [ @@ -320,6 +322,7 @@ protected function getOrderData(Bestellung $order, $hash) '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, '_')), + 'expiresAt' => date('Y-m-d', strtotime("+{$expiryDays} DAYS")) ]; if (static::MOLLIE_METHOD !== '') { diff --git a/version/110/paymentmethod/JTLMollieKlarnaPayLater.php b/version/110/paymentmethod/JTLMollieKlarnaPayLater.php index fd8f78b..7016c4c 100644 --- a/version/110/paymentmethod/JTLMollieKlarnaPayLater.php +++ b/version/110/paymentmethod/JTLMollieKlarnaPayLater.php @@ -4,5 +4,7 @@ class JTLMollieKlarnaPayLater extends JTLMollie { + const MAX_EXPIRY_DAYS = 28; + const MOLLIE_METHOD = \Mollie\Api\Types\PaymentMethod::KLARNA_PAY_LATER; } diff --git a/version/110/paymentmethod/JTLMollieKlarnaSliceIt.php b/version/110/paymentmethod/JTLMollieKlarnaSliceIt.php index 1ed2f03..e210232 100644 --- a/version/110/paymentmethod/JTLMollieKlarnaSliceIt.php +++ b/version/110/paymentmethod/JTLMollieKlarnaSliceIt.php @@ -4,5 +4,7 @@ class JTLMollieKlarnaSliceIt extends JTLMollie { + const MAX_EXPIRY_DAYS = 28; + const MOLLIE_METHOD = \Mollie\Api\Types\PaymentMethod::KLARNA_SLICE_IT; } From 0e7db837eefbe9e9f411c6b697a755569edcbf82 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Tue, 17 Nov 2020 11:25:48 +0100 Subject: [PATCH 152/280] fix #95, #98 --- info.xml | 7 ++++++ version/110/paymentmethod/JTLMollie.php | 7 +++++- .../110/paymentmethod/JTLMollieCreditCard.php | 11 ++++++---- .../paymentmethod/tpl/mollieComponents.tpl | 22 ++++++++++++++++++- 4 files changed, 41 insertions(+), 6 deletions(-) diff --git a/info.xml b/info.xml index c374466..9438740 100644 --- a/info.xml +++ b/info.xml @@ -136,6 +136,13 @@ + + skipComponentsLink + + + + + cctitle diff --git a/version/110/paymentmethod/JTLMollie.php b/version/110/paymentmethod/JTLMollie.php index d78471f..5653cad 100644 --- a/version/110/paymentmethod/JTLMollie.php +++ b/version/110/paymentmethod/JTLMollie.php @@ -192,6 +192,7 @@ public function preparePaymentProcess($order) $oMolliePayment = self::API()->orders->create($orderData); $this->updateHash($hash, $oMolliePayment->id); $_SESSION['oMolliePayment'] = $oMolliePayment; + unset($_SESSION['mollieCardToken'], $_SESSION['mollieCardTokenTS']); } else { $oMolliePayment = $_SESSION['oMolliePayment']; } @@ -329,9 +330,13 @@ protected function getOrderData(Bestellung $order, $hash) $data['method'] = static::MOLLIE_METHOD; } - if (static::MOLLIE_METHOD === \Mollie\Api\Types\PaymentMethod::CREDITCARD && array_key_exists('mollieCardToken', $_SESSION)) { + if (static::MOLLIE_METHOD === \Mollie\Api\Types\PaymentMethod::CREDITCARD + && array_key_exists('mollieCardToken', $_SESSION) + && array_key_exists('mollieCardTokenTS', $_SESSION) && time() < (int)$_SESSION['mollieCardTokenTS']) { $data['payment'] = new stdClass(); $data['payment']->cardToken = trim($_SESSION['mollieCardToken']); + } else { + unset($_SESSION['mollieCardToken'], $_SESSION['mollieCardTokenTS']); } if (($customerId = self::getMollieCustomerId((int)$_SESSION['Kunde']->kKunde)) !== false) { diff --git a/version/110/paymentmethod/JTLMollieCreditCard.php b/version/110/paymentmethod/JTLMollieCreditCard.php index b7bc092..0b62e36 100644 --- a/version/110/paymentmethod/JTLMollieCreditCard.php +++ b/version/110/paymentmethod/JTLMollieCreditCard.php @@ -8,9 +8,14 @@ class JTLMollieCreditCard extends JTLMollie { const MOLLIE_METHOD = \Mollie\Api\Types\PaymentMethod::CREDITCARD; - public function handleAdditional($aPost_arr) { + + if(array_key_exists('skip', $aPost_arr) && (int)$aPost_arr['skip']){ + unset($_SESSION['mollieCardToken'], $_SESSION['mollieCardTokenTS']); + return true; + } + $profileId = trim(Helper::getSetting('profileId')); if ($profileId === '' || strpos($profileId, 'pfl_') !== 0) { return true; @@ -20,8 +25,7 @@ public function handleAdditional($aPost_arr) return true; } - unset($_SESSION['mollieCardToken']); - unset($_SESSION['mollieCardTokenTS']); + unset($_SESSION['mollieCardToken'], $_SESSION['mollieCardTokenTS']); if (array_key_exists('cardToken', $aPost_arr) && trim($aPost_arr['cardToken'])) { $_SESSION['mollieCardToken'] = trim($aPost_arr['cardToken']); @@ -39,5 +43,4 @@ public function handleAdditional($aPost_arr) return false; } - } diff --git a/version/110/paymentmethod/tpl/mollieComponents.tpl b/version/110/paymentmethod/tpl/mollieComponents.tpl index 825bc9f..97ce7e2 100644 --- a/version/110/paymentmethod/tpl/mollieComponents.tpl +++ b/version/110/paymentmethod/tpl/mollieComponents.tpl @@ -48,6 +48,9 @@ title="PCI-DSS SAQ-A compliant"/> {/if} + @@ -55,6 +58,18 @@ "; echo "
" . "
" . - " " . - " Lizenz Informationen" . + " " . + " Lizenz Informationen" . ' ' . ' ' . "
" . - " " . - " Update Informationen" . + " " . + " Update Informationen" . ' ' . ' ' . "
" . - " " . - " Plugin informationen" . + " " . + " Plugin informationen" . ' ' . ' ' . ''; From 6e39697099d72cb21d2a498ec5569d608dd71424 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Tue, 17 Nov 2020 15:17:08 +0100 Subject: [PATCH 157/280] #95 --- info.xml | 11 +++++++- .../110/paymentmethod/JTLMollieCreditCard.php | 1 + .../paymentmethod/tpl/mollieComponents.tpl | 25 ++++++++++++------- 3 files changed, 27 insertions(+), 10 deletions(-) diff --git a/info.xml b/info.xml index 9438740..a26dcf7 100644 --- a/info.xml +++ b/info.xml @@ -134,12 +134,21 @@ expiryDays + + mollie Components überspringbar: + Wenn diese Einstellung aktiv ist, erscheint beim Zahlungszusatzschritt (Kreditkarte) ein Link, um diesen Schritt zu überspringen. + skipComponents + + + + + skipComponentsLink - + diff --git a/version/110/paymentmethod/JTLMollieCreditCard.php b/version/110/paymentmethod/JTLMollieCreditCard.php index 0b62e36..f5a8cd3 100644 --- a/version/110/paymentmethod/JTLMollieCreditCard.php +++ b/version/110/paymentmethod/JTLMollieCreditCard.php @@ -36,6 +36,7 @@ public function handleAdditional($aPost_arr) 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('skipComponents', Helper::getSetting('skipComponents')) ->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); diff --git a/version/110/paymentmethod/tpl/mollieComponents.tpl b/version/110/paymentmethod/tpl/mollieComponents.tpl index 97ce7e2..f156c9d 100644 --- a/version/110/paymentmethod/tpl/mollieComponents.tpl +++ b/version/110/paymentmethod/tpl/mollieComponents.tpl @@ -48,16 +48,17 @@ title="PCI-DSS SAQ-A compliant"/> {/if} - + {if $skipComponents == 'Y'} + + {/if} - - var errorMessage = {if isset($errorMessage)}{$errorMessage}{else}null{/if}; + + \ No newline at end of file From c92f9afa3f25e03536b85ee6f7f6a7d3261c25ec Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Thu, 19 Nov 2020 16:41:56 +0100 Subject: [PATCH 158/280] fix #106 --- info.xml | 1452 ++++++++++-------- version/110/adminmenu/orders.php | 9 - version/110/adminmenu/paymentmethods.php | 49 +- version/110/adminmenu/tpl/paymentmethods.tpl | 52 +- version/110/paymentmethod/JTLMollie.php | 21 +- 5 files changed, 910 insertions(+), 673 deletions(-) diff --git a/info.xml b/info.xml index a26dcf7..529b9da 100644 --- a/info.xml +++ b/info.xml @@ -1,653 +1,819 @@ - - mollie - Zahlungsartplugin für mollie.com - WebStollen - https://www.webstollen.de/ - 102 - ws_mollie - 405 - - - 100.sql - 2019-02-11 - - - 2019-02-26 - - - 2019-04-23 - - - 2019-05-22 - - - 2019-07-12 - - - 2019-11-26 - - - 2019-12-18 - - - 107.sql - 2020-03-02 - - - 2020-04-24 - - - 109.sql - 2020-08-17 - - - 2020-08-17 - - - 131_globalinclude.php - 144_notify.php - 181_sync.php - 140_smarty.php - - - - Bestellungen - orders.php - - - Zahlungsarten - paymentmethods.php - - - Info - info.php - - - Einstellungen - - API Key: - Füge hier deinen mollie API Key ein - api_key - - - Profile ID: - Füge hier deinen mollie Profil ID (pfl_) ein. Wird benötigt um mollie Components zu aktivieren - profileId - - - Trust-Grafik bei mollie Components anzeigen: - Bindet eine Trust-Grafik unterhalb des Kreditkartenformulars ein. - loadTrust - - - - - - - Zahlungsart Daten syncronisiernen - Lädt Name / Bild für die jeweilige Sprache automatisch von mollie, und speichert diese in der Datenbank - paymentmethod_sync - - - - - - - - - Checkout Styles laden - Lädt Stylesheets für das Evo Template, um den Checkout zu verschönern. - load_styles - - - - - - - - Artikel mit rationalen Stückzahlen - Artikel mit rationalen Stückzahlen werden dann unterstützt, jedoch als ein Artikel behandelt. KEIN Teilversand hierfür möglich! - supportQ - - - - - - - TransaktionsID des Zahlungseingangs: - Welche ID soll an die WAWI übetragen werden? Bei PayPal wird immer die PayPal Referenz angegeben. - wawiPaymentID - - - - - - - - Workflow-Secret: - Schlüssel, um die WAWI Workflow-Requests zu authentifizieren. - workflowSecret - - - Max. Gültigenkeit in Tagen: - Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. - expiryDays - - - - mollie Components überspringbar: - Wenn diese Einstellung aktiv ist, erscheint beim Zahlungszusatzschritt (Kreditkarte) ein Link, um diesen Schritt zu überspringen. - skipComponents - - - - - - - - - skipComponentsLink - - - - - - - cctitle - - - - - - - error_canceled - - + + mollie + Zahlungsartplugin für mollie.com + WebStollen + https://www.webstollen.de/ + 102 + ws_mollie + 405 + + + 100.sql + 2019-02-11 + + + 2019-02-26 + + + 2019-04-23 + + + 2019-05-22 + + + 2019-07-12 + + + 2019-11-26 + + + 2019-12-18 + + + 107.sql + 2020-03-02 + + + 2020-04-24 + + + 109.sql + 2020-08-17 + + + 2020-08-17 + + + 131_globalinclude.php + 144_notify.php + 181_sync.php + 140_smarty.php + + + + Bestellungen + orders.php + + + Zahlungsarten + paymentmethods.php + + + Info + info.php + + + Einstellungen + + API Key: + Füge hier deinen mollie API Key ein + api_key + + + Profile ID: + Füge hier deinen mollie Profil ID (pfl_) ein. Wird benötigt um mollie Components zu + aktivieren + + profileId + + + Trust-Grafik bei mollie Components anzeigen: + Bindet eine Trust-Grafik unterhalb des Kreditkartenformulars ein. + loadTrust + + + + + + + Zahlungsart Daten syncronisiernen + Lädt Name / Bild für die jeweilige Sprache automatisch von mollie, und speichert diese + in der Datenbank + + paymentmethod_sync + + + + + + + + + Checkout Styles laden + Lädt Stylesheets für das Evo Template, um den Checkout zu verschönern. + load_styles + + + + + + + + Artikel mit rationalen Stückzahlen + Artikel mit rationalen Stückzahlen werden dann unterstützt, jedoch als ein Artikel + behandelt. KEIN Teilversand hierfür möglich! + + supportQ + + + + + + + TransaktionsID des Zahlungseingangs: + Welche ID soll an die WAWI übetragen werden? Bei PayPal wird immer die PayPal Referenz + angegeben. + + wawiPaymentID + + + + + + + + Workflow-Secret: + Schlüssel, um die WAWI Workflow-Requests zu authentifizieren. + workflowSecret + + + Max. Gültigenkeit in Tagen: + Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status + führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. + + expiryDays + + + + mollie Components überspringbar: + Wenn diese Einstellung aktiv ist, erscheint beim Zahlungszusatzschritt (Kreditkarte) + ein Link, um diesen Schritt zu überspringen. + + skipComponents + + + + + + + + + + skipComponentsLink + + + + + + + + + cctitle + + + + + + + error_canceled + + - - - - - error_expired - - + + + + + + error_expired + + - - - - - error_open - - + + + + + + error_open + + - - - - - error_failed - - + + + + + + error_failed + + - - - - - lbl_cardHolder - - - - - - - lbl_cardNumber - - - - - - - lbl_expiryDate - - - - - - - lbl_varificationCode - - - - - - - cvchint_1 - - - - - - - cvchint_2 - - + + + + + + lbl_cardHolder + + + + + + + lbl_cardNumber + + + + + + + lbl_expiryDate + + + + + + + lbl_varificationCode + + + + + + + cvchint_1 + + + + + + + cvchint_2 + + - - - - - mcErrorMessage - Ein oder mehrere Felder sind ungültig. - - - - - - - - mollie - img/method/mollie@2x.png - 1 - 0 - mollie.com - OTHER - 0 - 0 - 1 - 0 - JTLMollie.php - JTLMollie - tpl/bestellabschluss.tpl - - mollie - mollie - Bezahlen Sie bequem mit verschiedenen Zahlungsmethoden. - - - - mollie Kreditkarte - img/method/creditcard@2x.png - 3 - 0 - mollie.com - CREDIT_CARD - 1 - 0 - 1 - 0 - JTLMollieCreditCard.php - JTLMollieCreditCard - tpl/bestellabschluss.tpl - tpl/mollieComponents.tpl - - Kreditkarte - mollie - Bezahlen Sie bequem mit Kreditkarte. - - - - mollie Apple Pay - img/method/applepay@2x.png - 3 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMollieApplePay.php - JTLMollieApplePay - tpl/bestellabschluss.tpl - - Apple Pay - mollie - Bezahlen Sie bequem mit Apple Pay. - - - - mollie Bancontact - img/method/bancontact@2x.png - 4 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMollieBancontact.php - JTLMollieBancontact - tpl/bestellabschluss.tpl - - Bancontact - mollie - Bezahlen Sie bequem mit Bancontact. - - - - mollie Banktransfer - img/method/banktransfer@2x.png - 5 - 0 - mollie.com - OTHER - 0 - 0 - 1 - 0 - JTLMollieBanktransfer.php - JTLMollieBanktransfer - tpl/bestellabschluss.tpl - - SEPA Überweisung - mollie - Bezahlen Sie bequem mit SEPA Überweisung. - - - - mollie Belfius - img/method/belfius@2x.png - 6 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMollieBelfius.php - JTLMollieBelfius - tpl/bestellabschluss.tpl - - Belfius - mollie - Bezahlen Sie bequem mit Belfius. - - - - mollie DirectDebit - img/method/directdebit@2x.png - 7 - 0 - mollie.com - DIRECT_DEBIT - 1 - 0 - 1 - 0 - JTLMollieDirectDebit.php - JTLMollieDirectDebit - tpl/bestellabschluss.tpl - - SEPA Lastschrift - mollie - Bezahlen Sie bequem mit SEPA Lastschrift. - - - - mollie EPS - img/method/eps@2x.png - 2 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMollieEPS.php - JTLMollieEPS - tpl/bestellabschluss.tpl - - EPS - mollie - Bezahlen Sie bequem mit EPS. - - - - mollie Giftcard - img/method/giftcard@2x.png - 8 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMollieGiftcard.php - JTLMollieGiftcard - tpl/bestellabschluss.tpl - - Gift cards - mollie - Bezahlen Sie bequem mit Gift cards. - - - - mollie Giropay - img/method/giropay@2x.png - 9 - 0 - mollie.com - GIROPAY - 1 - 0 - 1 - 0 - JTLMollieGiropay.php - JTLMollieGiropay - tpl/bestellabschluss.tpl - - Giropay - mollie - Bezahlen Sie bequem mit Giropay. - - - - mollie iDEAL - img/method/ideal@2x.png - 10 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMollieIDEAL.php - JTLMollieIDEAL - tpl/bestellabschluss.tpl - - iDEAL - mollie - Bezahlen Sie bequem mit iDEAL. - - - - mollie ING HomePay - img/method/inghomepay@2x.png - 11 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMollieINGHomePay.php - JTLMollieINGHomePay - tpl/bestellabschluss.tpl - - ING HomePay - mollie - Bezahlen Sie bequem mit ING HomePay. - - - - mollie KBC - img/method/kbc@2x.png - 12 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMollieKBC.php - JTLMollieKBC - tpl/bestellabschluss.tpl - - KBC - mollie - Bezahlen Sie bequem mit KBC. - - - - mollie PayPal - img/method/paypal@2x.png - 13 - 0 - mollie.com - PAYPAL - 1 - 0 - 1 - 0 - JTLMolliePayPal.php - JTLMolliePayPal - tpl/bestellabschluss.tpl - - PayPal - mollie - Bezahlen Sie bequem mit PayPal. - - - - mollie paysafecard - img/method/paysafecard@2x.png - 14 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMolliePaysafecard.php - JTLMolliePaysafecard - tpl/bestellabschluss.tpl - - paysafecard - mollie - Bezahlen Sie bequem mit paysafecard. - - - - mollie SOFORT - img/method/sofort@2x.png - 15 - 0 - mollie.com - DIRECT_E_BANKING - 1 - 0 - 1 - 0 - JTLMollieSofort.php - JTLMollieSofort - tpl/bestellabschluss.tpl - - SOFORT - mollie - Bezahlen Sie bequem mit SOFORT. - - - - mollie Klarna Pay Later - img/method/klarna@2x.png - 16 - 0 - mollie.com - INVOICE - 1 - 0 - 1 - 0 - JTLMollieKlarnaPayLater.php - JTLMollieKlarnaPayLater - tpl/bestellabschluss.tpl - - Klarna Pay Later - mollie - Bezahlen Sie bequem mit Klarna Pay Later. - - - - mollie Klarna Slice It - img/method/klarna@2x.png - 17 - 0 - mollie.com - FINANCING - 1 - 0 - 1 - 0 - JTLMollieKlarnaSliceIt.php - JTLMollieKlarnaSliceIt - tpl/bestellabschluss.tpl - - Klarna Slice It - mollie - Bezahlen Sie bequem mit Klarna Slice It. - - - - mollie Przelewy24 - img/method/Przelewy24@2x.png - 17 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMolliePrzelewy24.php - JTLMolliePrzelewy24 - tpl/bestellabschluss.tpl - - Przelewy24 - mollie - Bezahlen Sie bequem mit Przelewy24. - - - - mollie MyBank - img/method/mybank@2x.png - 17 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMollieMyBank.php - JTLMollieMyBank - tpl/bestellabschluss.tpl - - MyBank - mollie - Bezahlen Sie bequem mit MyBank. - - - - + + + + + + + mcErrorMessage + Ein oder mehrere Felder sind ungültig. + + + + + + + + mollie + img/method/mollie@2x.png + 1 + 0 + mollie.com + OTHER + 0 + 0 + 1 + 0 + JTLMollie.php + JTLMollie + tpl/bestellabschluss.tpl + + mollie + mollie + Bezahlen Sie bequem mit verschiedenen Zahlungsmethoden. + + + Max. Gültigenkeit in Tagen: + Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status + führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. + + expiryDays + + + + mollie Kreditkarte + img/method/creditcard@2x.png + 3 + 0 + mollie.com + CREDIT_CARD + 1 + 0 + 1 + 0 + JTLMollieCreditCard.php + JTLMollieCreditCard + tpl/bestellabschluss.tpl + tpl/mollieComponents.tpl + + Kreditkarte + mollie + Bezahlen Sie bequem mit Kreditkarte. + + + Max. Gültigenkeit in Tagen: + Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status + führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. + + expiryDays + + + + mollie Apple Pay + img/method/applepay@2x.png + 3 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMollieApplePay.php + JTLMollieApplePay + tpl/bestellabschluss.tpl + + Apple Pay + mollie + Bezahlen Sie bequem mit Apple Pay. + + + Max. Gültigenkeit in Tagen: + Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status + führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. + + expiryDays + + + + mollie Bancontact + img/method/bancontact@2x.png + 4 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMollieBancontact.php + JTLMollieBancontact + tpl/bestellabschluss.tpl + + Bancontact + mollie + Bezahlen Sie bequem mit Bancontact. + + + Max. Gültigenkeit in Tagen: + Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status + führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. + + expiryDays + + + + mollie Banktransfer + img/method/banktransfer@2x.png + 5 + 0 + mollie.com + OTHER + 0 + 0 + 1 + 0 + JTLMollieBanktransfer.php + JTLMollieBanktransfer + tpl/bestellabschluss.tpl + + SEPA Überweisung + mollie + Bezahlen Sie bequem mit SEPA Überweisung. + + + Max. Gültigenkeit in Tagen: + Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status + führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. + + expiryDays + + + + mollie Belfius + img/method/belfius@2x.png + 6 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMollieBelfius.php + JTLMollieBelfius + tpl/bestellabschluss.tpl + + Belfius + mollie + Bezahlen Sie bequem mit Belfius. + + + Max. Gültigenkeit in Tagen: + Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status + führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. + + expiryDays + + + + mollie DirectDebit + img/method/directdebit@2x.png + 7 + 0 + mollie.com + DIRECT_DEBIT + 1 + 0 + 1 + 0 + JTLMollieDirectDebit.php + JTLMollieDirectDebit + tpl/bestellabschluss.tpl + + SEPA Lastschrift + mollie + Bezahlen Sie bequem mit SEPA Lastschrift. + + + Max. Gültigenkeit in Tagen: + Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status + führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. + + expiryDays + + + + mollie EPS + img/method/eps@2x.png + 2 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMollieEPS.php + JTLMollieEPS + tpl/bestellabschluss.tpl + + EPS + mollie + Bezahlen Sie bequem mit EPS. + + + Max. Gültigenkeit in Tagen: + Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status + führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. + + expiryDays + + + + mollie Giftcard + img/method/giftcard@2x.png + 8 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMollieGiftcard.php + JTLMollieGiftcard + tpl/bestellabschluss.tpl + + Gift cards + mollie + Bezahlen Sie bequem mit Gift cards. + + + Max. Gültigenkeit in Tagen: + Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status + führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. + + expiryDays + + + + mollie Giropay + img/method/giropay@2x.png + 9 + 0 + mollie.com + GIROPAY + 1 + 0 + 1 + 0 + JTLMollieGiropay.php + JTLMollieGiropay + tpl/bestellabschluss.tpl + + Giropay + mollie + Bezahlen Sie bequem mit Giropay. + + + Max. Gültigenkeit in Tagen: + Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status + führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. + + expiryDays + + + + mollie iDEAL + img/method/ideal@2x.png + 10 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMollieIDEAL.php + JTLMollieIDEAL + tpl/bestellabschluss.tpl + + iDEAL + mollie + Bezahlen Sie bequem mit iDEAL. + + + Max. Gültigenkeit in Tagen: + Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status + führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. + + expiryDays + + + + mollie ING HomePay + img/method/inghomepay@2x.png + 11 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMollieINGHomePay.php + JTLMollieINGHomePay + tpl/bestellabschluss.tpl + + ING HomePay + mollie + Bezahlen Sie bequem mit ING HomePay. + + + Max. Gültigenkeit in Tagen: + Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status + führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. + + expiryDays + + + + mollie KBC + img/method/kbc@2x.png + 12 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMollieKBC.php + JTLMollieKBC + tpl/bestellabschluss.tpl + + KBC + mollie + Bezahlen Sie bequem mit KBC. + + + Max. Gültigenkeit in Tagen: + Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status + führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. + + expiryDays + + + + mollie PayPal + img/method/paypal@2x.png + 13 + 0 + mollie.com + PAYPAL + 1 + 0 + 1 + 0 + JTLMolliePayPal.php + JTLMolliePayPal + tpl/bestellabschluss.tpl + + PayPal + mollie + Bezahlen Sie bequem mit PayPal. + + + Max. Gültigenkeit in Tagen: + Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status + führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. + + expiryDays + + + + mollie paysafecard + img/method/paysafecard@2x.png + 14 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMolliePaysafecard.php + JTLMolliePaysafecard + tpl/bestellabschluss.tpl + + paysafecard + mollie + Bezahlen Sie bequem mit paysafecard. + + + Max. Gültigenkeit in Tagen: + Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status + führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. + + expiryDays + + + + mollie SOFORT + img/method/sofort@2x.png + 15 + 0 + mollie.com + DIRECT_E_BANKING + 1 + 0 + 1 + 0 + JTLMollieSofort.php + JTLMollieSofort + tpl/bestellabschluss.tpl + + SOFORT + mollie + Bezahlen Sie bequem mit SOFORT. + + + Max. Gültigenkeit in Tagen: + Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status + führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. + + expiryDays + + + + mollie Klarna Pay Later + img/method/klarna@2x.png + 16 + 0 + mollie.com + INVOICE + 1 + 0 + 1 + 0 + JTLMollieKlarnaPayLater.php + JTLMollieKlarnaPayLater + tpl/bestellabschluss.tpl + + Klarna Pay Later + mollie + Bezahlen Sie bequem mit Klarna Pay Later. + + + Max. Gültigenkeit in Tagen: + Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status + führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. + + expiryDays + + + + mollie Klarna Slice It + img/method/klarna@2x.png + 17 + 0 + mollie.com + FINANCING + 1 + 0 + 1 + 0 + JTLMollieKlarnaSliceIt.php + JTLMollieKlarnaSliceIt + tpl/bestellabschluss.tpl + + Klarna Slice It + mollie + Bezahlen Sie bequem mit Klarna Slice It. + + + Max. Gültigenkeit in Tagen: + Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status + führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. + + expiryDays + + + + mollie Przelewy24 + img/method/Przelewy24@2x.png + 17 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMolliePrzelewy24.php + JTLMolliePrzelewy24 + tpl/bestellabschluss.tpl + + Przelewy24 + mollie + Bezahlen Sie bequem mit Przelewy24. + + + Max. Gültigenkeit in Tagen: + Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status + führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. + + expiryDays + + + + mollie MyBank + img/method/mybank@2x.png + 17 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMollieMyBank.php + JTLMollieMyBank + tpl/bestellabschluss.tpl + + MyBank + mollie + Bezahlen Sie bequem mit MyBank. + + + Max. Gültigenkeit in Tagen: + Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status + führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. + + expiryDays + + + + \ No newline at end of file diff --git a/version/110/adminmenu/orders.php b/version/110/adminmenu/orders.php index ff35df5..f5bfc25 100644 --- a/version/110/adminmenu/orders.php +++ b/version/110/adminmenu/orders.php @@ -14,15 +14,6 @@ require_once __DIR__ . '/../paymentmethod/JTLMollie.php'; global $oPlugin; - if (ini_get('session.gc_maxlifetime') < 172800) { - Helper::addAlert(sprintf('Session Laufzeit ist derzeit %d Sekunden. Bei Zahlung vor Bestellabschluss sind ' - . 'die Zahlungslinks jedoch bis zu 48h gültig (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']) { diff --git a/version/110/adminmenu/paymentmethods.php b/version/110/adminmenu/paymentmethods.php index 1782978..df3bace 100644 --- a/version/110/adminmenu/paymentmethods.php +++ b/version/110/adminmenu/paymentmethods.php @@ -5,15 +5,15 @@ use ws_mollie\Mollie; require_once __DIR__ . '/../class/Helper.php'; + +global $oPlugin; + try { if (!Helper::init()) { - echo "Kein gltige Lizenz?"; + echo "Kein gültige Lizenz?"; return; } - global $oPlugin; - - $mollie = new MollieApiClient(); $mollie->setApiKey(Helper::getSetting("api_key")); @@ -43,10 +43,47 @@ } } + $allMethods = []; if ($active) { - $allMethods = $mollie->methods->allActive($params); + $_allMethods = $mollie->methods->allActive($params); } else { - $allMethods = $mollie->methods->allAvailable($params); + $_allMethods = $mollie->methods->allAvailable($params); + } + + $sessionLife = (int)ini_get('session.gc_maxlifetime'); + + /** @var \Mollie\Api\Resources\Method $method */ + foreach ($_allMethods as $method) { + + $id = $method->id === 'creditcard' ? 'kreditkarte' : $method->id; + $key = "kPlugin_{$oPlugin->kPlugin}_mollie{$id}"; + + $class = null; + $shop = null; + $oClass = null; + + if (array_key_exists($key, $oPlugin->oPluginZahlungsKlasseAssoc_arr)) { + $class = $oPlugin->oPluginZahlungsKlasseAssoc_arr[$key]; + include_once($oPlugin->cPluginPfad . 'paymentmethod/' . $class->cClassPfad); + /** @var JTLMollie $oClass */ + $oClass = new $class->cClassName($id); + } + if (array_key_exists($key, $oPlugin->oPluginZahlungsmethodeAssoc_arr)) { + $shop = $oPlugin->oPluginZahlungsmethodeAssoc_arr[$key]; + } + + + $maxExpiryDays = $oClass ? $oClass->getExpiryDays() : null; + $allMethods[$method->id] = (object)[ + 'mollie' => $method, + 'class' => $class, + 'oClass' => $oClass, + 'shop' => $shop, + 'maxExpiryDays' => $oClass ? $maxExpiryDays : null, + 'warning' => $oClass && ($maxExpiryDays * 24 * 60 * 60) > $sessionLife, + 'session' => round($sessionLife / 60 / 60, 2) . 'h' + ]; + } Shop::Smarty()->assign('profile', $profile) diff --git a/version/110/adminmenu/tpl/paymentmethods.tpl b/version/110/adminmenu/tpl/paymentmethods.tpl index 0097804..79ecd3b 100644 --- a/version/110/adminmenu/tpl/paymentmethods.tpl +++ b/version/110/adminmenu/tpl/paymentmethods.tpl @@ -59,23 +59,53 @@
BildIDNameName / IDInfo PreiseInfosLimits
{$method->description|utf8_decode}{$method->id}{$method->description|utf8_decode}{$method->mollie->description|utf8_decode} + {$method->mollie->description|utf8_decode}
+ {$method->mollie->id} +
+ {if $method->shop && $method->oClass} + {if $method->shop->nWaehrendBestellung} + Zahlung + VOR + Bestellabschluss + {if $method->warning} +
+ + + Gültigkeit ist länger als Session-Laufzeit ({$method->session}). + + {/if} + {else} + Zahlung + NACH + Bestellabschluss + {/if} +
+ Gültigkeit + : {$method->maxExpiryDays} Tage + + {else} + Derzeit nicht unterstützt. + {/if} +
    - {foreach from=$method->pricing item=price} -
  • {$price->description|utf8_decode}: {$price->fixed->value} {$price->fixed->currency} + {foreach from=$method->mollie->pricing item=price} +
  • + {$price->description|utf8_decode}: {$price->fixed->value} {$price->fixed->currency} {if $price->variable > 0.0} + {$price->variable}% {/if} @@ -84,9 +114,9 @@
- Min: {if $method->minimumAmount}{$method->minimumAmount->value} {$method->minimumAmount->currency}{else}n/a{/if} + Min: {if $method->mollie->minimumAmount}{$method->mollie->minimumAmount->value} {$method->mollie->minimumAmount->currency}{else}n/a{/if}
- Max: {if $method->maximumAmount}{$method->maximumAmount->value} {$method->maximumAmount->currency}{else}n/a{/if} + Max: {if $method->mollie->maximumAmount}{$method->mollie->maximumAmount->value} {$method->mollie->maximumAmount->currency}{else}n/a{/if}
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
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

+ + + + + + + + + + + + + + {foreach from=$order->payments() item=payment} + + + + + + + + + + + {/foreach} +
IDStatusMethodeAmountSettlementRefundedRemainingDetails
{$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} +
+
+{/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} +
+ + + + + + + + + + + + + + + + + + {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} + + + + + + + + + + + + + {/foreach} + + + + + + + + + + +
StatusSKUNameTypAnzahlMwStSteuerNettoBrutto 
+ {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*} +
{$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} + + + + + + + {/foreach} +
+ {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}
+ + diff --git a/version/111/adminmenu/tpl/orders.tpl b/version/111/adminmenu/tpl/orders.tpl new file mode 100644 index 0000000..669015a --- /dev/null +++ b/version/111/adminmenu/tpl/orders.tpl @@ -0,0 +1,132 @@ +{ws_mollie\Helper::showAlerts('orders')} + +{if $hasAPIKey == false} + + Jetzt kostenlos Mollie Account eröffnen! + +{else} + + + + + + + + + + + + + + + + {foreach from=$payments item=payment} + + + + + + + + + + + + {/foreach} + +
BestellNr.IDMollie StatusJTL StatusBetragWährungLocaleMethodeErstellt
+ {$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)}
+ {if $payments|count > 900} +
Hier werden nur die letzten 1000 Ergebnisse angezeigt.
+ {/if} + + +
+
+

Export:

+
+ +
+ + + + + +
+
+ +{/if} + diff --git a/version/111/adminmenu/tpl/paymentmethods.tpl b/version/111/adminmenu/tpl/paymentmethods.tpl new file mode 100644 index 0000000..79ecd3b --- /dev/null +++ b/version/111/adminmenu/tpl/paymentmethods.tpl @@ -0,0 +1,127 @@ +

Account Status

+ + + + + + + {if $profile->review} + + + {/if} + +
Mode:{$profile->mode}Status:{$profile->status}Review:{$profile->review->status}
+ +
+ +
+
+ + +
+ + + +
+
+ + +
+
+ + +
+
+ + + reset +
+
+
+ + +{if $allMethods && $allMethods|count} + + + + + + + + + + + + {foreach from=$allMethods item=method} + + + + + + + + {/foreach} + +
BildName / IDInfoPreiseLimits
{$method->mollie->description|utf8_decode} + {$method->mollie->description|utf8_decode}
+ {$method->mollie->id} +
+ {if $method->shop && $method->oClass} + {if $method->shop->nWaehrendBestellung} + Zahlung + VOR + Bestellabschluss + {if $method->warning} +
+ + + Gültigkeit ist länger als Session-Laufzeit ({$method->session}). + + {/if} + {else} + Zahlung + NACH + Bestellabschluss + {/if} +
+ Gültigkeit + : {$method->maxExpiryDays} Tage + + {else} + Derzeit nicht unterstützt. + {/if} +
+
    + {foreach from=$method->mollie->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->mollie->minimumAmount}{$method->mollie->minimumAmount->value} {$method->mollie->minimumAmount->currency}{else}n/a{/if} +
+ Max: {if $method->mollie->maximumAmount}{$method->mollie->maximumAmount->value} {$method->mollie->maximumAmount->currency}{else}n/a{/if} +
+{else} +
Es konnten keine Methoden abgerufen werden.
+{/if} \ No newline at end of file diff --git a/version/111/class/ExclusiveLock.php b/version/111/class/ExclusiveLock.php new file mode 100644 index 0000000..834e00f --- /dev/null +++ b/version/111/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/111/class/Helper.php b/version/111/class/Helper.php new file mode 100644 index 0000000..5f2a8be --- /dev/null +++ b/version/111/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/111/class/Model/AbstractModel.php b/version/111/class/Model/AbstractModel.php new file mode 100644 index 0000000..5638700 --- /dev/null +++ b/version/111/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/111/class/Mollie.php b/version/111/class/Mollie.php new file mode 100644 index 0000000..cc5a1fc --- /dev/null +++ b/version/111/class/Mollie.php @@ -0,0 +1,564 @@ +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 = (int)$oBestellung->cStatus; + } + $options = []; + + // Tracking Data + if (isset($oBestellung->oLieferschein_arr)) { + $nLS = count($oBestellung->oLieferschein_arr) - 1; + if ($nLS >= 0 && isset($oBestellung->oLieferschein_arr[$nLS]) && isset($oBestellung->oLieferschein_arr[$nLS]->oVersand_arr)) { + $nV = count($oBestellung->oLieferschein_arr[$nLS]->oVersand_arr) - 1; + if ($nV >= 0 && isset($oBestellung->oLieferschein_arr[$nLS]->oVersand_arr[$nV])) { + /** @var \Versand $oVersand */ + $oVersand = $oBestellung->oLieferschein_arr[$nLS]->oVersand_arr[$nV]; + $tracking = new stdClass(); + $tracking->carrier = $oVersand->getLogistik(); + $tracking->url = $oVersand->getLogistikURL(); + $tracking->code = $oVersand->getIdentCode(); + $options['tracking'] = $tracking; + } + } + } + + $logData = '#' . $oBestellung->kBestellung . '§' . $oBestellung->cBestellNr . '$' . $order->id; + + switch ($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/111/frontend/131_globalinclude.php b/version/111/frontend/131_globalinclude.php new file mode 100644 index 0000000..5778e21 --- /dev/null +++ b/version/111/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/111/frontend/140_smarty.php b/version/111/frontend/140_smarty.php new file mode 100644 index 0000000..ac119c6 --- /dev/null +++ b/version/111/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/111/frontend/144_notify.php b/version/111/frontend/144_notify.php new file mode 100644 index 0000000..d1826a4 --- /dev/null +++ b/version/111/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/111/frontend/181_sync.php b/version/111/frontend/181_sync.php new file mode 100644 index 0000000..86c610c --- /dev/null +++ b/version/111/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/111/frontend/img/trust_eng.png b/version/111/frontend/img/trust_eng.png new file mode 100644 index 0000000000000000000000000000000000000000..3d0177359de7fa93833765ac05d8b218fa1550f2 GIT binary patch literal 15299 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 Rmns)TMnX}%M${5 literal 0 HcmV?d00001 diff --git a/version/111/frontend/img/trust_fre.png b/version/111/frontend/img/trust_fre.png new file mode 100644 index 0000000000000000000000000000000000000000..ed1a2f6f03c56f6748aac8af0352de7fc0afd3a4 GIT binary patch literal 17319 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 Mu#8ZJpsxS_1AJc%;s5{u literal 0 HcmV?d00001 diff --git a/version/111/frontend/img/trust_ger.png b/version/111/frontend/img/trust_ger.png new file mode 100644 index 0000000000000000000000000000000000000000..e42821b06709e8f4371c66cfb5759d00df0e1afd GIT binary patch literal 15352 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 = "kPlugin_" . Helper::oPlugin()->kPlugin . "_mollie{$moduleID}"; + } + + /** + * @return Helper + */ + public static function Helper() + { + if (self::$_helper === null) { + self::$_helper = new ws_mollie\Helper(); + } + return self::$_helper; + } + + /** + * @param Bestellung $order + * @param Object $payment (Key, Zahlungsanbieter, Abgeholt, Zeit is set here) + * @return $this + * @throws Exception + */ + public function addIncomingPayment($order, $payment) + { + $model = (object)array_merge([ + 'kBestellung' => (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; + + $_SESSION['MOLLIE_CHECKBOXES'] = []; + foreach ($_POST as $key => $value) { + if (strpos($key, 'CheckBox_') !== false) { + $_SESSION['MOLLIE_CHECKBOXES'][$key] = $value; + } + } + + + 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 && $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; + unset($_SESSION['mollieCardToken'], $_SESSION['mollieCardTokenTS']); + } 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); + $expiryDays = $this->getExpiryDays(); + $_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, '_')), + 'expiresAt' => date('Y-m-d', strtotime("+{$expiryDays} DAYS")) + ]; + + if (static::MOLLIE_METHOD !== '') { + $data['method'] = static::MOLLIE_METHOD; + } + + if (static::MOLLIE_METHOD === \Mollie\Api\Types\PaymentMethod::CREDITCARD + && array_key_exists('mollieCardToken', $_SESSION) + && array_key_exists('mollieCardTokenTS', $_SESSION) && time() < (int)$_SESSION['mollieCardTokenTS']) { + $data['payment'] = new stdClass(); + $data['payment']->cardToken = trim($_SESSION['mollieCardToken']); + } else { + unset($_SESSION['mollieCardToken'], $_SESSION['mollieCardTokenTS']); + } + + 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"; + } + } + + /** + * @return int + */ + public function getExpiryDays() + { + $max = static::MAX_EXPIRY_DAYS; + $global = (int)Helper::getSetting('expiryDays'); + $local = (int)Helper::oPlugin()->oPluginEinstellungAssoc_arr[$this->cModulId . '_expiryDays']; + + return (int)min($local > 0 ? $local : $global, $global, $max); + } + + 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) + { + if (array_key_exists('MOLLIE_CHECKBOXES', $_SESSION) && is_array($_SESSION['MOLLIE_CHECKBOXES'])) { + $_POST = array_merge($_POST, $_SESSION['MOLLIE_CHECKBOXES']); + } + $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/111/paymentmethod/JTLMollieApplePay.php b/version/111/paymentmethod/JTLMollieApplePay.php new file mode 100644 index 0000000..ecf20a8 --- /dev/null +++ b/version/111/paymentmethod/JTLMollieApplePay.php @@ -0,0 +1,8 @@ + time() + && array_key_exists('mollieCardToken', $_SESSION) && trim($_SESSION['mollieCardToken']) !== '') { + return true; + } + + unset($_SESSION['mollieCardToken'], $_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('skipComponents', Helper::getSetting('skipComponents')) + ->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/111/paymentmethod/JTLMollieDirectDebit.php b/version/111/paymentmethod/JTLMollieDirectDebit.php new file mode 100644 index 0000000..ce0441d --- /dev/null +++ b/version/111/paymentmethod/JTLMollieDirectDebit.php @@ -0,0 +1,8 @@ +OH(NI>=T42<+x9g>;*Gy9DrKtJl=F((p(~XhRMojR(!TROq)4##x zi;wfn&C+>%^UTiFKSt7JYSXp1>ZPgDP*&5InbUcF<%^K^*xKlsoYHP{(wCajZ*$Ra zbJNPo(OY2BWNFmE!S~qO{POeCTVT|{z|(GX;Bt54e}mdsUi8b(sL>`X0000JbW%=J z01%HLkU-Cn-_OsV&!6AlpP5D4UE1#Sax&aZg(%L>z8x33MOZZ8H?WJ;;n51dMe)(}9UH1j29 ze@0RGfq`^s0!X#X7!_srsUP@btltZoyHfrIVq@*+2f)Ge+&BuBcbdrjKu5}NuE;){Yi3#o7gOK=v6Y0{rAbqNgQSz}}0I~5?ej{GsP%?vN z=_l4!?VPOmM>R@!2oOAkd1t|Pb#@H>-d=$PnbBs7=u%Z>9N;0iml z2#guk2rk-V%mMEvxQCZ1@+-_*(mao=fPWKs%h@Mp0)~gcfgO7j{4M(n<{@x^Z^Hk! ze1;0X32xx)(NPC3aetZbtnBss>W2NT-v%Bch%He^5RXIyLDWRp5;o{lcPr>qmkRZj lpHDtfd;A2~X0zTP_aA;i{an>LN7rz#m}I!{TEUogY_hW!fX z1?mg>C*-erx%(so1LG!77srr_xVP7C<}EQ0XbW_HZ(Bb#ysRpA(wRN~nf+#OlTe%( zXkfncL^KKCCrg-Lh=kEnU|a;ZB9QaR>Td+?i96wEUURmd^*;_;}q*?JtCN zs9v0_oUIYrJ>{ItUF)Suj=nY*E;y-_bg}zQ;ZT|@FU4Qeut^B)WfWUjV9g-3v@K+f-ik;kV{MOr_6wK;GGik>mTp$V%-RtP)+CPEi`n!UgTe~DWM4fFWeR( literal 0 HcmV?d00001 diff --git a/version/111/paymentmethod/img/method/bancontact@2x.png b/version/111/paymentmethod/img/method/bancontact@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..a87af77d20330ab4ee197fd750d0bd39a5b10f90 GIT binary patch literal 582 zcmV-M0=fN(P)lk!lq%lq?@9+Qr z|M>X$=jZ1jWQqR%{`vX&|JVTk=U{-T&j0$~pTFAg&hoWPVjpU$|LlN(mQMfcfPbmZpr$+j>2Uw#P;ZV{AZe)(UZem0@6X@u|MkEB z;XwWU{r~1*Ky`MXzS=N!uW*i8kF?YfT$A7F^MIC5pQk%!Gip%)000nlQchC<&w%eB zkRX4bpb&7+Z;x=Vl85vF00AONL_t(|UhS6GZp0uI1+V+IBnNQY-qL&T?f<_j%Vs4k zWi4ZPi#+c$LIR;fk}z^m8)w(24LdL-qBSjmiImqQ6%1%eKSC_H5hBJOQ3wcbh=A9j z0E`>M;F1Gj9uRN{NX-L}@Ce`*0RKJE1nw{TTbXGF`gs|rT7l!dln0%_EVm0RbGyKB zqJ*zRaiSTxE%@_=;_x?lSs8dz{y6#LPln}z>8GT40dLB`KB#<1qlM(E;D0OsM*0?TeIhg`dn6;Q{6Fh2l%qOS4K%wo8-q7AUD{?yGF(55vm4C&H_FzBH+J=d4+57}kr Up-!czfB*mh07*qoM6N<$g3OCHTL1t6 literal 0 HcmV?d00001 diff --git a/version/111/paymentmethod/img/method/banktransfer@2x.png b/version/111/paymentmethod/img/method/banktransfer@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..c70206bef4893f23fcd59d436273108d2f2eebc7 GIT binary patch literal 801 zcmV++1K#|JP)lk!lq*=;-9+mkX z{{U2_ztrjP@9%)A(*D5?-|6)J(MtZwET6yKpugSt`1lZBsz86cAZf7q`T3Bv*Z%(g z-|F=K#U1|5JO0^dAZoDx_u=pL`RC{7_xJZ;l*j-3@c!I)@AdkSwAlXDS^mf@aG%W2 z;O`J$tN-Md>+9=KiNUYR<6xA=@AUcq@WXGP%>DiS|LnB>%sc+*q+gWBFm$#4l$oJ=bMJL) zN$}UM z^EEI7D0q#*=`w@Mb&#yX6$WP@x&}s<8JvJ@pvqecQO^sez9^Xbs$t>(|Nn0Y_`k@X z`u+Uv`wm6F?mz#2{?4!aFGTBV&I9cbE(!7rW)PTg{{H;_^9ubA3J&Kd+&@2If#l5V zkwEFKo-U3d6>)E`o#Z>Lz~g$+{n^fDUKQE@|Mgd!a9=T#&e{4(sr-HO1o4KQ>uv;= zWX2_)yrQzk;QY@iN0x35n7oK-g-2+63_H(@QU|u6Z>|Z!r6lZ1zes9a?+x$E9%YhzX@O1Ta JS?83{1OT9Jm%RW0 literal 0 HcmV?d00001 diff --git a/version/111/paymentmethod/img/method/creditcard@2x.png b/version/111/paymentmethod/img/method/creditcard@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..b08be792753326b65345c752a6f350182a9393d2 GIT binary patch literal 3125 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 P00000NkvXXu0mjf3Vis# literal 0 HcmV?d00001 diff --git a/version/111/paymentmethod/img/method/directdebit@2x.png b/version/111/paymentmethod/img/method/directdebit@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..514ff845b84d38cd8eb97b9e2c53e5c117967944 GIT binary patch literal 801 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 literal 0 HcmV?d00001 diff --git a/version/111/paymentmethod/img/method/giropay@2x.png b/version/111/paymentmethod/img/method/giropay@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..b787e1fee50c9bcca112f734ef4bcbd4ecfb6d6b GIT binary patch literal 602 zcmV-g0;T5Kx~EOrH!)pASu;4ojd8OQ8=; zpbt!;!_w#B>GK{}r)iJG@bvggdAR@o{+6-TrM%mCn#w$GvMpk*ho#Tb-RaC5+y)hho537JnGBqPA~G@Ik#rt1jWCNmt_X5yY-;OM4Sm|;L0fCz(H!a59C z!6FQJ1`O=K0(U?&WmHmQ%ovl1g=xY%=0>sX7T{!DDr3#1AfT>{>*NQdp;XxeDnn^6 z;Fg|~18)oh=#B%J574HG=ZK=b0(2)=ZWs@6u|Psp2S`Ms-aSCKNc4dZ3ml0Y1JpF0 zACT7(WFOdH$J={=+}Kh?t@=QTh`Y)S;{lL4q2$K&0aK;&(@GqDK&DI^R~^tLy#OA$ z1Nay30gQkc{Q&0jzz(SpmbnlhVhfzVhaBhB0($}wh1S_^$N7}lg}e4p3Ic|F4;Z~b zTY@72isxg1#8BrSfnxv^S{6kiGl4E$H2v|f@*S9m0aJJk172Vm21F3Hg)IO)g#GGT oVe}rh6KIQG--ZM8)e@S10aM=ZI#^TblmGw#07*qoM6N<$f@FIOx&QzG literal 0 HcmV?d00001 diff --git a/version/111/paymentmethod/img/method/ideal@2x.png b/version/111/paymentmethod/img/method/ideal@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..efc4315a96a6b2d9b160578a65fe52206783f2ca GIT binary patch literal 845 zcmV-T1G4;yP)lk!ZZ65OMGC?}UYf;o;!m;NZf-!qXsn`1tsvqob6RlsGvz=jZ45_xJw({`vX& z+CYuwfU@xL?-Nv%`QPmApT=fqW&i*F(b3WK zzuD%1v(zAZ>+9>Xv$F87&$F|$@bK^%8W`-K#nT^p^1s=^!okAA!Tj&_DJdxZ{r%~X zz3Gp=&=7F!pvK@}pYN~F>5#mWl#|_1mb0_6g@uIHFobn>b?J}1M@UB*8yIC~W#VwE zc6N2$P?z9fpjKB^=ker~0000HbW%=J0PlbhkiUP=Adhe$&v1`#zea&7rvLx}*GWV{ zRCr#^*2j+9Fc5%YO7?ntl9{1;aqqou@0;Fxd;j;y*jNN`HV2Bl>~|3_{4oLqkzy%V z*t96C%}2Z9&SQ)86vWClksDVqqe|=&Z3|YQQjA*4CE6Eai>Qp6VzP3=CKt6Gk}WnU zMr|=|2#YGH?I~G;2n`TD#K5)puk^^z67b+ZZd-naz)7$!d_QRdc|mw#b1~<{2k2)FEaYF&OT-`GX$RPM#Nt`QAi#wXJk>zhFTO>59`Wo^#}<>sMjOed(+{-3ru0A7D$0jI558$ z)N0PF!RsCe2|{A+{jU4@5&uc>v9T(>X>= zpc$wJPDAG6XudKWan^4w_bUdHVBPG<>jQiVOn&QMzg?RgEbW=`(e{u7#up5;D^8W3 z2%8R3n@hIHS^6WCiFSq9p;8&OR7*Sn%M-cP>{s2YOOzKYHtDf;#GS4DUiRI4c22NA XzpeJ7+7%dW00000NkvXXu0mjfybi$$ literal 0 HcmV?d00001 diff --git a/version/111/paymentmethod/img/method/inghomepay@2x.png b/version/111/paymentmethod/img/method/inghomepay@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..538f219588886db215757eafd5c5151241f18b5a GIT binary patch literal 1118 zcmV-k1flzhP)`_0RK|}|55<|Q2_r?0RL0~|5E_}r-1)w9RKX&|5E_}=Gy;L z0RR90|6UOPlVJbp-~WC<|J1+#zn}l9fd6P9|A|olb1?tk&;RxB|Mc(wo^bzkF#pQ0 z|Fn<)>fisgkpF2Q|G%LBsek{okpG@<|H-fazM%hUAODC@|H-ibs(=5~!2gtB|K894 zs(@(VAMyYI01|XkPE!C7&ySx#AdugXK#$)bkdUC?LT6GX000A7Nkl+_F4;G0`t->#NE zT;V&r`f!+EySiCj<6V7Pt?{mYTH&4jj{)gM0TN(F3?6st+kjw6 z>LApXPB>Unt8V~;Cik9f49AhQ!$i7^fuL#4vW=&{86JR|lTsG~BRymzfEs|JX9J1K z03Dw$1C&G3WKK=%kB`J1r1*<~s2`z=k6T78&3xGOL&RV&0xXfJ0Ql@xfEn*A1CX9E zQ!WBD5?VbTK7XTsCp`U6crw}TsH%60W z2hoh@0nLYSxRBab{+9<3C+^Mz9xYb&ZxhMVDb+cqriY2<9AG-<8gN)^Cix5?)@kAU z;?6$;-SN`NKvD-cR@w%n?9AWi0I~xRElDnK5^Rh@FtDVHX8@ZJfJl->N&_A{l2bso z2x`kJr-3lmJ%9)DK@>~Q{7brt3fNKr^rbrq+|{-iAekxBG;uoyGqur4Ei0S?0=Yll zF_SR>W}x;7ttLalDFCI-OXsp?(S;*|rkk|uOcTs~fUR;0m?79z>!T@dSC<#zVpen3 zDj@L*GoMZY$tw7C*m%o|vLvel!qz~FMPzph=x6{KTjppdC7aC#VVdHg)$wl$bf*AC z1-Rnnz*LgVO4|B5HX#U@PXUn*;sq_sC5u*2fG7j7o&o~>%Wn3WWcg~#QmPptG|8+k2H7XW|=xVi9nUeg`1*I2IB*YJ(+JNL|VD24JQDXa_~} zqMBf8fF~Vbz5wvk*3xb81`yK5AZAEW$9)?Qt+BO>C3E@1Aktu4fz|6HW^Y;1@lk!lq%mkX z{~%3y0h-K!%;mq#+4%VQ5J7OCv&KMYjPLUG@9*#T_xE6cpCPBxaK_?)nX{kS?7!yn zfSI!2=Is9d{_pwx05oR#`T5`T`RC{7L9^Llzu!=FmQcCekkjew>+3LDf{>=XK(pDe zzt4c0vd`J#Fs;_V%-D~nykNlKAg9yc^7t^U)_~3BfX(J`#^Vv8&k>-{-}3p8(&?|? z?{JN&{r&x)v&FFA?=V_}aEz&7z~7M5=+D{X&+PS}+3awQs351(ptHqzpNxV4000qm zQchCIy&+X> z=*5Ul;OaQ@NK`Vzy8t_g2?_Jis)3C$i910Xw$PIU9&Uk!LpkskEkL9-LfkOWJAbaP zUroip18r(eg}^hN*BXg{sb1!Yfc6S#iGXvxN(6jb7x=sau0_D;#S-`?0_b=FJSG`H zPqbnfvWg$g}i**@5@#v5NT=$lzqSQdXDg|8f zIHlhJQN%Mfm~#2YP9b1YgB(!GAN!r?CIjA)sTANZfG||7{JhG5H)Vm3e?0>E>_vVi zq!;d4SOSQYxt#%m;F70Lx8o{r!Tt9&c8CI14(M}40nf9jzsNQAmkVA7gAM$Z|1+@m z0b{)*&IIp+jVE#-MjL9Dd6xv65#{P&<3u77*DDnbtf@m157r`vbG^_r?Ff8 d>Rr1A+%FMH_Q$8Zwr>Cc002ovPDHLkV1oT`waEYg literal 0 HcmV?d00001 diff --git a/version/111/paymentmethod/img/method/klarna@2x.png b/version/111/paymentmethod/img/method/klarna@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..e28a187b81e7c5a6256fea7382a643762746dd1e GIT binary patch literal 896 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 literal 0 HcmV?d00001 diff --git a/version/111/paymentmethod/img/method/paypal@2x.png b/version/111/paymentmethod/img/method/paypal@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..a816d7201f59ea7cef713f5e7895e66dcd6ee9a7 GIT binary patch literal 626 zcmV-&0*(ENP)zW{Q;0CK+oaK8X?zW{Q<0CB+pa=`#_!2of;na1S+alrro z|IFg@&*bxRu-m`e?~lRb-|hDbcETox$#AdRv()Q`yWm5X&|s$5P@dDD$>-eb_JFwG zpUUS$m(j@K@sPpeFpSLa_WMAU&p?#W{Qdsu^7&w=*MGR*^7#DO>Gd#+%P@?~P@U7S z((9ba=CIQ0sn6-_^!k0a-V=Mp)8_OXfyX(K&a%|&;_mkldc-e_%lZ5LgSp`#gUC6M z&erGk#LeN$0000GbW%=J0M8)rfN+qXfDoX6Z;yYFN6jxl0003wNklC4+MXiktqCYwRgSg6)KJbf z5Lj1?Y5+oU@|#dstX9C|0Ujt`J{M4b8Wr^cdi(ak0iFt>ORE}Nts8qh=FWCkI)}aEnE&{1?2hI?PIY68@ zbOdbw0PvXrf5i!Szy>sZ79ap>ye%)UHj^sMYbqagD6U zaJzaI>n$ypF23oVdS#o6|W|*DFT6j;X_Pjl^+{$7FxcM`F8{J!B6QqfZ6J=?T z0Z*i4z#}$g7~II(N7`*?T& O0000+D{~L?`zkmGy`PKgqj{m>0 z^Z&xI|35zdzp(26fxiDA9{<0v`v1;`{~L<_uT1&>;_Ck$4fn+3S%6jwlmz(&Gn{vr zARutRf5Q2Gh4~8e7rbanOaaP$^>lFzsfc?!?c};<10L727Z_ycPF(r9`v3o4QC^`f zNy*irThr_Lx8*f4F=sBE;Is9vL&{b+wWF_Q`cLpRlDMX^fZ@i14v}pdO3hrZ8V-u{ z6@GBmNPp@1=O;WPYJWl57EYgv)6tK(j<>!KX1Tkg-1yN7-6M=yr*jX!QWr1lo!e&; zepvX8JR>o1saCg`3ZOWgj;^L2z+zGho&3IENy|Lc5*g&izjA{*O9T;DjDIk7S9e6n)( p;e>?q6P^m(l+{vMe5&Mx9fO|m{vZE%WkG?%;OXk;vd$@?2>_eS)Oi2^ literal 0 HcmV?d00001 diff --git a/version/111/paymentmethod/tpl/bestellabschluss.tpl b/version/111/paymentmethod/tpl/bestellabschluss.tpl new file mode 100644 index 0000000..f7680f0 --- /dev/null +++ b/version/111/paymentmethod/tpl/bestellabschluss.tpl @@ -0,0 +1,5 @@ +{if isset($oMollieException)} +
+ {$oMollieException->getMessage()} +
+{/if} \ No newline at end of file diff --git a/version/111/paymentmethod/tpl/mollieComponents.tpl b/version/111/paymentmethod/tpl/mollieComponents.tpl new file mode 100644 index 0000000..f156c9d --- /dev/null +++ b/version/111/paymentmethod/tpl/mollieComponents.tpl @@ -0,0 +1,130 @@ +

{$mollieLang.cctitle}

+
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+ +
+
+ + +
+ +
+ {if $trustBadge} +
+ PCI-DSS SAQ-A compliant +
+ {/if} + {if $skipComponents == 'Y'} + + {/if} +
+ + + + + + + \ No newline at end of file diff --git a/version/111/sql/109.sql b/version/111/sql/109.sql new file mode 100644 index 0000000..41cda01 --- /dev/null +++ b/version/111/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/111/tpl/_alerts.tpl b/version/111/tpl/_alerts.tpl new file mode 100644 index 0000000..5279fa3 --- /dev/null +++ b/version/111/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} From 7cbff5d1d364e72c33237c206d885ae1be5c3da6 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Mon, 23 Nov 2020 10:31:21 +0100 Subject: [PATCH 162/280] =?UTF-8?q?fix=20UTF8=20rationale=20St=C3=BCckzahl?= =?UTF-8?q?en?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- version/110/paymentmethod/JTLMollie.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version/110/paymentmethod/JTLMollie.php b/version/110/paymentmethod/JTLMollie.php index ba208be..eeb624d 100644 --- a/version/110/paymentmethod/JTLMollie.php +++ b/version/110/paymentmethod/JTLMollie.php @@ -412,7 +412,7 @@ protected function getOrderData(Bestellung $order, $hash) && fmod($oPosition->nAnzahl, 1) !== 0.0) { $_netto *= $_amount; $_amount = 1; - $line->name .= sprintf(" (%.2f %s)", (float)$oPosition->nAnzahl, $oPosition->cEinheit); + $line->name .= utf8_encode(sprintf(" (%.2f %s)", (float)$oPosition->nAnzahl, $oPosition->cEinheit)); } } From 6f2a56d2a3c51c93baed3eeb2591b59db2ac7f6b Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Mon, 23 Nov 2020 10:32:16 +0100 Subject: [PATCH 163/280] =?UTF-8?q?fix=20UTF8=20rationale=20St=C3=BCckzahl?= =?UTF-8?q?en?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- version/111/paymentmethod/JTLMollie.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version/111/paymentmethod/JTLMollie.php b/version/111/paymentmethod/JTLMollie.php index ba208be..eeb624d 100644 --- a/version/111/paymentmethod/JTLMollie.php +++ b/version/111/paymentmethod/JTLMollie.php @@ -412,7 +412,7 @@ protected function getOrderData(Bestellung $order, $hash) && fmod($oPosition->nAnzahl, 1) !== 0.0) { $_netto *= $_amount; $_amount = 1; - $line->name .= sprintf(" (%.2f %s)", (float)$oPosition->nAnzahl, $oPosition->cEinheit); + $line->name .= utf8_encode(sprintf(" (%.2f %s)", (float)$oPosition->nAnzahl, $oPosition->cEinheit)); } } From 79c1533b03de2302cb12e7ee0fb7e28215ddd46b Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Thu, 26 Nov 2020 10:48:32 +0100 Subject: [PATCH 164/280] IE fixes, fix Lock Exception --- version/111/class/ExclusiveLock.php | 65 ++++++++----------- .../paymentmethod/tpl/mollieComponents.tpl | 9 +-- 2 files changed, 31 insertions(+), 43 deletions(-) diff --git a/version/111/class/ExclusiveLock.php b/version/111/class/ExclusiveLock.php index 834e00f..f182605 100644 --- a/version/111/class/ExclusiveLock.php +++ b/version/111/class/ExclusiveLock.php @@ -4,21 +4,19 @@ namespace ws_mollie; -use Noodlehaus\Exception; - class ExclusiveLock { protected $key; //user given value protected $file; //resource to lock - protected $own = false; //have we locked resource + protected $own = false; //have we locked resource protected $path = ""; - public function __construct( $key, $path = "" ) + public function __construct($key, $path = "") { $this->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!"); + $this->path = rtrim(realpath($path), '/') . '/'; + if (!is_dir($path) || !is_writable($path)) { + throw new \RuntimeException("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+'); @@ -27,15 +25,32 @@ public function __construct( $key, $path = "" ) public function __destruct() { - if( $this->own === true ) - $this->unlock( ); + if ($this->own === true) + $this->unlock(); } + 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 + } public function lock() { - if( !flock($this->file, LOCK_EX | LOCK_NB)) - { //failed + if (!flock($this->file, LOCK_EX | LOCK_NB)) { //failed $key = $this->key; error_log("ExclusiveLock::acquire_lock FAILED to acquire lock [$key]"); return false; @@ -43,34 +58,10 @@ public function lock() //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 ); + 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/111/paymentmethod/tpl/mollieComponents.tpl b/version/111/paymentmethod/tpl/mollieComponents.tpl index f156c9d..024393d 100644 --- a/version/111/paymentmethod/tpl/mollieComponents.tpl +++ b/version/111/paymentmethod/tpl/mollieComponents.tpl @@ -108,19 +108,16 @@ errorDiv.innerHTML = ''; mollie.createToken().then(function (result) { - const { - token, error - } = result; - if (error) { + if (result.error) { var alert = document.createElement('div'); alert.className = 'alert alert-danger'; alert.id = 'mollieErrorContent'; - alert.textContent = errorMessage ? errorMessage : error.message; + alert.textContent = errorMessage ? errorMessage : result.error.message; errorDiv.append(alert); } else { // Add token to the form const tokenInput = document.getElementById("cardToken"); - tokenInput.value = token; + tokenInput.value = result.token; // Re-submit form to the server form.submit(); } From e7002eeb94c48171bc5a503b4bf606ac918d24be Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Fri, 4 Dec 2020 13:23:14 +0100 Subject: [PATCH 165/280] fix workflow (cherry picked from commit 860096bcd2158747d42f20a28f11eaca71753761) --- workflow.php | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/workflow.php b/workflow.php index 8e900d0..eb1fc17 100644 --- a/workflow.php +++ b/workflow.php @@ -16,6 +16,8 @@ return; } + require_once $oPlugin->cAdminmenuPfad . '../paymentmethod/JTLMollie.php'; + //if (Helper::getSetting('notifyMollie') === 'W') { if (array_key_exists('secret', $_REQUEST) && trim($_REQUEST['secret']) !== '' && $_REQUEST['secret'] === Helper::getSetting('workflowSecret')) { @@ -33,9 +35,10 @@ switch (strtolower(trim($_REQUEST['action']))) { case 'storno': if ($oPayment = Payment::getPayment($kBestellung)) { - $logData .= '$' . $oPayment->kID . '�' . $oPayment->cOrderNumber; + $logData .= '$' . $oPayment->kID . '§' . $oPayment->cOrderNumber; $order = JTLMollie::API()->orders->get($oPayment->kID); - if (in_array($order->status, [OrderStatus::STATUS_AUTHORIZED])) { + + if ($order->status === OrderStatus::STATUS_AUTHORIZED) { $order = JTLMollie::API()->orders->cancel($oPayment->kID); Mollie::JTLMollie()->doLog("mollie//WORKFLOW: kBestellung:{$kBestellung} neuer Status: " . $order->status . ".", $logData, LOGLEVEL_NOTICE); } elseif ($order->status === OrderStatus::STATUS_PAID || $order->status === OrderStatus::STATUS_COMPLETED) { @@ -65,7 +68,7 @@ case 'shipped': if ($oPayment = Payment::getPayment($kBestellung)) { - $logData .= '$' . $oPayment->kID . '�' . $oPayment->cOrderNumber; + $logData .= '$' . $oPayment->kID . '�' . $oPayment->cOrderNumber; $order = JTLMollie::API()->orders->get($oPayment->kID); if (in_array($order->status, [OrderStatus::STATUS_PAID, OrderStatus::STATUS_AUTHORIZED, OrderStatus::STATUS_SHIPPING])) { if ($complete) { @@ -91,9 +94,9 @@ die('kBestellung oder action fehlen'); } } else { - Jtllog::writeLog("mollie//WORKFLOW Datei aufgerufen, Secret jedoch nicht g�ltig!"); + Jtllog::writeLog("mollie//WORKFLOW Datei aufgerufen, Secret jedoch nicht gültig!"); http_response_code(403); - die('Secret ungültig'); + die('Secret ungültig'); } //} else { // Jtllog::writeLog("mollie//WORKFLOW Datei aufgerufen, Setting jedoch nicht auf Workflow!"); From e18552bee42be073cc77584a08825140bc389845 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Fri, 18 Dec 2020 14:01:39 +0100 Subject: [PATCH 166/280] typo --- info.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/info.xml b/info.xml index 6b8f1db..33a72e4 100644 --- a/info.xml +++ b/info.xml @@ -87,7 +87,7 @@ - Zahlungsart Daten syncronisiernen + Zahlungsart Daten synchronisieren Lädt Name / Bild für die jeweilige Sprache automatisch von mollie, und speichert diese in der Datenbank paymentmethod_sync From 6f3f3c85f7f8bd8ea335bb820dec744ee0638899 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Fri, 18 Dec 2020 14:04:03 +0100 Subject: [PATCH 167/280] utf8 encode tracking --- version/111/class/Mollie.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/version/111/class/Mollie.php b/version/111/class/Mollie.php index cc5a1fc..e7e0d9b 100644 --- a/version/111/class/Mollie.php +++ b/version/111/class/Mollie.php @@ -83,9 +83,9 @@ public static function getShipmentOptions(Order $order, $kBestellung, $newStatus /** @var \Versand $oVersand */ $oVersand = $oBestellung->oLieferschein_arr[$nLS]->oVersand_arr[$nV]; $tracking = new stdClass(); - $tracking->carrier = $oVersand->getLogistik(); - $tracking->url = $oVersand->getLogistikURL(); - $tracking->code = $oVersand->getIdentCode(); + $tracking->carrier = utf8_encode($oVersand->getLogistik()); + $tracking->url = utf8_encode($oVersand->getLogistikURL()); + $tracking->code = utf8_encode($oVersand->getIdentCode()); $options['tracking'] = $tracking; } } From e7acaccfc332766c11173ee7aca6da102a2f2704 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Mon, 11 Jan 2021 10:48:32 +0100 Subject: [PATCH 168/280] fix #115 --- version/111/class/Mollie.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/version/111/class/Mollie.php b/version/111/class/Mollie.php index e7e0d9b..b402f2e 100644 --- a/version/111/class/Mollie.php +++ b/version/111/class/Mollie.php @@ -83,10 +83,12 @@ public static function getShipmentOptions(Order $order, $kBestellung, $newStatus /** @var \Versand $oVersand */ $oVersand = $oBestellung->oLieferschein_arr[$nLS]->oVersand_arr[$nV]; $tracking = new stdClass(); - $tracking->carrier = utf8_encode($oVersand->getLogistik()); - $tracking->url = utf8_encode($oVersand->getLogistikURL()); - $tracking->code = utf8_encode($oVersand->getIdentCode()); - $options['tracking'] = $tracking; + $tracking->carrier = utf8_encode(trim($oVersand->getLogistik())); + $tracking->url = utf8_encode(trim($oVersand->getLogistikURL())); + $tracking->code = utf8_encode(trim($oVersand->getIdentCode())); + if ($tracking->code && $tracking->carrier) { + $options['tracking'] = $tracking; + } } } } From 5aa397d526fcc5f85dbe867526b8211f1fd4b187 Mon Sep 17 00:00:00 2001 From: "dash.bar" Date: Mon, 11 Jan 2021 11:22:18 +0100 Subject: [PATCH 169/280] prepare finalize --- info.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/info.xml b/info.xml index 33a72e4..bb84101 100644 --- a/info.xml +++ b/info.xml @@ -44,7 +44,7 @@ 2020-11-19 - 2020-11-19 + 2021-01-11 131_globalinclude.php From 4bf74a43040ca4df82bd650addc75887441516c9 Mon Sep 17 00:00:00 2001 From: "dash.bar" Date: Mon, 11 Jan 2021 11:22:19 +0100 Subject: [PATCH 170/280] init version 112 --- info.xml | 3 + version/112/adminmenu/info.php | 64 ++ version/112/adminmenu/orders.php | 236 +++++ version/112/adminmenu/paymentmethods.php | 97 +++ version/112/adminmenu/tpl/info.tpl | 114 +++ .../tpl/mollie-account-erstellen.png | Bin 0 -> 38998 bytes version/112/adminmenu/tpl/order.tpl | 281 ++++++ version/112/adminmenu/tpl/orders.tpl | 132 +++ version/112/adminmenu/tpl/paymentmethods.tpl | 127 +++ version/112/class/ExclusiveLock.php | 67 ++ version/112/class/Helper.php | 352 ++++++++ version/112/class/Model/AbstractModel.php | 7 + version/112/class/Model/Payment.php | 84 ++ version/112/class/Mollie.php | 566 ++++++++++++ version/112/frontend/131_globalinclude.php | 120 +++ version/112/frontend/140_smarty.php | 78 ++ version/112/frontend/144_notify.php | 63 ++ version/112/frontend/181_sync.php | 43 + version/112/frontend/img/trust_eng.png | Bin 0 -> 15299 bytes version/112/frontend/img/trust_fre.png | Bin 0 -> 17319 bytes version/112/frontend/img/trust_ger.png | Bin 0 -> 15352 bytes version/112/paymentmethod/JTLMollie.php | 806 ++++++++++++++++++ .../112/paymentmethod/JTLMollieApplePay.php | 8 + .../112/paymentmethod/JTLMollieBancontact.php | 8 + .../paymentmethod/JTLMollieBanktransfer.php | 10 + .../112/paymentmethod/JTLMollieBelfius.php | 8 + .../112/paymentmethod/JTLMollieCreditCard.php | 47 + .../paymentmethod/JTLMollieDirectDebit.php | 8 + version/112/paymentmethod/JTLMollieEPS.php | 8 + .../112/paymentmethod/JTLMollieGiftcard.php | 8 + .../112/paymentmethod/JTLMollieGiropay.php | 8 + version/112/paymentmethod/JTLMollieIDEAL.php | 8 + .../112/paymentmethod/JTLMollieINGHomePay.php | 8 + version/112/paymentmethod/JTLMollieKBC.php | 8 + .../paymentmethod/JTLMollieKlarnaPayLater.php | 10 + .../paymentmethod/JTLMollieKlarnaSliceIt.php | 10 + version/112/paymentmethod/JTLMollieMyBank.php | 8 + version/112/paymentmethod/JTLMolliePayPal.php | 8 + .../paymentmethod/JTLMolliePaysafecard.php | 8 + .../112/paymentmethod/JTLMolliePrzelewy24.php | 8 + version/112/paymentmethod/JTLMollieSofort.php | 8 + .../img/method/Przelewy24@2x.png | Bin 0 -> 859 bytes .../paymentmethod/img/method/applepay@2x.png | Bin 0 -> 656 bytes .../img/method/bancontact@2x.png | Bin 0 -> 582 bytes .../img/method/banktransfer@2x.png | Bin 0 -> 801 bytes .../paymentmethod/img/method/belfius@2x.png | Bin 0 -> 377 bytes .../img/method/creditcard@2x.png | Bin 0 -> 3125 bytes .../img/method/directdebit@2x.png | Bin 0 -> 801 bytes .../112/paymentmethod/img/method/eps@2x.png | Bin 0 -> 536 bytes .../paymentmethod/img/method/giftcard@2x.png | Bin 0 -> 2218 bytes .../paymentmethod/img/method/giropay@2x.png | Bin 0 -> 602 bytes .../112/paymentmethod/img/method/ideal@2x.png | Bin 0 -> 845 bytes .../img/method/inghomepay@2x.png | Bin 0 -> 1118 bytes .../112/paymentmethod/img/method/kbc@2x.png | Bin 0 -> 799 bytes .../paymentmethod/img/method/klarna@2x.png | Bin 0 -> 896 bytes .../paymentmethod/img/method/mollie@2x.png | Bin 0 -> 5366 bytes .../paymentmethod/img/method/mybank@2x.png | Bin 0 -> 2111 bytes .../paymentmethod/img/method/paypal@2x.png | Bin 0 -> 626 bytes .../img/method/paysafecard@2x.png | Bin 0 -> 420 bytes .../paymentmethod/img/method/sofort@2x.png | Bin 0 -> 453 bytes .../paymentmethod/tpl/bestellabschluss.tpl | 5 + .../paymentmethod/tpl/mollieComponents.tpl | 127 +++ version/112/sql/109.sql | 2 + version/112/tpl/_alerts.tpl | 10 + 64 files changed, 3581 insertions(+) create mode 100644 version/112/adminmenu/info.php create mode 100644 version/112/adminmenu/orders.php create mode 100644 version/112/adminmenu/paymentmethods.php create mode 100644 version/112/adminmenu/tpl/info.tpl create mode 100644 version/112/adminmenu/tpl/mollie-account-erstellen.png create mode 100644 version/112/adminmenu/tpl/order.tpl create mode 100644 version/112/adminmenu/tpl/orders.tpl create mode 100644 version/112/adminmenu/tpl/paymentmethods.tpl create mode 100644 version/112/class/ExclusiveLock.php create mode 100644 version/112/class/Helper.php create mode 100644 version/112/class/Model/AbstractModel.php create mode 100644 version/112/class/Model/Payment.php create mode 100644 version/112/class/Mollie.php create mode 100644 version/112/frontend/131_globalinclude.php create mode 100644 version/112/frontend/140_smarty.php create mode 100644 version/112/frontend/144_notify.php create mode 100644 version/112/frontend/181_sync.php create mode 100644 version/112/frontend/img/trust_eng.png create mode 100644 version/112/frontend/img/trust_fre.png create mode 100644 version/112/frontend/img/trust_ger.png create mode 100644 version/112/paymentmethod/JTLMollie.php create mode 100644 version/112/paymentmethod/JTLMollieApplePay.php create mode 100644 version/112/paymentmethod/JTLMollieBancontact.php create mode 100644 version/112/paymentmethod/JTLMollieBanktransfer.php create mode 100644 version/112/paymentmethod/JTLMollieBelfius.php create mode 100644 version/112/paymentmethod/JTLMollieCreditCard.php create mode 100644 version/112/paymentmethod/JTLMollieDirectDebit.php create mode 100644 version/112/paymentmethod/JTLMollieEPS.php create mode 100644 version/112/paymentmethod/JTLMollieGiftcard.php create mode 100644 version/112/paymentmethod/JTLMollieGiropay.php create mode 100644 version/112/paymentmethod/JTLMollieIDEAL.php create mode 100644 version/112/paymentmethod/JTLMollieINGHomePay.php create mode 100644 version/112/paymentmethod/JTLMollieKBC.php create mode 100644 version/112/paymentmethod/JTLMollieKlarnaPayLater.php create mode 100644 version/112/paymentmethod/JTLMollieKlarnaSliceIt.php create mode 100644 version/112/paymentmethod/JTLMollieMyBank.php create mode 100644 version/112/paymentmethod/JTLMolliePayPal.php create mode 100644 version/112/paymentmethod/JTLMolliePaysafecard.php create mode 100644 version/112/paymentmethod/JTLMolliePrzelewy24.php create mode 100644 version/112/paymentmethod/JTLMollieSofort.php create mode 100644 version/112/paymentmethod/img/method/Przelewy24@2x.png create mode 100644 version/112/paymentmethod/img/method/applepay@2x.png create mode 100644 version/112/paymentmethod/img/method/bancontact@2x.png create mode 100644 version/112/paymentmethod/img/method/banktransfer@2x.png create mode 100644 version/112/paymentmethod/img/method/belfius@2x.png create mode 100644 version/112/paymentmethod/img/method/creditcard@2x.png create mode 100644 version/112/paymentmethod/img/method/directdebit@2x.png create mode 100644 version/112/paymentmethod/img/method/eps@2x.png create mode 100644 version/112/paymentmethod/img/method/giftcard@2x.png create mode 100644 version/112/paymentmethod/img/method/giropay@2x.png create mode 100644 version/112/paymentmethod/img/method/ideal@2x.png create mode 100644 version/112/paymentmethod/img/method/inghomepay@2x.png create mode 100644 version/112/paymentmethod/img/method/kbc@2x.png create mode 100644 version/112/paymentmethod/img/method/klarna@2x.png create mode 100644 version/112/paymentmethod/img/method/mollie@2x.png create mode 100644 version/112/paymentmethod/img/method/mybank@2x.png create mode 100644 version/112/paymentmethod/img/method/paypal@2x.png create mode 100644 version/112/paymentmethod/img/method/paysafecard@2x.png create mode 100644 version/112/paymentmethod/img/method/sofort@2x.png create mode 100644 version/112/paymentmethod/tpl/bestellabschluss.tpl create mode 100644 version/112/paymentmethod/tpl/mollieComponents.tpl create mode 100644 version/112/sql/109.sql create mode 100644 version/112/tpl/_alerts.tpl diff --git a/info.xml b/info.xml index bb84101..1e35b8a 100644 --- a/info.xml +++ b/info.xml @@ -46,6 +46,9 @@ 2021-01-11 + + 2021-01-11 + 131_globalinclude.php 144_notify.php diff --git a/version/112/adminmenu/info.php b/version/112/adminmenu/info.php new file mode 100644 index 0000000..817c5db --- /dev/null +++ b/version/112/adminmenu/info.php @@ -0,0 +1,64 @@ +assign('defaultTabbertab', Helper::getAdminmenu('Info') + Helper::getAdminmenu('Support')); + 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 "
" . + "
" . + " " . + " Lizenz Informationen" . + ' ' . + '
' . + "
" . + " " . + " Update Informationen" . + ' ' . + '
' . + "
" . + " " . + " Plugin informationen" . + ' ' . + '
' . + '
'; + + 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/112/adminmenu/orders.php b/version/112/adminmenu/orders.php new file mode 100644 index 0000000..f5bfc25 --- /dev/null +++ b/version/112/adminmenu/orders.php @@ -0,0 +1,236 @@ +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/112/adminmenu/paymentmethods.php b/version/112/adminmenu/paymentmethods.php new file mode 100644 index 0000000..df3bace --- /dev/null +++ b/version/112/adminmenu/paymentmethods.php @@ -0,0 +1,97 @@ +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'; + } + } + + $allMethods = []; + if ($active) { + $_allMethods = $mollie->methods->allActive($params); + } else { + $_allMethods = $mollie->methods->allAvailable($params); + } + + $sessionLife = (int)ini_get('session.gc_maxlifetime'); + + /** @var \Mollie\Api\Resources\Method $method */ + foreach ($_allMethods as $method) { + + $id = $method->id === 'creditcard' ? 'kreditkarte' : $method->id; + $key = "kPlugin_{$oPlugin->kPlugin}_mollie{$id}"; + + $class = null; + $shop = null; + $oClass = null; + + if (array_key_exists($key, $oPlugin->oPluginZahlungsKlasseAssoc_arr)) { + $class = $oPlugin->oPluginZahlungsKlasseAssoc_arr[$key]; + include_once($oPlugin->cPluginPfad . 'paymentmethod/' . $class->cClassPfad); + /** @var JTLMollie $oClass */ + $oClass = new $class->cClassName($id); + } + if (array_key_exists($key, $oPlugin->oPluginZahlungsmethodeAssoc_arr)) { + $shop = $oPlugin->oPluginZahlungsmethodeAssoc_arr[$key]; + } + + + $maxExpiryDays = $oClass ? $oClass->getExpiryDays() : null; + $allMethods[$method->id] = (object)[ + 'mollie' => $method, + 'class' => $class, + 'oClass' => $oClass, + 'shop' => $shop, + 'maxExpiryDays' => $oClass ? $maxExpiryDays : null, + 'warning' => $oClass && ($maxExpiryDays * 24 * 60 * 60) > $sessionLife, + 'session' => round($sessionLife / 60 / 60, 2) . 'h' + ]; + + } + + 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/112/adminmenu/tpl/info.tpl b/version/112/adminmenu/tpl/info.tpl new file mode 100644 index 0000000..2952fc6 --- /dev/null +++ b/version/112/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}
+
+
+
Changelog:
+
+ +
+
+ +
+
+ +
+
+
+ {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/112/adminmenu/tpl/mollie-account-erstellen.png b/version/112/adminmenu/tpl/mollie-account-erstellen.png new file mode 100644 index 0000000000000000000000000000000000000000..fc1819255ef725fa214cf2bf028cf3428794ecee GIT binary patch literal 38998 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 +

+ « + 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

+ + + + + + + + + + + + + + {foreach from=$order->payments() item=payment} + + + + + + + + + + + {/foreach} +
IDStatusMethodeAmountSettlementRefundedRemainingDetails
{$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} +
+
+{/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} +
+ + + + + + + + + + + + + + + + + + {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} + + + + + + + + + + + + + {/foreach} + + + + + + + + + + +
StatusSKUNameTypAnzahlMwStSteuerNettoBrutto 
+ {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*} +
{$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} + + + + + + + {/foreach} +
+ {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}
+ + diff --git a/version/112/adminmenu/tpl/orders.tpl b/version/112/adminmenu/tpl/orders.tpl new file mode 100644 index 0000000..669015a --- /dev/null +++ b/version/112/adminmenu/tpl/orders.tpl @@ -0,0 +1,132 @@ +{ws_mollie\Helper::showAlerts('orders')} + +{if $hasAPIKey == false} + + Jetzt kostenlos Mollie Account eröffnen! + +{else} + + + + + + + + + + + + + + + + {foreach from=$payments item=payment} + + + + + + + + + + + + {/foreach} + +
BestellNr.IDMollie StatusJTL StatusBetragWährungLocaleMethodeErstellt
+ {$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)}
+ {if $payments|count > 900} +
Hier werden nur die letzten 1000 Ergebnisse angezeigt.
+ {/if} + + +
+
+

Export:

+
+ +
+ + + + + +
+
+ +{/if} + diff --git a/version/112/adminmenu/tpl/paymentmethods.tpl b/version/112/adminmenu/tpl/paymentmethods.tpl new file mode 100644 index 0000000..79ecd3b --- /dev/null +++ b/version/112/adminmenu/tpl/paymentmethods.tpl @@ -0,0 +1,127 @@ +

Account Status

+ + + + + + + {if $profile->review} + + + {/if} + +
Mode:{$profile->mode}Status:{$profile->status}Review:{$profile->review->status}
+ +
+ +
+
+ + +
+ + + +
+
+ + +
+
+ + +
+
+ + + reset +
+
+
+ + +{if $allMethods && $allMethods|count} + + + + + + + + + + + + {foreach from=$allMethods item=method} + + + + + + + + {/foreach} + +
BildName / IDInfoPreiseLimits
{$method->mollie->description|utf8_decode} + {$method->mollie->description|utf8_decode}
+ {$method->mollie->id} +
+ {if $method->shop && $method->oClass} + {if $method->shop->nWaehrendBestellung} + Zahlung + VOR + Bestellabschluss + {if $method->warning} +
+ + + Gültigkeit ist länger als Session-Laufzeit ({$method->session}). + + {/if} + {else} + Zahlung + NACH + Bestellabschluss + {/if} +
+ Gültigkeit + : {$method->maxExpiryDays} Tage + + {else} + Derzeit nicht unterstützt. + {/if} +
+
    + {foreach from=$method->mollie->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->mollie->minimumAmount}{$method->mollie->minimumAmount->value} {$method->mollie->minimumAmount->currency}{else}n/a{/if} +
+ Max: {if $method->mollie->maximumAmount}{$method->mollie->maximumAmount->value} {$method->mollie->maximumAmount->currency}{else}n/a{/if} +
+{else} +
Es konnten keine Methoden abgerufen werden.
+{/if} \ No newline at end of file diff --git a/version/112/class/ExclusiveLock.php b/version/112/class/ExclusiveLock.php new file mode 100644 index 0000000..f182605 --- /dev/null +++ b/version/112/class/ExclusiveLock.php @@ -0,0 +1,67 @@ +key = $key; + $this->path = rtrim(realpath($path), '/') . '/'; + if (!is_dir($path) || !is_writable($path)) { + throw new \RuntimeException("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 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 + } + + 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 + } +} diff --git a/version/112/class/Helper.php b/version/112/class/Helper.php new file mode 100644 index 0000000..5f2a8be --- /dev/null +++ b/version/112/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/112/class/Model/AbstractModel.php b/version/112/class/Model/AbstractModel.php new file mode 100644 index 0000000..5638700 --- /dev/null +++ b/version/112/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/112/class/Mollie.php b/version/112/class/Mollie.php new file mode 100644 index 0000000..b402f2e --- /dev/null +++ b/version/112/class/Mollie.php @@ -0,0 +1,566 @@ +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 = (int)$oBestellung->cStatus; + } + $options = []; + + // Tracking Data + if (isset($oBestellung->oLieferschein_arr)) { + $nLS = count($oBestellung->oLieferschein_arr) - 1; + if ($nLS >= 0 && isset($oBestellung->oLieferschein_arr[$nLS]) && isset($oBestellung->oLieferschein_arr[$nLS]->oVersand_arr)) { + $nV = count($oBestellung->oLieferschein_arr[$nLS]->oVersand_arr) - 1; + if ($nV >= 0 && isset($oBestellung->oLieferschein_arr[$nLS]->oVersand_arr[$nV])) { + /** @var \Versand $oVersand */ + $oVersand = $oBestellung->oLieferschein_arr[$nLS]->oVersand_arr[$nV]; + $tracking = new stdClass(); + $tracking->carrier = utf8_encode(trim($oVersand->getLogistik())); + $tracking->url = utf8_encode(trim($oVersand->getLogistikURL())); + $tracking->code = utf8_encode(trim($oVersand->getIdentCode())); + if ($tracking->code && $tracking->carrier) { + $options['tracking'] = $tracking; + } + } + } + } + + $logData = '#' . $oBestellung->kBestellung . '§' . $oBestellung->cBestellNr . '$' . $order->id; + + switch ($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/112/frontend/131_globalinclude.php b/version/112/frontend/131_globalinclude.php new file mode 100644 index 0000000..5778e21 --- /dev/null +++ b/version/112/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/112/frontend/140_smarty.php b/version/112/frontend/140_smarty.php new file mode 100644 index 0000000..ac119c6 --- /dev/null +++ b/version/112/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/112/frontend/144_notify.php b/version/112/frontend/144_notify.php new file mode 100644 index 0000000..d1826a4 --- /dev/null +++ b/version/112/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/112/frontend/181_sync.php b/version/112/frontend/181_sync.php new file mode 100644 index 0000000..86c610c --- /dev/null +++ b/version/112/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/112/frontend/img/trust_eng.png b/version/112/frontend/img/trust_eng.png new file mode 100644 index 0000000000000000000000000000000000000000..3d0177359de7fa93833765ac05d8b218fa1550f2 GIT binary patch literal 15299 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 Rmns)TMnX}%M${5 literal 0 HcmV?d00001 diff --git a/version/112/frontend/img/trust_fre.png b/version/112/frontend/img/trust_fre.png new file mode 100644 index 0000000000000000000000000000000000000000..ed1a2f6f03c56f6748aac8af0352de7fc0afd3a4 GIT binary patch literal 17319 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 Mu#8ZJpsxS_1AJc%;s5{u literal 0 HcmV?d00001 diff --git a/version/112/frontend/img/trust_ger.png b/version/112/frontend/img/trust_ger.png new file mode 100644 index 0000000000000000000000000000000000000000..e42821b06709e8f4371c66cfb5759d00df0e1afd GIT binary patch literal 15352 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 = "kPlugin_" . Helper::oPlugin()->kPlugin . "_mollie{$moduleID}"; + } + + /** + * @return Helper + */ + public static function Helper() + { + if (self::$_helper === null) { + self::$_helper = new ws_mollie\Helper(); + } + return self::$_helper; + } + + /** + * @param Bestellung $order + * @param Object $payment (Key, Zahlungsanbieter, Abgeholt, Zeit is set here) + * @return $this + * @throws Exception + */ + public function addIncomingPayment($order, $payment) + { + $model = (object)array_merge([ + 'kBestellung' => (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; + + $_SESSION['MOLLIE_CHECKBOXES'] = []; + foreach ($_POST as $key => $value) { + if (strpos($key, 'CheckBox_') !== false) { + $_SESSION['MOLLIE_CHECKBOXES'][$key] = $value; + } + } + + + 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 && $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; + unset($_SESSION['mollieCardToken'], $_SESSION['mollieCardTokenTS']); + } 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); + $expiryDays = $this->getExpiryDays(); + $_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, '_')), + 'expiresAt' => date('Y-m-d', strtotime("+{$expiryDays} DAYS")) + ]; + + if (static::MOLLIE_METHOD !== '') { + $data['method'] = static::MOLLIE_METHOD; + } + + if (static::MOLLIE_METHOD === \Mollie\Api\Types\PaymentMethod::CREDITCARD + && array_key_exists('mollieCardToken', $_SESSION) + && array_key_exists('mollieCardTokenTS', $_SESSION) && time() < (int)$_SESSION['mollieCardTokenTS']) { + $data['payment'] = new stdClass(); + $data['payment']->cardToken = trim($_SESSION['mollieCardToken']); + } else { + unset($_SESSION['mollieCardToken'], $_SESSION['mollieCardTokenTS']); + } + + 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 .= utf8_encode(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"; + } + } + + /** + * @return int + */ + public function getExpiryDays() + { + $max = static::MAX_EXPIRY_DAYS; + $global = (int)Helper::getSetting('expiryDays'); + $local = (int)Helper::oPlugin()->oPluginEinstellungAssoc_arr[$this->cModulId . '_expiryDays']; + + return (int)min($local > 0 ? $local : $global, $global, $max); + } + + 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) + { + if (array_key_exists('MOLLIE_CHECKBOXES', $_SESSION) && is_array($_SESSION['MOLLIE_CHECKBOXES'])) { + $_POST = array_merge($_POST, $_SESSION['MOLLIE_CHECKBOXES']); + } + $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/112/paymentmethod/JTLMollieApplePay.php b/version/112/paymentmethod/JTLMollieApplePay.php new file mode 100644 index 0000000..ecf20a8 --- /dev/null +++ b/version/112/paymentmethod/JTLMollieApplePay.php @@ -0,0 +1,8 @@ + time() + && array_key_exists('mollieCardToken', $_SESSION) && trim($_SESSION['mollieCardToken']) !== '') { + return true; + } + + unset($_SESSION['mollieCardToken'], $_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('skipComponents', Helper::getSetting('skipComponents')) + ->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/112/paymentmethod/JTLMollieDirectDebit.php b/version/112/paymentmethod/JTLMollieDirectDebit.php new file mode 100644 index 0000000..ce0441d --- /dev/null +++ b/version/112/paymentmethod/JTLMollieDirectDebit.php @@ -0,0 +1,8 @@ +OH(NI>=T42<+x9g>;*Gy9DrKtJl=F((p(~XhRMojR(!TROq)4##x zi;wfn&C+>%^UTiFKSt7JYSXp1>ZPgDP*&5InbUcF<%^K^*xKlsoYHP{(wCajZ*$Ra zbJNPo(OY2BWNFmE!S~qO{POeCTVT|{z|(GX;Bt54e}mdsUi8b(sL>`X0000JbW%=J z01%HLkU-Cn-_OsV&!6AlpP5D4UE1#Sax&aZg(%L>z8x33MOZZ8H?WJ;;n51dMe)(}9UH1j29 ze@0RGfq`^s0!X#X7!_srsUP@btltZoyHfrIVq@*+2f)Ge+&BuBcbdrjKu5}NuE;){Yi3#o7gOK=v6Y0{rAbqNgQSz}}0I~5?ej{GsP%?vN z=_l4!?VPOmM>R@!2oOAkd1t|Pb#@H>-d=$PnbBs7=u%Z>9N;0iml z2#guk2rk-V%mMEvxQCZ1@+-_*(mao=fPWKs%h@Mp0)~gcfgO7j{4M(n<{@x^Z^Hk! ze1;0X32xx)(NPC3aetZbtnBss>W2NT-v%Bch%He^5RXIyLDWRp5;o{lcPr>qmkRZj lpHDtfd;A2~X0zTP_aA;i{an>LN7rz#m}I!{TEUogY_hW!fX z1?mg>C*-erx%(so1LG!77srr_xVP7C<}EQ0XbW_HZ(Bb#ysRpA(wRN~nf+#OlTe%( zXkfncL^KKCCrg-Lh=kEnU|a;ZB9QaR>Td+?i96wEUURmd^*;_;}q*?JtCN zs9v0_oUIYrJ>{ItUF)Suj=nY*E;y-_bg}zQ;ZT|@FU4Qeut^B)WfWUjV9g-3v@K+f-ik;kV{MOr_6wK;GGik>mTp$V%-RtP)+CPEi`n!UgTe~DWM4fFWeR( literal 0 HcmV?d00001 diff --git a/version/112/paymentmethod/img/method/bancontact@2x.png b/version/112/paymentmethod/img/method/bancontact@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..a87af77d20330ab4ee197fd750d0bd39a5b10f90 GIT binary patch literal 582 zcmV-M0=fN(P)lk!lq%lq?@9+Qr z|M>X$=jZ1jWQqR%{`vX&|JVTk=U{-T&j0$~pTFAg&hoWPVjpU$|LlN(mQMfcfPbmZpr$+j>2Uw#P;ZV{AZe)(UZem0@6X@u|MkEB z;XwWU{r~1*Ky`MXzS=N!uW*i8kF?YfT$A7F^MIC5pQk%!Gip%)000nlQchC<&w%eB zkRX4bpb&7+Z;x=Vl85vF00AONL_t(|UhS6GZp0uI1+V+IBnNQY-qL&T?f<_j%Vs4k zWi4ZPi#+c$LIR;fk}z^m8)w(24LdL-qBSjmiImqQ6%1%eKSC_H5hBJOQ3wcbh=A9j z0E`>M;F1Gj9uRN{NX-L}@Ce`*0RKJE1nw{TTbXGF`gs|rT7l!dln0%_EVm0RbGyKB zqJ*zRaiSTxE%@_=;_x?lSs8dz{y6#LPln}z>8GT40dLB`KB#<1qlM(E;D0OsM*0?TeIhg`dn6;Q{6Fh2l%qOS4K%wo8-q7AUD{?yGF(55vm4C&H_FzBH+J=d4+57}kr Up-!czfB*mh07*qoM6N<$g3OCHTL1t6 literal 0 HcmV?d00001 diff --git a/version/112/paymentmethod/img/method/banktransfer@2x.png b/version/112/paymentmethod/img/method/banktransfer@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..c70206bef4893f23fcd59d436273108d2f2eebc7 GIT binary patch literal 801 zcmV++1K#|JP)lk!lq*=;-9+mkX z{{U2_ztrjP@9%)A(*D5?-|6)J(MtZwET6yKpugSt`1lZBsz86cAZf7q`T3Bv*Z%(g z-|F=K#U1|5JO0^dAZoDx_u=pL`RC{7_xJZ;l*j-3@c!I)@AdkSwAlXDS^mf@aG%W2 z;O`J$tN-Md>+9=KiNUYR<6xA=@AUcq@WXGP%>DiS|LnB>%sc+*q+gWBFm$#4l$oJ=bMJL) zN$}UM z^EEI7D0q#*=`w@Mb&#yX6$WP@x&}s<8JvJ@pvqecQO^sez9^Xbs$t>(|Nn0Y_`k@X z`u+Uv`wm6F?mz#2{?4!aFGTBV&I9cbE(!7rW)PTg{{H;_^9ubA3J&Kd+&@2If#l5V zkwEFKo-U3d6>)E`o#Z>Lz~g$+{n^fDUKQE@|Mgd!a9=T#&e{4(sr-HO1o4KQ>uv;= zWX2_)yrQzk;QY@iN0x35n7oK-g-2+63_H(@QU|u6Z>|Z!r6lZ1zes9a?+x$E9%YhzX@O1Ta JS?83{1OT9Jm%RW0 literal 0 HcmV?d00001 diff --git a/version/112/paymentmethod/img/method/creditcard@2x.png b/version/112/paymentmethod/img/method/creditcard@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..b08be792753326b65345c752a6f350182a9393d2 GIT binary patch literal 3125 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 P00000NkvXXu0mjf3Vis# literal 0 HcmV?d00001 diff --git a/version/112/paymentmethod/img/method/directdebit@2x.png b/version/112/paymentmethod/img/method/directdebit@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..514ff845b84d38cd8eb97b9e2c53e5c117967944 GIT binary patch literal 801 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 literal 0 HcmV?d00001 diff --git a/version/112/paymentmethod/img/method/giropay@2x.png b/version/112/paymentmethod/img/method/giropay@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..b787e1fee50c9bcca112f734ef4bcbd4ecfb6d6b GIT binary patch literal 602 zcmV-g0;T5Kx~EOrH!)pASu;4ojd8OQ8=; zpbt!;!_w#B>GK{}r)iJG@bvggdAR@o{+6-TrM%mCn#w$GvMpk*ho#Tb-RaC5+y)hho537JnGBqPA~G@Ik#rt1jWCNmt_X5yY-;OM4Sm|;L0fCz(H!a59C z!6FQJ1`O=K0(U?&WmHmQ%ovl1g=xY%=0>sX7T{!DDr3#1AfT>{>*NQdp;XxeDnn^6 z;Fg|~18)oh=#B%J574HG=ZK=b0(2)=ZWs@6u|Psp2S`Ms-aSCKNc4dZ3ml0Y1JpF0 zACT7(WFOdH$J={=+}Kh?t@=QTh`Y)S;{lL4q2$K&0aK;&(@GqDK&DI^R~^tLy#OA$ z1Nay30gQkc{Q&0jzz(SpmbnlhVhfzVhaBhB0($}wh1S_^$N7}lg}e4p3Ic|F4;Z~b zTY@72isxg1#8BrSfnxv^S{6kiGl4E$H2v|f@*S9m0aJJk172Vm21F3Hg)IO)g#GGT oVe}rh6KIQG--ZM8)e@S10aM=ZI#^TblmGw#07*qoM6N<$f@FIOx&QzG literal 0 HcmV?d00001 diff --git a/version/112/paymentmethod/img/method/ideal@2x.png b/version/112/paymentmethod/img/method/ideal@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..efc4315a96a6b2d9b160578a65fe52206783f2ca GIT binary patch literal 845 zcmV-T1G4;yP)lk!ZZ65OMGC?}UYf;o;!m;NZf-!qXsn`1tsvqob6RlsGvz=jZ45_xJw({`vX& z+CYuwfU@xL?-Nv%`QPmApT=fqW&i*F(b3WK zzuD%1v(zAZ>+9>Xv$F87&$F|$@bK^%8W`-K#nT^p^1s=^!okAA!Tj&_DJdxZ{r%~X zz3Gp=&=7F!pvK@}pYN~F>5#mWl#|_1mb0_6g@uIHFobn>b?J}1M@UB*8yIC~W#VwE zc6N2$P?z9fpjKB^=ker~0000HbW%=J0PlbhkiUP=Adhe$&v1`#zea&7rvLx}*GWV{ zRCr#^*2j+9Fc5%YO7?ntl9{1;aqqou@0;Fxd;j;y*jNN`HV2Bl>~|3_{4oLqkzy%V z*t96C%}2Z9&SQ)86vWClksDVqqe|=&Z3|YQQjA*4CE6Eai>Qp6VzP3=CKt6Gk}WnU zMr|=|2#YGH?I~G;2n`TD#K5)puk^^z67b+ZZd-naz)7$!d_QRdc|mw#b1~<{2k2)FEaYF&OT-`GX$RPM#Nt`QAi#wXJk>zhFTO>59`Wo^#}<>sMjOed(+{-3ru0A7D$0jI558$ z)N0PF!RsCe2|{A+{jU4@5&uc>v9T(>X>= zpc$wJPDAG6XudKWan^4w_bUdHVBPG<>jQiVOn&QMzg?RgEbW=`(e{u7#up5;D^8W3 z2%8R3n@hIHS^6WCiFSq9p;8&OR7*Sn%M-cP>{s2YOOzKYHtDf;#GS4DUiRI4c22NA XzpeJ7+7%dW00000NkvXXu0mjfybi$$ literal 0 HcmV?d00001 diff --git a/version/112/paymentmethod/img/method/inghomepay@2x.png b/version/112/paymentmethod/img/method/inghomepay@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..538f219588886db215757eafd5c5151241f18b5a GIT binary patch literal 1118 zcmV-k1flzhP)`_0RK|}|55<|Q2_r?0RL0~|5E_}r-1)w9RKX&|5E_}=Gy;L z0RR90|6UOPlVJbp-~WC<|J1+#zn}l9fd6P9|A|olb1?tk&;RxB|Mc(wo^bzkF#pQ0 z|Fn<)>fisgkpF2Q|G%LBsek{okpG@<|H-fazM%hUAODC@|H-ibs(=5~!2gtB|K894 zs(@(VAMyYI01|XkPE!C7&ySx#AdugXK#$)bkdUC?LT6GX000A7Nkl+_F4;G0`t->#NE zT;V&r`f!+EySiCj<6V7Pt?{mYTH&4jj{)gM0TN(F3?6st+kjw6 z>LApXPB>Unt8V~;Cik9f49AhQ!$i7^fuL#4vW=&{86JR|lTsG~BRymzfEs|JX9J1K z03Dw$1C&G3WKK=%kB`J1r1*<~s2`z=k6T78&3xGOL&RV&0xXfJ0Ql@xfEn*A1CX9E zQ!WBD5?VbTK7XTsCp`U6crw}TsH%60W z2hoh@0nLYSxRBab{+9<3C+^Mz9xYb&ZxhMVDb+cqriY2<9AG-<8gN)^Cix5?)@kAU z;?6$;-SN`NKvD-cR@w%n?9AWi0I~xRElDnK5^Rh@FtDVHX8@ZJfJl->N&_A{l2bso z2x`kJr-3lmJ%9)DK@>~Q{7brt3fNKr^rbrq+|{-iAekxBG;uoyGqur4Ei0S?0=Yll zF_SR>W}x;7ttLalDFCI-OXsp?(S;*|rkk|uOcTs~fUR;0m?79z>!T@dSC<#zVpen3 zDj@L*GoMZY$tw7C*m%o|vLvel!qz~FMPzph=x6{KTjppdC7aC#VVdHg)$wl$bf*AC z1-Rnnz*LgVO4|B5HX#U@PXUn*;sq_sC5u*2fG7j7o&o~>%Wn3WWcg~#QmPptG|8+k2H7XW|=xVi9nUeg`1*I2IB*YJ(+JNL|VD24JQDXa_~} zqMBf8fF~Vbz5wvk*3xb81`yK5AZAEW$9)?Qt+BO>C3E@1Aktu4fz|6HW^Y;1@lk!lq%mkX z{~%3y0h-K!%;mq#+4%VQ5J7OCv&KMYjPLUG@9*#T_xE6cpCPBxaK_?)nX{kS?7!yn zfSI!2=Is9d{_pwx05oR#`T5`T`RC{7L9^Llzu!=FmQcCekkjew>+3LDf{>=XK(pDe zzt4c0vd`J#Fs;_V%-D~nykNlKAg9yc^7t^U)_~3BfX(J`#^Vv8&k>-{-}3p8(&?|? z?{JN&{r&x)v&FFA?=V_}aEz&7z~7M5=+D{X&+PS}+3awQs351(ptHqzpNxV4000qm zQchCIy&+X> z=*5Ul;OaQ@NK`Vzy8t_g2?_Jis)3C$i910Xw$PIU9&Uk!LpkskEkL9-LfkOWJAbaP zUroip18r(eg}^hN*BXg{sb1!Yfc6S#iGXvxN(6jb7x=sau0_D;#S-`?0_b=FJSG`H zPqbnfvWg$g}i**@5@#v5NT=$lzqSQdXDg|8f zIHlhJQN%Mfm~#2YP9b1YgB(!GAN!r?CIjA)sTANZfG||7{JhG5H)Vm3e?0>E>_vVi zq!;d4SOSQYxt#%m;F70Lx8o{r!Tt9&c8CI14(M}40nf9jzsNQAmkVA7gAM$Z|1+@m z0b{)*&IIp+jVE#-MjL9Dd6xv65#{P&<3u77*DDnbtf@m157r`vbG^_r?Ff8 d>Rr1A+%FMH_Q$8Zwr>Cc002ovPDHLkV1oT`waEYg literal 0 HcmV?d00001 diff --git a/version/112/paymentmethod/img/method/klarna@2x.png b/version/112/paymentmethod/img/method/klarna@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..e28a187b81e7c5a6256fea7382a643762746dd1e GIT binary patch literal 896 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 literal 0 HcmV?d00001 diff --git a/version/112/paymentmethod/img/method/paypal@2x.png b/version/112/paymentmethod/img/method/paypal@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..a816d7201f59ea7cef713f5e7895e66dcd6ee9a7 GIT binary patch literal 626 zcmV-&0*(ENP)zW{Q;0CK+oaK8X?zW{Q<0CB+pa=`#_!2of;na1S+alrro z|IFg@&*bxRu-m`e?~lRb-|hDbcETox$#AdRv()Q`yWm5X&|s$5P@dDD$>-eb_JFwG zpUUS$m(j@K@sPpeFpSLa_WMAU&p?#W{Qdsu^7&w=*MGR*^7#DO>Gd#+%P@?~P@U7S z((9ba=CIQ0sn6-_^!k0a-V=Mp)8_OXfyX(K&a%|&;_mkldc-e_%lZ5LgSp`#gUC6M z&erGk#LeN$0000GbW%=J0M8)rfN+qXfDoX6Z;yYFN6jxl0003wNklC4+MXiktqCYwRgSg6)KJbf z5Lj1?Y5+oU@|#dstX9C|0Ujt`J{M4b8Wr^cdi(ak0iFt>ORE}Nts8qh=FWCkI)}aEnE&{1?2hI?PIY68@ zbOdbw0PvXrf5i!Szy>sZ79ap>ye%)UHj^sMYbqagD6U zaJzaI>n$ypF23oVdS#o6|W|*DFT6j;X_Pjl^+{$7FxcM`F8{J!B6QqfZ6J=?T z0Z*i4z#}$g7~II(N7`*?T& O0000+D{~L?`zkmGy`PKgqj{m>0 z^Z&xI|35zdzp(26fxiDA9{<0v`v1;`{~L<_uT1&>;_Ck$4fn+3S%6jwlmz(&Gn{vr zARutRf5Q2Gh4~8e7rbanOaaP$^>lFzsfc?!?c};<10L727Z_ycPF(r9`v3o4QC^`f zNy*irThr_Lx8*f4F=sBE;Is9vL&{b+wWF_Q`cLpRlDMX^fZ@i14v}pdO3hrZ8V-u{ z6@GBmNPp@1=O;WPYJWl57EYgv)6tK(j<>!KX1Tkg-1yN7-6M=yr*jX!QWr1lo!e&; zepvX8JR>o1saCg`3ZOWgj;^L2z+zGho&3IENy|Lc5*g&izjA{*O9T;DjDIk7S9e6n)( p;e>?q6P^m(l+{vMe5&Mx9fO|m{vZE%WkG?%;OXk;vd$@?2>_eS)Oi2^ literal 0 HcmV?d00001 diff --git a/version/112/paymentmethod/tpl/bestellabschluss.tpl b/version/112/paymentmethod/tpl/bestellabschluss.tpl new file mode 100644 index 0000000..f7680f0 --- /dev/null +++ b/version/112/paymentmethod/tpl/bestellabschluss.tpl @@ -0,0 +1,5 @@ +{if isset($oMollieException)} +
+ {$oMollieException->getMessage()} +
+{/if} \ No newline at end of file diff --git a/version/112/paymentmethod/tpl/mollieComponents.tpl b/version/112/paymentmethod/tpl/mollieComponents.tpl new file mode 100644 index 0000000..024393d --- /dev/null +++ b/version/112/paymentmethod/tpl/mollieComponents.tpl @@ -0,0 +1,127 @@ +

{$mollieLang.cctitle}

+
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+ +
+
+ + +
+ +
+ {if $trustBadge} +
+ PCI-DSS SAQ-A compliant +
+ {/if} + {if $skipComponents == 'Y'} + + {/if} +
+ + + + + + + \ No newline at end of file diff --git a/version/112/sql/109.sql b/version/112/sql/109.sql new file mode 100644 index 0000000..41cda01 --- /dev/null +++ b/version/112/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/112/tpl/_alerts.tpl b/version/112/tpl/_alerts.tpl new file mode 100644 index 0000000..5279fa3 --- /dev/null +++ b/version/112/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} From 1be958977bd25a455af75b6d689ae824a6c3b195 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Mon, 11 Jan 2021 11:40:32 +0100 Subject: [PATCH 171/280] fix notice --- version/110/class/Mollie.php | 2 +- version/111/class/Mollie.php | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/version/110/class/Mollie.php b/version/110/class/Mollie.php index cc5a1fc..e2fd5f3 100644 --- a/version/110/class/Mollie.php +++ b/version/110/class/Mollie.php @@ -299,7 +299,7 @@ public static function handleOrder(Order $order, $kBestellung) $cHinweis = $mPayment->id; } - if ($mPayment->method === PaymentMethod::PAYPAL && isset($mPayment->details->paypalReference)) { + if ($mPayment->method === PaymentMethod::PAYPAL && isset($mPayment->details, $mPayment->details->paypalReference)) { $cHinweis = $mPayment->details->paypalReference; $oIncomingPayment->cZahler = isset($payment->details->paypalPayerId) ? $payment->details->paypalPayerId : ''; } diff --git a/version/111/class/Mollie.php b/version/111/class/Mollie.php index b402f2e..45f78f7 100644 --- a/version/111/class/Mollie.php +++ b/version/111/class/Mollie.php @@ -259,6 +259,9 @@ public static function handleOrder(Order $order, $kBestellung) ':mollieId1' => $mPayment->id, ':mollieId2' => $mPayment->id, ], 3); + }else{ + self::JTLMollie()->doLog('Mollie::handleOrder: kein Payment gefunden', $logData); + return false; } try { @@ -301,7 +304,7 @@ public static function handleOrder(Order $order, $kBestellung) $cHinweis = $mPayment->id; } - if ($mPayment->method === PaymentMethod::PAYPAL && isset($mPayment->details->paypalReference)) { + if ($mPayment->method === PaymentMethod::PAYPAL && isset($mPayment->details, $mPayment->details->paypalReference)) { $cHinweis = $mPayment->details->paypalReference; $oIncomingPayment->cZahler = isset($payment->details->paypalPayerId) ? $payment->details->paypalPayerId : ''; } From 22c60bd5c56a7f2b3a4adbbfdc558adf90fe63f8 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Mon, 11 Jan 2021 11:41:57 +0100 Subject: [PATCH 172/280] fix notice --- version/112/class/Mollie.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/version/112/class/Mollie.php b/version/112/class/Mollie.php index b402f2e..e1921c1 100644 --- a/version/112/class/Mollie.php +++ b/version/112/class/Mollie.php @@ -259,6 +259,9 @@ public static function handleOrder(Order $order, $kBestellung) ':mollieId1' => $mPayment->id, ':mollieId2' => $mPayment->id, ], 3); + } else { + self::JTLMollie()->doLog('Mollie::handleOrder: kein Payment gefunden', $logData); + return false; } try { @@ -301,8 +304,8 @@ public static function handleOrder(Order $order, $kBestellung) $cHinweis = $mPayment->id; } - if ($mPayment->method === PaymentMethod::PAYPAL && isset($mPayment->details->paypalReference)) { - $cHinweis = $mPayment->details->paypalReference; + if ($mPayment->method === PaymentMethod::PAYPAL && isset($mPayment->details, $mPayment->details->paypalReference)) { + $cHinweis = $mPayment->details->paypalReference; $oIncomingPayment->cZahler = isset($payment->details->paypalPayerId) ? $payment->details->paypalPayerId : ''; } From 276b8296c627ea5831f32efb2b2b99f036e260cb Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Wed, 7 Apr 2021 10:42:37 +0200 Subject: [PATCH 173/280] cs --- version/112/paymentmethod/JTLMollie.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/version/112/paymentmethod/JTLMollie.php b/version/112/paymentmethod/JTLMollie.php index eeb624d..4cb327c 100644 --- a/version/112/paymentmethod/JTLMollie.php +++ b/version/112/paymentmethod/JTLMollie.php @@ -687,6 +687,7 @@ public function canPayAgain() * * @return bool */ + public function isSelectable() { @@ -751,7 +752,13 @@ protected static function PossiblePaymentMethods($method, $locale, $billingCount { $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']); + 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) { From 50ce5a6f2587bdf7c0b5a5c53a4ca1e8ac60bfed Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Wed, 7 Apr 2021 18:12:36 +0200 Subject: [PATCH 174/280] init --- composer.json | 9 +- composer.lock | 743 ++++---- info.xml | 1634 +++++++++-------- version/112/class/API.php | 73 + .../112/class/Checkout/AbstractCheckout.php | 331 ++++ version/112/class/Checkout/Order/Address.php | 54 + .../112/class/Checkout/Order/OrderLine.php | 193 ++ version/112/class/Checkout/OrderCheckout.php | 210 +++ .../112/class/Checkout/Payment/Address.php | 65 + version/112/class/Checkout/Payment/Amount.php | 68 + version/112/class/Checkout/Payment/Locale.php | 44 + .../112/class/Checkout/PaymentCheckout.php | 111 ++ version/112/class/Hook/AbstractHook.php | 13 + version/112/class/Hook/ApplePay.php | 55 + version/112/class/Hook/Queue.php | 129 ++ version/112/class/Model/AbstractModel.php | 83 +- version/112/class/Model/Customer.php | 66 + version/112/class/Model/Payment.php | 53 + version/112/class/Model/Queue.php | 41 + version/112/class/Mollie.php | 5 + version/112/class/Queue.php | 65 + version/112/class/Traits/Jsonable.php | 20 + version/112/class/Traits/Plugin.php | 26 + version/112/class/Traits/RequestData.php | 55 + version/112/frontend/.htaccess | 9 + version/112/frontend/131_globalinclude.php | 216 +-- version/112/frontend/132_headPostGet.php | 17 + version/112/frontend/140_smarty.php | 114 +- version/112/frontend/144_notify.php | 63 - version/112/frontend/180_checkbox.php | 19 + version/112/frontend/181_sync.php | 33 +- version/112/frontend/210_storno.php | 17 + version/112/frontend/75_bestellungInDb.php | 17 + version/112/frontend/applepay.php | 18 + version/112/frontend/tpl/applepay.tpl | 17 + version/112/paymentmethod/JTLMollie.php | 757 ++++---- .../112/paymentmethod/JTLMollieApplePay.php | 9 +- .../112/paymentmethod/JTLMollieBancontact.php | 2 +- .../paymentmethod/JTLMollieBanktransfer.php | 17 +- .../112/paymentmethod/JTLMollieBelfius.php | 2 +- .../112/paymentmethod/JTLMollieCreditCard.php | 137 +- .../paymentmethod/JTLMollieDirectDebit.php | 11 +- version/112/paymentmethod/JTLMollieEPS.php | 2 +- .../112/paymentmethod/JTLMollieGiftcard.php | 2 +- .../112/paymentmethod/JTLMollieGiropay.php | 2 +- version/112/paymentmethod/JTLMollieIDEAL.php | 2 +- .../112/paymentmethod/JTLMollieINGHomePay.php | 21 +- version/112/paymentmethod/JTLMollieKBC.php | 7 +- .../paymentmethod/JTLMollieKlarnaPayLater.php | 2 +- .../paymentmethod/JTLMollieKlarnaSliceIt.php | 2 +- version/112/paymentmethod/JTLMollieMyBank.php | 2 +- version/112/paymentmethod/JTLMolliePayPal.php | 24 +- .../paymentmethod/JTLMolliePaysafecard.php | 7 +- .../112/paymentmethod/JTLMolliePrzelewy24.php | 9 +- version/112/paymentmethod/JTLMollieSofort.php | 2 +- .../paymentmethod/tpl/bestellabschluss.tpl | 16 +- version/112/sql/109.sql | 2 - version/112/sql/112.sql | 16 + 58 files changed, 4003 insertions(+), 1736 deletions(-) create mode 100644 version/112/class/API.php create mode 100644 version/112/class/Checkout/AbstractCheckout.php create mode 100644 version/112/class/Checkout/Order/Address.php create mode 100644 version/112/class/Checkout/Order/OrderLine.php create mode 100644 version/112/class/Checkout/OrderCheckout.php create mode 100644 version/112/class/Checkout/Payment/Address.php create mode 100644 version/112/class/Checkout/Payment/Amount.php create mode 100644 version/112/class/Checkout/Payment/Locale.php create mode 100644 version/112/class/Checkout/PaymentCheckout.php create mode 100644 version/112/class/Hook/AbstractHook.php create mode 100644 version/112/class/Hook/ApplePay.php create mode 100644 version/112/class/Hook/Queue.php create mode 100644 version/112/class/Model/Customer.php create mode 100644 version/112/class/Model/Queue.php create mode 100644 version/112/class/Queue.php create mode 100644 version/112/class/Traits/Jsonable.php create mode 100644 version/112/class/Traits/Plugin.php create mode 100644 version/112/class/Traits/RequestData.php create mode 100644 version/112/frontend/.htaccess create mode 100644 version/112/frontend/132_headPostGet.php delete mode 100644 version/112/frontend/144_notify.php create mode 100644 version/112/frontend/180_checkbox.php create mode 100644 version/112/frontend/210_storno.php create mode 100644 version/112/frontend/75_bestellungInDb.php create mode 100644 version/112/frontend/applepay.php create mode 100644 version/112/frontend/tpl/applepay.tpl delete mode 100644 version/112/sql/109.sql create mode 100644 version/112/sql/112.sql diff --git a/composer.json b/composer.json index 201560b..434acb9 100644 --- a/composer.json +++ b/composer.json @@ -3,8 +3,13 @@ "description": "mollie", "type": "project", "require": { - "roave/security-advisories": "dev-master", - "mollie/mollie-api-php": "^2.12.0" + "ext-json": "*", + "php": ">=5.6", + "mollie/mollie-api-php": "^v2.30.2" + } + , + "require-dev": { + "roave/security-advisories": "dev-latest" }, "license": "Proprietary", "authors": [ diff --git a/composer.lock b/composer.lock index 6073b23..187a444 100644 --- a/composer.lock +++ b/composer.lock @@ -4,20 +4,20 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "87704edab92c52e0357537f2ba85ebc5", + "content-hash": "b3222aabb4733c6c739d36dee243f4c2", "packages": [ { "name": "composer/ca-bundle", - "version": "1.2.8", + "version": "1.2.9", "source": { "type": "git", "url": "https://github.com/composer/ca-bundle.git", - "reference": "8a7ecad675253e4654ea05505233285377405215" + "reference": "78a0e288fdcebf92aa2318a8d3656168da6ac1a5" }, "dist": { "type": "zip", - "url": "https://github.com/gitapi/repos/composer/ca-bundle/zipball/8a7ecad675253e4654ea05505233285377405215", - "reference": "8a7ecad675253e4654ea05505233285377405215", + "url": "https://github.com/gitapi/repos/composer/ca-bundle/zipball/78a0e288fdcebf92aa2318a8d3656168da6ac1a5", + "reference": "78a0e288fdcebf92aa2318a8d3656168da6ac1a5", "shasum": "" }, "require": { @@ -26,14 +26,15 @@ "php": "^5.3.2 || ^7.0 || ^8.0" }, "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7 || 6.5 - 8", + "phpstan/phpstan": "^0.12.55", "psr/log": "^1.0", + "symfony/phpunit-bridge": "^4.2 || ^5", "symfony/process": "^2.5 || ^3.0 || ^4.0 || ^5.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.x-dev" + "dev-main": "1.x-dev" } }, "autoload": { @@ -74,7 +75,7 @@ "type": "tidelift" } ], - "time": "2020-08-23T12:54:47+00:00" + "time": "2021-01-12T12:10:35+00:00" }, { "name": "guzzlehttp/guzzle", @@ -145,16 +146,16 @@ }, { "name": "guzzlehttp/promises", - "version": "1.4.0", + "version": "1.4.1", "source": { "type": "git", "url": "https://github.com/guzzle/promises.git", - "reference": "60d379c243457e073cff02bc323a2a86cb355631" + "reference": "8e7d04f1f6450fef59366c399cfad4b9383aa30d" }, "dist": { "type": "zip", - "url": "https://github.com/gitapi/repos/guzzle/promises/zipball/60d379c243457e073cff02bc323a2a86cb355631", - "reference": "60d379c243457e073cff02bc323a2a86cb355631", + "url": "https://github.com/gitapi/repos/guzzle/promises/zipball/8e7d04f1f6450fef59366c399cfad4b9383aa30d", + "reference": "8e7d04f1f6450fef59366c399cfad4b9383aa30d", "shasum": "" }, "require": { @@ -192,20 +193,20 @@ "keywords": [ "promise" ], - "time": "2020-09-30T07:37:28+00:00" + "time": "2021-03-07T09:25:29+00:00" }, { "name": "guzzlehttp/psr7", - "version": "1.7.0", + "version": "1.8.1", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "53330f47520498c0ae1f61f7e2c90f55690c06a3" + "reference": "35ea11d335fd638b5882ff1725228b3d35496ab1" }, "dist": { "type": "zip", - "url": "https://github.com/gitapi/repos/guzzle/psr7/zipball/53330f47520498c0ae1f61f7e2c90f55690c06a3", - "reference": "53330f47520498c0ae1f61f7e2c90f55690c06a3", + "url": "https://github.com/gitapi/repos/guzzle/psr7/zipball/35ea11d335fd638b5882ff1725228b3d35496ab1", + "reference": "35ea11d335fd638b5882ff1725228b3d35496ab1", "shasum": "" }, "require": { @@ -263,20 +264,20 @@ "uri", "url" ], - "time": "2020-09-30T07:37:11+00:00" + "time": "2021-03-21T16:25:00+00:00" }, { "name": "mollie/mollie-api-php", - "version": "v2.24.0", + "version": "v2.30.2", "source": { "type": "git", "url": "https://github.com/mollie/mollie-api-php.git", - "reference": "52bd606724109906d61226698c8b031ccae9e637" + "reference": "c3eb21214583f21655d4182b4c5b2f73e5a1dd0e" }, "dist": { "type": "zip", - "url": "https://github.com/gitapi/repos/mollie/mollie-api-php/zipball/52bd606724109906d61226698c8b031ccae9e637", - "reference": "52bd606724109906d61226698c8b031ccae9e637", + "url": "https://github.com/gitapi/repos/mollie/mollie-api-php/zipball/c3eb21214583f21655d4182b4c5b2f73e5a1dd0e", + "reference": "c3eb21214583f21655d4182b4c5b2f73e5a1dd0e", "shasum": "" }, "require": { @@ -289,7 +290,8 @@ }, "require-dev": { "eloquent/liberator": "^2.0", - "phpunit/phpunit": "^5.7 || ^6.5 || ^7.1" + "friendsofphp/php-cs-fixer": "^v2.17", + "phpunit/phpunit": "^5.7 || ^6.5 || ^7.1 || ^8.5" }, "suggest": { "mollie/oauth2-mollie-php": "Use OAuth to authenticate with the Mollie API. This is needed for some endpoints. Visit https://docs.mollie.com/ for more information." @@ -349,7 +351,7 @@ "sofortbanking", "subscriptions" ], - "time": "2020-10-15T12:55:48+00:00" + "time": "2021-03-31T14:44:26+00:00" }, { "name": "paragonie/random_compat", @@ -490,319 +492,6 @@ "description": "A polyfill for getallheaders.", "time": "2019-03-08T08:55:37+00:00" }, - { - "name": "roave/security-advisories", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/Roave/SecurityAdvisories.git", - "reference": "d50c04efe771797b10510188c4fbd11ee9fb1bdc" - }, - "dist": { - "type": "zip", - "url": "https://github.com/gitapi/repos/Roave/SecurityAdvisories/zipball/d50c04efe771797b10510188c4fbd11ee9fb1bdc", - "reference": "d50c04efe771797b10510188c4fbd11ee9fb1bdc", - "shasum": "" - }, - "conflict": { - "3f/pygmentize": "<1.2", - "adodb/adodb-php": "<5.20.12", - "alterphp/easyadmin-extension-bundle": ">=1.2,<1.2.11|>=1.3,<1.3.1", - "amphp/artax": "<1.0.6|>=2,<2.0.6", - "amphp/http": "<1.0.1", - "amphp/http-client": ">=4,<4.4", - "api-platform/core": ">=2.2,<2.2.10|>=2.3,<2.3.6", - "asymmetricrypt/asymmetricrypt": ">=0,<9.9.99", - "aws/aws-sdk-php": ">=3,<3.2.1", - "bagisto/bagisto": "<0.1.5", - "barrelstrength/sprout-base-email": "<1.2.7", - "barrelstrength/sprout-forms": "<3.9", - "baserproject/basercms": ">=4,<=4.3.6|>=4.4,<4.4.1", - "bolt/bolt": "<3.7.1", - "brightlocal/phpwhois": "<=4.2.5", - "buddypress/buddypress": "<5.1.2", - "bugsnag/bugsnag-laravel": ">=2,<2.0.2", - "cakephp/cakephp": ">=1.3,<1.3.18|>=2,<2.4.99|>=2.5,<2.5.99|>=2.6,<2.6.12|>=2.7,<2.7.6|>=3,<3.5.18|>=3.6,<3.6.15|>=3.7,<3.7.7", - "cart2quote/module-quotation": ">=4.1.6,<=4.4.5|>=5,<5.4.4", - "cartalyst/sentry": "<=2.1.6", - "centreon/centreon": "<18.10.8|>=19,<19.4.5", - "cesnet/simplesamlphp-module-proxystatistics": "<3.1", - "codeigniter/framework": "<=3.0.6", - "composer/composer": "<=1-alpha.11", - "contao-components/mediaelement": ">=2.14.2,<2.21.1", - "contao/core": ">=2,<3.5.39", - "contao/core-bundle": "= 4.10.0|>=4,<4.4.52|>=4.5,<4.9.6", - "contao/listing-bundle": ">=4,<4.4.8", - "datadog/dd-trace": ">=0.30,<0.30.2", - "david-garcia/phpwhois": "<=4.3.1", - "derhansen/sf_event_mgt": "<4.3.1|>=5,<5.1.1", - "doctrine/annotations": ">=1,<1.2.7", - "doctrine/cache": ">=1,<1.3.2|>=1.4,<1.4.2", - "doctrine/common": ">=2,<2.4.3|>=2.5,<2.5.1", - "doctrine/dbal": ">=2,<2.0.8|>=2.1,<2.1.2", - "doctrine/doctrine-bundle": "<1.5.2", - "doctrine/doctrine-module": "<=0.7.1", - "doctrine/mongodb-odm": ">=1,<1.0.2", - "doctrine/mongodb-odm-bundle": ">=2,<3.0.1", - "doctrine/orm": ">=2,<2.4.8|>=2.5,<2.5.1", - "dolibarr/dolibarr": "<11.0.4", - "dompdf/dompdf": ">=0.6,<0.6.2", - "drupal/core": ">=7,<7.74|>=8,<8.8.11|>=8.9,<8.9.9|>=9,<9.0.8", - "drupal/drupal": ">=7,<7.74|>=8,<8.8.11|>=8.9,<8.9.9|>=9,<9.0.8", - "endroid/qr-code-bundle": "<3.4.2", - "enshrined/svg-sanitize": "<0.13.1", - "erusev/parsedown": "<1.7.2", - "ezsystems/demobundle": ">=5.4,<5.4.6.1", - "ezsystems/ezdemo-ls-extension": ">=5.4,<5.4.2.1", - "ezsystems/ezfind-ls": ">=5.3,<5.3.6.1|>=5.4,<5.4.11.1|>=2017.12,<2017.12.0.1", - "ezsystems/ezplatform": ">=1.7,<1.7.9.1|>=1.13,<1.13.5.1|>=2.5,<2.5.4", - "ezsystems/ezplatform-admin-ui": ">=1.3,<1.3.5|>=1.4,<1.4.6", - "ezsystems/ezplatform-admin-ui-assets": ">=4,<4.2.1|>=5,<5.0.1|>=5.1,<5.1.1", - "ezsystems/ezplatform-kernel": ">=1,<1.0.2.1", - "ezsystems/ezplatform-user": ">=1,<1.0.1", - "ezsystems/ezpublish-kernel": ">=5.3,<5.3.12.1|>=5.4,<5.4.14.2|>=6,<6.7.9.1|>=6.8,<6.13.6.3|>=7,<7.2.4.1|>=7.3,<7.3.2.1|>=7.5,<7.5.7.1", - "ezsystems/ezpublish-legacy": ">=5.3,<5.3.12.6|>=5.4,<5.4.14.2|>=2011,<2017.12.7.3|>=2018.6,<2018.6.1.4|>=2018.9,<2018.9.1.3|>=2019.3,<2019.3.5.1", - "ezsystems/platform-ui-assets-bundle": ">=4.2,<4.2.3", - "ezsystems/repository-forms": ">=2.3,<2.3.2.1", - "ezyang/htmlpurifier": "<4.1.1", - "firebase/php-jwt": "<2", - "fooman/tcpdf": "<6.2.22", - "fossar/tcpdf-parser": "<6.2.22", - "friendsofsymfony/oauth2-php": "<1.3", - "friendsofsymfony/rest-bundle": ">=1.2,<1.2.2", - "friendsofsymfony/user-bundle": ">=1.2,<1.3.5", - "friendsoftypo3/mediace": ">=7.6.2,<7.6.5", - "fuel/core": "<1.8.1", - "getgrav/grav": "<1.7-beta.8", - "gos/web-socket-bundle": "<1.10.4|>=2,<2.6.1|>=3,<3.3", - "gree/jose": "<=2.2", - "gregwar/rst": "<1.0.3", - "guzzlehttp/guzzle": ">=4-rc.2,<4.2.4|>=5,<5.3.1|>=6,<6.2.1", - "illuminate/auth": ">=4,<4.0.99|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.10", - "illuminate/cookie": ">=4,<=4.0.11|>=4.1,<=4.1.99999|>=4.2,<=4.2.99999|>=5,<=5.0.99999|>=5.1,<=5.1.99999|>=5.2,<=5.2.99999|>=5.3,<=5.3.99999|>=5.4,<=5.4.99999|>=5.5,<=5.5.49|>=5.6,<=5.6.99999|>=5.7,<=5.7.99999|>=5.8,<=5.8.99999|>=6,<6.18.31|>=7,<7.22.4", - "illuminate/database": ">=4,<4.0.99|>=4.1,<4.1.29|>=5.5,<=5.5.44|>=6,<6.18.34|>=7,<7.23.2", - "illuminate/encryption": ">=4,<=4.0.11|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.40|>=5.6,<5.6.15", - "illuminate/view": ">=7,<7.1.2", - "ivankristianto/phpwhois": "<=4.3", - "james-heinrich/getid3": "<1.9.9", - "joomla/session": "<1.3.1", - "jsmitty12/phpwhois": "<5.1", - "kazist/phpwhois": "<=4.2.6", - "kitodo/presentation": "<3.1.2", - "kreait/firebase-php": ">=3.2,<3.8.1", - "la-haute-societe/tcpdf": "<6.2.22", - "laravel/framework": ">=4,<4.0.99|>=4.1,<=4.1.99999|>=4.2,<=4.2.99999|>=5,<=5.0.99999|>=5.1,<=5.1.99999|>=5.2,<=5.2.99999|>=5.3,<=5.3.99999|>=5.4,<=5.4.99999|>=5.5,<=5.5.49|>=5.6,<=5.6.99999|>=5.7,<=5.7.99999|>=5.8,<=5.8.99999|>=6,<6.18.34|>=7,<7.23.2", - "laravel/socialite": ">=1,<1.0.99|>=2,<2.0.10", - "league/commonmark": "<0.18.3", - "librenms/librenms": "<1.53", - "livewire/livewire": ">2.2.4,<2.2.6", - "magento/community-edition": ">=2,<2.2.10|>=2.3,<2.3.3", - "magento/magento1ce": "<1.9.4.3", - "magento/magento1ee": ">=1,<1.14.4.3", - "magento/product-community-edition": ">=2,<2.2.10|>=2.3,<2.3.2-p.2", - "marcwillmann/turn": "<0.3.3", - "mediawiki/core": ">=1.27,<1.27.6|>=1.29,<1.29.3|>=1.30,<1.30.2|>=1.31,<1.31.9|>=1.32,<1.32.6|>=1.32.99,<1.33.3|>=1.33.99,<1.34.3|>=1.34.99,<1.35", - "mittwald/typo3_forum": "<1.2.1", - "monolog/monolog": ">=1.8,<1.12", - "namshi/jose": "<2.2", - "nette/application": ">=2,<2.0.19|>=2.1,<2.1.13|>=2.2,<2.2.10|>=2.3,<2.3.14|>=2.4,<2.4.16|>=3,<3.0.6", - "nette/nette": ">=2,<2.0.19|>=2.1,<2.1.13", - "nystudio107/craft-seomatic": "<3.3", - "nzo/url-encryptor-bundle": ">=4,<4.3.2|>=5,<5.0.1", - "october/backend": ">=1.0.319,<1.0.467", - "october/cms": ">=1.0.319,<1.0.466", - "october/october": ">=1.0.319,<1.0.466", - "october/rain": ">=1.0.319,<1.0.468", - "onelogin/php-saml": "<2.10.4", - "oneup/uploader-bundle": "<1.9.3|>=2,<2.1.5", - "openid/php-openid": "<2.3", - "openmage/magento-lts": "<19.4.8|>=20,<20.0.4", - "orchid/platform": ">=9,<9.4.4", - "oro/crm": ">=1.7,<1.7.4", - "oro/platform": ">=1.7,<1.7.4", - "padraic/humbug_get_contents": "<1.1.2", - "pagarme/pagarme-php": ">=0,<3", - "paragonie/random_compat": "<2", - "paypal/merchant-sdk-php": "<3.12", - "pear/archive_tar": "<1.4.4", - "personnummer/personnummer": "<3.0.2", - "phpfastcache/phpfastcache": ">=5,<5.0.13", - "phpmailer/phpmailer": "<6.1.6", - "phpmussel/phpmussel": ">=1,<1.6", - "phpmyadmin/phpmyadmin": "<4.9.2", - "phpoffice/phpexcel": "<1.8.2", - "phpoffice/phpspreadsheet": "<1.8", - "phpunit/phpunit": ">=4.8.19,<4.8.28|>=5.0.10,<5.6.3", - "phpwhois/phpwhois": "<=4.2.5", - "phpxmlrpc/extras": "<0.6.1", - "pimcore/pimcore": "<6.3", - "pocketmine/pocketmine-mp": "<3.15.4", - "prestashop/autoupgrade": ">=4,<4.10.1", - "prestashop/contactform": ">1.0.1,<4.3", - "prestashop/gamification": "<2.3.2", - "prestashop/productcomments": ">=4,<4.2", - "prestashop/ps_facetedsearch": "<3.4.1", - "privatebin/privatebin": "<1.2.2|>=1.3,<1.3.2", - "propel/propel": ">=2-alpha.1,<=2-alpha.7", - "propel/propel1": ">=1,<=1.7.1", - "pterodactyl/panel": "<0.7.19|>=1-rc.0,<=1-rc.6", - "pusher/pusher-php-server": "<2.2.1", - "rainlab/debugbar-plugin": "<3.1", - "robrichards/xmlseclibs": "<3.0.4", - "sabberworm/php-css-parser": ">=1,<1.0.1|>=2,<2.0.1|>=3,<3.0.1|>=4,<4.0.1|>=5,<5.0.9|>=5.1,<5.1.3|>=5.2,<5.2.1|>=6,<6.0.2|>=7,<7.0.4|>=8,<8.0.1|>=8.1,<8.1.1|>=8.2,<8.2.1|>=8.3,<8.3.1", - "sabre/dav": ">=1.6,<1.6.99|>=1.7,<1.7.11|>=1.8,<1.8.9", - "scheb/two-factor-bundle": ">=0,<3.26|>=4,<4.11", - "sensiolabs/connect": "<4.2.3", - "serluck/phpwhois": "<=4.2.6", - "shopware/core": "<=6.3.2", - "shopware/platform": "<=6.3.2", - "shopware/shopware": "<5.6.9", - "silverstripe/admin": ">=1.0.3,<1.0.4|>=1.1,<1.1.1", - "silverstripe/assets": ">=1,<1.4.7|>=1.5,<1.5.2", - "silverstripe/cms": "<4.3.6|>=4.4,<4.4.4", - "silverstripe/comments": ">=1.3,<1.9.99|>=2,<2.9.99|>=3,<3.1.1", - "silverstripe/forum": "<=0.6.1|>=0.7,<=0.7.3", - "silverstripe/framework": "<4.4.7|>=4.5,<4.5.4", - "silverstripe/graphql": ">=2,<2.0.5|>=3,<3.1.2|>=3.2,<3.2.4", - "silverstripe/registry": ">=2.1,<2.1.2|>=2.2,<2.2.1", - "silverstripe/restfulserver": ">=1,<1.0.9|>=2,<2.0.4", - "silverstripe/subsites": ">=2,<2.1.1", - "silverstripe/taxonomy": ">=1.3,<1.3.1|>=2,<2.0.1", - "silverstripe/userforms": "<3", - "simple-updates/phpwhois": "<=1", - "simplesamlphp/saml2": "<1.10.6|>=2,<2.3.8|>=3,<3.1.4", - "simplesamlphp/simplesamlphp": "<1.18.6", - "simplesamlphp/simplesamlphp-module-infocard": "<1.0.1", - "simplito/elliptic-php": "<1.0.6", - "slim/slim": "<2.6", - "smarty/smarty": "<3.1.33", - "socalnick/scn-social-auth": "<1.15.2", - "spoonity/tcpdf": "<6.2.22", - "squizlabs/php_codesniffer": ">=1,<2.8.1|>=3,<3.0.1", - "ssddanbrown/bookstack": "<0.29.2", - "stormpath/sdk": ">=0,<9.9.99", - "studio-42/elfinder": "<2.1.49", - "sulu/sulu": "<1.6.34|>=2,<2.0.10|>=2.1,<2.1.1", - "swiftmailer/swiftmailer": ">=4,<5.4.5", - "sylius/admin-bundle": ">=1,<1.0.17|>=1.1,<1.1.9|>=1.2,<1.2.2", - "sylius/grid": ">=1,<1.1.19|>=1.2,<1.2.18|>=1.3,<1.3.13|>=1.4,<1.4.5|>=1.5,<1.5.1", - "sylius/grid-bundle": ">=1,<1.1.19|>=1.2,<1.2.18|>=1.3,<1.3.13|>=1.4,<1.4.5|>=1.5,<1.5.1", - "sylius/resource-bundle": "<1.3.14|>=1.4,<1.4.7|>=1.5,<1.5.2|>=1.6,<1.6.4", - "sylius/sylius": "<1.6.9|>=1.7,<1.7.9|>=1.8,<1.8.3", - "symbiote/silverstripe-multivaluefield": ">=3,<3.0.99", - "symbiote/silverstripe-versionedfiles": "<=2.0.3", - "symfony/cache": ">=3.1,<3.4.35|>=4,<4.2.12|>=4.3,<4.3.8", - "symfony/dependency-injection": ">=2,<2.0.17|>=2.7,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", - "symfony/error-handler": ">=4.4,<4.4.4|>=5,<5.0.4", - "symfony/form": ">=2.3,<2.3.35|>=2.4,<2.6.12|>=2.7,<2.7.50|>=2.8,<2.8.49|>=3,<3.4.20|>=4,<4.0.15|>=4.1,<4.1.9|>=4.2,<4.2.1", - "symfony/framework-bundle": ">=2,<2.3.18|>=2.4,<2.4.8|>=2.5,<2.5.2|>=2.7,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", - "symfony/http-foundation": ">=2,<2.8.52|>=3,<3.4.35|>=4,<4.2.12|>=4.3,<4.3.8|>=4.4,<4.4.7|>=5,<5.0.7", - "symfony/http-kernel": ">=2,<2.8.52|>=3,<3.4.35|>=4,<4.2.12|>=4.3,<4.4.13|>=5,<5.1.5", - "symfony/intl": ">=2.7,<2.7.38|>=2.8,<2.8.31|>=3,<3.2.14|>=3.3,<3.3.13", - "symfony/mime": ">=4.3,<4.3.8", - "symfony/phpunit-bridge": ">=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", - "symfony/polyfill": ">=1,<1.10", - "symfony/polyfill-php55": ">=1,<1.10", - "symfony/proxy-manager-bridge": ">=2.7,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", - "symfony/routing": ">=2,<2.0.19", - "symfony/security": ">=2,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7|>=4.4,<4.4.7|>=5,<5.0.7", - "symfony/security-bundle": ">=2,<2.7.48|>=2.8,<2.8.41|>=3,<3.3.17|>=3.4,<3.4.11|>=4,<4.0.11", - "symfony/security-core": ">=2.4,<2.6.13|>=2.7,<2.7.9|>=2.7.30,<2.7.32|>=2.8,<2.8.37|>=3,<3.3.17|>=3.4,<3.4.7|>=4,<4.0.7", - "symfony/security-csrf": ">=2.4,<2.7.48|>=2.8,<2.8.41|>=3,<3.3.17|>=3.4,<3.4.11|>=4,<4.0.11", - "symfony/security-guard": ">=2.8,<2.8.41|>=3,<3.3.17|>=3.4,<3.4.11|>=4,<4.0.11", - "symfony/security-http": ">=2.3,<2.3.41|>=2.4,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.2.12|>=4.3,<4.3.8|>=4.4,<4.4.7|>=5,<5.0.7", - "symfony/serializer": ">=2,<2.0.11", - "symfony/symfony": ">=2,<2.8.52|>=3,<3.4.35|>=4,<4.2.12|>=4.3,<4.4.13|>=5,<5.1.5", - "symfony/translation": ">=2,<2.0.17", - "symfony/validator": ">=2,<2.0.24|>=2.1,<2.1.12|>=2.2,<2.2.5|>=2.3,<2.3.3", - "symfony/var-exporter": ">=4.2,<4.2.12|>=4.3,<4.3.8", - "symfony/web-profiler-bundle": ">=2,<2.3.19|>=2.4,<2.4.9|>=2.5,<2.5.4", - "symfony/yaml": ">=2,<2.0.22|>=2.1,<2.1.7", - "t3g/svg-sanitizer": "<1.0.3", - "tecnickcom/tcpdf": "<6.2.22", - "thelia/backoffice-default-template": ">=2.1,<2.1.2", - "thelia/thelia": ">=2.1-beta.1,<2.1.3", - "theonedemon/phpwhois": "<=4.2.5", - "titon/framework": ">=0,<9.9.99", - "truckersmp/phpwhois": "<=4.3.1", - "twig/twig": "<1.38|>=2,<2.7", - "typo3/cms": ">=6.2,<6.2.30|>=7,<7.6.32|>=8,<8.7.30|>=9,<9.5.20|>=10,<10.4.6", - "typo3/cms-core": ">=8,<8.7.30|>=9,<9.5.20|>=10,<10.4.6", - "typo3/flow": ">=1,<1.0.4|>=1.1,<1.1.1|>=2,<2.0.1|>=2.3,<2.3.16|>=3,<3.0.10|>=3.1,<3.1.7|>=3.2,<3.2.7|>=3.3,<3.3.5", - "typo3/neos": ">=1.1,<1.1.3|>=1.2,<1.2.13|>=2,<2.0.4", - "typo3/phar-stream-wrapper": ">=1,<2.1.1|>=3,<3.1.1", - "typo3fluid/fluid": ">=2,<2.0.8|>=2.1,<2.1.7|>=2.2,<2.2.4|>=2.3,<2.3.7|>=2.4,<2.4.4|>=2.5,<2.5.11|>=2.6,<2.6.10", - "ua-parser/uap-php": "<3.8", - "usmanhalalit/pixie": "<1.0.3|>=2,<2.0.2", - "verot/class.upload.php": "<=1.0.3|>=2,<=2.0.4", - "wallabag/tcpdf": "<6.2.22", - "willdurand/js-translation-bundle": "<2.1.1", - "yii2mod/yii2-cms": "<1.9.2", - "yiisoft/yii": ">=1.1.14,<1.1.15", - "yiisoft/yii2": "<2.0.38", - "yiisoft/yii2-bootstrap": "<2.0.4", - "yiisoft/yii2-dev": "<2.0.15", - "yiisoft/yii2-elasticsearch": "<2.0.5", - "yiisoft/yii2-gii": "<2.0.4", - "yiisoft/yii2-jui": "<2.0.4", - "yiisoft/yii2-redis": "<2.0.8", - "yourls/yourls": "<1.7.4", - "zendframework/zend-cache": ">=2.4,<2.4.8|>=2.5,<2.5.3", - "zendframework/zend-captcha": ">=2,<2.4.9|>=2.5,<2.5.2", - "zendframework/zend-crypt": ">=2,<2.4.9|>=2.5,<2.5.2", - "zendframework/zend-db": ">=2,<2.0.99|>=2.1,<2.1.99|>=2.2,<2.2.10|>=2.3,<2.3.5", - "zendframework/zend-developer-tools": ">=1.2.2,<1.2.3", - "zendframework/zend-diactoros": ">=1,<1.8.4", - "zendframework/zend-feed": ">=1,<2.10.3", - "zendframework/zend-form": ">=2,<2.2.7|>=2.3,<2.3.1", - "zendframework/zend-http": ">=1,<2.8.1", - "zendframework/zend-json": ">=2.1,<2.1.6|>=2.2,<2.2.6", - "zendframework/zend-ldap": ">=2,<2.0.99|>=2.1,<2.1.99|>=2.2,<2.2.8|>=2.3,<2.3.3", - "zendframework/zend-mail": ">=2,<2.4.11|>=2.5,<2.7.2", - "zendframework/zend-navigation": ">=2,<2.2.7|>=2.3,<2.3.1", - "zendframework/zend-session": ">=2,<2.0.99|>=2.1,<2.1.99|>=2.2,<2.2.9|>=2.3,<2.3.4", - "zendframework/zend-validator": ">=2.3,<2.3.6", - "zendframework/zend-view": ">=2,<2.2.7|>=2.3,<2.3.1", - "zendframework/zend-xmlrpc": ">=2.1,<2.1.6|>=2.2,<2.2.6", - "zendframework/zendframework": "<2.5.1", - "zendframework/zendframework1": "<1.12.20", - "zendframework/zendopenid": ">=2,<2.0.2", - "zendframework/zendxml": ">=1,<1.0.1", - "zetacomponents/mail": "<1.8.2", - "zf-commons/zfc-user": "<1.2.2", - "zfcampus/zf-apigility-doctrine": ">=1,<1.0.3", - "zfr/zfr-oauth2-server-module": "<0.1.2" - }, - "type": "metapackage", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com", - "role": "maintainer" - }, - { - "name": "Ilya Tribusean", - "email": "slash3b@gmail.com", - "role": "maintainer" - } - ], - "description": "Prevents installation of composer packages with known security vulnerabilities: no API, simply require it", - "funding": [ - { - "url": "https://github.com/Ocramius", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/roave/security-advisories", - "type": "tidelift" - } - ], - "time": "2020-11-19T14:02:08+00:00" - }, { "name": "symfony/polyfill-intl-idn", "version": "v1.19.0", @@ -1087,40 +776,375 @@ ], "authors": [ { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-10-23T09:01:57+00:00" + } + ], + "packages-dev": [ + { + "name": "roave/security-advisories", + "version": "dev-latest", + "source": { + "type": "git", + "url": "https://github.com/Roave/SecurityAdvisories.git", + "reference": "f3d64e623a75abaababa97e02a31e3771dea481a" + }, + "dist": { + "type": "zip", + "url": "https://github.com/gitapi/repos/Roave/SecurityAdvisories/zipball/f3d64e623a75abaababa97e02a31e3771dea481a", + "reference": "f3d64e623a75abaababa97e02a31e3771dea481a", + "shasum": "" + }, + "conflict": { + "3f/pygmentize": "<1.2", + "adodb/adodb-php": "<5.20.12", + "alterphp/easyadmin-extension-bundle": ">=1.2,<1.2.11|>=1.3,<1.3.1", + "amphp/artax": "<1.0.6|>=2,<2.0.6", + "amphp/http": "<1.0.1", + "amphp/http-client": ">=4,<4.4", + "api-platform/core": ">=2.2,<2.2.10|>=2.3,<2.3.6", + "asymmetricrypt/asymmetricrypt": ">=0,<9.9.99", + "aws/aws-sdk-php": ">=3,<3.2.1", + "bagisto/bagisto": "<0.1.5", + "barrelstrength/sprout-base-email": "<1.2.7", + "barrelstrength/sprout-forms": "<3.9", + "baserproject/basercms": ">=4,<=4.3.6|>=4.4,<4.4.1", + "bolt/bolt": "<3.7.1", + "bolt/core": "<4.1.13", + "brightlocal/phpwhois": "<=4.2.5", + "buddypress/buddypress": "<5.1.2", + "bugsnag/bugsnag-laravel": ">=2,<2.0.2", + "cakephp/cakephp": ">=1.3,<1.3.18|>=2,<2.4.99|>=2.5,<2.5.99|>=2.6,<2.6.12|>=2.7,<2.7.6|>=3,<3.5.18|>=3.6,<3.6.15|>=3.7,<3.7.7", + "cart2quote/module-quotation": ">=4.1.6,<=4.4.5|>=5,<5.4.4", + "cartalyst/sentry": "<=2.1.6", + "centreon/centreon": "<18.10.8|>=19,<19.4.5", + "cesnet/simplesamlphp-module-proxystatistics": "<3.1", + "codeigniter/framework": "<=3.0.6", + "composer/composer": "<=1-alpha.11", + "contao-components/mediaelement": ">=2.14.2,<2.21.1", + "contao/core": ">=2,<3.5.39", + "contao/core-bundle": ">=4,<4.4.52|>=4.5,<4.9.6|= 4.10.0", + "contao/listing-bundle": ">=4,<4.4.8", + "datadog/dd-trace": ">=0.30,<0.30.2", + "david-garcia/phpwhois": "<=4.3.1", + "derhansen/sf_event_mgt": "<4.3.1|>=5,<5.1.1", + "doctrine/annotations": ">=1,<1.2.7", + "doctrine/cache": ">=1,<1.3.2|>=1.4,<1.4.2", + "doctrine/common": ">=2,<2.4.3|>=2.5,<2.5.1", + "doctrine/dbal": ">=2,<2.0.8|>=2.1,<2.1.2", + "doctrine/doctrine-bundle": "<1.5.2", + "doctrine/doctrine-module": "<=0.7.1", + "doctrine/mongodb-odm": ">=1,<1.0.2", + "doctrine/mongodb-odm-bundle": ">=2,<3.0.1", + "doctrine/orm": ">=2,<2.4.8|>=2.5,<2.5.1|>=2.8.3,<2.8.4", + "dolibarr/dolibarr": "<11.0.4", + "dompdf/dompdf": ">=0.6,<0.6.2", + "drupal/core": ">=7,<7.74|>=8,<8.8.11|>=8.9,<8.9.9|>=9,<9.0.8", + "drupal/drupal": ">=7,<7.74|>=8,<8.8.11|>=8.9,<8.9.9|>=9,<9.0.8", + "endroid/qr-code-bundle": "<3.4.2", + "enshrined/svg-sanitize": "<0.13.1", + "erusev/parsedown": "<1.7.2", + "ezsystems/demobundle": ">=5.4,<5.4.6.1", + "ezsystems/ez-support-tools": ">=2.2,<2.2.3", + "ezsystems/ezdemo-ls-extension": ">=5.4,<5.4.2.1", + "ezsystems/ezfind-ls": ">=5.3,<5.3.6.1|>=5.4,<5.4.11.1|>=2017.12,<2017.12.0.1", + "ezsystems/ezplatform": ">=1.7,<1.7.9.1|>=1.13,<1.13.5.1|>=2.5,<2.5.4", + "ezsystems/ezplatform-admin-ui": ">=1.3,<1.3.5|>=1.4,<1.4.6", + "ezsystems/ezplatform-admin-ui-assets": ">=4,<4.2.1|>=5,<5.0.1|>=5.1,<5.1.1", + "ezsystems/ezplatform-kernel": "<=1.2.5|>=1.3,<=1.3.1", + "ezsystems/ezplatform-rest": ">=1.2,<=1.2.2|>=1.3,<=1.3.1", + "ezsystems/ezplatform-user": ">=1,<1.0.1", + "ezsystems/ezpublish-kernel": "<=6.13.8.1|>=7,<=7.5.15.1", + "ezsystems/ezpublish-legacy": ">=5.3,<5.3.12.6|>=5.4,<5.4.14.2|>=2011,<2017.12.7.3|>=2018.6,<2018.6.1.4|>=2018.9,<2018.9.1.3|>=2019.3,<2019.3.5.1", + "ezsystems/platform-ui-assets-bundle": ">=4.2,<4.2.3", + "ezsystems/repository-forms": ">=2.3,<2.3.2.1", + "ezyang/htmlpurifier": "<4.1.1", + "facade/ignition": "<1.16.14|>=2,<2.4.2|>=2.5,<2.5.2", + "firebase/php-jwt": "<2", + "flarum/sticky": ">=0.1-beta.14,<=0.1-beta.15", + "flarum/tags": "<=0.1-beta.13", + "fluidtypo3/vhs": "<5.1.1", + "fooman/tcpdf": "<6.2.22", + "fossar/tcpdf-parser": "<6.2.22", + "friendsofsymfony/oauth2-php": "<1.3", + "friendsofsymfony/rest-bundle": ">=1.2,<1.2.2", + "friendsofsymfony/user-bundle": ">=1.2,<1.3.5", + "friendsoftypo3/mediace": ">=7.6.2,<7.6.5", + "fuel/core": "<1.8.1", + "getgrav/grav": "<1.7-beta.8", + "getkirby/cms": ">=3,<3.4.5", + "getkirby/panel": "<2.5.14", + "gos/web-socket-bundle": "<1.10.4|>=2,<2.6.1|>=3,<3.3", + "gree/jose": "<=2.2", + "gregwar/rst": "<1.0.3", + "guzzlehttp/guzzle": ">=4-rc.2,<4.2.4|>=5,<5.3.1|>=6,<6.2.1", + "illuminate/auth": ">=4,<4.0.99|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.10", + "illuminate/cookie": ">=4,<=4.0.11|>=4.1,<=4.1.99999|>=4.2,<=4.2.99999|>=5,<=5.0.99999|>=5.1,<=5.1.99999|>=5.2,<=5.2.99999|>=5.3,<=5.3.99999|>=5.4,<=5.4.99999|>=5.5,<=5.5.49|>=5.6,<=5.6.99999|>=5.7,<=5.7.99999|>=5.8,<=5.8.99999|>=6,<6.18.31|>=7,<7.22.4", + "illuminate/database": "<6.20.14|>=7,<7.30.4|>=8,<8.24", + "illuminate/encryption": ">=4,<=4.0.11|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.40|>=5.6,<5.6.15", + "illuminate/view": ">=7,<7.1.2", + "impresscms/impresscms": "<=1.4.2", + "ivankristianto/phpwhois": "<=4.3", + "james-heinrich/getid3": "<1.9.9", + "joomla/archive": "<1.1.10", + "joomla/session": "<1.3.1", + "jsmitty12/phpwhois": "<5.1", + "kazist/phpwhois": "<=4.2.6", + "kitodo/presentation": "<3.1.2", + "kreait/firebase-php": ">=3.2,<3.8.1", + "la-haute-societe/tcpdf": "<6.2.22", + "laravel/framework": "<6.20.14|>=7,<7.30.4|>=8,<8.24", + "laravel/socialite": ">=1,<1.0.99|>=2,<2.0.10", + "league/commonmark": "<0.18.3", + "librenms/librenms": "<1.53", + "livewire/livewire": ">2.2.4,<2.2.6", + "magento/community-edition": ">=2,<2.2.10|>=2.3,<2.3.3", + "magento/magento1ce": "<1.9.4.3", + "magento/magento1ee": ">=1,<1.14.4.3", + "magento/product-community-edition": ">=2,<2.2.10|>=2.3,<2.3.2-p.2", + "marcwillmann/turn": "<0.3.3", + "mautic/core": "<3.3.2|= 2.13.1", + "mediawiki/core": ">=1.27,<1.27.6|>=1.29,<1.29.3|>=1.30,<1.30.2|>=1.31,<1.31.9|>=1.32,<1.32.6|>=1.32.99,<1.33.3|>=1.33.99,<1.34.3|>=1.34.99,<1.35", + "mittwald/typo3_forum": "<1.2.1", + "monolog/monolog": ">=1.8,<1.12", + "moodle/moodle": "<3.5.17|>=3.7,<3.7.9|>=3.8,<3.8.8|>=3.9,<3.9.5|>=3.10,<3.10.2", + "namshi/jose": "<2.2", + "nette/application": ">=2,<2.0.19|>=2.1,<2.1.13|>=2.2,<2.2.10|>=2.3,<2.3.14|>=2.4,<2.4.16|>=3,<3.0.6", + "nette/nette": ">=2,<2.0.19|>=2.1,<2.1.13", + "nystudio107/craft-seomatic": "<3.3", + "nzo/url-encryptor-bundle": ">=4,<4.3.2|>=5,<5.0.1", + "october/backend": "<1.1.2", + "october/cms": "= 1.0.469|>=1.0.319,<1.0.469", + "october/october": ">=1.0.319,<1.0.466", + "october/rain": "<1.0.472|>=1.1,<1.1.2", + "onelogin/php-saml": "<2.10.4", + "oneup/uploader-bundle": "<1.9.3|>=2,<2.1.5", + "openid/php-openid": "<2.3", + "openmage/magento-lts": "<19.4.8|>=20,<20.0.4", + "orchid/platform": ">=9,<9.4.4", + "oro/crm": ">=1.7,<1.7.4", + "oro/platform": ">=1.7,<1.7.4", + "padraic/humbug_get_contents": "<1.1.2", + "pagarme/pagarme-php": ">=0,<3", + "paragonie/random_compat": "<2", + "passbolt/passbolt_api": "<2.11", + "paypal/merchant-sdk-php": "<3.12", + "pear/archive_tar": "<1.4.12", + "personnummer/personnummer": "<3.0.2", + "phpfastcache/phpfastcache": ">=5,<5.0.13", + "phpmailer/phpmailer": "<6.1.6", + "phpmussel/phpmussel": ">=1,<1.6", + "phpmyadmin/phpmyadmin": "<4.9.6|>=5,<5.0.3", + "phpoffice/phpexcel": "<1.8.2", + "phpoffice/phpspreadsheet": "<1.16", + "phpunit/phpunit": ">=4.8.19,<4.8.28|>=5.0.10,<5.6.3", + "phpwhois/phpwhois": "<=4.2.5", + "phpxmlrpc/extras": "<0.6.1", + "pimcore/pimcore": "<6.8.8", + "pocketmine/pocketmine-mp": "<3.15.4", + "pressbooks/pressbooks": "<5.18", + "prestashop/autoupgrade": ">=4,<4.10.1", + "prestashop/contactform": ">1.0.1,<4.3", + "prestashop/gamification": "<2.3.2", + "prestashop/productcomments": ">=4,<4.2.1", + "prestashop/ps_emailsubscription": "<2.6.1", + "prestashop/ps_facetedsearch": "<3.4.1", + "privatebin/privatebin": "<1.2.2|>=1.3,<1.3.2", + "propel/propel": ">=2-alpha.1,<=2-alpha.7", + "propel/propel1": ">=1,<=1.7.1", + "pterodactyl/panel": "<0.7.19|>=1-rc.0,<=1-rc.6", + "pusher/pusher-php-server": "<2.2.1", + "rainlab/debugbar-plugin": "<3.1", + "robrichards/xmlseclibs": "<3.0.4", + "sabberworm/php-css-parser": ">=1,<1.0.1|>=2,<2.0.1|>=3,<3.0.1|>=4,<4.0.1|>=5,<5.0.9|>=5.1,<5.1.3|>=5.2,<5.2.1|>=6,<6.0.2|>=7,<7.0.4|>=8,<8.0.1|>=8.1,<8.1.1|>=8.2,<8.2.1|>=8.3,<8.3.1", + "sabre/dav": ">=1.6,<1.6.99|>=1.7,<1.7.11|>=1.8,<1.8.9", + "scheb/two-factor-bundle": ">=0,<3.26|>=4,<4.11", + "sensiolabs/connect": "<4.2.3", + "serluck/phpwhois": "<=4.2.6", + "shopware/core": "<=6.3.4", + "shopware/platform": "<=6.3.5.1", + "shopware/shopware": "<5.6.9", + "silverstripe/admin": ">=1.0.3,<1.0.4|>=1.1,<1.1.1", + "silverstripe/assets": ">=1,<1.4.7|>=1.5,<1.5.2", + "silverstripe/cms": "<4.3.6|>=4.4,<4.4.4", + "silverstripe/comments": ">=1.3,<1.9.99|>=2,<2.9.99|>=3,<3.1.1", + "silverstripe/forum": "<=0.6.1|>=0.7,<=0.7.3", + "silverstripe/framework": "<4.4.7|>=4.5,<4.5.4", + "silverstripe/graphql": ">=2,<2.0.5|>=3,<3.1.2|>=3.2,<3.2.4", + "silverstripe/registry": ">=2.1,<2.1.2|>=2.2,<2.2.1", + "silverstripe/restfulserver": ">=1,<1.0.9|>=2,<2.0.4", + "silverstripe/subsites": ">=2,<2.1.1", + "silverstripe/taxonomy": ">=1.3,<1.3.1|>=2,<2.0.1", + "silverstripe/userforms": "<3", + "simple-updates/phpwhois": "<=1", + "simplesamlphp/saml2": "<1.10.6|>=2,<2.3.8|>=3,<3.1.4", + "simplesamlphp/simplesamlphp": "<1.18.6", + "simplesamlphp/simplesamlphp-module-infocard": "<1.0.1", + "simplito/elliptic-php": "<1.0.6", + "slim/slim": "<2.6", + "smarty/smarty": "<3.1.39", + "socalnick/scn-social-auth": "<1.15.2", + "socialiteproviders/steam": "<1.1", + "spoonity/tcpdf": "<6.2.22", + "squizlabs/php_codesniffer": ">=1,<2.8.1|>=3,<3.0.1", + "ssddanbrown/bookstack": "<0.29.2", + "stormpath/sdk": ">=0,<9.9.99", + "studio-42/elfinder": "<2.1.49", + "sulu/sulu": "<1.6.34|>=2,<2.0.10|>=2.1,<2.1.1", + "swiftmailer/swiftmailer": ">=4,<5.4.5", + "sylius/admin-bundle": ">=1,<1.0.17|>=1.1,<1.1.9|>=1.2,<1.2.2", + "sylius/grid": ">=1,<1.1.19|>=1.2,<1.2.18|>=1.3,<1.3.13|>=1.4,<1.4.5|>=1.5,<1.5.1", + "sylius/grid-bundle": ">=1,<1.1.19|>=1.2,<1.2.18|>=1.3,<1.3.13|>=1.4,<1.4.5|>=1.5,<1.5.1", + "sylius/resource-bundle": "<1.3.14|>=1.4,<1.4.7|>=1.5,<1.5.2|>=1.6,<1.6.4", + "sylius/sylius": "<1.6.9|>=1.7,<1.7.9|>=1.8,<1.8.3", + "symbiote/silverstripe-multivaluefield": ">=3,<3.0.99", + "symbiote/silverstripe-queuedjobs": ">=3,<3.0.2|>=3.1,<3.1.4|>=4,<4.0.7|>=4.1,<4.1.2|>=4.2,<4.2.4|>=4.3,<4.3.3|>=4.4,<4.4.3|>=4.5,<4.5.1|>=4.6,<4.6.4", + "symbiote/silverstripe-versionedfiles": "<=2.0.3", + "symfony/cache": ">=3.1,<3.4.35|>=4,<4.2.12|>=4.3,<4.3.8", + "symfony/dependency-injection": ">=2,<2.0.17|>=2.7,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", + "symfony/error-handler": ">=4.4,<4.4.4|>=5,<5.0.4", + "symfony/form": ">=2.3,<2.3.35|>=2.4,<2.6.12|>=2.7,<2.7.50|>=2.8,<2.8.49|>=3,<3.4.20|>=4,<4.0.15|>=4.1,<4.1.9|>=4.2,<4.2.1", + "symfony/framework-bundle": ">=2,<2.3.18|>=2.4,<2.4.8|>=2.5,<2.5.2|>=2.7,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", + "symfony/http-foundation": ">=2,<2.8.52|>=3,<3.4.35|>=4,<4.2.12|>=4.3,<4.3.8|>=4.4,<4.4.7|>=5,<5.0.7", + "symfony/http-kernel": ">=2,<2.8.52|>=3,<3.4.35|>=4,<4.2.12|>=4.3,<4.4.13|>=5,<5.1.5", + "symfony/intl": ">=2.7,<2.7.38|>=2.8,<2.8.31|>=3,<3.2.14|>=3.3,<3.3.13", + "symfony/mime": ">=4.3,<4.3.8", + "symfony/phpunit-bridge": ">=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", + "symfony/polyfill": ">=1,<1.10", + "symfony/polyfill-php55": ">=1,<1.10", + "symfony/proxy-manager-bridge": ">=2.7,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", + "symfony/routing": ">=2,<2.0.19", + "symfony/security": ">=2,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7|>=4.4,<4.4.7|>=5,<5.0.7", + "symfony/security-bundle": ">=2,<2.7.48|>=2.8,<2.8.41|>=3,<3.3.17|>=3.4,<3.4.11|>=4,<4.0.11", + "symfony/security-core": ">=2.4,<2.6.13|>=2.7,<2.7.9|>=2.7.30,<2.7.32|>=2.8,<2.8.37|>=3,<3.3.17|>=3.4,<3.4.7|>=4,<4.0.7", + "symfony/security-csrf": ">=2.4,<2.7.48|>=2.8,<2.8.41|>=3,<3.3.17|>=3.4,<3.4.11|>=4,<4.0.11", + "symfony/security-guard": ">=2.8,<2.8.41|>=3,<3.3.17|>=3.4,<3.4.11|>=4,<4.0.11", + "symfony/security-http": ">=2.3,<2.3.41|>=2.4,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.2.12|>=4.3,<4.3.8|>=4.4,<4.4.7|>=5,<5.0.7", + "symfony/serializer": ">=2,<2.0.11", + "symfony/symfony": ">=2,<2.8.52|>=3,<3.4.35|>=4,<4.2.12|>=4.3,<4.4.13|>=5,<5.1.5", + "symfony/translation": ">=2,<2.0.17", + "symfony/validator": ">=2,<2.0.24|>=2.1,<2.1.12|>=2.2,<2.2.5|>=2.3,<2.3.3", + "symfony/var-exporter": ">=4.2,<4.2.12|>=4.3,<4.3.8", + "symfony/web-profiler-bundle": ">=2,<2.3.19|>=2.4,<2.4.9|>=2.5,<2.5.4", + "symfony/yaml": ">=2,<2.0.22|>=2.1,<2.1.7", + "t3g/svg-sanitizer": "<1.0.3", + "tecnickcom/tcpdf": "<6.2.22", + "thelia/backoffice-default-template": ">=2.1,<2.1.2", + "thelia/thelia": ">=2.1-beta.1,<2.1.3", + "theonedemon/phpwhois": "<=4.2.5", + "titon/framework": ">=0,<9.9.99", + "truckersmp/phpwhois": "<=4.3.1", + "twig/twig": "<1.38|>=2,<2.7", + "typo3/cms": ">=6.2,<6.2.30|>=7,<7.6.32|>=8,<8.7.38|>=9,<9.5.25|>=10,<10.4.14|>=11,<11.1.1", + "typo3/cms-backend": ">=7,<=7.6.50|>=8,<=8.7.39|>=9,<=9.5.24|>=10,<=10.4.13|>=11,<=11.1", + "typo3/cms-core": ">=6.2,<=6.2.56|>=7,<=7.6.50|>=8,<=8.7.39|>=9,<9.5.25|>=10,<10.4.14|>=11,<11.1.1", + "typo3/cms-form": ">=8,<=8.7.39|>=9,<=9.5.24|>=10,<=10.4.13|>=11,<=11.1", + "typo3/flow": ">=1,<1.0.4|>=1.1,<1.1.1|>=2,<2.0.1|>=2.3,<2.3.16|>=3,<3.0.10|>=3.1,<3.1.7|>=3.2,<3.2.7|>=3.3,<3.3.5", + "typo3/neos": ">=1.1,<1.1.3|>=1.2,<1.2.13|>=2,<2.0.4", + "typo3/phar-stream-wrapper": ">=1,<2.1.1|>=3,<3.1.1", + "typo3fluid/fluid": ">=2,<2.0.8|>=2.1,<2.1.7|>=2.2,<2.2.4|>=2.3,<2.3.7|>=2.4,<2.4.4|>=2.5,<2.5.11|>=2.6,<2.6.10", + "ua-parser/uap-php": "<3.8", + "usmanhalalit/pixie": "<1.0.3|>=2,<2.0.2", + "verot/class.upload.php": "<=1.0.3|>=2,<=2.0.4", + "vrana/adminer": "<4.7.9", + "wallabag/tcpdf": "<6.2.22", + "willdurand/js-translation-bundle": "<2.1.1", + "yii2mod/yii2-cms": "<1.9.2", + "yiisoft/yii": ">=1.1.14,<1.1.15", + "yiisoft/yii2": "<2.0.38", + "yiisoft/yii2-bootstrap": "<2.0.4", + "yiisoft/yii2-dev": "<2.0.15", + "yiisoft/yii2-elasticsearch": "<2.0.5", + "yiisoft/yii2-gii": "<2.0.4", + "yiisoft/yii2-jui": "<2.0.4", + "yiisoft/yii2-redis": "<2.0.8", + "yourls/yourls": "<1.7.4", + "zendframework/zend-cache": ">=2.4,<2.4.8|>=2.5,<2.5.3", + "zendframework/zend-captcha": ">=2,<2.4.9|>=2.5,<2.5.2", + "zendframework/zend-crypt": ">=2,<2.4.9|>=2.5,<2.5.2", + "zendframework/zend-db": ">=2,<2.0.99|>=2.1,<2.1.99|>=2.2,<2.2.10|>=2.3,<2.3.5", + "zendframework/zend-developer-tools": ">=1.2.2,<1.2.3", + "zendframework/zend-diactoros": ">=1,<1.8.4", + "zendframework/zend-feed": ">=1,<2.10.3", + "zendframework/zend-form": ">=2,<2.2.7|>=2.3,<2.3.1", + "zendframework/zend-http": ">=1,<2.8.1", + "zendframework/zend-json": ">=2.1,<2.1.6|>=2.2,<2.2.6", + "zendframework/zend-ldap": ">=2,<2.0.99|>=2.1,<2.1.99|>=2.2,<2.2.8|>=2.3,<2.3.3", + "zendframework/zend-mail": ">=2,<2.4.11|>=2.5,<2.7.2", + "zendframework/zend-navigation": ">=2,<2.2.7|>=2.3,<2.3.1", + "zendframework/zend-session": ">=2,<2.0.99|>=2.1,<2.1.99|>=2.2,<2.2.9|>=2.3,<2.3.4", + "zendframework/zend-validator": ">=2.3,<2.3.6", + "zendframework/zend-view": ">=2,<2.2.7|>=2.3,<2.3.1", + "zendframework/zend-xmlrpc": ">=2.1,<2.1.6|>=2.2,<2.2.6", + "zendframework/zendframework": "<2.5.1", + "zendframework/zendframework1": "<1.12.20", + "zendframework/zendopenid": ">=2,<2.0.2", + "zendframework/zendxml": ">=1,<1.0.1", + "zetacomponents/mail": "<1.8.2", + "zf-commons/zfc-user": "<1.2.2", + "zfcampus/zf-apigility-doctrine": ">=1,<1.0.3", + "zfr/zfr-oauth2-server-module": "<0.1.2" + }, + "type": "metapackage", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "role": "maintainer" }, { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" + "name": "Ilya Tribusean", + "email": "slash3b@gmail.com", + "role": "maintainer" } ], - "description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], + "description": "Prevents installation of composer packages with known security vulnerabilities: no API, simply require it", "funding": [ { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", + "url": "https://github.com/Ocramius", "type": "github" }, { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "url": "https://tidelift.com/funding/github/packagist/roave/security-advisories", "type": "tidelift" } ], - "time": "2020-10-23T09:01:57+00:00" + "time": "2021-04-06T18:11:53+00:00" } ], - "packages-dev": [], "aliases": [], "minimum-stability": "stable", "stability-flags": { @@ -1128,7 +1152,10 @@ }, "prefer-stable": false, "prefer-lowest": false, - "platform": [], + "platform": { + "ext-json": "*", + "php": ">=5.6" + }, "platform-dev": [], "plugin-api-version": "1.1.0" } diff --git a/info.xml b/info.xml index 1e35b8a..b1c80d3 100644 --- a/info.xml +++ b/info.xml @@ -1,771 +1,907 @@ - - mollie - Zahlungsartplugin für mollie.com - WebStollen - https://www.webstollen.de/ - 102 - ws_mollie - 405 - - - 100.sql - 2019-02-11 - - - 2019-02-26 - - - 2019-04-23 - - - 2019-05-22 - - - 2019-07-12 - - - 2019-11-26 - - - 2019-12-18 - - - 107.sql - 2020-03-02 - - - 2020-04-24 - - - 109.sql - 2020-08-17 - - - 2020-11-19 - - - 2021-01-11 - - - 2021-01-11 - - - 131_globalinclude.php - 144_notify.php - 181_sync.php - 140_smarty.php - - - - Bestellungen - orders.php - - - Zahlungsarten - paymentmethods.php - - - Info - info.php - - - Einstellungen - - API Key: - Füge hier deinen mollie API Key ein - api_key - - - Profile ID: - Füge hier deinen mollie Profil ID (pfl_) ein. Wird benötigt um mollie Components zu aktivieren - profileId - - - Trust-Grafik bei mollie Components anzeigen: - Bindet eine Trust-Grafik unterhalb des Kreditkartenformulars ein. - loadTrust - - - - - - - Zahlungsart Daten synchronisieren - Lädt Name / Bild für die jeweilige Sprache automatisch von mollie, und speichert diese in der Datenbank - paymentmethod_sync - - - - - - - - - Checkout Styles laden - Lädt Stylesheets für das Evo Template, um den Checkout zu verschönern. - load_styles - - - - - - - - Artikel mit rationalen Stückzahlen - Artikel mit rationalen Stückzahlen werden dann unterstützt, jedoch als ein Artikel behandelt. KEIN Teilversand hierfür möglich! - supportQ - - - - - - - TransaktionsID des Zahlungseingangs: - Welche ID soll an die WAWI übetragen werden? Bei PayPal wird immer die PayPal Referenz angegeben. - wawiPaymentID - - - - - - - - Workflow-Secret: - Schlüssel, um die WAWI Workflow-Requests zu authentifizieren. - workflowSecret - - - Max. Gültigenkeit in Tagen: - Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. - expiryDays - - - mollie Components überspringbar: - Wenn diese Einstellung aktiv ist, erscheint beim Zahlungszusatzschritt (Kreditkarte) ein Link, um diesen Schritt zu überspringen. - skipComponents - - - - - - - - - - skipComponentsLink - - + + mollie + Zahlungsartplugin für mollie.com + WebStollen + https://www.webstollen.de/ + 102 + ws_mollie + 405 + + + 100.sql + 2019-02-11 + + + 2019-02-26 + + + 2019-04-23 + + + 2019-05-22 + + + 2019-07-12 + + + 2019-11-26 + + + 2019-12-18 + + + 107.sql + 2020-03-02 + + + 2020-04-24 + + + 109.sql + 2020-08-17 + + + 2020-11-19 + + + 2021-01-11 + + + 2021-01-11 + 112.sql + + + 75_bestellungInDb.php + 131_globalinclude.php + 132_headPostGet.php + 140_smarty.php + 180_checkbox.php + 181_sync.php + 210_storno.php + + + + Bestellungen + orders.php + + + Zahlungsarten + paymentmethods.php + + + Info + info.php + + + Einstellungen + + Live API Key: + Füge hier deinen mollie API Key ein + api_key + + + Test API Key: + Füge hier deinen mollie API Key ein + test_api_key + + + Profile ID: + Füge hier deinen mollie Profil ID (pfl_) ein. Wird benötigt um mollie Components zu + aktivieren + + profileId + + + Zahlungsart zurücksetzen + Versucht, nach fehlgeschlagener oder abgebrochener Zahlung, die Zahlungsart bei Mollie + zurückzusetzen + + resetMethod + + + + + + + + Bestellabschluss + Hier kann das Bestellabschluss-Verhalten eingestellt werden. + checkoutMode + + + + + + + + + Fallback-Locale + Fallback, falls Locale nicht erkannt oder nicht vorhanden. + fallbackLocale + + + + + + + + + + + + + + + + + + + + + + + + + + + + Trust-Grafik bei mollie Components anzeigen: + Bindet eine Trust-Grafik unterhalb des Kreditkartenformulars ein. + loadTrust + + + + + + + Zahlungsart Daten synchronisieren + Lädt Name / Bild für die jeweilige Sprache automatisch von mollie, und speichert diese + in der Datenbank + + paymentmethod_sync + + + + + + + + + Checkout Styles laden + Lädt Stylesheets für das Evo Template, um den Checkout zu verschönern. + load_styles + + + + + + + + Artikel mit rationalen Stückzahlen + Artikel mit rationalen Stückzahlen werden dann unterstützt, jedoch als ein Artikel + behandelt. KEIN Teilversand hierfür möglich! + + supportQ + + + + + + + TransaktionsID des Zahlungseingangs: + Welche ID soll an die WAWI übetragen werden? Bei PayPal wird immer die PayPal Referenz + angegeben. + + wawiPaymentID + + + + + + + + Workflow-Secret: + Schlüssel, um die WAWI Workflow-Requests zu authentifizieren. + workflowSecret + + + Max. Gültigenkeit in Tagen: + Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" + Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 + Tage. + + expiryDays + + + mollie Components überspringbar: + Wenn diese Einstellung aktiv ist, erscheint beim Zahlungszusatzschritt (Kreditkarte) + ein Link, um diesen Schritt zu überspringen. + + skipComponents + + + + + + + + + + skipComponentsLink + + - - + - - - cctitle - - - - - - - error_canceled - - + + cctitle + + + + + + + error_canceled + + - - - - - error_expired - - + + error_expired + + - - - - - error_open - - + + error_open + + - - - - - error_failed - - + + error_failed + + - - - - - lbl_cardHolder - - - - - - - lbl_cardNumber - - - - - - - lbl_expiryDate - - - - - - - lbl_varificationCode - - - - - - - cvchint_1 - - - - - - - cvchint_2 - - + + lbl_cardHolder + + + + + + + lbl_cardNumber + + + + + + + lbl_expiryDate + + + + + + + lbl_varificationCode + + + + + + + cvchint_1 + + + + + + + cvchint_2 + + - - - - - mcErrorMessage - Ein oder mehrere Felder sind ungültig. - - - - - - - - mollie - img/method/mollie@2x.png - 1 - 0 - mollie.com - OTHER - 0 - 0 - 1 - 0 - JTLMollie.php - JTLMollie - tpl/bestellabschluss.tpl - - mollie - mollie - Bezahlen Sie bequem mit verschiedenen Zahlungsmethoden. - - - Max. Gültigenkeit in Tagen: - Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. - expiryDays - - - - mollie Kreditkarte - img/method/creditcard@2x.png - 3 - 0 - mollie.com - CREDIT_CARD - 1 - 0 - 1 - 0 - JTLMollieCreditCard.php - JTLMollieCreditCard - tpl/bestellabschluss.tpl - tpl/mollieComponents.tpl - - Kreditkarte - mollie - Bezahlen Sie bequem mit Kreditkarte. - - - Max. Gültigenkeit in Tagen: - Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. - expiryDays - - - - mollie Apple Pay - img/method/applepay@2x.png - 3 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMollieApplePay.php - JTLMollieApplePay - tpl/bestellabschluss.tpl - - Apple Pay - mollie - Bezahlen Sie bequem mit Apple Pay. - - - Max. Gültigenkeit in Tagen: - Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. - expiryDays - - - - mollie Bancontact - img/method/bancontact@2x.png - 4 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMollieBancontact.php - JTLMollieBancontact - tpl/bestellabschluss.tpl - - Bancontact - mollie - Bezahlen Sie bequem mit Bancontact. - - - Max. Gültigenkeit in Tagen: - Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. - expiryDays - - - - mollie Banktransfer - img/method/banktransfer@2x.png - 5 - 0 - mollie.com - OTHER - 0 - 0 - 1 - 0 - JTLMollieBanktransfer.php - JTLMollieBanktransfer - tpl/bestellabschluss.tpl - - SEPA Überweisung - mollie - Bezahlen Sie bequem mit SEPA Überweisung. - - - Max. Gültigenkeit in Tagen: - Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. - expiryDays - - - - mollie Belfius - img/method/belfius@2x.png - 6 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMollieBelfius.php - JTLMollieBelfius - tpl/bestellabschluss.tpl - - Belfius - mollie - Bezahlen Sie bequem mit Belfius. - - - Max. Gültigenkeit in Tagen: - Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. - expiryDays - - - - mollie DirectDebit - img/method/directdebit@2x.png - 7 - 0 - mollie.com - DIRECT_DEBIT - 1 - 0 - 1 - 0 - JTLMollieDirectDebit.php - JTLMollieDirectDebit - tpl/bestellabschluss.tpl - - SEPA Lastschrift - mollie - Bezahlen Sie bequem mit SEPA Lastschrift. - - - Max. Gültigenkeit in Tagen: - Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. - expiryDays - - - - mollie EPS - img/method/eps@2x.png - 2 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMollieEPS.php - JTLMollieEPS - tpl/bestellabschluss.tpl - - EPS - mollie - Bezahlen Sie bequem mit EPS. - - - Max. Gültigenkeit in Tagen: - Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. - expiryDays - - - - mollie Giftcard - img/method/giftcard@2x.png - 8 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMollieGiftcard.php - JTLMollieGiftcard - tpl/bestellabschluss.tpl - - Gift cards - mollie - Bezahlen Sie bequem mit Gift cards. - - - Max. Gültigenkeit in Tagen: - Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. - expiryDays - - - - mollie Giropay - img/method/giropay@2x.png - 9 - 0 - mollie.com - GIROPAY - 1 - 0 - 1 - 0 - JTLMollieGiropay.php - JTLMollieGiropay - tpl/bestellabschluss.tpl - - Giropay - mollie - Bezahlen Sie bequem mit Giropay. - - - Max. Gültigenkeit in Tagen: - Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. - expiryDays - - - - mollie iDEAL - img/method/ideal@2x.png - 10 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMollieIDEAL.php - JTLMollieIDEAL - tpl/bestellabschluss.tpl - - iDEAL - mollie - Bezahlen Sie bequem mit iDEAL. - - - Max. Gültigenkeit in Tagen: - Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. - expiryDays - - - - mollie ING HomePay - img/method/inghomepay@2x.png - 11 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMollieINGHomePay.php - JTLMollieINGHomePay - tpl/bestellabschluss.tpl - - ING HomePay - mollie - Bezahlen Sie bequem mit ING HomePay. - - - Max. Gültigenkeit in Tagen: - Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. - expiryDays - - - - mollie KBC - img/method/kbc@2x.png - 12 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMollieKBC.php - JTLMollieKBC - tpl/bestellabschluss.tpl - - KBC - mollie - Bezahlen Sie bequem mit KBC. - - - Max. Gültigenkeit in Tagen: - Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. - expiryDays - - - - mollie PayPal - img/method/paypal@2x.png - 13 - 0 - mollie.com - PAYPAL - 1 - 0 - 1 - 0 - JTLMolliePayPal.php - JTLMolliePayPal - tpl/bestellabschluss.tpl - - PayPal - mollie - Bezahlen Sie bequem mit PayPal. - - - Max. Gültigenkeit in Tagen: - Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. - expiryDays - - - - mollie paysafecard - img/method/paysafecard@2x.png - 14 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMolliePaysafecard.php - JTLMolliePaysafecard - tpl/bestellabschluss.tpl - - paysafecard - mollie - Bezahlen Sie bequem mit paysafecard. - - - Max. Gültigenkeit in Tagen: - Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. - expiryDays - - - - mollie SOFORT - img/method/sofort@2x.png - 15 - 0 - mollie.com - DIRECT_E_BANKING - 1 - 0 - 1 - 0 - JTLMollieSofort.php - JTLMollieSofort - tpl/bestellabschluss.tpl - - SOFORT - mollie - Bezahlen Sie bequem mit SOFORT. - - - Max. Gültigenkeit in Tagen: - Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. - expiryDays - - - - mollie Klarna Pay Later - img/method/klarna@2x.png - 16 - 0 - mollie.com - INVOICE - 1 - 0 - 1 - 0 - JTLMollieKlarnaPayLater.php - JTLMollieKlarnaPayLater - tpl/bestellabschluss.tpl - - Klarna Pay Later - mollie - Bezahlen Sie bequem mit Klarna Pay Later. - - - Max. Gültigenkeit in Tagen: - Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. - expiryDays - - - - mollie Klarna Slice It - img/method/klarna@2x.png - 17 - 0 - mollie.com - FINANCING - 1 - 0 - 1 - 0 - JTLMollieKlarnaSliceIt.php - JTLMollieKlarnaSliceIt - tpl/bestellabschluss.tpl - - Klarna Slice It - mollie - Bezahlen Sie bequem mit Klarna Slice It. - - - Max. Gültigenkeit in Tagen: - Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. - expiryDays - - - - mollie Przelewy24 - img/method/Przelewy24@2x.png - 17 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMolliePrzelewy24.php - JTLMolliePrzelewy24 - tpl/bestellabschluss.tpl - - Przelewy24 - mollie - Bezahlen Sie bequem mit Przelewy24. - - - Max. Gültigenkeit in Tagen: - Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. - expiryDays - - - - mollie MyBank - img/method/mybank@2x.png - 17 - 0 - mollie.com - OTHER - 1 - 0 - 1 - 0 - JTLMollieMyBank.php - JTLMollieMyBank - tpl/bestellabschluss.tpl - - MyBank - mollie - Bezahlen Sie bequem mit MyBank. - - - Max. Gültigenkeit in Tagen: - Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 Tage. - expiryDays - - - - + + + mcErrorMessage + Ein oder mehrere Felder sind ungültig. + + + + + + + + mollie + img/method/mollie@2x.png + 1 + 0 + mollie.com + OTHER + 0 + 0 + 1 + 0 + JTLMollie.php + JTLMollie + tpl/bestellabschluss.tpl + + mollie + mollie + Bezahlen Sie bequem mit verschiedenen Zahlungsmethoden. + + + Max. Gültigenkeit in Tagen: + Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" + Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 + Tage. + + expiryDays + + + + mollie Kreditkarte + img/method/creditcard@2x.png + 3 + 0 + mollie.com + CREDIT_CARD + 1 + 0 + 1 + 0 + JTLMollieCreditCard.php + JTLMollieCreditCard + tpl/bestellabschluss.tpl + tpl/mollieComponents.tpl + + Kreditkarte + mollie + Bezahlen Sie bequem mit Kreditkarte. + + + Max. Gültigenkeit in Tagen: + Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" + Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 + Tage. + + expiryDays + + + + mollie Apple Pay + img/method/applepay@2x.png + 3 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMollieApplePay.php + JTLMollieApplePay + tpl/bestellabschluss.tpl + + Apple Pay + mollie + Bezahlen Sie bequem mit Apple Pay. + + + Max. Gültigenkeit in Tagen: + Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" + Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 + Tage. + + expiryDays + + + + mollie Bancontact + img/method/bancontact@2x.png + 4 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMollieBancontact.php + JTLMollieBancontact + tpl/bestellabschluss.tpl + + Bancontact + mollie + Bezahlen Sie bequem mit Bancontact. + + + Max. Gültigenkeit in Tagen: + Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" + Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 + Tage. + + expiryDays + + + + mollie Banktransfer + img/method/banktransfer@2x.png + 5 + 0 + mollie.com + OTHER + 0 + 0 + 1 + 0 + JTLMollieBanktransfer.php + JTLMollieBanktransfer + tpl/bestellabschluss.tpl + + SEPA Überweisung + mollie + Bezahlen Sie bequem mit SEPA Überweisung. + + + Max. Gültigenkeit in Tagen: + Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" + Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 + Tage. + + expiryDays + + + + mollie Belfius + img/method/belfius@2x.png + 6 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMollieBelfius.php + JTLMollieBelfius + tpl/bestellabschluss.tpl + + Belfius + mollie + Bezahlen Sie bequem mit Belfius. + + + Max. Gültigenkeit in Tagen: + Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" + Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 + Tage. + + expiryDays + + + + mollie DirectDebit + img/method/directdebit@2x.png + 7 + 0 + mollie.com + DIRECT_DEBIT + 1 + 0 + 1 + 0 + JTLMollieDirectDebit.php + JTLMollieDirectDebit + tpl/bestellabschluss.tpl + + SEPA Lastschrift + mollie + Bezahlen Sie bequem mit SEPA Lastschrift. + + + Max. Gültigenkeit in Tagen: + Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" + Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 + Tage. + + expiryDays + + + + mollie EPS + img/method/eps@2x.png + 2 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMollieEPS.php + JTLMollieEPS + tpl/bestellabschluss.tpl + + EPS + mollie + Bezahlen Sie bequem mit EPS. + + + Max. Gültigenkeit in Tagen: + Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" + Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 + Tage. + + expiryDays + + + + mollie Giftcard + img/method/giftcard@2x.png + 8 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMollieGiftcard.php + JTLMollieGiftcard + tpl/bestellabschluss.tpl + + Gift cards + mollie + Bezahlen Sie bequem mit Gift cards. + + + Max. Gültigenkeit in Tagen: + Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" + Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 + Tage. + + expiryDays + + + + mollie Giropay + img/method/giropay@2x.png + 9 + 0 + mollie.com + GIROPAY + 1 + 0 + 1 + 0 + JTLMollieGiropay.php + JTLMollieGiropay + tpl/bestellabschluss.tpl + + Giropay + mollie + Bezahlen Sie bequem mit Giropay. + + + Max. Gültigenkeit in Tagen: + Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" + Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 + Tage. + + expiryDays + + + + mollie iDEAL + img/method/ideal@2x.png + 10 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMollieIDEAL.php + JTLMollieIDEAL + tpl/bestellabschluss.tpl + + iDEAL + mollie + Bezahlen Sie bequem mit iDEAL. + + + Max. Gültigenkeit in Tagen: + Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" + Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 + Tage. + + expiryDays + + + + mollie ING HomePay + img/method/inghomepay@2x.png + 11 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMollieINGHomePay.php + JTLMollieINGHomePay + tpl/bestellabschluss.tpl + + ING HomePay + mollie + Bezahlen Sie bequem mit ING HomePay. + + + Max. Gültigenkeit in Tagen: + Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" + Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 + Tage. + + expiryDays + + + + mollie KBC + img/method/kbc@2x.png + 12 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMollieKBC.php + JTLMollieKBC + tpl/bestellabschluss.tpl + + KBC + mollie + Bezahlen Sie bequem mit KBC. + + + Max. Gültigenkeit in Tagen: + Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" + Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 + Tage. + + expiryDays + + + + mollie PayPal + img/method/paypal@2x.png + 13 + 0 + mollie.com + PAYPAL + 1 + 0 + 1 + 0 + JTLMolliePayPal.php + JTLMolliePayPal + tpl/bestellabschluss.tpl + + PayPal + mollie + Bezahlen Sie bequem mit PayPal. + + + Max. Gültigenkeit in Tagen: + Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" + Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 + Tage. + + expiryDays + + + + mollie paysafecard + img/method/paysafecard@2x.png + 14 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMolliePaysafecard.php + JTLMolliePaysafecard + tpl/bestellabschluss.tpl + + paysafecard + mollie + Bezahlen Sie bequem mit paysafecard. + + + Max. Gültigenkeit in Tagen: + Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" + Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 + Tage. + + expiryDays + + + + mollie SOFORT + img/method/sofort@2x.png + 15 + 0 + mollie.com + DIRECT_E_BANKING + 1 + 0 + 1 + 0 + JTLMollieSofort.php + JTLMollieSofort + tpl/bestellabschluss.tpl + + SOFORT + mollie + Bezahlen Sie bequem mit SOFORT. + + + Max. Gültigenkeit in Tagen: + Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" + Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 + Tage. + + expiryDays + + + + mollie Klarna Pay Later + img/method/klarna@2x.png + 16 + 0 + mollie.com + INVOICE + 1 + 0 + 1 + 0 + JTLMollieKlarnaPayLater.php + JTLMollieKlarnaPayLater + tpl/bestellabschluss.tpl + + Klarna Pay Later + mollie + Bezahlen Sie bequem mit Klarna Pay Later. + + + Max. Gültigenkeit in Tagen: + Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" + Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 + Tage. + + expiryDays + + + + mollie Klarna Slice It + img/method/klarna@2x.png + 17 + 0 + mollie.com + FINANCING + 1 + 0 + 1 + 0 + JTLMollieKlarnaSliceIt.php + JTLMollieKlarnaSliceIt + tpl/bestellabschluss.tpl + + Klarna Slice It + mollie + Bezahlen Sie bequem mit Klarna Slice It. + + + Max. Gültigenkeit in Tagen: + Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" + Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 + Tage. + + expiryDays + + + + mollie Przelewy24 + img/method/Przelewy24@2x.png + 17 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMolliePrzelewy24.php + JTLMolliePrzelewy24 + tpl/bestellabschluss.tpl + + Przelewy24 + mollie + Bezahlen Sie bequem mit Przelewy24. + + + Max. Gültigenkeit in Tagen: + Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" + Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 + Tage. + + expiryDays + + + + mollie MyBank + img/method/mybank@2x.png + 17 + 0 + mollie.com + OTHER + 1 + 0 + 1 + 0 + JTLMollieMyBank.php + JTLMollieMyBank + tpl/bestellabschluss.tpl + + MyBank + mollie + Bezahlen Sie bequem mit MyBank. + + + Max. Gültigenkeit in Tagen: + Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" + Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 + Tage. + + expiryDays + + + + \ No newline at end of file diff --git a/version/112/class/API.php b/version/112/class/API.php new file mode 100644 index 0000000..91f2e24 --- /dev/null +++ b/version/112/class/API.php @@ -0,0 +1,73 @@ +test = (bool)$test; + } + + /** + * @return bool + */ + public static function getMode() + { + require_once PFAD_ROOT . PFAD_ADMIN . PFAD_INCLUDES . 'benutzerverwaltung_inc.php'; + if (\Shop::isAdmin()) { + // TODO: Check Option! + return true; + } + return false; + } + + public function Client() + { + if (!$this->client) { + $this->client = new MollieApiClient(new Client([ + RequestOptions::VERIFY => CaBundle::getBundledCaBundlePath(), + RequestOptions::TIMEOUT => 60 + ])); + $this->client->setApiKey($this->isTest() ? self::Plugin()->oPluginEinstellungAssoc_arr['test_api_key'] : self::Plugin()->oPluginEinstellungAssoc_arr['api_key']) + ->addVersionString('JTL-Shop/' . JTL_VERSION . JTL_MINOR_VERSION) + ->addVersionString('ws_mollie/' . self::Plugin()->nVersion); + } + return $this->client; + } + + /** + * @return bool + */ + public function isTest() + { + return $this->test; + } + + +} \ No newline at end of file diff --git a/version/112/class/Checkout/AbstractCheckout.php b/version/112/class/Checkout/AbstractCheckout.php new file mode 100644 index 0000000..ec71ec1 --- /dev/null +++ b/version/112/class/Checkout/AbstractCheckout.php @@ -0,0 +1,331 @@ +api = $api; + $this->oBestellung = $oBestellung; + } + + /** + * @param int $kBestellung + * @param bool $checkZA + * @return bool + */ + public static function isMollie($kBestellung, $checkZA = false) + { + if ($checkZA) { + $res = Shop::DB()->executeQueryPrepared('SELECT * FROM tzahlungsart WHERE cModulId LIKE :cModulId AND kZahlungsart = :kZahlungsart', [ + ':kZahlungsart' => $kBestellung, + ':cModulId' => 'kPlugin_' . self::Plugin()->kPlugin . '_%' + ], 1); + return $res ? true : false; + } + + return ($res = Shop::DB()->executeQueryPrepared('SELECT kId FROM xplugin_ws_mollie_payments WHERE kBestellung = :kBestellung;', [ + ':kBestellung' => $kBestellung, + ], 1)) && $res->kId; + } + + /** + * @param $id + * @return OrderCheckout|PaymentCheckout + * @throws RuntimeException + */ + public static function fromID($id) + { + if ($model = Payment::fromID($id)) { + return static::fromModel($model); + } + throw new RuntimeException(sprintf('Error loading Order: %s', $id)); + } + + /** + * @param $model + * @return OrderCheckout|PaymentCheckout + * @throws RuntimeException + */ + public static function fromModel($model) + { + if (!$model) { + throw new RuntimeException(sprintf('Error loading Order for Model: %s', print_r($model, 1))); + } + + $oBestellung = new Bestellung($model->kBestellung, true); + if (!$oBestellung->kBestellung) { + throw new RuntimeException(sprintf('Error loading Bestellung: %s', $model->kBestellung)); + } + + if (strpos($model->kID, 'tr_') !== false) { + $self = new PaymentCheckout($oBestellung); + } else { + $self = new OrderCheckout($oBestellung); + } + + $self->setModel($model); + return $self; + } + + /** + * @param $kBestellung + * @return OrderCheckout|PaymentCheckout + * * @throws RuntimeException + */ + public static function fromBestellung($kBestellung) + { + if ($model = Payment::fromID($kBestellung, 'kBestellung')) { + return self::fromModel($model); + } + throw new RuntimeException(sprintf('Error loading Order for Bestellung: %s', $kBestellung)); + } + + /** + * @todo + */ + public static function sendReminders() + { + // TODO + } + + abstract public function cancelOrRefund(); + + /** + * @param array $paymentOptions + * @return Payment|Order + */ + abstract public function create(array $paymentOptions = []); + + /** + * @param null $hash + */ + public function handleNotification($hash = null) + { + if (!$this->getHash()) { + $this->getModel()->cHash = $hash; + } + + $this->updateModel()->saveModel(); + if (!$this->getBestellung()->dBezahltDatum || $this->getBestellung()->dBezahltDatum === '0000-00-00') { + if ($incoming = $this->getIncomingPayment()) { + if ($this->completlyPaid()) { + $this->PaymentMethod()->setOrderStatusToPaid($this->getBestellung()); + static::makeFetchable($this->getBestellung(), $this->getModel()); + $this->PaymentMethod()->deletePaymentHash($this->getHash()); + + $this->PaymentMethod()->doLog(sprintf("Checkout::handleNotification: Bestellung '%s' als bezahlt markiert: %.2f %s", $this->getBestellung()->cBestellNr, (float)$incoming->fBetrag, $incoming->cISO), LOGLEVEL_NOTICE); + + $oZahlungsart = Shop::DB()->selectSingleRow('tzahlungsart', 'cModulId', $this->PaymentMethod()->moduleID); + if ($oZahlungsart && (int)$oZahlungsart->nMailSenden === 1) { + $this->PaymentMethod()->sendConfirmationMail($this->getBestellung()); + } + } else { + $this->PaymentMethod()->doLog(sprintf("Checkout::handleNotification: Bestellung '%s': nicht komplett bezahlt: %.2f %s", $this->getBestellung()->cBestellNr, (float)$incoming->fBetrag, $incoming->cISO), LOGLEVEL_ERROR); + } + } + } + } + + /** + * @return string + */ + public function getHash() + { + if ($this->getModel()->cHash) { + return $this->getModel()->cHash; + } + if (!$this->hash) { + $this->hash = $this->PaymentMethod()->generateHash($this->oBestellung); + } + return $this->hash; + } + + /** + * @return Payment + */ + public function getModel() + { + if (!$this->model) { + $this->model = Payment::fromID($this->oBestellung->kBestellung, 'kBestellung'); + } + return $this->model; + } + + /** + * @param $model + * @return $this + */ + protected function setModel($model) + { + if (!$this->model) { + $this->model = $model; + } else { + throw new RuntimeException('Model already set.'); + } + return $this; + } + + /** + * @return PaymentMethod + */ + public function PaymentMethod() + { + if (!$this->paymentMethod) { + if ($this->getBestellung()->Zahlungsart && strpos($this->getBestellung()->Zahlungsart->cModulId, "kPlugin_{$this::Plugin()->kPlugin}_") !== false) { + $this->paymentMethod = PaymentMethod::create($this->getBestellung()->Zahlungsart->cModulId); + } else { + $this->paymentMethod = PaymentMethod::create("kPlugin_{$this::Plugin()->kPlugin}_mollie"); + } + } + return $this->paymentMethod; + } + + /** + * @return Bestellung + */ + public function getBestellung() + { + if (!$this->oBestellung && $this->getModel()->kBestellung) { + $this->oBestellung = new Bestellung($this->getModel()->kBestellung, true); + } + return $this->oBestellung; + } + + /** + * @return $this + */ + public function updateModel() + { + + if ($this->getMollie()) { + $this->getModel()->kID = $this->getMollie()->id; + $this->getModel()->cLocale = $this->getMollie()->locale; + $this->getModel()->fAmount = (float)$this->getMollie()->amount->value; + $this->getModel()->cMethod = $this->getMollie()->method; + $this->getModel()->cCurrency = $this->getMollie()->amount->currency; + $this->getModel()->cStatus = $this->getMollie()->status; + if ($this->getMollie()->amountRefunded) { + $this->getModel()->fAmountRefunded = $this->getMollie()->amountRefunded->value; + } + if ($this->getMollie()->amountCaptured) { + $this->getModel()->fAmountCaptured = $this->getMollie()->amountCaptured->value; + } + } + + $this->getModel()->kBestellung = $this->getBestellung()->kBestellung; + $this->getModel()->cOrderNumber = $this->getBestellung()->cBestellNr; + $this->getModel()->cHash = $this->getHash(); + $this->getModel()->bSynced = $this->getModel()->bSynced !== null ? $this->getModel()->bSynced : false; + return $this; + } + + /** + * @return bool + */ + public function saveModel() + { + return $this->getModel()->save(); + } + + /** + * @param false $force + * @return Order|\Mollie\Api\Resources\Payment + */ + abstract public function getMollie($force = false); + + /** + * @return \stdClass + */ + abstract public function getIncomingPayment(); + + /** + * @return bool + */ + public function completlyPaid() + { + + if ($row = Shop::DB()->executeQueryPrepared("SELECT SUM(fBetrag) as fBetragSumme FROM tzahlungseingang WHERE kBestellung = :kBestellung", [ + ':kBestellung' => $this->getBestellung()->kBestellung + ], 1)) { + return $row->fBetragSumme >= ($this->getBestellung()->fGesamtsumme * (float)$this->getBestellung()->fWaehrungsFaktor); + } + return false; + + } + + /** + * @param Bestellung $oBestellung + * @param Payment $model + * @return bool + */ + public static function makeFetchable(Bestellung $oBestellung, Payment $model) + { + if ($oBestellung->cAbgeholt === 'Y' && !$model->bSynced) { + Shop::DB()->update('tbestellung', 'kBestellung', (int)$oBestellung->kBestellung, (object)['cAbgeholt' => 'N']); + $model->bSynced = true; + try { + return $model->save(); + } catch (Exception $e) { + \Jtllog::writeLog(sprintf("Fehler beim speichern des Models: %s / Bestellung: %s", $model->kID, $oBestellung->cBestellNr)); + } + } + return false; + } + + /** + * @return API + */ + public function API() + { + if (!$this->api) { + if ($this->getModel()->kID) { + $this->api = new API($this->getModel()->cMode === 'test'); + } else { + $this->api = new API(API::getMode()); + } + } + return $this->api; + } + +} \ No newline at end of file diff --git a/version/112/class/Checkout/Order/Address.php b/version/112/class/Checkout/Order/Address.php new file mode 100644 index 0000000..645315c --- /dev/null +++ b/version/112/class/Checkout/Order/Address.php @@ -0,0 +1,54 @@ +title = trim(($adresse->cAnrede === 'm' ? Shop::Lang()->get('mr') : Shop::Lang()->get('mrs')) . ' ' . $adresse->cTitel) ?: null; + $this->givenName = $adresse->cVorname; + $this->familyName = $adresse->cNachname; + $this->email = $adresse->cMail ?: null; + + if ($organizationName = trim($adresse->cFirma)) { + $this->organizationName = $organizationName; + } + } + +} \ No newline at end of file diff --git a/version/112/class/Checkout/Order/OrderLine.php b/version/112/class/Checkout/Order/OrderLine.php new file mode 100644 index 0000000..4d2da95 --- /dev/null +++ b/version/112/class/Checkout/Order/OrderLine.php @@ -0,0 +1,193 @@ +type = self::getType($oPosition->nPosTyp); + $this->name = $oPosition->cName; + + $_vatRate = (float)$oPosition->fMwSt / 100; + if ((int)$oPosition->nPosTyp === C_WARENKORBPOS_TYP_KUPON) { + $_netto = round($oPosition->fPreis * (1 + $_vatRate), 4); + $_vatRate = 0; + } else { + $_netto = round($oPosition->fPreis, 4); + } + $_amount = (float)$oPosition->nAnzahl; + + if (fmod($oPosition->nAnzahl, 1) !== 0.0) { + $_netto *= $_amount; + $_amount = 1; + $this->name .= sprintf(" (%.2f %s)", (float)$oPosition->nAnzahl, $oPosition->cEinheit); + } + + // TODO vorher 2 + $unitPriceNetto = round(($currency->fFaktor * $_netto), 4); + $unitPrice = round($unitPriceNetto * (1 + $_vatRate), 2); + $totalAmount = round($_amount * $unitPrice, 2); + $vatAmount = round($totalAmount - ($totalAmount / (1 + $_vatRate)), 2); + + $this->quantity = (int)$_amount; + $this->unitPrice = new Amount($unitPrice, $currency, false); + $this->totalAmount = new Amount($totalAmount, $currency, false); + $this->vatRate = number_format($_vatRate * 100, 2); + $this->vatAmount = new Amount($vatAmount, $currency, false); + + $metadata = []; + + if (isset($oPosition->Artikel)) { + $this->sku = $oPosition->Artikel->cArtNr; + $metadata['kArtikel'] = $oPosition->kArtikel; + if ($oPosition->cUnique !== '') { + $metadata['cUnique'] = $oPosition->cUnique; + } + } + + if (isset($oPosition->WarenkorbPosEigenschaftArr) && is_array($oPosition->WarenkorbPosEigenschaftArr) && count($oPosition->WarenkorbPosEigenschaftArr)) { + $metadata['properties'] = []; + /** @var \WarenkorbPosEigenschaft $eigenschaft */ + foreach ($oPosition->WarenkorbPosEigenschaftArr as $eigenschaft) { + $metadata['properties'][] = [ + 'kEigenschaft' => (int)$eigenschaft->kEigenschaft, + 'kEigenschaftWert' => (int)$eigenschaft->kEigenschaftWert, + 'name' => $eigenschaft->cEigenschaftName, + 'value' => $eigenschaft->cEigenschaftWertName, + ]; + if (strlen(json_encode($metadata)) > 1000) { + array_pop($metadata['properties']); + break; + } + } + + } + $this->metadata = $metadata; + } + + /** + * @param $nPosTyp + * @return string + */ + protected static function getType($nPosTyp): string + { + switch ($nPosTyp) { + case C_WARENKORBPOS_TYP_ARTIKEL: + case C_WARENKORBPOS_TYP_GRATISGESCHENK: + // TODO: digital / Download Artikel? + return OrderLineType::TYPE_PHYSICAL; + + case C_WARENKORBPOS_TYP_VERSANDPOS: + return OrderLineType::TYPE_SHIPPING_FEE; + + case C_WARENKORBPOS_TYP_VERPACKUNG: + case C_WARENKORBPOS_TYP_VERSANDZUSCHLAG: + case C_WARENKORBPOS_TYP_ZAHLUNGSART: + case C_WARENKORBPOS_TYP_VERSAND_ARTIKELABHAENGIG: + case C_WARENKORBPOS_TYP_NACHNAHMEGEBUEHR: + return OrderLineType::TYPE_SURCHARGE; + + case C_WARENKORBPOS_TYP_GUTSCHEIN: + case C_WARENKORBPOS_TYP_KUPON: + case C_WARENKORBPOS_TYP_NEUKUNDENKUPON: + return OrderLineType::TYPE_DISCOUNT; + + } + + throw new \RuntimeException('Unknown PosTyp.', (int)$nPosTyp); + } + + /** + * @param OrderLine[] $orderLines + * @param Amount $amount + * @param stdClass $currency + * @return OrderLine|null + */ + public static function getRoundingCompensation(array $orderLines, Amount $amount, $currency) + { + $sum = .0; + foreach ($orderLines as $line) { + $sum += (float)$line->totalAmount->value; + } + if (abs($sum - (float)$amount->value()) > 0) { + $diff = (round((float)$amount->value() - $sum, 2)); + if ($diff !== 0.0) { + $line = new self(); + $line->type = $diff > 0 ? OrderLineType::TYPE_SURCHARGE : OrderLineType::TYPE_DISCOUNT; + $line->name = 'Rundungsausgleich'; + $line->quantity = 1; + $line->unitPrice = new Amount($diff, $currency, false, false); + + $line->totalAmount = new Amount($diff, $currency, false, false); + $line->vatRate = "0.00"; + $line->vatAmount = new Amount(0, $currency, false, false); + return $line; + } + } + return null; + } + + /** + * @param Bestellung $oBestellung + * @return OrderLine + */ + public static function getCredit(Bestellung $oBestellung) + { + $line = new self(); + $line->type = OrderLineType::TYPE_STORE_CREDIT; + $line->name = 'Guthaben'; + $line->quantity = 1; + $line->unitPrice = new Amount($oBestellung->fGuthaben, $oBestellung->Waehrung, true); + $line->totalAmount = $line->unitPrice; + + $line->vatRate = "0.00"; + $line->vatAmount = new Amount(0, $oBestellung->Waehrung, true); + + return $line; + } + +} \ No newline at end of file diff --git a/version/112/class/Checkout/OrderCheckout.php b/version/112/class/Checkout/OrderCheckout.php new file mode 100644 index 0000000..f5972a6 --- /dev/null +++ b/version/112/class/Checkout/OrderCheckout.php @@ -0,0 +1,210 @@ +getMollie()) { + throw new \RuntimeException('Mollie-Order konnte nicht geladen werden: ' . $this->getModel()->kID); + } + if ((int)$this->getBestellung()->cStatus === BESTELLUNG_STATUS_STORNO) { + if ($this->getMollie()->isCancelable) { + $res = $this->getMollie()->cancel(); + return 'Order cancelled, Status: ' . $res->status; + } + $res = $this->getMollie()->refundAll(); + return "Order Refund initiiert, Status: " . $res->status; + } + throw new \RuntimeException('Bestellung ist derzeit nicht storniert, Status: ' . $this->getBestellung()->cStatus); + } + + public function getMollie($force = false) + { + if ($force || (!$this->order && $this->getModel()->kID)) { + try { + $this->order = $this->API()->Client()->orders->get($this->getModel()->kID, ['embed' => 'payments,shipments,refunds']); + } catch (Exception $e) { + throw new \RuntimeException(sprintf('Mollie-Order \'%s\' konnte nicht geladen werden: %s', $this->getModel()->kID, $e->getMessage())); + } + } + return $this->order; + } + + public function create(array $paymentOptions = []) + { + if ($this->getModel()->kID) { + try { + $this->order = $this->API()->Client()->orders->get($this->getModel()->kID, ['embed' => 'payments']); + if (in_array($this->order->status, [OrderStatus::STATUS_COMPLETED, OrderStatus::STATUS_PAID, OrderStatus::STATUS_AUTHORIZED, OrderStatus::STATUS_PENDING], true)) { + // TODO TRANLATE + throw new RuntimeException("ERROR: ALREADY PAID!"); //self::Plugin()->getLocalization()->getTranslation('errAlreadyPaid')); + } + if ($this->order->status === OrderStatus::STATUS_CREATED) { + if ($this->order->payments()) { + /** @var Payment $payment */ + foreach ($this->order->payments() as $payment) { + if ($payment->status === PaymentStatus::STATUS_OPEN) { + $this->payment = $payment; + break; + } + } + } + if (!$this->payment) { + $this->payment = $this->API()->Client()->orderPayments->createForId($this->getModel()->kID, $paymentOptions); + } + $this->updateModel()->saveModel(); + return $this->getMollie(true); + } + } catch (Exception $e) { + $this->PaymentMethod()->doLog(sprintf("OrderCheckout::create: Letzte Order '%s' konnte nicht geladen werden: %s, versuche neue zu erstellen.", $this->getModel()->kID, $e->getMessage()), LOGLEVEL_ERROR); + } + } + + try { + $req = $this->loadRequest($paymentOptions)->getRequestData(); + $this->order = $this->API()->Client()->orders->create($req); + $this->updateModel()->saveModel(); + } catch (Exception $e) { + $this->PaymentMethod()->doLog(sprintf("OrderCheckout::create: Neue Order '%s' konnte nicht erstellt werden: %s.", $this->getBestellung()->cBestellNr, $e->getMessage()), LOGLEVEL_ERROR); + throw new \RuntimeException('Order konnte nicht angelegt werden.'); + } + return $this->order; + } + + public function updateModel() + { + parent::updateModel(); + + if (!$this->payment && $this->getMollie() && $this->getMollie()->payments()) { + /** @var Payment $payment */ + foreach ($this->getMollie()->payments() as $payment) { + if (in_array($payment->status, [PaymentStatus::STATUS_OPEN, PaymentStatus::STATUS_PENDING, PaymentStatus::STATUS_AUTHORIZED, PaymentStatus::STATUS_PAID], true)) { + $this->payment = $payment; + break; + } + } + } + if ($this->payment) { + // TODO + // $this->getModel()->setTransactionId($this->payment->id); + $this->getModel()->cCheckoutURL = $this->payment->getCheckoutUrl(); + } + + $this->getModel()->cWebhookURL = $this->getMollie()->webhookUrl; + $this->getModel()->cRedirectURL = $this->getMollie()->redirectUrl; + + return $this; + } + + public function loadRequest($options = []) + { + + $this->setRequestData('locale', Locale::getLocale(\Session::getInstance()->Language()->getIso(), \Session::getInstance()->Customer()->cLand)) + ->setRequestData('amount', new Amount($this->getBestellung()->fGesamtsumme, $this->getBestellung()->Waehrung, true, true)) + ->setRequestData('orderNumber', $this->getBestellung()->cBestellNr) + ->setRequestData('metadata', [ + 'kBestellung' => $this->getBestellung()->kBestellung, + 'kKunde' => $this->getBestellung()->kKunde, + 'kKundengruppe' => \Session::getInstance()->CustomerGroup()->kKundengruppe, + 'cHash' => $this->getHash(), + ]) + ->setRequestData('redirectUrl', $this->PaymentMethod()->getReturnURL($this->getBestellung())) + ->setRequestData('webhookUrl', Shop::getURL(true) . '/?mollie=1'); + + $pm = $this->PaymentMethod(); + if (defined(get_class($pm) . '::METHOD') && $pm::METHOD !== '' + && (self::Plugin()->oPluginEinstellungAssoc_arr['resetMethod'] !== 'on' || !$this->getMollie())) { + + $this->setRequestData('method', $pm::METHOD); + } + + $this->setRequestData('billingAddress', new Address($this->getBestellung()->oRechnungsadresse)); + if ($this->getBestellung()->Lieferadresse !== null) { + if (!$this->getBestellung()->Lieferadresse->cMail) { + $this->getBestellung()->Lieferadresse->cMail = $this->getBestellung()->oRechnungsadresse->cMail; + } + $this->setRequestData('shippingAddress', new Address($this->getBestellung()->Lieferadresse)); + } + + if ( + !empty(\Session::getInstance()->Customer()->dGeburtstag) + && \Session::getInstance()->Customer()->dGeburtstag !== '0000-00-00' + && preg_match('/^\d{4}-\d{2}-\d{2}$/', trim(\Session::getInstance()->Customer()->dGeburtstag)) + ) { + $this->setRequestData('consumerDateOfBirth', trim(\Session::getInstance()->Customer()->dGeburtstag)); + } + + $lines = []; + foreach ($this->getBestellung()->Positionen as $oPosition) { + $lines[] = new OrderLine($oPosition, $this->getBestellung()->Waehrung); + } + + if ($this->getBestellung()->GuthabenNutzen && $this->getBestellung()->fGuthaben > 0) { + $lines[] = OrderLine::getCredit($this->getBestellung()); + } + + if ($comp = OrderLine::getRoundingCompensation($lines, $this->RequestData('amount'), $this->getBestellung()->Waehrung)) { + $lines[] = $comp; + } + $this->setRequestData('lines', $lines); + +// TODO +// if ($dueDays = (int)self::Plugin()->getConfig()->getValue($this->getPaymentMethod()->moduleID . '_dueDays')) { +// $max = $this->RequestData('method') && strpos($this->RequestData('method'), 'klarna') !== false ? 28 : 100; +// $this->setRequestData('expiresAt', date('Y-m-d', strtotime(sprintf("+%d DAYS", min($dueDays, $max))))); +// } + + $this->setRequestData('payment', $options); + + return $this; + } + + public function getIncomingPayment() + { + if (!$this->getMollie()) { + return null; + } + /** @var Payment $payment */ + foreach ($this->getMollie()->payments() as $payment) { + if (in_array($payment->status, + [PaymentStatus::STATUS_AUTHORIZED, PaymentStatus::STATUS_PAID], true)) { + $this->payment = $payment; + return (object)[ + 'fBetrag' => (float)$payment->amount->value, + 'cISO' => $payment->amount->currency, + 'cZahler' => $payment->details->paypalPayerId ?: $payment->customerId, + 'cHinweis' => $payment->details->paypalReference ?: $payment->id, + ]; + } + } + return null; + } +} \ No newline at end of file diff --git a/version/112/class/Checkout/Payment/Address.php b/version/112/class/Checkout/Payment/Address.php new file mode 100644 index 0000000..f6708d6 --- /dev/null +++ b/version/112/class/Checkout/Payment/Address.php @@ -0,0 +1,65 @@ +streetAndNumber = $adresse->cStrasse . ' ' . $adresse->cHausnummer; + $this->postalCode = $adresse->cPLZ; + $this->city = $adresse->cOrt; + $this->country = $adresse->cLand; + + if ( + isset($adresse->cAdressZusatz) + && trim($adresse->cAdressZusatz) !== '' + ) { + $this->streetAdditional = trim($adresse->cAdressZusatz); + } + + } +} \ No newline at end of file diff --git a/version/112/class/Checkout/Payment/Amount.php b/version/112/class/Checkout/Payment/Amount.php new file mode 100644 index 0000000..5c42d33 --- /dev/null +++ b/version/112/class/Checkout/Payment/Amount.php @@ -0,0 +1,68 @@ +data['value']; + } + + public function currency(){ + return $this->data['currency']; + } + + /** + * @var object + */ + protected $currency; + + public function __construct($value, $currency = null, $useFactor = true, $useRounding = false) + { + $this->currency = $currency; + if (!$currency) { + $this->waehrung = isset($_SESSION['Waehrung']) ? $_SESSION['Waehrung'] : null; + } + if (!$currency) { + $this->currency = Shop::DB()->select('twaehrung', 'cStandard', 'Y'); + } + + if ($useFactor) { + $value *= $currency->fFaktor; + } + if ($useRounding) { + $value = $this->optionaleRundung($value); + } + $this->data['value'] = number_format($value, 2, '.', ''); + + $this->data['currency'] = $currency->cISO; + } + + public function optionaleRundung($gesamtsumme) + { + $conf = \Shop::getSettings([CONF_KAUFABWICKLUNG]); + if (isset($conf['kaufabwicklung']['bestellabschluss_runden5']) && $conf['kaufabwicklung']['bestellabschluss_runden5'] == 1) { + $faktor = $this->currency->fFaktor; + $gesamtsumme *= $faktor; + + // simplification. see https://de.wikipedia.org/wiki/Rundung#Rappenrundung + $gesamtsumme = round($gesamtsumme * 20) / 20; + $gesamtsumme /= $faktor; + } + + return $gesamtsumme; + } + + public function jsonSerialize() + { + return $this->data; + } + +} \ No newline at end of file diff --git a/version/112/class/Checkout/Payment/Locale.php b/version/112/class/Checkout/Payment/Locale.php new file mode 100644 index 0000000..0017ab9 --- /dev/null +++ b/version/112/class/Checkout/Payment/Locale.php @@ -0,0 +1,44 @@ + ['lang' => 'de', 'country' => ['AT', 'DE', 'CH']], + 'fre' => ['lang' => 'fr', 'country' => ['BE', 'FR']], + 'dut' => ['lang' => 'nl', 'country' => ['BE', 'NL']], + 'spa' => ['lang' => 'es', 'country' => ['ES']], + 'ita' => ['lang' => 'it', 'country' => ['IT']], + 'pol' => ['lang' => 'pl', 'country' => ['PL']], + 'hun' => ['lang' => 'hu', 'country' => ['HU']], + 'por' => ['lang' => 'pt', 'country' => ['PT']], + 'nor' => ['lang' => 'nb', 'country' => ['NO']], + 'swe' => ['lang' => 'sv', 'country' => ['SE']], + 'fin' => ['lang' => 'fi', 'country' => ['FI']], + 'dan' => ['lang' => 'da', 'country' => ['DK']], + 'ice' => ['lang' => 'is', 'country' => ['IS']], + 'eng' => ['lang' => 'en', 'country' => ['GB', 'US']], + ]; + + public static function getLocale($cISOSprache, $country = null): string + { + if (array_key_exists($cISOSprache, self::$langs)) { + $locale = self::$langs[$cISOSprache]['lang']; + if ($country && is_array(self::$langs[$cISOSprache]['country']) && in_array($country, self::$langs[$cISOSprache]['country'], true)) { + $locale .= '_' . strtoupper($country); + } else { + $locale .= '_' . self::$langs[$cISOSprache]['country'][0]; + } + return $locale; + } + + return self::Plugin()->oPluginEinstellungAssoc_arr['fallbackLocale']; + } +} \ No newline at end of file diff --git a/version/112/class/Checkout/PaymentCheckout.php b/version/112/class/Checkout/PaymentCheckout.php new file mode 100644 index 0000000..cc9faec --- /dev/null +++ b/version/112/class/Checkout/PaymentCheckout.php @@ -0,0 +1,111 @@ +getBestellung()->cStatus === BESTELLUNG_STATUS_STORNO) { + if ($this->getMollie()->isCancelable) { + $res = $this->API()->Client()->payments->cancel($this->getMollie()->id); + return 'Payment cancelled, Status: ' . $res->status; + } + $res = $this->API()->Client()->payments->refund($this->getMollie(), ['amount' => $this->getMollie()->amount]); + return "Payment Refund initiiert, Status: " . $res->status; + } + throw new \RuntimeException('Bestellung ist derzeit nicht storniert, Status: ' . $this->getBestellung()->cStatus); + } + + public function getMollie($force = false) + { + if ($force || (!$this->payment && $this->getModel()->kID)) { + try { + $this->payment = $this->API()->Client()->payments->get($this->getModel()->kID, ['embed' => 'refunds']); + } catch (\Exception $e) { + throw new \RuntimeException('Mollie-Payment konnte nicht geladen werden: ' . $e->getMessage()); + } + } + return $this->payment; + } + + public function create(array $paymentOptions = []) + { + if ($this->getModel()->kID) { + try { + $this->payment = $this->API()->Client()->payments->get($this->getModel()->kID); + if ($this->payment->status === PaymentStatus::STATUS_OPEN) { + $this->updateModel()->updateModel(); + return $this->payment; + } + } catch (Exception $e) { + $this->PaymentMethod()->doLog(sprintf("PaymentCheckout::create: Letzte Transaktion '%s' konnte nicht geladen werden: %s, versuche neue zu erstellen.", $this->getModel()->kID, $e->getMessage()), LOGLEVEL_ERROR); + } + } + + try { + $req = $this->loadRequest($paymentOptions)->getRequestData(); + $this->payment = $this->API()->Client()->payments->create($req); + $this->updateModel()->saveModel(); + } catch (Exception $e) { + $this->PaymentMethod()->doLog(sprintf("PaymentCheckout::create: Neue Transaktion '%s' konnte nicht erstellt werden: %s.", $this->getBestellung()->cBestellNr, $e->getMessage()), LOGLEVEL_ERROR); + throw new \RuntimeException(sprintf('Mollie-Payment \'%s\' konnte nicht geladen werden: %s', $this->getModel()->kID, $e->getMessage())); + } + return $this->payment; + } + + public function loadRequest($options = []) + { + $this->setRequestData('amount', new Amount($this->getBestellung()->fGesamtsumme, $this->getBestellung()->Waehrung, true, true)) + ->setRequestData('description', 'Order ' . $this->getBestellung()->cBestellNr) + ->setRequestData('redirectUrl', $this->PaymentMethod()->getReturnURL($this->getBestellung())) + ->setRequestData('webhookUrl', Shop::getURL(true) . '/?mollie=1') + ->setRequestData('locale', Locale::getLocale(\Session::getInstance()->Language()->getIso(), \Session::getInstance()->Customer()->cLand)) + ->setRequestData('metadata', [ + 'kBestellung' => $this->getBestellung()->kBestellung, + 'kKunde' => $this->getBestellung()->kKunde, + 'kKundengruppe' => \Session::getInstance()->CustomerGroup()->kKundengruppe, + 'cHash' => $this->getHash(), + ]); + $pm = $this->PaymentMethod(); + if (defined(get_class($pm) . '::METHOD') && $pm::METHOD !== '' + && (self::Plugin()->oPluginEinstellungAssoc_arr['resetMethod'] !== 'Y' || !$this->getMollie())) { + $this->setRequestData('method', $pm::METHOD); + } + foreach ($options as $key => $value) { + $this->setRequestData($key, $value); + } + + return $this; + } + + public function getIncomingPayment() + { + if (!$this->getMollie()) { + return null; + } + if (in_array($this->getMollie()->status, [PaymentStatus::STATUS_AUTHORIZED, PaymentStatus::STATUS_PAID], true)) { + $data = []; + $data['fBetrag'] = (float)$this->getMollie()->amount->value; + $data['cISO'] = $this->getMollie()->amount->currency; + $data['cZahler'] = $this->getMollie()->details->paypalPayerId ?: $this->getMollie()->customerId; + $data['cHinweis'] = $this->getMollie()->details->paypalReference ?: $this->getMollie()->id; + return (object)$data; + } + return null; + } +} \ No newline at end of file diff --git a/version/112/class/Hook/AbstractHook.php b/version/112/class/Hook/AbstractHook.php new file mode 100644 index 0000000..8dcbbda --- /dev/null +++ b/version/112/class/Hook/AbstractHook.php @@ -0,0 +1,13 @@ +kPlugin)) + && array_key_exists($key, $_SESSION) && !array_key_exists("Zahlungsart", $_SESSION)) { + unset($_SESSION[$key]); + } + + if (!array_key_exists('ws_mollie_applepay_available', $_SESSION)) { + Shop::Smarty()->assign('applePayCheckURL', json_encode(self::Plugin()->cFrontendPfadURLSSL . 'applepay.php')); + pq('body')->append(Shop::Smarty()->fetch(self::Plugin()->cFrontendPfad . 'tpl/applepay.tpl')); + } + + } + + /** + * @return bool + */ + public static function isAvailable() + { + if (array_key_exists('ws_mollie_applepay_available', $_SESSION)) { + return $_SESSION['ws_mollie_applepay_available']; + } + return false; + } + + /** + * @param $status bool + */ + public static function setAvailable($status) + { + $_SESSION['ws_mollie_applepay_available'] = $status; + } + +} \ No newline at end of file diff --git a/version/112/class/Hook/Queue.php b/version/112/class/Hook/Queue.php new file mode 100644 index 0000000..5c9f8c3 --- /dev/null +++ b/version/112/class/Hook/Queue.php @@ -0,0 +1,129 @@ + INFO.XML + if (self::Plugin()->oPluginEinstellungAssoc_arr['onlyPaid'] === 'on' + && array_key_exists('oBestellung', $args_arr) + && AbstractCheckout::isMollie((int)$args_arr['oBestellung']->kZahlungsart, true)) { + + $args_arr['oBestellung']->cAbgeholt = 'Y'; + \Jtllog::writeLog('Switch cAbgeholt for kBestellung: ' . print_r($args_arr['oBestellung']->kBestellung, 1), JTLLOG_LEVEL_NOTICE); + } + } + + /** + * @param array $args_arr + */ + public static function xmlBestellStatus(array $args_arr): void + { + if (AbstractCheckout::isMollie((int)$args_arr['oBestellung']->kBestellung)) { + self::saveToQueue(HOOK_BESTELLUNGEN_XML_BESTELLSTATUS . ':' . (int)$args_arr['oBestellung']->kBestellung, [ + 'kBestellung' => $args_arr['oBestellung']->kBestellung, + 'status' => (int)$args_arr['status'] + ]); + } + } + + /** + * @param $hook + * @param $args_arr + * @param string $type + * @return bool + */ + protected static function saveToQueue($hook, $args_arr, $type = 'hook') + { + $mQueue = new QueueModel(Shop::DB()); + $mQueue->cType = $type . ':' . $hook; + $mQueue->cData = serialize($args_arr); + try { + return $mQueue->save(); + } catch (Exception $e) { + \Jtllog::writeLog('mollie::saveToQueue: ' . $e->getMessage() . ' - ' . print_r($args_arr, 1)); + return false; + } + } + + /** + * @param array $args_arr + */ + public static function xmlBearbeiteStorno(array $args_arr) + { + if (AbstractCheckout::isMollie((int)$args_arr['oBestellung']->kBestellung)) { + self::saveToQueue(HOOK_BESTELLUNGEN_XML_BEARBEITESTORNO . ':' . $args_arr['oBestellung']->kBestellung, ['kBestellung' => $args_arr['oBestellung']->kBestellung]); + } + } + + /** + * + */ + public static function headPostGet() + { + if (array_key_exists('mollie', $_REQUEST) && (int)$_REQUEST['mollie'] === 1 && array_key_exists('id', $_REQUEST)) { + self::saveToQueue($_REQUEST['id'], $_REQUEST['id'], 'webhook'); + exit(); + } + if (array_key_exists('m_pay', $_REQUEST)) { + try { + $raw = Shop::DB()->executeQueryPrepared('SELECT kID FROM `xplugin_ws_mollie_payments` WHERE dReminder IS NOT NULL AND MD5(CONCAT(kID, "-", kBestellung)) = :md5', [ + ':md5' => $_REQUEST['m_pay'] + ], 1); + + if (!$raw) { + // TODO! + throw new RuntimeException(self::Plugin()->oPluginSprachvariableAssoc_arr['errOrderNotFound']); + } + + if (strpos($raw->cOrderId, 'tr_') === 0) { + $checkout = PaymentCheckout::fromID($raw->cOrderId); + } else { + $checkout = OrderCheckout::fromID($raw->cOrderId); + } + $checkout->getMollie(true); + $checkout->updateModel()->saveModel(); + + if ($checkout->getBestellung()->dBezahltDatum !== null || in_array($checkout->getModel()->cStatus, ['completed', 'paid', 'authorized', 'pending'])) { + throw new RuntimeException(self::Plugin()->oPluginSprachvariableAssoc_arr['errAlreadyPaid']); + } + + $options = []; + if (self::Plugin()->oPluginEinstellungAssoc_arr['resetMethod'] !== 'on') { + $options['method'] = $checkout->getModel()->cMethod; + } + + $mollie = $checkout->create($options); // Order::repayOrder($orderModel->getOrderId(), $options, $api); + $url = $mollie->getCheckoutUrl(); + + header('Location: ' . $url); + exit(); + + } catch (RuntimeException $e) { + // TODO Workaround? + //$alertHelper = Shop::Container()->getAlertService(); + //$alertHelper->addAlert(Alert::TYPE_ERROR, $e->getMessage(), 'mollie_repay', ['dismissable' => true]); + } catch (Exception $e) { + Jtllog::writeLog('mollie:repay:error: ' . $e->getMessage() . "\n" . print_r($_REQUEST, 1)); + } + } + } + +} \ No newline at end of file diff --git a/version/112/class/Model/AbstractModel.php b/version/112/class/Model/AbstractModel.php index 5638700..46ab5ef 100644 --- a/version/112/class/Model/AbstractModel.php +++ b/version/112/class/Model/AbstractModel.php @@ -2,6 +2,87 @@ namespace ws_mollie\Model; -abstract class AbstractModel +use JsonSerializable; +use Shop; +use stdClass; + +abstract class AbstractModel implements JsonSerializable { + + const TABLE = null; + const PRIMARY = null; + + protected $new = false; + /** + * @var stdClass + */ + protected $data; + + public function __construct($data = null) + { + $this->data = $data; + if (!$data) { + $this->new = true; + } + } + + public static function fromID($id, $col = 'kID', $failIfNotExists = false) + { + if ($payment = Shop::DB()->executeQueryPrepared('SELECT * FROM ' . static::TABLE . ' WHERE :col = :id', + [':col' => $col, ':id' => $id], 1)) { + return new static($payment); + } + if ($failIfNotExists) { + throw new \RuntimeException(sprintf('Model %s in %s nicht gefunden!', $id, static::TABLE)); + } + return new static(); + } + + /** + * @return mixed|stdClass|null + */ + public function jsonSerialize() + { + return $this->data; + } + + public function __get($name) + { + if (isset($this->data->$name)) { + return $this->data->$name; + } + return null; + } + + public function __set($name, $value) + { + if (!$this->data) { + $this->data = new stdClass(); + } + $this->data->$name = $value; + } + + public function __isset($name) + { + return isset($this->data->$name); + } + + /** + * @return bool + */ + public function save() + { + if (!$this->data) { + throw new \RuntimeException('No Data to save!'); + } + + if ($this->new) { + Shop::DB()->insert(static::TABLE, $this->data); + $this->new = false; + return true; + } + Shop::DB()->update(static::TABLE, static::PRIMARY, $this->data->{static::PRIMARY}, $this->data); + return true; + } + } diff --git a/version/112/class/Model/Customer.php b/version/112/class/Model/Customer.php new file mode 100644 index 0000000..82c4f3b --- /dev/null +++ b/version/112/class/Model/Customer.php @@ -0,0 +1,66 @@ +kKunde, self::PRIMARY); + + $api = new API(API::getMode()); + + if (!$mCustomer->customerId) { + if (!array_key_exists('mollie_create_customer', $_SESSION['cPost_arr']) || $_SESSION['cPost_arr']['mollie_create_customer'] !== 'on') { + return null; + } + } else { + try { + $customer = $api->Client()->customers->get($mCustomer->customerId); + } catch (ApiException $e) { + $customer = new \stdClass(); + } + } + + + $customer->name = trim($oKunde->cVorname . ' ' . $oKunde->cNachname); + $customer->email = $oKunde->cMail; + $customer->locale = Locale::getLocale(\Session::getInstance()->Language()->getIso(), $oKunde->cLand); + $customer->metadata = (object)[ + 'kKunde' => $oKunde->kKunde, + 'kKundengruppe' => $oKunde->kKundengruppe, + 'cKundenNr' => $oKunde->cKundenNr, + ]; + + try { + if ($customer instanceof \Mollie\Api\Resources\Customer) { + $customer->update(); + } else { + $customer = $api->Client()->customers->create((array)$customer); + $mCustomer->customerId = $customer->id; + $mCustomer->save(); + } + } catch (\Exception $e) { + return null; + } + + return $mCustomer->customerId; + + } +} \ No newline at end of file diff --git a/version/112/class/Model/Payment.php b/version/112/class/Model/Payment.php index 6abe1d5..d21799e 100644 --- a/version/112/class/Model/Payment.php +++ b/version/112/class/Model/Payment.php @@ -7,10 +7,44 @@ use Shop; use ws_mollie\Mollie; +/** + * Class Payment + * @package ws_mollie\Model + * + * @property string $kID + * @property int $kBestellung + * @property string $cMode + * @property string $cStatus + * @property string $cHash + * @property float $fAmount + * @property string $cOrderNumber + * @property string $cCurrency + * @property string $cMethod + * @property string $cLocale + * @property bool $bCancelable + * @property string $cWebhookURL + * @property string $cRedirectURL + * @property string $cCheckoutURL + * @property float $fAmountCaptured + * @property float $fAmountRefunded + * @property string $dCreatedAt + * @property bool $bLockTimeout + * @property bool $bSynced + */ class Payment extends AbstractModel { const TABLE = 'xplugin_ws_mollie_payments'; + const PRIMARY = 'kID'; + + /** + * @param Order $oMolliePayment + * @param null $kBestellung + * @param null $hash + * @return array|bool|int|object + * @throws \Exception + * @deprecated + */ public static function updateFromPayment(Order $oMolliePayment, $kBestellung = null, $hash = null) { $logData = '#' . $kBestellung . '$' . $oMolliePayment->id; @@ -51,6 +85,11 @@ public static function updateFromPayment(Order $oMolliePayment, $kBestellung = n ); } + /** + * @param $kBestellung + * @return array|bool|int|object + * @deprecated + */ public static function getPayment($kBestellung) { $payment = Shop::DB()->executeQueryPrepared('SELECT * FROM ' . self::TABLE . ' WHERE kBestellung = :kBestellung', [':kBestellung' => $kBestellung], 1); @@ -60,6 +99,11 @@ public static function getPayment($kBestellung) return $payment; } + /** + * @param $kID + * @return array|bool|int|object + * @deprecated + */ public static function getPaymentMollie($kID) { $payment = Shop::DB()->executeQueryPrepared('SELECT * FROM ' . self::TABLE . ' WHERE kID = :kID', [':kID' => $kID], 1); @@ -72,6 +116,7 @@ public static function getPaymentMollie($kID) /** * @param $cHash * @return array|int|object + * @deprecated */ public static function getPaymentHash($cHash) { @@ -81,4 +126,12 @@ public static function getPaymentHash($cHash) } return $payment; } + + public function save() + { + if (!$this->dCreatedAt) { + $this->dCreatedAt = date('Y-m-d H:i:s'); + } + return parent::save(); + } } diff --git a/version/112/class/Model/Queue.php b/version/112/class/Model/Queue.php new file mode 100644 index 0000000..480339a --- /dev/null +++ b/version/112/class/Model/Queue.php @@ -0,0 +1,41 @@ +cResult = $result; + $this->dDone = $date ?: date('Y-m-d H:i:s'); + return $this->save(); + } + + public function save() + { + if (!$this->dCreated) { + $this->dCreated = date('Y-m-d H:i:s'); + } + $this->dModified = date('Y-m-d H:i:s'); + return parent::save(); + } + +} \ No newline at end of file diff --git a/version/112/class/Mollie.php b/version/112/class/Mollie.php index e1921c1..28416fc 100644 --- a/version/112/class/Mollie.php +++ b/version/112/class/Mollie.php @@ -23,6 +23,11 @@ use WarenkorbPos; use ws_mollie\Model\Payment; +/** + * Class Mollie + * @package ws_mollie + * @deprecated + */ abstract class Mollie { protected static $_jtlmollie; diff --git a/version/112/class/Queue.php b/version/112/class/Queue.php new file mode 100644 index 0000000..e352499 --- /dev/null +++ b/version/112/class/Queue.php @@ -0,0 +1,65 @@ +cType))) { + try { + switch ($type) { + case 'webhook': + self::handleWebhook($id, $todo); + break; + + case 'hook': + self::handleHook((int)$id, $todo); + break; + } + + } catch (Exception $e) { + \Jtllog::writeLog($e->getMessage() . " ({$type}, {$id})"); + $todo->done("{$e->getMessage()}\n{$e->getFile()}:{$e->getLine()}\n{$e->getTraceAsString()}"); + } + } + } + } + + private static function getOpen($limit) + { + $open = Shop::DB()->executeQueryPrepared(sprintf("SELECT * FROM %s WHERE dDone IS NULL ORDER BY dCreated DESC LIMIT 0, :LIMIT;", QueueModel::TABLE), [ + ':LIMIT' => $limit + ], 2); + + foreach ($open as $_raw) { + $queueModel = new QueueModel($_raw); + yield $queueModel; + } + } + + protected static function handleWebhook($id, QueueModel $todo) + { + //TODO + } + + protected static function handleHook($hook, QueueModel $todo) + { + //TODO + } + +} \ No newline at end of file diff --git a/version/112/class/Traits/Jsonable.php b/version/112/class/Traits/Jsonable.php new file mode 100644 index 0000000..a950e95 --- /dev/null +++ b/version/112/class/Traits/Jsonable.php @@ -0,0 +1,20 @@ +jsonSerialize(); + } + + public function jsonSerialize() + { + return array_filter(get_object_vars($this), function ($value) { + return $value === null || (is_string($value) && $value === '') ? false : true; + }); + } +} \ No newline at end of file diff --git a/version/112/class/Traits/Plugin.php b/version/112/class/Traits/Plugin.php new file mode 100644 index 0000000..0c3db22 --- /dev/null +++ b/version/112/class/Traits/Plugin.php @@ -0,0 +1,26 @@ +getRequestData()) { + $this->loadRequest(); + } + return $this->requestData[$key] ?: null; + } + + /** + * @return array|null + */ + public function getRequestData() + { + return $this->requestData; + } + + /** + * @param array $options + * @return $this + */ + abstract public function loadRequest($options = []); + + /** + * @param $key + * @param $value + * @return $this + */ + public function setRequestData($key, $value) + { + if (!$this->requestData) { + $this->requestData = []; + } + $this->requestData[$key] = $value; + return $this; + } + +} \ No newline at end of file diff --git a/version/112/frontend/.htaccess b/version/112/frontend/.htaccess new file mode 100644 index 0000000..df6c074 --- /dev/null +++ b/version/112/frontend/.htaccess @@ -0,0 +1,9 @@ + + + Require all granted + + + Order Allow,Deny + Allow from all + + diff --git a/version/112/frontend/131_globalinclude.php b/version/112/frontend/131_globalinclude.php index 5778e21..bc6e15f 100644 --- a/version/112/frontend/131_globalinclude.php +++ b/version/112/frontend/131_globalinclude.php @@ -1,118 +1,124 @@ 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(); + ifndef('MOLLIE_QUEUE_MAX', 3); + // TODO + //Queue::run(MOLLIE_QUEUE_MAX); + AbstractCheckout::sendReminders(); + + +// ob_start(); +// +// if (array_key_exists('mollie', $_REQUEST)) { +// +// require_once __DIR__ . '/../paymentmethod/JTLMollie.php'; +// +// if ($oZahlungSession = JTLMollie::getZahlungSession($_REQUEST['mollie'])) { +// +// $logData = '$' . $oZahlungSession->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/112/frontend/132_headPostGet.php b/version/112/frontend/132_headPostGet.php new file mode 100644 index 0000000..94afd33 --- /dev/null +++ b/version/112/frontend/132_headPostGet.php @@ -0,0 +1,17 @@ +oPluginSprachvariableAssoc_arr['error_' . $status]; +// pq('#fieldset-payment')->prepend('
' . $text . '
'); +// } + +// TODO STYLES +// 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 +// ); - if (array_key_exists('mollieStatus', $_REQUEST)) { - $status = $_REQUEST['mollieStatus']; - $text = Helper::oPlugin()->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/112/frontend/144_notify.php b/version/112/frontend/144_notify.php deleted file mode 100644 index d1826a4..0000000 --- a/version/112/frontend/144_notify.php +++ /dev/null @@ -1,63 +0,0 @@ - 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/112/frontend/180_checkbox.php b/version/112/frontend/180_checkbox.php new file mode 100644 index 0000000..6c1de06 --- /dev/null +++ b/version/112/frontend/180_checkbox.php @@ -0,0 +1,19 @@ +oPluginEinstellungAssoc_arr['useCustomerAPI'] === 'C') { + // TODO + // Checkbox::execute(isset($args_arr) ? $args_arr : []); + } + +} catch (Exception $e) { + Helper::logExc($e); +} \ No newline at end of file diff --git a/version/112/frontend/181_sync.php b/version/112/frontend/181_sync.php index 86c610c..22022a9 100644 --- a/version/112/frontend/181_sync.php +++ b/version/112/frontend/181_sync.php @@ -1,43 +1,14 @@ 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/112/frontend/210_storno.php b/version/112/frontend/210_storno.php new file mode 100644 index 0000000..f8e0dc8 --- /dev/null +++ b/version/112/frontend/210_storno.php @@ -0,0 +1,17 @@ + + // + diff --git a/version/112/paymentmethod/JTLMollie.php b/version/112/paymentmethod/JTLMollie.php index 4cb327c..d969dc9 100644 --- a/version/112/paymentmethod/JTLMollie.php +++ b/version/112/paymentmethod/JTLMollie.php @@ -6,11 +6,12 @@ use Mollie\Api\Exceptions\ApiException; use Mollie\Api\Exceptions\IncompatiblePlatform; use Mollie\Api\MollieApiClient; -use Mollie\Api\Resources\Order; use Mollie\Api\Types\OrderLineType; -use Mollie\Api\Types\OrderStatus; +use ws_mollie\API; +use ws_mollie\Checkout\OrderCheckout; +use ws_mollie\Checkout\PaymentCheckout; use ws_mollie\Helper; -use ws_mollie\Model\Payment; +use ws_mollie\Model\Customer; use ws_mollie\Mollie; require_once __DIR__ . '/../../../vendor/autoload.php'; @@ -20,29 +21,35 @@ class JTLMollie extends PaymentMethod { - const MAX_EXPIRY_DAYS = 100; + use \ws_mollie\Traits\Plugin; - const KUNDENATTRIBUT_CUSTOMERID = 'ws_mollie_customer_id'; + /** + * @deprecated + */ + const MAX_EXPIRY_DAYS = 100; - const ALLOW_PAYMENT_BEFORE_ORDER = true; + const ALLOW_PAYMENT_BEFORE_ORDER = false; /** * PaymentMethod identifier */ - const MOLLIE_METHOD = ""; + const METHOD = ""; /** * Use OrderAPI for this PaymentMethod + * @deprecated */ const ORDER_API = true; /** * @var Helper + * @deprecated */ protected static $_helper; /** * @var MollieApiClient + * @deprecated */ protected static $_mollie; /** @@ -51,18 +58,19 @@ class JTLMollie extends PaymentMethod protected static $_possiblePaymentMethods = []; /** * @var string + * @deprecated */ public $cBild; public function __construct($moduleID, $nAgainCheckout = 0) { parent::__construct($moduleID, $nAgainCheckout); - Helper::init(); - $this->cModulId = "kPlugin_" . Helper::oPlugin()->kPlugin . "_mollie{$moduleID}"; + $this->cModulId = "kPlugin_" . self::Plugin()->kPlugin . "_mollie{$moduleID}"; } /** * @return Helper + * @deprecated */ public static function Helper() { @@ -72,6 +80,72 @@ public static function Helper() return self::$_helper; } + /** + * @param $hash + * @return array|bool|int|object + * @deprecated + */ + public static function getZahlungSession($hash) + { + return Shop::DB()->executeQueryPrepared("SELECT * FROM tzahlungsession WHERE MD5(cZahlungsID) = :cZahlungsID", [':cZahlungsID' => trim($hash, '_')], 1); + } + + /** + * @param $method + * @param $locale + * @param $billingCountry + * @param $currency + * @param $amount + * @return mixed|null + * @throws ApiException + * @throws IncompatiblePlatform + * @deprecated + */ + 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]; + } + + /** + * @return MollieApiClient + * @throws ApiException + * @throws IncompatiblePlatform + * @deprecated + */ + 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 Object $payment (Key, Zahlungsanbieter, Abgeholt, Zeit is set here) @@ -140,177 +214,392 @@ public function setOrderStatusToPaid($order) */ public function preparePaymentProcess($order) { - $logData = '#' . $order->kBestellung . "?" . $order->cBestellNr; - $payable = (float)$order->fGesamtsumme > 0; + parent::preparePaymentProcess($order); + + try { - $_SESSION['MOLLIE_CHECKBOXES'] = []; - foreach ($_POST as $key => $value) { - if (strpos($key, 'CheckBox_') !== false) { - $_SESSION['MOLLIE_CHECKBOXES'][$key] = $value; + if ($this->duringCheckout) { + $this->doLog(sprintf("Zahlung vor Bestellabschluss nicht unterstützt (%s)!", $order->cBestellNr), LOGLEVEL_ERROR); + return; } - } + $payable = (float)$order->fGesamtsumme > 0; + if (!$payable) { + $this->doLog(sprintf("Bestellung '%s': Gesamtsumme %.2f, keine Zahlung notwendig!", $order->cBestellNr, $order->fGesamtsumme), LOGLEVEL_NOTICE); + return; + } - if ($payable) { - $this->updateMollieCustomer($_SESSION['Kunde']); - } + $paymentOptions = []; - try { + if ((int)Session::getInstance()->Customer()->nRegistriert && ($customerID = Customer::createOrUpdate(Session::getInstance()->Customer()))) { + $paymentOptions['customerId'] = $customerID; + } - 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 && $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); - } + // TODO: Options in info XML anlegen + $api = self::Plugin()->oPluginEinstellungAssoc_arr[$this->moduleID . '_api']; + + $paymentOptions = array_merge($paymentOptions, $this->getPaymentOptions($order, $api)); + + if ($api === 'payment') { + $checkout = new PaymentCheckout($order); + $payment = $checkout->create($paymentOptions); + $url = $payment->getCheckoutUrl(); + } else { + $checkout = new OrderCheckout($order); + $mOrder = $checkout->create($paymentOptions); + $url = $mOrder->getCheckoutUrl(); + } + + ifndef('MOLLIE_REDIRECT_DELAY', 3); + $checkoutMode = self::Plugin()->oPluginEinstellungAssoc_arr['checkoutMode']; + Shop::Smarty()->assign('redirect', $url) + ->assign('checkoutMode', $checkoutMode); + if ($checkoutMode === 'Y' && !headers_sent()) { + header('Location: ' . $url); } + + } catch (Exception $e) { - $this->doLog("Get Payment Error: " . $e->getMessage() . ". Create new ORDER...", $logData, LOGLEVEL_ERROR); + + $this->doLog('mollie::preparePaymentProcess: ' . $e->getMessage() . ' - ' . print_r(['cBestellNr' => $order->cBestellNr], 1), LOGLEVEL_ERROR); + Shop::Smarty()->assign('oMollieException', $e); + } - try { +// $logData = '#' . $order->kBestellung . "?" . $order->cBestellNr; +// +// $payable = (float)$order->fGesamtsumme > 0; +// +// $_SESSION['MOLLIE_CHECKBOXES'] = []; +// foreach ($_POST as $key => $value) { +// if (strpos($key, 'CheckBox_') !== false) { +// $_SESSION['MOLLIE_CHECKBOXES'][$key] = $value; +// } +// } +// +// +// 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 && $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; +// unset($_SESSION['mollieCardToken'], $_SESSION['mollieCardTokenTS']); +// } 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(); +// } + } + public function getPaymentOptions(Bestellung $order, $apiType) + { + return []; + } - 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(); - } + /** + * @param Bestellung $order + * @param string $hash + * @param array $args + */ + public function handleNotification($order, $hash, $args) + { - 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; - unset($_SESSION['mollieCardToken'], $_SESSION['mollieCardTokenTS']); - } 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(); - } + parent::handleNotification($order, $hash, $args); + + try { - if (!$oMolliePayment->getCheckoutUrl() && ($oMolliePayment->isAuthorized() || $oMolliePayment->isPaid())) { - header('Location: ' . $oMolliePayment->redirectUrl); - echo "redirect to order ..."; + $orderId = $args['id']; + $checkout = null; + if (strpos($orderId, 'tr_') === 0) { + $checkout = new PaymentCheckout($order); } else { - header('Location: ' . $oMolliePayment->getCheckoutUrl()); - echo "redirect to payment ..."; + $checkout = new OrderCheckout($order); } - 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(); + $checkout->handleNotification($hash); + + } catch (Exception $e) { + $this->doLog("mollie::handleNotification: Bestellung '{$order->cBestellNr}': {$e->getMessage()}", LOGLEVEL_ERROR); + Jtllog::writeLog($e->getMessage() . print_r($_REQUEST)); } + + +// $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 $oKunde Kunde + * @param Bestellung $order + * @param string $hash + * @param array $args + * + * @return boolean, true, if $order should be finalized */ - public function updateMollieCustomer($oKunde) + public function finalizeOrder($order, $hash, $args) { - - return; - -// if (!$oKunde->kKunde || (int)$oKunde->nRegistriert <= 0) { -// return; +// if (array_key_exists('MOLLIE_CHECKBOXES', $_SESSION) && is_array($_SESSION['MOLLIE_CHECKBOXES'])) { +// $_POST = array_merge($_POST, $_SESSION['MOLLIE_CHECKBOXES']); // } +// $result = false; // 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); -// } -// } +// if ($oZahlungSession = self::getZahlungSession(md5($hash))) { +// if ((int)$oZahlungSession->kBestellung <= 0) { // -// $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, -// ]); +// $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 { -// Shop::DB()->update('xplugin_ws_mollie_kunde', 'kKunde', (int)$oKunde->kKunde, (object)[ -// 'customerId' => $customer->id, -// ]); +// $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) { -// Helper::logExc($e); +// $this->doLog('JTLMollie::finalizeOrder: ' . $e->getMessage(), "#" . $hash); // } +// return $result; } /** - * @return MollieApiClient + * @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 (API::getMode()) { + $selectable = trim(self::Plugin()->oPluginEinstellungAssoc_arr['test_apiKey']) !== ''; + } else { + $selectable = trim(self::Plugin()->oPluginEinstellungAssoc_arr['apiKey']) !== ''; + if (!$selectable) { + $this->doLog("Live API Key missing!", LOGLEVEL_ERROR); + } + } + if ($selectable) { + try { + $locale = \ws_mollie\Checkout\Payment\Locale::getLocale(Session::getInstance()->Language()->getIso(), Session::getInstance()->Customer()->cLand); + $amount = Session::getInstance()->Basket()->gibGesamtsummeWaren(true) * Session::getInstance()->Currency()->fFaktor; + if ($amount <= 0) { + $amount = 0.01; + } + $selectable = self::isMethodPossible( + static::METHOD, + $locale, + Session::getInstance()->Customer()->cLand, + Session::getInstance()->Currency()->cISO, + $amount + ); + } catch (Exception $e) { + $selectable = false; + } + } + return $selectable && parent::isSelectable(); + /* + + + if (array_key_exists('mollieDeleteToken', $_REQUEST) && (int)$_REQUEST['mollieDeleteToken'] === 1) { + unset($_SESSION['mollieCardToken']); + unset($_SESSION['mollieCardTokenTS']); + } + + + $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 bool * @throws ApiException - * @throws IncompatiblePlatform */ - public static function API() + protected static function isMethodPossible($method, $locale, $billingCountry, $currency, $amount) { - 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); + + $api = new API(API::getMode()); + + if (!array_key_exists('mollie_possibleMethods', $_SESSION)) { + $_SESSION['mollie_possibleMethods'] = []; } - return self::$_mollie; + + $key = md5(serialize([$locale, $billingCountry, $currency, $amount])); + if (!array_key_exists($key, $_SESSION['mollie_possibleMethods'])) { + $_SESSION['mollie_possibleMethods'][$key] = $api->Client()->methods->allActive([ + 'locale' => $locale, + 'amount' => [ + 'currency' => $currency, + 'value' => number_format($amount, 2, ".", "") + ], + 'billingCountry' => $billingCountry, + 'resource' => 'orders', + 'includeWallets' => 'applepay', + ]); + } + + if ($method !== '') { + foreach ($_SESSION['mollie_possibleMethods'][$key] as $m) { + if ($m->id === $method) { + return true; + } + } + } else { + return true; + } + + return false; + + } + + /** + * @param array $args_arr + * @return bool + */ + public function isValidIntern($args_arr = []) + { + return $this->duringCheckout + ? static::ALLOW_PAYMENT_BEFORE_ORDER && parent::isValidIntern($args_arr) + : parent::isValidIntern($args_arr); } /** * @param Bestellung $order * @param $hash * @return array + * @deprecated */ protected function getOrderData(Bestellung $order, $hash) { @@ -516,6 +805,12 @@ protected function getOrderData(Bestellung $order, $hash) return $data; } + /** + * @param $cISOSprache + * @param null $country + * @return string + * @deprecated + */ public static function getLocale($cISOSprache, $country = null) { switch ($cISOSprache) { @@ -564,6 +859,7 @@ public static function getLocale($cISOSprache, $country = null) /** * @return int + * @deprecated */ public function getExpiryDays() { @@ -574,6 +870,11 @@ public function getExpiryDays() return (int)min($local > 0 ? $local : $global, $global, $max); } + /** + * @param $gesamtsumme + * @return float|int|mixed + * @deprecated + */ public function optionaleRundung($gesamtsumme) { $conf = Shop::getSettings([CONF_KAUFABWICKLUNG]); @@ -593,6 +894,11 @@ public function optionaleRundung($gesamtsumme) return $gesamtsumme; } + /** + * @param $kKunde + * @return false + * @deprecated + */ public static function getMollieCustomerId($kKunde) { //if ($row = Shop::DB()->select('xplugin_ws_mollie_kunde', 'kKunde', (int)$kKunde)) { @@ -601,180 +907,10 @@ public static function getMollieCustomerId($kKunde) 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) - { - if (array_key_exists('MOLLIE_CHECKBOXES', $_SESSION) && is_array($_SESSION['MOLLIE_CHECKBOXES'])) { - $_POST = array_merge($_POST, $_SESSION['MOLLIE_CHECKBOXES']); - } - $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 + * @deprecated */ protected function updatePaymentMethod($cISOSprache, $method) { @@ -797,17 +933,4 @@ protected function updatePaymentMethod($cISOSprache, $method) ], 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/112/paymentmethod/JTLMollieApplePay.php b/version/112/paymentmethod/JTLMollieApplePay.php index ecf20a8..4b23bf4 100644 --- a/version/112/paymentmethod/JTLMollieApplePay.php +++ b/version/112/paymentmethod/JTLMollieApplePay.php @@ -1,8 +1,15 @@ oRechnungsadresse->cMail; + $paymentOptions['locale'] = \ws_mollie\Checkout\Payment\Locale::getLocale(Session::getInstance()->Language()->getIso(), $order->oRechnungsadresse->cLand); + } + // TODO Option + $dueDays = (int)self::Plugin()->oPluginEinstellungAssoc_arr[$this->moduleID . '_dueDays']; + if ($dueDays > 3) { + $paymentOptions['dueDate'] = date('Y-m-d', strtotime("+{$dueDays} DAYS")); + } + return $paymentOptions; + } } diff --git a/version/112/paymentmethod/JTLMollieBelfius.php b/version/112/paymentmethod/JTLMollieBelfius.php index 1347b8e..91a6169 100644 --- a/version/112/paymentmethod/JTLMollieBelfius.php +++ b/version/112/paymentmethod/JTLMollieBelfius.php @@ -4,5 +4,5 @@ class JTLMollieBelfius extends JTLMollie { - const MOLLIE_METHOD = \Mollie\Api\Types\PaymentMethod::BELFIUS; + const METHOD = \Mollie\Api\Types\PaymentMethod::BELFIUS; } diff --git a/version/112/paymentmethod/JTLMollieCreditCard.php b/version/112/paymentmethod/JTLMollieCreditCard.php index f5a8cd3..b25bbad 100644 --- a/version/112/paymentmethod/JTLMollieCreditCard.php +++ b/version/112/paymentmethod/JTLMollieCreditCard.php @@ -1,47 +1,138 @@ clearToken(); + } + + protected function clearToken() + { + $this->unsetCache(self::CACHE_TOKEN) + ->unsetCache(self::CACHE_TOKEN_TIMESTAMP); + return true; + } + + public function handleAdditional($post) { - if(array_key_exists('skip', $aPost_arr) && (int)$aPost_arr['skip']){ - unset($_SESSION['mollieCardToken'], $_SESSION['mollieCardTokenTS']); - return true; + $components = self::Plugin()->oPluginEinstellungAssoc_arr[$this->moduleID . '_components']; + $profileId = self::Plugin()->oPluginEinstellungAssoc_arr['profileId']; + + if ($components === 'N' || !$profileId || trim($profileId) === '') { + return parent::handleAdditional($post); + } + + $cleared = false; + if (array_key_exists('clear', $post) && (int)$post['clear']) { + $cleared = $this->clearToken(); } - $profileId = trim(Helper::getSetting('profileId')); - if ($profileId === '' || strpos($profileId, 'pfl_') !== 0) { - return true; + if ($components === 'S' && array_key_exists('skip', $post) && (int)$post['skip']) { + return parent::handleAdditional($post); } - if (array_key_exists('mollieCardTokenTS', $_SESSION) && (int)$_SESSION['mollieCardTokenTS'] > time() - && array_key_exists('mollieCardToken', $_SESSION) && trim($_SESSION['mollieCardToken']) !== '') { - return true; + + try { + $trustBadge = (bool)self::Plugin()->oPluginEinstellungAssoc_arr[$this->moduleID . '_trustBadge']; + $locale = \ws_mollie\Checkout\Payment\Locale::getLocale(Session::getInstance()->Language()->getIso(), Session::getInstance()->Customer() ? Session::getInstance()->Customer()->cLand : null); + $mode = API::getMode(); + $errorMessage = json_encode(self::Plugin()->oPluginSprachvariableAssoc_arr['mcErrorMessage']); + } catch (Exception $e) { + Jtllog::writeLog($e->getMessage() . "\n" . print_r(['e' => $e], 1)); + return parent::handleAdditional($post); } - unset($_SESSION['mollieCardToken'], $_SESSION['mollieCardTokenTS']); + if (!$cleared && array_key_exists('cardToken', $post) && ($token = trim($post['cardToken']))) { + return $this->setToken($token) && parent::handleAdditional($post); + } - if (array_key_exists('cardToken', $aPost_arr) && trim($aPost_arr['cardToken'])) { - $_SESSION['mollieCardToken'] = trim($aPost_arr['cardToken']); - $_SESSION['mollieCardTokenTS'] = time() + 3600; - return true; + $token = false; + if (($ctTS = (int)$this->getCache(self::CACHE_TOKEN_TIMESTAMP)) && $ctTS > time()) { + $token = $this->getCache(self::CACHE_TOKEN); } 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('skipComponents', Helper::getSetting('skipComponents')) - ->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); + ->assign('trustBadge', $trustBadge ?: false) + ->assign('components', $components) + ->assign('locale', $locale ?: 'de_DE') + ->assign('token', $token ?: false) + ->assign('testMode', $mode ?: false) + ->assign('errorMessage', $errorMessage ?: null) + ->assign('mollieLang', self::Plugin()->oPluginSprachvariableAssoc_arr); return false; + +// if (array_key_exists('skip', $aPost_arr) && (int)$aPost_arr['skip']) { +// unset($_SESSION['mollieCardToken'], $_SESSION['mollieCardTokenTS']); +// return true; +// } +// +// $profileId = trim(Helper::getSetting('profileId')); +// if ($profileId === '' || strpos($profileId, 'pfl_') !== 0) { +// return true; +// } +// if (array_key_exists('mollieCardTokenTS', $_SESSION) && (int)$_SESSION['mollieCardTokenTS'] > time() +// && array_key_exists('mollieCardToken', $_SESSION) && trim($_SESSION['mollieCardToken']) !== '') { +// return true; +// } +// +// unset($_SESSION['mollieCardToken'], $_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('skipComponents', Helper::getSetting('skipComponents')) +// ->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; + } + + protected function setToken($token) + { + $this->addCache(self::CACHE_TOKEN, $token) + ->addCache(self::CACHE_TOKEN_TIMESTAMP, time() + 3600); + return true; + } + + public function getPaymentOptions(Bestellung $order, $apiType) + { + + $paymentOptions = []; + + if ($apiType === 'payment') { + if ($order->Lieferadresse !== null) { + if (!$order->Lieferadresse->cMail) { + $order->Lieferadresse->cMail = $order->oRechnungsadresse->cMail; + } + $paymentOptions['shippingAddress'] = new \ws_mollie\Checkout\Payment\Address($order->Lieferadresse); + } + + $paymentOptions['billingAddress'] = new \ws_mollie\Checkout\Payment\Address($order->oRechnungsadresse); + } + if ((int)$this->getCache(self::CACHE_TOKEN_TIMESTAMP) > time() && ($token = trim($this->getCache(self::CACHE_TOKEN)))) { + $paymentOptions['cardToken'] = $token; + } + return $paymentOptions; } } diff --git a/version/112/paymentmethod/JTLMollieDirectDebit.php b/version/112/paymentmethod/JTLMollieDirectDebit.php index ce0441d..aeb86d3 100644 --- a/version/112/paymentmethod/JTLMollieDirectDebit.php +++ b/version/112/paymentmethod/JTLMollieDirectDebit.php @@ -2,7 +2,16 @@ require_once __DIR__ . '/JTLMollie.php'; +/** + * Class JTLMollieDirectDebit + * @deprecated since 112 + */ class JTLMollieDirectDebit extends JTLMollie { - const MOLLIE_METHOD = \Mollie\Api\Types\PaymentMethod::DIRECTDEBIT; + const METHOD = \Mollie\Api\Types\PaymentMethod::DIRECTDEBIT; + + public function isSelectable() + { + return false; + } } diff --git a/version/112/paymentmethod/JTLMollieEPS.php b/version/112/paymentmethod/JTLMollieEPS.php index 9d06f83..df52c5e 100644 --- a/version/112/paymentmethod/JTLMollieEPS.php +++ b/version/112/paymentmethod/JTLMollieEPS.php @@ -4,5 +4,5 @@ class JTLMollieEPS extends JTLMollie { - const MOLLIE_METHOD = \Mollie\Api\Types\PaymentMethod::EPS; + const METHOD = \Mollie\Api\Types\PaymentMethod::EPS; } diff --git a/version/112/paymentmethod/JTLMollieGiftcard.php b/version/112/paymentmethod/JTLMollieGiftcard.php index 3556aac..79bda4a 100644 --- a/version/112/paymentmethod/JTLMollieGiftcard.php +++ b/version/112/paymentmethod/JTLMollieGiftcard.php @@ -4,5 +4,5 @@ class JTLMollieGiftcard extends JTLMollie { - const MOLLIE_METHOD = \Mollie\Api\Types\PaymentMethod::GIFTCARD; + const METHOD = \Mollie\Api\Types\PaymentMethod::GIFTCARD; } diff --git a/version/112/paymentmethod/JTLMollieGiropay.php b/version/112/paymentmethod/JTLMollieGiropay.php index 9f4232b..071e259 100644 --- a/version/112/paymentmethod/JTLMollieGiropay.php +++ b/version/112/paymentmethod/JTLMollieGiropay.php @@ -4,5 +4,5 @@ class JTLMollieGiropay extends JTLMollie { - const MOLLIE_METHOD = \Mollie\Api\Types\PaymentMethod::GIROPAY; + const METHOD = \Mollie\Api\Types\PaymentMethod::GIROPAY; } diff --git a/version/112/paymentmethod/JTLMollieIDEAL.php b/version/112/paymentmethod/JTLMollieIDEAL.php index e49cbf0..b08d852 100644 --- a/version/112/paymentmethod/JTLMollieIDEAL.php +++ b/version/112/paymentmethod/JTLMollieIDEAL.php @@ -4,5 +4,5 @@ class JTLMollieIDEAL extends JTLMollie { - const MOLLIE_METHOD = \Mollie\Api\Types\PaymentMethod::IDEAL; + const METHOD = \Mollie\Api\Types\PaymentMethod::IDEAL; } diff --git a/version/112/paymentmethod/JTLMollieINGHomePay.php b/version/112/paymentmethod/JTLMollieINGHomePay.php index be1003d..3d730ce 100644 --- a/version/112/paymentmethod/JTLMollieINGHomePay.php +++ b/version/112/paymentmethod/JTLMollieINGHomePay.php @@ -2,7 +2,26 @@ require_once __DIR__ . '/../../../vendor/autoload.php'; require_once __DIR__ . '/JTLMollie.php'; +/** + * Class JTLMollieINGHomePay + * @deprecated since 112 + */ class JTLMollieINGHomePay extends JTLMollie { - const MOLLIE_METHOD = \Mollie\Api\Types\PaymentMethod::INGHOMEPAY; + const METHOD = \Mollie\Api\Types\PaymentMethod::INGHOMEPAY; + + public function isSelectable() + { + return false; + } + + public function isValidIntern($args_arr = []) + { + return false; + } + + public function isValid($customer, $cart) + { + return false; + } } diff --git a/version/112/paymentmethod/JTLMollieKBC.php b/version/112/paymentmethod/JTLMollieKBC.php index 1dc7f07..20d11fb 100644 --- a/version/112/paymentmethod/JTLMollieKBC.php +++ b/version/112/paymentmethod/JTLMollieKBC.php @@ -4,5 +4,10 @@ class JTLMollieKBC extends JTLMollie { - const MOLLIE_METHOD = \Mollie\Api\Types\PaymentMethod::KBC; + const METHOD = \Mollie\Api\Types\PaymentMethod::KBC; + + public function getPaymentOptions(Bestellung $order, $apiType) + { + return ['description' => substr($order->cBestellNr, 0, 13)]; + } } diff --git a/version/112/paymentmethod/JTLMollieKlarnaPayLater.php b/version/112/paymentmethod/JTLMollieKlarnaPayLater.php index 7016c4c..266953f 100644 --- a/version/112/paymentmethod/JTLMollieKlarnaPayLater.php +++ b/version/112/paymentmethod/JTLMollieKlarnaPayLater.php @@ -6,5 +6,5 @@ class JTLMollieKlarnaPayLater extends JTLMollie { const MAX_EXPIRY_DAYS = 28; - const MOLLIE_METHOD = \Mollie\Api\Types\PaymentMethod::KLARNA_PAY_LATER; + const METHOD = \Mollie\Api\Types\PaymentMethod::KLARNA_PAY_LATER; } diff --git a/version/112/paymentmethod/JTLMollieKlarnaSliceIt.php b/version/112/paymentmethod/JTLMollieKlarnaSliceIt.php index e210232..25289e2 100644 --- a/version/112/paymentmethod/JTLMollieKlarnaSliceIt.php +++ b/version/112/paymentmethod/JTLMollieKlarnaSliceIt.php @@ -6,5 +6,5 @@ class JTLMollieKlarnaSliceIt extends JTLMollie { const MAX_EXPIRY_DAYS = 28; - const MOLLIE_METHOD = \Mollie\Api\Types\PaymentMethod::KLARNA_SLICE_IT; + const METHOD = \Mollie\Api\Types\PaymentMethod::KLARNA_SLICE_IT; } diff --git a/version/112/paymentmethod/JTLMollieMyBank.php b/version/112/paymentmethod/JTLMollieMyBank.php index 16051ad..def7553 100644 --- a/version/112/paymentmethod/JTLMollieMyBank.php +++ b/version/112/paymentmethod/JTLMollieMyBank.php @@ -4,5 +4,5 @@ class JTLMollieMyBank extends JTLMollie { - const MOLLIE_METHOD = \Mollie\Api\Types\PaymentMethod::MYBANK; + const METHOD = \Mollie\Api\Types\PaymentMethod::MYBANK; } diff --git a/version/112/paymentmethod/JTLMolliePayPal.php b/version/112/paymentmethod/JTLMolliePayPal.php index 8879991..340e3bf 100644 --- a/version/112/paymentmethod/JTLMolliePayPal.php +++ b/version/112/paymentmethod/JTLMolliePayPal.php @@ -1,8 +1,30 @@ Lieferadresse !== null) { + if (!$order->Lieferadresse->cMail) { + $order->Lieferadresse->cMail = $order->oRechnungsadresse->cMail; + } + $paymentOptions['shippingAddress'] = new Address($order->Lieferadresse); + } + $paymentOptions['description'] = 'Order ' . $order->cBestellNr; + } + + + return $paymentOptions; + } + } diff --git a/version/112/paymentmethod/JTLMolliePaysafecard.php b/version/112/paymentmethod/JTLMolliePaysafecard.php index 3a179b0..920e0fa 100644 --- a/version/112/paymentmethod/JTLMolliePaysafecard.php +++ b/version/112/paymentmethod/JTLMolliePaysafecard.php @@ -4,5 +4,10 @@ class JTLMolliePaysafecard extends JTLMollie { - const MOLLIE_METHOD = \Mollie\Api\Types\PaymentMethod::PAYSAFECARD; + const METHOD = \Mollie\Api\Types\PaymentMethod::PAYSAFECARD; + + public function getPaymentOptions(Bestellung $order, $apiType) + { + return $apiType === 'payment' ? ['customerReference' => $order->oKunde->kKunde] : []; + } } diff --git a/version/112/paymentmethod/JTLMolliePrzelewy24.php b/version/112/paymentmethod/JTLMolliePrzelewy24.php index eaa8099..ebd28ed 100644 --- a/version/112/paymentmethod/JTLMolliePrzelewy24.php +++ b/version/112/paymentmethod/JTLMolliePrzelewy24.php @@ -4,5 +4,12 @@ class JTLMolliePrzelewy24 extends JTLMollie { - const MOLLIE_METHOD = \Mollie\Api\Types\PaymentMethod::PRZELEWY24; + const METHOD = \Mollie\Api\Types\PaymentMethod::PRZELEWY24; + + + public function getPaymentOptions(Bestellung $order, $apiType) + { + return $apiType === 'payment' ? ['billingEmail' => $order->oRechnungsadresse->cMail] : []; + } + } diff --git a/version/112/paymentmethod/JTLMollieSofort.php b/version/112/paymentmethod/JTLMollieSofort.php index 7fd186b..c11060b 100644 --- a/version/112/paymentmethod/JTLMollieSofort.php +++ b/version/112/paymentmethod/JTLMollieSofort.php @@ -4,5 +4,5 @@ class JTLMollieSofort extends JTLMollie { - const MOLLIE_METHOD = \Mollie\Api\Types\PaymentMethod::SOFORT; + const METHOD = \Mollie\Api\Types\PaymentMethod::SOFORT; } diff --git a/version/112/paymentmethod/tpl/bestellabschluss.tpl b/version/112/paymentmethod/tpl/bestellabschluss.tpl index f7680f0..86dbf50 100644 --- a/version/112/paymentmethod/tpl/bestellabschluss.tpl +++ b/version/112/paymentmethod/tpl/bestellabschluss.tpl @@ -2,4 +2,18 @@
{$oMollieException->getMessage()}
-{/if} \ No newline at end of file +{/if} + +{if $redirect != ''} +
+
+ +
+
+ {if $checkoutMode == 'D'} + + {/if} +{/if} + diff --git a/version/112/sql/109.sql b/version/112/sql/109.sql deleted file mode 100644 index 41cda01..0000000 --- a/version/112/sql/109.sql +++ /dev/null @@ -1,2 +0,0 @@ -ALTER TABLE `xplugin_ws_mollie_payments` - ADD `bLockTimeout` tinyint(1) NOT NULL; \ No newline at end of file diff --git a/version/112/sql/112.sql b/version/112/sql/112.sql new file mode 100644 index 0000000..e37fe15 --- /dev/null +++ b/version/112/sql/112.sql @@ -0,0 +1,16 @@ +ALTER TABLE `xplugin_ws_mollie_payments` + ADD `bSynced` tinyint(1) NOT NULL; + +UPDATE xplugin_ws_mollie_payments SET bSynced = true; + +CREATE TABLE IF NOT EXISTS `xplugin_ws_mollie_queue` ( + `kId` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY, + `cType` VARCHAR(32) NOT NULL, + `cData` TEXT DEFAULT '', + `cResult` TEXT NULL DEFAULT NULL, + `dDone` DATETIME NULL DEFAULT NULL, + `dCreated` DATETIME NOT NULL, + `dModified` DATETIME NULL DEFAULT NULL +); + +ALTER TABLE xplugin_ws_mollie_payments ADD dReminder DATETIME NULL DEFAULT NULL; \ No newline at end of file From 522630f86e20dec8d3a378462030618e44ffce5c Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Wed, 7 Apr 2021 18:27:33 +0200 Subject: [PATCH 175/280] cleanup --- version/112/frontend/131_globalinclude.php | 101 ---- version/112/paymentmethod/JTLMollie.php | 611 +-------------------- 2 files changed, 11 insertions(+), 701 deletions(-) diff --git a/version/112/frontend/131_globalinclude.php b/version/112/frontend/131_globalinclude.php index bc6e15f..07c716c 100644 --- a/version/112/frontend/131_globalinclude.php +++ b/version/112/frontend/131_globalinclude.php @@ -18,107 +18,6 @@ //Queue::run(MOLLIE_QUEUE_MAX); AbstractCheckout::sendReminders(); - -// ob_start(); -// -// if (array_key_exists('mollie', $_REQUEST)) { -// -// require_once __DIR__ . '/../paymentmethod/JTLMollie.php'; -// -// if ($oZahlungSession = JTLMollie::getZahlungSession($_REQUEST['mollie'])) { -// -// $logData = '$' . $oZahlungSession->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/112/paymentmethod/JTLMollie.php b/version/112/paymentmethod/JTLMollie.php index d969dc9..245e0ff 100644 --- a/version/112/paymentmethod/JTLMollie.php +++ b/version/112/paymentmethod/JTLMollie.php @@ -1,18 +1,11 @@ cModulId = "kPlugin_" . self::Plugin()->kPlugin . "_mollie{$moduleID}"; } - /** - * @return Helper - * @deprecated - */ - public static function Helper() - { - if (self::$_helper === null) { - self::$_helper = new ws_mollie\Helper(); - } - return self::$_helper; - } - - /** - * @param $hash - * @return array|bool|int|object - * @deprecated - */ - public static function getZahlungSession($hash) - { - return Shop::DB()->executeQueryPrepared("SELECT * FROM tzahlungsession WHERE MD5(cZahlungsID) = :cZahlungsID", [':cZahlungsID' => trim($hash, '_')], 1); - } - - /** - * @param $method - * @param $locale - * @param $billingCountry - * @param $currency - * @param $amount - * @return mixed|null - * @throws ApiException - * @throws IncompatiblePlatform - * @deprecated - */ - 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]; - } - - /** - * @return MollieApiClient - * @throws ApiException - * @throws IncompatiblePlatform - * @deprecated - */ - 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 Object $payment (Key, Zahlungsanbieter, Abgeholt, Zeit is set here) - * @return $this - * @throws Exception - */ - public function addIncomingPayment($order, $payment) - { - $model = (object)array_merge([ - 'kBestellung' => (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 @@ -258,105 +106,22 @@ public function preparePaymentProcess($order) if ($checkoutMode === 'Y' && !headers_sent()) { header('Location: ' . $url); } - - } catch (Exception $e) { - $this->doLog('mollie::preparePaymentProcess: ' . $e->getMessage() . ' - ' . print_r(['cBestellNr' => $order->cBestellNr], 1), LOGLEVEL_ERROR); Shop::Smarty()->assign('oMollieException', $e); - } + } - -// $logData = '#' . $order->kBestellung . "?" . $order->cBestellNr; -// -// $payable = (float)$order->fGesamtsumme > 0; -// -// $_SESSION['MOLLIE_CHECKBOXES'] = []; -// foreach ($_POST as $key => $value) { -// if (strpos($key, 'CheckBox_') !== false) { -// $_SESSION['MOLLIE_CHECKBOXES'][$key] = $value; -// } -// } -// -// -// 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 && $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; -// unset($_SESSION['mollieCardToken'], $_SESSION['mollieCardTokenTS']); -// } 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 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; } public function getPaymentOptions(Bestellung $order, $apiType) @@ -371,11 +136,8 @@ public function getPaymentOptions(Bestellung $order, $apiType) */ public function handleNotification($order, $hash, $args) { - parent::handleNotification($order, $hash, $args); - try { - $orderId = $args['id']; $checkout = null; if (strpos($orderId, 'tr_') === 0) { @@ -389,58 +151,6 @@ public function handleNotification($order, $hash, $args) $this->doLog("mollie::handleNotification: Bestellung '{$order->cBestellNr}': {$e->getMessage()}", LOGLEVEL_ERROR); Jtllog::writeLog($e->getMessage() . print_r($_REQUEST)); } - - -// $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) - { -// if (array_key_exists('MOLLIE_CHECKBOXES', $_SESSION) && is_array($_SESSION['MOLLIE_CHECKBOXES'])) { -// $_POST = array_merge($_POST, $_SESSION['MOLLIE_CHECKBOXES']); -// } -// $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; } /** @@ -595,268 +305,6 @@ public function isValidIntern($args_arr = []) : parent::isValidIntern($args_arr); } - /** - * @param Bestellung $order - * @param $hash - * @return array - * @deprecated - */ - protected function getOrderData(Bestellung $order, $hash) - { - $locale = self::getLocale($_SESSION['cISOSprache'], $_SESSION['Kunde']->cLand); - $expiryDays = $this->getExpiryDays(); - $_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, '_')), - 'expiresAt' => date('Y-m-d', strtotime("+{$expiryDays} DAYS")) - ]; - - if (static::MOLLIE_METHOD !== '') { - $data['method'] = static::MOLLIE_METHOD; - } - - if (static::MOLLIE_METHOD === \Mollie\Api\Types\PaymentMethod::CREDITCARD - && array_key_exists('mollieCardToken', $_SESSION) - && array_key_exists('mollieCardTokenTS', $_SESSION) && time() < (int)$_SESSION['mollieCardTokenTS']) { - $data['payment'] = new stdClass(); - $data['payment']->cardToken = trim($_SESSION['mollieCardToken']); - } else { - unset($_SESSION['mollieCardToken'], $_SESSION['mollieCardTokenTS']); - } - - 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 .= utf8_encode(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; - } - - /** - * @param $cISOSprache - * @param null $country - * @return string - * @deprecated - */ - 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"; - } - } - /** * @return int * @deprecated @@ -870,43 +318,6 @@ public function getExpiryDays() return (int)min($local > 0 ? $local : $global, $global, $max); } - /** - * @param $gesamtsumme - * @return float|int|mixed - * @deprecated - */ - 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; - } - - /** - * @param $kKunde - * @return false - * @deprecated - */ - public static function getMollieCustomerId($kKunde) - { - //if ($row = Shop::DB()->select('xplugin_ws_mollie_kunde', 'kKunde', (int)$kKunde)) { - // return $row->customerId; - //} - return false; - } - /** * @param $cISOSprache * @param $method From 22c1db2ab308c91f9aadbcf7cee527b5eb62079c Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Thu, 8 Apr 2021 11:48:59 +0200 Subject: [PATCH 176/280] cleanup --- info.xml | 646 ++++++++++++------ .../112/paymentmethod/JTLMollieGiftcard.php | 8 - version/112/sql/112.sql | 16 - version/{112 => 200}/adminmenu/info.php | 5 +- version/{112 => 200}/adminmenu/orders.php | 12 +- .../{112 => 200}/adminmenu/paymentmethods.php | 3 +- version/{112 => 200}/adminmenu/tpl/info.tpl | 6 +- .../tpl/mollie-account-erstellen.png | Bin version/{112 => 200}/adminmenu/tpl/order.tpl | 2 +- version/{112 => 200}/adminmenu/tpl/orders.tpl | 4 +- .../adminmenu/tpl/paymentmethods.tpl | 0 version/{112 => 200}/class/API.php | 14 +- .../class/Checkout/AbstractCheckout.php | 29 +- .../class/Checkout/Order/Address.php | 0 .../class/Checkout/Order/OrderLine.php | 17 +- .../class/Checkout/OrderCheckout.php | 55 +- .../class/Checkout/Payment/Address.php | 8 +- .../class/Checkout/Payment/Amount.php | 26 +- .../class/Checkout/Payment/Locale.php | 2 +- .../class/Checkout/PaymentCheckout.php | 27 +- version/{112 => 200}/class/ExclusiveLock.php | 9 +- version/{112 => 200}/class/Helper.php | 5 +- .../{112 => 200}/class/Hook/AbstractHook.php | 0 version/{112 => 200}/class/Hook/ApplePay.php | 3 +- version/{112 => 200}/class/Hook/Queue.php | 12 +- .../class/Model/AbstractModel.php | 5 +- version/{112 => 200}/class/Model/Customer.php | 14 +- version/{112 => 200}/class/Model/Payment.php | 4 +- version/{112 => 200}/class/Model/Queue.php | 0 version/{112 => 200}/class/Mollie.php | 23 +- version/{112 => 200}/class/Queue.php | 12 +- .../{112 => 200}/class/Traits/Jsonable.php | 4 +- version/{112 => 200}/class/Traits/Plugin.php | 0 .../{112 => 200}/class/Traits/RequestData.php | 12 +- version/{112 => 200}/frontend/.htaccess | 0 .../frontend/131_globalinclude.php | 4 +- .../{112 => 200}/frontend/132_headPostGet.php | 0 version/{112 => 200}/frontend/140_smarty.php | 0 .../{112 => 200}/frontend/180_checkbox.php | 0 version/{112 => 200}/frontend/181_sync.php | 0 version/{112 => 200}/frontend/210_storno.php | 0 .../frontend/75_bestellungInDb.php | 2 +- version/{112 => 200}/frontend/applepay.php | 0 .../{112 => 200}/frontend/img/trust_eng.png | Bin .../{112 => 200}/frontend/img/trust_fre.png | Bin .../{112 => 200}/frontend/img/trust_ger.png | Bin .../{112 => 200}/frontend/tpl/applepay.tpl | 4 +- .../{112 => 200}/paymentmethod/JTLMollie.php | 20 +- .../paymentmethod/JTLMollieApplePay.php | 0 .../paymentmethod/JTLMollieBancontact.php | 0 .../paymentmethod/JTLMollieBanktransfer.php | 6 +- .../paymentmethod/JTLMollieBelfius.php | 0 .../paymentmethod/JTLMollieCreditCard.php | 21 +- .../paymentmethod/JTLMollieDirectDebit.php | 10 + .../paymentmethod/JTLMollieEPS.php | 0 .../200/paymentmethod/JTLMollieGiftcard.php | 27 + .../paymentmethod/JTLMollieGiropay.php | 0 .../paymentmethod/JTLMollieIDEAL.php | 0 .../paymentmethod/JTLMollieINGHomePay.php | 1 + .../paymentmethod/JTLMollieKBC.php | 0 .../paymentmethod/JTLMollieKlarnaPayLater.php | 0 .../paymentmethod/JTLMollieKlarnaSliceIt.php | 0 .../paymentmethod/JTLMollieMyBank.php | 0 .../paymentmethod/JTLMolliePayPal.php | 0 .../paymentmethod/JTLMolliePaysafecard.php | 0 .../paymentmethod/JTLMolliePrzelewy24.php | 0 .../paymentmethod/JTLMollieSofort.php | 0 .../img/method/Przelewy24@2x.png | Bin .../paymentmethod/img/method/applepay@2x.png | Bin .../img/method/bancontact@2x.png | Bin .../img/method/banktransfer@2x.png | Bin .../paymentmethod/img/method/belfius@2x.png | Bin .../img/method/creditcard@2x.png | Bin .../img/method/directdebit@2x.png | Bin .../paymentmethod/img/method/eps@2x.png | Bin .../paymentmethod/img/method/giftcard@2x.png | Bin .../paymentmethod/img/method/giropay@2x.png | Bin .../paymentmethod/img/method/ideal@2x.png | Bin .../img/method/inghomepay@2x.png | Bin .../paymentmethod/img/method/kbc@2x.png | Bin .../paymentmethod/img/method/klarna@2x.png | Bin .../paymentmethod/img/method/mollie@2x.png | Bin .../paymentmethod/img/method/mybank@2x.png | Bin .../paymentmethod/img/method/paypal@2x.png | Bin .../img/method/paysafecard@2x.png | Bin .../paymentmethod/img/method/sofort@2x.png | Bin .../paymentmethod/tpl/bestellabschluss.tpl | 0 .../paymentmethod/tpl/mollieComponents.tpl | 26 +- version/200/sql/200.sql | 19 + version/{112 => 200}/tpl/_alerts.tpl | 0 90 files changed, 719 insertions(+), 404 deletions(-) delete mode 100644 version/112/paymentmethod/JTLMollieGiftcard.php delete mode 100644 version/112/sql/112.sql rename version/{112 => 200}/adminmenu/info.php (96%) rename version/{112 => 200}/adminmenu/orders.php (96%) rename version/{112 => 200}/adminmenu/paymentmethods.php (98%) rename version/{112 => 200}/adminmenu/tpl/info.tpl (96%) rename version/{112 => 200}/adminmenu/tpl/mollie-account-erstellen.png (100%) rename version/{112 => 200}/adminmenu/tpl/order.tpl (99%) rename version/{112 => 200}/adminmenu/tpl/orders.tpl (98%) rename version/{112 => 200}/adminmenu/tpl/paymentmethods.tpl (100%) rename version/{112 => 200}/class/API.php (81%) rename version/{112 => 200}/class/Checkout/AbstractCheckout.php (97%) rename version/{112 => 200}/class/Checkout/Order/Address.php (100%) rename version/{112 => 200}/class/Checkout/Order/OrderLine.php (92%) rename version/{112 => 200}/class/Checkout/OrderCheckout.php (76%) rename version/{112 => 200}/class/Checkout/Payment/Address.php (85%) rename version/{112 => 200}/class/Checkout/Payment/Amount.php (84%) rename version/{112 => 200}/class/Checkout/Payment/Locale.php (99%) rename version/{112 => 200}/class/Checkout/PaymentCheckout.php (78%) rename version/{112 => 200}/class/ExclusiveLock.php (88%) rename version/{112 => 200}/class/Helper.php (98%) rename version/{112 => 200}/class/Hook/AbstractHook.php (100%) rename version/{112 => 200}/class/Hook/ApplePay.php (96%) rename version/{112 => 200}/class/Hook/Queue.php (89%) rename version/{112 => 200}/class/Model/AbstractModel.php (90%) rename version/{112 => 200}/class/Model/Customer.php (82%) rename version/{112 => 200}/class/Model/Payment.php (98%) rename version/{112 => 200}/class/Model/Queue.php (100%) rename version/{112 => 200}/class/Mollie.php (96%) rename version/{112 => 200}/class/Queue.php (86%) rename version/{112 => 200}/class/Traits/Jsonable.php (54%) rename version/{112 => 200}/class/Traits/Plugin.php (100%) rename version/{112 => 200}/class/Traits/RequestData.php (100%) rename version/{112 => 200}/frontend/.htaccess (100%) rename version/{112 => 200}/frontend/131_globalinclude.php (86%) rename version/{112 => 200}/frontend/132_headPostGet.php (100%) rename version/{112 => 200}/frontend/140_smarty.php (100%) rename version/{112 => 200}/frontend/180_checkbox.php (100%) rename version/{112 => 200}/frontend/181_sync.php (100%) rename version/{112 => 200}/frontend/210_storno.php (100%) rename version/{112 => 200}/frontend/75_bestellungInDb.php (89%) rename version/{112 => 200}/frontend/applepay.php (100%) rename version/{112 => 200}/frontend/img/trust_eng.png (100%) rename version/{112 => 200}/frontend/img/trust_fre.png (100%) rename version/{112 => 200}/frontend/img/trust_ger.png (100%) rename version/{112 => 200}/frontend/tpl/applepay.tpl (88%) rename version/{112 => 200}/paymentmethod/JTLMollie.php (96%) rename version/{112 => 200}/paymentmethod/JTLMollieApplePay.php (100%) rename version/{112 => 200}/paymentmethod/JTLMollieBancontact.php (100%) rename version/{112 => 200}/paymentmethod/JTLMollieBanktransfer.php (86%) rename version/{112 => 200}/paymentmethod/JTLMollieBelfius.php (100%) rename version/{112 => 200}/paymentmethod/JTLMollieCreditCard.php (86%) rename version/{112 => 200}/paymentmethod/JTLMollieDirectDebit.php (64%) rename version/{112 => 200}/paymentmethod/JTLMollieEPS.php (100%) create mode 100644 version/200/paymentmethod/JTLMollieGiftcard.php rename version/{112 => 200}/paymentmethod/JTLMollieGiropay.php (100%) rename version/{112 => 200}/paymentmethod/JTLMollieIDEAL.php (100%) rename version/{112 => 200}/paymentmethod/JTLMollieINGHomePay.php (91%) rename version/{112 => 200}/paymentmethod/JTLMollieKBC.php (100%) rename version/{112 => 200}/paymentmethod/JTLMollieKlarnaPayLater.php (100%) rename version/{112 => 200}/paymentmethod/JTLMollieKlarnaSliceIt.php (100%) rename version/{112 => 200}/paymentmethod/JTLMollieMyBank.php (100%) rename version/{112 => 200}/paymentmethod/JTLMolliePayPal.php (100%) rename version/{112 => 200}/paymentmethod/JTLMolliePaysafecard.php (100%) rename version/{112 => 200}/paymentmethod/JTLMolliePrzelewy24.php (100%) rename version/{112 => 200}/paymentmethod/JTLMollieSofort.php (100%) rename version/{112 => 200}/paymentmethod/img/method/Przelewy24@2x.png (100%) rename version/{112 => 200}/paymentmethod/img/method/applepay@2x.png (100%) rename version/{112 => 200}/paymentmethod/img/method/bancontact@2x.png (100%) rename version/{112 => 200}/paymentmethod/img/method/banktransfer@2x.png (100%) rename version/{112 => 200}/paymentmethod/img/method/belfius@2x.png (100%) rename version/{112 => 200}/paymentmethod/img/method/creditcard@2x.png (100%) rename version/{112 => 200}/paymentmethod/img/method/directdebit@2x.png (100%) rename version/{112 => 200}/paymentmethod/img/method/eps@2x.png (100%) rename version/{112 => 200}/paymentmethod/img/method/giftcard@2x.png (100%) rename version/{112 => 200}/paymentmethod/img/method/giropay@2x.png (100%) rename version/{112 => 200}/paymentmethod/img/method/ideal@2x.png (100%) rename version/{112 => 200}/paymentmethod/img/method/inghomepay@2x.png (100%) rename version/{112 => 200}/paymentmethod/img/method/kbc@2x.png (100%) rename version/{112 => 200}/paymentmethod/img/method/klarna@2x.png (100%) rename version/{112 => 200}/paymentmethod/img/method/mollie@2x.png (100%) rename version/{112 => 200}/paymentmethod/img/method/mybank@2x.png (100%) rename version/{112 => 200}/paymentmethod/img/method/paypal@2x.png (100%) rename version/{112 => 200}/paymentmethod/img/method/paysafecard@2x.png (100%) rename version/{112 => 200}/paymentmethod/img/method/sofort@2x.png (100%) rename version/{112 => 200}/paymentmethod/tpl/bestellabschluss.tpl (100%) rename version/{112 => 200}/paymentmethod/tpl/mollieComponents.tpl (86%) create mode 100644 version/200/sql/200.sql rename version/{112 => 200}/tpl/_alerts.tpl (100%) diff --git a/info.xml b/info.xml index b1c80d3..1a1069c 100644 --- a/info.xml +++ b/info.xml @@ -1,12 +1,12 @@ - mollie - Zahlungsartplugin für mollie.com - WebStollen - https://www.webstollen.de/ + Mollie + Mollie Payment Plugin + WebStollen GmbH + https://www.webstollen.de 102 ws_mollie - 405 + 406 100.sql @@ -47,9 +47,9 @@ 2021-01-11 - - 2021-01-11 - 112.sql + + 2021-04-09 + 200.sql 75_bestellungInDb.php @@ -85,10 +85,43 @@ Füge hier deinen mollie API Key ein test_api_key
+ + + Test API als Admin + Wenn diese Einstellung aktiviert ist, wird im Shop automatisch die Test-API verwendet, + wenn man als Admin im Backend eingeloggt ist. + + testAsAdmin + + + + + + + + Zahlungserinnerung + Soll bei fehlgeschlagener Zahlung ein Zahlungslink verschickt werden? Angabe in Stunden + nach Bestellung. (0 = deaktiviert) + + reminder + + + + Kunden bei Mollie anlegen (Customer API) + Wenn diese Einstellung aktiviert ist, hat der Kunde die Möglichkeit, per Checkbox, + seine Kundendaten bei Mollie zu speichern. Z.B. für Single-Click Checkout benötigt. + + useCustomerAPI + + + + + + Profile ID: - Füge hier deinen mollie Profil ID (pfl_) ein. Wird benötigt um mollie Components zu - aktivieren + Füge hier deinen mollie Profil ID (pfl_) ein. Wird benötigt um mollie Components zu + aktivieren profileId @@ -103,7 +136,30 @@ + + Nur bezahlte Bestellungen in die WAWI übertragen + Wenn diese Einstellung deaktiviert ist, können alle Bestellungen direkt von der WAWI + abgerufen werden. + + onlyPaid + + + + + + + + Bestellungen automatisch stornieren + Wenn diese Einstellung aktiviert ist, werden komplett Stornierte Bestellungen auch bei + Mollie storniert oder rückerstattet. + + autoRefund + + + + + Bestellabschluss Hier kann das Bestellabschluss-Verhalten eingestellt werden. @@ -114,7 +170,6 @@ - Fallback-Locale Fallback, falls Locale nicht erkannt oder nicht vorhanden. @@ -145,7 +200,7 @@ - + + Zahlungsart Daten synchronisieren - Lädt Name / Bild für die jeweilige Sprache automatisch von mollie, und speichert diese - in der Datenbank + Lädt Name / Bild für die jeweilige Sprache automatisch von mollie, und speichert diese + in der Datenbank paymentmethod_sync @@ -179,8 +235,8 @@ Artikel mit rationalen Stückzahlen - Artikel mit rationalen Stückzahlen werden dann unterstützt, jedoch als ein Artikel - behandelt. KEIN Teilversand hierfür möglich! + Artikel mit rationalen Stückzahlen werden dann unterstützt, jedoch als ein Artikel + behandelt. KEIN Teilversand hierfür möglich! supportQ @@ -190,8 +246,8 @@ TransaktionsID des Zahlungseingangs: - Welche ID soll an die WAWI übetragen werden? Bei PayPal wird immer die PayPal Referenz - angegeben. + Welche ID soll an die WAWI übetragen werden? Bei PayPal wird immer die PayPal Referenz + angegeben. wawiPaymentID @@ -208,33 +264,32 @@ Max. Gültigenkeit in Tagen: Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" - Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 - Tage. + Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 + Tage. expiryDays - + skipComponentsLink - - - + + + + cctitle @@ -242,6 +297,7 @@ + error_canceled @@ -253,6 +309,8 @@ You canceled the payment. Please select a different payment method if necessary.]]> + + error_expired @@ -263,6 +321,8 @@ Your payment session has expired, please try again.]]> + + error_open @@ -274,6 +334,8 @@ The payment process failed. Please try again or choose a different payment method.]]> + + error_failed @@ -285,6 +347,20 @@ The payment process failed. Please try again or choose a different paymentmethod.]]> + + + + + error_create + + + + + + + lbl_cardHolder @@ -292,6 +368,7 @@ + lbl_cardNumber @@ -299,6 +376,7 @@ + lbl_expiryDate @@ -306,6 +384,7 @@ + lbl_varificationCode @@ -313,6 +392,7 @@ + cvchint_1 @@ -320,6 +400,7 @@ + cvchint_2 @@ -331,6 +412,8 @@ The three-digit CVV/CVC number is shown on the reverse for Visa and Mastercard, and on the front of the card for American Express.]]> + + mcErrorMessage @@ -338,11 +421,77 @@ + + + + + clearDescr + Kreditkarte: Token bereits vorhanden + + + + + + + + + + clearButton + Kreditkarte: Token löschen + + + + + + + errAlreadyPaid + Wenn die Bestellung bereits bezahlt ist + + + + + + + errOrderNotFound + Wenn Bestellung nicht gefunden wurde. + + + + + + + + + + + checkboxText + Text der Checkbox, um einen Kunden bei Mollie anzulegen + + + + + + + + + + checkboxDescr + Beschreibung der Checkbox, um einen Kunden bei Mollie anzulegen + + + + + + + + + + - mollie + Mollie img/method/mollie@2x.png 1 0 @@ -356,21 +505,27 @@ JTLMollie tpl/bestellabschluss.tpl - mollie - mollie + Mollie + Mollie Bezahlen Sie bequem mit verschiedenen Zahlungsmethoden. - - Max. Gültigenkeit in Tagen: - Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" - Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 - Tage. - - expiryDays + + API + Welche API soll verwendet werden? + api + + + + + + + Gültigkeit in Tagen + Wie lange hat der Kunde Zeit die Bestellung zu bezahlen? (Order API) + dueDays - mollie Kreditkarte + Mollie Kreditkarte img/method/creditcard@2x.png 3 0 @@ -386,20 +541,47 @@ tpl/mollieComponents.tpl Kreditkarte - mollie + Mollie Bezahlen Sie bequem mit Kreditkarte. - - Max. Gültigenkeit in Tagen: - Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" - Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 - Tage. + + Mollie Components + Wenn diese Einstellung aktiviert ist, werden die Kreditkarten ggf. bereits im Shop + abgefragt. - expiryDays + components + + + + + + + + Trustgrafik anzeigen + Bindet eine Trust-Grafik unterhalb des Kreditkartenformulars ein. + loadTrust + + + + + + + API + Welche API soll verwendet werden? + api + + + + + + + Gültigkeit in Tagen + Wie lange hat der Kunde Zeit die Bestellung zu bezahlen? (Order API) + dueDays - mollie Apple Pay + Mollie Apple Pay img/method/applepay@2x.png 3 0 @@ -414,20 +596,26 @@ tpl/bestellabschluss.tpl Apple Pay - mollie + Mollie Bezahlen Sie bequem mit Apple Pay. - - Max. Gültigenkeit in Tagen: - Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" - Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 - Tage. - - expiryDays + + API + Welche API soll verwendet werden? + api + + + + + + + Gültigkeit in Tagen + Wie lange hat der Kunde Zeit die Bestellung zu bezahlen? (Order API) + dueDays - mollie Bancontact + Mollie Bancontact img/method/bancontact@2x.png 4 0 @@ -442,20 +630,26 @@ tpl/bestellabschluss.tpl Bancontact - mollie + Mollie Bezahlen Sie bequem mit Bancontact. - - Max. Gültigenkeit in Tagen: - Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" - Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 - Tage. - - expiryDays + + API + Welche API soll verwendet werden? + api + + + + + + + Gültigkeit in Tagen + Wie lange hat der Kunde Zeit die Bestellung zu bezahlen? (Order API) + dueDays - mollie Banktransfer + Mollie Banktransfer img/method/banktransfer@2x.png 5 0 @@ -470,20 +664,26 @@ tpl/bestellabschluss.tpl SEPA Überweisung - mollie + Mollie Bezahlen Sie bequem mit SEPA Überweisung. - - Max. Gültigenkeit in Tagen: - Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" - Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 - Tage. - - expiryDays + + API + Welche API soll verwendet werden? + api + + + + + + + Gültigkeit in Tagen + Wie lange hat der Kunde Zeit die Überweisung zu tätigen? + dueDays - mollie Belfius + Mollie Belfius img/method/belfius@2x.png 6 0 @@ -498,20 +698,26 @@ tpl/bestellabschluss.tpl Belfius - mollie + Mollie Bezahlen Sie bequem mit Belfius. - - Max. Gültigenkeit in Tagen: - Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" - Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 - Tage. - - expiryDays + + API + Welche API soll verwendet werden? + api + + + + + + + Gültigkeit in Tagen + Wie lange hat der Kunde Zeit die Bestellung zu bezahlen? (Order API) + dueDays - mollie DirectDebit + Mollie DirectDebit img/method/directdebit@2x.png 7 0 @@ -526,20 +732,12 @@ tpl/bestellabschluss.tpl SEPA Lastschrift - mollie + Mollie Bezahlen Sie bequem mit SEPA Lastschrift. - - Max. Gültigenkeit in Tagen: - Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" - Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 - Tage. - - expiryDays - - mollie EPS + Mollie EPS img/method/eps@2x.png 2 0 @@ -557,17 +755,23 @@ mollie Bezahlen Sie bequem mit EPS. - - Max. Gültigenkeit in Tagen: - Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" - Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 - Tage. - - expiryDays + + API + Welche API soll verwendet werden? + api + + + + + + + Gültigkeit in Tagen + Wie lange hat der Kunde Zeit die Bestellung zu bezahlen? (Order API) + dueDays - mollie Giftcard + Mollie Giftcard img/method/giftcard@2x.png 8 0 @@ -582,20 +786,12 @@ tpl/bestellabschluss.tpl Gift cards - mollie + Mollie Bezahlen Sie bequem mit Gift cards. - - Max. Gültigenkeit in Tagen: - Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" - Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 - Tage. - - expiryDays - - mollie Giropay + Mollie Giropay img/method/giropay@2x.png 9 0 @@ -610,20 +806,26 @@ tpl/bestellabschluss.tpl Giropay - mollie + mMllie Bezahlen Sie bequem mit Giropay. - - Max. Gültigenkeit in Tagen: - Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" - Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 - Tage. - - expiryDays + + API + Welche API soll verwendet werden? + api + + + + + + + Gültigkeit in Tagen + Wie lange hat der Kunde Zeit die Bestellung zu bezahlen? (Order API) + dueDays - mollie iDEAL + Mollie iDEAL img/method/ideal@2x.png 10 0 @@ -638,20 +840,26 @@ tpl/bestellabschluss.tpl iDEAL - mollie + Mollie Bezahlen Sie bequem mit iDEAL. - - Max. Gültigenkeit in Tagen: - Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" - Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 - Tage. - - expiryDays + + API + Welche API soll verwendet werden? + api + + + + + + + Gültigkeit in Tagen + Wie lange hat der Kunde Zeit die Bestellung zu bezahlen? (Order API) + dueDays - mollie ING HomePay + Mollie ING HomePay img/method/inghomepay@2x.png 11 0 @@ -669,17 +877,9 @@ mollie Bezahlen Sie bequem mit ING HomePay. - - Max. Gültigenkeit in Tagen: - Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" - Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 - Tage. - - expiryDays - - mollie KBC + Mollie KBC img/method/kbc@2x.png 12 0 @@ -694,20 +894,26 @@ tpl/bestellabschluss.tpl KBC - mollie + Mollie Bezahlen Sie bequem mit KBC. - - Max. Gültigenkeit in Tagen: - Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" - Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 - Tage. - - expiryDays + + API + Welche API soll verwendet werden? + api + + + + + + + Gültigkeit in Tagen + Wie lange hat der Kunde Zeit die Bestellung zu bezahlen? (Order API) + dueDays - mollie PayPal + Mollie PayPal img/method/paypal@2x.png 13 0 @@ -722,20 +928,26 @@ tpl/bestellabschluss.tpl PayPal - mollie + Mollie Bezahlen Sie bequem mit PayPal. - - Max. Gültigenkeit in Tagen: - Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" - Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 - Tage. - - expiryDays + + API + Welche API soll verwendet werden? + api + + + + + + + Gültigkeit in Tagen + Wie lange hat der Kunde Zeit die Bestellung zu bezahlen? (Order API) + dueDays - mollie paysafecard + Mollie paysafecard img/method/paysafecard@2x.png 14 0 @@ -750,20 +962,26 @@ tpl/bestellabschluss.tpl paysafecard - mollie + Mollie Bezahlen Sie bequem mit paysafecard. - - Max. Gültigenkeit in Tagen: - Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" - Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 - Tage. - - expiryDays + + API + Welche API soll verwendet werden? + api + + + + + + + Gültigkeit in Tagen + Wie lange hat der Kunde Zeit die Bestellung zu bezahlen? (Order API) + dueDays - mollie SOFORT + Mollie SOFORT img/method/sofort@2x.png 15 0 @@ -778,16 +996,22 @@ tpl/bestellabschluss.tpl SOFORT - mollie + Mollie Bezahlen Sie bequem mit SOFORT. - - Max. Gültigenkeit in Tagen: - Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" - Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 - Tage. - - expiryDays + + API + Welche API soll verwendet werden? + api + + + + + + + Gültigkeit in Tagen + Wie lange hat der Kunde Zeit die Bestellung zu bezahlen? (Order API) + dueDays @@ -809,17 +1033,14 @@ mollie Bezahlen Sie bequem mit Klarna Pay Later. - - Max. Gültigenkeit in Tagen: - Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" - Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 - Tage. - - expiryDays + + Gültigkeit in Tagen + Wie lange hat der Kunde Zeit die Bestellung zu bezahlen? + dueDays - mollie Klarna Slice It + Mollie Klarna Slice It img/method/klarna@2x.png 17 0 @@ -834,20 +1055,17 @@ tpl/bestellabschluss.tpl Klarna Slice It - mollie + Mollie Bezahlen Sie bequem mit Klarna Slice It. - - Max. Gültigenkeit in Tagen: - Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" - Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 - Tage. - - expiryDays + + Gültigkeit in Tagen + Wie lange hat der Kunde Zeit die Bestellung zu bezahlen? + dueDays - mollie Przelewy24 + Mollie Przelewy24 img/method/Przelewy24@2x.png 17 0 @@ -865,17 +1083,23 @@ mollie Bezahlen Sie bequem mit Przelewy24. - - Max. Gültigenkeit in Tagen: - Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" - Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 - Tage. - - expiryDays + + API + Welche API soll verwendet werden? + api + + + + + + + Gültigkeit in Tagen + Wie lange hat der Kunde Zeit die Bestellung zu bezahlen? (Order API) + dueDays - mollie MyBank + Mollie MyBank img/method/mybank@2x.png 17 0 @@ -890,16 +1114,22 @@ tpl/bestellabschluss.tpl MyBank - mollie + Mollie Bezahlen Sie bequem mit MyBank. - - Max. Gültigenkeit in Tagen: - Bestellungen bei mollie, die innerhalb dieser Zeit nicht zu einem "bezahlt" - Status führen, werden als ungültig erklärt. Die Klarna Zahlungsarten haben immer max. 28 - Tage. - - expiryDays + + API + Welche API soll verwendet werden? + api + + + + + + + Gültigkeit in Tagen + Wie lange hat der Kunde Zeit die Bestellung zu bezahlen? (Order API) + dueDays diff --git a/version/112/paymentmethod/JTLMollieGiftcard.php b/version/112/paymentmethod/JTLMollieGiftcard.php deleted file mode 100644 index 79bda4a..0000000 --- a/version/112/paymentmethod/JTLMollieGiftcard.php +++ /dev/null @@ -1,8 +0,0 @@ -assign('update', $latestRelease); } - } catch (\Exception $e) { + } catch (Exception $e) { } Shop::Smarty()->display(Helper::oPlugin()->cAdminmenuPfad . '/tpl/info.tpl'); if (file_exists(__DIR__ . '/_addon.php')) { try { + /** @noinspection PhpIncludeInspection */ include __DIR__ . '/_addon.php'; } catch (Exception $e) { } } - + } catch (Exception $e) { echo "
Fehler: {$e->getMessage()}
"; Helper::logExc($e); diff --git a/version/112/adminmenu/orders.php b/version/200/adminmenu/orders.php similarity index 96% rename from version/112/adminmenu/orders.php rename to version/200/adminmenu/orders.php index f5bfc25..37f8a52 100644 --- a/version/112/adminmenu/orders.php +++ b/version/200/adminmenu/orders.php @@ -1,6 +1,7 @@ format('Ymd') . '-' . $to->format('Ymd') . '.csv'); header('Pragma: no-cache'); - $out = fopen('php://output', 'w'); + $out = fopen('php://output', 'wb'); fputcsv($out, [ @@ -81,7 +82,7 @@ $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) { + if ($payment->status === PaymentStatus::STATUS_PAID) { $tmp['cPaymentId'] = $payment->id; } } @@ -117,7 +118,7 @@ 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); + Mollie::JTLMollie()->doLog("Order refunded:
" . print_r($refund, 1) . "
", '$' . $payment->kID . '#' . $payment->kBestellung . '§' . $payment->cOrderNumber); goto order; @@ -132,12 +133,12 @@ break; } $order = JTLMollie::API()->orders->get($_REQUEST['id']); - if ($order->status == OrderStatus::STATUS_CANCELED) { + 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); + Mollie::JTLMollie()->doLog("Order canceled:
" . print_r($cancel, 1) . "
", '$' . $payment->kID . '#' . $payment->kBestellung . '§' . $payment->cOrderNumber); goto order; case 'capture': @@ -188,6 +189,7 @@ $order = JTLMollie::API()->orders->get($_REQUEST['id'], ['embed' => 'payments,refunds']); $payment = Payment::getPaymentMollie($_REQUEST['id']); + $oBestellung = null; if ($payment) { $oBestellung = new Bestellung($payment->kBestellung, false); //\ws_mollie\Model\Payment::updateFromPayment($order, $oBestellung->kBestellung); diff --git a/version/112/adminmenu/paymentmethods.php b/version/200/adminmenu/paymentmethods.php similarity index 98% rename from version/112/adminmenu/paymentmethods.php rename to version/200/adminmenu/paymentmethods.php index df3bace..4fce56c 100644 --- a/version/112/adminmenu/paymentmethods.php +++ b/version/200/adminmenu/paymentmethods.php @@ -1,6 +1,7 @@ id === 'creditcard' ? 'kreditkarte' : $method->id; diff --git a/version/112/adminmenu/tpl/info.tpl b/version/200/adminmenu/tpl/info.tpl similarity index 96% rename from version/112/adminmenu/tpl/info.tpl rename to version/200/adminmenu/tpl/info.tpl index 2952fc6..2d41c95 100644 --- a/version/112/adminmenu/tpl/info.tpl +++ b/version/200/adminmenu/tpl/info.tpl @@ -100,10 +100,10 @@ $(function () { $(document).on('click', '.nav-tabs .tab a', function () { - var target = $(this).attr('href'); - var res = target.match(/plugin-tab-(\d+)/); + const target = $(this).attr('href'); + const res = target.match(/plugin-tab-(\d+)/); if (res !== null) { - var kAdminMenu = parseInt(res[res.index]); + const kAdminMenu = parseInt(res[res.index]); history.replaceState(null, 'emarketing', 'plugin.php?kPlugin={$oPlugin->kPlugin}&kPluginAdminMenu=' + kAdminMenu); } }); diff --git a/version/112/adminmenu/tpl/mollie-account-erstellen.png b/version/200/adminmenu/tpl/mollie-account-erstellen.png similarity index 100% rename from version/112/adminmenu/tpl/mollie-account-erstellen.png rename to version/200/adminmenu/tpl/mollie-account-erstellen.png diff --git a/version/112/adminmenu/tpl/order.tpl b/version/200/adminmenu/tpl/order.tpl similarity index 99% rename from version/112/adminmenu/tpl/order.tpl rename to version/200/adminmenu/tpl/order.tpl index 4cc896f..e99fe5b 100644 --- a/version/112/adminmenu/tpl/order.tpl +++ b/version/200/adminmenu/tpl/order.tpl @@ -55,7 +55,7 @@ Locale: {$order->locale} Erstellt: - {"d. M Y H:i:s"|date:($order->createdAt|strtotime)} + {"d. M Y H:i:s"|date:{$order->createdAt|strtotime}} diff --git a/version/112/adminmenu/tpl/orders.tpl b/version/200/adminmenu/tpl/orders.tpl similarity index 98% rename from version/112/adminmenu/tpl/orders.tpl rename to version/200/adminmenu/tpl/orders.tpl index 669015a..68d666e 100644 --- a/version/112/adminmenu/tpl/orders.tpl +++ b/version/200/adminmenu/tpl/orders.tpl @@ -84,7 +84,7 @@ {$payment->cLocale} {$payment->cMethod} {"d. M Y H:i"|date:($payment->dCreatedAt|strtotime)} + data-order="{$payment->dCreatedAt|strtotime}">{"d. M Y H:i"|date:{$payment->dCreatedAt|strtotime}} {/foreach} @@ -123,7 +123,7 @@ diff --git a/version/112/paymentmethod/JTLMollie.php b/version/200/paymentmethod/JTLMollie.php similarity index 96% rename from version/112/paymentmethod/JTLMollie.php rename to version/200/paymentmethod/JTLMollie.php index 245e0ff..87e556b 100644 --- a/version/112/paymentmethod/JTLMollie.php +++ b/version/200/paymentmethod/JTLMollie.php @@ -16,9 +16,6 @@ class JTLMollie extends PaymentMethod use \ws_mollie\Traits\Plugin; - /** - * @deprecated - */ const MAX_EXPIRY_DAYS = 100; const ALLOW_PAYMENT_BEFORE_ORDER = false; @@ -110,6 +107,7 @@ public function preparePaymentProcess($order) $this->doLog('mollie::preparePaymentProcess: ' . $e->getMessage() . ' - ' . print_r(['cBestellNr' => $order->cBestellNr], 1), LOGLEVEL_ERROR); Shop::Smarty()->assign('oMollieException', $e); } + return $this; } /** @@ -117,6 +115,7 @@ public function preparePaymentProcess($order) * @param null $data * @param int $level * @return $this + * @deprecated */ public function doLog($msg, $data = null, $level = LOGLEVEL_NOTICE) { @@ -129,6 +128,12 @@ public function getPaymentOptions(Bestellung $order, $apiType) return []; } + public function Log($msg, $data = null, $level = LOGLEVEL_NOTICE) + { + ZahlungsLog::add($this->moduleID, "[" . microtime(true) . " - " . $_SERVER['PHP_SELF'] . "] " . $msg, $data, $level); + return $this; + } + /** * @param Bestellung $order * @param string $hash @@ -307,21 +312,18 @@ public function isValidIntern($args_arr = []) /** * @return int - * @deprecated */ public function getExpiryDays() { - $max = static::MAX_EXPIRY_DAYS; - $global = (int)Helper::getSetting('expiryDays'); - $local = (int)Helper::oPlugin()->oPluginEinstellungAssoc_arr[$this->cModulId . '_expiryDays']; - - return (int)min($local > 0 ? $local : $global, $global, $max); + return (int)min(abs((int)Helper::oPlugin()->oPluginEinstellungAssoc_arr[$this->cModulId . '_dueDays']), static::MAX_EXPIRY_DAYS); } /** * @param $cISOSprache * @param $method * @deprecated + * @noinspection PhpDeprecationInspection + * @noinspection PhpDeprecationInspection */ protected function updatePaymentMethod($cISOSprache, $method) { diff --git a/version/112/paymentmethod/JTLMollieApplePay.php b/version/200/paymentmethod/JTLMollieApplePay.php similarity index 100% rename from version/112/paymentmethod/JTLMollieApplePay.php rename to version/200/paymentmethod/JTLMollieApplePay.php diff --git a/version/112/paymentmethod/JTLMollieBancontact.php b/version/200/paymentmethod/JTLMollieBancontact.php similarity index 100% rename from version/112/paymentmethod/JTLMollieBancontact.php rename to version/200/paymentmethod/JTLMollieBancontact.php diff --git a/version/112/paymentmethod/JTLMollieBanktransfer.php b/version/200/paymentmethod/JTLMollieBanktransfer.php similarity index 86% rename from version/112/paymentmethod/JTLMollieBanktransfer.php rename to version/200/paymentmethod/JTLMollieBanktransfer.php index 429c228..61e45aa 100644 --- a/version/112/paymentmethod/JTLMollieBanktransfer.php +++ b/version/200/paymentmethod/JTLMollieBanktransfer.php @@ -8,15 +8,15 @@ class JTLMollieBanktransfer extends JTLMollie const ALLOW_PAYMENT_BEFORE_ORDER = false; - public function getPaymentOptions(Bestellung $order, $apiType): array + public function getPaymentOptions(Bestellung $order, $apiType) { $paymentOptions = []; if ($apiType === 'payment') { $paymentOptions['billingEmail'] = $order->oRechnungsadresse->cMail; $paymentOptions['locale'] = \ws_mollie\Checkout\Payment\Locale::getLocale(Session::getInstance()->Language()->getIso(), $order->oRechnungsadresse->cLand); } - // TODO Option - $dueDays = (int)self::Plugin()->oPluginEinstellungAssoc_arr[$this->moduleID . '_dueDays']; + + $dueDays = $this->getExpiryDays(); if ($dueDays > 3) { $paymentOptions['dueDate'] = date('Y-m-d', strtotime("+{$dueDays} DAYS")); } diff --git a/version/112/paymentmethod/JTLMollieBelfius.php b/version/200/paymentmethod/JTLMollieBelfius.php similarity index 100% rename from version/112/paymentmethod/JTLMollieBelfius.php rename to version/200/paymentmethod/JTLMollieBelfius.php diff --git a/version/112/paymentmethod/JTLMollieCreditCard.php b/version/200/paymentmethod/JTLMollieCreditCard.php similarity index 86% rename from version/112/paymentmethod/JTLMollieCreditCard.php rename to version/200/paymentmethod/JTLMollieCreditCard.php index b25bbad..b51a661 100644 --- a/version/112/paymentmethod/JTLMollieCreditCard.php +++ b/version/200/paymentmethod/JTLMollieCreditCard.php @@ -1,6 +1,7 @@ oPluginEinstellungAssoc_arr[$this->moduleID . '_components']; $profileId = self::Plugin()->oPluginEinstellungAssoc_arr['profileId']; if ($components === 'N' || !$profileId || trim($profileId) === '') { - return parent::handleAdditional($post); + return parent::handleAdditional($aPost_arr); } $cleared = false; - if (array_key_exists('clear', $post) && (int)$post['clear']) { + if (array_key_exists('clear', $aPost_arr) && (int)$aPost_arr['clear']) { $cleared = $this->clearToken(); } - if ($components === 'S' && array_key_exists('skip', $post) && (int)$post['skip']) { - return parent::handleAdditional($post); + if ($components === 'S' && array_key_exists('skip', $aPost_arr) && (int)$aPost_arr['skip']) { + return parent::handleAdditional($aPost_arr); } try { @@ -51,11 +52,11 @@ public function handleAdditional($post) $errorMessage = json_encode(self::Plugin()->oPluginSprachvariableAssoc_arr['mcErrorMessage']); } catch (Exception $e) { Jtllog::writeLog($e->getMessage() . "\n" . print_r(['e' => $e], 1)); - return parent::handleAdditional($post); + return parent::handleAdditional($aPost_arr); } - if (!$cleared && array_key_exists('cardToken', $post) && ($token = trim($post['cardToken']))) { - return $this->setToken($token) && parent::handleAdditional($post); + if (!$cleared && array_key_exists('cardToken', $aPost_arr) && ($token = trim($aPost_arr['cardToken']))) { + return $this->setToken($token) && parent::handleAdditional($aPost_arr); } $token = false; @@ -124,10 +125,10 @@ public function getPaymentOptions(Bestellung $order, $apiType) if (!$order->Lieferadresse->cMail) { $order->Lieferadresse->cMail = $order->oRechnungsadresse->cMail; } - $paymentOptions['shippingAddress'] = new \ws_mollie\Checkout\Payment\Address($order->Lieferadresse); + $paymentOptions['shippingAddress'] = new Address($order->Lieferadresse); } - $paymentOptions['billingAddress'] = new \ws_mollie\Checkout\Payment\Address($order->oRechnungsadresse); + $paymentOptions['billingAddress'] = new Address($order->oRechnungsadresse); } if ((int)$this->getCache(self::CACHE_TOKEN_TIMESTAMP) > time() && ($token = trim($this->getCache(self::CACHE_TOKEN)))) { $paymentOptions['cardToken'] = $token; diff --git a/version/112/paymentmethod/JTLMollieDirectDebit.php b/version/200/paymentmethod/JTLMollieDirectDebit.php similarity index 64% rename from version/112/paymentmethod/JTLMollieDirectDebit.php rename to version/200/paymentmethod/JTLMollieDirectDebit.php index aeb86d3..7318e8a 100644 --- a/version/112/paymentmethod/JTLMollieDirectDebit.php +++ b/version/200/paymentmethod/JTLMollieDirectDebit.php @@ -14,4 +14,14 @@ public function isSelectable() { return false; } + + public function isValidIntern($args_arr = []) + { + return false; + } + + public function isValid($customer, $cart) + { + return false; + } } diff --git a/version/112/paymentmethod/JTLMollieEPS.php b/version/200/paymentmethod/JTLMollieEPS.php similarity index 100% rename from version/112/paymentmethod/JTLMollieEPS.php rename to version/200/paymentmethod/JTLMollieEPS.php diff --git a/version/200/paymentmethod/JTLMollieGiftcard.php b/version/200/paymentmethod/JTLMollieGiftcard.php new file mode 100644 index 0000000..40840f7 --- /dev/null +++ b/version/200/paymentmethod/JTLMollieGiftcard.php @@ -0,0 +1,27 @@ + // - - - Zahlungsart Daten synchronisieren - Lädt Name / Bild für die jeweilige Sprache automatisch von mollie, und speichert diese - in der Datenbank - - paymentmethod_sync - - - - - - - Checkout Styles laden Lädt Stylesheets für das Evo Template, um den Checkout zu verschönern. @@ -269,17 +331,6 @@
expiryDays
- diff --git a/version/200/adminmenu/tpl/orders.tpl b/version/200/adminmenu/tpl/orders.tpl index 68d666e..0b500ec 100644 --- a/version/200/adminmenu/tpl/orders.tpl +++ b/version/200/adminmenu/tpl/orders.tpl @@ -36,7 +36,7 @@ {$payment->kID} - {if $payment->cStatus == 'created'} + {if $payment->cStatus == 'created' || $payment->cStatus == 'open'} erstellt {elseif $payment->cStatus == 'pending'} austehend diff --git a/version/200/class/Checkout/AbstractCheckout.php b/version/200/class/Checkout/AbstractCheckout.php index 7a8ba59..f007eb2 100644 --- a/version/200/class/Checkout/AbstractCheckout.php +++ b/version/200/class/Checkout/AbstractCheckout.php @@ -101,16 +101,16 @@ public static function isMollie($kBestellung, $checkZA = false) } /** - * @param $id + * @param $kBestellung * @return OrderCheckout|PaymentCheckout - * @throws RuntimeException + * * @throws RuntimeException */ - public static function fromID($id) + public static function fromBestellung($kBestellung) { - if ($model = Payment::fromID($id)) { - return static::fromModel($model); + if ($model = Payment::fromID($kBestellung, 'kBestellung')) { + return self::fromModel($model); } - throw new RuntimeException(sprintf('Error loading Order: %s', $id)); + throw new RuntimeException(sprintf('Error loading Order for Bestellung: %s', $kBestellung)); } /** @@ -139,26 +139,179 @@ public static function fromModel($model) return $self; } + public static function sendReminders() + { + $reminder = (int)self::Plugin()->oPluginEinstellungAssoc_arr['reminder']; + + if (!$reminder) { + Shop::DB()->executeQueryPrepared('UPDATE xplugin_ws_mollie_payments SET dReminder = :dReminder WHERE dReminder IS NULL', [ + ':dReminder' => date('Y-m-d H:i:s') + ], 3); + return; + } + + $remindables = Shop::DB()->executeQueryPrepared("SELECT kId FROM xplugin_ws_mollie_payments WHERE dReminder IS NULL AND dCreatedAt < NOW() - INTERVAL :d HOUR AND cStatus IN ('created','open', 'expired', 'failed', 'canceled')", [ + ':d' => $reminder + ], 2); + foreach ($remindables as $remindable) { + try { + self::sendReminder($remindable->kId); + } catch (Exception $e) { + Jtllog::writeLog("AbstractCheckout::sendReminders: " . $e->getMessage()); + } + } + } + + public static function sendReminder($kID) + { + + $checkout = self::fromID($kID); + $return = true; + try { + $repayURL = Shop::getURL() . '/?m_pay=' . md5($checkout->getModel()->kID . '-' . $checkout->getBestellung()->kBestellung); + + $data = new stdClass(); + $data->tkunde = new \Kunde($checkout->getBestellung()->oKunde->kKunde); + if ($data->tkunde->kKunde) { + + $data->Bestellung = $checkout->getBestellung(); + $data->PayURL = $repayURL; + $data->Amount = gibPreisStringLocalized($checkout->getModel()->fAmount, $checkout->getBestellung()->Waehrung); //Preise::getLocalizedPriceString($order->getAmount(), Currency::fromISO($order->getCurrency()), false); + + require_once PFAD_ROOT . PFAD_INCLUDES . 'mailTools.php'; + + $mail = new stdClass(); + $mail->toEmail = $data->tkunde->cMail; + $mail->toName = trim((isset($data->tKunde->cVorname) + ? $data->tKunde->cVorname + : '') . ' ' . ( + isset($data->tKunde->cNachname) + ? $data->tKunde->cNachname + : '' + )) ?: $mail->toEmail; + $data->mail = $mail; + if (!($sentMail = sendeMail('kPlugin_' . self::Plugin()->kPlugin . '_zahlungserinnerung', $data))) { + $checkout->Log(sprintf("Zahlungserinnerung konnte nicht versand werden: %s\n%s", isset($sentMail->cFehler) ?: print_r($sentMail, 1), print_r($data, 1)), LOGLEVEL_ERROR); + $return = false; + } else { + $checkout->Log(sprintf("Zahlungserinnerung für %s verschickt.", $checkout->getBestellung()->cBestellNr)); + } + } else { + $checkout->Log("Kunde '{$checkout->getBestellung()->oKunde->kKunde}' nicht gefunden.", LOGLEVEL_ERROR); + } + } catch (Exception $e) { + $checkout->Log(sprintf("AbstractCheckout::sendReminder: Zahlungserinnerung für %s fehlgeschlagen: %s", $checkout->getBestellung()->cBestellNr, $e->getMessage())); + $return = false; + } + $checkout->getModel()->dReminder = date('Y-m-d H:i:s'); + $checkout->getModel()->save(); + return $return; + } + /** - * @param $kBestellung + * @param $id * @return OrderCheckout|PaymentCheckout - * * @throws RuntimeException + * @throws RuntimeException */ - public static function fromBestellung($kBestellung) + public static function fromID($id) { - if ($model = Payment::fromID($kBestellung, 'kBestellung')) { - return self::fromModel($model); + if ($model = Payment::fromID($id)) { + return static::fromModel($model); } - throw new RuntimeException(sprintf('Error loading Order for Bestellung: %s', $kBestellung)); + throw new RuntimeException(sprintf('Error loading Order: %s', $id)); } - public static function sendReminders() + /** + * @return Payment + */ + public function getModel() + { + if (!$this->model) { + $this->model = Payment::fromID($this->oBestellung->kBestellung, 'kBestellung'); + } + return $this->model; + } + + /** + * @param $model + * @return $this + */ + protected function setModel($model) { - // TODO + if (!$this->model) { + $this->model = $model; + } else { + throw new RuntimeException('Model already set.'); + } + return $this; + } + + /** + * @return Bestellung + */ + public function getBestellung() + { + if (!$this->oBestellung && $this->getModel()->kBestellung) { + $this->oBestellung = new Bestellung($this->getModel()->kBestellung, true); + } + return $this->oBestellung; + } + + public function Log($msg, $level = LOGLEVEL_NOTICE) + { + $data = ''; + if ($this->getBestellung()) { + $data .= '#' . $this->getBestellung()->kBestellung; + } + if ($this->getMollie()) { + $data .= '$' . $this->getMollie()->id; + } + ZahlungsLog::add($this->PaymentMethod()->moduleID, "[" . microtime(true) . " - " . $_SERVER['PHP_SELF'] . "] " . $msg, $data, $level); + return $this; + } + + /** + * @param false $force + * @return Order|\Mollie\Api\Resources\Payment|null + */ + abstract public function getMollie($force = false); + + /** + * @return JTLMollie + */ + public function PaymentMethod() + { + if (!$this->paymentMethod) { + if ($this->getBestellung()->Zahlungsart && strpos($this->getBestellung()->Zahlungsart->cModulId, "kPlugin_{$this::Plugin()->kPlugin}_") !== false) { + $this->paymentMethod = PaymentMethod::create($this->getBestellung()->Zahlungsart->cModulId); + } else { + $this->paymentMethod = PaymentMethod::create("kPlugin_{$this::Plugin()->kPlugin}_mollie"); + } + } + /** @noinspection PhpIncompatibleReturnTypeInspection */ + return $this->paymentMethod; + } + + /** + * @return string + */ + public function LogData() + { + + $data = ''; + if ($this->getBestellung()->kBestellung) { + $data .= '#' . $this->getBestellung()->kBestellung; + } + if ($this->getMollie()) { + $data .= '$' . $this->getMollie()->id; + } + + return $data; } /** * @return \Mollie\Api\Resources\Customer|null + * @todo: Kunde wieder löschbar machen ?! */ public function getCustomer($createOrUpdate = false) { @@ -217,42 +370,6 @@ public function getCustomer($createOrUpdate = false) return $this->customer; } - /** - * @return Bestellung - */ - public function getBestellung() - { - if (!$this->oBestellung && $this->getModel()->kBestellung) { - $this->oBestellung = new Bestellung($this->getModel()->kBestellung, true); - } - return $this->oBestellung; - } - - /** - * @return Payment - */ - public function getModel() - { - if (!$this->model) { - $this->model = Payment::fromID($this->oBestellung->kBestellung, 'kBestellung'); - } - return $this->model; - } - - /** - * @param $model - * @return $this - */ - protected function setModel($model) - { - if (!$this->model) { - $this->model = $model; - } else { - throw new RuntimeException('Model already set.'); - } - return $this; - } - /** * @return API */ @@ -268,41 +385,6 @@ public function API() return $this->api; } - public function Log($msg, $level = LOGLEVEL_NOTICE) - { - $data = ''; - if ($this->getBestellung()) { - $data .= '#' . $this->getBestellung()->kBestellung; - } - if ($this->getMollie()) { - $data .= '$' . $this->getMollie()->id; - } - ZahlungsLog::add($this->PaymentMethod()->moduleID, "[" . microtime(true) . " - " . $_SERVER['PHP_SELF'] . "] " . $msg, $data, $level); - return $this; - } - - /** - * @param false $force - * @return Order|\Mollie\Api\Resources\Payment - */ - abstract public function getMollie($force = false); - - /** - * @return JTLMollie - */ - public function PaymentMethod() - { - if (!$this->paymentMethod) { - if ($this->getBestellung()->Zahlungsart && strpos($this->getBestellung()->Zahlungsart->cModulId, "kPlugin_{$this::Plugin()->kPlugin}_") !== false) { - $this->paymentMethod = PaymentMethod::create($this->getBestellung()->Zahlungsart->cModulId); - } else { - $this->paymentMethod = PaymentMethod::create("kPlugin_{$this::Plugin()->kPlugin}_mollie"); - } - } - /** @noinspection PhpIncompatibleReturnTypeInspection */ - return $this->paymentMethod; - } - public static function getLocale($cISOSprache = null, $country = null) { @@ -343,19 +425,18 @@ public function handleNotification($hash = null) if (!$this->getBestellung()->dBezahltDatum || $this->getBestellung()->dBezahltDatum === '0000-00-00') { if ($incoming = $this->getIncomingPayment()) { $this->PaymentMethod()->addIncomingPayment($this->getBestellung(), $incoming); - if ($this->completlyPaid()) { - $this->PaymentMethod()->setOrderStatusToPaid($this->getBestellung()); - static::makeFetchable($this->getBestellung(), $this->getModel()); - $this->PaymentMethod()->deletePaymentHash($this->getHash()); - $this->Log(sprintf("Checkout::handleNotification: Bestellung '%s' als bezahlt markiert: %.2f %s", $this->getBestellung()->cBestellNr, (float)$incoming->fBetrag, $incoming->cISO)); + $this->PaymentMethod()->setOrderStatusToPaid($this->getBestellung()); + static::makeFetchable($this->getBestellung(), $this->getModel()); + $this->PaymentMethod()->deletePaymentHash($this->getHash()); + $this->Log(sprintf("Checkout::handleNotification: Bestellung '%s' als bezahlt markiert: %.2f %s", $this->getBestellung()->cBestellNr, (float)$incoming->fBetrag, $incoming->cISO)); - $oZahlungsart = Shop::DB()->selectSingleRow('tzahlungsart', 'cModulId', $this->PaymentMethod()->moduleID); - if ($oZahlungsart && (int)$oZahlungsart->nMailSenden === 1) { - require_once PFAD_ROOT . 'includes/mailTools.php'; - $this->PaymentMethod()->sendConfirmationMail($this->getBestellung()); - } - } else { + $oZahlungsart = Shop::DB()->selectSingleRow('tzahlungsart', 'cModulId', $this->PaymentMethod()->moduleID); + if ($oZahlungsart && (int)$oZahlungsart->nMailSenden === 1) { + require_once PFAD_ROOT . 'includes/mailTools.php'; + $this->PaymentMethod()->sendConfirmationMail($this->getBestellung()); + } + if (!$this->completlyPaid()) { $this->Log(sprintf("Checkout::handleNotification: Bestellung '%s': nicht komplett bezahlt: %.2f %s", $this->getBestellung()->cBestellNr, (float)$incoming->fBetrag, $incoming->cISO), LOGLEVEL_ERROR); } } @@ -421,21 +502,6 @@ public function updateModel() */ abstract public function getIncomingPayment(); - /** - * @return bool - */ - public function completlyPaid() - { - - if ($row = Shop::DB()->executeQueryPrepared("SELECT SUM(fBetrag) as fBetragSumme FROM tzahlungseingang WHERE kBestellung = :kBestellung", [ - ':kBestellung' => $this->getBestellung()->kBestellung - ], 1)) { - return $row->fBetragSumme >= ($this->getBestellung()->fGesamtsumme * (float)$this->getBestellung()->fWaehrungsFaktor); - } - return false; - - } - /** * @param Bestellung $oBestellung * @param Payment $model @@ -455,4 +521,19 @@ public static function makeFetchable(Bestellung $oBestellung, Payment $model) return false; } + /** + * @return bool + */ + public function completlyPaid() + { + + if ($row = Shop::DB()->executeQueryPrepared("SELECT SUM(fBetrag) as fBetragSumme FROM tzahlungseingang WHERE kBestellung = :kBestellung", [ + ':kBestellung' => $this->getBestellung()->kBestellung + ], 1)) { + return $row->fBetragSumme >= round($this->getBestellung()->fGesamtsumme * (float)$this->getBestellung()->fWaehrungsFaktor, 2); + } + return false; + + } + } \ No newline at end of file diff --git a/version/200/class/Checkout/AbstractResource.php b/version/200/class/Checkout/AbstractResource.php index 09e612c..4550abc 100644 --- a/version/200/class/Checkout/AbstractResource.php +++ b/version/200/class/Checkout/AbstractResource.php @@ -13,23 +13,4 @@ abstract class AbstractResource implements JsonSerializable use Plugin; use RequestData; - public function __get($name) - { - return $this->RequestData($name); - } - - public function __set($name, $value) - { - return $this->setRequestData($name, $value); - } - - public function __serialize() - { - return $this->getRequestData() ?: []; - } - - public function __isset($name) - { - return $this->RequestData($name) !== null; - } } \ No newline at end of file diff --git a/version/200/class/Checkout/Exception/ResourceValidityException.php b/version/200/class/Checkout/Exception/ResourceValidityException.php index 129a1ea..6cf44d2 100644 --- a/version/200/class/Checkout/Exception/ResourceValidityException.php +++ b/version/200/class/Checkout/Exception/ResourceValidityException.php @@ -1,7 +1,9 @@ name || !$resource->quantity || !$resource->unitPrice || !$resource->totalAmount || !$resource->vatRate || !$resource->vatAmount) { - throw \ResourceValidityException::trigger(\ResourceValidityException::ERROR_REQUIRED, + throw ResourceValidityException::trigger(ResourceValidityException::ERROR_REQUIRED, ['name', 'quantity', 'unitPrice', 'totalAmount', 'vatRate', 'vatAmount'], $resource); } @@ -116,7 +117,6 @@ public static function factory($oPosition, $currency = null) * @param null|stdClass $currency * @return $this * @todo Setting for Fraction handling needed? - * @TODO DEBUG/TEST */ protected function fill($oPosition, $currency = null) { @@ -133,7 +133,7 @@ protected function fill($oPosition, $currency = null) $netto = $isKupon ? round($oPosition->fPreis * (1 + $vatRate), 4) : round($oPosition->fPreis, 4); // Fraction? transform, as it were 1, and set quantity to 1 - $netto = round(($isFrac ? $netto * (int)$oPosition->nAnzahl : $netto) * $currency->fFaktor, 4); + $netto = round(($isFrac ? $netto * (float)$oPosition->nAnzahl : $netto) * $currency->fFaktor, 4); $this->quantity = $isFrac ? 1 : (int)$oPosition->nAnzahl; // Fraction? include quantity and unit in name @@ -143,11 +143,11 @@ protected function fill($oPosition, $currency = null) //$unitPriceNetto = round(($currency->fFaktor * $netto), 4); - $this->unitPrice = Amount::factory(round($netto * (1 + $vatRate), 2), $currency, false); - $this->totalAmount = Amount::factory(round($this->quantity * $this->unitPrice->value, 2), $currency, false); + $this->unitPrice = Amount::factory(round($netto * (1 + $vatRate), 2), $currency->cISO, false); + $this->totalAmount = Amount::factory(round($this->quantity * $this->unitPrice->value, 2), $currency->cISO, false); $this->vatRate = number_format($vatRate * 100, 2); - $this->vatAmount = Amount::factory(round($this->totalAmount->value - ($this->totalAmount->value / (1 + $vatRate)), 2), $currency, false); + $this->vatAmount = Amount::factory(round($this->totalAmount->value - ($this->totalAmount->value / (1 + $vatRate)), 2), $currency->cISO, false); $metadata = []; diff --git a/version/200/class/Checkout/OrderCheckout.php b/version/200/class/Checkout/OrderCheckout.php index 0e28fc3..ec34322 100644 --- a/version/200/class/Checkout/OrderCheckout.php +++ b/version/200/class/Checkout/OrderCheckout.php @@ -17,6 +17,24 @@ use ws_mollie\Checkout\Order\OrderLine; use ws_mollie\Checkout\Payment\Amount; +/** + * Class OrderCheckout + * @package ws_mollie\Checkout + * + * @property string $locale + * @property Amount $amount + * @property string $orderNumber + * @property array|null $metadata + * @property string $redirectUrl + * @property string $webhookUrl + * @property string|null $method + * @property Address $billingAddress + * @property Address|null $shippingAddress + * @property string|null $consumerDateOfBirth + * @property OrderLine[] $lines + * @property string|null $expiresAt + * @property array|null $payment + */ class OrderCheckout extends AbstractCheckout { @@ -26,9 +44,9 @@ class OrderCheckout extends AbstractCheckout protected $order; /** - * @var Payment + * @var Payment|null */ - protected $payment; + protected $_payment; /** * @return string @@ -42,10 +60,13 @@ public function cancelOrRefund() if ((int)$this->getBestellung()->cStatus === BESTELLUNG_STATUS_STORNO) { if ($this->getMollie()->isCancelable) { $res = $this->getMollie()->cancel(); - return 'Order cancelled, Status: ' . $res->status; + $result = 'Order cancelled, Status: ' . $res->status; + } else { + $res = $this->getMollie()->refundAll(); + $result = "Order Refund initiiert, Status: " . $res->status; } - $res = $this->getMollie()->refundAll(); - return "Order Refund initiiert, Status: " . $res->status; + $this->PaymentMethod()->Log("OrderCheckout::cancelOrRefund: " . $result, $this->LogData()); + return $result; } throw new RuntimeException('Bestellung ist derzeit nicht storniert, Status: ' . $this->getBestellung()->cStatus); } @@ -62,6 +83,10 @@ public function getMollie($force = false) return $this->order; } + /** + * @param array $paymentOptions + * @return Order|Payment + */ public function create(array $paymentOptions = []) { if ($this->getModel()->kID) { @@ -76,19 +101,18 @@ public function create(array $paymentOptions = []) /** @var Payment $payment */ foreach ($this->order->payments() as $payment) { if ($payment->status === PaymentStatus::STATUS_OPEN) { - $this->payment = $payment; + $this->setPayment($payment); break; } } } - if (!$this->payment) { - $this->payment = $this->API()->Client()->orderPayments->createForId($this->getModel()->kID, $paymentOptions); + if (!$this->getPayment()) { + $this->setPayment($this->API()->Client()->orderPayments->createForId($this->getModel()->kID, $paymentOptions)); } $this->updateModel()->saveModel(); return $this->getMollie(true); } } catch (RuntimeException $e) { - //$this->Log(sprintf("OrderCheckout::create: Letzte Order '%s' konnte nicht geladen werden: %s", $this->getModel()->kID, $e->getMessage()), LOGLEVEL_ERROR); throw $e; } catch (Exception $e) { $this->Log(sprintf("OrderCheckout::create: Letzte Order '%s' konnte nicht geladen werden: %s, versuche neue zu erstellen.", $this->getModel()->kID, $e->getMessage()), LOGLEVEL_ERROR); @@ -96,81 +120,102 @@ public function create(array $paymentOptions = []) } try { - $req = $this->loadRequest($paymentOptions)->getRequestData(); + $req = $this->loadRequest()->jsonSerialize(); $this->order = $this->API()->Client()->orders->create($req); $this->Log(sprintf("Order für '%s' wurde erfolgreich angelegt: %s", $this->getBestellung()->cBestellNr, $this->order->id)); $this->updateModel()->saveModel(); + return $this->order; } catch (Exception $e) { $this->Log(sprintf("OrderCheckout::create: Neue Order '%s' konnte nicht erstellt werden: %s.", $this->getBestellung()->cBestellNr, $e->getMessage()), LOGLEVEL_ERROR); throw new RuntimeException(sprintf("Order für '%s' konnte nicht angelegt werden: %s", $this->getBestellung()->cBestellNr, $e->getMessage())); } - return $this->order; } + /** + * @return Payment|null + */ + public function getPayment() + { + return $this->_payment; + } + + /** + * @param $payment + * @return $this + */ + public function setPayment($payment) + { + $this->_payment = $payment; + return $this; + } + + /** + * @return $this|OrderCheckout + */ public function updateModel() { parent::updateModel(); - if (!$this->payment && $this->getMollie() && $this->getMollie()->payments()) { + if (!$this->getPayment() && $this->getMollie() && $this->getMollie()->payments()) { /** @var Payment $payment */ foreach ($this->getMollie()->payments() as $payment) { if (in_array($payment->status, [PaymentStatus::STATUS_OPEN, PaymentStatus::STATUS_PENDING, PaymentStatus::STATUS_AUTHORIZED, PaymentStatus::STATUS_PAID], true)) { - $this->payment = $payment; + $this->setPayment($payment); break; } } } - if ($this->payment) { - $this->getModel()->cTransactionId = $this->payment->id; - + if ($this->getPayment()) { + $this->getModel()->cTransactionId = $this->getPayment()->id; } if ($this->getMollie()) { $this->getModel()->cCheckoutURL = $this->getMollie()->getCheckoutUrl(); $this->getModel()->cWebhookURL = $this->getMollie()->webhookUrl; $this->getModel()->cRedirectURL = $this->getMollie()->redirectUrl; } - return $this; } /** * @param array $options * @return $this|OrderCheckout - * @throws ApiException - * @throws \Mollie\Api\Exceptions\IncompatiblePlatform */ public function loadRequest($options = []) { - if ((int)$this->getBestellung()->oKunde->nRegistriert - && ($customer = $this->getCustomer(array_key_exists('mollie_create_customer', $_SESSION['cPost_arr'] ?: []) || $_SESSION['cPost_arr']['mollie_create_customer'] !== 'Y')) + if ($this->getBestellung()->oKunde->nRegistriert + && ($customer = $this->getCustomer( + array_key_exists('mollie_create_customer', $_SESSION['cPost_arr'] ?: []) && $_SESSION['cPost_arr']['mollie_create_customer'] === 'Y') + ) && isset($customer)) { $options['customerId'] = $customer->id; } - $this->setRequestData('locale', self::getLocale(Session::getInstance()->Language()->getIso(), Session::getInstance()->Customer()->cLand)) - ->setRequestData('amount', Amount::factory($this->getBestellung()->fGesamtsummeKundenwaehrung, $this->getBestellung()->Waehrung->cISO, true)) - ->setRequestData('orderNumber', $this->getBestellung()->cBestellNr) - ->setRequestData('metadata', [ - 'kBestellung' => $this->getBestellung()->kBestellung, - 'kKunde' => $this->getBestellung()->kKunde, - 'kKundengruppe' => Session::getInstance()->CustomerGroup()->kKundengruppe, - 'cHash' => $this->getHash(), - ]) - ->setRequestData('redirectUrl', $this->PaymentMethod()->getReturnURL($this->getBestellung())) - ->setRequestData('webhookUrl', Shop::getURL(true) . '/?mollie=1'); + $this->locale = self::getLocale(Session::getInstance()->Language()->getIso(), Session::getInstance()->Customer()->cLand); + $this->amount = Amount::factory($this->getBestellung()->fGesamtsummeKundenwaehrung, $this->getBestellung()->Waehrung->cISO, true); + $this->orderNumber = $this->getBestellung()->cBestellNr; + $this->metadata = [ + 'kBestellung' => $this->getBestellung()->kBestellung, + 'kKunde' => $this->getBestellung()->kKunde, + 'kKundengruppe' => Session::getInstance()->CustomerGroup()->kKundengruppe, + 'cHash' => $this->getHash(), + ]; + + $this->redirectUrl = $this->PaymentMethod()->getReturnURL($this->getBestellung()); + $this->webhookUrl = Shop::getURL(true) . '/?mollie=1'; $pm = $this->PaymentMethod(); - if ($pm::METHOD !== '' && (self::Plugin()->oPluginEinstellungAssoc_arr['resetMethod'] !== 'on' || !$this->getMollie())) { - $this->setRequestData('method', $pm::METHOD); + $isPayAgain = strpos($_SERVER['PHP_SELF'], 'bestellab_again') !== false; + if ($pm::METHOD !== '' && (self::Plugin()->oPluginEinstellungAssoc_arr['resetMethod'] !== 'Y' || !$isPayAgain)) { + $this->method = $pm::METHOD; } - $this->setRequestData('billingAddress', Address::factory($this->getBestellung()->oRechnungsadresse)); + $this->billingAddress = Address::factory($this->getBestellung()->oRechnungsadresse); if ($this->getBestellung()->Lieferadresse !== null) { if (!$this->getBestellung()->Lieferadresse->cMail) { $this->getBestellung()->Lieferadresse->cMail = $this->getBestellung()->oRechnungsadresse->cMail; } - $this->setRequestData('shippingAddress', Address::factory($this->getBestellung()->Lieferadresse)); + $this->shippingAddress = Address::factory($this->getBestellung()->Lieferadresse); } if ( @@ -178,7 +223,7 @@ public function loadRequest($options = []) && Session::getInstance()->Customer()->dGeburtstag !== '0000-00-00' && preg_match('/^\d{4}-\d{2}-\d{2}$/', trim(Session::getInstance()->Customer()->dGeburtstag)) ) { - $this->setRequestData('consumerDateOfBirth', trim(Session::getInstance()->Customer()->dGeburtstag)); + $this->consumerDateOfBirth = trim(Session::getInstance()->Customer()->dGeburtstag); } $lines = []; @@ -190,21 +235,24 @@ public function loadRequest($options = []) $lines[] = OrderLine::getCredit($this->getBestellung()); } - if ($comp = OrderLine::getRoundingCompensation($lines, $this->RequestData('amount'), $this->getBestellung()->Waehrung->cISO)) { + if ($comp = OrderLine::getRoundingCompensation($lines, $this->amount, $this->getBestellung()->Waehrung->cISO)) { $lines[] = $comp; } - $this->setRequestData('lines', $lines); + $this->lines = $lines; if ($dueDays = $this->PaymentMethod()->getExpiryDays()) { - $max = $this->RequestData('method') && strpos($this->RequestData('method'), 'klarna') !== false ? 28 : 100; - $this->setRequestData('expiresAt', date('Y-m-d', strtotime(sprintf("+%d DAYS", min($dueDays, $max))))); + $max = $this->method && strpos($this->method, 'klarna') !== false ? 28 : 100; + $this->expiresAt = date('Y-m-d', strtotime(sprintf("+%d DAYS", min($dueDays, $max)))); } - $this->setRequestData('payment', $options); + $this->payment = $options; return $this; } + /** + * @return object|null + */ public function getIncomingPayment() { if (!$this->getMollie()) { @@ -214,13 +262,17 @@ public function getIncomingPayment() foreach ($this->getMollie()->payments() as $payment) { if (in_array($payment->status, [PaymentStatus::STATUS_AUTHORIZED, PaymentStatus::STATUS_PAID], true)) { - $this->payment = $payment; - return (object)[ + $this->setPayment($payment); + $data = (object)[ 'fBetrag' => (float)$payment->amount->value, 'cISO' => $payment->amount->currency, 'cZahler' => $payment->details->paypalPayerId ?: $payment->customerId, 'cHinweis' => $payment->details->paypalReference ?: $payment->id, ]; + if (isset($payment->details, $payment->details->paypalFee)) { + $data->fZahlungsgebuehr = $payment->details->paypalFee->value; + } + return $data; } } return null; diff --git a/version/200/class/Checkout/Payment/Address.php b/version/200/class/Checkout/Payment/Address.php index 24280b6..ea460c1 100644 --- a/version/200/class/Checkout/Payment/Address.php +++ b/version/200/class/Checkout/Payment/Address.php @@ -4,7 +4,7 @@ namespace ws_mollie\Checkout\Payment; -use ResourceValidityException; +use ws_mollie\Checkout\Exception\ResourceValidityException; use ws_mollie\Checkout\AbstractResource; /** diff --git a/version/200/class/Checkout/Payment/Amount.php b/version/200/class/Checkout/Payment/Amount.php index fed1c84..21acef9 100644 --- a/version/200/class/Checkout/Payment/Amount.php +++ b/version/200/class/Checkout/Payment/Amount.php @@ -3,10 +3,9 @@ namespace ws_mollie\Checkout\Payment; - -use ResourceValidityException; use Shop; use ws_mollie\Checkout\AbstractResource; +use ws_mollie\Checkout\Exception\ResourceValidityException; /** * Class Amount diff --git a/version/200/class/Checkout/PaymentCheckout.php b/version/200/class/Checkout/PaymentCheckout.php index ff44e59..521481b 100644 --- a/version/200/class/Checkout/PaymentCheckout.php +++ b/version/200/class/Checkout/PaymentCheckout.php @@ -12,15 +12,30 @@ use RuntimeException; use Session; use Shop; +use ws_mollie\Checkout\Payment\Address; use ws_mollie\Checkout\Payment\Amount; +/** + * Class PaymentCheckout + * @package ws_mollie\Checkout + * + * @property string $locale + * @property Amount $amount + * @property string $description + * @property array|null $metadata + * @property string $redirectUrl + * @property string $webhookUrl + * @property string|null $method + * @property Address $billingAddress + * @property string|null $expiresAt + */ class PaymentCheckout extends AbstractCheckout { /** - * @var Payment + * @var Payment|null */ - protected $payment; + protected $_payment; /** * @return string @@ -32,37 +47,66 @@ public function cancelOrRefund() if ((int)$this->getBestellung()->cStatus === BESTELLUNG_STATUS_STORNO) { if ($this->getMollie()->isCancelable) { $res = $this->API()->Client()->payments->cancel($this->getMollie()->id); - return 'Payment cancelled, Status: ' . $res->status; + $result = 'Payment cancelled, Status: ' . $res->status; + } else { + $res = $this->API()->Client()->payments->refund($this->getMollie(), ['amount' => $this->getMollie()->amount]); + $result = "Payment Refund initiiert, Status: " . $res->status; } - $res = $this->API()->Client()->payments->refund($this->getMollie(), ['amount' => $this->getMollie()->amount]); - return "Payment Refund initiiert, Status: " . $res->status; + $this->PaymentMethod()->Log("PaymentCheckout::cancelOrRefund: " . $result, $this->LogData()); + return $result; } throw new RuntimeException('Bestellung ist derzeit nicht storniert, Status: ' . $this->getBestellung()->cStatus); } + /** + * @param false $force + * @return \Mollie\Api\Resources\Order|Payment + */ public function getMollie($force = false) { - if ($force || (!$this->payment && $this->getModel()->kID)) { + if ($force || (!$this->getPayment() && $this->getModel()->kID)) { try { - $this->payment = $this->API()->Client()->payments->get($this->getModel()->kID, ['embed' => 'refunds']); + $this->setPayment($this->API()->Client()->payments->get($this->getModel()->kID, ['embed' => 'refunds'])); } catch (Exception $e) { throw new RuntimeException('Mollie-Payment konnte nicht geladen werden: ' . $e->getMessage()); } } - return $this->payment; + return $this->getPayment(); } + /** + * @return Payment|null + */ + public function getPayment() + { + return $this->_payment; + } + + /** + * @param $payment + * @return $this + */ + public function setPayment($payment) + { + $this->_payment = $payment; + return $this; + } + + /** + * @param array $paymentOptions + * @return \Mollie\Api\Resources\Order|Payment|\ws_mollie\Model\Payment + */ public function create(array $paymentOptions = []) { if ($this->getModel()->kID) { try { - $this->payment = $this->API()->Client()->payments->get($this->getModel()->kID); - if ($this->payment->status === PaymentStatus::STATUS_PAID) { + $this->setPayment($this->API()->Client()->payments->get($this->getModel()->kID)); + if ($this->getPayment()->status === PaymentStatus::STATUS_PAID) { throw new RuntimeException(self::Plugin()->oPluginSprachvariableAssoc_arr['errAlreadyPaid']); } - if ($this->payment->status === PaymentStatus::STATUS_OPEN) { + if ($this->getPayment()->status === PaymentStatus::STATUS_OPEN) { $this->updateModel()->saveModel(); - return $this->payment; + return $this->getPayment(); } } catch (RuntimeException $e) { //$this->Log(sprintf("PaymentCheckout::create: Letzte Transaktion '%s' konnte nicht geladen werden: %s", $this->getModel()->kID, $e->getMessage()), LOGLEVEL_ERROR); @@ -73,66 +117,74 @@ public function create(array $paymentOptions = []) } try { - $req = $this->loadRequest($paymentOptions)->getRequestData(); - $this->payment = $this->API()->Client()->payments->create($req); - $this->Log(sprintf("Payment für '%s' wurde erfolgreich angelegt: %s", $this->getBestellung()->cBestellNr, $this->payment->id)); + $req = $this->loadRequest($paymentOptions)->jsonSerialize(); + $this->setPayment($this->API()->Client()->payments->create($req)); + $this->Log(sprintf("Payment für '%s' wurde erfolgreich angelegt: %s", $this->getBestellung()->cBestellNr, $this->getPayment()->id)); $this->updateModel()->saveModel(); + return $this->getPayment(); } catch (Exception $e) { $this->Log(sprintf("PaymentCheckout::create: Neue Transaktion für '%s' konnte nicht erstellt werden: %s.", $this->getBestellung()->cBestellNr, $e->getMessage()), LOGLEVEL_ERROR); throw new RuntimeException(sprintf('Mollie-Payment \'%s\' konnte nicht geladen werden: %s', $this->getBestellung()->cBestellNr, $e->getMessage())); } - return $this->payment; } /** * @param array $options * @return $this|PaymentCheckout - * @throws ApiException - * @throws IncompatiblePlatform */ public function loadRequest($options = []) { if ($this->getBestellung()->oKunde->nRegistriert - && ($customer = $this->getCustomer(array_key_exists('mollie_create_customer', $_SESSION['cPost_arr'] ?: []) || $_SESSION['cPost_arr']['mollie_create_customer'] !== 'Y')) + && ($customer = $this->getCustomer( + array_key_exists('mollie_create_customer', $_SESSION['cPost_arr'] ?: []) && $_SESSION['cPost_arr']['mollie_create_customer'] === 'Y') + ) && isset($customer)) { $options['customerId'] = $customer->id; } - $this->setRequestData('amount', Amount::factory($this->getBestellung()->fGesamtsummeKundenwaehrung, $this->getBestellung()->Waehrung->cISO, true)) - ->setRequestData('description', 'Order ' . $this->getBestellung()->cBestellNr) - ->setRequestData('redirectUrl', $this->PaymentMethod()->getReturnURL($this->getBestellung())) - ->setRequestData('webhookUrl', Shop::getURL(true) . '/?mollie=1') - ->setRequestData('locale', self::getLocale(Session::getInstance()->Language()->getIso(), Session::getInstance()->Customer()->cLand)) - ->setRequestData('metadata', [ - 'kBestellung' => $this->getBestellung()->kBestellung, - 'kKunde' => $this->getBestellung()->kKunde, - 'kKundengruppe' => Session::getInstance()->CustomerGroup()->kKundengruppe, - 'cHash' => $this->getHash(), - ]); + $this->amount = Amount::factory($this->getBestellung()->fGesamtsummeKundenwaehrung, $this->getBestellung()->Waehrung->cISO, true); + $this->description = 'Order ' . $this->getBestellung()->cBestellNr; + $this->redirectUrl = $this->PaymentMethod()->getReturnURL($this->getBestellung()); + $this->webhookUrl = Shop::getURL(true) . '/?mollie=1'; + $this->locale = self::getLocale(Session::getInstance()->Language()->getIso(), Session::getInstance()->Customer()->cLand); + $this->metadata = [ + 'kBestellung' => $this->getBestellung()->kBestellung, + 'kKunde' => $this->getBestellung()->kKunde, + 'kKundengruppe' => Session::getInstance()->CustomerGroup()->kKundengruppe, + 'cHash' => $this->getHash(), + ]; $pm = $this->PaymentMethod(); - if ($pm::METHOD !== '' && (self::Plugin()->oPluginEinstellungAssoc_arr['resetMethod'] !== 'Y' || !$this->getMollie())) { - $this->setRequestData('method', $pm::METHOD); + $isPayAgain = strpos($_SERVER['PHP_SELF'], 'bestellab_again') !== false; + if ($pm::METHOD !== '' && (self::Plugin()->oPluginEinstellungAssoc_arr['resetMethod'] !== 'Y' || !$isPayAgain)) { + $this->method = $pm::METHOD; } foreach ($options as $key => $value) { - $this->setRequestData($key, $value); + $this->$key = $value; } return $this; } + /** + * @return object|null + */ public function getIncomingPayment() { if (!$this->getMollie()) { return null; } + if (in_array($this->getMollie()->status, [PaymentStatus::STATUS_AUTHORIZED, PaymentStatus::STATUS_PAID], true)) { $data = []; $data['fBetrag'] = (float)$this->getMollie()->amount->value; $data['cISO'] = $this->getMollie()->amount->currency; $data['cZahler'] = $this->getMollie()->details->paypalPayerId ?: $this->getMollie()->customerId; $data['cHinweis'] = $this->getMollie()->details->paypalReference ?: $this->getMollie()->id; + if (isset($this->getMollie()->details, $this->getMollie()->details->paypalFee)) { + $data['fZahlungsgebuehr'] = $this->getMollie()->details->paypalFee->value; + } return (object)$data; } return null; diff --git a/version/200/class/Hook/Queue.php b/version/200/class/Hook/Queue.php index de05da1..e4a47bf 100644 --- a/version/200/class/Hook/Queue.php +++ b/version/200/class/Hook/Queue.php @@ -92,19 +92,20 @@ public static function headPostGet() } if (strpos($raw->cOrderId, 'tr_') === 0) { - $checkout = PaymentCheckout::fromID($raw->cOrderId); + $checkout = PaymentCheckout::fromID($raw->kID); } else { - $checkout = OrderCheckout::fromID($raw->cOrderId); + $checkout = OrderCheckout::fromID($raw->kID); } $checkout->getMollie(true); $checkout->updateModel()->saveModel(); - if ($checkout->getBestellung()->dBezahltDatum !== null || in_array($checkout->getModel()->cStatus, ['completed', 'paid', 'authorized', 'pending'])) { + if (($checkout->getBestellung()->dBezahltDatum !== null && $checkout->getBestellung()->dBezahltDatum !== '0000-00-00') + || in_array($checkout->getModel()->cStatus, ['completed', 'paid', 'authorized', 'pending'])) { throw new RuntimeException(self::Plugin()->oPluginSprachvariableAssoc_arr['errAlreadyPaid']); } $options = []; - if (self::Plugin()->oPluginEinstellungAssoc_arr['resetMethod'] !== 'on') { + if (self::Plugin()->oPluginEinstellungAssoc_arr['resetMethod'] !== 'Y') { $options['method'] = $checkout->getModel()->cMethod; } diff --git a/version/200/class/Queue.php b/version/200/class/Queue.php index 4f00864..e8e6eec 100644 --- a/version/200/class/Queue.php +++ b/version/200/class/Queue.php @@ -7,6 +7,9 @@ use Exception; use Generator; use Jtllog; +use JTLMollie; +use Mollie\Api\Exceptions\ApiException; +use Mollie\Api\Exceptions\IncompatiblePlatform; use Mollie\Api\Types\OrderStatus; use RuntimeException; use Shop; @@ -74,9 +77,8 @@ protected static function handleWebhook($id, QueueModel $todo) * @param $hook * @param QueueModel $todo * @return bool - * @throws \Mollie\Api\Exceptions\ApiException - * @throws \Mollie\Api\Exceptions\IncompatiblePlatform - * @todo TEST / DEBUG !!! + * @throws ApiException + * @throws IncompatiblePlatform */ protected static function handleHook($hook, QueueModel $todo) { @@ -92,7 +94,7 @@ protected static function handleHook($hook, QueueModel $todo) return $todo->done("Bestellung noch nicht versendet: {$checkout->getBestellung()->cStatus}"); } - /** @var $method \JTLMollie */ + /** @var $method JTLMollie */ if ((int)$data['status'] && array_key_exists('status', $data) && $checkout->PaymentMethod() @@ -107,13 +109,13 @@ protected static function handleHook($hook, QueueModel $todo) if ($shipments = Shipment::syncBestellung($checkout)) { foreach ($shipments as $shipment) { if (is_string($shipment)) { - $checkout->PaymentMethod()->doLog("Shipping-Error: {$shipment}"); - $result .= "Shipping-Error: {$shipment}\n"; + $checkout->PaymentMethod()->Log("Shipping-Error: {$shipment}", $checkout->LogData()); + $result .= "Shipping-Error: {$shipment};\n"; + } else { - $checkout->PaymentMethod()->doLog("Order shipped: \n" . print_r($shipment, 1)); - $result .= "Order shipped: {$shipment->id}\n"; + $checkout->PaymentMethod()->Log("Order shipped: \n" . print_r($shipment, 1)); + $result .= "Order shipped: {$shipment->id};\n"; } - } } else { $result = 'No Shipments ready!'; @@ -122,18 +124,19 @@ protected static function handleHook($hook, QueueModel $todo) $result = $e->getMessage() . "\n" . $e->getFile() . ":" . $e->getLine() . "\n" . $e->getTraceAsString(); } } else { - $result = 'Unexpected Mollie Status: ' . $checkout->getMollie()->status; + $result = sprintf('Unerwarteter Mollie Status "%s" für %s', $checkout->getMollie()->status, $checkout->getBestellung()->cBestellNr); } - } else { $result = 'Nothing to do.'; } - return $todo->done($result); + } else { + $result = "kBestellung missing"; } - return $todo->done("kBestellung missing"); + $checkout->PaymentMethod()->Log("Queue::handleHook: " . $result, $checkout->LogData()); + return $todo->done($result); case HOOK_BESTELLUNGEN_XML_BEARBEITESTORNO: - if (self::Plugin()->oPluginEinstellungAssoc_arr['autoRefund'] !== 'on') { + if (self::Plugin()->oPluginEinstellungAssoc_arr['autoRefund'] !== 'Y') { throw new RuntimeException('Auto-Refund disabled'); } diff --git a/version/200/class/Shipment.php b/version/200/class/Shipment.php index 40b0000..9d3328a 100644 --- a/version/200/class/Shipment.php +++ b/version/200/class/Shipment.php @@ -15,24 +15,21 @@ use RuntimeException; use Shop; use Versand; +use ws_mollie\Checkout\AbstractResource; use ws_mollie\Checkout\OrderCheckout; -use ws_mollie\Traits\Plugin; -use ws_mollie\Traits\RequestData; use ws_mollie\Model\Shipment as ShipmentModel; /** * Class Shipment * @package ws_mollie * - * @todo TEST / DEBUG !!! + * @property array|null $lines + * @property string|null $tracking + * */ -class Shipment +class Shipment extends AbstractResource { - use Plugin; - - use RequestData; - /** * @var int|null */ @@ -56,6 +53,11 @@ class Shipment */ protected $model; + /** + * @var bool + */ + protected $isGuest = false; + /** * Shipment constructor. * @param $kLieferschein @@ -75,9 +77,35 @@ public function __construct($kLieferschein, OrderCheckout $checkout = null) if (!count($this->getLieferschein()->oVersand_arr)) { throw new RuntimeException('Kein Versand gefunden!'); } + + if (!$this->getCheckout()->getBestellung()->oKunde->nRegistriert) { + $this->isGuest = true; + } + } + + public function getLieferschein() + { + if (!$this->oLieferschein && $this->kLieferschein) { + $this->oLieferschein = new Lieferschein($this->kLieferschein); + } + return $this->oLieferschein; + } + + /** + * @return OrderCheckout + * @throws Exception + */ + public function getCheckout() + { + if (!$this->checkout) { + //TODO evtl. load by lieferschien + throw new Exception('Should not happen, but it did!'); + } + return $this->checkout; } - public static function syncBestellung(OrderCheckout $checkout){ + public static function syncBestellung(OrderCheckout $checkout) + { $shipments = []; if ($checkout->getBestellung()->kBestellung) { @@ -122,12 +150,28 @@ public static function syncBestellung(OrderCheckout $checkout){ return $shipments; } - public function getLieferschein() + /** + * @return mixed + * @throws ApiException + * @throws IncompatiblePlatform + * @throws Exception + */ + public function send() { - if (!$this->oLieferschein && $this->kLieferschein) { - $this->oLieferschein = new Lieferschein($this->kLieferschein); + + if ($this->getShipment()) { + throw new RuntimeException('Lieferschien bereits an Mollie übertragen: ' . $this->getShipment()->id); } - return $this->oLieferschein; + + if ($this->getCheckout()->getMollie(true)->status === OrderStatus::STATUS_COMPLETED) { + throw new RuntimeException('Bestellung bei Mollie bereits abgeschlossen!'); + } + + $api = $this->getCheckout()->API()->Client(); + $this->shipment = $api->shipments->createForId($this->checkout->getModel()->kID, $this->loadRequest()->getRequestData()); + + return $this->updateModel()->saveModel(); + } /** @@ -145,7 +189,6 @@ public function getShipment($force = false) return $this->shipment; } - /** * @return ShipmentModel * @throws Exception @@ -153,10 +196,10 @@ public function getShipment($force = false) public function getModel() { if (!$this->model && $this->kLieferschein) { - $this->model = ShipmentModel::fromID($this->kLieferschein,'kLieferschein'); + $this->model = ShipmentModel::fromID($this->kLieferschein, 'kLieferschein'); if (!$this->model->dCreated) { - $this->getModel()->dCreated = date('Y-m-d H:i:s'); + $this->model->dCreated = date('Y-m-d H:i:s'); } $this->updateModel(); } @@ -185,19 +228,6 @@ public function updateModel() return $this; } - /** - * @return OrderCheckout - * @throws Exception - */ - public function getCheckout() - { - if (!$this->checkout) { - //TODO evtl. load by lieferschien - throw new Exception('Should not happen, but it did!'); - } - return $this->checkout; - } - /** * @param array $options * @return $this @@ -215,43 +245,18 @@ public function loadRequest($options = []) if ($oVersand->getLogistikVarUrl()) { $tracking['url'] = $oVersand->getLogistikURL(); } - $this->setRequestData('tracking', $tracking); + $this->tracking = $tracking; } // TODO: Wenn alle Lieferschiene in der WAWI erstellt wurden, aber nicht im Shop, kommt status 4. - if ((int)$this->getCheckout()->getBestellung()->cStatus === BESTELLUNG_STATUS_VERSANDT) { - $this->setRequestData('lines', []); + if ($this->isGuest || (int)$this->getCheckout()->getBestellung()->cStatus === BESTELLUNG_STATUS_VERSANDT) { + $this->lines = []; } else { - $this->setRequestData('lines', $this->getOrderLines()); + $this->lines = $this->getOrderLines(); } return $this; } - /** - * @return mixed - * @throws ApiException - * @throws IncompatiblePlatform - * @throws Exception - */ - public function send() - { - - if ($this->getShipment()) { - throw new RuntimeException('Lieferschien bereits an Mollie übertragen: ' . $this->getShipment()->id); - } - - if ($this->getCheckout()->getMollie(true)->status === OrderStatus::STATUS_COMPLETED) { - throw new RuntimeException('Bestellung bei Mollie bereits abgeschlossen!'); - } - - $api = $this->getCheckout()->API()->Client(); - - $this->shipment = $api->shipments->createForId($this->checkout->getModel()->kID, $this->loadRequest()->getRequestData()); - - return $this->updateModel()->saveModel(); - - } - /** * @return array * @throws Exception @@ -288,11 +293,8 @@ protected function getOrderLines() $shippedOrderLines[] = $orderLine->id; break; } - } } - - return $lines; } diff --git a/version/200/class/Traits/RequestData.php b/version/200/class/Traits/RequestData.php index 7894bd8..f56f6ef 100644 --- a/version/200/class/Traits/RequestData.php +++ b/version/200/class/Traits/RequestData.php @@ -12,37 +12,27 @@ trait RequestData */ protected $requestData; - /** - * @param $key string - * @return mixed|null - */ - public function RequestData($key) + public function jsonSerialize() { - if (!$this->getRequestData()) { - $this->loadRequest(); - } - return $this->requestData[$key] ?: null; + return $this->requestData; } - /** - * @return array|null - */ - public function getRequestData() + public function __get($name) { - return $this->requestData; + if (!$this->requestData) { + $this->loadRequest(); + } + return is_string($this->requestData[$name]) ? utf8_decode($this->requestData[$name]) : $this->requestData[$name]; } - /** - * @param $key - * @param $value - * @return $this - */ - public function setRequestData($key, $value) + public function __set($name, $value) { if (!$this->requestData) { $this->requestData = []; } - $this->requestData[$key] = $value; + + $this->requestData[$name] = is_string($value) ? utf8_encode($value) : $value; + return $this; } @@ -50,13 +40,20 @@ public function setRequestData($key, $value) * @param array $options * @return $this */ - public function loadRequest($options = []){ + public function loadRequest($options = []) + { return $this; } - public function jsonSerialize() + + public function __serialize() { - return $this->requestData; + return $this->requestData ?: []; + } + + public function __isset($name) + { + return $this->requestData[$name] !== null; } } \ No newline at end of file diff --git a/version/200/frontend/140_smarty.php b/version/200/frontend/140_smarty.php index 65bbdf7..6cddd50 100644 --- a/version/200/frontend/140_smarty.php +++ b/version/200/frontend/140_smarty.php @@ -9,13 +9,6 @@ ApplePay::execute(isset($args_arr) ? $args_arr : []); -// TODO ERROR MESSAGE -// if (array_key_exists('mollieStatus', $_REQUEST)) { -// $status = $_REQUEST['mollieStatus']; -// $text = Helper::oPlugin()->oPluginSprachvariableAssoc_arr['error_' . $status]; -// pq('#fieldset-payment')->prepend('
' . $text . '
'); -// } - // TODO STYLES // switch (Helper::getSetting('load_styles')) { // case 'Y': diff --git a/version/200/paymentmethod/JTLMollie.php b/version/200/paymentmethod/JTLMollie.php index 1073ed9..9fdfda7 100644 --- a/version/200/paymentmethod/JTLMollie.php +++ b/version/200/paymentmethod/JTLMollie.php @@ -100,8 +100,9 @@ public function preparePaymentProcess($order) header('Location: ' . $url); } } catch (Exception $e) { - $this->Log('mollie::preparePaymentProcess: ' . $e->getMessage() . ' - ' . print_r(['cBestellNr' => $order->cBestellNr], 1), LOGLEVEL_ERROR); - Shop::Smarty()->assign('oMollieException', $e); + $this->Log('mollie::preparePaymentProcess: ' . $e->getMessage() . ' - ' . print_r(['cBestellNr' => $order->cBestellNr], 1), '#' . $order->kBestellung, LOGLEVEL_ERROR); + Shop::Smarty()->assign('oMollieException', $e) + ->assign('tryAgain', Shop::getURL() . '/bestellab_again.php?kBestellung=' . $order->kBestellung); } } @@ -167,7 +168,12 @@ public function isSelectable() if ($selectable) { try { $locale = AbstractCheckout::getLocale(Session::getInstance()->Language()->getIso(), Session::getInstance()->Customer()->cLand); - $amount = Session::getInstance()->Basket()->gibGesamtsummeWaren(true) * Session::getInstance()->Currency()->fFaktor; + $amount = Session::getInstance()->Basket()->gibGesamtsummeWarenExt([ + C_WARENKORBPOS_TYP_ARTIKEL, + C_WARENKORBPOS_TYP_KUPON, + C_WARENKORBPOS_TYP_GUTSCHEIN, + C_WARENKORBPOS_TYP_NEUKUNDENKUPON, + ], true) * Session::getInstance()->Currency()->fFaktor; if ($amount <= 0) { $amount = 0.01; } @@ -251,32 +257,4 @@ public function getExpiryDays() return (int)min(abs((int)Helper::oPlugin()->oPluginEinstellungAssoc_arr[$this->cModulId . '_dueDays']), static::MAX_EXPIRY_DAYS) ?: static::MAX_EXPIRY_DAYS; } - /** - * @param $cISOSprache - * @param $method - * @deprecated - * @noinspection PhpDeprecationInspection - * @noinspection PhpDeprecationInspection - */ - 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); - } - } } diff --git a/version/200/paymentmethod/JTLMollieCreditCard.php b/version/200/paymentmethod/JTLMollieCreditCard.php index ec85fe5..b689e51 100644 --- a/version/200/paymentmethod/JTLMollieCreditCard.php +++ b/version/200/paymentmethod/JTLMollieCreditCard.php @@ -16,6 +16,11 @@ class JTLMollieCreditCard extends JTLMollie public function handleNotification($order, $hash, $args) { parent::handleNotification($order, $hash, $args); + } + + public function preparePaymentProcess($order) + { + parent::preparePaymentProcess($order); $this->clearToken(); } @@ -46,7 +51,7 @@ public function handleAdditional($aPost_arr) } try { - $trustBadge = (bool)self::Plugin()->oPluginEinstellungAssoc_arr[$this->moduleID . '_trustBadge']; + $trustBadge = (bool)self::Plugin()->oPluginEinstellungAssoc_arr[$this->moduleID . '_loadTrust']; $locale = AbstractCheckout::getLocale(Session::getInstance()->Language()->getIso(), Session::getInstance()->Customer() ? Session::getInstance()->Customer()->cLand : null); $mode = API::getMode(); $errorMessage = json_encode(self::Plugin()->oPluginSprachvariableAssoc_arr['mcErrorMessage']); @@ -65,7 +70,7 @@ public function handleAdditional($aPost_arr) } Shop::Smarty()->assign('profileId', $profileId) - ->assign('trustBadge', $trustBadge ?: false) + ->assign('trustBadge', $trustBadge ? self::Plugin()->cFrontendPfadURLSSL . 'img/trust_' . $_SESSION['cISOSprache'] . '.png' : false) ->assign('components', $components) ->assign('locale', $locale ?: 'de_DE') ->assign('token', $token ?: false) diff --git a/version/200/paymentmethod/tpl/bestellabschluss.tpl b/version/200/paymentmethod/tpl/bestellabschluss.tpl index 63becef..b26d8ef 100644 --- a/version/200/paymentmethod/tpl/bestellabschluss.tpl +++ b/version/200/paymentmethod/tpl/bestellabschluss.tpl @@ -2,14 +2,21 @@
{$oMollieException->getMessage()}
+ {/if} {if isset($redirect) && $redirect != ''} {if $checkoutMode == 'D'} diff --git a/version/200/paymentmethod/tpl/mollieComponents.tpl b/version/200/paymentmethod/tpl/mollieComponents.tpl index fce180c..38907e0 100644 --- a/version/200/paymentmethod/tpl/mollieComponents.tpl +++ b/version/200/paymentmethod/tpl/mollieComponents.tpl @@ -1,6 +1,31 @@

{$mollieLang.cctitle}

+
+
+ + {if $token !== false} + +
+
+ {$mollieLang.clearDescr} +
+
+ +
+
+ + {if $trustBadge} +
+ PCI-DSS SAQ-A compliant +
+ {/if} + + {else} + +
@@ -40,8 +65,8 @@

{$mollieLang.cvchint_2}

-
+ {if $trustBadge}
PCI-DSS SAQ-A compliant - +{/if} + + + + - - - +{/if} diff --git a/version/201/adminmenu/tpl/mollie-account-erstellen.png b/version/201/adminmenu/tpl/mollie-account-erstellen.png new file mode 100644 index 0000000000000000000000000000000000000000..fc1819255ef725fa214cf2bf028cf3428794ecee GIT binary patch literal 38998 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 +

+ « + 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 isset($order->customerId)} + ID: + {$order->customerId} +
+ {/if} + {if isset($order->billingAddress, $order->billingAddress->organizationName)} + {$order->billingAddress->organizationName} + {elseif isset($order->billingAddress)} + {$order->billingAddress->title} {$order->billingAddress->givenName} {$order->billingAddress->familyName} + {/if} +
Mollie Checkout: + {if $order->getCheckoutURL()} + mollie.com/... + {else} + n/a + {/if} + RePay-URL: + +
+{if $order->id|strpos:"ord_" !== false && $order->payments()->count > 0} +

Zahlungen

+ + + + + + + + + + + + + + {foreach from=$order->payments() item=payment} + + + + + + + + + + + {/foreach} +
IDStatusMethodeAmountSettlementRefundedRemainingDetails
{$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} +
+
+{/if} + +
+ {if ($order->status === 'authorized' || $order->status === 'shipping') && $oBestellung->cStatus|intval >= 3} + + Zahlung erfassen1 + + {/if} + {if !$order->amountRefunded || ($order->amount->value > $order->amountRefunded->value)} + Rückerstatten2 + + {/if} + {if $order->isCancelable} + Abbrechen3 + + {/if} +
+ +{if $order->id|strpos:"ord_" !== false} +

Positionen:

+ + + + + + + + + + + + + + + + + {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} + + + + + + + + + + + + + {/foreach} + + + + + + + + + + +
StatusSKUNameTypAnzahlMwStSteuerNettoBrutto 
+ {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'} + abgebrochen + {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*} +
{$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.
+
+{/if} + +{if isset($shipments) && $shipments|count} +

Shipmets

+ + + + + + + + + + + {foreach from=$shipments item=shipment} + + + + + + + {/foreach} + +
Lieferschein Nr.Mollie IDCarrierCode
{$shipment->getLieferschein()->getLieferscheinNr()}{$shipment->getShipment()->id} + {if isset($shipment->getShipment()->tracking)} + {$shipment->getShipment()->tracking->carrier} + {else} + - + {/if} + {if isset($shipment->getShipment()->tracking)} + {if isset($shipment->getShipment()->tracking->url)} + + {$shipment->getShipment()->tracking->code} + + {else} + {$shipment->getShipment()->tracking->code} + {/if} + {else} + - + {/if} +
+{/if} + +

Log

+ + {foreach from=$logs item=log} + + + + + + + {/foreach} +
+ {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}
+ + diff --git a/version/201/adminmenu/tpl/orders.tpl b/version/201/adminmenu/tpl/orders.tpl new file mode 100644 index 0000000..8745a0c --- /dev/null +++ b/version/201/adminmenu/tpl/orders.tpl @@ -0,0 +1,158 @@ +{ws_mollie\Helper::showAlerts('orders')} + +{if $hasAPIKey == false} + + Jetzt kostenlos Mollie Account eröffnen! + +{else} + + + + + + + + + + + + + + + {foreach from=$checkouts item=checkout} + + + + + + + + + + + + + + + {/foreach} + +
BestellNr.IDMollie StatusJTL StatusBetragMethodeErstellt 
+ {if $checkout->getModel()->bSynced == false && $checkout->getBestellung()->cAbgeholt === 'Y'} + * + {/if} + {$checkout->getModel()->cOrderNumber} + {if $checkout->getModel()->cMode == 'test'} + TEST + {/if} + {if $checkout->getModel()->bLockTimeout} + LOCK TIMEOUT + {/if} + {if $checkout->getModel()->dReminder && $checkout->getModel()->dReminder !== '0000-00-00 00:00:00'} + getModel()->dReminder|strtotime}}"> + {/if} + + {$checkout->getModel()->kID} + + {if $checkout->getModel()->cStatus == 'created' || $checkout->getModel()->cStatus == 'open'} + erstellt + {elseif $checkout->getModel()->cStatus == 'pending'} + austehend + {elseif $checkout->getModel()->cStatus == 'paid'} + bezahlt + {elseif $checkout->getModel()->cStatus == 'authorized'} + autorisiert + {elseif $checkout->getModel()->cStatus == 'shipping'} + versendet + {elseif $checkout->getModel()->cStatus == 'completed'} + abgeschlossen + {elseif $checkout->getModel()->cStatus == 'expired'} + abgelaufen + {elseif $checkout->getModel()->cStatus == 'canceled'} + abgebrochen + {else} + Unbekannt: {$checkout->getModel()->cStatus} + {/if} + {if $checkout->getModel()->fAmountRefunded && $checkout->getModel()->fAmountRefunded == $checkout->getModel()->fAmount} + (total refund) + {elseif $checkout->getModel()->fAmountRefunded && $checkout->getModel()->fAmountRefunded > 0} + (partly refund) + {/if} + + + {if $checkout->getBestellung()->cStatus|intval == 1} + OFFEN + {elseif $checkout->getBestellung()->cStatus|intval == 2} + IN BEARBEITUNG + {elseif $checkout->getBestellung()->cStatus|intval == 3} + BEZAHLT + {elseif $checkout->getBestellung()->cStatus|intval == 4} + VERSANDT + {elseif $checkout->getBestellung()->cStatus|intval == 5} + TEILVERSANDT + {elseif $checkout->getBestellung()->cStatus|intval == -1} + STORNO + {else} + n/a + {/if} + {$checkout->getModel()->fAmount|number_format:2:',':''} {$checkout->getModel()->cCurrency}{$checkout->getModel()->cMethod}{"d. M Y H:i"|date:{$checkout->getModel()->dCreatedAt|strtotime}} +
+ +
+ {if $checkout->getModel()->bSynced == false && $checkout->getBestellung()->cAbgeholt === 'Y'} + + {/if} + {if $checkout->remindable()} + + {/if} +
+
+
+ {if $payments|count > 900} +
Hier werden nur die letzten 1000 Ergebnisse angezeigt.
+ {/if} + + +
+
+

Export:

+
+ +
+ + + + + +
+
+ +{/if} + diff --git a/version/201/adminmenu/tpl/paymentmethods.tpl b/version/201/adminmenu/tpl/paymentmethods.tpl new file mode 100644 index 0000000..4fc8ab0 --- /dev/null +++ b/version/201/adminmenu/tpl/paymentmethods.tpl @@ -0,0 +1,138 @@ +

Account Status

+ + + + + + + {if $profile->review} + + + {/if} + +
Mode:{$profile->mode}Status:{$profile->status}Review:{$profile->review->status}
+ +
+ +
+
+ + +
+ + + +
+
+ + +
+
+ + +
+
+ + + reset +
+
+
+ + +{if $allMethods && $allMethods|count} + + + + + + + + + + + + {foreach from=$allMethods item=method} + + + + + + + + {/foreach} + +
BildName / IDInfoPreiseLimits
{$method->mollie->description|utf8_decode} + {if $method->mollie->status === 'activated'} + + {else} + + {/if} + {$method->mollie->description|utf8_decode}
+ {$method->mollie->id} +
+ {if $method->shop && $method->oClass} + + {if intval($method->shop->nWaehrendBestellung) === 1} + Zahlung VOR Bestellabschluss nicht unterstützt! + {/if} + + {*if $method->shop->nWaehrendBestellung} + Zahlung + VOR + Bestellabschluss + {if $method->warning} +
+ + + Gültigkeit ist länger als Session-Laufzeit ({$method->session}). + + {/if} + {else} + Zahlung + NACH + Bestellabschluss + {/if*} +
+ Gültigkeit: {$method->maxExpiryDays} Tage + + {else} + Derzeit nicht unterstützt. + {/if} +
+
    + {foreach from=$method->mollie->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->mollie->minimumAmount}{$method->mollie->minimumAmount->value} {$method->mollie->minimumAmount->currency}{else}n/a{/if} +
+ Max: {if $method->mollie->maximumAmount}{$method->mollie->maximumAmount->value} {$method->mollie->maximumAmount->currency}{else}n/a{/if} +
+{else} +
Es konnten keine Methoden abgerufen werden.
+{/if} \ No newline at end of file diff --git a/version/201/class/API.php b/version/201/class/API.php new file mode 100644 index 0000000..ef6293d --- /dev/null +++ b/version/201/class/API.php @@ -0,0 +1,78 @@ +test = $test === null ? self::getMode() : $test; + } + + /** + * @return bool + */ + public static function getMode() + { + require_once PFAD_ROOT . PFAD_ADMIN . PFAD_INCLUDES . 'benutzerverwaltung_inc.php'; + return Shop::isAdmin() && self::Plugin()->oPluginEinstellungAssoc_arr["testAsAdmin"] === 'Y'; + } + + /** + * @return MollieApiClient + * @throws ApiException + * @throws IncompatiblePlatform + */ + public function Client() + { + if (!$this->client) { + $this->client = new MollieApiClient(new Client([ + RequestOptions::VERIFY => CaBundle::getBundledCaBundlePath(), + RequestOptions::TIMEOUT => 60 + ])); + $this->client->setApiKey($this->isTest() ? self::Plugin()->oPluginEinstellungAssoc_arr['test_api_key'] : self::Plugin()->oPluginEinstellungAssoc_arr['api_key']) + ->addVersionString('JTL-Shop/' . JTL_VERSION . JTL_MINOR_VERSION) + ->addVersionString('ws_mollie/' . self::Plugin()->nVersion); + } + return $this->client; + } + + /** + * @return bool + */ + public function isTest() + { + return $this->test; + } + + +} \ No newline at end of file diff --git a/version/201/class/Checkout/AbstractCheckout.php b/version/201/class/Checkout/AbstractCheckout.php new file mode 100644 index 0000000..e77deb6 --- /dev/null +++ b/version/201/class/Checkout/AbstractCheckout.php @@ -0,0 +1,621 @@ + ['lang' => 'de', 'country' => ['DE', 'AT', 'CH']], + 'fre' => ['lang' => 'fr', 'country' => ['BE', 'FR']], + 'dut' => ['lang' => 'nl', 'country' => ['BE', 'NL']], + 'spa' => ['lang' => 'es', 'country' => ['ES']], + 'ita' => ['lang' => 'it', 'country' => ['IT']], + 'pol' => ['lang' => 'pl', 'country' => ['PL']], + 'hun' => ['lang' => 'hu', 'country' => ['HU']], + 'por' => ['lang' => 'pt', 'country' => ['PT']], + 'nor' => ['lang' => 'nb', 'country' => ['NO']], + 'swe' => ['lang' => 'sv', 'country' => ['SE']], + 'fin' => ['lang' => 'fi', 'country' => ['FI']], + 'dan' => ['lang' => 'da', 'country' => ['DK']], + 'ice' => ['lang' => 'is', 'country' => ['IS']], + 'eng' => ['lang' => 'en', 'country' => ['GB', 'US']], + ]; + /** + * @var \Mollie\Api\Resources\Customer|null + */ + protected $customer; + + /** + * @var string + */ + private $hash; + /** + * @var API + */ + private $api; + /** + * @var JTLMollie + */ + private $paymentMethod; + /** + * @var Bestellung + */ + private $oBestellung; + /** + * @var Payment + */ + private $model; + + /** + * AbstractCheckout constructor. + * @param $oBestellung + * @param null $api + */ + public function __construct(Bestellung $oBestellung, $api = null) + { + $this->api = $api; + $this->oBestellung = $oBestellung; + } + + /** + * @param int $kBestellung + * @param bool $checkZA + * @return bool + */ + public static function isMollie($kBestellung, $checkZA = false) + { + if ($checkZA) { + $res = Shop::DB()->executeQueryPrepared('SELECT * FROM tzahlungsart WHERE cModulId LIKE :cModulId AND kZahlungsart = :kZahlungsart', [ + ':kZahlungsart' => $kBestellung, + ':cModulId' => 'kPlugin_' . self::Plugin()->kPlugin . '_%' + ], 1); + return $res ? true : false; + } + + return ($res = Shop::DB()->executeQueryPrepared('SELECT kId FROM xplugin_ws_mollie_payments WHERE kBestellung = :kBestellung;', [ + ':kBestellung' => $kBestellung, + ], 1)) && $res->kId; + } + + /** + * @param $kBestellung + * @return OrderCheckout|PaymentCheckout + * * @throws RuntimeException + */ + public static function fromBestellung($kBestellung) + { + if ($model = Payment::fromID($kBestellung, 'kBestellung')) { + return self::fromModel($model); + } + throw new RuntimeException(sprintf('Error loading Order for Bestellung: %s', $kBestellung)); + } + + /** + * @param $model + * @return OrderCheckout|PaymentCheckout + * @throws RuntimeException + */ + public static function fromModel($model, $bFill = true) + { + if (!$model) { + throw new RuntimeException(sprintf('Error loading Order for Model: %s', print_r($model, 1))); + } + + $oBestellung = new Bestellung($model->kBestellung, $bFill); + if (!$oBestellung->kBestellung) { + throw new RuntimeException(sprintf('Error loading Bestellung: %s', $model->kBestellung)); + } + + if (strpos($model->kID, 'tr_') !== false) { + $self = new PaymentCheckout($oBestellung); + } else { + $self = new OrderCheckout($oBestellung); + } + + $self->setModel($model); + return $self; + } + + public static function sendReminders() + { + $reminder = (int)self::Plugin()->oPluginEinstellungAssoc_arr['reminder']; + + /*if (!$reminder) { + Shop::DB()->executeQueryPrepared('UPDATE xplugin_ws_mollie_payments SET dReminder = :dReminder WHERE dReminder IS NULL', [ + ':dReminder' => date('Y-m-d H:i:s') + ], 3); + return; + }*/ + + $sql = "SELECT p.kId FROM xplugin_ws_mollie_payments p JOIN tbestellung b ON b.kBestellung = p.kBestellung WHERE p.dReminder IS NULL OR p.dReminder = '0000-00-00 00:00:00' AND p.dCreatedAt < NOW() - INTERVAL :d HOUR AND p.cStatus IN ('created','open', 'expired', 'failed', 'canceled') AND NOT b.cStatus = '-1'"; + + $remindables = Shop::DB()->executeQueryPrepared($sql, [ + ':d' => $reminder + ], 2); + foreach ($remindables as $remindable) { + try { + self::sendReminder($remindable->kId); + } catch (Exception $e) { + Jtllog::writeLog("AbstractCheckout::sendReminders: " . $e->getMessage()); + } + } + } + + public static function sendReminder($kID) + { + + $checkout = self::fromID($kID); + $return = true; + try { + $repayURL = Shop::getURL() . '/?m_pay=' . md5($checkout->getModel()->kID . '-' . $checkout->getBestellung()->kBestellung); + + $data = new stdClass(); + $data->tkunde = new Kunde($checkout->getBestellung()->oKunde->kKunde); + if ($data->tkunde->kKunde) { + + $data->Bestellung = $checkout->getBestellung(); + $data->PayURL = $repayURL; + $data->Amount = gibPreisStringLocalized($checkout->getModel()->fAmount, $checkout->getBestellung()->Waehrung); //Preise::getLocalizedPriceString($order->getAmount(), Currency::fromISO($order->getCurrency()), false); + + require_once PFAD_ROOT . PFAD_INCLUDES . 'mailTools.php'; + + $mail = new stdClass(); + $mail->toEmail = $data->tkunde->cMail; + $mail->toName = trim((isset($data->tKunde->cVorname) + ? $data->tKunde->cVorname + : '') . ' ' . ( + isset($data->tKunde->cNachname) + ? $data->tKunde->cNachname + : '' + )) ?: $mail->toEmail; + $data->mail = $mail; + if (!($sentMail = sendeMail('kPlugin_' . self::Plugin()->kPlugin . '_zahlungserinnerung', $data))) { + $checkout->Log(sprintf("Zahlungserinnerung konnte nicht versand werden: %s\n%s", isset($sentMail->cFehler) ?: print_r($sentMail, 1), print_r($data, 1)), LOGLEVEL_ERROR); + $return = false; + } else { + $checkout->Log(sprintf("Zahlungserinnerung für %s verschickt.", $checkout->getBestellung()->cBestellNr)); + } + } else { + $checkout->Log("Kunde '{$checkout->getBestellung()->oKunde->kKunde}' nicht gefunden.", LOGLEVEL_ERROR); + } + } catch (Exception $e) { + $checkout->Log(sprintf("AbstractCheckout::sendReminder: Zahlungserinnerung für %s fehlgeschlagen: %s", $checkout->getBestellung()->cBestellNr, $e->getMessage())); + $return = false; + } + $checkout->getModel()->dReminder = date('Y-m-d H:i:s'); + $checkout->getModel()->save(); + return $return; + } + + /** + * @param $id + * @return OrderCheckout|PaymentCheckout + * @throws RuntimeException + */ + public static function fromID($id) + { + if ($model = Payment::fromID($id)) { + return static::fromModel($model); + } + throw new RuntimeException(sprintf('Error loading Order: %s', $id)); + } + + /** + * @return Payment + */ + public function getModel() + { + if (!$this->model) { + $this->model = Payment::fromID($this->oBestellung->kBestellung, 'kBestellung'); + } + return $this->model; + } + + /** + * @param $model + * @return $this + */ + protected function setModel($model) + { + if (!$this->model) { + $this->model = $model; + } else { + throw new RuntimeException('Model already set.'); + } + return $this; + } + + /** + * @return Bestellung + */ + public function getBestellung() + { + if (!$this->oBestellung && $this->getModel()->kBestellung) { + $this->oBestellung = new Bestellung($this->getModel()->kBestellung, true); + } + return $this->oBestellung; + } + + public function Log($msg, $level = LOGLEVEL_NOTICE) + { + $data = ''; + if ($this->getBestellung()) { + $data .= '#' . $this->getBestellung()->kBestellung; + } + if ($this->getMollie()) { + $data .= '$' . $this->getMollie()->id; + } + ZahlungsLog::add($this->PaymentMethod()->moduleID, "[" . microtime(true) . " - " . $_SERVER['PHP_SELF'] . "] " . $msg, $data, $level); + return $this; + } + + /** + * @param false $force + * @return Order|\Mollie\Api\Resources\Payment|null + */ + abstract public function getMollie($force = false); + + /** + * @return JTLMollie + */ + public function PaymentMethod() + { + if (!$this->paymentMethod) { + if ($this->getBestellung()->Zahlungsart && strpos($this->getBestellung()->Zahlungsart->cModulId, "kPlugin_{$this::Plugin()->kPlugin}_") !== false) { + $this->paymentMethod = PaymentMethod::create($this->getBestellung()->Zahlungsart->cModulId); + } else { + $this->paymentMethod = PaymentMethod::create("kPlugin_{$this::Plugin()->kPlugin}_mollie"); + } + } + /** @noinspection PhpIncompatibleReturnTypeInspection */ + return $this->paymentMethod; + } + + /** + * @param AbstractCheckout $checkout + * @return \Mollie\Api\Resources\BaseResource|\Mollie\Api\Resources\Refund + * @throws ApiException + */ + public static function refund(AbstractCheckout $checkout) + { + if ($checkout->getMollie()->resource === 'order') { + /** @var Order $order */ + $order = $checkout->getMollie(); + if (in_array($order->status, [OrderStatus::STATUS_CANCELED, OrderStatus::STATUS_EXPIRED, OrderStatus::STATUS_CREATED], true)) { + throw new RuntimeException('Bestellung kann derzeit nicht zurückerstattet werden.'); + } + $refund = $order->refundAll(); + $checkout->Log(sprintf('Bestellung wurde manuell zurückerstattet: %s', $refund->id)); + return $refund; + } + if ($checkout->getMollie()->resource === 'payment') { + /** @var \Mollie\Api\Resources\Payment $payment */ + $payment = $checkout->getMollie(); + if (in_array($payment->status, [PaymentStatus::STATUS_CANCELED, PaymentStatus::STATUS_EXPIRED, PaymentStatus::STATUS_OPEN], true)) { + throw new RuntimeException('Zahlung kann derzeit nicht zurückerstattet werden.'); + } + $refund = $checkout->API()->Client()->payments->refund($checkout->getMollie(), ['amount' => $checkout->getMollie()->amount]); + $checkout->Log(sprintf('Zahlung wurde manuell zurückerstattet: %s', $refund->id)); + return $refund; + } + throw new RuntimeException(sprintf('Unbekannte Resource: %s', $checkout->getMollie()->resource)); + } + + /** + * @return API + */ + public function API() + { + if (!$this->api) { + if ($this->getModel()->kID) { + $this->api = new API($this->getModel()->cMode === 'test'); + } else { + $this->api = new API(API::getMode()); + } + } + return $this->api; + } + + /** + * @param $checkout + * @return Order|\Mollie\Api\Resources\Payment + * @throws ApiException + */ + public static function cancel($checkout) + { + if ($checkout instanceof OrderCheckout) { + return OrderCheckout::cancel($checkout); + } + if ($checkout instanceof PaymentCheckout) { + return PaymentCheckout::cancel($checkout); + } + throw new RuntimeException('AbstractCheckout::cancel: Invalid Checkout!'); + } + + /** + * @return array|bool|int|object|null + */ + public function getLogs() + { + return 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' => '%#' . ($this->getBestellung()->kBestellung ?: '##') . '%', + ':cBestellNr' => '%§' . ($this->getBestellung()->cBestellNr ?: '§§') . '%', + ':MollieID' => '%$' . ($this->getMollie()->id ?: '$$') . '%', + ], 2); + } + + /** + * @return bool + */ + public function remindable() + { + return (int)$this->getBestellung()->cStatus !== BESTELLUNG_STATUS_STORNO && !in_array($this->getModel()->cStatus, [PaymentStatus::STATUS_PAID, PaymentStatus::STATUS_AUTHORIZED, PaymentStatus::STATUS_PENDING, OrderStatus::STATUS_COMPLETED, OrderStatus::STATUS_SHIPPING], true); + } + + /** + * @return string + */ + public function LogData() + { + + $data = ''; + if ($this->getBestellung()->kBestellung) { + $data .= '#' . $this->getBestellung()->kBestellung; + } + if ($this->getMollie()) { + $data .= '$' . $this->getMollie()->id; + } + + return $data; + } + + /** + * @return \Mollie\Api\Resources\Customer|null + * @todo: Kunde wieder löschbar machen ?! + */ + public function getCustomer($createOrUpdate = false) + { + if (!$this->customer) { + $customerModel = Customer::fromID($this->getBestellung()->oKunde->kKunde, 'kKunde'); + if ($customerModel->customerId) { + try { + $this->customer = $this->API()->Client()->customers->get($customerModel->customerId); + } catch (ApiException $e) { + $this->Log(sprintf("Fehler beim laden des Mollie Customers %s (kKunde: %d): %s", $customerModel->customerId, $customerModel->kKunde, $e->getMessage()), LOGLEVEL_ERROR); + } + } + + if ($createOrUpdate) { + $oKunde = $this->getBestellung()->oKunde; + + $customer = [ + 'name' => trim($oKunde->cVorname . ' ' . $oKunde->cNachname), + 'email' => $oKunde->cMail, + 'locale' => self::getLocale(Session::getInstance()->Language()->getIso(), $oKunde->cLand), + 'metadata' => (object)[ + 'kKunde' => $oKunde->kKunde, + 'kKundengruppe' => $oKunde->kKundengruppe, + 'cKundenNr' => $oKunde->cKundenNr, + ], + ]; + + if ($this->customer) { // UPDATE + + $this->customer->name = $customer['name']; + $this->customer->email = $customer['email']; + $this->customer->locale = $customer['locale']; + $this->customer->metadata = $customer['metadata']; + + try { + $this->customer->update(); + } catch (Exception $e) { + $this->Log(sprintf("Fehler beim aktualisieren des Mollie Customers %s: %s\n%s", $this->customer->id, $e->getMessage(), print_r($customer, 1)), LOGLEVEL_ERROR); + } + + + } else { // create + + try { + $this->customer = $this->API()->Client()->customers->create($customer); + $customerModel->kKunde = $oKunde->kKunde; + $customerModel->customerId = $this->customer->id; + $customerModel->save(); + $this->Log(sprintf("Customer '%s' für Kunde %s (%d) bei Mollie angelegt.", $this->customer->id, $this->customer->name, $this->getBestellung()->kKunde)); + } catch (Exception $e) { + $this->Log(sprintf("Fehler beim anlegen eines Mollie Customers: %s\n%s", $e->getMessage(), print_r($customer, 1)), LOGLEVEL_ERROR); + } + } + } + } + return $this->customer; + } + + public static function getLocale($cISOSprache = null, $country = null) + { + + if ($cISOSprache === null) { + $cISOSprache = gibStandardsprache()->cISO; + } + if (array_key_exists($cISOSprache, self::$localeLangs)) { + $locale = self::$localeLangs[$cISOSprache]['lang']; + if ($country && is_array(self::$localeLangs[$cISOSprache]['country']) && in_array($country, self::$localeLangs[$cISOSprache]['country'], true)) { + $locale .= '_' . strtoupper($country); + } else { + $locale .= '_' . self::$localeLangs[$cISOSprache]['country'][0]; + } + return $locale; + } + + return self::Plugin()->oPluginEinstellungAssoc_arr['fallbackLocale']; + } + + abstract public function cancelOrRefund($force = false); + + /** + * @param array $paymentOptions + * @return Payment|Order + */ + abstract public function create(array $paymentOptions = []); + + /** + * @param null $hash + */ + public function handleNotification($hash = null) + { + if (!$this->getHash()) { + $this->getModel()->cHash = $hash; + } + + $this->updateModel()->saveModel(); + if (!$this->getBestellung()->dBezahltDatum || $this->getBestellung()->dBezahltDatum === '0000-00-00') { + if ($incoming = $this->getIncomingPayment()) { + $this->PaymentMethod()->addIncomingPayment($this->getBestellung(), $incoming); + + $this->PaymentMethod()->setOrderStatusToPaid($this->getBestellung()); + static::makeFetchable($this->getBestellung(), $this->getModel()); + $this->PaymentMethod()->deletePaymentHash($this->getHash()); + $this->Log(sprintf("Checkout::handleNotification: Bestellung '%s' als bezahlt markiert: %.2f %s", $this->getBestellung()->cBestellNr, (float)$incoming->fBetrag, $incoming->cISO)); + + $oZahlungsart = Shop::DB()->selectSingleRow('tzahlungsart', 'cModulId', $this->PaymentMethod()->moduleID); + if ($oZahlungsart && (int)$oZahlungsart->nMailSenden === 1) { + require_once PFAD_ROOT . 'includes/mailTools.php'; + $this->PaymentMethod()->sendConfirmationMail($this->getBestellung()); + } + if (!$this->completlyPaid()) { + $this->Log(sprintf("Checkout::handleNotification: Bestellung '%s': nicht komplett bezahlt: %.2f %s", $this->getBestellung()->cBestellNr, (float)$incoming->fBetrag, $incoming->cISO), LOGLEVEL_ERROR); + } + } + } + } + + /** + * @return string + */ + public function getHash() + { + if ($this->getModel()->cHash) { + return $this->getModel()->cHash; + } + if (!$this->hash) { + $this->hash = $this->PaymentMethod()->generateHash($this->oBestellung); + } + return $this->hash; + } + + /** + * @return bool + */ + public function saveModel() + { + return $this->getModel()->save(); + } + + /** + * @return $this + */ + public function updateModel() + { + + if ($this->getMollie()) { + $this->getModel()->kID = $this->getMollie()->id; + $this->getModel()->cLocale = $this->getMollie()->locale; + $this->getModel()->fAmount = (float)$this->getMollie()->amount->value; + $this->getModel()->cMethod = $this->getMollie()->method; + $this->getModel()->cCurrency = $this->getMollie()->amount->currency; + $this->getModel()->cStatus = $this->getMollie()->status; + if ($this->getMollie()->amountRefunded) { + $this->getModel()->fAmountRefunded = $this->getMollie()->amountRefunded->value; + } + if ($this->getMollie()->amountCaptured) { + $this->getModel()->fAmountCaptured = $this->getMollie()->amountCaptured->value; + } + $this->getModel()->cMode = $this->getMollie()->mode ?: null; + $this->getModel()->cRedirectURL = $this->getMollie()->redirectUrl; + $this->getModel()->cWebhookURL = $this->getMollie()->webhookUrl; + $this->getModel()->cCheckoutURL = $this->getMollie()->getCheckoutUrl(); + } + + $this->getModel()->kBestellung = $this->getBestellung()->kBestellung; + $this->getModel()->cOrderNumber = $this->getBestellung()->cBestellNr; + $this->getModel()->cHash = $this->getHash(); + + $this->getModel()->bSynced = $this->getModel()->bSynced !== null ? $this->getModel()->bSynced : Helper::getSetting('onlyPaid') !== 'Y'; + return $this; + } + + /** + * @return stdClass + */ + abstract public function getIncomingPayment(); + + /** + * @param Bestellung $oBestellung + * @param Payment $model + * @return bool + */ + public static function makeFetchable(Bestellung $oBestellung, Payment $model) + { + // TODO: force ? + if ($oBestellung->cAbgeholt === 'Y' && !$model->bSynced) { + Shop::DB()->update('tbestellung', 'kBestellung', $oBestellung->kBestellung, (object)['cAbgeholt' => 'N']); + } + $model->bSynced = true; + try { + return $model->save(); + } catch (Exception $e) { + Jtllog::writeLog(sprintf("Fehler beim speichern des Models: %s / Bestellung: %s", $model->kID, $oBestellung->cBestellNr)); + } + return false; + } + + /** + * @return bool + */ + public function completlyPaid() + { + + if ($row = Shop::DB()->executeQueryPrepared("SELECT SUM(fBetrag) as fBetragSumme FROM tzahlungseingang WHERE kBestellung = :kBestellung", [ + ':kBestellung' => $this->getBestellung()->kBestellung + ], 1)) { + return $row->fBetragSumme >= round($this->getBestellung()->fGesamtsumme * (float)$this->getBestellung()->fWaehrungsFaktor, 2); + } + return false; + + } + + /** + * @return string + */ + public function getRepayURL() + { + return Shop::getURL(true) . '/?m_pay=' . md5($this->getModel()->kID . '-' . $this->getBestellung()->kBestellung); + } + +} \ No newline at end of file diff --git a/version/201/class/Checkout/AbstractResource.php b/version/201/class/Checkout/AbstractResource.php new file mode 100644 index 0000000..7ca9813 --- /dev/null +++ b/version/201/class/Checkout/AbstractResource.php @@ -0,0 +1,18 @@ +title = trim(($address->cAnrede === 'm' ? Shop::Lang()->get('mr') : Shop::Lang()->get('mrs')) . ' ' . $address->cTitel) ?: null; + $resource->givenName = $address->cVorname; + $resource->familyName = $address->cNachname; + $resource->email = $address->cMail ?: null; + + if ($organizationName = trim($address->cFirma)) { + $resource->organizationName = $organizationName; + } + + // Validity-Check + // TODO: Phone, with E.164 check + // TODO: Is Email-Format Check needed? + if (!$resource->givenName || !$resource->familyName || !$resource->email) { + throw ResourceValidityException::trigger(ResourceValidityException::ERROR_REQUIRED, ['givenName', 'familyName', 'email'], $resource); + } + return $resource; + } + +} \ No newline at end of file diff --git a/version/201/class/Checkout/Order/OrderLine.php b/version/201/class/Checkout/Order/OrderLine.php new file mode 100644 index 0000000..b68ccc9 --- /dev/null +++ b/version/201/class/Checkout/Order/OrderLine.php @@ -0,0 +1,223 @@ +totalAmount->value; + } + if (abs($sum - (float)$amount->value) > 0) { + $diff = (round((float)$amount->value - $sum, 2)); + if ($diff !== 0.0) { + $line = new self(); + $line->type = $diff > 0 ? OrderLineType::TYPE_SURCHARGE : OrderLineType::TYPE_DISCOUNT; + // TODO: Translation needed? + $line->name = 'Rundungsausgleich'; + $line->quantity = 1; + $line->unitPrice = Amount::factory($diff, $currency); + $line->totalAmount = Amount::factory($diff, $currency); + $line->vatRate = "0.00"; + $line->vatAmount = Amount::factory(0, $currency); + return $line; + } + } + return null; + } + + /** + * @param Bestellung $oBestellung + * @return OrderLine + */ + public static function getCredit(Bestellung $oBestellung) + { + $line = new self(); + $line->type = OrderLineType::TYPE_STORE_CREDIT; + $line->name = 'Guthaben'; + $line->quantity = 1; + // TODO: check currency of Guthaben + $line->unitPrice = Amount::factory($oBestellung->fGuthaben, $oBestellung->Waehrung->cISO); + $line->totalAmount = $line->unitPrice; + $line->vatRate = "0.00"; + $line->vatAmount = Amount::factory(0, $oBestellung->Waehrung->cISO); + + return $line; + } + + /** + * @param stdClass|WarenkorbPos $oPosition + * @param null $currency + * @return OrderLine + */ + public static function factory($oPosition, $currency = null) + { + if (!$oPosition) { + throw new RuntimeException('$oPosition invalid:', print_r($oPosition)); + } + + $resource = new static(); + + $resource->fill($oPosition, $currency); + + // Validity Check + if (!$resource->name || !$resource->quantity || !$resource->unitPrice || !$resource->totalAmount + || !$resource->vatRate || !$resource->vatAmount) { + throw ResourceValidityException::trigger(ResourceValidityException::ERROR_REQUIRED, + ['name', 'quantity', 'unitPrice', 'totalAmount', 'vatRate', 'vatAmount'], $resource); + } + + return $resource; + + } + + /** + * @param WarenkorbPos|stdClass $oPosition + * @param null|stdClass $currency + * @return $this + * @todo Setting for Fraction handling needed? + */ + protected function fill($oPosition, $currency = null) + { + + if (!$currency) { + $currency = Amount::FallbackCurrency(); + } + + $isKupon = (int)$oPosition->nPosTyp === (int)C_WARENKORBPOS_TYP_KUPON; + $isFrac = fmod($oPosition->nAnzahl, 1) !== 0.0; + + // Kupon? set vatRate to 0 and adjust netto + $vatRate = $isKupon ? 0 : (float)$oPosition->fMwSt / 100; + $netto = $isKupon ? round($oPosition->fPreis * (1 + $vatRate), 4) : round($oPosition->fPreis, 4); + + // Fraction? transform, as it were 1, and set quantity to 1 + $netto = round(($isFrac ? $netto * (float)$oPosition->nAnzahl : $netto) * $currency->fFaktor, 4); + $this->quantity = $isFrac ? 1 : (int)$oPosition->nAnzahl; + + // Fraction? include quantity and unit in name + $this->name = $isFrac ? sprintf("%s (%.2f %s)", $oPosition->cName, (float)$oPosition->nAnzahl, $oPosition->cEinheit) : $oPosition->cName; + + $this->mapType($oPosition->nPosTyp); + + //$unitPriceNetto = round(($currency->fFaktor * $netto), 4); + + $this->unitPrice = Amount::factory(round($netto * (1 + $vatRate), 2), $currency->cISO, false); + $this->totalAmount = Amount::factory(round($this->quantity * $this->unitPrice->value, 2), $currency->cISO, false); + + $this->vatRate = number_format($vatRate * 100, 2); + $this->vatAmount = Amount::factory(round($this->totalAmount->value - ($this->totalAmount->value / (1 + $vatRate)), 2), $currency->cISO, false); + + $metadata = []; + + // Is Artikel ? + if (isset($oPosition->Artikel)) { + $this->sku = $oPosition->Artikel->cArtNr; + $metadata['kArtikel'] = $oPosition->kArtikel; + if ($oPosition->cUnique !== '') { + $metadata['cUnique'] = $oPosition->cUnique; + } + } + + if (isset($oPosition->WarenkorbPosEigenschaftArr) && is_array($oPosition->WarenkorbPosEigenschaftArr) && count($oPosition->WarenkorbPosEigenschaftArr)) { + $metadata['properties'] = []; + /** @var WarenkorbPosEigenschaft $warenkorbPosEigenschaft */ + foreach ($oPosition->WarenkorbPosEigenschaftArr as $warenkorbPosEigenschaft) { + $metadata['properties'][] = [ + 'kEigenschaft' => $warenkorbPosEigenschaft->kEigenschaft, + 'kEigenschaftWert' => $warenkorbPosEigenschaft->kEigenschaftWert, + 'name' => $warenkorbPosEigenschaft->cEigenschaftName, + 'value' => $warenkorbPosEigenschaft->cEigenschaftWertName, + ]; + if (strlen(json_encode($metadata)) > 1000) { + array_pop($metadata['properties']); + break; + } + } + + } + $this->metadata = $metadata; + + return $this; + + + } + + /** + * @param $nPosTyp + * @return OrderLine + */ + protected function mapType($nPosTyp) + { + switch ($nPosTyp) { + case C_WARENKORBPOS_TYP_ARTIKEL: + case C_WARENKORBPOS_TYP_GRATISGESCHENK: + // TODO: digital / Download Artikel? + $this->type = OrderLineType::TYPE_PHYSICAL; + return $this; + + case C_WARENKORBPOS_TYP_VERSANDPOS: + $this->type = OrderLineType::TYPE_SHIPPING_FEE; + return $this; + + case C_WARENKORBPOS_TYP_VERPACKUNG: + case C_WARENKORBPOS_TYP_VERSANDZUSCHLAG: + case C_WARENKORBPOS_TYP_ZAHLUNGSART: + case C_WARENKORBPOS_TYP_VERSAND_ARTIKELABHAENGIG: + case C_WARENKORBPOS_TYP_NACHNAHMEGEBUEHR: + $this->type = OrderLineType::TYPE_SURCHARGE; + return $this; + + case C_WARENKORBPOS_TYP_GUTSCHEIN: + case C_WARENKORBPOS_TYP_KUPON: + case C_WARENKORBPOS_TYP_NEUKUNDENKUPON: + $this->type = OrderLineType::TYPE_DISCOUNT; + return $this; + + } + + throw new RuntimeException('Unknown PosTyp.', (int)$nPosTyp); + } + +} \ No newline at end of file diff --git a/version/201/class/Checkout/OrderCheckout.php b/version/201/class/Checkout/OrderCheckout.php new file mode 100644 index 0000000..3478c6c --- /dev/null +++ b/version/201/class/Checkout/OrderCheckout.php @@ -0,0 +1,356 @@ +getMollie()->status !== OrderStatus::STATUS_AUTHORIZED && $checkout->getMollie()->status !== OrderStatus::STATUS_SHIPPING) { + throw new RuntimeException('Nur autorisierte Zahlungen können erfasst werden!'); + } + $shipment = $checkout->API()->Client()->shipments->createFor($checkout->getMollie(), ['lines' => []]); + $checkout->Log(sprintf('Bestellung wurde manuell erfasst/versandt: %s', $shipment->id)); + return $shipment->id; + } + + /** + * @param false $force + * @return Order|null + */ + public function getMollie($force = false) + { + if ($force || (!$this->order && $this->getModel()->kID)) { + try { + $this->order = $this->API()->Client()->orders->get($this->getModel()->kID, ['embed' => 'payments,shipments,refunds']); + } catch (Exception $e) { + throw new RuntimeException(sprintf('Mollie-Order \'%s\' konnte nicht geladen werden: %s', $this->getModel()->kID, $e->getMessage())); + } + } + return $this->order; + } + + /** + * @param OrderCheckout $checkout + * @return Order + * @throws ApiException + */ + public static function cancel($checkout) + { + if (!$checkout->getMollie()->isCancelable) { + throw new RuntimeException('Bestellung kann nicht abgebrochen werden.'); + } + $order = $checkout->getMollie()->cancel(); + $checkout->Log('Bestellung wurde manuell abgebrochen.'); + return $order; + } + + /** + * @return array + */ + public function getShipments() + { + $shipments = []; + $lieferschien_arr = Shop::DB()->executeQueryPrepared("SELECT kLieferschein FROM tlieferschein WHERE kInetBestellung = :kBestellung", [ + ':kBestellung' => (int)$this->getBestellung()->kBestellung + ], 2); + + foreach ($lieferschien_arr as $lieferschein) { + $shipments[] = new Shipment($lieferschein->kLieferschein, $this); + } + return $shipments; + } + + /** + * @return string + * @throws ApiException + */ + public function cancelOrRefund($force = false) + { + if (!$this->getMollie()) { + throw new RuntimeException('Mollie-Order konnte nicht geladen werden: ' . $this->getModel()->kID); + } + if ($force || (int)$this->getBestellung()->cStatus === BESTELLUNG_STATUS_STORNO) { + if ($this->getMollie()->isCancelable) { + $res = $this->getMollie()->cancel(); + $result = 'Order cancelled, Status: ' . $res->status; + } else { + $res = $this->getMollie()->refundAll(); + $result = "Order Refund initiiert, Status: " . $res->status; + } + $this->PaymentMethod()->Log("OrderCheckout::cancelOrRefund: " . $result, $this->LogData()); + return $result; + } + throw new RuntimeException('Bestellung ist derzeit nicht storniert, Status: ' . $this->getBestellung()->cStatus); + } + + /** + * @param array $paymentOptions + * @return Order|Payment + */ + public function create(array $paymentOptions = []) + { + if ($this->getModel()->kID) { + try { + $this->order = $this->API()->Client()->orders->get($this->getModel()->kID, ['embed' => 'payments']); + if (in_array($this->order->status, [OrderStatus::STATUS_COMPLETED, OrderStatus::STATUS_PAID, OrderStatus::STATUS_AUTHORIZED, OrderStatus::STATUS_PENDING], true)) { + $this->handleNotification(); + throw new RuntimeException(self::Plugin()->oPluginSprachvariableAssoc_arr['errAlreadyPaid']); + } + if ($this->order->status === OrderStatus::STATUS_CREATED) { + if ($this->order->payments()) { + /** @var Payment $payment */ + foreach ($this->order->payments() as $payment) { + if ($payment->status === PaymentStatus::STATUS_OPEN) { + $this->setPayment($payment); + break; + } + } + } + if (!$this->getPayment()) { + $this->setPayment($this->API()->Client()->orderPayments->createForId($this->getModel()->kID, $paymentOptions)); + } + $this->updateModel()->saveModel(); + return $this->getMollie(true); + } + } catch (RuntimeException $e) { + throw $e; + } catch (Exception $e) { + $this->Log(sprintf("OrderCheckout::create: Letzte Order '%s' konnte nicht geladen werden: %s, versuche neue zu erstellen.", $this->getModel()->kID, $e->getMessage()), LOGLEVEL_ERROR); + } + } + + try { + $req = $this->loadRequest()->jsonSerialize(); + $this->order = $this->API()->Client()->orders->create($req); + $this->Log(sprintf("Order für '%s' wurde erfolgreich angelegt: %s", $this->getBestellung()->cBestellNr, $this->order->id)); + $this->updateModel()->saveModel(); + return $this->order; + } catch (Exception $e) { + $this->Log(sprintf("OrderCheckout::create: Neue Order '%s' konnte nicht erstellt werden: %s.", $this->getBestellung()->cBestellNr, $e->getMessage()), LOGLEVEL_ERROR); + throw new RuntimeException(sprintf("Order für '%s' konnte nicht angelegt werden: %s", $this->getBestellung()->cBestellNr, $e->getMessage())); + } + } + + /** + * @return Payment|null + */ + public function getPayment($search = false) + { + if (!$this->_payment && $search) { + foreach ($this->getMollie()->payments() as $payment) { + if (in_array($payment->status, [ + PaymentStatus::STATUS_AUTHORIZED, + PaymentStatus::STATUS_PAID, + PaymentStatus::STATUS_PENDING, + ], true)) { + $this->_payment = $payment; + break; + } + } + } + return $this->_payment; + } + + /** + * @param $payment + * @return $this + */ + public function setPayment($payment) + { + $this->_payment = $payment; + return $this; + } + + /** + * @return $this|OrderCheckout + */ + public function updateModel() + { + parent::updateModel(); + + if (!$this->getPayment() && $this->getMollie() && $this->getMollie()->payments()) { + /** @var Payment $payment */ + foreach ($this->getMollie()->payments() as $payment) { + if (in_array($payment->status, [PaymentStatus::STATUS_OPEN, PaymentStatus::STATUS_PENDING, PaymentStatus::STATUS_AUTHORIZED, PaymentStatus::STATUS_PAID], true)) { + $this->setPayment($payment); + break; + } + } + } + if ($this->getPayment()) { + $this->getModel()->cTransactionId = $this->getPayment()->id; + } + if ($this->getMollie()) { + $this->getModel()->cCheckoutURL = $this->getMollie()->getCheckoutUrl(); + $this->getModel()->cWebhookURL = $this->getMollie()->webhookUrl; + $this->getModel()->cRedirectURL = $this->getMollie()->redirectUrl; + } + return $this; + } + + /** + * @param array $options + * @return $this|OrderCheckout + */ + public function loadRequest($options = []) + { + + if ($this->getBestellung()->oKunde->nRegistriert + && ($customer = $this->getCustomer( + array_key_exists('mollie_create_customer', $_SESSION['cPost_arr'] ?: []) && $_SESSION['cPost_arr']['mollie_create_customer'] === 'Y') + ) + && isset($customer)) { + $options['customerId'] = $customer->id; + } + + $this->locale = self::getLocale(Session::getInstance()->Language()->getIso(), Session::getInstance()->Customer()->cLand); + $this->amount = Amount::factory($this->getBestellung()->fGesamtsummeKundenwaehrung, $this->getBestellung()->Waehrung->cISO, true); + $this->orderNumber = $this->getBestellung()->cBestellNr; + $this->metadata = [ + 'kBestellung' => $this->getBestellung()->kBestellung, + 'kKunde' => $this->getBestellung()->kKunde, + 'kKundengruppe' => Session::getInstance()->CustomerGroup()->kKundengruppe, + 'cHash' => $this->getHash(), + ]; + + $this->redirectUrl = $this->PaymentMethod()->getReturnURL($this->getBestellung()); + $this->webhookUrl = Shop::getURL(true) . '/?mollie=1'; + + $pm = $this->PaymentMethod(); + $isPayAgain = strpos($_SERVER['PHP_SELF'], 'bestellab_again') !== false; + if ($pm::METHOD !== '' && (self::Plugin()->oPluginEinstellungAssoc_arr['resetMethod'] !== 'Y' || !$isPayAgain)) { + $this->method = $pm::METHOD; + } + + $this->billingAddress = Address::factory($this->getBestellung()->oRechnungsadresse); + if ($this->getBestellung()->Lieferadresse !== null) { + if (!$this->getBestellung()->Lieferadresse->cMail) { + $this->getBestellung()->Lieferadresse->cMail = $this->getBestellung()->oRechnungsadresse->cMail; + } + $this->shippingAddress = Address::factory($this->getBestellung()->Lieferadresse); + } + + if ( + !empty(Session::getInstance()->Customer()->dGeburtstag) + && Session::getInstance()->Customer()->dGeburtstag !== '0000-00-00' + && preg_match('/^\d{4}-\d{2}-\d{2}$/', trim(Session::getInstance()->Customer()->dGeburtstag)) + ) { + $this->consumerDateOfBirth = trim(Session::getInstance()->Customer()->dGeburtstag); + } + + $lines = []; + foreach ($this->getBestellung()->Positionen as $oPosition) { + $lines[] = OrderLine::factory($oPosition, $this->getBestellung()->Waehrung); + } + + if ($this->getBestellung()->GuthabenNutzen && $this->getBestellung()->fGuthaben > 0) { + $lines[] = OrderLine::getCredit($this->getBestellung()); + } + + if ($comp = OrderLine::getRoundingCompensation($lines, $this->amount, $this->getBestellung()->Waehrung->cISO)) { + $lines[] = $comp; + } + $this->lines = $lines; + + if ($dueDays = $this->PaymentMethod()->getExpiryDays()) { + $max = $this->method && strpos($this->method, 'klarna') !== false ? 28 : 100; + $this->expiresAt = date('Y-m-d', strtotime(sprintf("+%d DAYS", min($dueDays, $max)))); + } + + $this->payment = $options; + + return $this; + } + + /** + * @return object|null + */ + public function getIncomingPayment() + { + if (!$this->getMollie()) { + return null; + } + + if (Helper::getSetting('wawiPaymentID') === 'ord') { + $cHinweis = $this->getMollie()->id; + } else { + if (Helper::getSetting('wawiPaymentID') === 'tr') { + $cHinweis = $this->getPayment(true)->id; + } else { + $cHinweis = sprintf("%s / %s", $this->getMollie()->id, $this->getPayment(true)->id); + } + } + + /** @var Payment $payment */ + foreach ($this->getMollie()->payments() as $payment) { + if (in_array($payment->status, + [PaymentStatus::STATUS_AUTHORIZED, PaymentStatus::STATUS_PAID], true)) { + $this->setPayment($payment); + $data = (object)[ + 'fBetrag' => (float)$payment->amount->value, + 'cISO' => $payment->amount->currency, + 'cZahler' => $payment->details->paypalPayerId ?: $payment->customerId, + 'cHinweis' => $payment->details->paypalReference ?: $cHinweis, + ]; + if (isset($payment->details, $payment->details->paypalFee)) { + $data->fZahlungsgebuehr = $payment->details->paypalFee->value; + } + return $data; + } + } + return null; + } +} \ No newline at end of file diff --git a/version/201/class/Checkout/Payment/Address.php b/version/201/class/Checkout/Payment/Address.php new file mode 100644 index 0000000..ea460c1 --- /dev/null +++ b/version/201/class/Checkout/Payment/Address.php @@ -0,0 +1,54 @@ +streetAndNumber = $address->cStrasse . ' ' . $address->cHausnummer; + $resource->postalCode = $address->cPLZ; + $resource->city = $address->cOrt; + $resource->country = $address->cLand; + + if ( + isset($address->cAdressZusatz) + && trim($address->cAdressZusatz) !== '' + ) { + $resource->streetAdditional = trim($address->cAdressZusatz); + } + + // Validity-Check + // TODO: Check for valid Country Code? + // TODO: Check PostalCode requirement Country? + if (!$resource->streetAndNumber || !$resource->city || !$resource->country) { + throw ResourceValidityException::trigger(ResourceValidityException::ERROR_REQUIRED, ['streetAndNumber', 'city', 'country'], $resource); + } + + return $resource; + } + + +} \ No newline at end of file diff --git a/version/201/class/Checkout/Payment/Amount.php b/version/201/class/Checkout/Payment/Amount.php new file mode 100644 index 0000000..21acef9 --- /dev/null +++ b/version/201/class/Checkout/Payment/Amount.php @@ -0,0 +1,72 @@ + true [5 Rappen Rounding]) + * @return Amount + */ + public static function factory($value, $currency = null, $useRounding = false) + { + + if (!$currency) { + $currency = static::FallbackCurrency()->cISO; + } + + $resource = new static(); + + $resource->currency = $currency; + //$resource->value = number_format(round($useRounding ? $resource->round($value * (float)$currency->fFaktor) : $value * (float)$currency->fFaktor, 2), 2, '.', ''); + $resource->value = number_format(round($useRounding ? $resource->round($value) : $value, 2), 2, '.', ''); + + // Validity Check + // TODO: Check ISO Code? + // TODO: Check Value + if (!$resource->currency || !$resource->value) { + throw ResourceValidityException::trigger(ResourceValidityException::ERROR_REQUIRED, ['currency', 'value'], $resource); + } + return $resource; + } + + /** + * @return \stdClass + */ + public static function FallbackCurrency() + { + return isset($_SESSION['Waehrung']) ? $_SESSION['Waehrung'] : Shop::DB()->select('twaehrung', 'cStandard', 'Y'); + } + + /** + * Check if 5 Rappen rounding is necessary + * + * @return float + */ + protected function round($value) + { + + $conf = Shop::getSettings([CONF_KAUFABWICKLUNG]); + if (isset($conf['kaufabwicklung']['bestellabschluss_runden5']) && (int)$conf['kaufabwicklung']['bestellabschluss_runden5'] === 1) { + $value = round($value * 20) / 20; + } + return $value; + } + + +} \ No newline at end of file diff --git a/version/201/class/Checkout/PaymentCheckout.php b/version/201/class/Checkout/PaymentCheckout.php new file mode 100644 index 0000000..6b187d3 --- /dev/null +++ b/version/201/class/Checkout/PaymentCheckout.php @@ -0,0 +1,209 @@ +getMollie()) { + throw new RuntimeException('Mollie-Order konnte nicht geladen werden: ' . $this->getModel()->kID); + } + if ($force || (int)$this->getBestellung()->cStatus === BESTELLUNG_STATUS_STORNO) { + if ($this->getMollie()->isCancelable) { + $res = $this->API()->Client()->payments->cancel($this->getMollie()->id); + $result = 'Payment cancelled, Status: ' . $res->status; + } else { + $res = $this->API()->Client()->payments->refund($this->getMollie(), ['amount' => $this->getMollie()->amount]); + $result = "Payment Refund initiiert, Status: " . $res->status; + } + $this->PaymentMethod()->Log("PaymentCheckout::cancelOrRefund: " . $result, $this->LogData()); + return $result; + } + throw new RuntimeException('Bestellung ist derzeit nicht storniert, Status: ' . $this->getBestellung()->cStatus); + } + + /** + * @param false $force + * @return Payment|null + */ + public function getMollie($force = false) + { + if ($force || (!$this->getPayment() && $this->getModel()->kID)) { + try { + $this->setPayment($this->API()->Client()->payments->get($this->getModel()->kID, ['embed' => 'refunds'])); + } catch (Exception $e) { + throw new RuntimeException('Mollie-Payment konnte nicht geladen werden: ' . $e->getMessage()); + } + } + return $this->getPayment(); + } + + /** + * @return Payment|null + */ + public function getPayment() + { + return $this->_payment; + } + + /** + * @param $payment + * @return $this + */ + public function setPayment($payment) + { + $this->_payment = $payment; + return $this; + } + + /** + * @param array $paymentOptions + * @return \Mollie\Api\Resources\Order|Payment|\ws_mollie\Model\Payment + */ + public function create(array $paymentOptions = []) + { + if ($this->getModel()->kID) { + try { + $this->setPayment($this->API()->Client()->payments->get($this->getModel()->kID)); + if ($this->getPayment()->status === PaymentStatus::STATUS_PAID) { + throw new RuntimeException(self::Plugin()->oPluginSprachvariableAssoc_arr['errAlreadyPaid']); + } + if ($this->getPayment()->status === PaymentStatus::STATUS_OPEN) { + $this->updateModel()->saveModel(); + return $this->getPayment(); + } + } catch (RuntimeException $e) { + //$this->Log(sprintf("PaymentCheckout::create: Letzte Transaktion '%s' konnte nicht geladen werden: %s", $this->getModel()->kID, $e->getMessage()), LOGLEVEL_ERROR); + throw $e; + } catch (Exception $e) { + $this->Log(sprintf("PaymentCheckout::create: Letzte Transaktion '%s' konnte nicht geladen werden: %s, versuche neue zu erstellen.", $this->getModel()->kID, $e->getMessage()), LOGLEVEL_ERROR); + } + } + + try { + $req = $this->loadRequest($paymentOptions)->jsonSerialize(); + $this->setPayment($this->API()->Client()->payments->create($req)); + $this->Log(sprintf("Payment für '%s' wurde erfolgreich angelegt: %s", $this->getBestellung()->cBestellNr, $this->getPayment()->id)); + $this->updateModel()->saveModel(); + return $this->getPayment(); + } catch (Exception $e) { + $this->Log(sprintf("PaymentCheckout::create: Neue Transaktion für '%s' konnte nicht erstellt werden: %s.", $this->getBestellung()->cBestellNr, $e->getMessage()), LOGLEVEL_ERROR); + throw new RuntimeException(sprintf('Mollie-Payment \'%s\' konnte nicht geladen werden: %s', $this->getBestellung()->cBestellNr, $e->getMessage())); + } + } + + + /** + * @param array $options + * @return $this|PaymentCheckout + */ + public function loadRequest($options = []) + { + + if ($this->getBestellung()->oKunde->nRegistriert + && ($customer = $this->getCustomer( + array_key_exists('mollie_create_customer', $_SESSION['cPost_arr'] ?: []) && $_SESSION['cPost_arr']['mollie_create_customer'] === 'Y') + ) + && isset($customer)) { + $options['customerId'] = $customer->id; + } + + $this->amount = Amount::factory($this->getBestellung()->fGesamtsummeKundenwaehrung, $this->getBestellung()->Waehrung->cISO, true); + $this->description = 'Order ' . $this->getBestellung()->cBestellNr; + $this->redirectUrl = $this->PaymentMethod()->getReturnURL($this->getBestellung()); + $this->webhookUrl = Shop::getURL(true) . '/?mollie=1'; + $this->locale = self::getLocale(Session::getInstance()->Language()->getIso(), Session::getInstance()->Customer()->cLand); + $this->metadata = [ + 'kBestellung' => $this->getBestellung()->kBestellung, + 'kKunde' => $this->getBestellung()->kKunde, + 'kKundengruppe' => Session::getInstance()->CustomerGroup()->kKundengruppe, + 'cHash' => $this->getHash(), + ]; + $pm = $this->PaymentMethod(); + $isPayAgain = strpos($_SERVER['PHP_SELF'], 'bestellab_again') !== false; + if ($pm::METHOD !== '' && (self::Plugin()->oPluginEinstellungAssoc_arr['resetMethod'] !== 'Y' || !$isPayAgain)) { + $this->method = $pm::METHOD; + } + foreach ($options as $key => $value) { + $this->$key = $value; + } + + return $this; + } + + /** + * @return object|null + */ + public function getIncomingPayment() + { + if (!$this->getMollie()) { + return null; + } + + if (in_array($this->getMollie()->status, [PaymentStatus::STATUS_AUTHORIZED, PaymentStatus::STATUS_PAID], true)) { + $data = []; + $data['fBetrag'] = (float)$this->getMollie()->amount->value; + $data['cISO'] = $this->getMollie()->amount->currency; + $data['cZahler'] = $this->getMollie()->details->paypalPayerId ?: $this->getMollie()->customerId; + $data['cHinweis'] = $this->getMollie()->details->paypalReference ?: $this->getMollie()->id; + if (isset($this->getMollie()->details, $this->getMollie()->details->paypalFee)) { + $data['fZahlungsgebuehr'] = $this->getMollie()->details->paypalFee->value; + } + return (object)$data; + } + return null; + } + + /** + * @param PaymentCheckout $checkout + * @return Payment + */ + public static function cancel($checkout) + { + if(!$checkout->getMollie()->isCancelable){ + throw new RuntimeException('Zahlung kann nicht abgebrochen werden.'); + } + $payment = $checkout->API()->Client()->payments->cancel($checkout->getMollie()->id); + $checkout->Log('Zahlung wurde manuell abgebrochen.'); + return $payment; + } +} \ No newline at end of file diff --git a/version/201/class/ExclusiveLock.php b/version/201/class/ExclusiveLock.php new file mode 100644 index 0000000..3e481c9 --- /dev/null +++ b/version/201/class/ExclusiveLock.php @@ -0,0 +1,70 @@ +key = $key; + $this->path = rtrim(realpath($path), '/') . '/'; + if (!is_dir($path) || !is_writable($path)) { + throw new RuntimeException("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", 'wb+'); + } + + + public function __destruct() + { + if ($this->own === true) { + $this->unlock(); + } + } + + 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 + } + + 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 + } +} diff --git a/version/201/class/Helper.php b/version/201/class/Helper.php new file mode 100644 index 0000000..5f2a8be --- /dev/null +++ b/version/201/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/201/class/Hook/AbstractHook.php b/version/201/class/Hook/AbstractHook.php new file mode 100644 index 0000000..8dcbbda --- /dev/null +++ b/version/201/class/Hook/AbstractHook.php @@ -0,0 +1,13 @@ +kPlugin)) + && array_key_exists($key, $_SESSION) && !array_key_exists("Zahlungsart", $_SESSION)) { + unset($_SESSION[$key]); + } + + if (!array_key_exists('ws_mollie_applepay_available', $_SESSION)) { + Shop::Smarty()->assign('applePayCheckURL', json_encode(self::Plugin()->cFrontendPfadURLSSL . 'applepay.php')); + pq('body')->append(Shop::Smarty()->fetch(self::Plugin()->cFrontendPfad . 'tpl/applepay.tpl')); + } + + } + + /** + * @return bool + */ + public static function isAvailable() + { + if (array_key_exists('ws_mollie_applepay_available', $_SESSION)) { + return $_SESSION['ws_mollie_applepay_available']; + } + return false; + } + + /** + * @param $status bool + */ + public static function setAvailable($status) + { + $_SESSION['ws_mollie_applepay_available'] = $status; + } + +} \ No newline at end of file diff --git a/version/201/class/Hook/Checkbox.php b/version/201/class/Hook/Checkbox.php new file mode 100644 index 0000000..6df972c --- /dev/null +++ b/version/201/class/Hook/Checkbox.php @@ -0,0 +1,60 @@ +cModulId, 'kPlugin_' . self::Plugin()->kPlugin . '_') === false) { + return; + } + + if (array_key_exists('nAnzeigeOrt', $args_arr) && $args_arr['nAnzeigeOrt'] === CHECKBOX_ORT_BESTELLABSCHLUSS && (int)Session::getInstance()->Customer()->nRegistriert) { + + $mCustomer = Customer::fromID(Session::getInstance()->Customer()->kKunde, 'kKunde'); + + if ($mCustomer->customerId) { + return; + } + + $checkbox = new \CheckBox(); + $checkbox->kLink = 0; + $checkbox->kCheckBox = -1; + $checkbox->kCheckBoxFunktion = 0; + $checkbox->cName = 'MOLLIE SAVE CUSTOMER'; + $checkbox->cKundengruppe = ';1;'; + $checkbox->cAnzeigeOrt = ';2;'; + $checkbox->nAktiv = 1; + $checkbox->nPflicht = 0; + $checkbox->nLogging = 0; + $checkbox->nSort = 999; + $checkbox->dErstellt = date('Y-m-d H:i:s'); + $checkbox->oCheckBoxSprache_arr = []; + + $langs = gibAlleSprachen(); + foreach ($langs as $lang) { + $checkbox->oCheckBoxSprache_arr[$lang->kSprache] = (object)[ + 'cText' => self::Plugin()->oPluginSprachvariableAssoc_arr['checkboxText'], + 'cBeschreibung' => self::Plugin()->oPluginSprachvariableAssoc_arr['checkboxDescr'], + 'kSprache' => $lang->kSprache, + 'kCheckbox' => -1 + ]; + } + + $checkbox->kKundengruppe_arr = [Session::getInstance()->Customer()->kKundengruppe]; + $checkbox->kAnzeigeOrt_arr = [CHECKBOX_ORT_BESTELLABSCHLUSS]; + $checkbox->cID = "mollie_create_customer"; + $checkbox->cLink = ''; + + $args_arr['oCheckBox_arr'][] = $checkbox; + + } + } +} \ No newline at end of file diff --git a/version/201/class/Hook/Queue.php b/version/201/class/Hook/Queue.php new file mode 100644 index 0000000..9dbef9b --- /dev/null +++ b/version/201/class/Hook/Queue.php @@ -0,0 +1,129 @@ +fGesamtsumme > 0 + && self::Plugin()->oPluginEinstellungAssoc_arr['onlyPaid'] === 'Y' + && AbstractCheckout::isMollie((int)$args_arr['oBestellung']->kZahlungsart, true)) { + + $args_arr['oBestellung']->cAbgeholt = 'Y'; + Jtllog::writeLog('Switch cAbgeholt for kBestellung: ' . print_r($args_arr['oBestellung']->kBestellung, 1), JTLLOG_LEVEL_NOTICE); + } + } + + /** + * @param array $args_arr + */ + public static function xmlBestellStatus(array $args_arr) + { + if (AbstractCheckout::isMollie((int)$args_arr['oBestellung']->kBestellung)) { + self::saveToQueue(HOOK_BESTELLUNGEN_XML_BESTELLSTATUS . ':' . (int)$args_arr['oBestellung']->kBestellung, [ + 'kBestellung' => $args_arr['oBestellung']->kBestellung, + 'status' => (int)$args_arr['status'] + ]); + } + } + + /** + * @param $hook + * @param $args_arr + * @param string $type + * @return bool + */ + protected static function saveToQueue($hook, $args_arr, $type = 'hook') + { + $mQueue = new QueueModel(); + $mQueue->cType = $type . ':' . $hook; + $mQueue->cData = serialize($args_arr); + try { + return $mQueue->save(); + } catch (Exception $e) { + Jtllog::writeLog('mollie::saveToQueue: ' . $e->getMessage() . ' - ' . print_r($args_arr, 1)); + return false; + } + } + + /** + * @param array $args_arr + */ + public static function xmlBearbeiteStorno(array $args_arr) + { + if (AbstractCheckout::isMollie((int)$args_arr['oBestellung']->kBestellung)) { + self::saveToQueue(HOOK_BESTELLUNGEN_XML_BEARBEITESTORNO . ':' . $args_arr['oBestellung']->kBestellung, ['kBestellung' => $args_arr['oBestellung']->kBestellung]); + } + } + + /** + * + */ + public static function headPostGet() + { + if (array_key_exists('mollie', $_REQUEST) && (int)$_REQUEST['mollie'] === 1 && array_key_exists('id', $_REQUEST)) { + self::saveToQueue($_REQUEST['id'], $_REQUEST['id'], 'webhook'); + exit(); + } + if (array_key_exists('m_pay', $_REQUEST)) { + try { + $raw = Shop::DB()->executeQueryPrepared('SELECT kID FROM `xplugin_ws_mollie_payments` WHERE dReminder IS NOT NULL AND MD5(CONCAT(kID, "-", kBestellung)) = :md5', [ + ':md5' => $_REQUEST['m_pay'] + ], 1); + + if (!$raw) { + throw new RuntimeException(self::Plugin()->oPluginSprachvariableAssoc_arr['errOrderNotFound']); + } + + if (strpos($raw->cOrderId, 'tr_') === 0) { + $checkout = PaymentCheckout::fromID($raw->kID); + } else { + $checkout = OrderCheckout::fromID($raw->kID); + } + $checkout->getMollie(true); + $checkout->updateModel()->saveModel(); + + if (($checkout->getBestellung()->dBezahltDatum !== null && $checkout->getBestellung()->dBezahltDatum !== '0000-00-00') + || in_array($checkout->getModel()->cStatus, ['completed', 'paid', 'authorized', 'pending'])) { + throw new RuntimeException(self::Plugin()->oPluginSprachvariableAssoc_arr['errAlreadyPaid']); + } + + $options = []; + if (self::Plugin()->oPluginEinstellungAssoc_arr['resetMethod'] !== 'Y') { + $options['method'] = $checkout->getModel()->cMethod; + } + + $mollie = $checkout->create($options); // Order::repayOrder($orderModel->getOrderId(), $options, $api); + $url = $mollie->getCheckoutUrl(); + + header('Location: ' . $url); + exit(); + + } catch (RuntimeException $e) { + // TODO Workaround? + //$alertHelper = Shop::Container()->getAlertService(); + //$alertHelper->addAlert(Alert::TYPE_ERROR, $e->getMessage(), 'mollie_repay', ['dismissable' => true]); + } catch (Exception $e) { + Jtllog::writeLog('mollie:repay:error: ' . $e->getMessage() . "\n" . print_r($_REQUEST, 1)); + } + } + } + +} \ No newline at end of file diff --git a/version/201/class/Model/AbstractModel.php b/version/201/class/Model/AbstractModel.php new file mode 100644 index 0000000..1dc9a47 --- /dev/null +++ b/version/201/class/Model/AbstractModel.php @@ -0,0 +1,92 @@ +data = $data; + if (!$data) { + $this->new = true; + } + } + + public static function fromID($id, $col = 'kID', $failIfNotExists = false) + { + if ($payment = Shop::DB()->executeQueryPrepared("SELECT * FROM " . static::TABLE . " WHERE {$col} = :id", + [':id' => $id], 1)) { + return new static($payment); + } + if ($failIfNotExists) { + throw new RuntimeException(sprintf('Model %s in %s nicht gefunden!', $id, static::TABLE)); + } + return new static(); + } + + /** + * @return mixed|stdClass|null + */ + public function jsonSerialize() + { + return $this->data; + } + + public function __get($name) + { + if (isset($this->data->$name)) { + return $this->data->$name; + } + return null; + } + + public function __set($name, $value) + { + if (!$this->data) { + $this->data = new stdClass(); + } + $this->data->$name = $value; + } + + public function __isset($name) + { + return isset($this->data->$name); + } + + /** + * @return bool + */ + public function save() + { + if (!$this->data) { + throw new RuntimeException('No Data to save!'); + } + + if ($this->new) { + Shop::DB()->insert(static::TABLE, $this->data); + $this->new = false; + return true; + } + Shop::DB()->update(static::TABLE, static::PRIMARY, $this->data->{static::PRIMARY}, $this->data); + return true; + } + +} diff --git a/version/201/class/Model/Customer.php b/version/201/class/Model/Customer.php new file mode 100644 index 0000000..7be9e15 --- /dev/null +++ b/version/201/class/Model/Customer.php @@ -0,0 +1,19 @@ +dCreatedAt) { + $this->dCreatedAt = date('Y-m-d H:i:s'); + } + if($this->new){ + $this->dReminder = self::NULL; + } + return parent::save(); + } +} diff --git a/version/201/class/Model/Queue.php b/version/201/class/Model/Queue.php new file mode 100644 index 0000000..480339a --- /dev/null +++ b/version/201/class/Model/Queue.php @@ -0,0 +1,41 @@ +cResult = $result; + $this->dDone = $date ?: date('Y-m-d H:i:s'); + return $this->save(); + } + + public function save() + { + if (!$this->dCreated) { + $this->dCreated = date('Y-m-d H:i:s'); + } + $this->dModified = date('Y-m-d H:i:s'); + return parent::save(); + } + +} \ No newline at end of file diff --git a/version/201/class/Model/Shipment.php b/version/201/class/Model/Shipment.php new file mode 100644 index 0000000..bece7b4 --- /dev/null +++ b/version/201/class/Model/Shipment.php @@ -0,0 +1,28 @@ +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); + } + } + } + } + + 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[] = AbstractCheckout::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/201/class/Queue.php b/version/201/class/Queue.php new file mode 100644 index 0000000..0607690 --- /dev/null +++ b/version/201/class/Queue.php @@ -0,0 +1,153 @@ +cType))) { + try { + switch ($type) { + case 'webhook': + self::handleWebhook($id, $todo); + break; + + case 'hook': + self::handleHook((int)$id, $todo); + break; + } + + } catch (Exception $e) { + Jtllog::writeLog($e->getMessage() . " ({$type}, {$id})"); + $todo->done("{$e->getMessage()}\n{$e->getFile()}:{$e->getLine()}\n{$e->getTraceAsString()}"); + } + } + } + } + + /** + * @param $limit + * @return Generator|QueueModel[] + */ + private static function getOpen($limit) + { + /** @noinspection SqlResolve */ + $open = Shop::DB()->executeQueryPrepared(sprintf("SELECT * FROM %s WHERE dDone IS NULL ORDER BY dCreated DESC LIMIT 0, :LIMIT;", QueueModel::TABLE), [ + ':LIMIT' => $limit + ], 2); + + foreach ($open as $_raw) { + yield new QueueModel($_raw); + } + } + + protected static function handleWebhook($id, QueueModel $todo) + { + $checkout = AbstractCheckout::fromID($id); + if ($checkout->getBestellung()->kBestellung && $checkout->PaymentMethod()) { + $checkout->handleNotification(); + return $todo->done('Status: ' . $checkout->getMollie()->status); + } + throw new RuntimeException("Bestellung oder Zahlungsart konnte nicht geladen werden: {$id}"); + } + + /** + * @param $hook + * @param QueueModel $todo + * @return bool + * @throws ApiException + * @throws IncompatiblePlatform + */ + protected static function handleHook($hook, QueueModel $todo) + { + $data = unserialize($todo->cData); + if (array_key_exists('kBestellung', $data)) { + switch ($hook) { + case HOOK_BESTELLUNGEN_XML_BESTELLSTATUS: + if ((int)$data['kBestellung']) { + $checkout = AbstractCheckout::fromBestellung($data['kBestellung']); + + $result = ""; + if ((int)$checkout->getBestellung()->cStatus < BESTELLUNG_STATUS_VERSANDT) { + return $todo->done("Bestellung noch nicht versendet: {$checkout->getBestellung()->cStatus}"); + } + + /** @var $method JTLMollie */ + if ((int)$data['status'] + && array_key_exists('status', $data) + && $checkout->PaymentMethod() + && (strpos($checkout->getModel()->kID, 'tr_') === false) + && $checkout->getMollie()) { + /** @var OrderCheckout $checkout */ + $checkout->handleNotification(); + if ($checkout->getMollie()->status === OrderStatus::STATUS_COMPLETED) { + $result = 'Mollie Status already ' . $checkout->getMollie()->status; + } else if ($checkout->getMollie()->isCreated() || $checkout->getMollie()->isPaid() || $checkout->getMollie()->isAuthorized() || $checkout->getMollie()->isShipping() || $checkout->getMollie()->isPending()) { + try { + if ($shipments = Shipment::syncBestellung($checkout)) { + foreach ($shipments as $shipment) { + if (is_string($shipment)) { + $checkout->PaymentMethod()->Log("Shipping-Error: {$shipment}", $checkout->LogData()); + $result .= "Shipping-Error: {$shipment};\n"; + + } else { + $checkout->PaymentMethod()->Log("Order shipped: \n" . print_r($shipment, 1)); + $result .= "Order shipped: {$shipment->id};\n"; + } + } + } else { + $result = 'No Shipments ready!'; + } + } catch (RuntimeException $e) { + $result = $e->getMessage(); + } catch (Exception $e) { + $result = $e->getMessage() . "\n" . $e->getFile() . ":" . $e->getLine() . "\n" . $e->getTraceAsString(); + } + } else { + $result = sprintf('Unerwarteter Mollie Status "%s" für %s', $checkout->getMollie()->status, $checkout->getBestellung()->cBestellNr); + } + } else { + $result = 'Nothing to do.'; + } + } else { + $result = "kBestellung missing"; + } + $checkout->PaymentMethod()->Log("Queue::handleHook: " . $result, $checkout->LogData()); + return $todo->done($result); + + case HOOK_BESTELLUNGEN_XML_BEARBEITESTORNO: + if (self::Plugin()->oPluginEinstellungAssoc_arr['autoRefund'] !== 'Y') { + throw new RuntimeException('Auto-Refund disabled'); + } + + $checkout = AbstractCheckout::fromBestellung((int)$data['kBestellung']); + return $todo->done($checkout->cancelOrRefund()); + } + } + return false; + } + +} \ No newline at end of file diff --git a/version/201/class/Shipment.php b/version/201/class/Shipment.php new file mode 100644 index 0000000..7152dad --- /dev/null +++ b/version/201/class/Shipment.php @@ -0,0 +1,318 @@ +kLieferschein = $kLieferschein; + if ($checkout) { + $this->checkout = $checkout; + } + + if (!$this->getLieferschein() || !$this->getLieferschein()->getLieferschein()) { + throw new RuntimeException('Lieferschein konnte nicht geladen werden'); + } + + if (!count($this->getLieferschein()->oVersand_arr)) { + throw new RuntimeException('Kein Versand gefunden!'); + } + + if (!$this->getCheckout()->getBestellung()->oKunde->nRegistriert) { + $this->isGuest = true; + } + } + + public function getLieferschein() + { + if (!$this->oLieferschein && $this->kLieferschein) { + $this->oLieferschein = new Lieferschein($this->kLieferschein); + } + return $this->oLieferschein; + } + + /** + * @return OrderCheckout + * @throws Exception + */ + public function getCheckout() + { + if (!$this->checkout) { + //TODO evtl. load by lieferschien + throw new Exception('Should not happen, but it did!'); + } + return $this->checkout; + } + + public static function syncBestellung(OrderCheckout $checkout) + { + $shipments = []; + if ($checkout->getBestellung()->kBestellung) { + + $oKunde = $checkout->getBestellung()->oKunde ?: new Kunde($checkout->getBestellung()->kKunde); + + $shippingActive = Helper::getSetting('shippingActive'); + if ($shippingActive === 'N') { + throw new RuntimeException('Shipping deaktiviert'); + } + + if (($shippingActive === 'K') && ((int)$checkout->getBestellung()->cStatus !== BESTELLUNG_STATUS_VERSANDT) && !$oKunde->nRegistriert) { + throw new RuntimeException('Shipping für Gast-Bestellungen und Teilversand deaktiviert'); + } + + /** @var Lieferschein $oLieferschein */ + foreach ($checkout->getBestellung()->oLieferschein_arr as $oLieferschein) { + + try { + + $shipment = new Shipment($oLieferschein->getLieferschein(), $checkout); + + $mode = self::Plugin()->oPluginEinstellungAssoc_arr['shippingMode']; + switch ($mode) { + case 'A': + // ship directly + if (!$shipment->send() && !$shipment->getShipment()) { + throw new RuntimeException('Shipment konnte nicht gespeichert werden.'); + } + $shipments[] = $shipment->getShipment(); + break; + + case 'B': + // only ship if complete shipping + if ($oKunde->nRegistriert || (int)$checkout->getBestellung()->cStatus === BESTELLUNG_STATUS_VERSANDT) { + if (!$shipment->send() && !$shipment->getShipment()) { + throw new RuntimeException('Shipment konnte nicht gespeichert werden.'); + } + $shipments[] = $shipment->getShipment(); + break; + } + throw new RuntimeException('Gastbestellung noch nicht komplett versendet!'); + } + } catch (RuntimeException $e) { + $shipments[] = $e->getMessage(); + } catch (Exception $e) { + $shipments[] = $e->getMessage(); + $checkout->Log("mollie: Shipment::syncBestellung (BestellNr. {$checkout->getBestellung()->cBestellNr}, Lieferschein: {$shipment->getLieferschein()->getLieferscheinNr()}) - " . $e->getMessage(), LOGLEVEL_ERROR); + } + } + } + return $shipments; + } + + /** + * @return mixed + * @throws ApiException + * @throws IncompatiblePlatform + * @throws Exception + */ + public function send() + { + + if ($this->getShipment()) { + throw new RuntimeException('Lieferschien bereits an Mollie übertragen: ' . $this->getShipment()->id); + } + + if ($this->getCheckout()->getMollie(true)->status === OrderStatus::STATUS_COMPLETED) { + throw new RuntimeException('Bestellung bei Mollie bereits abgeschlossen!'); + } + + $api = $this->getCheckout()->API()->Client(); + $this->shipment = $api->shipments->createForId($this->checkout->getModel()->kID, $this->loadRequest()->jsonSerialize()); + + return $this->updateModel()->saveModel(); + + } + + /** + * @param false $force + * @return BaseResource|\Mollie\Api\Resources\Shipment + * @throws ApiException + * @throws IncompatiblePlatform + * @throws Exception + */ + public function getShipment($force = false) + { + if (($force || !$this->shipment) && $this->getModel() && $this->getModel()->cShipmentId) { + $this->shipment = $this->getCheckout()->API()->Client()->shipments->getForId($this->getModel()->cOrderId, $this->getModel()->cShipmentId); + } + return $this->shipment; + } + + /** + * @return ShipmentModel + * @throws Exception + */ + public function getModel() + { + if (!$this->model && $this->kLieferschein) { + $this->model = ShipmentModel::fromID($this->kLieferschein, 'kLieferschein'); + + if (!$this->model->dCreated) { + $this->model->dCreated = date('Y-m-d H:i:s'); + } + $this->updateModel(); + } + return $this->model; + } + + /** + * @return $this + * @throws Exception + */ + public function updateModel() + { + $this->getModel()->kLieferschein = $this->kLieferschein; + if ($this->getCheckout()) { + $this->getModel()->cOrderId = $this->getCheckout()->getModel()->kID; + $this->getModel()->kBestellung = $this->getCheckout()->getModel()->kBestellung; + } + if ($this->getShipment()) { + $this->getModel()->cShipmentId = $this->getShipment()->id; + $this->getModel()->cUrl = $this->getShipment()->getTrackingUrl() ?: ''; + } + if (isset($this->tracking)) { + $this->getModel()->cCarrier = $this->tracking['carrier'] ?: ''; + $this->getModel()->cCode = $this->tracking['code'] ?: ''; + } + return $this; + } + + /** + * @param array $options + * @return $this + * @throws Exception + */ + public function loadRequest($options = []) + { + /** @var Versand $oVersand */ + $oVersand = $this->getLieferschein()->oVersand_arr[0]; + if ($oVersand->getIdentCode() && $oVersand->getLogistik()) { + $tracking = [ + 'carrier' => $oVersand->getLogistik(), + 'code' => $oVersand->getIdentCode(), + ]; + if ($oVersand->getLogistikVarUrl()) { + $tracking['url'] = $oVersand->getLogistikURL(); + } + $this->tracking = $tracking; + } + + // TODO: Wenn alle Lieferschiene in der WAWI erstellt wurden, aber nicht im Shop, kommt status 4. + if ($this->isGuest || (int)$this->getCheckout()->getBestellung()->cStatus === BESTELLUNG_STATUS_VERSANDT) { + $this->lines = []; + } else { + $this->lines = $this->getOrderLines(); + } + return $this; + } + + /** + * @return array + * @throws Exception + */ + protected function getOrderLines() + { + $lines = []; + + if (!count($this->getLieferschein()->oLieferscheinPos_arr)) { + return $lines; + } + + // Bei Stücklisten, sonst gibt es mehrere OrderLines für die selbe ID + $shippedOrderLines = []; + + /** @var Lieferscheinpos $oLieferscheinPos */ + foreach ($this->getLieferschein()->oLieferscheinPos_arr as $oLieferscheinPos) { + + $wkpos = Shop::DB()->executeQueryPrepared('SELECT * FROM twarenkorbpos WHERE kBestellpos = :kBestellpos', [ + ':kBestellpos' => $oLieferscheinPos->getBestellPos() + ], 1); + + /** @var OrderLine $orderLine */ + foreach ($this->getCheckout()->getMollie()->lines as $orderLine) { + + if ($orderLine->sku === $wkpos->cArtNr && !in_array($orderLine->id, $shippedOrderLines, true)) { + + if ($quantity = min($oLieferscheinPos->getAnzahl(), $orderLine->shippableQuantity)) { + $lines[] = [ + 'id' => $orderLine->id, + 'quantity' => $quantity + ]; + } + $shippedOrderLines[] = $orderLine->id; + break; + } + } + } + return $lines; + } + + /** + * @return bool + * @throws Exception + */ + public function saveModel() + { + return $this->getModel()->save(); + } +} \ No newline at end of file diff --git a/version/201/class/Traits/Jsonable.php b/version/201/class/Traits/Jsonable.php new file mode 100644 index 0000000..afc0988 --- /dev/null +++ b/version/201/class/Traits/Jsonable.php @@ -0,0 +1,20 @@ +jsonSerialize(); + } + + public function jsonSerialize() + { + return array_filter(get_object_vars($this), static function ($value) { + return !($value === null || (is_string($value) && $value === '')); + }); + } +} \ No newline at end of file diff --git a/version/201/class/Traits/Plugin.php b/version/201/class/Traits/Plugin.php new file mode 100644 index 0000000..5b2c3a3 --- /dev/null +++ b/version/201/class/Traits/Plugin.php @@ -0,0 +1,25 @@ +requestData; + } + + public function __get($name) + { + if (!$this->requestData) { + $this->loadRequest(); + } + return is_string($this->requestData[$name]) ? utf8_decode($this->requestData[$name]) : $this->requestData[$name]; + } + + public function __set($name, $value) + { + if (!$this->requestData) { + $this->requestData = []; + } + + $this->requestData[$name] = is_string($value) ? utf8_encode($value) : $value; + + return $this; + } + + /** + * @param array $options + * @return $this + */ + public function loadRequest($options = []) + { + return $this; + } + + + public function __serialize() + { + return $this->requestData ?: []; + } + + public function __isset($name) + { + return $this->requestData[$name] !== null; + } + +} \ No newline at end of file diff --git a/version/201/frontend/.htaccess b/version/201/frontend/.htaccess new file mode 100644 index 0000000..df6c074 --- /dev/null +++ b/version/201/frontend/.htaccess @@ -0,0 +1,9 @@ + + + Require all granted + + + Order Allow,Deny + Allow from all + + diff --git a/version/201/frontend/131_globalinclude.php b/version/201/frontend/131_globalinclude.php new file mode 100644 index 0000000..7093ca7 --- /dev/null +++ b/version/201/frontend/131_globalinclude.php @@ -0,0 +1,30 @@ +append( + << + /* MOLLIE CHECKOUT STYLES*/ + #fieldset-payment .form-group > div:hover, #checkout-shipping-payment .form-group > div:hover { + background-color: #eee; + color: black; + } + {$selector} label { + {$border} + } + + {$selector} label::after { + clear: both; + content: ' '; + display: block; + } + + {$selector} label span small { + line-height: 48px; + } + + {$selector} label img { + float: right; + } + +HTML + ); + +} catch (Exception $e) { + Helper::logExc($e); +} diff --git a/version/201/frontend/180_checkbox.php b/version/201/frontend/180_checkbox.php new file mode 100644 index 0000000..95a070f --- /dev/null +++ b/version/201/frontend/180_checkbox.php @@ -0,0 +1,18 @@ +oPluginEinstellungAssoc_arr['useCustomerAPI'] === 'C') { + \ws_mollie\Hook\Checkbox::execute($args_arr); + } + +} catch (Exception $e) { + Helper::logExc($e); +} \ No newline at end of file diff --git a/version/201/frontend/181_sync.php b/version/201/frontend/181_sync.php new file mode 100644 index 0000000..22022a9 --- /dev/null +++ b/version/201/frontend/181_sync.php @@ -0,0 +1,14 @@ +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 Rmns)TMnX}%M${5 literal 0 HcmV?d00001 diff --git a/version/201/frontend/img/trust_fre.png b/version/201/frontend/img/trust_fre.png new file mode 100644 index 0000000000000000000000000000000000000000..ed1a2f6f03c56f6748aac8af0352de7fc0afd3a4 GIT binary patch literal 17319 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 Mu#8ZJpsxS_1AJc%;s5{u literal 0 HcmV?d00001 diff --git a/version/201/frontend/img/trust_ger.png b/version/201/frontend/img/trust_ger.png new file mode 100644 index 0000000000000000000000000000000000000000..e42821b06709e8f4371c66cfb5759d00df0e1afd GIT binary patch literal 15352 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 + diff --git a/version/201/paymentmethod/JTLMollie.php b/version/201/paymentmethod/JTLMollie.php new file mode 100644 index 0000000..dfdcfd0 --- /dev/null +++ b/version/201/paymentmethod/JTLMollie.php @@ -0,0 +1,260 @@ +cModulId = "kPlugin_" . self::Plugin()->kPlugin . "_mollie" . $moduleID; + } + + /** + * @param Bestellung $order + * @return PaymentMethod + */ + public function setOrderStatusToPaid($order) + { + // If paid already, do nothing + if ((int)$order->cStatus >= BESTELLUNG_STATUS_BEZAHLT) { + return $this; + } + return parent::setOrderStatusToPaid($order); + } + + /** + * Prepares everything so that the Customer can start the Payment Process. + * Tells Template Engine. + * + * @param Bestellung $order + * @return void + */ + public function preparePaymentProcess($order) + { + + parent::preparePaymentProcess($order); + + try { + + if ($this->duringCheckout) { + $this->Log(sprintf("Zahlung vor Bestellabschluss nicht unterstützt (%s)!", $order->cBestellNr), sprintf("#%s", $order->kBestellung), LOGLEVEL_ERROR); + return; + } + + $payable = (float)$order->fGesamtsumme > 0; + if (!$payable) { + $this->Log(sprintf("Bestellung '%s': Gesamtsumme %.2f, keine Zahlung notwendig!", $order->cBestellNr, $order->fGesamtsumme), sprintf("#%s", $order->kBestellung)); + return; + } + + $paymentOptions = []; + + $api = array_key_exists($this->moduleID . '_api', self::Plugin()->oPluginEinstellungAssoc_arr) ? self::Plugin()->oPluginEinstellungAssoc_arr[$this->moduleID . '_api'] : 'order'; + + $paymentOptions = array_merge($paymentOptions, $this->getPaymentOptions($order, $api)); + + if ($api === 'payment') { + $checkout = new PaymentCheckout($order); + $payment = $checkout->create($paymentOptions); + $url = $payment->getCheckoutUrl(); + } else { + $checkout = new OrderCheckout($order); + $mOrder = $checkout->create($paymentOptions); + $url = $mOrder->getCheckoutUrl(); + } + + ifndef('MOLLIE_REDIRECT_DELAY', 3); + $checkoutMode = self::Plugin()->oPluginEinstellungAssoc_arr['checkoutMode']; + Shop::Smarty()->assign('redirect', $url) + ->assign('checkoutMode', $checkoutMode); + if ($checkoutMode === 'Y' && !headers_sent()) { + header('Location: ' . $url); + } + } catch (Exception $e) { + $this->Log('mollie::preparePaymentProcess: ' . $e->getMessage() . ' - ' . print_r(['cBestellNr' => $order->cBestellNr], 1), '#' . $order->kBestellung, LOGLEVEL_ERROR); + Shop::Smarty()->assign('oMollieException', $e) + ->assign('tryAgain', Shop::getURL() . '/bestellab_again.php?kBestellung=' . $order->kBestellung); + } + } + + public function Log($msg, $data = null, $level = LOGLEVEL_NOTICE) + { + ZahlungsLog::add($this->moduleID, "[" . microtime(true) . " - " . $_SERVER['PHP_SELF'] . "] " . $msg, $data, $level); + return $this; + } + + public function getPaymentOptions(Bestellung $order, $apiType) + { + return []; + } + + /** + * @param Bestellung $order + * @param string $hash + * @param array $args + */ + public function handleNotification($order, $hash, $args) + { + parent::handleNotification($order, $hash, $args); + try { + $orderId = $args['id']; + $checkout = null; + if (strpos($orderId, 'tr_') === 0) { + $checkout = new PaymentCheckout($order); + } else { + $checkout = new OrderCheckout($order); + } + $checkout->handleNotification($hash); + + } catch (Exception $e) { + $checkout->Log(sprintf("mollie::handleNotification: Fehler bei Bestellung '%s': %s\n%s", $order->cBestellNr, $e->getMessage(), print_r($args, 1)), LOGLEVEL_ERROR); + } + } + + /** + * @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 (API::getMode()) { + $selectable = trim(self::Plugin()->oPluginEinstellungAssoc_arr['test_api_key']) !== ''; + } else { + $selectable = trim(self::Plugin()->oPluginEinstellungAssoc_arr['api_key']) !== ''; + if (!$selectable) { + Jtllog::writeLog("Live API Key missing!"); + } + } + if ($selectable) { + try { + $locale = AbstractCheckout::getLocale(Session::getInstance()->Language()->getIso(), Session::getInstance()->Customer()->cLand); + $amount = Session::getInstance()->Basket()->gibGesamtsummeWarenExt([ + C_WARENKORBPOS_TYP_ARTIKEL, + C_WARENKORBPOS_TYP_KUPON, + C_WARENKORBPOS_TYP_GUTSCHEIN, + C_WARENKORBPOS_TYP_NEUKUNDENKUPON, + ], true) * Session::getInstance()->Currency()->fFaktor; + if ($amount <= 0) { + $amount = 0.01; + } + $selectable = self::isMethodPossible( + static::METHOD, + $locale, + Session::getInstance()->Customer()->cLand, + Session::getInstance()->Currency()->cISO, + $amount + ); + } catch (Exception $e) { + Helper::logExc($e); + $selectable = false; + } + } + return $selectable && parent::isSelectable(); + } + + /** + * @param $method + * @param $locale + * @param $billingCountry + * @param $currency + * @param $amount + * @return bool + * @throws ApiException + */ + protected static function isMethodPossible($method, $locale, $billingCountry, $currency, $amount) + { + + $api = new API(API::getMode()); + + if (!array_key_exists('mollie_possibleMethods', $_SESSION)) { + $_SESSION['mollie_possibleMethods'] = []; + } + + $key = md5(serialize([$locale, $billingCountry, $currency, $amount])); + if (!array_key_exists($key, $_SESSION['mollie_possibleMethods'])) { + $_SESSION['mollie_possibleMethods'][$key] = $api->Client()->methods->allActive([ + 'locale' => $locale, + 'amount' => [ + 'currency' => $currency, + 'value' => number_format($amount, 2, ".", "") + ], + 'billingCountry' => $billingCountry, + 'resource' => 'orders', + 'includeWallets' => 'applepay', + ]); + } + + if ($method !== '') { + foreach ($_SESSION['mollie_possibleMethods'][$key] as $m) { + if ($m->id === $method) { + return true; + } + } + } else { + return true; + } + + return false; + + } + + /** + * @param array $args_arr + * @return bool + */ + public function isValidIntern($args_arr = []) + { + return $this->duringCheckout + ? static::ALLOW_PAYMENT_BEFORE_ORDER && parent::isValidIntern($args_arr) + : parent::isValidIntern($args_arr); + } + + /** + * @return int + */ + public function getExpiryDays() + { + return (int)min(abs((int)Helper::oPlugin()->oPluginEinstellungAssoc_arr[$this->cModulId . '_dueDays']), static::MAX_EXPIRY_DAYS) ?: static::MAX_EXPIRY_DAYS; + } + +} diff --git a/version/201/paymentmethod/JTLMollieApplePay.php b/version/201/paymentmethod/JTLMollieApplePay.php new file mode 100644 index 0000000..4b23bf4 --- /dev/null +++ b/version/201/paymentmethod/JTLMollieApplePay.php @@ -0,0 +1,15 @@ +oRechnungsadresse->cMail; + $paymentOptions['locale'] = AbstractCheckout::getLocale(Session::getInstance()->Language()->getIso(), $order->oRechnungsadresse->cLand); + } + + $dueDays = $this->getExpiryDays(); + if ($dueDays > 3) { + $paymentOptions['dueDate'] = date('Y-m-d', strtotime("+{$dueDays} DAYS")); + } + return $paymentOptions; + } +} diff --git a/version/201/paymentmethod/JTLMollieBelfius.php b/version/201/paymentmethod/JTLMollieBelfius.php new file mode 100644 index 0000000..91a6169 --- /dev/null +++ b/version/201/paymentmethod/JTLMollieBelfius.php @@ -0,0 +1,8 @@ +clearToken(); + } + + protected function clearToken() + { + $this->unsetCache(self::CACHE_TOKEN) + ->unsetCache(self::CACHE_TOKEN_TIMESTAMP); + return true; + } + + public function handleAdditional($aPost_arr) + { + + $components = self::Plugin()->oPluginEinstellungAssoc_arr[$this->moduleID . '_components']; + $profileId = self::Plugin()->oPluginEinstellungAssoc_arr['profileId']; + + if ($components === 'N' || !$profileId || trim($profileId) === '') { + return parent::handleAdditional($aPost_arr); + } + + $cleared = false; + if (array_key_exists('clear', $aPost_arr) && (int)$aPost_arr['clear']) { + $cleared = $this->clearToken(); + } + + if ($components === 'S' && array_key_exists('skip', $aPost_arr) && (int)$aPost_arr['skip']) { + return parent::handleAdditional($aPost_arr); + } + + try { + $trustBadge = (bool)self::Plugin()->oPluginEinstellungAssoc_arr[$this->moduleID . '_loadTrust']; + $locale = AbstractCheckout::getLocale(Session::getInstance()->Language()->getIso(), Session::getInstance()->Customer() ? Session::getInstance()->Customer()->cLand : null); + $mode = API::getMode(); + $errorMessage = json_encode(self::Plugin()->oPluginSprachvariableAssoc_arr['mcErrorMessage']); + } catch (Exception $e) { + Jtllog::writeLog($e->getMessage() . "\n" . print_r(['e' => $e], 1)); + return parent::handleAdditional($aPost_arr); + } + + if (!$cleared && array_key_exists('cardToken', $aPost_arr) && ($token = trim($aPost_arr['cardToken']))) { + return $this->setToken($token) && parent::handleAdditional($aPost_arr); + } + + $token = false; + if (($ctTS = (int)$this->getCache(self::CACHE_TOKEN_TIMESTAMP)) && $ctTS > time()) { + $token = $this->getCache(self::CACHE_TOKEN); + } + + Shop::Smarty()->assign('profileId', $profileId) + ->assign('trustBadge', $trustBadge ? self::Plugin()->cFrontendPfadURLSSL . 'img/trust_' . $_SESSION['cISOSprache'] . '.png' : false) + ->assign('components', $components) + ->assign('locale', $locale ?: 'de_DE') + ->assign('token', $token ?: false) + ->assign('testMode', $mode ?: false) + ->assign('errorMessage', $errorMessage ?: null) + ->assign('mollieLang', self::Plugin()->oPluginSprachvariableAssoc_arr); + + return false; + +// if (array_key_exists('skip', $aPost_arr) && (int)$aPost_arr['skip']) { +// unset($_SESSION['mollieCardToken'], $_SESSION['mollieCardTokenTS']); +// return true; +// } +// +// $profileId = trim(Helper::getSetting('profileId')); +// if ($profileId === '' || strpos($profileId, 'pfl_') !== 0) { +// return true; +// } +// if (array_key_exists('mollieCardTokenTS', $_SESSION) && (int)$_SESSION['mollieCardTokenTS'] > time() +// && array_key_exists('mollieCardToken', $_SESSION) && trim($_SESSION['mollieCardToken']) !== '') { +// return true; +// } +// +// unset($_SESSION['mollieCardToken'], $_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('skipComponents', Helper::getSetting('skipComponents')) +// ->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; + } + + protected function setToken($token) + { + $this->addCache(self::CACHE_TOKEN, $token) + ->addCache(self::CACHE_TOKEN_TIMESTAMP, time() + 3600); + return true; + } + + public function getPaymentOptions(Bestellung $order, $apiType) + { + + $paymentOptions = []; + + if ($apiType === 'payment') { + if ($order->Lieferadresse !== null) { + if (!$order->Lieferadresse->cMail) { + $order->Lieferadresse->cMail = $order->oRechnungsadresse->cMail; + } + $paymentOptions['shippingAddress'] = Address::factory($order->Lieferadresse); + } + + $paymentOptions['billingAddress'] = Address::factory($order->oRechnungsadresse); + } + if ((int)$this->getCache(self::CACHE_TOKEN_TIMESTAMP) > time() && ($token = trim($this->getCache(self::CACHE_TOKEN)))) { + $paymentOptions['cardToken'] = $token; + } + return $paymentOptions; + } + +} diff --git a/version/201/paymentmethod/JTLMollieDirectDebit.php b/version/201/paymentmethod/JTLMollieDirectDebit.php new file mode 100644 index 0000000..7318e8a --- /dev/null +++ b/version/201/paymentmethod/JTLMollieDirectDebit.php @@ -0,0 +1,27 @@ + substr($order->cBestellNr, 0, 13)]; + } +} diff --git a/version/201/paymentmethod/JTLMollieKlarnaPayLater.php b/version/201/paymentmethod/JTLMollieKlarnaPayLater.php new file mode 100644 index 0000000..266953f --- /dev/null +++ b/version/201/paymentmethod/JTLMollieKlarnaPayLater.php @@ -0,0 +1,10 @@ +Lieferadresse !== null) { + if (!$order->Lieferadresse->cMail) { + $order->Lieferadresse->cMail = $order->oRechnungsadresse->cMail; + } + $paymentOptions['shippingAddress'] = Address::factory($order->Lieferadresse); + } + $paymentOptions['description'] = 'Order ' . $order->cBestellNr; + } + + + return $paymentOptions; + } + +} diff --git a/version/201/paymentmethod/JTLMolliePaysafecard.php b/version/201/paymentmethod/JTLMolliePaysafecard.php new file mode 100644 index 0000000..920e0fa --- /dev/null +++ b/version/201/paymentmethod/JTLMolliePaysafecard.php @@ -0,0 +1,13 @@ + $order->oKunde->kKunde] : []; + } +} diff --git a/version/201/paymentmethod/JTLMolliePrzelewy24.php b/version/201/paymentmethod/JTLMolliePrzelewy24.php new file mode 100644 index 0000000..ebd28ed --- /dev/null +++ b/version/201/paymentmethod/JTLMolliePrzelewy24.php @@ -0,0 +1,15 @@ + $order->oRechnungsadresse->cMail] : []; + } + +} diff --git a/version/201/paymentmethod/JTLMollieSofort.php b/version/201/paymentmethod/JTLMollieSofort.php new file mode 100644 index 0000000..c11060b --- /dev/null +++ b/version/201/paymentmethod/JTLMollieSofort.php @@ -0,0 +1,8 @@ +OH(NI>=T42<+x9g>;*Gy9DrKtJl=F((p(~XhRMojR(!TROq)4##x zi;wfn&C+>%^UTiFKSt7JYSXp1>ZPgDP*&5InbUcF<%^K^*xKlsoYHP{(wCajZ*$Ra zbJNPo(OY2BWNFmE!S~qO{POeCTVT|{z|(GX;Bt54e}mdsUi8b(sL>`X0000JbW%=J z01%HLkU-Cn-_OsV&!6AlpP5D4UE1#Sax&aZg(%L>z8x33MOZZ8H?WJ;;n51dMe)(}9UH1j29 ze@0RGfq`^s0!X#X7!_srsUP@btltZoyHfrIVq@*+2f)Ge+&BuBcbdrjKu5}NuE;){Yi3#o7gOK=v6Y0{rAbqNgQSz}}0I~5?ej{GsP%?vN z=_l4!?VPOmM>R@!2oOAkd1t|Pb#@H>-d=$PnbBs7=u%Z>9N;0iml z2#guk2rk-V%mMEvxQCZ1@+-_*(mao=fPWKs%h@Mp0)~gcfgO7j{4M(n<{@x^Z^Hk! ze1;0X32xx)(NPC3aetZbtnBss>W2NT-v%Bch%He^5RXIyLDWRp5;o{lcPr>qmkRZj lpHDtfd;A2~X0zTP_aA;i{an>LN7rz#m}I!{TEUogY_hW!fX z1?mg>C*-erx%(so1LG!77srr_xVP7C<}EQ0XbW_HZ(Bb#ysRpA(wRN~nf+#OlTe%( zXkfncL^KKCCrg-Lh=kEnU|a;ZB9QaR>Td+?i96wEUURmd^*;_;}q*?JtCN zs9v0_oUIYrJ>{ItUF)Suj=nY*E;y-_bg}zQ;ZT|@FU4Qeut^B)WfWUjV9g-3v@K+f-ik;kV{MOr_6wK;GGik>mTp$V%-RtP)+CPEi`n!UgTe~DWM4fFWeR( literal 0 HcmV?d00001 diff --git a/version/201/paymentmethod/img/method/bancontact@2x.png b/version/201/paymentmethod/img/method/bancontact@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..a87af77d20330ab4ee197fd750d0bd39a5b10f90 GIT binary patch literal 582 zcmV-M0=fN(P)lk!lq%lq?@9+Qr z|M>X$=jZ1jWQqR%{`vX&|JVTk=U{-T&j0$~pTFAg&hoWPVjpU$|LlN(mQMfcfPbmZpr$+j>2Uw#P;ZV{AZe)(UZem0@6X@u|MkEB z;XwWU{r~1*Ky`MXzS=N!uW*i8kF?YfT$A7F^MIC5pQk%!Gip%)000nlQchC<&w%eB zkRX4bpb&7+Z;x=Vl85vF00AONL_t(|UhS6GZp0uI1+V+IBnNQY-qL&T?f<_j%Vs4k zWi4ZPi#+c$LIR;fk}z^m8)w(24LdL-qBSjmiImqQ6%1%eKSC_H5hBJOQ3wcbh=A9j z0E`>M;F1Gj9uRN{NX-L}@Ce`*0RKJE1nw{TTbXGF`gs|rT7l!dln0%_EVm0RbGyKB zqJ*zRaiSTxE%@_=;_x?lSs8dz{y6#LPln}z>8GT40dLB`KB#<1qlM(E;D0OsM*0?TeIhg`dn6;Q{6Fh2l%qOS4K%wo8-q7AUD{?yGF(55vm4C&H_FzBH+J=d4+57}kr Up-!czfB*mh07*qoM6N<$g3OCHTL1t6 literal 0 HcmV?d00001 diff --git a/version/201/paymentmethod/img/method/banktransfer@2x.png b/version/201/paymentmethod/img/method/banktransfer@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..c70206bef4893f23fcd59d436273108d2f2eebc7 GIT binary patch literal 801 zcmV++1K#|JP)lk!lq*=;-9+mkX z{{U2_ztrjP@9%)A(*D5?-|6)J(MtZwET6yKpugSt`1lZBsz86cAZf7q`T3Bv*Z%(g z-|F=K#U1|5JO0^dAZoDx_u=pL`RC{7_xJZ;l*j-3@c!I)@AdkSwAlXDS^mf@aG%W2 z;O`J$tN-Md>+9=KiNUYR<6xA=@AUcq@WXGP%>DiS|LnB>%sc+*q+gWBFm$#4l$oJ=bMJL) zN$}UM z^EEI7D0q#*=`w@Mb&#yX6$WP@x&}s<8JvJ@pvqecQO^sez9^Xbs$t>(|Nn0Y_`k@X z`u+Uv`wm6F?mz#2{?4!aFGTBV&I9cbE(!7rW)PTg{{H;_^9ubA3J&Kd+&@2If#l5V zkwEFKo-U3d6>)E`o#Z>Lz~g$+{n^fDUKQE@|Mgd!a9=T#&e{4(sr-HO1o4KQ>uv;= zWX2_)yrQzk;QY@iN0x35n7oK-g-2+63_H(@QU|u6Z>|Z!r6lZ1zes9a?+x$E9%YhzX@O1Ta JS?83{1OT9Jm%RW0 literal 0 HcmV?d00001 diff --git a/version/201/paymentmethod/img/method/creditcard@2x.png b/version/201/paymentmethod/img/method/creditcard@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..b08be792753326b65345c752a6f350182a9393d2 GIT binary patch literal 3125 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 P00000NkvXXu0mjf3Vis# literal 0 HcmV?d00001 diff --git a/version/201/paymentmethod/img/method/directdebit@2x.png b/version/201/paymentmethod/img/method/directdebit@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..514ff845b84d38cd8eb97b9e2c53e5c117967944 GIT binary patch literal 801 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 literal 0 HcmV?d00001 diff --git a/version/201/paymentmethod/img/method/giropay@2x.png b/version/201/paymentmethod/img/method/giropay@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..b787e1fee50c9bcca112f734ef4bcbd4ecfb6d6b GIT binary patch literal 602 zcmV-g0;T5Kx~EOrH!)pASu;4ojd8OQ8=; zpbt!;!_w#B>GK{}r)iJG@bvggdAR@o{+6-TrM%mCn#w$GvMpk*ho#Tb-RaC5+y)hho537JnGBqPA~G@Ik#rt1jWCNmt_X5yY-;OM4Sm|;L0fCz(H!a59C z!6FQJ1`O=K0(U?&WmHmQ%ovl1g=xY%=0>sX7T{!DDr3#1AfT>{>*NQdp;XxeDnn^6 z;Fg|~18)oh=#B%J574HG=ZK=b0(2)=ZWs@6u|Psp2S`Ms-aSCKNc4dZ3ml0Y1JpF0 zACT7(WFOdH$J={=+}Kh?t@=QTh`Y)S;{lL4q2$K&0aK;&(@GqDK&DI^R~^tLy#OA$ z1Nay30gQkc{Q&0jzz(SpmbnlhVhfzVhaBhB0($}wh1S_^$N7}lg}e4p3Ic|F4;Z~b zTY@72isxg1#8BrSfnxv^S{6kiGl4E$H2v|f@*S9m0aJJk172Vm21F3Hg)IO)g#GGT oVe}rh6KIQG--ZM8)e@S10aM=ZI#^TblmGw#07*qoM6N<$f@FIOx&QzG literal 0 HcmV?d00001 diff --git a/version/201/paymentmethod/img/method/ideal@2x.png b/version/201/paymentmethod/img/method/ideal@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..efc4315a96a6b2d9b160578a65fe52206783f2ca GIT binary patch literal 845 zcmV-T1G4;yP)lk!ZZ65OMGC?}UYf;o;!m;NZf-!qXsn`1tsvqob6RlsGvz=jZ45_xJw({`vX& z+CYuwfU@xL?-Nv%`QPmApT=fqW&i*F(b3WK zzuD%1v(zAZ>+9>Xv$F87&$F|$@bK^%8W`-K#nT^p^1s=^!okAA!Tj&_DJdxZ{r%~X zz3Gp=&=7F!pvK@}pYN~F>5#mWl#|_1mb0_6g@uIHFobn>b?J}1M@UB*8yIC~W#VwE zc6N2$P?z9fpjKB^=ker~0000HbW%=J0PlbhkiUP=Adhe$&v1`#zea&7rvLx}*GWV{ zRCr#^*2j+9Fc5%YO7?ntl9{1;aqqou@0;Fxd;j;y*jNN`HV2Bl>~|3_{4oLqkzy%V z*t96C%}2Z9&SQ)86vWClksDVqqe|=&Z3|YQQjA*4CE6Eai>Qp6VzP3=CKt6Gk}WnU zMr|=|2#YGH?I~G;2n`TD#K5)puk^^z67b+ZZd-naz)7$!d_QRdc|mw#b1~<{2k2)FEaYF&OT-`GX$RPM#Nt`QAi#wXJk>zhFTO>59`Wo^#}<>sMjOed(+{-3ru0A7D$0jI558$ z)N0PF!RsCe2|{A+{jU4@5&uc>v9T(>X>= zpc$wJPDAG6XudKWan^4w_bUdHVBPG<>jQiVOn&QMzg?RgEbW=`(e{u7#up5;D^8W3 z2%8R3n@hIHS^6WCiFSq9p;8&OR7*Sn%M-cP>{s2YOOzKYHtDf;#GS4DUiRI4c22NA XzpeJ7+7%dW00000NkvXXu0mjfybi$$ literal 0 HcmV?d00001 diff --git a/version/201/paymentmethod/img/method/inghomepay@2x.png b/version/201/paymentmethod/img/method/inghomepay@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..538f219588886db215757eafd5c5151241f18b5a GIT binary patch literal 1118 zcmV-k1flzhP)`_0RK|}|55<|Q2_r?0RL0~|5E_}r-1)w9RKX&|5E_}=Gy;L z0RR90|6UOPlVJbp-~WC<|J1+#zn}l9fd6P9|A|olb1?tk&;RxB|Mc(wo^bzkF#pQ0 z|Fn<)>fisgkpF2Q|G%LBsek{okpG@<|H-fazM%hUAODC@|H-ibs(=5~!2gtB|K894 zs(@(VAMyYI01|XkPE!C7&ySx#AdugXK#$)bkdUC?LT6GX000A7Nkl+_F4;G0`t->#NE zT;V&r`f!+EySiCj<6V7Pt?{mYTH&4jj{)gM0TN(F3?6st+kjw6 z>LApXPB>Unt8V~;Cik9f49AhQ!$i7^fuL#4vW=&{86JR|lTsG~BRymzfEs|JX9J1K z03Dw$1C&G3WKK=%kB`J1r1*<~s2`z=k6T78&3xGOL&RV&0xXfJ0Ql@xfEn*A1CX9E zQ!WBD5?VbTK7XTsCp`U6crw}TsH%60W z2hoh@0nLYSxRBab{+9<3C+^Mz9xYb&ZxhMVDb+cqriY2<9AG-<8gN)^Cix5?)@kAU z;?6$;-SN`NKvD-cR@w%n?9AWi0I~xRElDnK5^Rh@FtDVHX8@ZJfJl->N&_A{l2bso z2x`kJr-3lmJ%9)DK@>~Q{7brt3fNKr^rbrq+|{-iAekxBG;uoyGqur4Ei0S?0=Yll zF_SR>W}x;7ttLalDFCI-OXsp?(S;*|rkk|uOcTs~fUR;0m?79z>!T@dSC<#zVpen3 zDj@L*GoMZY$tw7C*m%o|vLvel!qz~FMPzph=x6{KTjppdC7aC#VVdHg)$wl$bf*AC z1-Rnnz*LgVO4|B5HX#U@PXUn*;sq_sC5u*2fG7j7o&o~>%Wn3WWcg~#QmPptG|8+k2H7XW|=xVi9nUeg`1*I2IB*YJ(+JNL|VD24JQDXa_~} zqMBf8fF~Vbz5wvk*3xb81`yK5AZAEW$9)?Qt+BO>C3E@1Aktu4fz|6HW^Y;1@lk!lq%mkX z{~%3y0h-K!%;mq#+4%VQ5J7OCv&KMYjPLUG@9*#T_xE6cpCPBxaK_?)nX{kS?7!yn zfSI!2=Is9d{_pwx05oR#`T5`T`RC{7L9^Llzu!=FmQcCekkjew>+3LDf{>=XK(pDe zzt4c0vd`J#Fs;_V%-D~nykNlKAg9yc^7t^U)_~3BfX(J`#^Vv8&k>-{-}3p8(&?|? z?{JN&{r&x)v&FFA?=V_}aEz&7z~7M5=+D{X&+PS}+3awQs351(ptHqzpNxV4000qm zQchCIy&+X> z=*5Ul;OaQ@NK`Vzy8t_g2?_Jis)3C$i910Xw$PIU9&Uk!LpkskEkL9-LfkOWJAbaP zUroip18r(eg}^hN*BXg{sb1!Yfc6S#iGXvxN(6jb7x=sau0_D;#S-`?0_b=FJSG`H zPqbnfvWg$g}i**@5@#v5NT=$lzqSQdXDg|8f zIHlhJQN%Mfm~#2YP9b1YgB(!GAN!r?CIjA)sTANZfG||7{JhG5H)Vm3e?0>E>_vVi zq!;d4SOSQYxt#%m;F70Lx8o{r!Tt9&c8CI14(M}40nf9jzsNQAmkVA7gAM$Z|1+@m z0b{)*&IIp+jVE#-MjL9Dd6xv65#{P&<3u77*DDnbtf@m157r`vbG^_r?Ff8 d>Rr1A+%FMH_Q$8Zwr>Cc002ovPDHLkV1oT`waEYg literal 0 HcmV?d00001 diff --git a/version/201/paymentmethod/img/method/klarna@2x.png b/version/201/paymentmethod/img/method/klarna@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..e28a187b81e7c5a6256fea7382a643762746dd1e GIT binary patch literal 896 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 literal 0 HcmV?d00001 diff --git a/version/201/paymentmethod/img/method/paypal@2x.png b/version/201/paymentmethod/img/method/paypal@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..a816d7201f59ea7cef713f5e7895e66dcd6ee9a7 GIT binary patch literal 626 zcmV-&0*(ENP)zW{Q;0CK+oaK8X?zW{Q<0CB+pa=`#_!2of;na1S+alrro z|IFg@&*bxRu-m`e?~lRb-|hDbcETox$#AdRv()Q`yWm5X&|s$5P@dDD$>-eb_JFwG zpUUS$m(j@K@sPpeFpSLa_WMAU&p?#W{Qdsu^7&w=*MGR*^7#DO>Gd#+%P@?~P@U7S z((9ba=CIQ0sn6-_^!k0a-V=Mp)8_OXfyX(K&a%|&;_mkldc-e_%lZ5LgSp`#gUC6M z&erGk#LeN$0000GbW%=J0M8)rfN+qXfDoX6Z;yYFN6jxl0003wNklC4+MXiktqCYwRgSg6)KJbf z5Lj1?Y5+oU@|#dstX9C|0Ujt`J{M4b8Wr^cdi(ak0iFt>ORE}Nts8qh=FWCkI)}aEnE&{1?2hI?PIY68@ zbOdbw0PvXrf5i!Szy>sZ79ap>ye%)UHj^sMYbqagD6U zaJzaI>n$ypF23oVdS#o6|W|*DFT6j;X_Pjl^+{$7FxcM`F8{J!B6QqfZ6J=?T z0Z*i4z#}$g7~II(N7`*?T& O0000+D{~L?`zkmGy`PKgqj{m>0 z^Z&xI|35zdzp(26fxiDA9{<0v`v1;`{~L<_uT1&>;_Ck$4fn+3S%6jwlmz(&Gn{vr zARutRf5Q2Gh4~8e7rbanOaaP$^>lFzsfc?!?c};<10L727Z_ycPF(r9`v3o4QC^`f zNy*irThr_Lx8*f4F=sBE;Is9vL&{b+wWF_Q`cLpRlDMX^fZ@i14v}pdO3hrZ8V-u{ z6@GBmNPp@1=O;WPYJWl57EYgv)6tK(j<>!KX1Tkg-1yN7-6M=yr*jX!QWr1lo!e&; zepvX8JR>o1saCg`3ZOWgj;^L2z+zGho&3IENy|Lc5*g&izjA{*O9T;DjDIk7S9e6n)( p;e>?q6P^m(l+{vMe5&Mx9fO|m{vZE%WkG?%;OXk;vd$@?2>_eS)Oi2^ literal 0 HcmV?d00001 diff --git a/version/201/paymentmethod/tpl/bestellabschluss.tpl b/version/201/paymentmethod/tpl/bestellabschluss.tpl new file mode 100644 index 0000000..b26d8ef --- /dev/null +++ b/version/201/paymentmethod/tpl/bestellabschluss.tpl @@ -0,0 +1,26 @@ +{if isset($oMollieException)} +
+ {$oMollieException->getMessage()} +
+ +{/if} + +{if isset($redirect) && $redirect != ''} + + {if $checkoutMode == 'D'} + + {/if} +{/if} + diff --git a/version/201/paymentmethod/tpl/mollieComponents.tpl b/version/201/paymentmethod/tpl/mollieComponents.tpl new file mode 100644 index 0000000..38907e0 --- /dev/null +++ b/version/201/paymentmethod/tpl/mollieComponents.tpl @@ -0,0 +1,147 @@ +

{$mollieLang.cctitle}

+ +
+ +
+ + {if $token !== false} + +
+
+ {$mollieLang.clearDescr} +
+
+ +
+
+ + {if $trustBadge} +
+ PCI-DSS SAQ-A compliant +
+ {/if} + + {else} + + +
+ +
+
+
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+ +
+
+ + +
+
+ + {if $trustBadge} +
+ PCI-DSS SAQ-A compliant +
+ {/if} + {if $components == 'S'} + + {/if} +
+ +{/if} + + + + + + \ No newline at end of file diff --git a/version/201/sql/200.sql b/version/201/sql/200.sql new file mode 100644 index 0000000..0d28bdc --- /dev/null +++ b/version/201/sql/200.sql @@ -0,0 +1,31 @@ +CREATE TABLE IF NOT EXISTS `xplugin_ws_mollie_queue` ( + `kId` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY, + `cType` VARCHAR(32) NOT NULL, + `cData` TEXT DEFAULT '', + `cResult` TEXT NULL DEFAULT NULL, + `dDone` DATETIME NULL DEFAULT NULL, + `dCreated` DATETIME NOT NULL, + `dModified` DATETIME NULL DEFAULT NULL +); + +ALTER TABLE `xplugin_ws_mollie_payments` + ADD `dReminder` datetime NULL; +ALTER TABLE `xplugin_ws_mollie_payments` + ADD `cTransactionId` VARCHAR(32) DEFAULT ''; +ALTER TABLE `xplugin_ws_mollie_payments` + ADD `bSynced` TINYINT(1) NOT NULL; + +UPDATE `xplugin_ws_mollie_payments` +SET `bSynced` = true; + +CREATE TABLE IF NOT EXISTS `xplugin_ws_mollie_shipments` ( + `kLieferschien` int(11) NOT NULL PRIMARY KEY, + `kBestellung` int(11) NOT NULL, + `cOrderId` VARCHAR(32) NOT NULL, + `cShipmentId` VARCHAR(32) NOT NULL, + `cCarrier` VARCHAR(255) DEFAULT '', + `cCode` VARCHAR(255) DEFAULT '', + `cUrl` VARCHAR(512) DEFAULT '', + `dCreated` DATETIME NOT NULL, + `dModified` DATETIME NULL DEFAULT NULL +); \ No newline at end of file diff --git a/version/201/tpl/_alerts.tpl b/version/201/tpl/_alerts.tpl new file mode 100644 index 0000000..5279fa3 --- /dev/null +++ b/version/201/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} From 76e831ba1bb5d40f697c1767eaeae88a4b45d4db Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Thu, 22 Apr 2021 10:02:29 +0200 Subject: [PATCH 202/280] adminmenu error handling --- version/200/adminmenu/orders.php | 4 +--- version/201/adminmenu/orders.php | 5 +---- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/version/200/adminmenu/orders.php b/version/200/adminmenu/orders.php index 9b09dc2..60cfd5d 100644 --- a/version/200/adminmenu/orders.php +++ b/version/200/adminmenu/orders.php @@ -204,12 +204,10 @@ Shop::Smarty()->display($oPlugin->cAdminmenuPfad . '/tpl/order.tpl'); return; - } catch (InvalidArgumentException $e) { - Helper::addAlert('Fehler: ' . $e->getMessage(), 'danger', 'orders'); } catch (Exception $e) { Helper::addAlert('Fehler: ' . $e->getMessage(), 'danger', 'orders'); - return; } + break; } } diff --git a/version/201/adminmenu/orders.php b/version/201/adminmenu/orders.php index 9b09dc2..4a3e126 100644 --- a/version/201/adminmenu/orders.php +++ b/version/201/adminmenu/orders.php @@ -203,13 +203,10 @@ ->assign('logs', $checkout->getLogs()); Shop::Smarty()->display($oPlugin->cAdminmenuPfad . '/tpl/order.tpl'); return; - - } catch (InvalidArgumentException $e) { - Helper::addAlert('Fehler: ' . $e->getMessage(), 'danger', 'orders'); } catch (Exception $e) { Helper::addAlert('Fehler: ' . $e->getMessage(), 'danger', 'orders'); - return; } + break; } } From 7d1cd32ba0e670a2b84260d197d3e9245abf9442 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Fri, 23 Apr 2021 10:58:46 +0200 Subject: [PATCH 203/280] fix sendReminders --- .../200/class/Checkout/AbstractCheckout.php | 121 +++++++++--------- version/200/paymentmethod/JTLMollie.php | 6 +- .../200/paymentmethod/JTLMollieApplePay.php | 2 + .../201/class/Checkout/AbstractCheckout.php | 120 ++++++++--------- version/201/paymentmethod/JTLMollie.php | 3 +- 5 files changed, 129 insertions(+), 123 deletions(-) diff --git a/version/200/class/Checkout/AbstractCheckout.php b/version/200/class/Checkout/AbstractCheckout.php index e77deb6..2793d96 100644 --- a/version/200/class/Checkout/AbstractCheckout.php +++ b/version/200/class/Checkout/AbstractCheckout.php @@ -147,14 +147,15 @@ public static function sendReminders() { $reminder = (int)self::Plugin()->oPluginEinstellungAssoc_arr['reminder']; - /*if (!$reminder) { - Shop::DB()->executeQueryPrepared('UPDATE xplugin_ws_mollie_payments SET dReminder = :dReminder WHERE dReminder IS NULL', [ - ':dReminder' => date('Y-m-d H:i:s') - ], 3); + if (!$reminder) { return; - }*/ + } + + $sql = "SELECT p.kId FROM xplugin_ws_mollie_payments p JOIN tbestellung b ON b.kBestellung = p.kBestellung " + . "WHERE (p.dReminder IS NULL OR p.dReminder = '0000-00-00 00:00:00') " + . "AND p.dCreatedAt < NOW() - INTERVAL :d HOUR AND p.dCreatedAt > NOW() - INTERVAL 7 DAY " + ."AND p.cStatus IN ('created','open', 'expired', 'failed', 'canceled') AND NOT b.cStatus = '-1'"; - $sql = "SELECT p.kId FROM xplugin_ws_mollie_payments p JOIN tbestellung b ON b.kBestellung = p.kBestellung WHERE p.dReminder IS NULL OR p.dReminder = '0000-00-00 00:00:00' AND p.dCreatedAt < NOW() - INTERVAL :d HOUR AND p.cStatus IN ('created','open', 'expired', 'failed', 'canceled') AND NOT b.cStatus = '-1'"; $remindables = Shop::DB()->executeQueryPrepared($sql, [ ':d' => $reminder @@ -228,27 +229,51 @@ public static function fromID($id) } /** - * @return Payment + * @param AbstractCheckout $checkout + * @return \Mollie\Api\Resources\BaseResource|\Mollie\Api\Resources\Refund + * @throws ApiException */ - public function getModel() + public static function refund(AbstractCheckout $checkout) { - if (!$this->model) { - $this->model = Payment::fromID($this->oBestellung->kBestellung, 'kBestellung'); + if ($checkout->getMollie()->resource === 'order') { + /** @var Order $order */ + $order = $checkout->getMollie(); + if (in_array($order->status, [OrderStatus::STATUS_CANCELED, OrderStatus::STATUS_EXPIRED, OrderStatus::STATUS_CREATED], true)) { + throw new RuntimeException('Bestellung kann derzeit nicht zurückerstattet werden.'); + } + $refund = $order->refundAll(); + $checkout->Log(sprintf('Bestellung wurde manuell zurückerstattet: %s', $refund->id)); + return $refund; } - return $this->model; + if ($checkout->getMollie()->resource === 'payment') { + /** @var \Mollie\Api\Resources\Payment $payment */ + $payment = $checkout->getMollie(); + if (in_array($payment->status, [PaymentStatus::STATUS_CANCELED, PaymentStatus::STATUS_EXPIRED, PaymentStatus::STATUS_OPEN], true)) { + throw new RuntimeException('Zahlung kann derzeit nicht zurückerstattet werden.'); + } + $refund = $checkout->API()->Client()->payments->refund($checkout->getMollie(), ['amount' => $checkout->getMollie()->amount]); + $checkout->Log(sprintf('Zahlung wurde manuell zurückerstattet: %s', $refund->id)); + return $refund; + } + throw new RuntimeException(sprintf('Unbekannte Resource: %s', $checkout->getMollie()->resource)); } /** - * @param $model - * @return $this + * @param false $force + * @return Order|\Mollie\Api\Resources\Payment|null */ - protected function setModel($model) + abstract public function getMollie($force = false); + + public function Log($msg, $level = LOGLEVEL_NOTICE) { - if (!$this->model) { - $this->model = $model; - } else { - throw new RuntimeException('Model already set.'); + $data = ''; + if ($this->getBestellung()) { + $data .= '#' . $this->getBestellung()->kBestellung; + } + if ($this->getMollie()) { + $data .= '$' . $this->getMollie()->id; } + ZahlungsLog::add($this->PaymentMethod()->moduleID, "[" . microtime(true) . " - " . $_SERVER['PHP_SELF'] . "] " . $msg, $data, $level); return $this; } @@ -263,24 +288,30 @@ public function getBestellung() return $this->oBestellung; } - public function Log($msg, $level = LOGLEVEL_NOTICE) + /** + * @return Payment + */ + public function getModel() { - $data = ''; - if ($this->getBestellung()) { - $data .= '#' . $this->getBestellung()->kBestellung; - } - if ($this->getMollie()) { - $data .= '$' . $this->getMollie()->id; + if (!$this->model) { + $this->model = Payment::fromID($this->oBestellung->kBestellung, 'kBestellung'); } - ZahlungsLog::add($this->PaymentMethod()->moduleID, "[" . microtime(true) . " - " . $_SERVER['PHP_SELF'] . "] " . $msg, $data, $level); - return $this; + return $this->model; } /** - * @param false $force - * @return Order|\Mollie\Api\Resources\Payment|null + * @param $model + * @return $this */ - abstract public function getMollie($force = false); + protected function setModel($model) + { + if (!$this->model) { + $this->model = $model; + } else { + throw new RuntimeException('Model already set.'); + } + return $this; + } /** * @return JTLMollie @@ -298,36 +329,6 @@ public function PaymentMethod() return $this->paymentMethod; } - /** - * @param AbstractCheckout $checkout - * @return \Mollie\Api\Resources\BaseResource|\Mollie\Api\Resources\Refund - * @throws ApiException - */ - public static function refund(AbstractCheckout $checkout) - { - if ($checkout->getMollie()->resource === 'order') { - /** @var Order $order */ - $order = $checkout->getMollie(); - if (in_array($order->status, [OrderStatus::STATUS_CANCELED, OrderStatus::STATUS_EXPIRED, OrderStatus::STATUS_CREATED], true)) { - throw new RuntimeException('Bestellung kann derzeit nicht zurückerstattet werden.'); - } - $refund = $order->refundAll(); - $checkout->Log(sprintf('Bestellung wurde manuell zurückerstattet: %s', $refund->id)); - return $refund; - } - if ($checkout->getMollie()->resource === 'payment') { - /** @var \Mollie\Api\Resources\Payment $payment */ - $payment = $checkout->getMollie(); - if (in_array($payment->status, [PaymentStatus::STATUS_CANCELED, PaymentStatus::STATUS_EXPIRED, PaymentStatus::STATUS_OPEN], true)) { - throw new RuntimeException('Zahlung kann derzeit nicht zurückerstattet werden.'); - } - $refund = $checkout->API()->Client()->payments->refund($checkout->getMollie(), ['amount' => $checkout->getMollie()->amount]); - $checkout->Log(sprintf('Zahlung wurde manuell zurückerstattet: %s', $refund->id)); - return $refund; - } - throw new RuntimeException(sprintf('Unbekannte Resource: %s', $checkout->getMollie()->resource)); - } - /** * @return API */ diff --git a/version/200/paymentmethod/JTLMollie.php b/version/200/paymentmethod/JTLMollie.php index dfdcfd0..c3bc7a8 100644 --- a/version/200/paymentmethod/JTLMollie.php +++ b/version/200/paymentmethod/JTLMollie.php @@ -7,10 +7,12 @@ use ws_mollie\Checkout\PaymentCheckout; use ws_mollie\Helper; -require_once __DIR__ . '/../../../vendor/autoload.php'; +//require_once __DIR__ . '/../../../vendor/autoload.php'; require_once __DIR__ . '/../class/Helper.php'; require_once __DIR__ . '/../../../../../modules/PaymentMethod.class.php'; -require_once __DIR__ . '/../class/Traits/Plugin.php'; +//require_once __DIR__ . '/../class/Traits/Plugin.php'; + +Helper::init(); class JTLMollie extends PaymentMethod { diff --git a/version/200/paymentmethod/JTLMollieApplePay.php b/version/200/paymentmethod/JTLMollieApplePay.php index 4b23bf4..64c6541 100644 --- a/version/200/paymentmethod/JTLMollieApplePay.php +++ b/version/200/paymentmethod/JTLMollieApplePay.php @@ -2,6 +2,7 @@ use ws_mollie\Hook\ApplePay; +require_once __DIR__ . '/../class/Helper.php'; require_once __DIR__ . '/JTLMollie.php'; class JTLMollieApplePay extends JTLMollie @@ -10,6 +11,7 @@ class JTLMollieApplePay extends JTLMollie public function isSelectable() { + \ws_mollie\Helper::init(); return ApplePay::isAvailable() && parent::isSelectable(); } } diff --git a/version/201/class/Checkout/AbstractCheckout.php b/version/201/class/Checkout/AbstractCheckout.php index e77deb6..73ca98e 100644 --- a/version/201/class/Checkout/AbstractCheckout.php +++ b/version/201/class/Checkout/AbstractCheckout.php @@ -147,14 +147,14 @@ public static function sendReminders() { $reminder = (int)self::Plugin()->oPluginEinstellungAssoc_arr['reminder']; - /*if (!$reminder) { - Shop::DB()->executeQueryPrepared('UPDATE xplugin_ws_mollie_payments SET dReminder = :dReminder WHERE dReminder IS NULL', [ - ':dReminder' => date('Y-m-d H:i:s') - ], 3); + if (!$reminder) { return; - }*/ + } - $sql = "SELECT p.kId FROM xplugin_ws_mollie_payments p JOIN tbestellung b ON b.kBestellung = p.kBestellung WHERE p.dReminder IS NULL OR p.dReminder = '0000-00-00 00:00:00' AND p.dCreatedAt < NOW() - INTERVAL :d HOUR AND p.cStatus IN ('created','open', 'expired', 'failed', 'canceled') AND NOT b.cStatus = '-1'"; + $sql = "SELECT p.kId FROM xplugin_ws_mollie_payments p JOIN tbestellung b ON b.kBestellung = p.kBestellung " + . "WHERE (p.dReminder IS NULL OR p.dReminder = '0000-00-00 00:00:00') " + . "AND p.dCreatedAt < NOW() - INTERVAL :d HOUR AND p.dCreatedAt > NOW() - INTERVAL 7 DAY " + . "AND p.cStatus IN ('created','open', 'expired', 'failed', 'canceled') AND NOT b.cStatus = '-1'"; $remindables = Shop::DB()->executeQueryPrepared($sql, [ ':d' => $reminder @@ -228,27 +228,51 @@ public static function fromID($id) } /** - * @return Payment + * @param AbstractCheckout $checkout + * @return \Mollie\Api\Resources\BaseResource|\Mollie\Api\Resources\Refund + * @throws ApiException */ - public function getModel() + public static function refund(AbstractCheckout $checkout) { - if (!$this->model) { - $this->model = Payment::fromID($this->oBestellung->kBestellung, 'kBestellung'); + if ($checkout->getMollie()->resource === 'order') { + /** @var Order $order */ + $order = $checkout->getMollie(); + if (in_array($order->status, [OrderStatus::STATUS_CANCELED, OrderStatus::STATUS_EXPIRED, OrderStatus::STATUS_CREATED], true)) { + throw new RuntimeException('Bestellung kann derzeit nicht zurückerstattet werden.'); + } + $refund = $order->refundAll(); + $checkout->Log(sprintf('Bestellung wurde manuell zurückerstattet: %s', $refund->id)); + return $refund; } - return $this->model; + if ($checkout->getMollie()->resource === 'payment') { + /** @var \Mollie\Api\Resources\Payment $payment */ + $payment = $checkout->getMollie(); + if (in_array($payment->status, [PaymentStatus::STATUS_CANCELED, PaymentStatus::STATUS_EXPIRED, PaymentStatus::STATUS_OPEN], true)) { + throw new RuntimeException('Zahlung kann derzeit nicht zurückerstattet werden.'); + } + $refund = $checkout->API()->Client()->payments->refund($checkout->getMollie(), ['amount' => $checkout->getMollie()->amount]); + $checkout->Log(sprintf('Zahlung wurde manuell zurückerstattet: %s', $refund->id)); + return $refund; + } + throw new RuntimeException(sprintf('Unbekannte Resource: %s', $checkout->getMollie()->resource)); } /** - * @param $model - * @return $this + * @param false $force + * @return Order|\Mollie\Api\Resources\Payment|null */ - protected function setModel($model) + abstract public function getMollie($force = false); + + public function Log($msg, $level = LOGLEVEL_NOTICE) { - if (!$this->model) { - $this->model = $model; - } else { - throw new RuntimeException('Model already set.'); + $data = ''; + if ($this->getBestellung()) { + $data .= '#' . $this->getBestellung()->kBestellung; } + if ($this->getMollie()) { + $data .= '$' . $this->getMollie()->id; + } + ZahlungsLog::add($this->PaymentMethod()->moduleID, "[" . microtime(true) . " - " . $_SERVER['PHP_SELF'] . "] " . $msg, $data, $level); return $this; } @@ -263,24 +287,30 @@ public function getBestellung() return $this->oBestellung; } - public function Log($msg, $level = LOGLEVEL_NOTICE) + /** + * @return Payment + */ + public function getModel() { - $data = ''; - if ($this->getBestellung()) { - $data .= '#' . $this->getBestellung()->kBestellung; - } - if ($this->getMollie()) { - $data .= '$' . $this->getMollie()->id; + if (!$this->model) { + $this->model = Payment::fromID($this->oBestellung->kBestellung, 'kBestellung'); } - ZahlungsLog::add($this->PaymentMethod()->moduleID, "[" . microtime(true) . " - " . $_SERVER['PHP_SELF'] . "] " . $msg, $data, $level); - return $this; + return $this->model; } /** - * @param false $force - * @return Order|\Mollie\Api\Resources\Payment|null + * @param $model + * @return $this */ - abstract public function getMollie($force = false); + protected function setModel($model) + { + if (!$this->model) { + $this->model = $model; + } else { + throw new RuntimeException('Model already set.'); + } + return $this; + } /** * @return JTLMollie @@ -298,36 +328,6 @@ public function PaymentMethod() return $this->paymentMethod; } - /** - * @param AbstractCheckout $checkout - * @return \Mollie\Api\Resources\BaseResource|\Mollie\Api\Resources\Refund - * @throws ApiException - */ - public static function refund(AbstractCheckout $checkout) - { - if ($checkout->getMollie()->resource === 'order') { - /** @var Order $order */ - $order = $checkout->getMollie(); - if (in_array($order->status, [OrderStatus::STATUS_CANCELED, OrderStatus::STATUS_EXPIRED, OrderStatus::STATUS_CREATED], true)) { - throw new RuntimeException('Bestellung kann derzeit nicht zurückerstattet werden.'); - } - $refund = $order->refundAll(); - $checkout->Log(sprintf('Bestellung wurde manuell zurückerstattet: %s', $refund->id)); - return $refund; - } - if ($checkout->getMollie()->resource === 'payment') { - /** @var \Mollie\Api\Resources\Payment $payment */ - $payment = $checkout->getMollie(); - if (in_array($payment->status, [PaymentStatus::STATUS_CANCELED, PaymentStatus::STATUS_EXPIRED, PaymentStatus::STATUS_OPEN], true)) { - throw new RuntimeException('Zahlung kann derzeit nicht zurückerstattet werden.'); - } - $refund = $checkout->API()->Client()->payments->refund($checkout->getMollie(), ['amount' => $checkout->getMollie()->amount]); - $checkout->Log(sprintf('Zahlung wurde manuell zurückerstattet: %s', $refund->id)); - return $refund; - } - throw new RuntimeException(sprintf('Unbekannte Resource: %s', $checkout->getMollie()->resource)); - } - /** * @return API */ diff --git a/version/201/paymentmethod/JTLMollie.php b/version/201/paymentmethod/JTLMollie.php index dfdcfd0..2f42afa 100644 --- a/version/201/paymentmethod/JTLMollie.php +++ b/version/201/paymentmethod/JTLMollie.php @@ -10,7 +10,8 @@ require_once __DIR__ . '/../../../vendor/autoload.php'; require_once __DIR__ . '/../class/Helper.php'; require_once __DIR__ . '/../../../../../modules/PaymentMethod.class.php'; -require_once __DIR__ . '/../class/Traits/Plugin.php'; + +Helper::init(); class JTLMollie extends PaymentMethod { From c37de42d2b6f30de1471da5350fab2fbab0202db Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Fri, 23 Apr 2021 12:20:26 +0200 Subject: [PATCH 204/280] fix switch language --- version/201/class/API.php | 2 +- version/201/paymentmethod/JTLMollie.php | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/version/201/class/API.php b/version/201/class/API.php index ef6293d..3ed4f27 100644 --- a/version/201/class/API.php +++ b/version/201/class/API.php @@ -44,7 +44,7 @@ public function __construct($test = null) public static function getMode() { require_once PFAD_ROOT . PFAD_ADMIN . PFAD_INCLUDES . 'benutzerverwaltung_inc.php'; - return Shop::isAdmin() && self::Plugin()->oPluginEinstellungAssoc_arr["testAsAdmin"] === 'Y'; + return self::Plugin()->oPluginEinstellungAssoc_arr["testAsAdmin"] === 'Y' && Shop::isAdmin(); } /** diff --git a/version/201/paymentmethod/JTLMollie.php b/version/201/paymentmethod/JTLMollie.php index 2f42afa..1494095 100644 --- a/version/201/paymentmethod/JTLMollie.php +++ b/version/201/paymentmethod/JTLMollie.php @@ -213,7 +213,7 @@ protected static function isMethodPossible($method, $locale, $billingCountry, $c $key = md5(serialize([$locale, $billingCountry, $currency, $amount])); if (!array_key_exists($key, $_SESSION['mollie_possibleMethods'])) { - $_SESSION['mollie_possibleMethods'][$key] = $api->Client()->methods->allActive([ + $active = $api->Client()->methods->allActive([ 'locale' => $locale, 'amount' => [ 'currency' => $currency, @@ -223,6 +223,9 @@ protected static function isMethodPossible($method, $locale, $billingCountry, $c 'resource' => 'orders', 'includeWallets' => 'applepay', ]); + foreach($active as $a){ + $_SESSION['mollie_possibleMethods'][$key][] = (object)['id' =>$a->id]; + } } if ($method !== '') { From 809c378f77c2f56b53bcca37ddbc5b82d1bf1957 Mon Sep 17 00:00:00 2001 From: "dash.bar" Date: Fri, 23 Apr 2021 12:27:52 +0200 Subject: [PATCH 205/280] prepare finalize --- info.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/info.xml b/info.xml index beea361..95a8b5d 100644 --- a/info.xml +++ b/info.xml @@ -51,7 +51,7 @@ 2021-04-22 - 2021-04-22 + 2021-04-23 75_bestellungInDb.php From 11f55dcc446c21dd787c1ee86ce028c15564e156 Mon Sep 17 00:00:00 2001 From: "dash.bar" Date: Fri, 23 Apr 2021 12:27:52 +0200 Subject: [PATCH 206/280] init version 202 --- info.xml | 3 + version/202/adminmenu/info.php | 64 ++ version/202/adminmenu/orders.php | 234 +++++++ version/202/adminmenu/paymentmethods.php | 98 +++ version/202/adminmenu/tpl/info.tpl | 114 ++++ .../tpl/mollie-account-erstellen.png | Bin 0 -> 38998 bytes version/202/adminmenu/tpl/order.tpl | 344 ++++++++++ version/202/adminmenu/tpl/orders.tpl | 158 +++++ version/202/adminmenu/tpl/paymentmethods.tpl | 138 ++++ version/202/class/API.php | 78 +++ .../202/class/Checkout/AbstractCheckout.php | 621 ++++++++++++++++++ .../202/class/Checkout/AbstractResource.php | 18 + .../Exception/ResourceValidityException.php | 23 + version/202/class/Checkout/Order/Address.php | 44 ++ .../202/class/Checkout/Order/OrderLine.php | 223 +++++++ version/202/class/Checkout/OrderCheckout.php | 356 ++++++++++ .../202/class/Checkout/Payment/Address.php | 54 ++ version/202/class/Checkout/Payment/Amount.php | 72 ++ .../202/class/Checkout/PaymentCheckout.php | 209 ++++++ version/202/class/ExclusiveLock.php | 70 ++ version/202/class/Helper.php | 352 ++++++++++ version/202/class/Hook/AbstractHook.php | 13 + version/202/class/Hook/ApplePay.php | 56 ++ version/202/class/Hook/Checkbox.php | 60 ++ version/202/class/Hook/Queue.php | 129 ++++ version/202/class/Model/AbstractModel.php | 92 +++ version/202/class/Model/Customer.php | 19 + version/202/class/Model/Payment.php | 47 ++ version/202/class/Model/Queue.php | 41 ++ version/202/class/Model/Shipment.php | 28 + version/202/class/Mollie.php | 274 ++++++++ version/202/class/Queue.php | 153 +++++ version/202/class/Shipment.php | 318 +++++++++ version/202/class/Traits/Jsonable.php | 20 + version/202/class/Traits/Plugin.php | 25 + version/202/class/Traits/RequestData.php | 59 ++ version/202/frontend/.htaccess | 9 + version/202/frontend/131_globalinclude.php | 30 + version/202/frontend/132_headPostGet.php | 17 + version/202/frontend/140_smarty.php | 58 ++ version/202/frontend/180_checkbox.php | 18 + version/202/frontend/181_sync.php | 14 + version/202/frontend/210_storno.php | 17 + version/202/frontend/75_bestellungInDb.php | 17 + version/202/frontend/applepay.php | 18 + version/202/frontend/img/trust_eng.png | Bin 0 -> 15299 bytes version/202/frontend/img/trust_fre.png | Bin 0 -> 17319 bytes version/202/frontend/img/trust_ger.png | Bin 0 -> 15352 bytes version/202/frontend/tpl/applepay.tpl | 15 + version/202/paymentmethod/JTLMollie.php | 264 ++++++++ .../202/paymentmethod/JTLMollieApplePay.php | 15 + .../202/paymentmethod/JTLMollieBancontact.php | 8 + .../paymentmethod/JTLMollieBanktransfer.php | 28 + .../202/paymentmethod/JTLMollieBelfius.php | 8 + .../202/paymentmethod/JTLMollieCreditCard.php | 144 ++++ .../paymentmethod/JTLMollieDirectDebit.php | 27 + version/202/paymentmethod/JTLMollieEPS.php | 8 + .../202/paymentmethod/JTLMollieGiftcard.php | 27 + .../202/paymentmethod/JTLMollieGiropay.php | 8 + version/202/paymentmethod/JTLMollieIDEAL.php | 8 + .../202/paymentmethod/JTLMollieINGHomePay.php | 28 + version/202/paymentmethod/JTLMollieKBC.php | 13 + .../paymentmethod/JTLMollieKlarnaPayLater.php | 10 + .../paymentmethod/JTLMollieKlarnaSliceIt.php | 10 + version/202/paymentmethod/JTLMollieMyBank.php | 8 + version/202/paymentmethod/JTLMolliePayPal.php | 36 + .../paymentmethod/JTLMolliePaysafecard.php | 13 + .../202/paymentmethod/JTLMolliePrzelewy24.php | 15 + version/202/paymentmethod/JTLMollieSofort.php | 8 + .../img/method/Przelewy24@2x.png | Bin 0 -> 859 bytes .../paymentmethod/img/method/applepay@2x.png | Bin 0 -> 656 bytes .../img/method/bancontact@2x.png | Bin 0 -> 582 bytes .../img/method/banktransfer@2x.png | Bin 0 -> 801 bytes .../paymentmethod/img/method/belfius@2x.png | Bin 0 -> 377 bytes .../img/method/creditcard@2x.png | Bin 0 -> 3125 bytes .../img/method/directdebit@2x.png | Bin 0 -> 801 bytes .../202/paymentmethod/img/method/eps@2x.png | Bin 0 -> 536 bytes .../paymentmethod/img/method/giftcard@2x.png | Bin 0 -> 2218 bytes .../paymentmethod/img/method/giropay@2x.png | Bin 0 -> 602 bytes .../202/paymentmethod/img/method/ideal@2x.png | Bin 0 -> 845 bytes .../img/method/inghomepay@2x.png | Bin 0 -> 1118 bytes .../202/paymentmethod/img/method/kbc@2x.png | Bin 0 -> 799 bytes .../paymentmethod/img/method/klarna@2x.png | Bin 0 -> 896 bytes .../paymentmethod/img/method/mollie@2x.png | Bin 0 -> 5366 bytes .../paymentmethod/img/method/mybank@2x.png | Bin 0 -> 2111 bytes .../paymentmethod/img/method/paypal@2x.png | Bin 0 -> 626 bytes .../img/method/paysafecard@2x.png | Bin 0 -> 420 bytes .../paymentmethod/img/method/sofort@2x.png | Bin 0 -> 453 bytes .../paymentmethod/tpl/bestellabschluss.tpl | 26 + .../paymentmethod/tpl/mollieComponents.tpl | 147 +++++ version/202/sql/200.sql | 31 + version/202/tpl/_alerts.tpl | 10 + 92 files changed, 5720 insertions(+) create mode 100644 version/202/adminmenu/info.php create mode 100644 version/202/adminmenu/orders.php create mode 100644 version/202/adminmenu/paymentmethods.php create mode 100644 version/202/adminmenu/tpl/info.tpl create mode 100644 version/202/adminmenu/tpl/mollie-account-erstellen.png create mode 100644 version/202/adminmenu/tpl/order.tpl create mode 100644 version/202/adminmenu/tpl/orders.tpl create mode 100644 version/202/adminmenu/tpl/paymentmethods.tpl create mode 100644 version/202/class/API.php create mode 100644 version/202/class/Checkout/AbstractCheckout.php create mode 100644 version/202/class/Checkout/AbstractResource.php create mode 100644 version/202/class/Checkout/Exception/ResourceValidityException.php create mode 100644 version/202/class/Checkout/Order/Address.php create mode 100644 version/202/class/Checkout/Order/OrderLine.php create mode 100644 version/202/class/Checkout/OrderCheckout.php create mode 100644 version/202/class/Checkout/Payment/Address.php create mode 100644 version/202/class/Checkout/Payment/Amount.php create mode 100644 version/202/class/Checkout/PaymentCheckout.php create mode 100644 version/202/class/ExclusiveLock.php create mode 100644 version/202/class/Helper.php create mode 100644 version/202/class/Hook/AbstractHook.php create mode 100644 version/202/class/Hook/ApplePay.php create mode 100644 version/202/class/Hook/Checkbox.php create mode 100644 version/202/class/Hook/Queue.php create mode 100644 version/202/class/Model/AbstractModel.php create mode 100644 version/202/class/Model/Customer.php create mode 100644 version/202/class/Model/Payment.php create mode 100644 version/202/class/Model/Queue.php create mode 100644 version/202/class/Model/Shipment.php create mode 100644 version/202/class/Mollie.php create mode 100644 version/202/class/Queue.php create mode 100644 version/202/class/Shipment.php create mode 100644 version/202/class/Traits/Jsonable.php create mode 100644 version/202/class/Traits/Plugin.php create mode 100644 version/202/class/Traits/RequestData.php create mode 100644 version/202/frontend/.htaccess create mode 100644 version/202/frontend/131_globalinclude.php create mode 100644 version/202/frontend/132_headPostGet.php create mode 100644 version/202/frontend/140_smarty.php create mode 100644 version/202/frontend/180_checkbox.php create mode 100644 version/202/frontend/181_sync.php create mode 100644 version/202/frontend/210_storno.php create mode 100644 version/202/frontend/75_bestellungInDb.php create mode 100644 version/202/frontend/applepay.php create mode 100644 version/202/frontend/img/trust_eng.png create mode 100644 version/202/frontend/img/trust_fre.png create mode 100644 version/202/frontend/img/trust_ger.png create mode 100644 version/202/frontend/tpl/applepay.tpl create mode 100644 version/202/paymentmethod/JTLMollie.php create mode 100644 version/202/paymentmethod/JTLMollieApplePay.php create mode 100644 version/202/paymentmethod/JTLMollieBancontact.php create mode 100644 version/202/paymentmethod/JTLMollieBanktransfer.php create mode 100644 version/202/paymentmethod/JTLMollieBelfius.php create mode 100644 version/202/paymentmethod/JTLMollieCreditCard.php create mode 100644 version/202/paymentmethod/JTLMollieDirectDebit.php create mode 100644 version/202/paymentmethod/JTLMollieEPS.php create mode 100644 version/202/paymentmethod/JTLMollieGiftcard.php create mode 100644 version/202/paymentmethod/JTLMollieGiropay.php create mode 100644 version/202/paymentmethod/JTLMollieIDEAL.php create mode 100644 version/202/paymentmethod/JTLMollieINGHomePay.php create mode 100644 version/202/paymentmethod/JTLMollieKBC.php create mode 100644 version/202/paymentmethod/JTLMollieKlarnaPayLater.php create mode 100644 version/202/paymentmethod/JTLMollieKlarnaSliceIt.php create mode 100644 version/202/paymentmethod/JTLMollieMyBank.php create mode 100644 version/202/paymentmethod/JTLMolliePayPal.php create mode 100644 version/202/paymentmethod/JTLMolliePaysafecard.php create mode 100644 version/202/paymentmethod/JTLMolliePrzelewy24.php create mode 100644 version/202/paymentmethod/JTLMollieSofort.php create mode 100644 version/202/paymentmethod/img/method/Przelewy24@2x.png create mode 100644 version/202/paymentmethod/img/method/applepay@2x.png create mode 100644 version/202/paymentmethod/img/method/bancontact@2x.png create mode 100644 version/202/paymentmethod/img/method/banktransfer@2x.png create mode 100644 version/202/paymentmethod/img/method/belfius@2x.png create mode 100644 version/202/paymentmethod/img/method/creditcard@2x.png create mode 100644 version/202/paymentmethod/img/method/directdebit@2x.png create mode 100644 version/202/paymentmethod/img/method/eps@2x.png create mode 100644 version/202/paymentmethod/img/method/giftcard@2x.png create mode 100644 version/202/paymentmethod/img/method/giropay@2x.png create mode 100644 version/202/paymentmethod/img/method/ideal@2x.png create mode 100644 version/202/paymentmethod/img/method/inghomepay@2x.png create mode 100644 version/202/paymentmethod/img/method/kbc@2x.png create mode 100644 version/202/paymentmethod/img/method/klarna@2x.png create mode 100644 version/202/paymentmethod/img/method/mollie@2x.png create mode 100644 version/202/paymentmethod/img/method/mybank@2x.png create mode 100644 version/202/paymentmethod/img/method/paypal@2x.png create mode 100644 version/202/paymentmethod/img/method/paysafecard@2x.png create mode 100644 version/202/paymentmethod/img/method/sofort@2x.png create mode 100644 version/202/paymentmethod/tpl/bestellabschluss.tpl create mode 100644 version/202/paymentmethod/tpl/mollieComponents.tpl create mode 100644 version/202/sql/200.sql create mode 100644 version/202/tpl/_alerts.tpl diff --git a/info.xml b/info.xml index 95a8b5d..11f7439 100644 --- a/info.xml +++ b/info.xml @@ -53,6 +53,9 @@ 2021-04-23 + + 2021-04-23 + 75_bestellungInDb.php 131_globalinclude.php diff --git a/version/202/adminmenu/info.php b/version/202/adminmenu/info.php new file mode 100644 index 0000000..817c5db --- /dev/null +++ b/version/202/adminmenu/info.php @@ -0,0 +1,64 @@ +assign('defaultTabbertab', Helper::getAdminmenu('Info') + Helper::getAdminmenu('Support')); + 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 "
" . + "
" . + " " . + " Lizenz Informationen" . + ' ' . + '
' . + "
" . + " " . + " Update Informationen" . + ' ' . + '
' . + "
" . + " " . + " Plugin informationen" . + ' ' . + '
' . + '
'; + + 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/202/adminmenu/orders.php b/version/202/adminmenu/orders.php new file mode 100644 index 0000000..4a3e126 --- /dev/null +++ b/version/202/adminmenu/orders.php @@ -0,0 +1,234 @@ +getModel()->kID)) { + Helper::addAlert('Zahlungserinnerung wurde verschickt.', 'success', 'orders'); + } else { + Helper::addAlert('Es ist ein Fehler aufgetreten, prüfe den Log.', 'danger', 'orders'); + } + } else { + Helper::addAlert('Bestellung konnte nicht geladen werden.', 'danger', 'orders'); + } + + + break; + + case "fetchable": + + if (array_key_exists('kBestellung', $_REQUEST) && ($checkout = AbstractCheckout::fromBestellung((int)$_REQUEST['kBestellung']))) { + if (AbstractCheckout::makeFetchable($checkout->getBestellung(), $checkout->getModel())) { + Helper::addAlert('Bestellung kann jetzt von der WAWI abgeholt werden.', 'success', 'orders'); + } else { + Helper::addAlert('Es ist ein Fehler aufgetreten, prüfe den Log.', 'danger', 'orders'); + } + } else { + Helper::addAlert('Bestellung konnte nicht geladen werden.', 'danger', 'orders'); + } + + break; + + 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); + + + 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', 'wb'); + + + fputcsv($out, [ + 'kBestellung', + 'OrderID', + 'Status (mollie)', + 'BestellNr', + 'Status (JTL)', + 'Mode', + 'OriginalOrderNumber', + 'Currency', + 'Amount', + 'Method', + 'PaymentID', + 'Created' + ]); + + + foreach ($orders as $order) { + $order = new ws_mollie\Model\Payment($order); + $checkout = AbstractCheckout::fromModel($order); + + $tmp = [ + 'kBestellung' => $order->kBestellung, + 'cOrderId' => $order->kID, + 'cStatus' => $checkout->getMollie() ? $checkout->getMollie()->status : $order->cStatus, + 'cBestellNr' => $checkout->getBestellung() ? $checkout->getBestellung()->cBestellNr : $order->cOrderNumber, + 'nStatus' => $checkout->getBestellung() ? $checkout->getBestellung()->cStatus : 0, + 'cMode' => $order->cMode, + 'cOriginalOrderNumber' => $checkout->getMollie() && isset($checkout->getMollie()->metadata->originalOrderNumber) ? $checkout->getMollie()->metadata->originalOrderNumber : '', + 'cCurrency' => $order->cCurrency, + 'fAmount' => $order->fAmount, + 'cMethod' => $order->cMethod, + 'cPaymentId' => $order->cTransactionId, + 'dCreated' => $order->dCreatedAt, + ]; + + try { + if ($checkout->getMollie() && $checkout->getMollie()->resource === 'order') { + foreach ($checkout->getMollie()->payments() as $payment) { + if ($payment->status === 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': + try { + if (!array_key_exists('id', $_REQUEST)) { + throw new InvalidArgumentException('Keine ID angegeben!', 'danger', 'orders'); + } + $checkout = AbstractCheckout::fromID($_REQUEST['id']); + if ($refund = $checkout::refund($checkout)) { + Helper::addAlert(sprintf('Bestellung wurde zurückerstattet (%s).', $refund->id), 'success', 'orders'); + } + goto order; + } catch (InvalidArgumentException $e) { + Helper::addAlert('Fehler: ' . $e->getMessage(), 'danger', 'orders'); + } catch (Exception $e) { + Helper::addAlert('Fehler: ' . $e->getMessage(), 'danger', 'orders'); + goto order; + } + break; + + case 'cancel': + try { + if (!array_key_exists('id', $_REQUEST)) { + throw new InvalidArgumentException('Keine ID angeben!'); + } + $checkout = AbstractCheckout::fromID($_REQUEST['id']); + if ($checkout::cancel($checkout)) { + Helper::addAlert('Bestellung wurde abgebrochen.', 'success', 'orders'); + } + goto order; + } catch (InvalidArgumentException $e) { + Helper::addAlert('Fehler: ' . $e->getMessage(), 'danger', 'orders'); + } catch (Exception $e) { + Helper::addAlert('Fehler: ' . $e->getMessage(), 'danger', 'orders'); + goto order; + } + break; + + case 'capture': + try { + if (!array_key_exists('id', $_REQUEST)) { + throw new InvalidArgumentException('Keine ID angeben!'); + } + $checkout = AbstractCheckout::fromID($_REQUEST['id']); + if ($shipmentId = OrderCheckout::capture($checkout)) { + Helper::addAlert(sprintf('Zahlung erfolgreich erfasst/versandt (%s).', $shipmentId), 'success', 'orders'); + } + goto order; + } catch (InvalidArgumentException $e) { + Helper::addAlert('Fehler: ' . $e->getMessage(), 'danger', 'orders'); + } catch (Exception $e) { + Helper::addAlert('Fehler: ' . $e->getMessage(), 'danger', 'orders'); + goto order; + } + break; + + case 'order': + order: + try { + + if (!array_key_exists('id', $_REQUEST)) { + throw new InvalidArgumentException('Keine ID angeben!'); + } + + $checkout = AbstractCheckout::fromID($_REQUEST['id']); + + if ($checkout instanceof OrderCheckout) { + Shop::Smarty()->assign('shipments', $checkout->getShipments()); + } + + Shop::Smarty()->assign('payment', $checkout->getModel()) + ->assign('oBestellung', $checkout->getBestellung()) + ->assign('order', $checkout->getMollie()) + ->assign('checkout', $checkout) + ->assign('logs', $checkout->getLogs()); + Shop::Smarty()->display($oPlugin->cAdminmenuPfad . '/tpl/order.tpl'); + return; + } catch (Exception $e) { + Helper::addAlert('Fehler: ' . $e->getMessage(), 'danger', 'orders'); + } + break; + } + } + + Mollie::fixZahlungsarten(); + + $checkouts = []; + $payments = Shop::DB()->executeQueryPrepared("SELECT * FROM xplugin_ws_mollie_payments WHERE kBestellung IS NOT NULL ORDER BY dCreatedAt DESC LIMIT 1000;", [], 2); + foreach ($payments as $i => $payment) { + $payment = new Payment($payment); + $checkouts[$payment->kBestellung] = AbstractCheckout::fromModel($payment, false); + } + + Shop::Smarty()->assign('payments', $payments) + ->assign('checkouts', $checkouts) + ->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/202/adminmenu/paymentmethods.php b/version/202/adminmenu/paymentmethods.php new file mode 100644 index 0000000..d7e11c4 --- /dev/null +++ b/version/202/adminmenu/paymentmethods.php @@ -0,0 +1,98 @@ +setApiKey(Helper::getSetting("api_key")); + + $profile = $mollie->profiles->get('me'); + + $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}$/']]) ?: AbstractCheckout::getLocale(); + $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', + 'locale' => $locale + ]; + if ($amount && $currency) { + $params['amount'] = ['value' => number_format($amount, 2, '.', ''), 'currency' => $currency]; + if ($active) { + $params['includeWallets'] = 'applepay'; + //$params['resource'] = 'orders'; + } + } + + $allMethods = []; + if ($active) { + $_allMethods = $mollie->methods->allActive($params); + } else { + $_allMethods = $mollie->methods->allAvailable($params); + } + + $sessionLife = (int)ini_get('session.gc_maxlifetime'); + + /** @var Method $method */ + foreach ($_allMethods as $method) { + + $id = $method->id === 'creditcard' ? 'kreditkarte' : $method->id; + $key = "kPlugin_{$oPlugin->kPlugin}_mollie{$id}"; + + $class = null; + $shop = null; + $oClass = null; + + if (!in_array($id, ['voucher', 'giftcard', 'directdebit'], true) && array_key_exists($key, $oPlugin->oPluginZahlungsKlasseAssoc_arr)) { + $class = $oPlugin->oPluginZahlungsKlasseAssoc_arr[$key]; + include_once($oPlugin->cPluginPfad . 'paymentmethod/' . $class->cClassPfad); + /** @var JTLMollie $oClass */ + $oClass = new $class->cClassName($id); + } + if (array_key_exists($key, $oPlugin->oPluginZahlungsmethodeAssoc_arr)) { + $shop = $oPlugin->oPluginZahlungsmethodeAssoc_arr[$key]; + } + + + $maxExpiryDays = $oClass ? $oClass->getExpiryDays() : null; + $allMethods[$method->id] = (object)[ + 'mollie' => $method, + 'class' => $class, + 'oClass' => $oClass, + 'shop' => $shop, + 'maxExpiryDays' => $oClass ? $maxExpiryDays : null, + 'warning' => $oClass && ($maxExpiryDays * 24 * 60 * 60) > $sessionLife, + 'session' => round($sessionLife / 60 / 60, 2) . 'h' + ]; + + } + + 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/202/adminmenu/tpl/info.tpl b/version/202/adminmenu/tpl/info.tpl new file mode 100644 index 0000000..2952fc6 --- /dev/null +++ b/version/202/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}
+
+
+
Changelog:
+
+ +
+
+ +
+
+ +
+
+
+ {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/202/adminmenu/tpl/mollie-account-erstellen.png b/version/202/adminmenu/tpl/mollie-account-erstellen.png new file mode 100644 index 0000000000000000000000000000000000000000..fc1819255ef725fa214cf2bf028cf3428794ecee GIT binary patch literal 38998 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 +

+ « + 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 isset($order->customerId)} + ID: + {$order->customerId} +
+ {/if} + {if isset($order->billingAddress, $order->billingAddress->organizationName)} + {$order->billingAddress->organizationName} + {elseif isset($order->billingAddress)} + {$order->billingAddress->title} {$order->billingAddress->givenName} {$order->billingAddress->familyName} + {/if} +
Mollie Checkout: + {if $order->getCheckoutURL()} + mollie.com/... + {else} + n/a + {/if} + RePay-URL: + +
+{if $order->id|strpos:"ord_" !== false && $order->payments()->count > 0} +

Zahlungen

+ + + + + + + + + + + + + + {foreach from=$order->payments() item=payment} + + + + + + + + + + + {/foreach} +
IDStatusMethodeAmountSettlementRefundedRemainingDetails
{$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} +
+
+{/if} + +
+ {if ($order->status === 'authorized' || $order->status === 'shipping') && $oBestellung->cStatus|intval >= 3} + + Zahlung erfassen1 + + {/if} + {if !$order->amountRefunded || ($order->amount->value > $order->amountRefunded->value)} + Rückerstatten2 + + {/if} + {if $order->isCancelable} + Abbrechen3 + + {/if} +
+ +{if $order->id|strpos:"ord_" !== false} +

Positionen:

+ + + + + + + + + + + + + + + + + {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} + + + + + + + + + + + + + {/foreach} + + + + + + + + + + +
StatusSKUNameTypAnzahlMwStSteuerNettoBrutto 
+ {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'} + abgebrochen + {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*} +
{$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.
+
+{/if} + +{if isset($shipments) && $shipments|count} +

Shipmets

+ + + + + + + + + + + {foreach from=$shipments item=shipment} + + + + + + + {/foreach} + +
Lieferschein Nr.Mollie IDCarrierCode
{$shipment->getLieferschein()->getLieferscheinNr()}{$shipment->getShipment()->id} + {if isset($shipment->getShipment()->tracking)} + {$shipment->getShipment()->tracking->carrier} + {else} + - + {/if} + {if isset($shipment->getShipment()->tracking)} + {if isset($shipment->getShipment()->tracking->url)} + + {$shipment->getShipment()->tracking->code} + + {else} + {$shipment->getShipment()->tracking->code} + {/if} + {else} + - + {/if} +
+{/if} + +

Log

+ + {foreach from=$logs item=log} + + + + + + + {/foreach} +
+ {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}
+ + diff --git a/version/202/adminmenu/tpl/orders.tpl b/version/202/adminmenu/tpl/orders.tpl new file mode 100644 index 0000000..8745a0c --- /dev/null +++ b/version/202/adminmenu/tpl/orders.tpl @@ -0,0 +1,158 @@ +{ws_mollie\Helper::showAlerts('orders')} + +{if $hasAPIKey == false} + + Jetzt kostenlos Mollie Account eröffnen! + +{else} + + + + + + + + + + + + + + + {foreach from=$checkouts item=checkout} + + + + + + + + + + + + + + + {/foreach} + +
BestellNr.IDMollie StatusJTL StatusBetragMethodeErstellt 
+ {if $checkout->getModel()->bSynced == false && $checkout->getBestellung()->cAbgeholt === 'Y'} + * + {/if} + {$checkout->getModel()->cOrderNumber} + {if $checkout->getModel()->cMode == 'test'} + TEST + {/if} + {if $checkout->getModel()->bLockTimeout} + LOCK TIMEOUT + {/if} + {if $checkout->getModel()->dReminder && $checkout->getModel()->dReminder !== '0000-00-00 00:00:00'} + getModel()->dReminder|strtotime}}"> + {/if} + + {$checkout->getModel()->kID} + + {if $checkout->getModel()->cStatus == 'created' || $checkout->getModel()->cStatus == 'open'} + erstellt + {elseif $checkout->getModel()->cStatus == 'pending'} + austehend + {elseif $checkout->getModel()->cStatus == 'paid'} + bezahlt + {elseif $checkout->getModel()->cStatus == 'authorized'} + autorisiert + {elseif $checkout->getModel()->cStatus == 'shipping'} + versendet + {elseif $checkout->getModel()->cStatus == 'completed'} + abgeschlossen + {elseif $checkout->getModel()->cStatus == 'expired'} + abgelaufen + {elseif $checkout->getModel()->cStatus == 'canceled'} + abgebrochen + {else} + Unbekannt: {$checkout->getModel()->cStatus} + {/if} + {if $checkout->getModel()->fAmountRefunded && $checkout->getModel()->fAmountRefunded == $checkout->getModel()->fAmount} + (total refund) + {elseif $checkout->getModel()->fAmountRefunded && $checkout->getModel()->fAmountRefunded > 0} + (partly refund) + {/if} + + + {if $checkout->getBestellung()->cStatus|intval == 1} + OFFEN + {elseif $checkout->getBestellung()->cStatus|intval == 2} + IN BEARBEITUNG + {elseif $checkout->getBestellung()->cStatus|intval == 3} + BEZAHLT + {elseif $checkout->getBestellung()->cStatus|intval == 4} + VERSANDT + {elseif $checkout->getBestellung()->cStatus|intval == 5} + TEILVERSANDT + {elseif $checkout->getBestellung()->cStatus|intval == -1} + STORNO + {else} + n/a + {/if} + {$checkout->getModel()->fAmount|number_format:2:',':''} {$checkout->getModel()->cCurrency}{$checkout->getModel()->cMethod}{"d. M Y H:i"|date:{$checkout->getModel()->dCreatedAt|strtotime}} +
+ +
+ {if $checkout->getModel()->bSynced == false && $checkout->getBestellung()->cAbgeholt === 'Y'} + + {/if} + {if $checkout->remindable()} + + {/if} +
+
+
+ {if $payments|count > 900} +
Hier werden nur die letzten 1000 Ergebnisse angezeigt.
+ {/if} + + +
+
+

Export:

+
+ +
+ + + + + +
+
+ +{/if} + diff --git a/version/202/adminmenu/tpl/paymentmethods.tpl b/version/202/adminmenu/tpl/paymentmethods.tpl new file mode 100644 index 0000000..4fc8ab0 --- /dev/null +++ b/version/202/adminmenu/tpl/paymentmethods.tpl @@ -0,0 +1,138 @@ +

Account Status

+ + + + + + + {if $profile->review} + + + {/if} + +
Mode:{$profile->mode}Status:{$profile->status}Review:{$profile->review->status}
+ +
+ +
+
+ + +
+ + + +
+
+ + +
+
+ + +
+
+ + + reset +
+
+
+ + +{if $allMethods && $allMethods|count} + + + + + + + + + + + + {foreach from=$allMethods item=method} + + + + + + + + {/foreach} + +
BildName / IDInfoPreiseLimits
{$method->mollie->description|utf8_decode} + {if $method->mollie->status === 'activated'} + + {else} + + {/if} + {$method->mollie->description|utf8_decode}
+ {$method->mollie->id} +
+ {if $method->shop && $method->oClass} + + {if intval($method->shop->nWaehrendBestellung) === 1} + Zahlung VOR Bestellabschluss nicht unterstützt! + {/if} + + {*if $method->shop->nWaehrendBestellung} + Zahlung + VOR + Bestellabschluss + {if $method->warning} +
+ + + Gültigkeit ist länger als Session-Laufzeit ({$method->session}). + + {/if} + {else} + Zahlung + NACH + Bestellabschluss + {/if*} +
+ Gültigkeit: {$method->maxExpiryDays} Tage + + {else} + Derzeit nicht unterstützt. + {/if} +
+
    + {foreach from=$method->mollie->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->mollie->minimumAmount}{$method->mollie->minimumAmount->value} {$method->mollie->minimumAmount->currency}{else}n/a{/if} +
+ Max: {if $method->mollie->maximumAmount}{$method->mollie->maximumAmount->value} {$method->mollie->maximumAmount->currency}{else}n/a{/if} +
+{else} +
Es konnten keine Methoden abgerufen werden.
+{/if} \ No newline at end of file diff --git a/version/202/class/API.php b/version/202/class/API.php new file mode 100644 index 0000000..3ed4f27 --- /dev/null +++ b/version/202/class/API.php @@ -0,0 +1,78 @@ +test = $test === null ? self::getMode() : $test; + } + + /** + * @return bool + */ + public static function getMode() + { + require_once PFAD_ROOT . PFAD_ADMIN . PFAD_INCLUDES . 'benutzerverwaltung_inc.php'; + return self::Plugin()->oPluginEinstellungAssoc_arr["testAsAdmin"] === 'Y' && Shop::isAdmin(); + } + + /** + * @return MollieApiClient + * @throws ApiException + * @throws IncompatiblePlatform + */ + public function Client() + { + if (!$this->client) { + $this->client = new MollieApiClient(new Client([ + RequestOptions::VERIFY => CaBundle::getBundledCaBundlePath(), + RequestOptions::TIMEOUT => 60 + ])); + $this->client->setApiKey($this->isTest() ? self::Plugin()->oPluginEinstellungAssoc_arr['test_api_key'] : self::Plugin()->oPluginEinstellungAssoc_arr['api_key']) + ->addVersionString('JTL-Shop/' . JTL_VERSION . JTL_MINOR_VERSION) + ->addVersionString('ws_mollie/' . self::Plugin()->nVersion); + } + return $this->client; + } + + /** + * @return bool + */ + public function isTest() + { + return $this->test; + } + + +} \ No newline at end of file diff --git a/version/202/class/Checkout/AbstractCheckout.php b/version/202/class/Checkout/AbstractCheckout.php new file mode 100644 index 0000000..73ca98e --- /dev/null +++ b/version/202/class/Checkout/AbstractCheckout.php @@ -0,0 +1,621 @@ + ['lang' => 'de', 'country' => ['DE', 'AT', 'CH']], + 'fre' => ['lang' => 'fr', 'country' => ['BE', 'FR']], + 'dut' => ['lang' => 'nl', 'country' => ['BE', 'NL']], + 'spa' => ['lang' => 'es', 'country' => ['ES']], + 'ita' => ['lang' => 'it', 'country' => ['IT']], + 'pol' => ['lang' => 'pl', 'country' => ['PL']], + 'hun' => ['lang' => 'hu', 'country' => ['HU']], + 'por' => ['lang' => 'pt', 'country' => ['PT']], + 'nor' => ['lang' => 'nb', 'country' => ['NO']], + 'swe' => ['lang' => 'sv', 'country' => ['SE']], + 'fin' => ['lang' => 'fi', 'country' => ['FI']], + 'dan' => ['lang' => 'da', 'country' => ['DK']], + 'ice' => ['lang' => 'is', 'country' => ['IS']], + 'eng' => ['lang' => 'en', 'country' => ['GB', 'US']], + ]; + /** + * @var \Mollie\Api\Resources\Customer|null + */ + protected $customer; + + /** + * @var string + */ + private $hash; + /** + * @var API + */ + private $api; + /** + * @var JTLMollie + */ + private $paymentMethod; + /** + * @var Bestellung + */ + private $oBestellung; + /** + * @var Payment + */ + private $model; + + /** + * AbstractCheckout constructor. + * @param $oBestellung + * @param null $api + */ + public function __construct(Bestellung $oBestellung, $api = null) + { + $this->api = $api; + $this->oBestellung = $oBestellung; + } + + /** + * @param int $kBestellung + * @param bool $checkZA + * @return bool + */ + public static function isMollie($kBestellung, $checkZA = false) + { + if ($checkZA) { + $res = Shop::DB()->executeQueryPrepared('SELECT * FROM tzahlungsart WHERE cModulId LIKE :cModulId AND kZahlungsart = :kZahlungsart', [ + ':kZahlungsart' => $kBestellung, + ':cModulId' => 'kPlugin_' . self::Plugin()->kPlugin . '_%' + ], 1); + return $res ? true : false; + } + + return ($res = Shop::DB()->executeQueryPrepared('SELECT kId FROM xplugin_ws_mollie_payments WHERE kBestellung = :kBestellung;', [ + ':kBestellung' => $kBestellung, + ], 1)) && $res->kId; + } + + /** + * @param $kBestellung + * @return OrderCheckout|PaymentCheckout + * * @throws RuntimeException + */ + public static function fromBestellung($kBestellung) + { + if ($model = Payment::fromID($kBestellung, 'kBestellung')) { + return self::fromModel($model); + } + throw new RuntimeException(sprintf('Error loading Order for Bestellung: %s', $kBestellung)); + } + + /** + * @param $model + * @return OrderCheckout|PaymentCheckout + * @throws RuntimeException + */ + public static function fromModel($model, $bFill = true) + { + if (!$model) { + throw new RuntimeException(sprintf('Error loading Order for Model: %s', print_r($model, 1))); + } + + $oBestellung = new Bestellung($model->kBestellung, $bFill); + if (!$oBestellung->kBestellung) { + throw new RuntimeException(sprintf('Error loading Bestellung: %s', $model->kBestellung)); + } + + if (strpos($model->kID, 'tr_') !== false) { + $self = new PaymentCheckout($oBestellung); + } else { + $self = new OrderCheckout($oBestellung); + } + + $self->setModel($model); + return $self; + } + + public static function sendReminders() + { + $reminder = (int)self::Plugin()->oPluginEinstellungAssoc_arr['reminder']; + + if (!$reminder) { + return; + } + + $sql = "SELECT p.kId FROM xplugin_ws_mollie_payments p JOIN tbestellung b ON b.kBestellung = p.kBestellung " + . "WHERE (p.dReminder IS NULL OR p.dReminder = '0000-00-00 00:00:00') " + . "AND p.dCreatedAt < NOW() - INTERVAL :d HOUR AND p.dCreatedAt > NOW() - INTERVAL 7 DAY " + . "AND p.cStatus IN ('created','open', 'expired', 'failed', 'canceled') AND NOT b.cStatus = '-1'"; + + $remindables = Shop::DB()->executeQueryPrepared($sql, [ + ':d' => $reminder + ], 2); + foreach ($remindables as $remindable) { + try { + self::sendReminder($remindable->kId); + } catch (Exception $e) { + Jtllog::writeLog("AbstractCheckout::sendReminders: " . $e->getMessage()); + } + } + } + + public static function sendReminder($kID) + { + + $checkout = self::fromID($kID); + $return = true; + try { + $repayURL = Shop::getURL() . '/?m_pay=' . md5($checkout->getModel()->kID . '-' . $checkout->getBestellung()->kBestellung); + + $data = new stdClass(); + $data->tkunde = new Kunde($checkout->getBestellung()->oKunde->kKunde); + if ($data->tkunde->kKunde) { + + $data->Bestellung = $checkout->getBestellung(); + $data->PayURL = $repayURL; + $data->Amount = gibPreisStringLocalized($checkout->getModel()->fAmount, $checkout->getBestellung()->Waehrung); //Preise::getLocalizedPriceString($order->getAmount(), Currency::fromISO($order->getCurrency()), false); + + require_once PFAD_ROOT . PFAD_INCLUDES . 'mailTools.php'; + + $mail = new stdClass(); + $mail->toEmail = $data->tkunde->cMail; + $mail->toName = trim((isset($data->tKunde->cVorname) + ? $data->tKunde->cVorname + : '') . ' ' . ( + isset($data->tKunde->cNachname) + ? $data->tKunde->cNachname + : '' + )) ?: $mail->toEmail; + $data->mail = $mail; + if (!($sentMail = sendeMail('kPlugin_' . self::Plugin()->kPlugin . '_zahlungserinnerung', $data))) { + $checkout->Log(sprintf("Zahlungserinnerung konnte nicht versand werden: %s\n%s", isset($sentMail->cFehler) ?: print_r($sentMail, 1), print_r($data, 1)), LOGLEVEL_ERROR); + $return = false; + } else { + $checkout->Log(sprintf("Zahlungserinnerung für %s verschickt.", $checkout->getBestellung()->cBestellNr)); + } + } else { + $checkout->Log("Kunde '{$checkout->getBestellung()->oKunde->kKunde}' nicht gefunden.", LOGLEVEL_ERROR); + } + } catch (Exception $e) { + $checkout->Log(sprintf("AbstractCheckout::sendReminder: Zahlungserinnerung für %s fehlgeschlagen: %s", $checkout->getBestellung()->cBestellNr, $e->getMessage())); + $return = false; + } + $checkout->getModel()->dReminder = date('Y-m-d H:i:s'); + $checkout->getModel()->save(); + return $return; + } + + /** + * @param $id + * @return OrderCheckout|PaymentCheckout + * @throws RuntimeException + */ + public static function fromID($id) + { + if ($model = Payment::fromID($id)) { + return static::fromModel($model); + } + throw new RuntimeException(sprintf('Error loading Order: %s', $id)); + } + + /** + * @param AbstractCheckout $checkout + * @return \Mollie\Api\Resources\BaseResource|\Mollie\Api\Resources\Refund + * @throws ApiException + */ + public static function refund(AbstractCheckout $checkout) + { + if ($checkout->getMollie()->resource === 'order') { + /** @var Order $order */ + $order = $checkout->getMollie(); + if (in_array($order->status, [OrderStatus::STATUS_CANCELED, OrderStatus::STATUS_EXPIRED, OrderStatus::STATUS_CREATED], true)) { + throw new RuntimeException('Bestellung kann derzeit nicht zurückerstattet werden.'); + } + $refund = $order->refundAll(); + $checkout->Log(sprintf('Bestellung wurde manuell zurückerstattet: %s', $refund->id)); + return $refund; + } + if ($checkout->getMollie()->resource === 'payment') { + /** @var \Mollie\Api\Resources\Payment $payment */ + $payment = $checkout->getMollie(); + if (in_array($payment->status, [PaymentStatus::STATUS_CANCELED, PaymentStatus::STATUS_EXPIRED, PaymentStatus::STATUS_OPEN], true)) { + throw new RuntimeException('Zahlung kann derzeit nicht zurückerstattet werden.'); + } + $refund = $checkout->API()->Client()->payments->refund($checkout->getMollie(), ['amount' => $checkout->getMollie()->amount]); + $checkout->Log(sprintf('Zahlung wurde manuell zurückerstattet: %s', $refund->id)); + return $refund; + } + throw new RuntimeException(sprintf('Unbekannte Resource: %s', $checkout->getMollie()->resource)); + } + + /** + * @param false $force + * @return Order|\Mollie\Api\Resources\Payment|null + */ + abstract public function getMollie($force = false); + + public function Log($msg, $level = LOGLEVEL_NOTICE) + { + $data = ''; + if ($this->getBestellung()) { + $data .= '#' . $this->getBestellung()->kBestellung; + } + if ($this->getMollie()) { + $data .= '$' . $this->getMollie()->id; + } + ZahlungsLog::add($this->PaymentMethod()->moduleID, "[" . microtime(true) . " - " . $_SERVER['PHP_SELF'] . "] " . $msg, $data, $level); + return $this; + } + + /** + * @return Bestellung + */ + public function getBestellung() + { + if (!$this->oBestellung && $this->getModel()->kBestellung) { + $this->oBestellung = new Bestellung($this->getModel()->kBestellung, true); + } + return $this->oBestellung; + } + + /** + * @return Payment + */ + public function getModel() + { + if (!$this->model) { + $this->model = Payment::fromID($this->oBestellung->kBestellung, 'kBestellung'); + } + return $this->model; + } + + /** + * @param $model + * @return $this + */ + protected function setModel($model) + { + if (!$this->model) { + $this->model = $model; + } else { + throw new RuntimeException('Model already set.'); + } + return $this; + } + + /** + * @return JTLMollie + */ + public function PaymentMethod() + { + if (!$this->paymentMethod) { + if ($this->getBestellung()->Zahlungsart && strpos($this->getBestellung()->Zahlungsart->cModulId, "kPlugin_{$this::Plugin()->kPlugin}_") !== false) { + $this->paymentMethod = PaymentMethod::create($this->getBestellung()->Zahlungsart->cModulId); + } else { + $this->paymentMethod = PaymentMethod::create("kPlugin_{$this::Plugin()->kPlugin}_mollie"); + } + } + /** @noinspection PhpIncompatibleReturnTypeInspection */ + return $this->paymentMethod; + } + + /** + * @return API + */ + public function API() + { + if (!$this->api) { + if ($this->getModel()->kID) { + $this->api = new API($this->getModel()->cMode === 'test'); + } else { + $this->api = new API(API::getMode()); + } + } + return $this->api; + } + + /** + * @param $checkout + * @return Order|\Mollie\Api\Resources\Payment + * @throws ApiException + */ + public static function cancel($checkout) + { + if ($checkout instanceof OrderCheckout) { + return OrderCheckout::cancel($checkout); + } + if ($checkout instanceof PaymentCheckout) { + return PaymentCheckout::cancel($checkout); + } + throw new RuntimeException('AbstractCheckout::cancel: Invalid Checkout!'); + } + + /** + * @return array|bool|int|object|null + */ + public function getLogs() + { + return 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' => '%#' . ($this->getBestellung()->kBestellung ?: '##') . '%', + ':cBestellNr' => '%§' . ($this->getBestellung()->cBestellNr ?: '§§') . '%', + ':MollieID' => '%$' . ($this->getMollie()->id ?: '$$') . '%', + ], 2); + } + + /** + * @return bool + */ + public function remindable() + { + return (int)$this->getBestellung()->cStatus !== BESTELLUNG_STATUS_STORNO && !in_array($this->getModel()->cStatus, [PaymentStatus::STATUS_PAID, PaymentStatus::STATUS_AUTHORIZED, PaymentStatus::STATUS_PENDING, OrderStatus::STATUS_COMPLETED, OrderStatus::STATUS_SHIPPING], true); + } + + /** + * @return string + */ + public function LogData() + { + + $data = ''; + if ($this->getBestellung()->kBestellung) { + $data .= '#' . $this->getBestellung()->kBestellung; + } + if ($this->getMollie()) { + $data .= '$' . $this->getMollie()->id; + } + + return $data; + } + + /** + * @return \Mollie\Api\Resources\Customer|null + * @todo: Kunde wieder löschbar machen ?! + */ + public function getCustomer($createOrUpdate = false) + { + if (!$this->customer) { + $customerModel = Customer::fromID($this->getBestellung()->oKunde->kKunde, 'kKunde'); + if ($customerModel->customerId) { + try { + $this->customer = $this->API()->Client()->customers->get($customerModel->customerId); + } catch (ApiException $e) { + $this->Log(sprintf("Fehler beim laden des Mollie Customers %s (kKunde: %d): %s", $customerModel->customerId, $customerModel->kKunde, $e->getMessage()), LOGLEVEL_ERROR); + } + } + + if ($createOrUpdate) { + $oKunde = $this->getBestellung()->oKunde; + + $customer = [ + 'name' => trim($oKunde->cVorname . ' ' . $oKunde->cNachname), + 'email' => $oKunde->cMail, + 'locale' => self::getLocale(Session::getInstance()->Language()->getIso(), $oKunde->cLand), + 'metadata' => (object)[ + 'kKunde' => $oKunde->kKunde, + 'kKundengruppe' => $oKunde->kKundengruppe, + 'cKundenNr' => $oKunde->cKundenNr, + ], + ]; + + if ($this->customer) { // UPDATE + + $this->customer->name = $customer['name']; + $this->customer->email = $customer['email']; + $this->customer->locale = $customer['locale']; + $this->customer->metadata = $customer['metadata']; + + try { + $this->customer->update(); + } catch (Exception $e) { + $this->Log(sprintf("Fehler beim aktualisieren des Mollie Customers %s: %s\n%s", $this->customer->id, $e->getMessage(), print_r($customer, 1)), LOGLEVEL_ERROR); + } + + + } else { // create + + try { + $this->customer = $this->API()->Client()->customers->create($customer); + $customerModel->kKunde = $oKunde->kKunde; + $customerModel->customerId = $this->customer->id; + $customerModel->save(); + $this->Log(sprintf("Customer '%s' für Kunde %s (%d) bei Mollie angelegt.", $this->customer->id, $this->customer->name, $this->getBestellung()->kKunde)); + } catch (Exception $e) { + $this->Log(sprintf("Fehler beim anlegen eines Mollie Customers: %s\n%s", $e->getMessage(), print_r($customer, 1)), LOGLEVEL_ERROR); + } + } + } + } + return $this->customer; + } + + public static function getLocale($cISOSprache = null, $country = null) + { + + if ($cISOSprache === null) { + $cISOSprache = gibStandardsprache()->cISO; + } + if (array_key_exists($cISOSprache, self::$localeLangs)) { + $locale = self::$localeLangs[$cISOSprache]['lang']; + if ($country && is_array(self::$localeLangs[$cISOSprache]['country']) && in_array($country, self::$localeLangs[$cISOSprache]['country'], true)) { + $locale .= '_' . strtoupper($country); + } else { + $locale .= '_' . self::$localeLangs[$cISOSprache]['country'][0]; + } + return $locale; + } + + return self::Plugin()->oPluginEinstellungAssoc_arr['fallbackLocale']; + } + + abstract public function cancelOrRefund($force = false); + + /** + * @param array $paymentOptions + * @return Payment|Order + */ + abstract public function create(array $paymentOptions = []); + + /** + * @param null $hash + */ + public function handleNotification($hash = null) + { + if (!$this->getHash()) { + $this->getModel()->cHash = $hash; + } + + $this->updateModel()->saveModel(); + if (!$this->getBestellung()->dBezahltDatum || $this->getBestellung()->dBezahltDatum === '0000-00-00') { + if ($incoming = $this->getIncomingPayment()) { + $this->PaymentMethod()->addIncomingPayment($this->getBestellung(), $incoming); + + $this->PaymentMethod()->setOrderStatusToPaid($this->getBestellung()); + static::makeFetchable($this->getBestellung(), $this->getModel()); + $this->PaymentMethod()->deletePaymentHash($this->getHash()); + $this->Log(sprintf("Checkout::handleNotification: Bestellung '%s' als bezahlt markiert: %.2f %s", $this->getBestellung()->cBestellNr, (float)$incoming->fBetrag, $incoming->cISO)); + + $oZahlungsart = Shop::DB()->selectSingleRow('tzahlungsart', 'cModulId', $this->PaymentMethod()->moduleID); + if ($oZahlungsart && (int)$oZahlungsart->nMailSenden === 1) { + require_once PFAD_ROOT . 'includes/mailTools.php'; + $this->PaymentMethod()->sendConfirmationMail($this->getBestellung()); + } + if (!$this->completlyPaid()) { + $this->Log(sprintf("Checkout::handleNotification: Bestellung '%s': nicht komplett bezahlt: %.2f %s", $this->getBestellung()->cBestellNr, (float)$incoming->fBetrag, $incoming->cISO), LOGLEVEL_ERROR); + } + } + } + } + + /** + * @return string + */ + public function getHash() + { + if ($this->getModel()->cHash) { + return $this->getModel()->cHash; + } + if (!$this->hash) { + $this->hash = $this->PaymentMethod()->generateHash($this->oBestellung); + } + return $this->hash; + } + + /** + * @return bool + */ + public function saveModel() + { + return $this->getModel()->save(); + } + + /** + * @return $this + */ + public function updateModel() + { + + if ($this->getMollie()) { + $this->getModel()->kID = $this->getMollie()->id; + $this->getModel()->cLocale = $this->getMollie()->locale; + $this->getModel()->fAmount = (float)$this->getMollie()->amount->value; + $this->getModel()->cMethod = $this->getMollie()->method; + $this->getModel()->cCurrency = $this->getMollie()->amount->currency; + $this->getModel()->cStatus = $this->getMollie()->status; + if ($this->getMollie()->amountRefunded) { + $this->getModel()->fAmountRefunded = $this->getMollie()->amountRefunded->value; + } + if ($this->getMollie()->amountCaptured) { + $this->getModel()->fAmountCaptured = $this->getMollie()->amountCaptured->value; + } + $this->getModel()->cMode = $this->getMollie()->mode ?: null; + $this->getModel()->cRedirectURL = $this->getMollie()->redirectUrl; + $this->getModel()->cWebhookURL = $this->getMollie()->webhookUrl; + $this->getModel()->cCheckoutURL = $this->getMollie()->getCheckoutUrl(); + } + + $this->getModel()->kBestellung = $this->getBestellung()->kBestellung; + $this->getModel()->cOrderNumber = $this->getBestellung()->cBestellNr; + $this->getModel()->cHash = $this->getHash(); + + $this->getModel()->bSynced = $this->getModel()->bSynced !== null ? $this->getModel()->bSynced : Helper::getSetting('onlyPaid') !== 'Y'; + return $this; + } + + /** + * @return stdClass + */ + abstract public function getIncomingPayment(); + + /** + * @param Bestellung $oBestellung + * @param Payment $model + * @return bool + */ + public static function makeFetchable(Bestellung $oBestellung, Payment $model) + { + // TODO: force ? + if ($oBestellung->cAbgeholt === 'Y' && !$model->bSynced) { + Shop::DB()->update('tbestellung', 'kBestellung', $oBestellung->kBestellung, (object)['cAbgeholt' => 'N']); + } + $model->bSynced = true; + try { + return $model->save(); + } catch (Exception $e) { + Jtllog::writeLog(sprintf("Fehler beim speichern des Models: %s / Bestellung: %s", $model->kID, $oBestellung->cBestellNr)); + } + return false; + } + + /** + * @return bool + */ + public function completlyPaid() + { + + if ($row = Shop::DB()->executeQueryPrepared("SELECT SUM(fBetrag) as fBetragSumme FROM tzahlungseingang WHERE kBestellung = :kBestellung", [ + ':kBestellung' => $this->getBestellung()->kBestellung + ], 1)) { + return $row->fBetragSumme >= round($this->getBestellung()->fGesamtsumme * (float)$this->getBestellung()->fWaehrungsFaktor, 2); + } + return false; + + } + + /** + * @return string + */ + public function getRepayURL() + { + return Shop::getURL(true) . '/?m_pay=' . md5($this->getModel()->kID . '-' . $this->getBestellung()->kBestellung); + } + +} \ No newline at end of file diff --git a/version/202/class/Checkout/AbstractResource.php b/version/202/class/Checkout/AbstractResource.php new file mode 100644 index 0000000..7ca9813 --- /dev/null +++ b/version/202/class/Checkout/AbstractResource.php @@ -0,0 +1,18 @@ +title = trim(($address->cAnrede === 'm' ? Shop::Lang()->get('mr') : Shop::Lang()->get('mrs')) . ' ' . $address->cTitel) ?: null; + $resource->givenName = $address->cVorname; + $resource->familyName = $address->cNachname; + $resource->email = $address->cMail ?: null; + + if ($organizationName = trim($address->cFirma)) { + $resource->organizationName = $organizationName; + } + + // Validity-Check + // TODO: Phone, with E.164 check + // TODO: Is Email-Format Check needed? + if (!$resource->givenName || !$resource->familyName || !$resource->email) { + throw ResourceValidityException::trigger(ResourceValidityException::ERROR_REQUIRED, ['givenName', 'familyName', 'email'], $resource); + } + return $resource; + } + +} \ No newline at end of file diff --git a/version/202/class/Checkout/Order/OrderLine.php b/version/202/class/Checkout/Order/OrderLine.php new file mode 100644 index 0000000..b68ccc9 --- /dev/null +++ b/version/202/class/Checkout/Order/OrderLine.php @@ -0,0 +1,223 @@ +totalAmount->value; + } + if (abs($sum - (float)$amount->value) > 0) { + $diff = (round((float)$amount->value - $sum, 2)); + if ($diff !== 0.0) { + $line = new self(); + $line->type = $diff > 0 ? OrderLineType::TYPE_SURCHARGE : OrderLineType::TYPE_DISCOUNT; + // TODO: Translation needed? + $line->name = 'Rundungsausgleich'; + $line->quantity = 1; + $line->unitPrice = Amount::factory($diff, $currency); + $line->totalAmount = Amount::factory($diff, $currency); + $line->vatRate = "0.00"; + $line->vatAmount = Amount::factory(0, $currency); + return $line; + } + } + return null; + } + + /** + * @param Bestellung $oBestellung + * @return OrderLine + */ + public static function getCredit(Bestellung $oBestellung) + { + $line = new self(); + $line->type = OrderLineType::TYPE_STORE_CREDIT; + $line->name = 'Guthaben'; + $line->quantity = 1; + // TODO: check currency of Guthaben + $line->unitPrice = Amount::factory($oBestellung->fGuthaben, $oBestellung->Waehrung->cISO); + $line->totalAmount = $line->unitPrice; + $line->vatRate = "0.00"; + $line->vatAmount = Amount::factory(0, $oBestellung->Waehrung->cISO); + + return $line; + } + + /** + * @param stdClass|WarenkorbPos $oPosition + * @param null $currency + * @return OrderLine + */ + public static function factory($oPosition, $currency = null) + { + if (!$oPosition) { + throw new RuntimeException('$oPosition invalid:', print_r($oPosition)); + } + + $resource = new static(); + + $resource->fill($oPosition, $currency); + + // Validity Check + if (!$resource->name || !$resource->quantity || !$resource->unitPrice || !$resource->totalAmount + || !$resource->vatRate || !$resource->vatAmount) { + throw ResourceValidityException::trigger(ResourceValidityException::ERROR_REQUIRED, + ['name', 'quantity', 'unitPrice', 'totalAmount', 'vatRate', 'vatAmount'], $resource); + } + + return $resource; + + } + + /** + * @param WarenkorbPos|stdClass $oPosition + * @param null|stdClass $currency + * @return $this + * @todo Setting for Fraction handling needed? + */ + protected function fill($oPosition, $currency = null) + { + + if (!$currency) { + $currency = Amount::FallbackCurrency(); + } + + $isKupon = (int)$oPosition->nPosTyp === (int)C_WARENKORBPOS_TYP_KUPON; + $isFrac = fmod($oPosition->nAnzahl, 1) !== 0.0; + + // Kupon? set vatRate to 0 and adjust netto + $vatRate = $isKupon ? 0 : (float)$oPosition->fMwSt / 100; + $netto = $isKupon ? round($oPosition->fPreis * (1 + $vatRate), 4) : round($oPosition->fPreis, 4); + + // Fraction? transform, as it were 1, and set quantity to 1 + $netto = round(($isFrac ? $netto * (float)$oPosition->nAnzahl : $netto) * $currency->fFaktor, 4); + $this->quantity = $isFrac ? 1 : (int)$oPosition->nAnzahl; + + // Fraction? include quantity and unit in name + $this->name = $isFrac ? sprintf("%s (%.2f %s)", $oPosition->cName, (float)$oPosition->nAnzahl, $oPosition->cEinheit) : $oPosition->cName; + + $this->mapType($oPosition->nPosTyp); + + //$unitPriceNetto = round(($currency->fFaktor * $netto), 4); + + $this->unitPrice = Amount::factory(round($netto * (1 + $vatRate), 2), $currency->cISO, false); + $this->totalAmount = Amount::factory(round($this->quantity * $this->unitPrice->value, 2), $currency->cISO, false); + + $this->vatRate = number_format($vatRate * 100, 2); + $this->vatAmount = Amount::factory(round($this->totalAmount->value - ($this->totalAmount->value / (1 + $vatRate)), 2), $currency->cISO, false); + + $metadata = []; + + // Is Artikel ? + if (isset($oPosition->Artikel)) { + $this->sku = $oPosition->Artikel->cArtNr; + $metadata['kArtikel'] = $oPosition->kArtikel; + if ($oPosition->cUnique !== '') { + $metadata['cUnique'] = $oPosition->cUnique; + } + } + + if (isset($oPosition->WarenkorbPosEigenschaftArr) && is_array($oPosition->WarenkorbPosEigenschaftArr) && count($oPosition->WarenkorbPosEigenschaftArr)) { + $metadata['properties'] = []; + /** @var WarenkorbPosEigenschaft $warenkorbPosEigenschaft */ + foreach ($oPosition->WarenkorbPosEigenschaftArr as $warenkorbPosEigenschaft) { + $metadata['properties'][] = [ + 'kEigenschaft' => $warenkorbPosEigenschaft->kEigenschaft, + 'kEigenschaftWert' => $warenkorbPosEigenschaft->kEigenschaftWert, + 'name' => $warenkorbPosEigenschaft->cEigenschaftName, + 'value' => $warenkorbPosEigenschaft->cEigenschaftWertName, + ]; + if (strlen(json_encode($metadata)) > 1000) { + array_pop($metadata['properties']); + break; + } + } + + } + $this->metadata = $metadata; + + return $this; + + + } + + /** + * @param $nPosTyp + * @return OrderLine + */ + protected function mapType($nPosTyp) + { + switch ($nPosTyp) { + case C_WARENKORBPOS_TYP_ARTIKEL: + case C_WARENKORBPOS_TYP_GRATISGESCHENK: + // TODO: digital / Download Artikel? + $this->type = OrderLineType::TYPE_PHYSICAL; + return $this; + + case C_WARENKORBPOS_TYP_VERSANDPOS: + $this->type = OrderLineType::TYPE_SHIPPING_FEE; + return $this; + + case C_WARENKORBPOS_TYP_VERPACKUNG: + case C_WARENKORBPOS_TYP_VERSANDZUSCHLAG: + case C_WARENKORBPOS_TYP_ZAHLUNGSART: + case C_WARENKORBPOS_TYP_VERSAND_ARTIKELABHAENGIG: + case C_WARENKORBPOS_TYP_NACHNAHMEGEBUEHR: + $this->type = OrderLineType::TYPE_SURCHARGE; + return $this; + + case C_WARENKORBPOS_TYP_GUTSCHEIN: + case C_WARENKORBPOS_TYP_KUPON: + case C_WARENKORBPOS_TYP_NEUKUNDENKUPON: + $this->type = OrderLineType::TYPE_DISCOUNT; + return $this; + + } + + throw new RuntimeException('Unknown PosTyp.', (int)$nPosTyp); + } + +} \ No newline at end of file diff --git a/version/202/class/Checkout/OrderCheckout.php b/version/202/class/Checkout/OrderCheckout.php new file mode 100644 index 0000000..3478c6c --- /dev/null +++ b/version/202/class/Checkout/OrderCheckout.php @@ -0,0 +1,356 @@ +getMollie()->status !== OrderStatus::STATUS_AUTHORIZED && $checkout->getMollie()->status !== OrderStatus::STATUS_SHIPPING) { + throw new RuntimeException('Nur autorisierte Zahlungen können erfasst werden!'); + } + $shipment = $checkout->API()->Client()->shipments->createFor($checkout->getMollie(), ['lines' => []]); + $checkout->Log(sprintf('Bestellung wurde manuell erfasst/versandt: %s', $shipment->id)); + return $shipment->id; + } + + /** + * @param false $force + * @return Order|null + */ + public function getMollie($force = false) + { + if ($force || (!$this->order && $this->getModel()->kID)) { + try { + $this->order = $this->API()->Client()->orders->get($this->getModel()->kID, ['embed' => 'payments,shipments,refunds']); + } catch (Exception $e) { + throw new RuntimeException(sprintf('Mollie-Order \'%s\' konnte nicht geladen werden: %s', $this->getModel()->kID, $e->getMessage())); + } + } + return $this->order; + } + + /** + * @param OrderCheckout $checkout + * @return Order + * @throws ApiException + */ + public static function cancel($checkout) + { + if (!$checkout->getMollie()->isCancelable) { + throw new RuntimeException('Bestellung kann nicht abgebrochen werden.'); + } + $order = $checkout->getMollie()->cancel(); + $checkout->Log('Bestellung wurde manuell abgebrochen.'); + return $order; + } + + /** + * @return array + */ + public function getShipments() + { + $shipments = []; + $lieferschien_arr = Shop::DB()->executeQueryPrepared("SELECT kLieferschein FROM tlieferschein WHERE kInetBestellung = :kBestellung", [ + ':kBestellung' => (int)$this->getBestellung()->kBestellung + ], 2); + + foreach ($lieferschien_arr as $lieferschein) { + $shipments[] = new Shipment($lieferschein->kLieferschein, $this); + } + return $shipments; + } + + /** + * @return string + * @throws ApiException + */ + public function cancelOrRefund($force = false) + { + if (!$this->getMollie()) { + throw new RuntimeException('Mollie-Order konnte nicht geladen werden: ' . $this->getModel()->kID); + } + if ($force || (int)$this->getBestellung()->cStatus === BESTELLUNG_STATUS_STORNO) { + if ($this->getMollie()->isCancelable) { + $res = $this->getMollie()->cancel(); + $result = 'Order cancelled, Status: ' . $res->status; + } else { + $res = $this->getMollie()->refundAll(); + $result = "Order Refund initiiert, Status: " . $res->status; + } + $this->PaymentMethod()->Log("OrderCheckout::cancelOrRefund: " . $result, $this->LogData()); + return $result; + } + throw new RuntimeException('Bestellung ist derzeit nicht storniert, Status: ' . $this->getBestellung()->cStatus); + } + + /** + * @param array $paymentOptions + * @return Order|Payment + */ + public function create(array $paymentOptions = []) + { + if ($this->getModel()->kID) { + try { + $this->order = $this->API()->Client()->orders->get($this->getModel()->kID, ['embed' => 'payments']); + if (in_array($this->order->status, [OrderStatus::STATUS_COMPLETED, OrderStatus::STATUS_PAID, OrderStatus::STATUS_AUTHORIZED, OrderStatus::STATUS_PENDING], true)) { + $this->handleNotification(); + throw new RuntimeException(self::Plugin()->oPluginSprachvariableAssoc_arr['errAlreadyPaid']); + } + if ($this->order->status === OrderStatus::STATUS_CREATED) { + if ($this->order->payments()) { + /** @var Payment $payment */ + foreach ($this->order->payments() as $payment) { + if ($payment->status === PaymentStatus::STATUS_OPEN) { + $this->setPayment($payment); + break; + } + } + } + if (!$this->getPayment()) { + $this->setPayment($this->API()->Client()->orderPayments->createForId($this->getModel()->kID, $paymentOptions)); + } + $this->updateModel()->saveModel(); + return $this->getMollie(true); + } + } catch (RuntimeException $e) { + throw $e; + } catch (Exception $e) { + $this->Log(sprintf("OrderCheckout::create: Letzte Order '%s' konnte nicht geladen werden: %s, versuche neue zu erstellen.", $this->getModel()->kID, $e->getMessage()), LOGLEVEL_ERROR); + } + } + + try { + $req = $this->loadRequest()->jsonSerialize(); + $this->order = $this->API()->Client()->orders->create($req); + $this->Log(sprintf("Order für '%s' wurde erfolgreich angelegt: %s", $this->getBestellung()->cBestellNr, $this->order->id)); + $this->updateModel()->saveModel(); + return $this->order; + } catch (Exception $e) { + $this->Log(sprintf("OrderCheckout::create: Neue Order '%s' konnte nicht erstellt werden: %s.", $this->getBestellung()->cBestellNr, $e->getMessage()), LOGLEVEL_ERROR); + throw new RuntimeException(sprintf("Order für '%s' konnte nicht angelegt werden: %s", $this->getBestellung()->cBestellNr, $e->getMessage())); + } + } + + /** + * @return Payment|null + */ + public function getPayment($search = false) + { + if (!$this->_payment && $search) { + foreach ($this->getMollie()->payments() as $payment) { + if (in_array($payment->status, [ + PaymentStatus::STATUS_AUTHORIZED, + PaymentStatus::STATUS_PAID, + PaymentStatus::STATUS_PENDING, + ], true)) { + $this->_payment = $payment; + break; + } + } + } + return $this->_payment; + } + + /** + * @param $payment + * @return $this + */ + public function setPayment($payment) + { + $this->_payment = $payment; + return $this; + } + + /** + * @return $this|OrderCheckout + */ + public function updateModel() + { + parent::updateModel(); + + if (!$this->getPayment() && $this->getMollie() && $this->getMollie()->payments()) { + /** @var Payment $payment */ + foreach ($this->getMollie()->payments() as $payment) { + if (in_array($payment->status, [PaymentStatus::STATUS_OPEN, PaymentStatus::STATUS_PENDING, PaymentStatus::STATUS_AUTHORIZED, PaymentStatus::STATUS_PAID], true)) { + $this->setPayment($payment); + break; + } + } + } + if ($this->getPayment()) { + $this->getModel()->cTransactionId = $this->getPayment()->id; + } + if ($this->getMollie()) { + $this->getModel()->cCheckoutURL = $this->getMollie()->getCheckoutUrl(); + $this->getModel()->cWebhookURL = $this->getMollie()->webhookUrl; + $this->getModel()->cRedirectURL = $this->getMollie()->redirectUrl; + } + return $this; + } + + /** + * @param array $options + * @return $this|OrderCheckout + */ + public function loadRequest($options = []) + { + + if ($this->getBestellung()->oKunde->nRegistriert + && ($customer = $this->getCustomer( + array_key_exists('mollie_create_customer', $_SESSION['cPost_arr'] ?: []) && $_SESSION['cPost_arr']['mollie_create_customer'] === 'Y') + ) + && isset($customer)) { + $options['customerId'] = $customer->id; + } + + $this->locale = self::getLocale(Session::getInstance()->Language()->getIso(), Session::getInstance()->Customer()->cLand); + $this->amount = Amount::factory($this->getBestellung()->fGesamtsummeKundenwaehrung, $this->getBestellung()->Waehrung->cISO, true); + $this->orderNumber = $this->getBestellung()->cBestellNr; + $this->metadata = [ + 'kBestellung' => $this->getBestellung()->kBestellung, + 'kKunde' => $this->getBestellung()->kKunde, + 'kKundengruppe' => Session::getInstance()->CustomerGroup()->kKundengruppe, + 'cHash' => $this->getHash(), + ]; + + $this->redirectUrl = $this->PaymentMethod()->getReturnURL($this->getBestellung()); + $this->webhookUrl = Shop::getURL(true) . '/?mollie=1'; + + $pm = $this->PaymentMethod(); + $isPayAgain = strpos($_SERVER['PHP_SELF'], 'bestellab_again') !== false; + if ($pm::METHOD !== '' && (self::Plugin()->oPluginEinstellungAssoc_arr['resetMethod'] !== 'Y' || !$isPayAgain)) { + $this->method = $pm::METHOD; + } + + $this->billingAddress = Address::factory($this->getBestellung()->oRechnungsadresse); + if ($this->getBestellung()->Lieferadresse !== null) { + if (!$this->getBestellung()->Lieferadresse->cMail) { + $this->getBestellung()->Lieferadresse->cMail = $this->getBestellung()->oRechnungsadresse->cMail; + } + $this->shippingAddress = Address::factory($this->getBestellung()->Lieferadresse); + } + + if ( + !empty(Session::getInstance()->Customer()->dGeburtstag) + && Session::getInstance()->Customer()->dGeburtstag !== '0000-00-00' + && preg_match('/^\d{4}-\d{2}-\d{2}$/', trim(Session::getInstance()->Customer()->dGeburtstag)) + ) { + $this->consumerDateOfBirth = trim(Session::getInstance()->Customer()->dGeburtstag); + } + + $lines = []; + foreach ($this->getBestellung()->Positionen as $oPosition) { + $lines[] = OrderLine::factory($oPosition, $this->getBestellung()->Waehrung); + } + + if ($this->getBestellung()->GuthabenNutzen && $this->getBestellung()->fGuthaben > 0) { + $lines[] = OrderLine::getCredit($this->getBestellung()); + } + + if ($comp = OrderLine::getRoundingCompensation($lines, $this->amount, $this->getBestellung()->Waehrung->cISO)) { + $lines[] = $comp; + } + $this->lines = $lines; + + if ($dueDays = $this->PaymentMethod()->getExpiryDays()) { + $max = $this->method && strpos($this->method, 'klarna') !== false ? 28 : 100; + $this->expiresAt = date('Y-m-d', strtotime(sprintf("+%d DAYS", min($dueDays, $max)))); + } + + $this->payment = $options; + + return $this; + } + + /** + * @return object|null + */ + public function getIncomingPayment() + { + if (!$this->getMollie()) { + return null; + } + + if (Helper::getSetting('wawiPaymentID') === 'ord') { + $cHinweis = $this->getMollie()->id; + } else { + if (Helper::getSetting('wawiPaymentID') === 'tr') { + $cHinweis = $this->getPayment(true)->id; + } else { + $cHinweis = sprintf("%s / %s", $this->getMollie()->id, $this->getPayment(true)->id); + } + } + + /** @var Payment $payment */ + foreach ($this->getMollie()->payments() as $payment) { + if (in_array($payment->status, + [PaymentStatus::STATUS_AUTHORIZED, PaymentStatus::STATUS_PAID], true)) { + $this->setPayment($payment); + $data = (object)[ + 'fBetrag' => (float)$payment->amount->value, + 'cISO' => $payment->amount->currency, + 'cZahler' => $payment->details->paypalPayerId ?: $payment->customerId, + 'cHinweis' => $payment->details->paypalReference ?: $cHinweis, + ]; + if (isset($payment->details, $payment->details->paypalFee)) { + $data->fZahlungsgebuehr = $payment->details->paypalFee->value; + } + return $data; + } + } + return null; + } +} \ No newline at end of file diff --git a/version/202/class/Checkout/Payment/Address.php b/version/202/class/Checkout/Payment/Address.php new file mode 100644 index 0000000..ea460c1 --- /dev/null +++ b/version/202/class/Checkout/Payment/Address.php @@ -0,0 +1,54 @@ +streetAndNumber = $address->cStrasse . ' ' . $address->cHausnummer; + $resource->postalCode = $address->cPLZ; + $resource->city = $address->cOrt; + $resource->country = $address->cLand; + + if ( + isset($address->cAdressZusatz) + && trim($address->cAdressZusatz) !== '' + ) { + $resource->streetAdditional = trim($address->cAdressZusatz); + } + + // Validity-Check + // TODO: Check for valid Country Code? + // TODO: Check PostalCode requirement Country? + if (!$resource->streetAndNumber || !$resource->city || !$resource->country) { + throw ResourceValidityException::trigger(ResourceValidityException::ERROR_REQUIRED, ['streetAndNumber', 'city', 'country'], $resource); + } + + return $resource; + } + + +} \ No newline at end of file diff --git a/version/202/class/Checkout/Payment/Amount.php b/version/202/class/Checkout/Payment/Amount.php new file mode 100644 index 0000000..21acef9 --- /dev/null +++ b/version/202/class/Checkout/Payment/Amount.php @@ -0,0 +1,72 @@ + true [5 Rappen Rounding]) + * @return Amount + */ + public static function factory($value, $currency = null, $useRounding = false) + { + + if (!$currency) { + $currency = static::FallbackCurrency()->cISO; + } + + $resource = new static(); + + $resource->currency = $currency; + //$resource->value = number_format(round($useRounding ? $resource->round($value * (float)$currency->fFaktor) : $value * (float)$currency->fFaktor, 2), 2, '.', ''); + $resource->value = number_format(round($useRounding ? $resource->round($value) : $value, 2), 2, '.', ''); + + // Validity Check + // TODO: Check ISO Code? + // TODO: Check Value + if (!$resource->currency || !$resource->value) { + throw ResourceValidityException::trigger(ResourceValidityException::ERROR_REQUIRED, ['currency', 'value'], $resource); + } + return $resource; + } + + /** + * @return \stdClass + */ + public static function FallbackCurrency() + { + return isset($_SESSION['Waehrung']) ? $_SESSION['Waehrung'] : Shop::DB()->select('twaehrung', 'cStandard', 'Y'); + } + + /** + * Check if 5 Rappen rounding is necessary + * + * @return float + */ + protected function round($value) + { + + $conf = Shop::getSettings([CONF_KAUFABWICKLUNG]); + if (isset($conf['kaufabwicklung']['bestellabschluss_runden5']) && (int)$conf['kaufabwicklung']['bestellabschluss_runden5'] === 1) { + $value = round($value * 20) / 20; + } + return $value; + } + + +} \ No newline at end of file diff --git a/version/202/class/Checkout/PaymentCheckout.php b/version/202/class/Checkout/PaymentCheckout.php new file mode 100644 index 0000000..6b187d3 --- /dev/null +++ b/version/202/class/Checkout/PaymentCheckout.php @@ -0,0 +1,209 @@ +getMollie()) { + throw new RuntimeException('Mollie-Order konnte nicht geladen werden: ' . $this->getModel()->kID); + } + if ($force || (int)$this->getBestellung()->cStatus === BESTELLUNG_STATUS_STORNO) { + if ($this->getMollie()->isCancelable) { + $res = $this->API()->Client()->payments->cancel($this->getMollie()->id); + $result = 'Payment cancelled, Status: ' . $res->status; + } else { + $res = $this->API()->Client()->payments->refund($this->getMollie(), ['amount' => $this->getMollie()->amount]); + $result = "Payment Refund initiiert, Status: " . $res->status; + } + $this->PaymentMethod()->Log("PaymentCheckout::cancelOrRefund: " . $result, $this->LogData()); + return $result; + } + throw new RuntimeException('Bestellung ist derzeit nicht storniert, Status: ' . $this->getBestellung()->cStatus); + } + + /** + * @param false $force + * @return Payment|null + */ + public function getMollie($force = false) + { + if ($force || (!$this->getPayment() && $this->getModel()->kID)) { + try { + $this->setPayment($this->API()->Client()->payments->get($this->getModel()->kID, ['embed' => 'refunds'])); + } catch (Exception $e) { + throw new RuntimeException('Mollie-Payment konnte nicht geladen werden: ' . $e->getMessage()); + } + } + return $this->getPayment(); + } + + /** + * @return Payment|null + */ + public function getPayment() + { + return $this->_payment; + } + + /** + * @param $payment + * @return $this + */ + public function setPayment($payment) + { + $this->_payment = $payment; + return $this; + } + + /** + * @param array $paymentOptions + * @return \Mollie\Api\Resources\Order|Payment|\ws_mollie\Model\Payment + */ + public function create(array $paymentOptions = []) + { + if ($this->getModel()->kID) { + try { + $this->setPayment($this->API()->Client()->payments->get($this->getModel()->kID)); + if ($this->getPayment()->status === PaymentStatus::STATUS_PAID) { + throw new RuntimeException(self::Plugin()->oPluginSprachvariableAssoc_arr['errAlreadyPaid']); + } + if ($this->getPayment()->status === PaymentStatus::STATUS_OPEN) { + $this->updateModel()->saveModel(); + return $this->getPayment(); + } + } catch (RuntimeException $e) { + //$this->Log(sprintf("PaymentCheckout::create: Letzte Transaktion '%s' konnte nicht geladen werden: %s", $this->getModel()->kID, $e->getMessage()), LOGLEVEL_ERROR); + throw $e; + } catch (Exception $e) { + $this->Log(sprintf("PaymentCheckout::create: Letzte Transaktion '%s' konnte nicht geladen werden: %s, versuche neue zu erstellen.", $this->getModel()->kID, $e->getMessage()), LOGLEVEL_ERROR); + } + } + + try { + $req = $this->loadRequest($paymentOptions)->jsonSerialize(); + $this->setPayment($this->API()->Client()->payments->create($req)); + $this->Log(sprintf("Payment für '%s' wurde erfolgreich angelegt: %s", $this->getBestellung()->cBestellNr, $this->getPayment()->id)); + $this->updateModel()->saveModel(); + return $this->getPayment(); + } catch (Exception $e) { + $this->Log(sprintf("PaymentCheckout::create: Neue Transaktion für '%s' konnte nicht erstellt werden: %s.", $this->getBestellung()->cBestellNr, $e->getMessage()), LOGLEVEL_ERROR); + throw new RuntimeException(sprintf('Mollie-Payment \'%s\' konnte nicht geladen werden: %s', $this->getBestellung()->cBestellNr, $e->getMessage())); + } + } + + + /** + * @param array $options + * @return $this|PaymentCheckout + */ + public function loadRequest($options = []) + { + + if ($this->getBestellung()->oKunde->nRegistriert + && ($customer = $this->getCustomer( + array_key_exists('mollie_create_customer', $_SESSION['cPost_arr'] ?: []) && $_SESSION['cPost_arr']['mollie_create_customer'] === 'Y') + ) + && isset($customer)) { + $options['customerId'] = $customer->id; + } + + $this->amount = Amount::factory($this->getBestellung()->fGesamtsummeKundenwaehrung, $this->getBestellung()->Waehrung->cISO, true); + $this->description = 'Order ' . $this->getBestellung()->cBestellNr; + $this->redirectUrl = $this->PaymentMethod()->getReturnURL($this->getBestellung()); + $this->webhookUrl = Shop::getURL(true) . '/?mollie=1'; + $this->locale = self::getLocale(Session::getInstance()->Language()->getIso(), Session::getInstance()->Customer()->cLand); + $this->metadata = [ + 'kBestellung' => $this->getBestellung()->kBestellung, + 'kKunde' => $this->getBestellung()->kKunde, + 'kKundengruppe' => Session::getInstance()->CustomerGroup()->kKundengruppe, + 'cHash' => $this->getHash(), + ]; + $pm = $this->PaymentMethod(); + $isPayAgain = strpos($_SERVER['PHP_SELF'], 'bestellab_again') !== false; + if ($pm::METHOD !== '' && (self::Plugin()->oPluginEinstellungAssoc_arr['resetMethod'] !== 'Y' || !$isPayAgain)) { + $this->method = $pm::METHOD; + } + foreach ($options as $key => $value) { + $this->$key = $value; + } + + return $this; + } + + /** + * @return object|null + */ + public function getIncomingPayment() + { + if (!$this->getMollie()) { + return null; + } + + if (in_array($this->getMollie()->status, [PaymentStatus::STATUS_AUTHORIZED, PaymentStatus::STATUS_PAID], true)) { + $data = []; + $data['fBetrag'] = (float)$this->getMollie()->amount->value; + $data['cISO'] = $this->getMollie()->amount->currency; + $data['cZahler'] = $this->getMollie()->details->paypalPayerId ?: $this->getMollie()->customerId; + $data['cHinweis'] = $this->getMollie()->details->paypalReference ?: $this->getMollie()->id; + if (isset($this->getMollie()->details, $this->getMollie()->details->paypalFee)) { + $data['fZahlungsgebuehr'] = $this->getMollie()->details->paypalFee->value; + } + return (object)$data; + } + return null; + } + + /** + * @param PaymentCheckout $checkout + * @return Payment + */ + public static function cancel($checkout) + { + if(!$checkout->getMollie()->isCancelable){ + throw new RuntimeException('Zahlung kann nicht abgebrochen werden.'); + } + $payment = $checkout->API()->Client()->payments->cancel($checkout->getMollie()->id); + $checkout->Log('Zahlung wurde manuell abgebrochen.'); + return $payment; + } +} \ No newline at end of file diff --git a/version/202/class/ExclusiveLock.php b/version/202/class/ExclusiveLock.php new file mode 100644 index 0000000..3e481c9 --- /dev/null +++ b/version/202/class/ExclusiveLock.php @@ -0,0 +1,70 @@ +key = $key; + $this->path = rtrim(realpath($path), '/') . '/'; + if (!is_dir($path) || !is_writable($path)) { + throw new RuntimeException("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", 'wb+'); + } + + + public function __destruct() + { + if ($this->own === true) { + $this->unlock(); + } + } + + 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 + } + + 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 + } +} diff --git a/version/202/class/Helper.php b/version/202/class/Helper.php new file mode 100644 index 0000000..5f2a8be --- /dev/null +++ b/version/202/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/202/class/Hook/AbstractHook.php b/version/202/class/Hook/AbstractHook.php new file mode 100644 index 0000000..8dcbbda --- /dev/null +++ b/version/202/class/Hook/AbstractHook.php @@ -0,0 +1,13 @@ +kPlugin)) + && array_key_exists($key, $_SESSION) && !array_key_exists("Zahlungsart", $_SESSION)) { + unset($_SESSION[$key]); + } + + if (!array_key_exists('ws_mollie_applepay_available', $_SESSION)) { + Shop::Smarty()->assign('applePayCheckURL', json_encode(self::Plugin()->cFrontendPfadURLSSL . 'applepay.php')); + pq('body')->append(Shop::Smarty()->fetch(self::Plugin()->cFrontendPfad . 'tpl/applepay.tpl')); + } + + } + + /** + * @return bool + */ + public static function isAvailable() + { + if (array_key_exists('ws_mollie_applepay_available', $_SESSION)) { + return $_SESSION['ws_mollie_applepay_available']; + } + return false; + } + + /** + * @param $status bool + */ + public static function setAvailable($status) + { + $_SESSION['ws_mollie_applepay_available'] = $status; + } + +} \ No newline at end of file diff --git a/version/202/class/Hook/Checkbox.php b/version/202/class/Hook/Checkbox.php new file mode 100644 index 0000000..6df972c --- /dev/null +++ b/version/202/class/Hook/Checkbox.php @@ -0,0 +1,60 @@ +cModulId, 'kPlugin_' . self::Plugin()->kPlugin . '_') === false) { + return; + } + + if (array_key_exists('nAnzeigeOrt', $args_arr) && $args_arr['nAnzeigeOrt'] === CHECKBOX_ORT_BESTELLABSCHLUSS && (int)Session::getInstance()->Customer()->nRegistriert) { + + $mCustomer = Customer::fromID(Session::getInstance()->Customer()->kKunde, 'kKunde'); + + if ($mCustomer->customerId) { + return; + } + + $checkbox = new \CheckBox(); + $checkbox->kLink = 0; + $checkbox->kCheckBox = -1; + $checkbox->kCheckBoxFunktion = 0; + $checkbox->cName = 'MOLLIE SAVE CUSTOMER'; + $checkbox->cKundengruppe = ';1;'; + $checkbox->cAnzeigeOrt = ';2;'; + $checkbox->nAktiv = 1; + $checkbox->nPflicht = 0; + $checkbox->nLogging = 0; + $checkbox->nSort = 999; + $checkbox->dErstellt = date('Y-m-d H:i:s'); + $checkbox->oCheckBoxSprache_arr = []; + + $langs = gibAlleSprachen(); + foreach ($langs as $lang) { + $checkbox->oCheckBoxSprache_arr[$lang->kSprache] = (object)[ + 'cText' => self::Plugin()->oPluginSprachvariableAssoc_arr['checkboxText'], + 'cBeschreibung' => self::Plugin()->oPluginSprachvariableAssoc_arr['checkboxDescr'], + 'kSprache' => $lang->kSprache, + 'kCheckbox' => -1 + ]; + } + + $checkbox->kKundengruppe_arr = [Session::getInstance()->Customer()->kKundengruppe]; + $checkbox->kAnzeigeOrt_arr = [CHECKBOX_ORT_BESTELLABSCHLUSS]; + $checkbox->cID = "mollie_create_customer"; + $checkbox->cLink = ''; + + $args_arr['oCheckBox_arr'][] = $checkbox; + + } + } +} \ No newline at end of file diff --git a/version/202/class/Hook/Queue.php b/version/202/class/Hook/Queue.php new file mode 100644 index 0000000..9dbef9b --- /dev/null +++ b/version/202/class/Hook/Queue.php @@ -0,0 +1,129 @@ +fGesamtsumme > 0 + && self::Plugin()->oPluginEinstellungAssoc_arr['onlyPaid'] === 'Y' + && AbstractCheckout::isMollie((int)$args_arr['oBestellung']->kZahlungsart, true)) { + + $args_arr['oBestellung']->cAbgeholt = 'Y'; + Jtllog::writeLog('Switch cAbgeholt for kBestellung: ' . print_r($args_arr['oBestellung']->kBestellung, 1), JTLLOG_LEVEL_NOTICE); + } + } + + /** + * @param array $args_arr + */ + public static function xmlBestellStatus(array $args_arr) + { + if (AbstractCheckout::isMollie((int)$args_arr['oBestellung']->kBestellung)) { + self::saveToQueue(HOOK_BESTELLUNGEN_XML_BESTELLSTATUS . ':' . (int)$args_arr['oBestellung']->kBestellung, [ + 'kBestellung' => $args_arr['oBestellung']->kBestellung, + 'status' => (int)$args_arr['status'] + ]); + } + } + + /** + * @param $hook + * @param $args_arr + * @param string $type + * @return bool + */ + protected static function saveToQueue($hook, $args_arr, $type = 'hook') + { + $mQueue = new QueueModel(); + $mQueue->cType = $type . ':' . $hook; + $mQueue->cData = serialize($args_arr); + try { + return $mQueue->save(); + } catch (Exception $e) { + Jtllog::writeLog('mollie::saveToQueue: ' . $e->getMessage() . ' - ' . print_r($args_arr, 1)); + return false; + } + } + + /** + * @param array $args_arr + */ + public static function xmlBearbeiteStorno(array $args_arr) + { + if (AbstractCheckout::isMollie((int)$args_arr['oBestellung']->kBestellung)) { + self::saveToQueue(HOOK_BESTELLUNGEN_XML_BEARBEITESTORNO . ':' . $args_arr['oBestellung']->kBestellung, ['kBestellung' => $args_arr['oBestellung']->kBestellung]); + } + } + + /** + * + */ + public static function headPostGet() + { + if (array_key_exists('mollie', $_REQUEST) && (int)$_REQUEST['mollie'] === 1 && array_key_exists('id', $_REQUEST)) { + self::saveToQueue($_REQUEST['id'], $_REQUEST['id'], 'webhook'); + exit(); + } + if (array_key_exists('m_pay', $_REQUEST)) { + try { + $raw = Shop::DB()->executeQueryPrepared('SELECT kID FROM `xplugin_ws_mollie_payments` WHERE dReminder IS NOT NULL AND MD5(CONCAT(kID, "-", kBestellung)) = :md5', [ + ':md5' => $_REQUEST['m_pay'] + ], 1); + + if (!$raw) { + throw new RuntimeException(self::Plugin()->oPluginSprachvariableAssoc_arr['errOrderNotFound']); + } + + if (strpos($raw->cOrderId, 'tr_') === 0) { + $checkout = PaymentCheckout::fromID($raw->kID); + } else { + $checkout = OrderCheckout::fromID($raw->kID); + } + $checkout->getMollie(true); + $checkout->updateModel()->saveModel(); + + if (($checkout->getBestellung()->dBezahltDatum !== null && $checkout->getBestellung()->dBezahltDatum !== '0000-00-00') + || in_array($checkout->getModel()->cStatus, ['completed', 'paid', 'authorized', 'pending'])) { + throw new RuntimeException(self::Plugin()->oPluginSprachvariableAssoc_arr['errAlreadyPaid']); + } + + $options = []; + if (self::Plugin()->oPluginEinstellungAssoc_arr['resetMethod'] !== 'Y') { + $options['method'] = $checkout->getModel()->cMethod; + } + + $mollie = $checkout->create($options); // Order::repayOrder($orderModel->getOrderId(), $options, $api); + $url = $mollie->getCheckoutUrl(); + + header('Location: ' . $url); + exit(); + + } catch (RuntimeException $e) { + // TODO Workaround? + //$alertHelper = Shop::Container()->getAlertService(); + //$alertHelper->addAlert(Alert::TYPE_ERROR, $e->getMessage(), 'mollie_repay', ['dismissable' => true]); + } catch (Exception $e) { + Jtllog::writeLog('mollie:repay:error: ' . $e->getMessage() . "\n" . print_r($_REQUEST, 1)); + } + } + } + +} \ No newline at end of file diff --git a/version/202/class/Model/AbstractModel.php b/version/202/class/Model/AbstractModel.php new file mode 100644 index 0000000..1dc9a47 --- /dev/null +++ b/version/202/class/Model/AbstractModel.php @@ -0,0 +1,92 @@ +data = $data; + if (!$data) { + $this->new = true; + } + } + + public static function fromID($id, $col = 'kID', $failIfNotExists = false) + { + if ($payment = Shop::DB()->executeQueryPrepared("SELECT * FROM " . static::TABLE . " WHERE {$col} = :id", + [':id' => $id], 1)) { + return new static($payment); + } + if ($failIfNotExists) { + throw new RuntimeException(sprintf('Model %s in %s nicht gefunden!', $id, static::TABLE)); + } + return new static(); + } + + /** + * @return mixed|stdClass|null + */ + public function jsonSerialize() + { + return $this->data; + } + + public function __get($name) + { + if (isset($this->data->$name)) { + return $this->data->$name; + } + return null; + } + + public function __set($name, $value) + { + if (!$this->data) { + $this->data = new stdClass(); + } + $this->data->$name = $value; + } + + public function __isset($name) + { + return isset($this->data->$name); + } + + /** + * @return bool + */ + public function save() + { + if (!$this->data) { + throw new RuntimeException('No Data to save!'); + } + + if ($this->new) { + Shop::DB()->insert(static::TABLE, $this->data); + $this->new = false; + return true; + } + Shop::DB()->update(static::TABLE, static::PRIMARY, $this->data->{static::PRIMARY}, $this->data); + return true; + } + +} diff --git a/version/202/class/Model/Customer.php b/version/202/class/Model/Customer.php new file mode 100644 index 0000000..7be9e15 --- /dev/null +++ b/version/202/class/Model/Customer.php @@ -0,0 +1,19 @@ +dCreatedAt) { + $this->dCreatedAt = date('Y-m-d H:i:s'); + } + if($this->new){ + $this->dReminder = self::NULL; + } + return parent::save(); + } +} diff --git a/version/202/class/Model/Queue.php b/version/202/class/Model/Queue.php new file mode 100644 index 0000000..480339a --- /dev/null +++ b/version/202/class/Model/Queue.php @@ -0,0 +1,41 @@ +cResult = $result; + $this->dDone = $date ?: date('Y-m-d H:i:s'); + return $this->save(); + } + + public function save() + { + if (!$this->dCreated) { + $this->dCreated = date('Y-m-d H:i:s'); + } + $this->dModified = date('Y-m-d H:i:s'); + return parent::save(); + } + +} \ No newline at end of file diff --git a/version/202/class/Model/Shipment.php b/version/202/class/Model/Shipment.php new file mode 100644 index 0000000..bece7b4 --- /dev/null +++ b/version/202/class/Model/Shipment.php @@ -0,0 +1,28 @@ +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); + } + } + } + } + + 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[] = AbstractCheckout::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/202/class/Queue.php b/version/202/class/Queue.php new file mode 100644 index 0000000..0607690 --- /dev/null +++ b/version/202/class/Queue.php @@ -0,0 +1,153 @@ +cType))) { + try { + switch ($type) { + case 'webhook': + self::handleWebhook($id, $todo); + break; + + case 'hook': + self::handleHook((int)$id, $todo); + break; + } + + } catch (Exception $e) { + Jtllog::writeLog($e->getMessage() . " ({$type}, {$id})"); + $todo->done("{$e->getMessage()}\n{$e->getFile()}:{$e->getLine()}\n{$e->getTraceAsString()}"); + } + } + } + } + + /** + * @param $limit + * @return Generator|QueueModel[] + */ + private static function getOpen($limit) + { + /** @noinspection SqlResolve */ + $open = Shop::DB()->executeQueryPrepared(sprintf("SELECT * FROM %s WHERE dDone IS NULL ORDER BY dCreated DESC LIMIT 0, :LIMIT;", QueueModel::TABLE), [ + ':LIMIT' => $limit + ], 2); + + foreach ($open as $_raw) { + yield new QueueModel($_raw); + } + } + + protected static function handleWebhook($id, QueueModel $todo) + { + $checkout = AbstractCheckout::fromID($id); + if ($checkout->getBestellung()->kBestellung && $checkout->PaymentMethod()) { + $checkout->handleNotification(); + return $todo->done('Status: ' . $checkout->getMollie()->status); + } + throw new RuntimeException("Bestellung oder Zahlungsart konnte nicht geladen werden: {$id}"); + } + + /** + * @param $hook + * @param QueueModel $todo + * @return bool + * @throws ApiException + * @throws IncompatiblePlatform + */ + protected static function handleHook($hook, QueueModel $todo) + { + $data = unserialize($todo->cData); + if (array_key_exists('kBestellung', $data)) { + switch ($hook) { + case HOOK_BESTELLUNGEN_XML_BESTELLSTATUS: + if ((int)$data['kBestellung']) { + $checkout = AbstractCheckout::fromBestellung($data['kBestellung']); + + $result = ""; + if ((int)$checkout->getBestellung()->cStatus < BESTELLUNG_STATUS_VERSANDT) { + return $todo->done("Bestellung noch nicht versendet: {$checkout->getBestellung()->cStatus}"); + } + + /** @var $method JTLMollie */ + if ((int)$data['status'] + && array_key_exists('status', $data) + && $checkout->PaymentMethod() + && (strpos($checkout->getModel()->kID, 'tr_') === false) + && $checkout->getMollie()) { + /** @var OrderCheckout $checkout */ + $checkout->handleNotification(); + if ($checkout->getMollie()->status === OrderStatus::STATUS_COMPLETED) { + $result = 'Mollie Status already ' . $checkout->getMollie()->status; + } else if ($checkout->getMollie()->isCreated() || $checkout->getMollie()->isPaid() || $checkout->getMollie()->isAuthorized() || $checkout->getMollie()->isShipping() || $checkout->getMollie()->isPending()) { + try { + if ($shipments = Shipment::syncBestellung($checkout)) { + foreach ($shipments as $shipment) { + if (is_string($shipment)) { + $checkout->PaymentMethod()->Log("Shipping-Error: {$shipment}", $checkout->LogData()); + $result .= "Shipping-Error: {$shipment};\n"; + + } else { + $checkout->PaymentMethod()->Log("Order shipped: \n" . print_r($shipment, 1)); + $result .= "Order shipped: {$shipment->id};\n"; + } + } + } else { + $result = 'No Shipments ready!'; + } + } catch (RuntimeException $e) { + $result = $e->getMessage(); + } catch (Exception $e) { + $result = $e->getMessage() . "\n" . $e->getFile() . ":" . $e->getLine() . "\n" . $e->getTraceAsString(); + } + } else { + $result = sprintf('Unerwarteter Mollie Status "%s" für %s', $checkout->getMollie()->status, $checkout->getBestellung()->cBestellNr); + } + } else { + $result = 'Nothing to do.'; + } + } else { + $result = "kBestellung missing"; + } + $checkout->PaymentMethod()->Log("Queue::handleHook: " . $result, $checkout->LogData()); + return $todo->done($result); + + case HOOK_BESTELLUNGEN_XML_BEARBEITESTORNO: + if (self::Plugin()->oPluginEinstellungAssoc_arr['autoRefund'] !== 'Y') { + throw new RuntimeException('Auto-Refund disabled'); + } + + $checkout = AbstractCheckout::fromBestellung((int)$data['kBestellung']); + return $todo->done($checkout->cancelOrRefund()); + } + } + return false; + } + +} \ No newline at end of file diff --git a/version/202/class/Shipment.php b/version/202/class/Shipment.php new file mode 100644 index 0000000..7152dad --- /dev/null +++ b/version/202/class/Shipment.php @@ -0,0 +1,318 @@ +kLieferschein = $kLieferschein; + if ($checkout) { + $this->checkout = $checkout; + } + + if (!$this->getLieferschein() || !$this->getLieferschein()->getLieferschein()) { + throw new RuntimeException('Lieferschein konnte nicht geladen werden'); + } + + if (!count($this->getLieferschein()->oVersand_arr)) { + throw new RuntimeException('Kein Versand gefunden!'); + } + + if (!$this->getCheckout()->getBestellung()->oKunde->nRegistriert) { + $this->isGuest = true; + } + } + + public function getLieferschein() + { + if (!$this->oLieferschein && $this->kLieferschein) { + $this->oLieferschein = new Lieferschein($this->kLieferschein); + } + return $this->oLieferschein; + } + + /** + * @return OrderCheckout + * @throws Exception + */ + public function getCheckout() + { + if (!$this->checkout) { + //TODO evtl. load by lieferschien + throw new Exception('Should not happen, but it did!'); + } + return $this->checkout; + } + + public static function syncBestellung(OrderCheckout $checkout) + { + $shipments = []; + if ($checkout->getBestellung()->kBestellung) { + + $oKunde = $checkout->getBestellung()->oKunde ?: new Kunde($checkout->getBestellung()->kKunde); + + $shippingActive = Helper::getSetting('shippingActive'); + if ($shippingActive === 'N') { + throw new RuntimeException('Shipping deaktiviert'); + } + + if (($shippingActive === 'K') && ((int)$checkout->getBestellung()->cStatus !== BESTELLUNG_STATUS_VERSANDT) && !$oKunde->nRegistriert) { + throw new RuntimeException('Shipping für Gast-Bestellungen und Teilversand deaktiviert'); + } + + /** @var Lieferschein $oLieferschein */ + foreach ($checkout->getBestellung()->oLieferschein_arr as $oLieferschein) { + + try { + + $shipment = new Shipment($oLieferschein->getLieferschein(), $checkout); + + $mode = self::Plugin()->oPluginEinstellungAssoc_arr['shippingMode']; + switch ($mode) { + case 'A': + // ship directly + if (!$shipment->send() && !$shipment->getShipment()) { + throw new RuntimeException('Shipment konnte nicht gespeichert werden.'); + } + $shipments[] = $shipment->getShipment(); + break; + + case 'B': + // only ship if complete shipping + if ($oKunde->nRegistriert || (int)$checkout->getBestellung()->cStatus === BESTELLUNG_STATUS_VERSANDT) { + if (!$shipment->send() && !$shipment->getShipment()) { + throw new RuntimeException('Shipment konnte nicht gespeichert werden.'); + } + $shipments[] = $shipment->getShipment(); + break; + } + throw new RuntimeException('Gastbestellung noch nicht komplett versendet!'); + } + } catch (RuntimeException $e) { + $shipments[] = $e->getMessage(); + } catch (Exception $e) { + $shipments[] = $e->getMessage(); + $checkout->Log("mollie: Shipment::syncBestellung (BestellNr. {$checkout->getBestellung()->cBestellNr}, Lieferschein: {$shipment->getLieferschein()->getLieferscheinNr()}) - " . $e->getMessage(), LOGLEVEL_ERROR); + } + } + } + return $shipments; + } + + /** + * @return mixed + * @throws ApiException + * @throws IncompatiblePlatform + * @throws Exception + */ + public function send() + { + + if ($this->getShipment()) { + throw new RuntimeException('Lieferschien bereits an Mollie übertragen: ' . $this->getShipment()->id); + } + + if ($this->getCheckout()->getMollie(true)->status === OrderStatus::STATUS_COMPLETED) { + throw new RuntimeException('Bestellung bei Mollie bereits abgeschlossen!'); + } + + $api = $this->getCheckout()->API()->Client(); + $this->shipment = $api->shipments->createForId($this->checkout->getModel()->kID, $this->loadRequest()->jsonSerialize()); + + return $this->updateModel()->saveModel(); + + } + + /** + * @param false $force + * @return BaseResource|\Mollie\Api\Resources\Shipment + * @throws ApiException + * @throws IncompatiblePlatform + * @throws Exception + */ + public function getShipment($force = false) + { + if (($force || !$this->shipment) && $this->getModel() && $this->getModel()->cShipmentId) { + $this->shipment = $this->getCheckout()->API()->Client()->shipments->getForId($this->getModel()->cOrderId, $this->getModel()->cShipmentId); + } + return $this->shipment; + } + + /** + * @return ShipmentModel + * @throws Exception + */ + public function getModel() + { + if (!$this->model && $this->kLieferschein) { + $this->model = ShipmentModel::fromID($this->kLieferschein, 'kLieferschein'); + + if (!$this->model->dCreated) { + $this->model->dCreated = date('Y-m-d H:i:s'); + } + $this->updateModel(); + } + return $this->model; + } + + /** + * @return $this + * @throws Exception + */ + public function updateModel() + { + $this->getModel()->kLieferschein = $this->kLieferschein; + if ($this->getCheckout()) { + $this->getModel()->cOrderId = $this->getCheckout()->getModel()->kID; + $this->getModel()->kBestellung = $this->getCheckout()->getModel()->kBestellung; + } + if ($this->getShipment()) { + $this->getModel()->cShipmentId = $this->getShipment()->id; + $this->getModel()->cUrl = $this->getShipment()->getTrackingUrl() ?: ''; + } + if (isset($this->tracking)) { + $this->getModel()->cCarrier = $this->tracking['carrier'] ?: ''; + $this->getModel()->cCode = $this->tracking['code'] ?: ''; + } + return $this; + } + + /** + * @param array $options + * @return $this + * @throws Exception + */ + public function loadRequest($options = []) + { + /** @var Versand $oVersand */ + $oVersand = $this->getLieferschein()->oVersand_arr[0]; + if ($oVersand->getIdentCode() && $oVersand->getLogistik()) { + $tracking = [ + 'carrier' => $oVersand->getLogistik(), + 'code' => $oVersand->getIdentCode(), + ]; + if ($oVersand->getLogistikVarUrl()) { + $tracking['url'] = $oVersand->getLogistikURL(); + } + $this->tracking = $tracking; + } + + // TODO: Wenn alle Lieferschiene in der WAWI erstellt wurden, aber nicht im Shop, kommt status 4. + if ($this->isGuest || (int)$this->getCheckout()->getBestellung()->cStatus === BESTELLUNG_STATUS_VERSANDT) { + $this->lines = []; + } else { + $this->lines = $this->getOrderLines(); + } + return $this; + } + + /** + * @return array + * @throws Exception + */ + protected function getOrderLines() + { + $lines = []; + + if (!count($this->getLieferschein()->oLieferscheinPos_arr)) { + return $lines; + } + + // Bei Stücklisten, sonst gibt es mehrere OrderLines für die selbe ID + $shippedOrderLines = []; + + /** @var Lieferscheinpos $oLieferscheinPos */ + foreach ($this->getLieferschein()->oLieferscheinPos_arr as $oLieferscheinPos) { + + $wkpos = Shop::DB()->executeQueryPrepared('SELECT * FROM twarenkorbpos WHERE kBestellpos = :kBestellpos', [ + ':kBestellpos' => $oLieferscheinPos->getBestellPos() + ], 1); + + /** @var OrderLine $orderLine */ + foreach ($this->getCheckout()->getMollie()->lines as $orderLine) { + + if ($orderLine->sku === $wkpos->cArtNr && !in_array($orderLine->id, $shippedOrderLines, true)) { + + if ($quantity = min($oLieferscheinPos->getAnzahl(), $orderLine->shippableQuantity)) { + $lines[] = [ + 'id' => $orderLine->id, + 'quantity' => $quantity + ]; + } + $shippedOrderLines[] = $orderLine->id; + break; + } + } + } + return $lines; + } + + /** + * @return bool + * @throws Exception + */ + public function saveModel() + { + return $this->getModel()->save(); + } +} \ No newline at end of file diff --git a/version/202/class/Traits/Jsonable.php b/version/202/class/Traits/Jsonable.php new file mode 100644 index 0000000..afc0988 --- /dev/null +++ b/version/202/class/Traits/Jsonable.php @@ -0,0 +1,20 @@ +jsonSerialize(); + } + + public function jsonSerialize() + { + return array_filter(get_object_vars($this), static function ($value) { + return !($value === null || (is_string($value) && $value === '')); + }); + } +} \ No newline at end of file diff --git a/version/202/class/Traits/Plugin.php b/version/202/class/Traits/Plugin.php new file mode 100644 index 0000000..5b2c3a3 --- /dev/null +++ b/version/202/class/Traits/Plugin.php @@ -0,0 +1,25 @@ +requestData; + } + + public function __get($name) + { + if (!$this->requestData) { + $this->loadRequest(); + } + return is_string($this->requestData[$name]) ? utf8_decode($this->requestData[$name]) : $this->requestData[$name]; + } + + public function __set($name, $value) + { + if (!$this->requestData) { + $this->requestData = []; + } + + $this->requestData[$name] = is_string($value) ? utf8_encode($value) : $value; + + return $this; + } + + /** + * @param array $options + * @return $this + */ + public function loadRequest($options = []) + { + return $this; + } + + + public function __serialize() + { + return $this->requestData ?: []; + } + + public function __isset($name) + { + return $this->requestData[$name] !== null; + } + +} \ No newline at end of file diff --git a/version/202/frontend/.htaccess b/version/202/frontend/.htaccess new file mode 100644 index 0000000..df6c074 --- /dev/null +++ b/version/202/frontend/.htaccess @@ -0,0 +1,9 @@ + + + Require all granted + + + Order Allow,Deny + Allow from all + + diff --git a/version/202/frontend/131_globalinclude.php b/version/202/frontend/131_globalinclude.php new file mode 100644 index 0000000..7093ca7 --- /dev/null +++ b/version/202/frontend/131_globalinclude.php @@ -0,0 +1,30 @@ +append( + << + /* MOLLIE CHECKOUT STYLES*/ + #fieldset-payment .form-group > div:hover, #checkout-shipping-payment .form-group > div:hover { + background-color: #eee; + color: black; + } + {$selector} label { + {$border} + } + + {$selector} label::after { + clear: both; + content: ' '; + display: block; + } + + {$selector} label span small { + line-height: 48px; + } + + {$selector} label img { + float: right; + } + +HTML + ); + +} catch (Exception $e) { + Helper::logExc($e); +} diff --git a/version/202/frontend/180_checkbox.php b/version/202/frontend/180_checkbox.php new file mode 100644 index 0000000..95a070f --- /dev/null +++ b/version/202/frontend/180_checkbox.php @@ -0,0 +1,18 @@ +oPluginEinstellungAssoc_arr['useCustomerAPI'] === 'C') { + \ws_mollie\Hook\Checkbox::execute($args_arr); + } + +} catch (Exception $e) { + Helper::logExc($e); +} \ No newline at end of file diff --git a/version/202/frontend/181_sync.php b/version/202/frontend/181_sync.php new file mode 100644 index 0000000..22022a9 --- /dev/null +++ b/version/202/frontend/181_sync.php @@ -0,0 +1,14 @@ +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 Rmns)TMnX}%M${5 literal 0 HcmV?d00001 diff --git a/version/202/frontend/img/trust_fre.png b/version/202/frontend/img/trust_fre.png new file mode 100644 index 0000000000000000000000000000000000000000..ed1a2f6f03c56f6748aac8af0352de7fc0afd3a4 GIT binary patch literal 17319 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 Mu#8ZJpsxS_1AJc%;s5{u literal 0 HcmV?d00001 diff --git a/version/202/frontend/img/trust_ger.png b/version/202/frontend/img/trust_ger.png new file mode 100644 index 0000000000000000000000000000000000000000..e42821b06709e8f4371c66cfb5759d00df0e1afd GIT binary patch literal 15352 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 + diff --git a/version/202/paymentmethod/JTLMollie.php b/version/202/paymentmethod/JTLMollie.php new file mode 100644 index 0000000..1494095 --- /dev/null +++ b/version/202/paymentmethod/JTLMollie.php @@ -0,0 +1,264 @@ +cModulId = "kPlugin_" . self::Plugin()->kPlugin . "_mollie" . $moduleID; + } + + /** + * @param Bestellung $order + * @return PaymentMethod + */ + public function setOrderStatusToPaid($order) + { + // If paid already, do nothing + if ((int)$order->cStatus >= BESTELLUNG_STATUS_BEZAHLT) { + return $this; + } + return parent::setOrderStatusToPaid($order); + } + + /** + * Prepares everything so that the Customer can start the Payment Process. + * Tells Template Engine. + * + * @param Bestellung $order + * @return void + */ + public function preparePaymentProcess($order) + { + + parent::preparePaymentProcess($order); + + try { + + if ($this->duringCheckout) { + $this->Log(sprintf("Zahlung vor Bestellabschluss nicht unterstützt (%s)!", $order->cBestellNr), sprintf("#%s", $order->kBestellung), LOGLEVEL_ERROR); + return; + } + + $payable = (float)$order->fGesamtsumme > 0; + if (!$payable) { + $this->Log(sprintf("Bestellung '%s': Gesamtsumme %.2f, keine Zahlung notwendig!", $order->cBestellNr, $order->fGesamtsumme), sprintf("#%s", $order->kBestellung)); + return; + } + + $paymentOptions = []; + + $api = array_key_exists($this->moduleID . '_api', self::Plugin()->oPluginEinstellungAssoc_arr) ? self::Plugin()->oPluginEinstellungAssoc_arr[$this->moduleID . '_api'] : 'order'; + + $paymentOptions = array_merge($paymentOptions, $this->getPaymentOptions($order, $api)); + + if ($api === 'payment') { + $checkout = new PaymentCheckout($order); + $payment = $checkout->create($paymentOptions); + $url = $payment->getCheckoutUrl(); + } else { + $checkout = new OrderCheckout($order); + $mOrder = $checkout->create($paymentOptions); + $url = $mOrder->getCheckoutUrl(); + } + + ifndef('MOLLIE_REDIRECT_DELAY', 3); + $checkoutMode = self::Plugin()->oPluginEinstellungAssoc_arr['checkoutMode']; + Shop::Smarty()->assign('redirect', $url) + ->assign('checkoutMode', $checkoutMode); + if ($checkoutMode === 'Y' && !headers_sent()) { + header('Location: ' . $url); + } + } catch (Exception $e) { + $this->Log('mollie::preparePaymentProcess: ' . $e->getMessage() . ' - ' . print_r(['cBestellNr' => $order->cBestellNr], 1), '#' . $order->kBestellung, LOGLEVEL_ERROR); + Shop::Smarty()->assign('oMollieException', $e) + ->assign('tryAgain', Shop::getURL() . '/bestellab_again.php?kBestellung=' . $order->kBestellung); + } + } + + public function Log($msg, $data = null, $level = LOGLEVEL_NOTICE) + { + ZahlungsLog::add($this->moduleID, "[" . microtime(true) . " - " . $_SERVER['PHP_SELF'] . "] " . $msg, $data, $level); + return $this; + } + + public function getPaymentOptions(Bestellung $order, $apiType) + { + return []; + } + + /** + * @param Bestellung $order + * @param string $hash + * @param array $args + */ + public function handleNotification($order, $hash, $args) + { + parent::handleNotification($order, $hash, $args); + try { + $orderId = $args['id']; + $checkout = null; + if (strpos($orderId, 'tr_') === 0) { + $checkout = new PaymentCheckout($order); + } else { + $checkout = new OrderCheckout($order); + } + $checkout->handleNotification($hash); + + } catch (Exception $e) { + $checkout->Log(sprintf("mollie::handleNotification: Fehler bei Bestellung '%s': %s\n%s", $order->cBestellNr, $e->getMessage(), print_r($args, 1)), LOGLEVEL_ERROR); + } + } + + /** + * @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 (API::getMode()) { + $selectable = trim(self::Plugin()->oPluginEinstellungAssoc_arr['test_api_key']) !== ''; + } else { + $selectable = trim(self::Plugin()->oPluginEinstellungAssoc_arr['api_key']) !== ''; + if (!$selectable) { + Jtllog::writeLog("Live API Key missing!"); + } + } + if ($selectable) { + try { + $locale = AbstractCheckout::getLocale(Session::getInstance()->Language()->getIso(), Session::getInstance()->Customer()->cLand); + $amount = Session::getInstance()->Basket()->gibGesamtsummeWarenExt([ + C_WARENKORBPOS_TYP_ARTIKEL, + C_WARENKORBPOS_TYP_KUPON, + C_WARENKORBPOS_TYP_GUTSCHEIN, + C_WARENKORBPOS_TYP_NEUKUNDENKUPON, + ], true) * Session::getInstance()->Currency()->fFaktor; + if ($amount <= 0) { + $amount = 0.01; + } + $selectable = self::isMethodPossible( + static::METHOD, + $locale, + Session::getInstance()->Customer()->cLand, + Session::getInstance()->Currency()->cISO, + $amount + ); + } catch (Exception $e) { + Helper::logExc($e); + $selectable = false; + } + } + return $selectable && parent::isSelectable(); + } + + /** + * @param $method + * @param $locale + * @param $billingCountry + * @param $currency + * @param $amount + * @return bool + * @throws ApiException + */ + protected static function isMethodPossible($method, $locale, $billingCountry, $currency, $amount) + { + + $api = new API(API::getMode()); + + if (!array_key_exists('mollie_possibleMethods', $_SESSION)) { + $_SESSION['mollie_possibleMethods'] = []; + } + + $key = md5(serialize([$locale, $billingCountry, $currency, $amount])); + if (!array_key_exists($key, $_SESSION['mollie_possibleMethods'])) { + $active = $api->Client()->methods->allActive([ + 'locale' => $locale, + 'amount' => [ + 'currency' => $currency, + 'value' => number_format($amount, 2, ".", "") + ], + 'billingCountry' => $billingCountry, + 'resource' => 'orders', + 'includeWallets' => 'applepay', + ]); + foreach($active as $a){ + $_SESSION['mollie_possibleMethods'][$key][] = (object)['id' =>$a->id]; + } + } + + if ($method !== '') { + foreach ($_SESSION['mollie_possibleMethods'][$key] as $m) { + if ($m->id === $method) { + return true; + } + } + } else { + return true; + } + + return false; + + } + + /** + * @param array $args_arr + * @return bool + */ + public function isValidIntern($args_arr = []) + { + return $this->duringCheckout + ? static::ALLOW_PAYMENT_BEFORE_ORDER && parent::isValidIntern($args_arr) + : parent::isValidIntern($args_arr); + } + + /** + * @return int + */ + public function getExpiryDays() + { + return (int)min(abs((int)Helper::oPlugin()->oPluginEinstellungAssoc_arr[$this->cModulId . '_dueDays']), static::MAX_EXPIRY_DAYS) ?: static::MAX_EXPIRY_DAYS; + } + +} diff --git a/version/202/paymentmethod/JTLMollieApplePay.php b/version/202/paymentmethod/JTLMollieApplePay.php new file mode 100644 index 0000000..4b23bf4 --- /dev/null +++ b/version/202/paymentmethod/JTLMollieApplePay.php @@ -0,0 +1,15 @@ +oRechnungsadresse->cMail; + $paymentOptions['locale'] = AbstractCheckout::getLocale(Session::getInstance()->Language()->getIso(), $order->oRechnungsadresse->cLand); + } + + $dueDays = $this->getExpiryDays(); + if ($dueDays > 3) { + $paymentOptions['dueDate'] = date('Y-m-d', strtotime("+{$dueDays} DAYS")); + } + return $paymentOptions; + } +} diff --git a/version/202/paymentmethod/JTLMollieBelfius.php b/version/202/paymentmethod/JTLMollieBelfius.php new file mode 100644 index 0000000..91a6169 --- /dev/null +++ b/version/202/paymentmethod/JTLMollieBelfius.php @@ -0,0 +1,8 @@ +clearToken(); + } + + protected function clearToken() + { + $this->unsetCache(self::CACHE_TOKEN) + ->unsetCache(self::CACHE_TOKEN_TIMESTAMP); + return true; + } + + public function handleAdditional($aPost_arr) + { + + $components = self::Plugin()->oPluginEinstellungAssoc_arr[$this->moduleID . '_components']; + $profileId = self::Plugin()->oPluginEinstellungAssoc_arr['profileId']; + + if ($components === 'N' || !$profileId || trim($profileId) === '') { + return parent::handleAdditional($aPost_arr); + } + + $cleared = false; + if (array_key_exists('clear', $aPost_arr) && (int)$aPost_arr['clear']) { + $cleared = $this->clearToken(); + } + + if ($components === 'S' && array_key_exists('skip', $aPost_arr) && (int)$aPost_arr['skip']) { + return parent::handleAdditional($aPost_arr); + } + + try { + $trustBadge = (bool)self::Plugin()->oPluginEinstellungAssoc_arr[$this->moduleID . '_loadTrust']; + $locale = AbstractCheckout::getLocale(Session::getInstance()->Language()->getIso(), Session::getInstance()->Customer() ? Session::getInstance()->Customer()->cLand : null); + $mode = API::getMode(); + $errorMessage = json_encode(self::Plugin()->oPluginSprachvariableAssoc_arr['mcErrorMessage']); + } catch (Exception $e) { + Jtllog::writeLog($e->getMessage() . "\n" . print_r(['e' => $e], 1)); + return parent::handleAdditional($aPost_arr); + } + + if (!$cleared && array_key_exists('cardToken', $aPost_arr) && ($token = trim($aPost_arr['cardToken']))) { + return $this->setToken($token) && parent::handleAdditional($aPost_arr); + } + + $token = false; + if (($ctTS = (int)$this->getCache(self::CACHE_TOKEN_TIMESTAMP)) && $ctTS > time()) { + $token = $this->getCache(self::CACHE_TOKEN); + } + + Shop::Smarty()->assign('profileId', $profileId) + ->assign('trustBadge', $trustBadge ? self::Plugin()->cFrontendPfadURLSSL . 'img/trust_' . $_SESSION['cISOSprache'] . '.png' : false) + ->assign('components', $components) + ->assign('locale', $locale ?: 'de_DE') + ->assign('token', $token ?: false) + ->assign('testMode', $mode ?: false) + ->assign('errorMessage', $errorMessage ?: null) + ->assign('mollieLang', self::Plugin()->oPluginSprachvariableAssoc_arr); + + return false; + +// if (array_key_exists('skip', $aPost_arr) && (int)$aPost_arr['skip']) { +// unset($_SESSION['mollieCardToken'], $_SESSION['mollieCardTokenTS']); +// return true; +// } +// +// $profileId = trim(Helper::getSetting('profileId')); +// if ($profileId === '' || strpos($profileId, 'pfl_') !== 0) { +// return true; +// } +// if (array_key_exists('mollieCardTokenTS', $_SESSION) && (int)$_SESSION['mollieCardTokenTS'] > time() +// && array_key_exists('mollieCardToken', $_SESSION) && trim($_SESSION['mollieCardToken']) !== '') { +// return true; +// } +// +// unset($_SESSION['mollieCardToken'], $_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('skipComponents', Helper::getSetting('skipComponents')) +// ->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; + } + + protected function setToken($token) + { + $this->addCache(self::CACHE_TOKEN, $token) + ->addCache(self::CACHE_TOKEN_TIMESTAMP, time() + 3600); + return true; + } + + public function getPaymentOptions(Bestellung $order, $apiType) + { + + $paymentOptions = []; + + if ($apiType === 'payment') { + if ($order->Lieferadresse !== null) { + if (!$order->Lieferadresse->cMail) { + $order->Lieferadresse->cMail = $order->oRechnungsadresse->cMail; + } + $paymentOptions['shippingAddress'] = Address::factory($order->Lieferadresse); + } + + $paymentOptions['billingAddress'] = Address::factory($order->oRechnungsadresse); + } + if ((int)$this->getCache(self::CACHE_TOKEN_TIMESTAMP) > time() && ($token = trim($this->getCache(self::CACHE_TOKEN)))) { + $paymentOptions['cardToken'] = $token; + } + return $paymentOptions; + } + +} diff --git a/version/202/paymentmethod/JTLMollieDirectDebit.php b/version/202/paymentmethod/JTLMollieDirectDebit.php new file mode 100644 index 0000000..7318e8a --- /dev/null +++ b/version/202/paymentmethod/JTLMollieDirectDebit.php @@ -0,0 +1,27 @@ + substr($order->cBestellNr, 0, 13)]; + } +} diff --git a/version/202/paymentmethod/JTLMollieKlarnaPayLater.php b/version/202/paymentmethod/JTLMollieKlarnaPayLater.php new file mode 100644 index 0000000..266953f --- /dev/null +++ b/version/202/paymentmethod/JTLMollieKlarnaPayLater.php @@ -0,0 +1,10 @@ +Lieferadresse !== null) { + if (!$order->Lieferadresse->cMail) { + $order->Lieferadresse->cMail = $order->oRechnungsadresse->cMail; + } + $paymentOptions['shippingAddress'] = Address::factory($order->Lieferadresse); + } + $paymentOptions['description'] = 'Order ' . $order->cBestellNr; + } + + + return $paymentOptions; + } + +} diff --git a/version/202/paymentmethod/JTLMolliePaysafecard.php b/version/202/paymentmethod/JTLMolliePaysafecard.php new file mode 100644 index 0000000..920e0fa --- /dev/null +++ b/version/202/paymentmethod/JTLMolliePaysafecard.php @@ -0,0 +1,13 @@ + $order->oKunde->kKunde] : []; + } +} diff --git a/version/202/paymentmethod/JTLMolliePrzelewy24.php b/version/202/paymentmethod/JTLMolliePrzelewy24.php new file mode 100644 index 0000000..ebd28ed --- /dev/null +++ b/version/202/paymentmethod/JTLMolliePrzelewy24.php @@ -0,0 +1,15 @@ + $order->oRechnungsadresse->cMail] : []; + } + +} diff --git a/version/202/paymentmethod/JTLMollieSofort.php b/version/202/paymentmethod/JTLMollieSofort.php new file mode 100644 index 0000000..c11060b --- /dev/null +++ b/version/202/paymentmethod/JTLMollieSofort.php @@ -0,0 +1,8 @@ +OH(NI>=T42<+x9g>;*Gy9DrKtJl=F((p(~XhRMojR(!TROq)4##x zi;wfn&C+>%^UTiFKSt7JYSXp1>ZPgDP*&5InbUcF<%^K^*xKlsoYHP{(wCajZ*$Ra zbJNPo(OY2BWNFmE!S~qO{POeCTVT|{z|(GX;Bt54e}mdsUi8b(sL>`X0000JbW%=J z01%HLkU-Cn-_OsV&!6AlpP5D4UE1#Sax&aZg(%L>z8x33MOZZ8H?WJ;;n51dMe)(}9UH1j29 ze@0RGfq`^s0!X#X7!_srsUP@btltZoyHfrIVq@*+2f)Ge+&BuBcbdrjKu5}NuE;){Yi3#o7gOK=v6Y0{rAbqNgQSz}}0I~5?ej{GsP%?vN z=_l4!?VPOmM>R@!2oOAkd1t|Pb#@H>-d=$PnbBs7=u%Z>9N;0iml z2#guk2rk-V%mMEvxQCZ1@+-_*(mao=fPWKs%h@Mp0)~gcfgO7j{4M(n<{@x^Z^Hk! ze1;0X32xx)(NPC3aetZbtnBss>W2NT-v%Bch%He^5RXIyLDWRp5;o{lcPr>qmkRZj lpHDtfd;A2~X0zTP_aA;i{an>LN7rz#m}I!{TEUogY_hW!fX z1?mg>C*-erx%(so1LG!77srr_xVP7C<}EQ0XbW_HZ(Bb#ysRpA(wRN~nf+#OlTe%( zXkfncL^KKCCrg-Lh=kEnU|a;ZB9QaR>Td+?i96wEUURmd^*;_;}q*?JtCN zs9v0_oUIYrJ>{ItUF)Suj=nY*E;y-_bg}zQ;ZT|@FU4Qeut^B)WfWUjV9g-3v@K+f-ik;kV{MOr_6wK;GGik>mTp$V%-RtP)+CPEi`n!UgTe~DWM4fFWeR( literal 0 HcmV?d00001 diff --git a/version/202/paymentmethod/img/method/bancontact@2x.png b/version/202/paymentmethod/img/method/bancontact@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..a87af77d20330ab4ee197fd750d0bd39a5b10f90 GIT binary patch literal 582 zcmV-M0=fN(P)lk!lq%lq?@9+Qr z|M>X$=jZ1jWQqR%{`vX&|JVTk=U{-T&j0$~pTFAg&hoWPVjpU$|LlN(mQMfcfPbmZpr$+j>2Uw#P;ZV{AZe)(UZem0@6X@u|MkEB z;XwWU{r~1*Ky`MXzS=N!uW*i8kF?YfT$A7F^MIC5pQk%!Gip%)000nlQchC<&w%eB zkRX4bpb&7+Z;x=Vl85vF00AONL_t(|UhS6GZp0uI1+V+IBnNQY-qL&T?f<_j%Vs4k zWi4ZPi#+c$LIR;fk}z^m8)w(24LdL-qBSjmiImqQ6%1%eKSC_H5hBJOQ3wcbh=A9j z0E`>M;F1Gj9uRN{NX-L}@Ce`*0RKJE1nw{TTbXGF`gs|rT7l!dln0%_EVm0RbGyKB zqJ*zRaiSTxE%@_=;_x?lSs8dz{y6#LPln}z>8GT40dLB`KB#<1qlM(E;D0OsM*0?TeIhg`dn6;Q{6Fh2l%qOS4K%wo8-q7AUD{?yGF(55vm4C&H_FzBH+J=d4+57}kr Up-!czfB*mh07*qoM6N<$g3OCHTL1t6 literal 0 HcmV?d00001 diff --git a/version/202/paymentmethod/img/method/banktransfer@2x.png b/version/202/paymentmethod/img/method/banktransfer@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..c70206bef4893f23fcd59d436273108d2f2eebc7 GIT binary patch literal 801 zcmV++1K#|JP)lk!lq*=;-9+mkX z{{U2_ztrjP@9%)A(*D5?-|6)J(MtZwET6yKpugSt`1lZBsz86cAZf7q`T3Bv*Z%(g z-|F=K#U1|5JO0^dAZoDx_u=pL`RC{7_xJZ;l*j-3@c!I)@AdkSwAlXDS^mf@aG%W2 z;O`J$tN-Md>+9=KiNUYR<6xA=@AUcq@WXGP%>DiS|LnB>%sc+*q+gWBFm$#4l$oJ=bMJL) zN$}UM z^EEI7D0q#*=`w@Mb&#yX6$WP@x&}s<8JvJ@pvqecQO^sez9^Xbs$t>(|Nn0Y_`k@X z`u+Uv`wm6F?mz#2{?4!aFGTBV&I9cbE(!7rW)PTg{{H;_^9ubA3J&Kd+&@2If#l5V zkwEFKo-U3d6>)E`o#Z>Lz~g$+{n^fDUKQE@|Mgd!a9=T#&e{4(sr-HO1o4KQ>uv;= zWX2_)yrQzk;QY@iN0x35n7oK-g-2+63_H(@QU|u6Z>|Z!r6lZ1zes9a?+x$E9%YhzX@O1Ta JS?83{1OT9Jm%RW0 literal 0 HcmV?d00001 diff --git a/version/202/paymentmethod/img/method/creditcard@2x.png b/version/202/paymentmethod/img/method/creditcard@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..b08be792753326b65345c752a6f350182a9393d2 GIT binary patch literal 3125 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 P00000NkvXXu0mjf3Vis# literal 0 HcmV?d00001 diff --git a/version/202/paymentmethod/img/method/directdebit@2x.png b/version/202/paymentmethod/img/method/directdebit@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..514ff845b84d38cd8eb97b9e2c53e5c117967944 GIT binary patch literal 801 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 literal 0 HcmV?d00001 diff --git a/version/202/paymentmethod/img/method/giropay@2x.png b/version/202/paymentmethod/img/method/giropay@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..b787e1fee50c9bcca112f734ef4bcbd4ecfb6d6b GIT binary patch literal 602 zcmV-g0;T5Kx~EOrH!)pASu;4ojd8OQ8=; zpbt!;!_w#B>GK{}r)iJG@bvggdAR@o{+6-TrM%mCn#w$GvMpk*ho#Tb-RaC5+y)hho537JnGBqPA~G@Ik#rt1jWCNmt_X5yY-;OM4Sm|;L0fCz(H!a59C z!6FQJ1`O=K0(U?&WmHmQ%ovl1g=xY%=0>sX7T{!DDr3#1AfT>{>*NQdp;XxeDnn^6 z;Fg|~18)oh=#B%J574HG=ZK=b0(2)=ZWs@6u|Psp2S`Ms-aSCKNc4dZ3ml0Y1JpF0 zACT7(WFOdH$J={=+}Kh?t@=QTh`Y)S;{lL4q2$K&0aK;&(@GqDK&DI^R~^tLy#OA$ z1Nay30gQkc{Q&0jzz(SpmbnlhVhfzVhaBhB0($}wh1S_^$N7}lg}e4p3Ic|F4;Z~b zTY@72isxg1#8BrSfnxv^S{6kiGl4E$H2v|f@*S9m0aJJk172Vm21F3Hg)IO)g#GGT oVe}rh6KIQG--ZM8)e@S10aM=ZI#^TblmGw#07*qoM6N<$f@FIOx&QzG literal 0 HcmV?d00001 diff --git a/version/202/paymentmethod/img/method/ideal@2x.png b/version/202/paymentmethod/img/method/ideal@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..efc4315a96a6b2d9b160578a65fe52206783f2ca GIT binary patch literal 845 zcmV-T1G4;yP)lk!ZZ65OMGC?}UYf;o;!m;NZf-!qXsn`1tsvqob6RlsGvz=jZ45_xJw({`vX& z+CYuwfU@xL?-Nv%`QPmApT=fqW&i*F(b3WK zzuD%1v(zAZ>+9>Xv$F87&$F|$@bK^%8W`-K#nT^p^1s=^!okAA!Tj&_DJdxZ{r%~X zz3Gp=&=7F!pvK@}pYN~F>5#mWl#|_1mb0_6g@uIHFobn>b?J}1M@UB*8yIC~W#VwE zc6N2$P?z9fpjKB^=ker~0000HbW%=J0PlbhkiUP=Adhe$&v1`#zea&7rvLx}*GWV{ zRCr#^*2j+9Fc5%YO7?ntl9{1;aqqou@0;Fxd;j;y*jNN`HV2Bl>~|3_{4oLqkzy%V z*t96C%}2Z9&SQ)86vWClksDVqqe|=&Z3|YQQjA*4CE6Eai>Qp6VzP3=CKt6Gk}WnU zMr|=|2#YGH?I~G;2n`TD#K5)puk^^z67b+ZZd-naz)7$!d_QRdc|mw#b1~<{2k2)FEaYF&OT-`GX$RPM#Nt`QAi#wXJk>zhFTO>59`Wo^#}<>sMjOed(+{-3ru0A7D$0jI558$ z)N0PF!RsCe2|{A+{jU4@5&uc>v9T(>X>= zpc$wJPDAG6XudKWan^4w_bUdHVBPG<>jQiVOn&QMzg?RgEbW=`(e{u7#up5;D^8W3 z2%8R3n@hIHS^6WCiFSq9p;8&OR7*Sn%M-cP>{s2YOOzKYHtDf;#GS4DUiRI4c22NA XzpeJ7+7%dW00000NkvXXu0mjfybi$$ literal 0 HcmV?d00001 diff --git a/version/202/paymentmethod/img/method/inghomepay@2x.png b/version/202/paymentmethod/img/method/inghomepay@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..538f219588886db215757eafd5c5151241f18b5a GIT binary patch literal 1118 zcmV-k1flzhP)`_0RK|}|55<|Q2_r?0RL0~|5E_}r-1)w9RKX&|5E_}=Gy;L z0RR90|6UOPlVJbp-~WC<|J1+#zn}l9fd6P9|A|olb1?tk&;RxB|Mc(wo^bzkF#pQ0 z|Fn<)>fisgkpF2Q|G%LBsek{okpG@<|H-fazM%hUAODC@|H-ibs(=5~!2gtB|K894 zs(@(VAMyYI01|XkPE!C7&ySx#AdugXK#$)bkdUC?LT6GX000A7Nkl+_F4;G0`t->#NE zT;V&r`f!+EySiCj<6V7Pt?{mYTH&4jj{)gM0TN(F3?6st+kjw6 z>LApXPB>Unt8V~;Cik9f49AhQ!$i7^fuL#4vW=&{86JR|lTsG~BRymzfEs|JX9J1K z03Dw$1C&G3WKK=%kB`J1r1*<~s2`z=k6T78&3xGOL&RV&0xXfJ0Ql@xfEn*A1CX9E zQ!WBD5?VbTK7XTsCp`U6crw}TsH%60W z2hoh@0nLYSxRBab{+9<3C+^Mz9xYb&ZxhMVDb+cqriY2<9AG-<8gN)^Cix5?)@kAU z;?6$;-SN`NKvD-cR@w%n?9AWi0I~xRElDnK5^Rh@FtDVHX8@ZJfJl->N&_A{l2bso z2x`kJr-3lmJ%9)DK@>~Q{7brt3fNKr^rbrq+|{-iAekxBG;uoyGqur4Ei0S?0=Yll zF_SR>W}x;7ttLalDFCI-OXsp?(S;*|rkk|uOcTs~fUR;0m?79z>!T@dSC<#zVpen3 zDj@L*GoMZY$tw7C*m%o|vLvel!qz~FMPzph=x6{KTjppdC7aC#VVdHg)$wl$bf*AC z1-Rnnz*LgVO4|B5HX#U@PXUn*;sq_sC5u*2fG7j7o&o~>%Wn3WWcg~#QmPptG|8+k2H7XW|=xVi9nUeg`1*I2IB*YJ(+JNL|VD24JQDXa_~} zqMBf8fF~Vbz5wvk*3xb81`yK5AZAEW$9)?Qt+BO>C3E@1Aktu4fz|6HW^Y;1@lk!lq%mkX z{~%3y0h-K!%;mq#+4%VQ5J7OCv&KMYjPLUG@9*#T_xE6cpCPBxaK_?)nX{kS?7!yn zfSI!2=Is9d{_pwx05oR#`T5`T`RC{7L9^Llzu!=FmQcCekkjew>+3LDf{>=XK(pDe zzt4c0vd`J#Fs;_V%-D~nykNlKAg9yc^7t^U)_~3BfX(J`#^Vv8&k>-{-}3p8(&?|? z?{JN&{r&x)v&FFA?=V_}aEz&7z~7M5=+D{X&+PS}+3awQs351(ptHqzpNxV4000qm zQchCIy&+X> z=*5Ul;OaQ@NK`Vzy8t_g2?_Jis)3C$i910Xw$PIU9&Uk!LpkskEkL9-LfkOWJAbaP zUroip18r(eg}^hN*BXg{sb1!Yfc6S#iGXvxN(6jb7x=sau0_D;#S-`?0_b=FJSG`H zPqbnfvWg$g}i**@5@#v5NT=$lzqSQdXDg|8f zIHlhJQN%Mfm~#2YP9b1YgB(!GAN!r?CIjA)sTANZfG||7{JhG5H)Vm3e?0>E>_vVi zq!;d4SOSQYxt#%m;F70Lx8o{r!Tt9&c8CI14(M}40nf9jzsNQAmkVA7gAM$Z|1+@m z0b{)*&IIp+jVE#-MjL9Dd6xv65#{P&<3u77*DDnbtf@m157r`vbG^_r?Ff8 d>Rr1A+%FMH_Q$8Zwr>Cc002ovPDHLkV1oT`waEYg literal 0 HcmV?d00001 diff --git a/version/202/paymentmethod/img/method/klarna@2x.png b/version/202/paymentmethod/img/method/klarna@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..e28a187b81e7c5a6256fea7382a643762746dd1e GIT binary patch literal 896 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 literal 0 HcmV?d00001 diff --git a/version/202/paymentmethod/img/method/paypal@2x.png b/version/202/paymentmethod/img/method/paypal@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..a816d7201f59ea7cef713f5e7895e66dcd6ee9a7 GIT binary patch literal 626 zcmV-&0*(ENP)zW{Q;0CK+oaK8X?zW{Q<0CB+pa=`#_!2of;na1S+alrro z|IFg@&*bxRu-m`e?~lRb-|hDbcETox$#AdRv()Q`yWm5X&|s$5P@dDD$>-eb_JFwG zpUUS$m(j@K@sPpeFpSLa_WMAU&p?#W{Qdsu^7&w=*MGR*^7#DO>Gd#+%P@?~P@U7S z((9ba=CIQ0sn6-_^!k0a-V=Mp)8_OXfyX(K&a%|&;_mkldc-e_%lZ5LgSp`#gUC6M z&erGk#LeN$0000GbW%=J0M8)rfN+qXfDoX6Z;yYFN6jxl0003wNklC4+MXiktqCYwRgSg6)KJbf z5Lj1?Y5+oU@|#dstX9C|0Ujt`J{M4b8Wr^cdi(ak0iFt>ORE}Nts8qh=FWCkI)}aEnE&{1?2hI?PIY68@ zbOdbw0PvXrf5i!Szy>sZ79ap>ye%)UHj^sMYbqagD6U zaJzaI>n$ypF23oVdS#o6|W|*DFT6j;X_Pjl^+{$7FxcM`F8{J!B6QqfZ6J=?T z0Z*i4z#}$g7~II(N7`*?T& O0000+D{~L?`zkmGy`PKgqj{m>0 z^Z&xI|35zdzp(26fxiDA9{<0v`v1;`{~L<_uT1&>;_Ck$4fn+3S%6jwlmz(&Gn{vr zARutRf5Q2Gh4~8e7rbanOaaP$^>lFzsfc?!?c};<10L727Z_ycPF(r9`v3o4QC^`f zNy*irThr_Lx8*f4F=sBE;Is9vL&{b+wWF_Q`cLpRlDMX^fZ@i14v}pdO3hrZ8V-u{ z6@GBmNPp@1=O;WPYJWl57EYgv)6tK(j<>!KX1Tkg-1yN7-6M=yr*jX!QWr1lo!e&; zepvX8JR>o1saCg`3ZOWgj;^L2z+zGho&3IENy|Lc5*g&izjA{*O9T;DjDIk7S9e6n)( p;e>?q6P^m(l+{vMe5&Mx9fO|m{vZE%WkG?%;OXk;vd$@?2>_eS)Oi2^ literal 0 HcmV?d00001 diff --git a/version/202/paymentmethod/tpl/bestellabschluss.tpl b/version/202/paymentmethod/tpl/bestellabschluss.tpl new file mode 100644 index 0000000..b26d8ef --- /dev/null +++ b/version/202/paymentmethod/tpl/bestellabschluss.tpl @@ -0,0 +1,26 @@ +{if isset($oMollieException)} +
+ {$oMollieException->getMessage()} +
+ +{/if} + +{if isset($redirect) && $redirect != ''} + + {if $checkoutMode == 'D'} + + {/if} +{/if} + diff --git a/version/202/paymentmethod/tpl/mollieComponents.tpl b/version/202/paymentmethod/tpl/mollieComponents.tpl new file mode 100644 index 0000000..38907e0 --- /dev/null +++ b/version/202/paymentmethod/tpl/mollieComponents.tpl @@ -0,0 +1,147 @@ +

{$mollieLang.cctitle}

+ +
+ +
+ + {if $token !== false} + +
+
+ {$mollieLang.clearDescr} +
+
+ +
+
+ + {if $trustBadge} +
+ PCI-DSS SAQ-A compliant +
+ {/if} + + {else} + + +
+ +
+
+
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+ +
+
+ + +
+
+ + {if $trustBadge} +
+ PCI-DSS SAQ-A compliant +
+ {/if} + {if $components == 'S'} + + {/if} +
+ +{/if} + + + + + + \ No newline at end of file diff --git a/version/202/sql/200.sql b/version/202/sql/200.sql new file mode 100644 index 0000000..0d28bdc --- /dev/null +++ b/version/202/sql/200.sql @@ -0,0 +1,31 @@ +CREATE TABLE IF NOT EXISTS `xplugin_ws_mollie_queue` ( + `kId` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY, + `cType` VARCHAR(32) NOT NULL, + `cData` TEXT DEFAULT '', + `cResult` TEXT NULL DEFAULT NULL, + `dDone` DATETIME NULL DEFAULT NULL, + `dCreated` DATETIME NOT NULL, + `dModified` DATETIME NULL DEFAULT NULL +); + +ALTER TABLE `xplugin_ws_mollie_payments` + ADD `dReminder` datetime NULL; +ALTER TABLE `xplugin_ws_mollie_payments` + ADD `cTransactionId` VARCHAR(32) DEFAULT ''; +ALTER TABLE `xplugin_ws_mollie_payments` + ADD `bSynced` TINYINT(1) NOT NULL; + +UPDATE `xplugin_ws_mollie_payments` +SET `bSynced` = true; + +CREATE TABLE IF NOT EXISTS `xplugin_ws_mollie_shipments` ( + `kLieferschien` int(11) NOT NULL PRIMARY KEY, + `kBestellung` int(11) NOT NULL, + `cOrderId` VARCHAR(32) NOT NULL, + `cShipmentId` VARCHAR(32) NOT NULL, + `cCarrier` VARCHAR(255) DEFAULT '', + `cCode` VARCHAR(255) DEFAULT '', + `cUrl` VARCHAR(512) DEFAULT '', + `dCreated` DATETIME NOT NULL, + `dModified` DATETIME NULL DEFAULT NULL +); \ No newline at end of file diff --git a/version/202/tpl/_alerts.tpl b/version/202/tpl/_alerts.tpl new file mode 100644 index 0000000..5279fa3 --- /dev/null +++ b/version/202/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} From a046e5e58a565ac6847c3b84b7e36bc0e2445f32 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Fri, 23 Apr 2021 13:58:43 +0200 Subject: [PATCH 207/280] fix session / language --- version/200/paymentmethod/JTLMollie.php | 2 +- version/201/paymentmethod/JTLMollie.php | 2 +- version/202/paymentmethod/JTLMollie.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/version/200/paymentmethod/JTLMollie.php b/version/200/paymentmethod/JTLMollie.php index c3bc7a8..0146566 100644 --- a/version/200/paymentmethod/JTLMollie.php +++ b/version/200/paymentmethod/JTLMollie.php @@ -169,7 +169,7 @@ public function isSelectable() } if ($selectable) { try { - $locale = AbstractCheckout::getLocale(Session::getInstance()->Language()->getIso(), Session::getInstance()->Customer()->cLand); + $locale = AbstractCheckout::getLocale($_SESSION['cISOSprache'], Session::getInstance()->Customer()->cLand); $amount = Session::getInstance()->Basket()->gibGesamtsummeWarenExt([ C_WARENKORBPOS_TYP_ARTIKEL, C_WARENKORBPOS_TYP_KUPON, diff --git a/version/201/paymentmethod/JTLMollie.php b/version/201/paymentmethod/JTLMollie.php index 1494095..bcefebd 100644 --- a/version/201/paymentmethod/JTLMollie.php +++ b/version/201/paymentmethod/JTLMollie.php @@ -168,7 +168,7 @@ public function isSelectable() } if ($selectable) { try { - $locale = AbstractCheckout::getLocale(Session::getInstance()->Language()->getIso(), Session::getInstance()->Customer()->cLand); + $locale = AbstractCheckout::getLocale($_SESSION['cISOSprache'], Session::getInstance()->Customer()->cLand); $amount = Session::getInstance()->Basket()->gibGesamtsummeWarenExt([ C_WARENKORBPOS_TYP_ARTIKEL, C_WARENKORBPOS_TYP_KUPON, diff --git a/version/202/paymentmethod/JTLMollie.php b/version/202/paymentmethod/JTLMollie.php index 1494095..bcefebd 100644 --- a/version/202/paymentmethod/JTLMollie.php +++ b/version/202/paymentmethod/JTLMollie.php @@ -168,7 +168,7 @@ public function isSelectable() } if ($selectable) { try { - $locale = AbstractCheckout::getLocale(Session::getInstance()->Language()->getIso(), Session::getInstance()->Customer()->cLand); + $locale = AbstractCheckout::getLocale($_SESSION['cISOSprache'], Session::getInstance()->Customer()->cLand); $amount = Session::getInstance()->Basket()->gibGesamtsummeWarenExt([ C_WARENKORBPOS_TYP_ARTIKEL, C_WARENKORBPOS_TYP_KUPON, From 676a3c543843dbc5ff07831e71e7a749bdc958f7 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Mon, 26 Apr 2021 12:07:26 +0200 Subject: [PATCH 208/280] fix Sprache ISO --- version/202/class/Checkout/AbstractCheckout.php | 2 +- version/202/class/Checkout/OrderCheckout.php | 2 +- version/202/class/Checkout/PaymentCheckout.php | 2 +- version/202/paymentmethod/JTLMollieBanktransfer.php | 2 +- version/202/paymentmethod/JTLMollieCreditCard.php | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/version/202/class/Checkout/AbstractCheckout.php b/version/202/class/Checkout/AbstractCheckout.php index 73ca98e..ca15646 100644 --- a/version/202/class/Checkout/AbstractCheckout.php +++ b/version/202/class/Checkout/AbstractCheckout.php @@ -418,7 +418,7 @@ public function getCustomer($createOrUpdate = false) $customer = [ 'name' => trim($oKunde->cVorname . ' ' . $oKunde->cNachname), 'email' => $oKunde->cMail, - 'locale' => self::getLocale(Session::getInstance()->Language()->getIso(), $oKunde->cLand), + 'locale' => self::getLocale($_SESSION['cISOSprache'], $oKunde->cLand), 'metadata' => (object)[ 'kKunde' => $oKunde->kKunde, 'kKundengruppe' => $oKunde->kKundengruppe, diff --git a/version/202/class/Checkout/OrderCheckout.php b/version/202/class/Checkout/OrderCheckout.php index 3478c6c..45d1d95 100644 --- a/version/202/class/Checkout/OrderCheckout.php +++ b/version/202/class/Checkout/OrderCheckout.php @@ -256,7 +256,7 @@ public function loadRequest($options = []) $options['customerId'] = $customer->id; } - $this->locale = self::getLocale(Session::getInstance()->Language()->getIso(), Session::getInstance()->Customer()->cLand); + $this->locale = self::getLocale($_SESSION['cISOSprache'], Session::getInstance()->Customer()->cLand); $this->amount = Amount::factory($this->getBestellung()->fGesamtsummeKundenwaehrung, $this->getBestellung()->Waehrung->cISO, true); $this->orderNumber = $this->getBestellung()->cBestellNr; $this->metadata = [ diff --git a/version/202/class/Checkout/PaymentCheckout.php b/version/202/class/Checkout/PaymentCheckout.php index 6b187d3..fc88a64 100644 --- a/version/202/class/Checkout/PaymentCheckout.php +++ b/version/202/class/Checkout/PaymentCheckout.php @@ -151,7 +151,7 @@ public function loadRequest($options = []) $this->description = 'Order ' . $this->getBestellung()->cBestellNr; $this->redirectUrl = $this->PaymentMethod()->getReturnURL($this->getBestellung()); $this->webhookUrl = Shop::getURL(true) . '/?mollie=1'; - $this->locale = self::getLocale(Session::getInstance()->Language()->getIso(), Session::getInstance()->Customer()->cLand); + $this->locale = self::getLocale($_SESSION['cISOSprache'], Session::getInstance()->Customer()->cLand); $this->metadata = [ 'kBestellung' => $this->getBestellung()->kBestellung, 'kKunde' => $this->getBestellung()->kKunde, diff --git a/version/202/paymentmethod/JTLMollieBanktransfer.php b/version/202/paymentmethod/JTLMollieBanktransfer.php index 017e28e..90022ea 100644 --- a/version/202/paymentmethod/JTLMollieBanktransfer.php +++ b/version/202/paymentmethod/JTLMollieBanktransfer.php @@ -16,7 +16,7 @@ public function getPaymentOptions(Bestellung $order, $apiType) $paymentOptions = []; if ($apiType === 'payment') { $paymentOptions['billingEmail'] = $order->oRechnungsadresse->cMail; - $paymentOptions['locale'] = AbstractCheckout::getLocale(Session::getInstance()->Language()->getIso(), $order->oRechnungsadresse->cLand); + $paymentOptions['locale'] = AbstractCheckout::getLocale($_SESSION['cISOSprache'], $order->oRechnungsadresse->cLand); } $dueDays = $this->getExpiryDays(); diff --git a/version/202/paymentmethod/JTLMollieCreditCard.php b/version/202/paymentmethod/JTLMollieCreditCard.php index b689e51..7288926 100644 --- a/version/202/paymentmethod/JTLMollieCreditCard.php +++ b/version/202/paymentmethod/JTLMollieCreditCard.php @@ -52,7 +52,7 @@ public function handleAdditional($aPost_arr) try { $trustBadge = (bool)self::Plugin()->oPluginEinstellungAssoc_arr[$this->moduleID . '_loadTrust']; - $locale = AbstractCheckout::getLocale(Session::getInstance()->Language()->getIso(), Session::getInstance()->Customer() ? Session::getInstance()->Customer()->cLand : null); + $locale = AbstractCheckout::getLocale($_SESSION['cISOSprache'], Session::getInstance()->Customer() ? Session::getInstance()->Customer()->cLand : null); $mode = API::getMode(); $errorMessage = json_encode(self::Plugin()->oPluginSprachvariableAssoc_arr['mcErrorMessage']); } catch (Exception $e) { From b18696de3f4f094fd9e21f65667bede5a16fc56a Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Thu, 6 May 2021 10:30:15 +0200 Subject: [PATCH 209/280] fix #120, #121, #122 --- version/202/adminmenu/orders.php | 6 +++++- version/202/adminmenu/tpl/paymentmethods.tpl | 20 +++++++++++++------ .../202/class/Checkout/Order/OrderLine.php | 10 +++++----- version/202/class/Checkout/OrderCheckout.php | 10 ++++++++-- 4 files changed, 32 insertions(+), 14 deletions(-) diff --git a/version/202/adminmenu/orders.php b/version/202/adminmenu/orders.php index 4a3e126..af6af9f 100644 --- a/version/202/adminmenu/orders.php +++ b/version/202/adminmenu/orders.php @@ -216,7 +216,11 @@ $payments = Shop::DB()->executeQueryPrepared("SELECT * FROM xplugin_ws_mollie_payments WHERE kBestellung IS NOT NULL ORDER BY dCreatedAt DESC LIMIT 1000;", [], 2); foreach ($payments as $i => $payment) { $payment = new Payment($payment); - $checkouts[$payment->kBestellung] = AbstractCheckout::fromModel($payment, false); + try { + $checkouts[$payment->kBestellung] = AbstractCheckout::fromModel($payment, false); + } catch (Exception $e) { + //Helper::addAlert($e->getMessage(), 'danger', 'orders'); + } } Shop::Smarty()->assign('payments', $payments) diff --git a/version/202/adminmenu/tpl/paymentmethods.tpl b/version/202/adminmenu/tpl/paymentmethods.tpl index 4fc8ab0..9f0dbf1 100644 --- a/version/202/adminmenu/tpl/paymentmethods.tpl +++ b/version/202/adminmenu/tpl/paymentmethods.tpl @@ -9,11 +9,19 @@ Review: {$profile->review->status} {/if} + {if $profile->_links->checkoutPreviewUrl->href} + + Checkout + Preview + + {/if} + + Mollie Dashboard + -
-
@@ -43,7 +51,7 @@ value="{if "amount"|array_key_exists:$smarty.get && $smarty.get.amount}{$smarty.get.amount}{else}10{/if}" name="amount" id="cAmount">
-
+
@@ -52,8 +60,7 @@
- - +
{if $allMethods && $allMethods|count} @@ -106,7 +113,8 @@ Bestellabschluss {/if*}
- Gültigkeit: {$method->maxExpiryDays} Tage + Gültigkeit + : {$method->maxExpiryDays} Tage {else} Derzeit nicht unterstützt. diff --git a/version/202/class/Checkout/Order/OrderLine.php b/version/202/class/Checkout/Order/OrderLine.php index b68ccc9..992975a 100644 --- a/version/202/class/Checkout/Order/OrderLine.php +++ b/version/202/class/Checkout/Order/OrderLine.php @@ -156,7 +156,7 @@ protected function fill($oPosition, $currency = null) $this->sku = $oPosition->Artikel->cArtNr; $metadata['kArtikel'] = $oPosition->kArtikel; if ($oPosition->cUnique !== '') { - $metadata['cUnique'] = $oPosition->cUnique; + $metadata['cUnique'] = utf8_encode($oPosition->cUnique); } } @@ -165,10 +165,10 @@ protected function fill($oPosition, $currency = null) /** @var WarenkorbPosEigenschaft $warenkorbPosEigenschaft */ foreach ($oPosition->WarenkorbPosEigenschaftArr as $warenkorbPosEigenschaft) { $metadata['properties'][] = [ - 'kEigenschaft' => $warenkorbPosEigenschaft->kEigenschaft, - 'kEigenschaftWert' => $warenkorbPosEigenschaft->kEigenschaftWert, - 'name' => $warenkorbPosEigenschaft->cEigenschaftName, - 'value' => $warenkorbPosEigenschaft->cEigenschaftWertName, + 'kEigenschaft' => (int)$warenkorbPosEigenschaft->kEigenschaft, + 'kEigenschaftWert' => (int)$warenkorbPosEigenschaft->kEigenschaftWert, + 'name' => utf8_encode($warenkorbPosEigenschaft->cEigenschaftName), + 'value' => utf8_encode($warenkorbPosEigenschaft->cEigenschaftWertName), ]; if (strlen(json_encode($metadata)) > 1000) { array_pop($metadata['properties']); diff --git a/version/202/class/Checkout/OrderCheckout.php b/version/202/class/Checkout/OrderCheckout.php index 45d1d95..c2a67bd 100644 --- a/version/202/class/Checkout/OrderCheckout.php +++ b/version/202/class/Checkout/OrderCheckout.php @@ -306,8 +306,14 @@ public function loadRequest($options = []) $this->lines = $lines; if ($dueDays = $this->PaymentMethod()->getExpiryDays()) { - $max = $this->method && strpos($this->method, 'klarna') !== false ? 28 : 100; - $this->expiresAt = date('Y-m-d', strtotime(sprintf("+%d DAYS", min($dueDays, $max)))); + try { + $max = $this->method && strpos($this->method, 'klarna') !== false ? 28 : 100; + $date = new \DateTime(sprintf("+%d DAYS", min($dueDays, $max)), new \DateTimeZone('UTC')); + $this->expiresAt = $date->format('Y-m-d'); + //date('Y-m-d', strtotime(sprintf("+%d DAYS", min($dueDays, $max)))); + } catch (Exception $e) { + $this->Log($e->getMessage(), LOGLEVEL_ERROR); + } } $this->payment = $options; From d8832d31d4e8387c64fcba7452dd92c9fcc5a135 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Thu, 6 May 2021 10:41:14 +0200 Subject: [PATCH 210/280] check metadata --- version/202/class/Checkout/Order/OrderLine.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/version/202/class/Checkout/Order/OrderLine.php b/version/202/class/Checkout/Order/OrderLine.php index 992975a..7fe7911 100644 --- a/version/202/class/Checkout/Order/OrderLine.php +++ b/version/202/class/Checkout/Order/OrderLine.php @@ -177,7 +177,9 @@ protected function fill($oPosition, $currency = null) } } - $this->metadata = $metadata; + if (json_encode($metadata) !== false) { + $this->metadata = $metadata; + } return $this; From bc223e1ea0de75a00179b010ed92d1f632b02951 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Thu, 6 May 2021 13:25:27 +0200 Subject: [PATCH 211/280] fix #99 --- version/202/adminmenu/tpl/_addon.tpl | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 version/202/adminmenu/tpl/_addon.tpl diff --git a/version/202/adminmenu/tpl/_addon.tpl b/version/202/adminmenu/tpl/_addon.tpl new file mode 100644 index 0000000..6539757 --- /dev/null +++ b/version/202/adminmenu/tpl/_addon.tpl @@ -0,0 +1,6 @@ + \ No newline at end of file From d88d29ffc56134b9090c3ae0d3cc4a6f2c6ef4fe Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Thu, 6 May 2021 13:28:10 +0200 Subject: [PATCH 212/280] updated version CreateDate --- info.xml | 2160 +++++++++++++++++++++++++++--------------------------- 1 file changed, 1098 insertions(+), 1062 deletions(-) diff --git a/info.xml b/info.xml index 11f7439..548be26 100644 --- a/info.xml +++ b/info.xml @@ -1,1105 +1,1141 @@ - - Mollie - Mollie Payment Plugin - WebStollen GmbH - https://www.webstollen.de - 102 - ws_mollie - 406 - - - 100.sql - 2019-02-11 - - - 2019-02-26 - - - 2019-04-23 - - - 2019-05-22 - - - 2019-07-12 - - - 2019-11-26 - - - 2019-12-18 - - - 107.sql - 2020-03-02 - - - 2020-04-24 - - - 109.sql - 2020-08-17 - - - 2020-11-19 - - - 2021-01-11 - - - 200.sql - 2021-04-22 - - - 2021-04-23 - - - 2021-04-23 - - - 75_bestellungInDb.php - 131_globalinclude.php - 132_headPostGet.php - 140_smarty.php - 180_checkbox.php - 181_sync.php - 210_storno.php - - - - Bestellungen - orders.php - - - Zahlungsarten - paymentmethods.php - - - Info - info.php - - - Einstellungen - - Live API Key: - Füge hier deinen mollie API Key ein - api_key - - - Test API Key: - Füge hier deinen mollie API Key ein - test_api_key - - - Test API als Admin - Wenn diese Einstellung aktiviert ist, wird im Shop automatisch die Test-API verwendet, wenn man als Admin im Backend eingeloggt ist. - testAsAdmin - - - - - - - Zahlungserinnerung - Soll bei fehlgeschlagener Zahlung ein Zahlungslink verschickt werden? Angabe in Stunden nach Bestellung. (0 = deaktiviert) - reminder - - - Kunden bei Mollie anlegen (Customer API) - Wenn diese Einstellung aktiviert ist, hat der Kunde die Möglichkeit, per Checkbox, seine Kundendaten bei Mollie zu speichern. Z.B. für Single-Click Checkout benötigt. - useCustomerAPI - - - - - - - Profile ID: - Füge hier deinen mollie Profil ID (pfl_) ein. Wird benötigt um mollie Components zu aktivieren - profileId - - - Zahlungsart zurücksetzen - Versucht, nach fehlgeschlagener oder abgebrochener Zahlung, die Zahlungsart bei Mollie zurückzusetzen - resetMethod - - - - - - - Nur bezahlte Bestellungen in die WAWI übertragen - Wenn diese Einstellung deaktiviert ist, können alle Bestellungen direkt von der WAWI abgerufen werden. - onlyPaid - - - - - - - Teilversand Verhalten - Bei Gastbestellungen und Teilversand. - shippingMode - - - - - - - Versand bei Mollie - Soll Versandinformation für OrderAPI Methoden an Mollie gesendet werden?. - shippingActive - - - - - - - - Bestellungen automatisch stornieren - Wenn diese Einstellung aktiviert ist, werden komplett Stornierte Bestellungen auch bei Mollie storniert oder rückerstattet. - autoRefund - - - - - - - Bestellabschluss - Hier kann das Bestellabschluss-Verhalten eingestellt werden. - checkoutMode - - - - - - - - Fallback-Locale - Fallback, falls Locale nicht erkannt oder nicht vorhanden. - fallbackLocale - - - - - - - - - - - - - - - - - - - - - - - - - - Checkout Styles laden - Lädt Stylesheets für das Evo Template, um den Checkout zu verschönern. - load_styles - - - - - - - - Artikel mit rationalen Stückzahlen - Artikel mit rationalen Stückzahlen werden dann unterstützt, jedoch als ein Artikel behandelt. KEIN Teilversand hierfür möglich! - supportQ - - - - - - - TransaktionsID des Zahlungseingangs: - Welche ID soll an die WAWI übetragen werden? Bei PayPal wird immer die PayPal Referenz angegeben. - wawiPaymentID - - - - - - - - Workflow-Secret: - Schlüssel, um die WAWI Workflow-Requests zu authentifizieren. - workflowSecret - - - - - - skipComponentsLink - - - - - - - - cctitle - - - - - - - - error_canceled - - + + Mollie + Mollie Payment Plugin + WebStollen GmbH + https://www.webstollen.de + 102 + ws_mollie + 406 + + + 100.sql + 2019-02-11 + + + 2019-02-26 + + + 2019-04-23 + + + 2019-05-22 + + + 2019-07-12 + + + 2019-11-26 + + + 2019-12-18 + + + 107.sql + 2020-03-02 + + + 2020-04-24 + + + 109.sql + 2020-08-17 + + + 2020-11-19 + + + 2021-01-11 + + + 200.sql + 2021-04-22 + + + 2021-04-23 + + + 2021-05-06 + + + 75_bestellungInDb.php + 131_globalinclude.php + 132_headPostGet.php + 140_smarty.php + 180_checkbox.php + 181_sync.php + 210_storno.php + + + + Bestellungen + orders.php + + + Zahlungsarten + paymentmethods.php + + + Info + info.php + + + Einstellungen + + Live API Key: + Füge hier deinen mollie API Key ein + api_key + + + Test API Key: + Füge hier deinen mollie API Key ein + test_api_key + + + Test API als Admin + Wenn diese Einstellung aktiviert ist, wird im Shop automatisch die Test-API verwendet, + wenn man als Admin im Backend eingeloggt ist. + + testAsAdmin + + + + + + + Zahlungserinnerung + Soll bei fehlgeschlagener Zahlung ein Zahlungslink verschickt werden? Angabe in Stunden + nach Bestellung. (0 = deaktiviert) + + reminder + + + Kunden bei Mollie anlegen (Customer API) + Wenn diese Einstellung aktiviert ist, hat der Kunde die Möglichkeit, per Checkbox, + seine Kundendaten bei Mollie zu speichern. Z.B. für Single-Click Checkout benötigt. + + useCustomerAPI + + + + + + + Profile ID: + Füge hier deinen mollie Profil ID (pfl_) ein. Wird benötigt um mollie Components zu + aktivieren + + profileId + + + Zahlungsart zurücksetzen + Versucht, nach fehlgeschlagener oder abgebrochener Zahlung, die Zahlungsart bei Mollie + zurückzusetzen + + resetMethod + + + + + + + Nur bezahlte Bestellungen in die WAWI übertragen + Wenn diese Einstellung deaktiviert ist, können alle Bestellungen direkt von der WAWI + abgerufen werden. + + onlyPaid + + + + + + + Teilversand Verhalten + Bei Gastbestellungen und Teilversand. + shippingMode + + + + + + + Versand bei Mollie + Soll Versandinformation für OrderAPI Methoden an Mollie gesendet werden?. + shippingActive + + + + + + + + Bestellungen automatisch stornieren + Wenn diese Einstellung aktiviert ist, werden komplett Stornierte Bestellungen auch bei + Mollie storniert oder rückerstattet. + + autoRefund + + + + + + + Bestellabschluss + Hier kann das Bestellabschluss-Verhalten eingestellt werden. + checkoutMode + + + + + + + + Fallback-Locale + Fallback, falls Locale nicht erkannt oder nicht vorhanden. + fallbackLocale + + + + + + + + + + + + + + + + + + + + + + + + + + Checkout Styles laden + Lädt Stylesheets für das Evo Template, um den Checkout zu verschönern. + load_styles + + + + + + + + Artikel mit rationalen Stückzahlen + Artikel mit rationalen Stückzahlen werden dann unterstützt, jedoch als ein Artikel + behandelt. KEIN Teilversand hierfür möglich! + + supportQ + + + + + + + TransaktionsID des Zahlungseingangs: + Welche ID soll an die WAWI übetragen werden? Bei PayPal wird immer die PayPal Referenz + angegeben. + + wawiPaymentID + + + + + + + + Workflow-Secret: + Schlüssel, um die WAWI Workflow-Requests zu authentifizieren. + workflowSecret + + + + + + skipComponentsLink + + + + + + + + cctitle + + + + + + + + error_canceled + + - - - - - - error_expired - - + + error_expired + + - - - - - - error_open - - + + error_open + + - - - - - - error_failed - - + + error_failed + + - - - - - - error_create - - + + error_create + + - - - - - - lbl_cardHolder - - - - - - - - lbl_cardNumber - - - - - - - - lbl_expiryDate - - - - - - - - lbl_varificationCode - - - - - - - - cvchint_1 - - - - - - - - cvchint_2 - - + + lbl_cardHolder + + + + + + + + lbl_cardNumber + + + + + + + + lbl_expiryDate + + + + + + + + lbl_varificationCode + + + + + + + + cvchint_1 + + + + + + + + cvchint_2 + + - - - - - - mcErrorMessage - Ein oder mehrere Felder sind ungültig. - - - - - - - clearDescr - Kreditkarte: Token bereits vorhanden - + + mcErrorMessage + Ein oder mehrere Felder sind ungültig. + + + + + + + clearDescr + Kreditkarte: Token bereits vorhanden + - - - - - - clearButton - Kreditkarte: Token löschen - - - - - - - errAlreadyPaid - Wenn die Bestellung bereits bezahlt ist - - - - - - - errOrderNotFound - Wenn Bestellung nicht gefunden wurde. - + + + clearButton + Kreditkarte: Token löschen + + + + + + + errAlreadyPaid + Wenn die Bestellung bereits bezahlt ist + + + + + + + errOrderNotFound + Wenn Bestellung nicht gefunden wurde. + - - - - - - checkboxText - Text der Checkbox, um einen Kunden bei Mollie anzulegen - + + checkboxText + Text der Checkbox, um einen Kunden bei Mollie anzulegen + - - + - - - - checkboxDescr - Beschreibung der Checkbox, um einen Kunden bei Mollie anzulegen - + + checkboxDescr + Beschreibung der Checkbox, um einen Kunden bei Mollie anzulegen + - - - - - - - - Mollie - img/method/mollie@2x.png - 1 - 1 - mollie.com - OTHER - 0 - 0 - 1 - 0 - JTLMollie.php - JTLMollie - tpl/bestellabschluss.tpl - - Mollie - Mollie - Bezahlen Sie bequem mit verschiedenen Zahlungsmethoden. - - - API - Welche API soll verwendet werden? - api - - - - - - - Gültigkeit in Tagen - Wie lange hat der Kunde Zeit die Bestellung zu bezahlen? (Order API) - dueDays - - - - Mollie Kreditkarte - img/method/creditcard@2x.png - 3 - 1 - mollie.com - CREDIT_CARD - 0 - 0 - 1 - 0 - JTLMollieCreditCard.php - JTLMollieCreditCard - tpl/bestellabschluss.tpl - tpl/mollieComponents.tpl - - Kreditkarte - Mollie - Bezahlen Sie bequem mit Kreditkarte. - - - Mollie Components - Wenn diese Einstellung aktiviert ist, werden die Kreditkarten ggf. bereits im Shop abgefragt. - components - - - - - - - - Trustgrafik anzeigen - Bindet eine Trust-Grafik unterhalb des Kreditkartenformulars ein. - loadTrust - - - - - - - API - Welche API soll verwendet werden? - api - - - - - - - Gültigkeit in Tagen - Wie lange hat der Kunde Zeit die Bestellung zu bezahlen? (Order API) - dueDays - - - - Mollie Apple Pay - img/method/applepay@2x.png - 3 - 1 - mollie.com - OTHER - 0 - 0 - 1 - 0 - JTLMollieApplePay.php - JTLMollieApplePay - tpl/bestellabschluss.tpl - - Apple Pay - Mollie - Bezahlen Sie bequem mit Apple Pay. - - - API - Welche API soll verwendet werden? - api - - - - - - - Gültigkeit in Tagen - Wie lange hat der Kunde Zeit die Bestellung zu bezahlen? (Order API) - dueDays - - - - Mollie Bancontact - img/method/bancontact@2x.png - 4 - 1 - mollie.com - OTHER - 0 - 0 - 1 - 0 - JTLMollieBancontact.php - JTLMollieBancontact - tpl/bestellabschluss.tpl - - Bancontact - Mollie - Bezahlen Sie bequem mit Bancontact. - - - API - Welche API soll verwendet werden? - api - - - - - - - Gültigkeit in Tagen - Wie lange hat der Kunde Zeit die Bestellung zu bezahlen? (Order API) - dueDays - - - - Mollie Banktransfer - img/method/banktransfer@2x.png - 5 - 1 - mollie.com - OTHER - 0 - 0 - 1 - 0 - JTLMollieBanktransfer.php - JTLMollieBanktransfer - tpl/bestellabschluss.tpl - - SEPA Überweisung - Mollie - Bezahlen Sie bequem mit SEPA Überweisung. - - - API - Welche API soll verwendet werden? - api - - - - - - - Gültigkeit in Tagen - Wie lange hat der Kunde Zeit die Überweisung zu tätigen? - dueDays - - - - Mollie Belfius - img/method/belfius@2x.png - 6 - 1 - mollie.com - OTHER - 0 - 0 - 1 - 0 - JTLMollieBelfius.php - JTLMollieBelfius - tpl/bestellabschluss.tpl - - Belfius - Mollie - Bezahlen Sie bequem mit Belfius. - - - API - Welche API soll verwendet werden? - api - - - - - - - Gültigkeit in Tagen - Wie lange hat der Kunde Zeit die Bestellung zu bezahlen? (Order API) - dueDays - - - - Mollie DirectDebit - img/method/directdebit@2x.png - 7 - 1 - mollie.com - DIRECT_DEBIT - 0 - 0 - 1 - 0 - JTLMollieDirectDebit.php - JTLMollieDirectDebit - tpl/bestellabschluss.tpl - - SEPA Lastschrift - Mollie - Bezahlen Sie bequem mit SEPA Lastschrift. - - - - Mollie EPS - img/method/eps@2x.png - 2 - 1 - mollie.com - OTHER - 0 - 0 - 1 - 0 - JTLMollieEPS.php - JTLMollieEPS - tpl/bestellabschluss.tpl - - EPS - mollie - Bezahlen Sie bequem mit EPS. - - - API - Welche API soll verwendet werden? - api - - - - - - - Gültigkeit in Tagen - Wie lange hat der Kunde Zeit die Bestellung zu bezahlen? (Order API) - dueDays - - - - Mollie Giftcard - img/method/giftcard@2x.png - 8 - 1 - mollie.com - OTHER - 0 - 0 - 1 - 0 - JTLMollieGiftcard.php - JTLMollieGiftcard - tpl/bestellabschluss.tpl - - Gift cards - Mollie - Bezahlen Sie bequem mit Gift cards. - - - - Mollie Giropay - img/method/giropay@2x.png - 9 - 1 - mollie.com - GIROPAY - 0 - 0 - 1 - 0 - JTLMollieGiropay.php - JTLMollieGiropay - tpl/bestellabschluss.tpl - - Giropay - mMllie - Bezahlen Sie bequem mit Giropay. - - - API - Welche API soll verwendet werden? - api - - - - - - - Gültigkeit in Tagen - Wie lange hat der Kunde Zeit die Bestellung zu bezahlen? (Order API) - dueDays - - - - Mollie iDEAL - img/method/ideal@2x.png - 10 - 1 - mollie.com - OTHER - 0 - 0 - 1 - 0 - JTLMollieIDEAL.php - JTLMollieIDEAL - tpl/bestellabschluss.tpl - - iDEAL - Mollie - Bezahlen Sie bequem mit iDEAL. - - - API - Welche API soll verwendet werden? - api - - - - - - - Gültigkeit in Tagen - Wie lange hat der Kunde Zeit die Bestellung zu bezahlen? (Order API) - dueDays - - - - Mollie ING HomePay - img/method/inghomepay@2x.png - 11 - 1 - mollie.com - OTHER - 0 - 0 - 1 - 0 - JTLMollieINGHomePay.php - JTLMollieINGHomePay - tpl/bestellabschluss.tpl - - ING HomePay - mollie - Bezahlen Sie bequem mit ING HomePay. - - - - Mollie KBC - img/method/kbc@2x.png - 12 - 1 - mollie.com - OTHER - 0 - 0 - 1 - 0 - JTLMollieKBC.php - JTLMollieKBC - tpl/bestellabschluss.tpl - - KBC - Mollie - Bezahlen Sie bequem mit KBC. - - - API - Welche API soll verwendet werden? - api - - - - - - - Gültigkeit in Tagen - Wie lange hat der Kunde Zeit die Bestellung zu bezahlen? (Order API) - dueDays - - - - Mollie PayPal - img/method/paypal@2x.png - 13 - 1 - mollie.com - PAYPAL - 0 - 0 - 1 - 0 - JTLMolliePayPal.php - JTLMolliePayPal - tpl/bestellabschluss.tpl - - PayPal - Mollie - Bezahlen Sie bequem mit PayPal. - - - API - Welche API soll verwendet werden? - api - - - - - - - Gültigkeit in Tagen - Wie lange hat der Kunde Zeit die Bestellung zu bezahlen? (Order API) - dueDays - - - - Mollie paysafecard - img/method/paysafecard@2x.png - 14 - 1 - mollie.com - OTHER - 0 - 0 - 1 - 0 - JTLMolliePaysafecard.php - JTLMolliePaysafecard - tpl/bestellabschluss.tpl - - paysafecard - Mollie - Bezahlen Sie bequem mit paysafecard. - - - API - Welche API soll verwendet werden? - api - - - - - - - Gültigkeit in Tagen - Wie lange hat der Kunde Zeit die Bestellung zu bezahlen? (Order API) - dueDays - - - - Mollie SOFORT - img/method/sofort@2x.png - 15 - 1 - mollie.com - DIRECT_E_BANKING - 0 - 0 - 1 - 0 - JTLMollieSofort.php - JTLMollieSofort - tpl/bestellabschluss.tpl - - SOFORT - Mollie - Bezahlen Sie bequem mit SOFORT. - - - API - Welche API soll verwendet werden? - api - - - - - - - Gültigkeit in Tagen - Wie lange hat der Kunde Zeit die Bestellung zu bezahlen? (Order API) - dueDays - - - - mollie Klarna Pay Later - img/method/klarna@2x.png - 16 - 1 - mollie.com - INVOICE - 0 - 0 - 1 - 0 - JTLMollieKlarnaPayLater.php - JTLMollieKlarnaPayLater - tpl/bestellabschluss.tpl - - Klarna Pay Later - mollie - Bezahlen Sie bequem mit Klarna Pay Later. - - - Gültigkeit in Tagen - Wie lange hat der Kunde Zeit die Bestellung zu bezahlen? - dueDays - - - - Mollie Klarna Slice It - img/method/klarna@2x.png - 17 - 1 - mollie.com - FINANCING - 0 - 0 - 1 - 0 - JTLMollieKlarnaSliceIt.php - JTLMollieKlarnaSliceIt - tpl/bestellabschluss.tpl - - Klarna Slice It - Mollie - Bezahlen Sie bequem mit Klarna Slice It. - - - Gültigkeit in Tagen - Wie lange hat der Kunde Zeit die Bestellung zu bezahlen? - dueDays - - - - Mollie Przelewy24 - img/method/Przelewy24@2x.png - 17 - 1 - mollie.com - OTHER - 0 - 0 - 1 - 0 - JTLMolliePrzelewy24.php - JTLMolliePrzelewy24 - tpl/bestellabschluss.tpl - - Przelewy24 - mollie - Bezahlen Sie bequem mit Przelewy24. - - - API - Welche API soll verwendet werden? - api - - - - - - - Gültigkeit in Tagen - Wie lange hat der Kunde Zeit die Bestellung zu bezahlen? (Order API) - dueDays - - - - Mollie MyBank - img/method/mybank@2x.png - 17 - 1 - mollie.com - OTHER - 0 - 0 - 1 - 0 - JTLMollieMyBank.php - JTLMollieMyBank - tpl/bestellabschluss.tpl - - MyBank - Mollie - Bezahlen Sie bequem mit MyBank. - - - API - Welche API soll verwendet werden? - api - - - - - - - Gültigkeit in Tagen - Wie lange hat der Kunde Zeit die Bestellung zu bezahlen? (Order API) - dueDays - - - - - - - + + + + + Mollie + img/method/mollie@2x.png + 1 + 1 + mollie.com + OTHER + 0 + 0 + 1 + 0 + JTLMollie.php + JTLMollie + tpl/bestellabschluss.tpl + + Mollie + Mollie + Bezahlen Sie bequem mit verschiedenen Zahlungsmethoden. + + + API + Welche API soll verwendet werden? + api + + + + + + + Gültigkeit in Tagen + Wie lange hat der Kunde Zeit die Bestellung zu bezahlen? (Order API) + dueDays + + + + Mollie Kreditkarte + img/method/creditcard@2x.png + 3 + 1 + mollie.com + CREDIT_CARD + 0 + 0 + 1 + 0 + JTLMollieCreditCard.php + JTLMollieCreditCard + tpl/bestellabschluss.tpl + tpl/mollieComponents.tpl + + Kreditkarte + Mollie + Bezahlen Sie bequem mit Kreditkarte. + + + Mollie Components + Wenn diese Einstellung aktiviert ist, werden die Kreditkarten ggf. bereits im Shop + abgefragt. + + components + + + + + + + + Trustgrafik anzeigen + Bindet eine Trust-Grafik unterhalb des Kreditkartenformulars ein. + loadTrust + + + + + + + API + Welche API soll verwendet werden? + api + + + + + + + Gültigkeit in Tagen + Wie lange hat der Kunde Zeit die Bestellung zu bezahlen? (Order API) + dueDays + + + + Mollie Apple Pay + img/method/applepay@2x.png + 3 + 1 + mollie.com + OTHER + 0 + 0 + 1 + 0 + JTLMollieApplePay.php + JTLMollieApplePay + tpl/bestellabschluss.tpl + + Apple Pay + Mollie + Bezahlen Sie bequem mit Apple Pay. + + + API + Welche API soll verwendet werden? + api + + + + + + + Gültigkeit in Tagen + Wie lange hat der Kunde Zeit die Bestellung zu bezahlen? (Order API) + dueDays + + + + Mollie Bancontact + img/method/bancontact@2x.png + 4 + 1 + mollie.com + OTHER + 0 + 0 + 1 + 0 + JTLMollieBancontact.php + JTLMollieBancontact + tpl/bestellabschluss.tpl + + Bancontact + Mollie + Bezahlen Sie bequem mit Bancontact. + + + API + Welche API soll verwendet werden? + api + + + + + + + Gültigkeit in Tagen + Wie lange hat der Kunde Zeit die Bestellung zu bezahlen? (Order API) + dueDays + + + + Mollie Banktransfer + img/method/banktransfer@2x.png + 5 + 1 + mollie.com + OTHER + 0 + 0 + 1 + 0 + JTLMollieBanktransfer.php + JTLMollieBanktransfer + tpl/bestellabschluss.tpl + + SEPA Überweisung + Mollie + Bezahlen Sie bequem mit SEPA Überweisung. + + + API + Welche API soll verwendet werden? + api + + + + + + + Gültigkeit in Tagen + Wie lange hat der Kunde Zeit die Überweisung zu tätigen? + dueDays + + + + Mollie Belfius + img/method/belfius@2x.png + 6 + 1 + mollie.com + OTHER + 0 + 0 + 1 + 0 + JTLMollieBelfius.php + JTLMollieBelfius + tpl/bestellabschluss.tpl + + Belfius + Mollie + Bezahlen Sie bequem mit Belfius. + + + API + Welche API soll verwendet werden? + api + + + + + + + Gültigkeit in Tagen + Wie lange hat der Kunde Zeit die Bestellung zu bezahlen? (Order API) + dueDays + + + + Mollie DirectDebit + img/method/directdebit@2x.png + 7 + 1 + mollie.com + DIRECT_DEBIT + 0 + 0 + 1 + 0 + JTLMollieDirectDebit.php + JTLMollieDirectDebit + tpl/bestellabschluss.tpl + + SEPA Lastschrift + Mollie + Bezahlen Sie bequem mit SEPA Lastschrift. + + + + Mollie EPS + img/method/eps@2x.png + 2 + 1 + mollie.com + OTHER + 0 + 0 + 1 + 0 + JTLMollieEPS.php + JTLMollieEPS + tpl/bestellabschluss.tpl + + EPS + mollie + Bezahlen Sie bequem mit EPS. + + + API + Welche API soll verwendet werden? + api + + + + + + + Gültigkeit in Tagen + Wie lange hat der Kunde Zeit die Bestellung zu bezahlen? (Order API) + dueDays + + + + Mollie Giftcard + img/method/giftcard@2x.png + 8 + 1 + mollie.com + OTHER + 0 + 0 + 1 + 0 + JTLMollieGiftcard.php + JTLMollieGiftcard + tpl/bestellabschluss.tpl + + Gift cards + Mollie + Bezahlen Sie bequem mit Gift cards. + + + + Mollie Giropay + img/method/giropay@2x.png + 9 + 1 + mollie.com + GIROPAY + 0 + 0 + 1 + 0 + JTLMollieGiropay.php + JTLMollieGiropay + tpl/bestellabschluss.tpl + + Giropay + mMllie + Bezahlen Sie bequem mit Giropay. + + + API + Welche API soll verwendet werden? + api + + + + + + + Gültigkeit in Tagen + Wie lange hat der Kunde Zeit die Bestellung zu bezahlen? (Order API) + dueDays + + + + Mollie iDEAL + img/method/ideal@2x.png + 10 + 1 + mollie.com + OTHER + 0 + 0 + 1 + 0 + JTLMollieIDEAL.php + JTLMollieIDEAL + tpl/bestellabschluss.tpl + + iDEAL + Mollie + Bezahlen Sie bequem mit iDEAL. + + + API + Welche API soll verwendet werden? + api + + + + + + + Gültigkeit in Tagen + Wie lange hat der Kunde Zeit die Bestellung zu bezahlen? (Order API) + dueDays + + + + Mollie ING HomePay + img/method/inghomepay@2x.png + 11 + 1 + mollie.com + OTHER + 0 + 0 + 1 + 0 + JTLMollieINGHomePay.php + JTLMollieINGHomePay + tpl/bestellabschluss.tpl + + ING HomePay + mollie + Bezahlen Sie bequem mit ING HomePay. + + + + Mollie KBC + img/method/kbc@2x.png + 12 + 1 + mollie.com + OTHER + 0 + 0 + 1 + 0 + JTLMollieKBC.php + JTLMollieKBC + tpl/bestellabschluss.tpl + + KBC + Mollie + Bezahlen Sie bequem mit KBC. + + + API + Welche API soll verwendet werden? + api + + + + + + + Gültigkeit in Tagen + Wie lange hat der Kunde Zeit die Bestellung zu bezahlen? (Order API) + dueDays + + + + Mollie PayPal + img/method/paypal@2x.png + 13 + 1 + mollie.com + PAYPAL + 0 + 0 + 1 + 0 + JTLMolliePayPal.php + JTLMolliePayPal + tpl/bestellabschluss.tpl + + PayPal + Mollie + Bezahlen Sie bequem mit PayPal. + + + API + Welche API soll verwendet werden? + api + + + + + + + Gültigkeit in Tagen + Wie lange hat der Kunde Zeit die Bestellung zu bezahlen? (Order API) + dueDays + + + + Mollie paysafecard + img/method/paysafecard@2x.png + 14 + 1 + mollie.com + OTHER + 0 + 0 + 1 + 0 + JTLMolliePaysafecard.php + JTLMolliePaysafecard + tpl/bestellabschluss.tpl + + paysafecard + Mollie + Bezahlen Sie bequem mit paysafecard. + + + API + Welche API soll verwendet werden? + api + + + + + + + Gültigkeit in Tagen + Wie lange hat der Kunde Zeit die Bestellung zu bezahlen? (Order API) + dueDays + + + + Mollie SOFORT + img/method/sofort@2x.png + 15 + 1 + mollie.com + DIRECT_E_BANKING + 0 + 0 + 1 + 0 + JTLMollieSofort.php + JTLMollieSofort + tpl/bestellabschluss.tpl + + SOFORT + Mollie + Bezahlen Sie bequem mit SOFORT. + + + API + Welche API soll verwendet werden? + api + + + + + + + Gültigkeit in Tagen + Wie lange hat der Kunde Zeit die Bestellung zu bezahlen? (Order API) + dueDays + + + + mollie Klarna Pay Later + img/method/klarna@2x.png + 16 + 1 + mollie.com + INVOICE + 0 + 0 + 1 + 0 + JTLMollieKlarnaPayLater.php + JTLMollieKlarnaPayLater + tpl/bestellabschluss.tpl + + Klarna Pay Later + mollie + Bezahlen Sie bequem mit Klarna Pay Later. + + + Gültigkeit in Tagen + Wie lange hat der Kunde Zeit die Bestellung zu bezahlen? + dueDays + + + + Mollie Klarna Slice It + img/method/klarna@2x.png + 17 + 1 + mollie.com + FINANCING + 0 + 0 + 1 + 0 + JTLMollieKlarnaSliceIt.php + JTLMollieKlarnaSliceIt + tpl/bestellabschluss.tpl + + Klarna Slice It + Mollie + Bezahlen Sie bequem mit Klarna Slice It. + + + Gültigkeit in Tagen + Wie lange hat der Kunde Zeit die Bestellung zu bezahlen? + dueDays + + + + Mollie Przelewy24 + img/method/Przelewy24@2x.png + 17 + 1 + mollie.com + OTHER + 0 + 0 + 1 + 0 + JTLMolliePrzelewy24.php + JTLMolliePrzelewy24 + tpl/bestellabschluss.tpl + + Przelewy24 + mollie + Bezahlen Sie bequem mit Przelewy24. + + + API + Welche API soll verwendet werden? + api + + + + + + + Gültigkeit in Tagen + Wie lange hat der Kunde Zeit die Bestellung zu bezahlen? (Order API) + dueDays + + + + Mollie MyBank + img/method/mybank@2x.png + 17 + 1 + mollie.com + OTHER + 0 + 0 + 1 + 0 + JTLMollieMyBank.php + JTLMollieMyBank + tpl/bestellabschluss.tpl + + MyBank + Mollie + Bezahlen Sie bequem mit MyBank. + + + API + Welche API soll verwendet werden? + api + + + + + + + Gültigkeit in Tagen + Wie lange hat der Kunde Zeit die Bestellung zu bezahlen? (Order API) + dueDays + + + + + + + \ No newline at end of file From 6e14803c96b5ae38aca5db1ece09bb8045f37c8c Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Thu, 6 May 2021 13:37:58 +0200 Subject: [PATCH 213/280] update mollie-api-php --- composer.json | 2 +- composer.lock | 74 ++++++++++++++++++++++++++++++--------------------- 2 files changed, 44 insertions(+), 32 deletions(-) diff --git a/composer.json b/composer.json index d0e0526..96ac757 100644 --- a/composer.json +++ b/composer.json @@ -6,7 +6,7 @@ "ext-json": "*", "ext-curl": "*", "php": ">=5.6", - "mollie/mollie-api-php": "^v2.30.2" + "mollie/mollie-api-php": "^v2.31.1" } , "require-dev": { diff --git a/composer.lock b/composer.lock index 187a444..eeace36 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "b3222aabb4733c6c739d36dee243f4c2", + "content-hash": "4ceee3c5cacb717215861c1bc668ac23", "packages": [ { "name": "composer/ca-bundle", @@ -197,16 +197,16 @@ }, { "name": "guzzlehttp/psr7", - "version": "1.8.1", + "version": "1.8.2", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "35ea11d335fd638b5882ff1725228b3d35496ab1" + "reference": "dc960a912984efb74d0a90222870c72c87f10c91" }, "dist": { "type": "zip", - "url": "https://github.com/gitapi/repos/guzzle/psr7/zipball/35ea11d335fd638b5882ff1725228b3d35496ab1", - "reference": "35ea11d335fd638b5882ff1725228b3d35496ab1", + "url": "https://github.com/gitapi/repos/guzzle/psr7/zipball/dc960a912984efb74d0a90222870c72c87f10c91", + "reference": "dc960a912984efb74d0a90222870c72c87f10c91", "shasum": "" }, "require": { @@ -264,20 +264,20 @@ "uri", "url" ], - "time": "2021-03-21T16:25:00+00:00" + "time": "2021-04-26T09:17:50+00:00" }, { "name": "mollie/mollie-api-php", - "version": "v2.30.2", + "version": "v2.31.1", "source": { "type": "git", "url": "https://github.com/mollie/mollie-api-php.git", - "reference": "c3eb21214583f21655d4182b4c5b2f73e5a1dd0e" + "reference": "c1a500d251255e29919c6250d5c741ae4fe4e178" }, "dist": { "type": "zip", - "url": "https://github.com/gitapi/repos/mollie/mollie-api-php/zipball/c3eb21214583f21655d4182b4c5b2f73e5a1dd0e", - "reference": "c3eb21214583f21655d4182b4c5b2f73e5a1dd0e", + "url": "https://github.com/gitapi/repos/mollie/mollie-api-php/zipball/c1a500d251255e29919c6250d5c741ae4fe4e178", + "reference": "c1a500d251255e29919c6250d5c741ae4fe4e178", "shasum": "" }, "require": { @@ -351,20 +351,20 @@ "sofortbanking", "subscriptions" ], - "time": "2021-03-31T14:44:26+00:00" + "time": "2021-04-26T11:38:41+00:00" }, { "name": "paragonie/random_compat", - "version": "v2.0.19", + "version": "v2.0.20", "source": { "type": "git", "url": "https://github.com/paragonie/random_compat.git", - "reference": "446fc9faa5c2a9ddf65eb7121c0af7e857295241" + "reference": "0f1f60250fccffeaf5dda91eea1c018aed1adc2a" }, "dist": { "type": "zip", - "url": "https://github.com/gitapi/repos/paragonie/random_compat/zipball/446fc9faa5c2a9ddf65eb7121c0af7e857295241", - "reference": "446fc9faa5c2a9ddf65eb7121c0af7e857295241", + "url": "https://github.com/gitapi/repos/paragonie/random_compat/zipball/0f1f60250fccffeaf5dda91eea1c018aed1adc2a", + "reference": "0f1f60250fccffeaf5dda91eea1c018aed1adc2a", "shasum": "" }, "require": { @@ -400,7 +400,7 @@ "pseudorandom", "random" ], - "time": "2020-10-15T10:06:57+00:00" + "time": "2021-04-17T09:33:01+00:00" }, { "name": "psr/http-message", @@ -816,12 +816,12 @@ "source": { "type": "git", "url": "https://github.com/Roave/SecurityAdvisories.git", - "reference": "f3d64e623a75abaababa97e02a31e3771dea481a" + "reference": "db47aac368cb81bc9d3b09556e63b716be61cf43" }, "dist": { "type": "zip", - "url": "https://github.com/gitapi/repos/Roave/SecurityAdvisories/zipball/f3d64e623a75abaababa97e02a31e3771dea481a", - "reference": "f3d64e623a75abaababa97e02a31e3771dea481a", + "url": "https://github.com/gitapi/repos/Roave/SecurityAdvisories/zipball/db47aac368cb81bc9d3b09556e63b716be61cf43", + "reference": "db47aac368cb81bc9d3b09556e63b716be61cf43", "shasum": "" }, "conflict": { @@ -838,6 +838,7 @@ "barrelstrength/sprout-base-email": "<1.2.7", "barrelstrength/sprout-forms": "<3.9", "baserproject/basercms": ">=4,<=4.3.6|>=4.4,<4.4.1", + "bk2k/bootstrap-package": ">=7.1,<7.1.2|>=8,<8.0.8|>=9,<9.0.4|>=9.1,<9.1.3|>=10,<10.0.10|>=11,<11.0.3", "bolt/bolt": "<3.7.1", "bolt/core": "<4.1.13", "brightlocal/phpwhois": "<=4.2.5", @@ -849,7 +850,7 @@ "centreon/centreon": "<18.10.8|>=19,<19.4.5", "cesnet/simplesamlphp-module-proxystatistics": "<3.1", "codeigniter/framework": "<=3.0.6", - "composer/composer": "<=1-alpha.11", + "composer/composer": "<1.10.22|>=2-alpha.1,<2.0.13", "contao-components/mediaelement": ">=2.14.2,<2.21.1", "contao/core": ">=2,<3.5.39", "contao/core-bundle": ">=4,<4.4.52|>=4.5,<4.9.6|= 4.10.0", @@ -900,8 +901,8 @@ "friendsofsymfony/user-bundle": ">=1.2,<1.3.5", "friendsoftypo3/mediace": ">=7.6.2,<7.6.5", "fuel/core": "<1.8.1", - "getgrav/grav": "<1.7-beta.8", - "getkirby/cms": ">=3,<3.4.5", + "getgrav/grav": "<1.7.11", + "getkirby/cms": "<3.5.4", "getkirby/panel": "<2.5.14", "gos/web-socket-bundle": "<1.10.4|>=2,<2.6.1|>=3,<3.3", "gree/jose": "<=2.2", @@ -909,7 +910,7 @@ "guzzlehttp/guzzle": ">=4-rc.2,<4.2.4|>=5,<5.3.1|>=6,<6.2.1", "illuminate/auth": ">=4,<4.0.99|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.10", "illuminate/cookie": ">=4,<=4.0.11|>=4.1,<=4.1.99999|>=4.2,<=4.2.99999|>=5,<=5.0.99999|>=5.1,<=5.1.99999|>=5.2,<=5.2.99999|>=5.3,<=5.3.99999|>=5.4,<=5.4.99999|>=5.5,<=5.5.49|>=5.6,<=5.6.99999|>=5.7,<=5.7.99999|>=5.8,<=5.8.99999|>=6,<6.18.31|>=7,<7.22.4", - "illuminate/database": "<6.20.14|>=7,<7.30.4|>=8,<8.24", + "illuminate/database": "<6.20.26|>=7,<8.40", "illuminate/encryption": ">=4,<=4.0.11|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.40|>=5.6,<5.6.15", "illuminate/view": ">=7,<7.1.2", "impresscms/impresscms": "<=1.4.2", @@ -922,7 +923,7 @@ "kitodo/presentation": "<3.1.2", "kreait/firebase-php": ">=3.2,<3.8.1", "la-haute-societe/tcpdf": "<6.2.22", - "laravel/framework": "<6.20.14|>=7,<7.30.4|>=8,<8.24", + "laravel/framework": "<6.20.26|>=7,<8.40", "laravel/socialite": ">=1,<1.0.99|>=2,<2.0.10", "league/commonmark": "<0.18.3", "librenms/librenms": "<1.53", @@ -938,6 +939,9 @@ "monolog/monolog": ">=1.8,<1.12", "moodle/moodle": "<3.5.17|>=3.7,<3.7.9|>=3.8,<3.8.8|>=3.9,<3.9.5|>=3.10,<3.10.2", "namshi/jose": "<2.2", + "neos/flow": ">=1,<1.0.4|>=1.1,<1.1.1|>=2,<2.0.1|>=2.3,<2.3.16|>=3,<3.0.12|>=3.1,<3.1.10|>=3.2,<3.2.13|>=3.3,<3.3.13|>=4,<4.0.6", + "neos/neos": ">=1.1,<1.1.3|>=1.2,<1.2.13|>=2,<2.0.4|>=2.3,<2.9.99|>=3,<3.0.20|>=3.1,<3.1.18|>=3.2,<3.2.14|>=3.3,<3.3.23|>=4,<4.0.17|>=4.1,<4.1.16|>=4.2,<4.2.12|>=4.3,<4.3.3", + "neos/swiftmailer": ">=4.1,<4.1.99|>=5.4,<5.4.5", "nette/application": ">=2,<2.0.19|>=2.1,<2.1.13|>=2.2,<2.2.10|>=2.3,<2.3.14|>=2.4,<2.4.16|>=3,<3.0.6", "nette/nette": ">=2,<2.0.19|>=2.1,<2.1.13", "nystudio107/craft-seomatic": "<3.3", @@ -949,7 +953,7 @@ "onelogin/php-saml": "<2.10.4", "oneup/uploader-bundle": "<1.9.3|>=2,<2.1.5", "openid/php-openid": "<2.3", - "openmage/magento-lts": "<19.4.8|>=20,<20.0.4", + "openmage/magento-lts": "<=19.4.12|>=20,<=20.0.8", "orchid/platform": ">=9,<9.4.4", "oro/crm": ">=1.7,<1.7.4", "oro/platform": ">=1.7,<1.7.4", @@ -961,11 +965,12 @@ "pear/archive_tar": "<1.4.12", "personnummer/personnummer": "<3.0.2", "phpfastcache/phpfastcache": ">=5,<5.0.13", - "phpmailer/phpmailer": "<6.1.6", + "phpmailer/phpmailer": "<6.1.6|>=6.1.8,<6.4.1", "phpmussel/phpmussel": ">=1,<1.6", "phpmyadmin/phpmyadmin": "<4.9.6|>=5,<5.0.3", "phpoffice/phpexcel": "<1.8.2", "phpoffice/phpspreadsheet": "<1.16", + "phpseclib/phpseclib": "<2.0.31|>=3,<3.0.7", "phpunit/phpunit": ">=4.8.19,<4.8.28|>=5.0.10,<5.6.3", "phpwhois/phpwhois": "<=4.2.5", "phpxmlrpc/extras": "<0.6.1", @@ -983,15 +988,18 @@ "propel/propel1": ">=1,<=1.7.1", "pterodactyl/panel": "<0.7.19|>=1-rc.0,<=1-rc.6", "pusher/pusher-php-server": "<2.2.1", + "pwweb/laravel-core": "<=0.3.6-beta", "rainlab/debugbar-plugin": "<3.1", + "rmccue/requests": ">=1.6,<1.8", "robrichards/xmlseclibs": "<3.0.4", "sabberworm/php-css-parser": ">=1,<1.0.1|>=2,<2.0.1|>=3,<3.0.1|>=4,<4.0.1|>=5,<5.0.9|>=5.1,<5.1.3|>=5.2,<5.2.1|>=6,<6.0.2|>=7,<7.0.4|>=8,<8.0.1|>=8.1,<8.1.1|>=8.2,<8.2.1|>=8.3,<8.3.1", "sabre/dav": ">=1.6,<1.6.99|>=1.7,<1.7.11|>=1.8,<1.8.9", "scheb/two-factor-bundle": ">=0,<3.26|>=4,<4.11", "sensiolabs/connect": "<4.2.3", "serluck/phpwhois": "<=4.2.6", - "shopware/core": "<=6.3.4", - "shopware/platform": "<=6.3.5.1", + "shopware/core": "<=6.3.5.2", + "shopware/platform": "<=6.3.5.2", + "shopware/production": "<=6.3.5.2", "shopware/shopware": "<5.6.9", "silverstripe/admin": ">=1.0.3,<1.0.4|>=1.1,<1.1.1", "silverstripe/assets": ">=1,<1.4.7|>=1.5,<1.5.2", @@ -1068,15 +1076,17 @@ "typo3/cms-backend": ">=7,<=7.6.50|>=8,<=8.7.39|>=9,<=9.5.24|>=10,<=10.4.13|>=11,<=11.1", "typo3/cms-core": ">=6.2,<=6.2.56|>=7,<=7.6.50|>=8,<=8.7.39|>=9,<9.5.25|>=10,<10.4.14|>=11,<11.1.1", "typo3/cms-form": ">=8,<=8.7.39|>=9,<=9.5.24|>=10,<=10.4.13|>=11,<=11.1", - "typo3/flow": ">=1,<1.0.4|>=1.1,<1.1.1|>=2,<2.0.1|>=2.3,<2.3.16|>=3,<3.0.10|>=3.1,<3.1.7|>=3.2,<3.2.7|>=3.3,<3.3.5", - "typo3/neos": ">=1.1,<1.1.3|>=1.2,<1.2.13|>=2,<2.0.4", + "typo3/flow": ">=1,<1.0.4|>=1.1,<1.1.1|>=2,<2.0.1|>=2.3,<2.3.16|>=3,<3.0.12|>=3.1,<3.1.10|>=3.2,<3.2.13|>=3.3,<3.3.13|>=4,<4.0.6", + "typo3/neos": ">=1.1,<1.1.3|>=1.2,<1.2.13|>=2,<2.0.4|>=2.3,<2.3.99|>=3,<3.0.20|>=3.1,<3.1.18|>=3.2,<3.2.14|>=3.3,<3.3.23|>=4,<4.0.17|>=4.1,<4.1.16|>=4.2,<4.2.12|>=4.3,<4.3.3", "typo3/phar-stream-wrapper": ">=1,<2.1.1|>=3,<3.1.1", + "typo3/swiftmailer": ">=4.1,<4.1.99|>=5.4,<5.4.5", "typo3fluid/fluid": ">=2,<2.0.8|>=2.1,<2.1.7|>=2.2,<2.2.4|>=2.3,<2.3.7|>=2.4,<2.4.4|>=2.5,<2.5.11|>=2.6,<2.6.10", "ua-parser/uap-php": "<3.8", "usmanhalalit/pixie": "<1.0.3|>=2,<2.0.2", "verot/class.upload.php": "<=1.0.3|>=2,<=2.0.4", "vrana/adminer": "<4.7.9", "wallabag/tcpdf": "<6.2.22", + "wikimedia/parsoid": "<0.12.2", "willdurand/js-translation-bundle": "<2.1.1", "yii2mod/yii2-cms": "<1.9.2", "yiisoft/yii": ">=1.1.14,<1.1.15", @@ -1088,6 +1098,7 @@ "yiisoft/yii2-jui": "<2.0.4", "yiisoft/yii2-redis": "<2.0.8", "yourls/yourls": "<1.7.4", + "zendesk/zendesk_api_client_php": "<2.2.11", "zendframework/zend-cache": ">=2.4,<2.4.8|>=2.5,<2.5.3", "zendframework/zend-captcha": ">=2,<2.4.9|>=2.5,<2.5.2", "zendframework/zend-crypt": ">=2,<2.4.9|>=2.5,<2.5.2", @@ -1142,7 +1153,7 @@ "type": "tidelift" } ], - "time": "2021-04-06T18:11:53+00:00" + "time": "2021-05-02T09:01:19+00:00" } ], "aliases": [], @@ -1154,6 +1165,7 @@ "prefer-lowest": false, "platform": { "ext-json": "*", + "ext-curl": "*", "php": ">=5.6" }, "platform-dev": [], From eb200cfce2b5eed9f197cd8bd45afb7c682230b2 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Tue, 11 May 2021 11:19:06 +0200 Subject: [PATCH 214/280] init 203, added bLock on Queue #125 --- info.xml | 4 + version/203/adminmenu/info.php | 64 ++ version/203/adminmenu/orders.php | 238 +++++++ version/203/adminmenu/paymentmethods.php | 98 +++ version/203/adminmenu/tpl/_addon.tpl | 6 + version/203/adminmenu/tpl/info.tpl | 114 ++++ .../tpl/mollie-account-erstellen.png | Bin 0 -> 38998 bytes version/203/adminmenu/tpl/order.tpl | 344 ++++++++++ version/203/adminmenu/tpl/orders.tpl | 158 +++++ version/203/adminmenu/tpl/paymentmethods.tpl | 146 ++++ version/203/class/API.php | 78 +++ .../203/class/Checkout/AbstractCheckout.php | 621 ++++++++++++++++++ .../203/class/Checkout/AbstractResource.php | 18 + .../Exception/ResourceValidityException.php | 23 + version/203/class/Checkout/Order/Address.php | 44 ++ .../203/class/Checkout/Order/OrderLine.php | 225 +++++++ version/203/class/Checkout/OrderCheckout.php | 362 ++++++++++ .../203/class/Checkout/Payment/Address.php | 54 ++ version/203/class/Checkout/Payment/Amount.php | 72 ++ .../203/class/Checkout/PaymentCheckout.php | 209 ++++++ version/203/class/ExclusiveLock.php | 70 ++ version/203/class/Helper.php | 352 ++++++++++ version/203/class/Hook/AbstractHook.php | 13 + version/203/class/Hook/ApplePay.php | 56 ++ version/203/class/Hook/Checkbox.php | 60 ++ version/203/class/Hook/Queue.php | 129 ++++ version/203/class/Model/AbstractModel.php | 92 +++ version/203/class/Model/Customer.php | 19 + version/203/class/Model/Payment.php | 47 ++ version/203/class/Model/Queue.php | 42 ++ version/203/class/Model/Shipment.php | 28 + version/203/class/Mollie.php | 274 ++++++++ version/203/class/Queue.php | 180 +++++ version/203/class/Shipment.php | 318 +++++++++ version/203/class/Traits/Jsonable.php | 20 + version/203/class/Traits/Plugin.php | 25 + version/203/class/Traits/RequestData.php | 59 ++ version/203/frontend/.htaccess | 9 + version/203/frontend/131_globalinclude.php | 34 + version/203/frontend/132_headPostGet.php | 17 + version/203/frontend/140_smarty.php | 58 ++ version/203/frontend/180_checkbox.php | 18 + version/203/frontend/181_sync.php | 14 + version/203/frontend/210_storno.php | 17 + version/203/frontend/75_bestellungInDb.php | 17 + version/203/frontend/applepay.php | 18 + version/203/frontend/img/trust_eng.png | Bin 0 -> 15299 bytes version/203/frontend/img/trust_fre.png | Bin 0 -> 17319 bytes version/203/frontend/img/trust_ger.png | Bin 0 -> 15352 bytes version/203/frontend/tpl/applepay.tpl | 15 + version/203/paymentmethod/JTLMollie.php | 264 ++++++++ .../203/paymentmethod/JTLMollieApplePay.php | 15 + .../203/paymentmethod/JTLMollieBancontact.php | 8 + .../paymentmethod/JTLMollieBanktransfer.php | 28 + .../203/paymentmethod/JTLMollieBelfius.php | 8 + .../203/paymentmethod/JTLMollieCreditCard.php | 144 ++++ .../paymentmethod/JTLMollieDirectDebit.php | 27 + version/203/paymentmethod/JTLMollieEPS.php | 8 + .../203/paymentmethod/JTLMollieGiftcard.php | 27 + .../203/paymentmethod/JTLMollieGiropay.php | 8 + version/203/paymentmethod/JTLMollieIDEAL.php | 8 + .../203/paymentmethod/JTLMollieINGHomePay.php | 28 + version/203/paymentmethod/JTLMollieKBC.php | 13 + .../paymentmethod/JTLMollieKlarnaPayLater.php | 10 + .../paymentmethod/JTLMollieKlarnaSliceIt.php | 10 + version/203/paymentmethod/JTLMollieMyBank.php | 8 + version/203/paymentmethod/JTLMolliePayPal.php | 36 + .../paymentmethod/JTLMolliePaysafecard.php | 13 + .../203/paymentmethod/JTLMolliePrzelewy24.php | 15 + version/203/paymentmethod/JTLMollieSofort.php | 8 + .../img/method/Przelewy24@2x.png | Bin 0 -> 859 bytes .../paymentmethod/img/method/applepay@2x.png | Bin 0 -> 656 bytes .../img/method/bancontact@2x.png | Bin 0 -> 582 bytes .../img/method/banktransfer@2x.png | Bin 0 -> 801 bytes .../paymentmethod/img/method/belfius@2x.png | Bin 0 -> 377 bytes .../img/method/creditcard@2x.png | Bin 0 -> 3125 bytes .../img/method/directdebit@2x.png | Bin 0 -> 801 bytes .../203/paymentmethod/img/method/eps@2x.png | Bin 0 -> 536 bytes .../paymentmethod/img/method/giftcard@2x.png | Bin 0 -> 2218 bytes .../paymentmethod/img/method/giropay@2x.png | Bin 0 -> 602 bytes .../203/paymentmethod/img/method/ideal@2x.png | Bin 0 -> 845 bytes .../img/method/inghomepay@2x.png | Bin 0 -> 1118 bytes .../203/paymentmethod/img/method/kbc@2x.png | Bin 0 -> 799 bytes .../paymentmethod/img/method/klarna@2x.png | Bin 0 -> 896 bytes .../paymentmethod/img/method/mollie@2x.png | Bin 0 -> 5366 bytes .../paymentmethod/img/method/mybank@2x.png | Bin 0 -> 2111 bytes .../paymentmethod/img/method/paypal@2x.png | Bin 0 -> 626 bytes .../img/method/paysafecard@2x.png | Bin 0 -> 420 bytes .../paymentmethod/img/method/sofort@2x.png | Bin 0 -> 453 bytes .../paymentmethod/tpl/bestellabschluss.tpl | 26 + .../paymentmethod/tpl/mollieComponents.tpl | 147 +++++ version/203/sql/203.sql | 2 + version/203/tpl/_alerts.tpl | 10 + 93 files changed, 5750 insertions(+) create mode 100644 version/203/adminmenu/info.php create mode 100644 version/203/adminmenu/orders.php create mode 100644 version/203/adminmenu/paymentmethods.php create mode 100644 version/203/adminmenu/tpl/_addon.tpl create mode 100644 version/203/adminmenu/tpl/info.tpl create mode 100644 version/203/adminmenu/tpl/mollie-account-erstellen.png create mode 100644 version/203/adminmenu/tpl/order.tpl create mode 100644 version/203/adminmenu/tpl/orders.tpl create mode 100644 version/203/adminmenu/tpl/paymentmethods.tpl create mode 100644 version/203/class/API.php create mode 100644 version/203/class/Checkout/AbstractCheckout.php create mode 100644 version/203/class/Checkout/AbstractResource.php create mode 100644 version/203/class/Checkout/Exception/ResourceValidityException.php create mode 100644 version/203/class/Checkout/Order/Address.php create mode 100644 version/203/class/Checkout/Order/OrderLine.php create mode 100644 version/203/class/Checkout/OrderCheckout.php create mode 100644 version/203/class/Checkout/Payment/Address.php create mode 100644 version/203/class/Checkout/Payment/Amount.php create mode 100644 version/203/class/Checkout/PaymentCheckout.php create mode 100644 version/203/class/ExclusiveLock.php create mode 100644 version/203/class/Helper.php create mode 100644 version/203/class/Hook/AbstractHook.php create mode 100644 version/203/class/Hook/ApplePay.php create mode 100644 version/203/class/Hook/Checkbox.php create mode 100644 version/203/class/Hook/Queue.php create mode 100644 version/203/class/Model/AbstractModel.php create mode 100644 version/203/class/Model/Customer.php create mode 100644 version/203/class/Model/Payment.php create mode 100644 version/203/class/Model/Queue.php create mode 100644 version/203/class/Model/Shipment.php create mode 100644 version/203/class/Mollie.php create mode 100644 version/203/class/Queue.php create mode 100644 version/203/class/Shipment.php create mode 100644 version/203/class/Traits/Jsonable.php create mode 100644 version/203/class/Traits/Plugin.php create mode 100644 version/203/class/Traits/RequestData.php create mode 100644 version/203/frontend/.htaccess create mode 100644 version/203/frontend/131_globalinclude.php create mode 100644 version/203/frontend/132_headPostGet.php create mode 100644 version/203/frontend/140_smarty.php create mode 100644 version/203/frontend/180_checkbox.php create mode 100644 version/203/frontend/181_sync.php create mode 100644 version/203/frontend/210_storno.php create mode 100644 version/203/frontend/75_bestellungInDb.php create mode 100644 version/203/frontend/applepay.php create mode 100644 version/203/frontend/img/trust_eng.png create mode 100644 version/203/frontend/img/trust_fre.png create mode 100644 version/203/frontend/img/trust_ger.png create mode 100644 version/203/frontend/tpl/applepay.tpl create mode 100644 version/203/paymentmethod/JTLMollie.php create mode 100644 version/203/paymentmethod/JTLMollieApplePay.php create mode 100644 version/203/paymentmethod/JTLMollieBancontact.php create mode 100644 version/203/paymentmethod/JTLMollieBanktransfer.php create mode 100644 version/203/paymentmethod/JTLMollieBelfius.php create mode 100644 version/203/paymentmethod/JTLMollieCreditCard.php create mode 100644 version/203/paymentmethod/JTLMollieDirectDebit.php create mode 100644 version/203/paymentmethod/JTLMollieEPS.php create mode 100644 version/203/paymentmethod/JTLMollieGiftcard.php create mode 100644 version/203/paymentmethod/JTLMollieGiropay.php create mode 100644 version/203/paymentmethod/JTLMollieIDEAL.php create mode 100644 version/203/paymentmethod/JTLMollieINGHomePay.php create mode 100644 version/203/paymentmethod/JTLMollieKBC.php create mode 100644 version/203/paymentmethod/JTLMollieKlarnaPayLater.php create mode 100644 version/203/paymentmethod/JTLMollieKlarnaSliceIt.php create mode 100644 version/203/paymentmethod/JTLMollieMyBank.php create mode 100644 version/203/paymentmethod/JTLMolliePayPal.php create mode 100644 version/203/paymentmethod/JTLMolliePaysafecard.php create mode 100644 version/203/paymentmethod/JTLMolliePrzelewy24.php create mode 100644 version/203/paymentmethod/JTLMollieSofort.php create mode 100644 version/203/paymentmethod/img/method/Przelewy24@2x.png create mode 100644 version/203/paymentmethod/img/method/applepay@2x.png create mode 100644 version/203/paymentmethod/img/method/bancontact@2x.png create mode 100644 version/203/paymentmethod/img/method/banktransfer@2x.png create mode 100644 version/203/paymentmethod/img/method/belfius@2x.png create mode 100644 version/203/paymentmethod/img/method/creditcard@2x.png create mode 100644 version/203/paymentmethod/img/method/directdebit@2x.png create mode 100644 version/203/paymentmethod/img/method/eps@2x.png create mode 100644 version/203/paymentmethod/img/method/giftcard@2x.png create mode 100644 version/203/paymentmethod/img/method/giropay@2x.png create mode 100644 version/203/paymentmethod/img/method/ideal@2x.png create mode 100644 version/203/paymentmethod/img/method/inghomepay@2x.png create mode 100644 version/203/paymentmethod/img/method/kbc@2x.png create mode 100644 version/203/paymentmethod/img/method/klarna@2x.png create mode 100644 version/203/paymentmethod/img/method/mollie@2x.png create mode 100644 version/203/paymentmethod/img/method/mybank@2x.png create mode 100644 version/203/paymentmethod/img/method/paypal@2x.png create mode 100644 version/203/paymentmethod/img/method/paysafecard@2x.png create mode 100644 version/203/paymentmethod/img/method/sofort@2x.png create mode 100644 version/203/paymentmethod/tpl/bestellabschluss.tpl create mode 100644 version/203/paymentmethod/tpl/mollieComponents.tpl create mode 100644 version/203/sql/203.sql create mode 100644 version/203/tpl/_alerts.tpl diff --git a/info.xml b/info.xml index 548be26..2984237 100644 --- a/info.xml +++ b/info.xml @@ -57,6 +57,10 @@ 2021-05-06 + + 2021-05-11 + 203.sql + 75_bestellungInDb.php 131_globalinclude.php diff --git a/version/203/adminmenu/info.php b/version/203/adminmenu/info.php new file mode 100644 index 0000000..817c5db --- /dev/null +++ b/version/203/adminmenu/info.php @@ -0,0 +1,64 @@ +assign('defaultTabbertab', Helper::getAdminmenu('Info') + Helper::getAdminmenu('Support')); + 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 "
" . + "
" . + " " . + " Lizenz Informationen" . + ' ' . + '
' . + "
" . + " " . + " Update Informationen" . + ' ' . + '
' . + "
" . + " " . + " Plugin informationen" . + ' ' . + '
' . + '
'; + + 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/203/adminmenu/orders.php b/version/203/adminmenu/orders.php new file mode 100644 index 0000000..af6af9f --- /dev/null +++ b/version/203/adminmenu/orders.php @@ -0,0 +1,238 @@ +getModel()->kID)) { + Helper::addAlert('Zahlungserinnerung wurde verschickt.', 'success', 'orders'); + } else { + Helper::addAlert('Es ist ein Fehler aufgetreten, prüfe den Log.', 'danger', 'orders'); + } + } else { + Helper::addAlert('Bestellung konnte nicht geladen werden.', 'danger', 'orders'); + } + + + break; + + case "fetchable": + + if (array_key_exists('kBestellung', $_REQUEST) && ($checkout = AbstractCheckout::fromBestellung((int)$_REQUEST['kBestellung']))) { + if (AbstractCheckout::makeFetchable($checkout->getBestellung(), $checkout->getModel())) { + Helper::addAlert('Bestellung kann jetzt von der WAWI abgeholt werden.', 'success', 'orders'); + } else { + Helper::addAlert('Es ist ein Fehler aufgetreten, prüfe den Log.', 'danger', 'orders'); + } + } else { + Helper::addAlert('Bestellung konnte nicht geladen werden.', 'danger', 'orders'); + } + + break; + + 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); + + + 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', 'wb'); + + + fputcsv($out, [ + 'kBestellung', + 'OrderID', + 'Status (mollie)', + 'BestellNr', + 'Status (JTL)', + 'Mode', + 'OriginalOrderNumber', + 'Currency', + 'Amount', + 'Method', + 'PaymentID', + 'Created' + ]); + + + foreach ($orders as $order) { + $order = new ws_mollie\Model\Payment($order); + $checkout = AbstractCheckout::fromModel($order); + + $tmp = [ + 'kBestellung' => $order->kBestellung, + 'cOrderId' => $order->kID, + 'cStatus' => $checkout->getMollie() ? $checkout->getMollie()->status : $order->cStatus, + 'cBestellNr' => $checkout->getBestellung() ? $checkout->getBestellung()->cBestellNr : $order->cOrderNumber, + 'nStatus' => $checkout->getBestellung() ? $checkout->getBestellung()->cStatus : 0, + 'cMode' => $order->cMode, + 'cOriginalOrderNumber' => $checkout->getMollie() && isset($checkout->getMollie()->metadata->originalOrderNumber) ? $checkout->getMollie()->metadata->originalOrderNumber : '', + 'cCurrency' => $order->cCurrency, + 'fAmount' => $order->fAmount, + 'cMethod' => $order->cMethod, + 'cPaymentId' => $order->cTransactionId, + 'dCreated' => $order->dCreatedAt, + ]; + + try { + if ($checkout->getMollie() && $checkout->getMollie()->resource === 'order') { + foreach ($checkout->getMollie()->payments() as $payment) { + if ($payment->status === 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': + try { + if (!array_key_exists('id', $_REQUEST)) { + throw new InvalidArgumentException('Keine ID angegeben!', 'danger', 'orders'); + } + $checkout = AbstractCheckout::fromID($_REQUEST['id']); + if ($refund = $checkout::refund($checkout)) { + Helper::addAlert(sprintf('Bestellung wurde zurückerstattet (%s).', $refund->id), 'success', 'orders'); + } + goto order; + } catch (InvalidArgumentException $e) { + Helper::addAlert('Fehler: ' . $e->getMessage(), 'danger', 'orders'); + } catch (Exception $e) { + Helper::addAlert('Fehler: ' . $e->getMessage(), 'danger', 'orders'); + goto order; + } + break; + + case 'cancel': + try { + if (!array_key_exists('id', $_REQUEST)) { + throw new InvalidArgumentException('Keine ID angeben!'); + } + $checkout = AbstractCheckout::fromID($_REQUEST['id']); + if ($checkout::cancel($checkout)) { + Helper::addAlert('Bestellung wurde abgebrochen.', 'success', 'orders'); + } + goto order; + } catch (InvalidArgumentException $e) { + Helper::addAlert('Fehler: ' . $e->getMessage(), 'danger', 'orders'); + } catch (Exception $e) { + Helper::addAlert('Fehler: ' . $e->getMessage(), 'danger', 'orders'); + goto order; + } + break; + + case 'capture': + try { + if (!array_key_exists('id', $_REQUEST)) { + throw new InvalidArgumentException('Keine ID angeben!'); + } + $checkout = AbstractCheckout::fromID($_REQUEST['id']); + if ($shipmentId = OrderCheckout::capture($checkout)) { + Helper::addAlert(sprintf('Zahlung erfolgreich erfasst/versandt (%s).', $shipmentId), 'success', 'orders'); + } + goto order; + } catch (InvalidArgumentException $e) { + Helper::addAlert('Fehler: ' . $e->getMessage(), 'danger', 'orders'); + } catch (Exception $e) { + Helper::addAlert('Fehler: ' . $e->getMessage(), 'danger', 'orders'); + goto order; + } + break; + + case 'order': + order: + try { + + if (!array_key_exists('id', $_REQUEST)) { + throw new InvalidArgumentException('Keine ID angeben!'); + } + + $checkout = AbstractCheckout::fromID($_REQUEST['id']); + + if ($checkout instanceof OrderCheckout) { + Shop::Smarty()->assign('shipments', $checkout->getShipments()); + } + + Shop::Smarty()->assign('payment', $checkout->getModel()) + ->assign('oBestellung', $checkout->getBestellung()) + ->assign('order', $checkout->getMollie()) + ->assign('checkout', $checkout) + ->assign('logs', $checkout->getLogs()); + Shop::Smarty()->display($oPlugin->cAdminmenuPfad . '/tpl/order.tpl'); + return; + } catch (Exception $e) { + Helper::addAlert('Fehler: ' . $e->getMessage(), 'danger', 'orders'); + } + break; + } + } + + Mollie::fixZahlungsarten(); + + $checkouts = []; + $payments = Shop::DB()->executeQueryPrepared("SELECT * FROM xplugin_ws_mollie_payments WHERE kBestellung IS NOT NULL ORDER BY dCreatedAt DESC LIMIT 1000;", [], 2); + foreach ($payments as $i => $payment) { + $payment = new Payment($payment); + try { + $checkouts[$payment->kBestellung] = AbstractCheckout::fromModel($payment, false); + } catch (Exception $e) { + //Helper::addAlert($e->getMessage(), 'danger', 'orders'); + } + } + + Shop::Smarty()->assign('payments', $payments) + ->assign('checkouts', $checkouts) + ->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/203/adminmenu/paymentmethods.php b/version/203/adminmenu/paymentmethods.php new file mode 100644 index 0000000..d7e11c4 --- /dev/null +++ b/version/203/adminmenu/paymentmethods.php @@ -0,0 +1,98 @@ +setApiKey(Helper::getSetting("api_key")); + + $profile = $mollie->profiles->get('me'); + + $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}$/']]) ?: AbstractCheckout::getLocale(); + $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', + 'locale' => $locale + ]; + if ($amount && $currency) { + $params['amount'] = ['value' => number_format($amount, 2, '.', ''), 'currency' => $currency]; + if ($active) { + $params['includeWallets'] = 'applepay'; + //$params['resource'] = 'orders'; + } + } + + $allMethods = []; + if ($active) { + $_allMethods = $mollie->methods->allActive($params); + } else { + $_allMethods = $mollie->methods->allAvailable($params); + } + + $sessionLife = (int)ini_get('session.gc_maxlifetime'); + + /** @var Method $method */ + foreach ($_allMethods as $method) { + + $id = $method->id === 'creditcard' ? 'kreditkarte' : $method->id; + $key = "kPlugin_{$oPlugin->kPlugin}_mollie{$id}"; + + $class = null; + $shop = null; + $oClass = null; + + if (!in_array($id, ['voucher', 'giftcard', 'directdebit'], true) && array_key_exists($key, $oPlugin->oPluginZahlungsKlasseAssoc_arr)) { + $class = $oPlugin->oPluginZahlungsKlasseAssoc_arr[$key]; + include_once($oPlugin->cPluginPfad . 'paymentmethod/' . $class->cClassPfad); + /** @var JTLMollie $oClass */ + $oClass = new $class->cClassName($id); + } + if (array_key_exists($key, $oPlugin->oPluginZahlungsmethodeAssoc_arr)) { + $shop = $oPlugin->oPluginZahlungsmethodeAssoc_arr[$key]; + } + + + $maxExpiryDays = $oClass ? $oClass->getExpiryDays() : null; + $allMethods[$method->id] = (object)[ + 'mollie' => $method, + 'class' => $class, + 'oClass' => $oClass, + 'shop' => $shop, + 'maxExpiryDays' => $oClass ? $maxExpiryDays : null, + 'warning' => $oClass && ($maxExpiryDays * 24 * 60 * 60) > $sessionLife, + 'session' => round($sessionLife / 60 / 60, 2) . 'h' + ]; + + } + + 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/203/adminmenu/tpl/_addon.tpl b/version/203/adminmenu/tpl/_addon.tpl new file mode 100644 index 0000000..6539757 --- /dev/null +++ b/version/203/adminmenu/tpl/_addon.tpl @@ -0,0 +1,6 @@ + \ No newline at end of file diff --git a/version/203/adminmenu/tpl/info.tpl b/version/203/adminmenu/tpl/info.tpl new file mode 100644 index 0000000..2952fc6 --- /dev/null +++ b/version/203/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}
+
+
+
Changelog:
+
+ +
+
+ +
+
+ +
+
+
+ {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/203/adminmenu/tpl/mollie-account-erstellen.png b/version/203/adminmenu/tpl/mollie-account-erstellen.png new file mode 100644 index 0000000000000000000000000000000000000000..fc1819255ef725fa214cf2bf028cf3428794ecee GIT binary patch literal 38998 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 +

+ « + 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 isset($order->customerId)} + ID: + {$order->customerId} +
+ {/if} + {if isset($order->billingAddress, $order->billingAddress->organizationName)} + {$order->billingAddress->organizationName} + {elseif isset($order->billingAddress)} + {$order->billingAddress->title} {$order->billingAddress->givenName} {$order->billingAddress->familyName} + {/if} +
Mollie Checkout: + {if $order->getCheckoutURL()} + mollie.com/... + {else} + n/a + {/if} + RePay-URL: + +
+{if $order->id|strpos:"ord_" !== false && $order->payments()->count > 0} +

Zahlungen

+ + + + + + + + + + + + + + {foreach from=$order->payments() item=payment} + + + + + + + + + + + {/foreach} +
IDStatusMethodeAmountSettlementRefundedRemainingDetails
{$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} +
+
+{/if} + +
+ {if ($order->status === 'authorized' || $order->status === 'shipping') && $oBestellung->cStatus|intval >= 3} + + Zahlung erfassen1 + + {/if} + {if !$order->amountRefunded || ($order->amount->value > $order->amountRefunded->value)} + Rückerstatten2 + + {/if} + {if $order->isCancelable} + Abbrechen3 + + {/if} +
+ +{if $order->id|strpos:"ord_" !== false} +

Positionen:

+ + + + + + + + + + + + + + + + + {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} + + + + + + + + + + + + + {/foreach} + + + + + + + + + + +
StatusSKUNameTypAnzahlMwStSteuerNettoBrutto 
+ {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'} + abgebrochen + {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*} +
{$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.
+
+{/if} + +{if isset($shipments) && $shipments|count} +

Shipmets

+ + + + + + + + + + + {foreach from=$shipments item=shipment} + + + + + + + {/foreach} + +
Lieferschein Nr.Mollie IDCarrierCode
{$shipment->getLieferschein()->getLieferscheinNr()}{$shipment->getShipment()->id} + {if isset($shipment->getShipment()->tracking)} + {$shipment->getShipment()->tracking->carrier} + {else} + - + {/if} + {if isset($shipment->getShipment()->tracking)} + {if isset($shipment->getShipment()->tracking->url)} + + {$shipment->getShipment()->tracking->code} + + {else} + {$shipment->getShipment()->tracking->code} + {/if} + {else} + - + {/if} +
+{/if} + +

Log

+ + {foreach from=$logs item=log} + + + + + + + {/foreach} +
+ {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}
+ + diff --git a/version/203/adminmenu/tpl/orders.tpl b/version/203/adminmenu/tpl/orders.tpl new file mode 100644 index 0000000..8745a0c --- /dev/null +++ b/version/203/adminmenu/tpl/orders.tpl @@ -0,0 +1,158 @@ +{ws_mollie\Helper::showAlerts('orders')} + +{if $hasAPIKey == false} + + Jetzt kostenlos Mollie Account eröffnen! + +{else} + + + + + + + + + + + + + + + {foreach from=$checkouts item=checkout} + + + + + + + + + + + + + + + {/foreach} + +
BestellNr.IDMollie StatusJTL StatusBetragMethodeErstellt 
+ {if $checkout->getModel()->bSynced == false && $checkout->getBestellung()->cAbgeholt === 'Y'} + * + {/if} + {$checkout->getModel()->cOrderNumber} + {if $checkout->getModel()->cMode == 'test'} + TEST + {/if} + {if $checkout->getModel()->bLockTimeout} + LOCK TIMEOUT + {/if} + {if $checkout->getModel()->dReminder && $checkout->getModel()->dReminder !== '0000-00-00 00:00:00'} + getModel()->dReminder|strtotime}}"> + {/if} + + {$checkout->getModel()->kID} + + {if $checkout->getModel()->cStatus == 'created' || $checkout->getModel()->cStatus == 'open'} + erstellt + {elseif $checkout->getModel()->cStatus == 'pending'} + austehend + {elseif $checkout->getModel()->cStatus == 'paid'} + bezahlt + {elseif $checkout->getModel()->cStatus == 'authorized'} + autorisiert + {elseif $checkout->getModel()->cStatus == 'shipping'} + versendet + {elseif $checkout->getModel()->cStatus == 'completed'} + abgeschlossen + {elseif $checkout->getModel()->cStatus == 'expired'} + abgelaufen + {elseif $checkout->getModel()->cStatus == 'canceled'} + abgebrochen + {else} + Unbekannt: {$checkout->getModel()->cStatus} + {/if} + {if $checkout->getModel()->fAmountRefunded && $checkout->getModel()->fAmountRefunded == $checkout->getModel()->fAmount} + (total refund) + {elseif $checkout->getModel()->fAmountRefunded && $checkout->getModel()->fAmountRefunded > 0} + (partly refund) + {/if} + + + {if $checkout->getBestellung()->cStatus|intval == 1} + OFFEN + {elseif $checkout->getBestellung()->cStatus|intval == 2} + IN BEARBEITUNG + {elseif $checkout->getBestellung()->cStatus|intval == 3} + BEZAHLT + {elseif $checkout->getBestellung()->cStatus|intval == 4} + VERSANDT + {elseif $checkout->getBestellung()->cStatus|intval == 5} + TEILVERSANDT + {elseif $checkout->getBestellung()->cStatus|intval == -1} + STORNO + {else} + n/a + {/if} + {$checkout->getModel()->fAmount|number_format:2:',':''} {$checkout->getModel()->cCurrency}{$checkout->getModel()->cMethod}{"d. M Y H:i"|date:{$checkout->getModel()->dCreatedAt|strtotime}} +
+ +
+ {if $checkout->getModel()->bSynced == false && $checkout->getBestellung()->cAbgeholt === 'Y'} + + {/if} + {if $checkout->remindable()} + + {/if} +
+
+
+ {if $payments|count > 900} +
Hier werden nur die letzten 1000 Ergebnisse angezeigt.
+ {/if} + + +
+
+

Export:

+
+ +
+ + + + + +
+
+ +{/if} + diff --git a/version/203/adminmenu/tpl/paymentmethods.tpl b/version/203/adminmenu/tpl/paymentmethods.tpl new file mode 100644 index 0000000..9f0dbf1 --- /dev/null +++ b/version/203/adminmenu/tpl/paymentmethods.tpl @@ -0,0 +1,146 @@ +

Account Status

+ + + + + + + {if $profile->review} + + + {/if} + {if $profile->_links->checkoutPreviewUrl->href} + + {/if} + + +
Mode:{$profile->mode}Status:{$profile->status}Review:{$profile->review->status} + Checkout + Preview + + Mollie Dashboard +
+
+
+
+ + +
+ + + +
+
+ + +
+
+ + +
+
+ + + reset +
+
+
+
+{if $allMethods && $allMethods|count} + + + + + + + + + + + + {foreach from=$allMethods item=method} + + + + + + + + {/foreach} + +
BildName / IDInfoPreiseLimits
{$method->mollie->description|utf8_decode} + {if $method->mollie->status === 'activated'} + + {else} + + {/if} + {$method->mollie->description|utf8_decode}
+ {$method->mollie->id} +
+ {if $method->shop && $method->oClass} + + {if intval($method->shop->nWaehrendBestellung) === 1} + Zahlung VOR Bestellabschluss nicht unterstützt! + {/if} + + {*if $method->shop->nWaehrendBestellung} + Zahlung + VOR + Bestellabschluss + {if $method->warning} +
+ + + Gültigkeit ist länger als Session-Laufzeit ({$method->session}). + + {/if} + {else} + Zahlung + NACH + Bestellabschluss + {/if*} +
+ Gültigkeit + : {$method->maxExpiryDays} Tage + + {else} + Derzeit nicht unterstützt. + {/if} +
+
    + {foreach from=$method->mollie->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->mollie->minimumAmount}{$method->mollie->minimumAmount->value} {$method->mollie->minimumAmount->currency}{else}n/a{/if} +
+ Max: {if $method->mollie->maximumAmount}{$method->mollie->maximumAmount->value} {$method->mollie->maximumAmount->currency}{else}n/a{/if} +
+{else} +
Es konnten keine Methoden abgerufen werden.
+{/if} \ No newline at end of file diff --git a/version/203/class/API.php b/version/203/class/API.php new file mode 100644 index 0000000..3ed4f27 --- /dev/null +++ b/version/203/class/API.php @@ -0,0 +1,78 @@ +test = $test === null ? self::getMode() : $test; + } + + /** + * @return bool + */ + public static function getMode() + { + require_once PFAD_ROOT . PFAD_ADMIN . PFAD_INCLUDES . 'benutzerverwaltung_inc.php'; + return self::Plugin()->oPluginEinstellungAssoc_arr["testAsAdmin"] === 'Y' && Shop::isAdmin(); + } + + /** + * @return MollieApiClient + * @throws ApiException + * @throws IncompatiblePlatform + */ + public function Client() + { + if (!$this->client) { + $this->client = new MollieApiClient(new Client([ + RequestOptions::VERIFY => CaBundle::getBundledCaBundlePath(), + RequestOptions::TIMEOUT => 60 + ])); + $this->client->setApiKey($this->isTest() ? self::Plugin()->oPluginEinstellungAssoc_arr['test_api_key'] : self::Plugin()->oPluginEinstellungAssoc_arr['api_key']) + ->addVersionString('JTL-Shop/' . JTL_VERSION . JTL_MINOR_VERSION) + ->addVersionString('ws_mollie/' . self::Plugin()->nVersion); + } + return $this->client; + } + + /** + * @return bool + */ + public function isTest() + { + return $this->test; + } + + +} \ No newline at end of file diff --git a/version/203/class/Checkout/AbstractCheckout.php b/version/203/class/Checkout/AbstractCheckout.php new file mode 100644 index 0000000..ca15646 --- /dev/null +++ b/version/203/class/Checkout/AbstractCheckout.php @@ -0,0 +1,621 @@ + ['lang' => 'de', 'country' => ['DE', 'AT', 'CH']], + 'fre' => ['lang' => 'fr', 'country' => ['BE', 'FR']], + 'dut' => ['lang' => 'nl', 'country' => ['BE', 'NL']], + 'spa' => ['lang' => 'es', 'country' => ['ES']], + 'ita' => ['lang' => 'it', 'country' => ['IT']], + 'pol' => ['lang' => 'pl', 'country' => ['PL']], + 'hun' => ['lang' => 'hu', 'country' => ['HU']], + 'por' => ['lang' => 'pt', 'country' => ['PT']], + 'nor' => ['lang' => 'nb', 'country' => ['NO']], + 'swe' => ['lang' => 'sv', 'country' => ['SE']], + 'fin' => ['lang' => 'fi', 'country' => ['FI']], + 'dan' => ['lang' => 'da', 'country' => ['DK']], + 'ice' => ['lang' => 'is', 'country' => ['IS']], + 'eng' => ['lang' => 'en', 'country' => ['GB', 'US']], + ]; + /** + * @var \Mollie\Api\Resources\Customer|null + */ + protected $customer; + + /** + * @var string + */ + private $hash; + /** + * @var API + */ + private $api; + /** + * @var JTLMollie + */ + private $paymentMethod; + /** + * @var Bestellung + */ + private $oBestellung; + /** + * @var Payment + */ + private $model; + + /** + * AbstractCheckout constructor. + * @param $oBestellung + * @param null $api + */ + public function __construct(Bestellung $oBestellung, $api = null) + { + $this->api = $api; + $this->oBestellung = $oBestellung; + } + + /** + * @param int $kBestellung + * @param bool $checkZA + * @return bool + */ + public static function isMollie($kBestellung, $checkZA = false) + { + if ($checkZA) { + $res = Shop::DB()->executeQueryPrepared('SELECT * FROM tzahlungsart WHERE cModulId LIKE :cModulId AND kZahlungsart = :kZahlungsart', [ + ':kZahlungsart' => $kBestellung, + ':cModulId' => 'kPlugin_' . self::Plugin()->kPlugin . '_%' + ], 1); + return $res ? true : false; + } + + return ($res = Shop::DB()->executeQueryPrepared('SELECT kId FROM xplugin_ws_mollie_payments WHERE kBestellung = :kBestellung;', [ + ':kBestellung' => $kBestellung, + ], 1)) && $res->kId; + } + + /** + * @param $kBestellung + * @return OrderCheckout|PaymentCheckout + * * @throws RuntimeException + */ + public static function fromBestellung($kBestellung) + { + if ($model = Payment::fromID($kBestellung, 'kBestellung')) { + return self::fromModel($model); + } + throw new RuntimeException(sprintf('Error loading Order for Bestellung: %s', $kBestellung)); + } + + /** + * @param $model + * @return OrderCheckout|PaymentCheckout + * @throws RuntimeException + */ + public static function fromModel($model, $bFill = true) + { + if (!$model) { + throw new RuntimeException(sprintf('Error loading Order for Model: %s', print_r($model, 1))); + } + + $oBestellung = new Bestellung($model->kBestellung, $bFill); + if (!$oBestellung->kBestellung) { + throw new RuntimeException(sprintf('Error loading Bestellung: %s', $model->kBestellung)); + } + + if (strpos($model->kID, 'tr_') !== false) { + $self = new PaymentCheckout($oBestellung); + } else { + $self = new OrderCheckout($oBestellung); + } + + $self->setModel($model); + return $self; + } + + public static function sendReminders() + { + $reminder = (int)self::Plugin()->oPluginEinstellungAssoc_arr['reminder']; + + if (!$reminder) { + return; + } + + $sql = "SELECT p.kId FROM xplugin_ws_mollie_payments p JOIN tbestellung b ON b.kBestellung = p.kBestellung " + . "WHERE (p.dReminder IS NULL OR p.dReminder = '0000-00-00 00:00:00') " + . "AND p.dCreatedAt < NOW() - INTERVAL :d HOUR AND p.dCreatedAt > NOW() - INTERVAL 7 DAY " + . "AND p.cStatus IN ('created','open', 'expired', 'failed', 'canceled') AND NOT b.cStatus = '-1'"; + + $remindables = Shop::DB()->executeQueryPrepared($sql, [ + ':d' => $reminder + ], 2); + foreach ($remindables as $remindable) { + try { + self::sendReminder($remindable->kId); + } catch (Exception $e) { + Jtllog::writeLog("AbstractCheckout::sendReminders: " . $e->getMessage()); + } + } + } + + public static function sendReminder($kID) + { + + $checkout = self::fromID($kID); + $return = true; + try { + $repayURL = Shop::getURL() . '/?m_pay=' . md5($checkout->getModel()->kID . '-' . $checkout->getBestellung()->kBestellung); + + $data = new stdClass(); + $data->tkunde = new Kunde($checkout->getBestellung()->oKunde->kKunde); + if ($data->tkunde->kKunde) { + + $data->Bestellung = $checkout->getBestellung(); + $data->PayURL = $repayURL; + $data->Amount = gibPreisStringLocalized($checkout->getModel()->fAmount, $checkout->getBestellung()->Waehrung); //Preise::getLocalizedPriceString($order->getAmount(), Currency::fromISO($order->getCurrency()), false); + + require_once PFAD_ROOT . PFAD_INCLUDES . 'mailTools.php'; + + $mail = new stdClass(); + $mail->toEmail = $data->tkunde->cMail; + $mail->toName = trim((isset($data->tKunde->cVorname) + ? $data->tKunde->cVorname + : '') . ' ' . ( + isset($data->tKunde->cNachname) + ? $data->tKunde->cNachname + : '' + )) ?: $mail->toEmail; + $data->mail = $mail; + if (!($sentMail = sendeMail('kPlugin_' . self::Plugin()->kPlugin . '_zahlungserinnerung', $data))) { + $checkout->Log(sprintf("Zahlungserinnerung konnte nicht versand werden: %s\n%s", isset($sentMail->cFehler) ?: print_r($sentMail, 1), print_r($data, 1)), LOGLEVEL_ERROR); + $return = false; + } else { + $checkout->Log(sprintf("Zahlungserinnerung für %s verschickt.", $checkout->getBestellung()->cBestellNr)); + } + } else { + $checkout->Log("Kunde '{$checkout->getBestellung()->oKunde->kKunde}' nicht gefunden.", LOGLEVEL_ERROR); + } + } catch (Exception $e) { + $checkout->Log(sprintf("AbstractCheckout::sendReminder: Zahlungserinnerung für %s fehlgeschlagen: %s", $checkout->getBestellung()->cBestellNr, $e->getMessage())); + $return = false; + } + $checkout->getModel()->dReminder = date('Y-m-d H:i:s'); + $checkout->getModel()->save(); + return $return; + } + + /** + * @param $id + * @return OrderCheckout|PaymentCheckout + * @throws RuntimeException + */ + public static function fromID($id) + { + if ($model = Payment::fromID($id)) { + return static::fromModel($model); + } + throw new RuntimeException(sprintf('Error loading Order: %s', $id)); + } + + /** + * @param AbstractCheckout $checkout + * @return \Mollie\Api\Resources\BaseResource|\Mollie\Api\Resources\Refund + * @throws ApiException + */ + public static function refund(AbstractCheckout $checkout) + { + if ($checkout->getMollie()->resource === 'order') { + /** @var Order $order */ + $order = $checkout->getMollie(); + if (in_array($order->status, [OrderStatus::STATUS_CANCELED, OrderStatus::STATUS_EXPIRED, OrderStatus::STATUS_CREATED], true)) { + throw new RuntimeException('Bestellung kann derzeit nicht zurückerstattet werden.'); + } + $refund = $order->refundAll(); + $checkout->Log(sprintf('Bestellung wurde manuell zurückerstattet: %s', $refund->id)); + return $refund; + } + if ($checkout->getMollie()->resource === 'payment') { + /** @var \Mollie\Api\Resources\Payment $payment */ + $payment = $checkout->getMollie(); + if (in_array($payment->status, [PaymentStatus::STATUS_CANCELED, PaymentStatus::STATUS_EXPIRED, PaymentStatus::STATUS_OPEN], true)) { + throw new RuntimeException('Zahlung kann derzeit nicht zurückerstattet werden.'); + } + $refund = $checkout->API()->Client()->payments->refund($checkout->getMollie(), ['amount' => $checkout->getMollie()->amount]); + $checkout->Log(sprintf('Zahlung wurde manuell zurückerstattet: %s', $refund->id)); + return $refund; + } + throw new RuntimeException(sprintf('Unbekannte Resource: %s', $checkout->getMollie()->resource)); + } + + /** + * @param false $force + * @return Order|\Mollie\Api\Resources\Payment|null + */ + abstract public function getMollie($force = false); + + public function Log($msg, $level = LOGLEVEL_NOTICE) + { + $data = ''; + if ($this->getBestellung()) { + $data .= '#' . $this->getBestellung()->kBestellung; + } + if ($this->getMollie()) { + $data .= '$' . $this->getMollie()->id; + } + ZahlungsLog::add($this->PaymentMethod()->moduleID, "[" . microtime(true) . " - " . $_SERVER['PHP_SELF'] . "] " . $msg, $data, $level); + return $this; + } + + /** + * @return Bestellung + */ + public function getBestellung() + { + if (!$this->oBestellung && $this->getModel()->kBestellung) { + $this->oBestellung = new Bestellung($this->getModel()->kBestellung, true); + } + return $this->oBestellung; + } + + /** + * @return Payment + */ + public function getModel() + { + if (!$this->model) { + $this->model = Payment::fromID($this->oBestellung->kBestellung, 'kBestellung'); + } + return $this->model; + } + + /** + * @param $model + * @return $this + */ + protected function setModel($model) + { + if (!$this->model) { + $this->model = $model; + } else { + throw new RuntimeException('Model already set.'); + } + return $this; + } + + /** + * @return JTLMollie + */ + public function PaymentMethod() + { + if (!$this->paymentMethod) { + if ($this->getBestellung()->Zahlungsart && strpos($this->getBestellung()->Zahlungsart->cModulId, "kPlugin_{$this::Plugin()->kPlugin}_") !== false) { + $this->paymentMethod = PaymentMethod::create($this->getBestellung()->Zahlungsart->cModulId); + } else { + $this->paymentMethod = PaymentMethod::create("kPlugin_{$this::Plugin()->kPlugin}_mollie"); + } + } + /** @noinspection PhpIncompatibleReturnTypeInspection */ + return $this->paymentMethod; + } + + /** + * @return API + */ + public function API() + { + if (!$this->api) { + if ($this->getModel()->kID) { + $this->api = new API($this->getModel()->cMode === 'test'); + } else { + $this->api = new API(API::getMode()); + } + } + return $this->api; + } + + /** + * @param $checkout + * @return Order|\Mollie\Api\Resources\Payment + * @throws ApiException + */ + public static function cancel($checkout) + { + if ($checkout instanceof OrderCheckout) { + return OrderCheckout::cancel($checkout); + } + if ($checkout instanceof PaymentCheckout) { + return PaymentCheckout::cancel($checkout); + } + throw new RuntimeException('AbstractCheckout::cancel: Invalid Checkout!'); + } + + /** + * @return array|bool|int|object|null + */ + public function getLogs() + { + return 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' => '%#' . ($this->getBestellung()->kBestellung ?: '##') . '%', + ':cBestellNr' => '%§' . ($this->getBestellung()->cBestellNr ?: '§§') . '%', + ':MollieID' => '%$' . ($this->getMollie()->id ?: '$$') . '%', + ], 2); + } + + /** + * @return bool + */ + public function remindable() + { + return (int)$this->getBestellung()->cStatus !== BESTELLUNG_STATUS_STORNO && !in_array($this->getModel()->cStatus, [PaymentStatus::STATUS_PAID, PaymentStatus::STATUS_AUTHORIZED, PaymentStatus::STATUS_PENDING, OrderStatus::STATUS_COMPLETED, OrderStatus::STATUS_SHIPPING], true); + } + + /** + * @return string + */ + public function LogData() + { + + $data = ''; + if ($this->getBestellung()->kBestellung) { + $data .= '#' . $this->getBestellung()->kBestellung; + } + if ($this->getMollie()) { + $data .= '$' . $this->getMollie()->id; + } + + return $data; + } + + /** + * @return \Mollie\Api\Resources\Customer|null + * @todo: Kunde wieder löschbar machen ?! + */ + public function getCustomer($createOrUpdate = false) + { + if (!$this->customer) { + $customerModel = Customer::fromID($this->getBestellung()->oKunde->kKunde, 'kKunde'); + if ($customerModel->customerId) { + try { + $this->customer = $this->API()->Client()->customers->get($customerModel->customerId); + } catch (ApiException $e) { + $this->Log(sprintf("Fehler beim laden des Mollie Customers %s (kKunde: %d): %s", $customerModel->customerId, $customerModel->kKunde, $e->getMessage()), LOGLEVEL_ERROR); + } + } + + if ($createOrUpdate) { + $oKunde = $this->getBestellung()->oKunde; + + $customer = [ + 'name' => trim($oKunde->cVorname . ' ' . $oKunde->cNachname), + 'email' => $oKunde->cMail, + 'locale' => self::getLocale($_SESSION['cISOSprache'], $oKunde->cLand), + 'metadata' => (object)[ + 'kKunde' => $oKunde->kKunde, + 'kKundengruppe' => $oKunde->kKundengruppe, + 'cKundenNr' => $oKunde->cKundenNr, + ], + ]; + + if ($this->customer) { // UPDATE + + $this->customer->name = $customer['name']; + $this->customer->email = $customer['email']; + $this->customer->locale = $customer['locale']; + $this->customer->metadata = $customer['metadata']; + + try { + $this->customer->update(); + } catch (Exception $e) { + $this->Log(sprintf("Fehler beim aktualisieren des Mollie Customers %s: %s\n%s", $this->customer->id, $e->getMessage(), print_r($customer, 1)), LOGLEVEL_ERROR); + } + + + } else { // create + + try { + $this->customer = $this->API()->Client()->customers->create($customer); + $customerModel->kKunde = $oKunde->kKunde; + $customerModel->customerId = $this->customer->id; + $customerModel->save(); + $this->Log(sprintf("Customer '%s' für Kunde %s (%d) bei Mollie angelegt.", $this->customer->id, $this->customer->name, $this->getBestellung()->kKunde)); + } catch (Exception $e) { + $this->Log(sprintf("Fehler beim anlegen eines Mollie Customers: %s\n%s", $e->getMessage(), print_r($customer, 1)), LOGLEVEL_ERROR); + } + } + } + } + return $this->customer; + } + + public static function getLocale($cISOSprache = null, $country = null) + { + + if ($cISOSprache === null) { + $cISOSprache = gibStandardsprache()->cISO; + } + if (array_key_exists($cISOSprache, self::$localeLangs)) { + $locale = self::$localeLangs[$cISOSprache]['lang']; + if ($country && is_array(self::$localeLangs[$cISOSprache]['country']) && in_array($country, self::$localeLangs[$cISOSprache]['country'], true)) { + $locale .= '_' . strtoupper($country); + } else { + $locale .= '_' . self::$localeLangs[$cISOSprache]['country'][0]; + } + return $locale; + } + + return self::Plugin()->oPluginEinstellungAssoc_arr['fallbackLocale']; + } + + abstract public function cancelOrRefund($force = false); + + /** + * @param array $paymentOptions + * @return Payment|Order + */ + abstract public function create(array $paymentOptions = []); + + /** + * @param null $hash + */ + public function handleNotification($hash = null) + { + if (!$this->getHash()) { + $this->getModel()->cHash = $hash; + } + + $this->updateModel()->saveModel(); + if (!$this->getBestellung()->dBezahltDatum || $this->getBestellung()->dBezahltDatum === '0000-00-00') { + if ($incoming = $this->getIncomingPayment()) { + $this->PaymentMethod()->addIncomingPayment($this->getBestellung(), $incoming); + + $this->PaymentMethod()->setOrderStatusToPaid($this->getBestellung()); + static::makeFetchable($this->getBestellung(), $this->getModel()); + $this->PaymentMethod()->deletePaymentHash($this->getHash()); + $this->Log(sprintf("Checkout::handleNotification: Bestellung '%s' als bezahlt markiert: %.2f %s", $this->getBestellung()->cBestellNr, (float)$incoming->fBetrag, $incoming->cISO)); + + $oZahlungsart = Shop::DB()->selectSingleRow('tzahlungsart', 'cModulId', $this->PaymentMethod()->moduleID); + if ($oZahlungsart && (int)$oZahlungsart->nMailSenden === 1) { + require_once PFAD_ROOT . 'includes/mailTools.php'; + $this->PaymentMethod()->sendConfirmationMail($this->getBestellung()); + } + if (!$this->completlyPaid()) { + $this->Log(sprintf("Checkout::handleNotification: Bestellung '%s': nicht komplett bezahlt: %.2f %s", $this->getBestellung()->cBestellNr, (float)$incoming->fBetrag, $incoming->cISO), LOGLEVEL_ERROR); + } + } + } + } + + /** + * @return string + */ + public function getHash() + { + if ($this->getModel()->cHash) { + return $this->getModel()->cHash; + } + if (!$this->hash) { + $this->hash = $this->PaymentMethod()->generateHash($this->oBestellung); + } + return $this->hash; + } + + /** + * @return bool + */ + public function saveModel() + { + return $this->getModel()->save(); + } + + /** + * @return $this + */ + public function updateModel() + { + + if ($this->getMollie()) { + $this->getModel()->kID = $this->getMollie()->id; + $this->getModel()->cLocale = $this->getMollie()->locale; + $this->getModel()->fAmount = (float)$this->getMollie()->amount->value; + $this->getModel()->cMethod = $this->getMollie()->method; + $this->getModel()->cCurrency = $this->getMollie()->amount->currency; + $this->getModel()->cStatus = $this->getMollie()->status; + if ($this->getMollie()->amountRefunded) { + $this->getModel()->fAmountRefunded = $this->getMollie()->amountRefunded->value; + } + if ($this->getMollie()->amountCaptured) { + $this->getModel()->fAmountCaptured = $this->getMollie()->amountCaptured->value; + } + $this->getModel()->cMode = $this->getMollie()->mode ?: null; + $this->getModel()->cRedirectURL = $this->getMollie()->redirectUrl; + $this->getModel()->cWebhookURL = $this->getMollie()->webhookUrl; + $this->getModel()->cCheckoutURL = $this->getMollie()->getCheckoutUrl(); + } + + $this->getModel()->kBestellung = $this->getBestellung()->kBestellung; + $this->getModel()->cOrderNumber = $this->getBestellung()->cBestellNr; + $this->getModel()->cHash = $this->getHash(); + + $this->getModel()->bSynced = $this->getModel()->bSynced !== null ? $this->getModel()->bSynced : Helper::getSetting('onlyPaid') !== 'Y'; + return $this; + } + + /** + * @return stdClass + */ + abstract public function getIncomingPayment(); + + /** + * @param Bestellung $oBestellung + * @param Payment $model + * @return bool + */ + public static function makeFetchable(Bestellung $oBestellung, Payment $model) + { + // TODO: force ? + if ($oBestellung->cAbgeholt === 'Y' && !$model->bSynced) { + Shop::DB()->update('tbestellung', 'kBestellung', $oBestellung->kBestellung, (object)['cAbgeholt' => 'N']); + } + $model->bSynced = true; + try { + return $model->save(); + } catch (Exception $e) { + Jtllog::writeLog(sprintf("Fehler beim speichern des Models: %s / Bestellung: %s", $model->kID, $oBestellung->cBestellNr)); + } + return false; + } + + /** + * @return bool + */ + public function completlyPaid() + { + + if ($row = Shop::DB()->executeQueryPrepared("SELECT SUM(fBetrag) as fBetragSumme FROM tzahlungseingang WHERE kBestellung = :kBestellung", [ + ':kBestellung' => $this->getBestellung()->kBestellung + ], 1)) { + return $row->fBetragSumme >= round($this->getBestellung()->fGesamtsumme * (float)$this->getBestellung()->fWaehrungsFaktor, 2); + } + return false; + + } + + /** + * @return string + */ + public function getRepayURL() + { + return Shop::getURL(true) . '/?m_pay=' . md5($this->getModel()->kID . '-' . $this->getBestellung()->kBestellung); + } + +} \ No newline at end of file diff --git a/version/203/class/Checkout/AbstractResource.php b/version/203/class/Checkout/AbstractResource.php new file mode 100644 index 0000000..7ca9813 --- /dev/null +++ b/version/203/class/Checkout/AbstractResource.php @@ -0,0 +1,18 @@ +title = trim(($address->cAnrede === 'm' ? Shop::Lang()->get('mr') : Shop::Lang()->get('mrs')) . ' ' . $address->cTitel) ?: null; + $resource->givenName = $address->cVorname; + $resource->familyName = $address->cNachname; + $resource->email = $address->cMail ?: null; + + if ($organizationName = trim($address->cFirma)) { + $resource->organizationName = $organizationName; + } + + // Validity-Check + // TODO: Phone, with E.164 check + // TODO: Is Email-Format Check needed? + if (!$resource->givenName || !$resource->familyName || !$resource->email) { + throw ResourceValidityException::trigger(ResourceValidityException::ERROR_REQUIRED, ['givenName', 'familyName', 'email'], $resource); + } + return $resource; + } + +} \ No newline at end of file diff --git a/version/203/class/Checkout/Order/OrderLine.php b/version/203/class/Checkout/Order/OrderLine.php new file mode 100644 index 0000000..7fe7911 --- /dev/null +++ b/version/203/class/Checkout/Order/OrderLine.php @@ -0,0 +1,225 @@ +totalAmount->value; + } + if (abs($sum - (float)$amount->value) > 0) { + $diff = (round((float)$amount->value - $sum, 2)); + if ($diff !== 0.0) { + $line = new self(); + $line->type = $diff > 0 ? OrderLineType::TYPE_SURCHARGE : OrderLineType::TYPE_DISCOUNT; + // TODO: Translation needed? + $line->name = 'Rundungsausgleich'; + $line->quantity = 1; + $line->unitPrice = Amount::factory($diff, $currency); + $line->totalAmount = Amount::factory($diff, $currency); + $line->vatRate = "0.00"; + $line->vatAmount = Amount::factory(0, $currency); + return $line; + } + } + return null; + } + + /** + * @param Bestellung $oBestellung + * @return OrderLine + */ + public static function getCredit(Bestellung $oBestellung) + { + $line = new self(); + $line->type = OrderLineType::TYPE_STORE_CREDIT; + $line->name = 'Guthaben'; + $line->quantity = 1; + // TODO: check currency of Guthaben + $line->unitPrice = Amount::factory($oBestellung->fGuthaben, $oBestellung->Waehrung->cISO); + $line->totalAmount = $line->unitPrice; + $line->vatRate = "0.00"; + $line->vatAmount = Amount::factory(0, $oBestellung->Waehrung->cISO); + + return $line; + } + + /** + * @param stdClass|WarenkorbPos $oPosition + * @param null $currency + * @return OrderLine + */ + public static function factory($oPosition, $currency = null) + { + if (!$oPosition) { + throw new RuntimeException('$oPosition invalid:', print_r($oPosition)); + } + + $resource = new static(); + + $resource->fill($oPosition, $currency); + + // Validity Check + if (!$resource->name || !$resource->quantity || !$resource->unitPrice || !$resource->totalAmount + || !$resource->vatRate || !$resource->vatAmount) { + throw ResourceValidityException::trigger(ResourceValidityException::ERROR_REQUIRED, + ['name', 'quantity', 'unitPrice', 'totalAmount', 'vatRate', 'vatAmount'], $resource); + } + + return $resource; + + } + + /** + * @param WarenkorbPos|stdClass $oPosition + * @param null|stdClass $currency + * @return $this + * @todo Setting for Fraction handling needed? + */ + protected function fill($oPosition, $currency = null) + { + + if (!$currency) { + $currency = Amount::FallbackCurrency(); + } + + $isKupon = (int)$oPosition->nPosTyp === (int)C_WARENKORBPOS_TYP_KUPON; + $isFrac = fmod($oPosition->nAnzahl, 1) !== 0.0; + + // Kupon? set vatRate to 0 and adjust netto + $vatRate = $isKupon ? 0 : (float)$oPosition->fMwSt / 100; + $netto = $isKupon ? round($oPosition->fPreis * (1 + $vatRate), 4) : round($oPosition->fPreis, 4); + + // Fraction? transform, as it were 1, and set quantity to 1 + $netto = round(($isFrac ? $netto * (float)$oPosition->nAnzahl : $netto) * $currency->fFaktor, 4); + $this->quantity = $isFrac ? 1 : (int)$oPosition->nAnzahl; + + // Fraction? include quantity and unit in name + $this->name = $isFrac ? sprintf("%s (%.2f %s)", $oPosition->cName, (float)$oPosition->nAnzahl, $oPosition->cEinheit) : $oPosition->cName; + + $this->mapType($oPosition->nPosTyp); + + //$unitPriceNetto = round(($currency->fFaktor * $netto), 4); + + $this->unitPrice = Amount::factory(round($netto * (1 + $vatRate), 2), $currency->cISO, false); + $this->totalAmount = Amount::factory(round($this->quantity * $this->unitPrice->value, 2), $currency->cISO, false); + + $this->vatRate = number_format($vatRate * 100, 2); + $this->vatAmount = Amount::factory(round($this->totalAmount->value - ($this->totalAmount->value / (1 + $vatRate)), 2), $currency->cISO, false); + + $metadata = []; + + // Is Artikel ? + if (isset($oPosition->Artikel)) { + $this->sku = $oPosition->Artikel->cArtNr; + $metadata['kArtikel'] = $oPosition->kArtikel; + if ($oPosition->cUnique !== '') { + $metadata['cUnique'] = utf8_encode($oPosition->cUnique); + } + } + + if (isset($oPosition->WarenkorbPosEigenschaftArr) && is_array($oPosition->WarenkorbPosEigenschaftArr) && count($oPosition->WarenkorbPosEigenschaftArr)) { + $metadata['properties'] = []; + /** @var WarenkorbPosEigenschaft $warenkorbPosEigenschaft */ + foreach ($oPosition->WarenkorbPosEigenschaftArr as $warenkorbPosEigenschaft) { + $metadata['properties'][] = [ + 'kEigenschaft' => (int)$warenkorbPosEigenschaft->kEigenschaft, + 'kEigenschaftWert' => (int)$warenkorbPosEigenschaft->kEigenschaftWert, + 'name' => utf8_encode($warenkorbPosEigenschaft->cEigenschaftName), + 'value' => utf8_encode($warenkorbPosEigenschaft->cEigenschaftWertName), + ]; + if (strlen(json_encode($metadata)) > 1000) { + array_pop($metadata['properties']); + break; + } + } + + } + if (json_encode($metadata) !== false) { + $this->metadata = $metadata; + } + + return $this; + + + } + + /** + * @param $nPosTyp + * @return OrderLine + */ + protected function mapType($nPosTyp) + { + switch ($nPosTyp) { + case C_WARENKORBPOS_TYP_ARTIKEL: + case C_WARENKORBPOS_TYP_GRATISGESCHENK: + // TODO: digital / Download Artikel? + $this->type = OrderLineType::TYPE_PHYSICAL; + return $this; + + case C_WARENKORBPOS_TYP_VERSANDPOS: + $this->type = OrderLineType::TYPE_SHIPPING_FEE; + return $this; + + case C_WARENKORBPOS_TYP_VERPACKUNG: + case C_WARENKORBPOS_TYP_VERSANDZUSCHLAG: + case C_WARENKORBPOS_TYP_ZAHLUNGSART: + case C_WARENKORBPOS_TYP_VERSAND_ARTIKELABHAENGIG: + case C_WARENKORBPOS_TYP_NACHNAHMEGEBUEHR: + $this->type = OrderLineType::TYPE_SURCHARGE; + return $this; + + case C_WARENKORBPOS_TYP_GUTSCHEIN: + case C_WARENKORBPOS_TYP_KUPON: + case C_WARENKORBPOS_TYP_NEUKUNDENKUPON: + $this->type = OrderLineType::TYPE_DISCOUNT; + return $this; + + } + + throw new RuntimeException('Unknown PosTyp.', (int)$nPosTyp); + } + +} \ No newline at end of file diff --git a/version/203/class/Checkout/OrderCheckout.php b/version/203/class/Checkout/OrderCheckout.php new file mode 100644 index 0000000..c2a67bd --- /dev/null +++ b/version/203/class/Checkout/OrderCheckout.php @@ -0,0 +1,362 @@ +getMollie()->status !== OrderStatus::STATUS_AUTHORIZED && $checkout->getMollie()->status !== OrderStatus::STATUS_SHIPPING) { + throw new RuntimeException('Nur autorisierte Zahlungen können erfasst werden!'); + } + $shipment = $checkout->API()->Client()->shipments->createFor($checkout->getMollie(), ['lines' => []]); + $checkout->Log(sprintf('Bestellung wurde manuell erfasst/versandt: %s', $shipment->id)); + return $shipment->id; + } + + /** + * @param false $force + * @return Order|null + */ + public function getMollie($force = false) + { + if ($force || (!$this->order && $this->getModel()->kID)) { + try { + $this->order = $this->API()->Client()->orders->get($this->getModel()->kID, ['embed' => 'payments,shipments,refunds']); + } catch (Exception $e) { + throw new RuntimeException(sprintf('Mollie-Order \'%s\' konnte nicht geladen werden: %s', $this->getModel()->kID, $e->getMessage())); + } + } + return $this->order; + } + + /** + * @param OrderCheckout $checkout + * @return Order + * @throws ApiException + */ + public static function cancel($checkout) + { + if (!$checkout->getMollie()->isCancelable) { + throw new RuntimeException('Bestellung kann nicht abgebrochen werden.'); + } + $order = $checkout->getMollie()->cancel(); + $checkout->Log('Bestellung wurde manuell abgebrochen.'); + return $order; + } + + /** + * @return array + */ + public function getShipments() + { + $shipments = []; + $lieferschien_arr = Shop::DB()->executeQueryPrepared("SELECT kLieferschein FROM tlieferschein WHERE kInetBestellung = :kBestellung", [ + ':kBestellung' => (int)$this->getBestellung()->kBestellung + ], 2); + + foreach ($lieferschien_arr as $lieferschein) { + $shipments[] = new Shipment($lieferschein->kLieferschein, $this); + } + return $shipments; + } + + /** + * @return string + * @throws ApiException + */ + public function cancelOrRefund($force = false) + { + if (!$this->getMollie()) { + throw new RuntimeException('Mollie-Order konnte nicht geladen werden: ' . $this->getModel()->kID); + } + if ($force || (int)$this->getBestellung()->cStatus === BESTELLUNG_STATUS_STORNO) { + if ($this->getMollie()->isCancelable) { + $res = $this->getMollie()->cancel(); + $result = 'Order cancelled, Status: ' . $res->status; + } else { + $res = $this->getMollie()->refundAll(); + $result = "Order Refund initiiert, Status: " . $res->status; + } + $this->PaymentMethod()->Log("OrderCheckout::cancelOrRefund: " . $result, $this->LogData()); + return $result; + } + throw new RuntimeException('Bestellung ist derzeit nicht storniert, Status: ' . $this->getBestellung()->cStatus); + } + + /** + * @param array $paymentOptions + * @return Order|Payment + */ + public function create(array $paymentOptions = []) + { + if ($this->getModel()->kID) { + try { + $this->order = $this->API()->Client()->orders->get($this->getModel()->kID, ['embed' => 'payments']); + if (in_array($this->order->status, [OrderStatus::STATUS_COMPLETED, OrderStatus::STATUS_PAID, OrderStatus::STATUS_AUTHORIZED, OrderStatus::STATUS_PENDING], true)) { + $this->handleNotification(); + throw new RuntimeException(self::Plugin()->oPluginSprachvariableAssoc_arr['errAlreadyPaid']); + } + if ($this->order->status === OrderStatus::STATUS_CREATED) { + if ($this->order->payments()) { + /** @var Payment $payment */ + foreach ($this->order->payments() as $payment) { + if ($payment->status === PaymentStatus::STATUS_OPEN) { + $this->setPayment($payment); + break; + } + } + } + if (!$this->getPayment()) { + $this->setPayment($this->API()->Client()->orderPayments->createForId($this->getModel()->kID, $paymentOptions)); + } + $this->updateModel()->saveModel(); + return $this->getMollie(true); + } + } catch (RuntimeException $e) { + throw $e; + } catch (Exception $e) { + $this->Log(sprintf("OrderCheckout::create: Letzte Order '%s' konnte nicht geladen werden: %s, versuche neue zu erstellen.", $this->getModel()->kID, $e->getMessage()), LOGLEVEL_ERROR); + } + } + + try { + $req = $this->loadRequest()->jsonSerialize(); + $this->order = $this->API()->Client()->orders->create($req); + $this->Log(sprintf("Order für '%s' wurde erfolgreich angelegt: %s", $this->getBestellung()->cBestellNr, $this->order->id)); + $this->updateModel()->saveModel(); + return $this->order; + } catch (Exception $e) { + $this->Log(sprintf("OrderCheckout::create: Neue Order '%s' konnte nicht erstellt werden: %s.", $this->getBestellung()->cBestellNr, $e->getMessage()), LOGLEVEL_ERROR); + throw new RuntimeException(sprintf("Order für '%s' konnte nicht angelegt werden: %s", $this->getBestellung()->cBestellNr, $e->getMessage())); + } + } + + /** + * @return Payment|null + */ + public function getPayment($search = false) + { + if (!$this->_payment && $search) { + foreach ($this->getMollie()->payments() as $payment) { + if (in_array($payment->status, [ + PaymentStatus::STATUS_AUTHORIZED, + PaymentStatus::STATUS_PAID, + PaymentStatus::STATUS_PENDING, + ], true)) { + $this->_payment = $payment; + break; + } + } + } + return $this->_payment; + } + + /** + * @param $payment + * @return $this + */ + public function setPayment($payment) + { + $this->_payment = $payment; + return $this; + } + + /** + * @return $this|OrderCheckout + */ + public function updateModel() + { + parent::updateModel(); + + if (!$this->getPayment() && $this->getMollie() && $this->getMollie()->payments()) { + /** @var Payment $payment */ + foreach ($this->getMollie()->payments() as $payment) { + if (in_array($payment->status, [PaymentStatus::STATUS_OPEN, PaymentStatus::STATUS_PENDING, PaymentStatus::STATUS_AUTHORIZED, PaymentStatus::STATUS_PAID], true)) { + $this->setPayment($payment); + break; + } + } + } + if ($this->getPayment()) { + $this->getModel()->cTransactionId = $this->getPayment()->id; + } + if ($this->getMollie()) { + $this->getModel()->cCheckoutURL = $this->getMollie()->getCheckoutUrl(); + $this->getModel()->cWebhookURL = $this->getMollie()->webhookUrl; + $this->getModel()->cRedirectURL = $this->getMollie()->redirectUrl; + } + return $this; + } + + /** + * @param array $options + * @return $this|OrderCheckout + */ + public function loadRequest($options = []) + { + + if ($this->getBestellung()->oKunde->nRegistriert + && ($customer = $this->getCustomer( + array_key_exists('mollie_create_customer', $_SESSION['cPost_arr'] ?: []) && $_SESSION['cPost_arr']['mollie_create_customer'] === 'Y') + ) + && isset($customer)) { + $options['customerId'] = $customer->id; + } + + $this->locale = self::getLocale($_SESSION['cISOSprache'], Session::getInstance()->Customer()->cLand); + $this->amount = Amount::factory($this->getBestellung()->fGesamtsummeKundenwaehrung, $this->getBestellung()->Waehrung->cISO, true); + $this->orderNumber = $this->getBestellung()->cBestellNr; + $this->metadata = [ + 'kBestellung' => $this->getBestellung()->kBestellung, + 'kKunde' => $this->getBestellung()->kKunde, + 'kKundengruppe' => Session::getInstance()->CustomerGroup()->kKundengruppe, + 'cHash' => $this->getHash(), + ]; + + $this->redirectUrl = $this->PaymentMethod()->getReturnURL($this->getBestellung()); + $this->webhookUrl = Shop::getURL(true) . '/?mollie=1'; + + $pm = $this->PaymentMethod(); + $isPayAgain = strpos($_SERVER['PHP_SELF'], 'bestellab_again') !== false; + if ($pm::METHOD !== '' && (self::Plugin()->oPluginEinstellungAssoc_arr['resetMethod'] !== 'Y' || !$isPayAgain)) { + $this->method = $pm::METHOD; + } + + $this->billingAddress = Address::factory($this->getBestellung()->oRechnungsadresse); + if ($this->getBestellung()->Lieferadresse !== null) { + if (!$this->getBestellung()->Lieferadresse->cMail) { + $this->getBestellung()->Lieferadresse->cMail = $this->getBestellung()->oRechnungsadresse->cMail; + } + $this->shippingAddress = Address::factory($this->getBestellung()->Lieferadresse); + } + + if ( + !empty(Session::getInstance()->Customer()->dGeburtstag) + && Session::getInstance()->Customer()->dGeburtstag !== '0000-00-00' + && preg_match('/^\d{4}-\d{2}-\d{2}$/', trim(Session::getInstance()->Customer()->dGeburtstag)) + ) { + $this->consumerDateOfBirth = trim(Session::getInstance()->Customer()->dGeburtstag); + } + + $lines = []; + foreach ($this->getBestellung()->Positionen as $oPosition) { + $lines[] = OrderLine::factory($oPosition, $this->getBestellung()->Waehrung); + } + + if ($this->getBestellung()->GuthabenNutzen && $this->getBestellung()->fGuthaben > 0) { + $lines[] = OrderLine::getCredit($this->getBestellung()); + } + + if ($comp = OrderLine::getRoundingCompensation($lines, $this->amount, $this->getBestellung()->Waehrung->cISO)) { + $lines[] = $comp; + } + $this->lines = $lines; + + if ($dueDays = $this->PaymentMethod()->getExpiryDays()) { + try { + $max = $this->method && strpos($this->method, 'klarna') !== false ? 28 : 100; + $date = new \DateTime(sprintf("+%d DAYS", min($dueDays, $max)), new \DateTimeZone('UTC')); + $this->expiresAt = $date->format('Y-m-d'); + //date('Y-m-d', strtotime(sprintf("+%d DAYS", min($dueDays, $max)))); + } catch (Exception $e) { + $this->Log($e->getMessage(), LOGLEVEL_ERROR); + } + } + + $this->payment = $options; + + return $this; + } + + /** + * @return object|null + */ + public function getIncomingPayment() + { + if (!$this->getMollie()) { + return null; + } + + if (Helper::getSetting('wawiPaymentID') === 'ord') { + $cHinweis = $this->getMollie()->id; + } else { + if (Helper::getSetting('wawiPaymentID') === 'tr') { + $cHinweis = $this->getPayment(true)->id; + } else { + $cHinweis = sprintf("%s / %s", $this->getMollie()->id, $this->getPayment(true)->id); + } + } + + /** @var Payment $payment */ + foreach ($this->getMollie()->payments() as $payment) { + if (in_array($payment->status, + [PaymentStatus::STATUS_AUTHORIZED, PaymentStatus::STATUS_PAID], true)) { + $this->setPayment($payment); + $data = (object)[ + 'fBetrag' => (float)$payment->amount->value, + 'cISO' => $payment->amount->currency, + 'cZahler' => $payment->details->paypalPayerId ?: $payment->customerId, + 'cHinweis' => $payment->details->paypalReference ?: $cHinweis, + ]; + if (isset($payment->details, $payment->details->paypalFee)) { + $data->fZahlungsgebuehr = $payment->details->paypalFee->value; + } + return $data; + } + } + return null; + } +} \ No newline at end of file diff --git a/version/203/class/Checkout/Payment/Address.php b/version/203/class/Checkout/Payment/Address.php new file mode 100644 index 0000000..ea460c1 --- /dev/null +++ b/version/203/class/Checkout/Payment/Address.php @@ -0,0 +1,54 @@ +streetAndNumber = $address->cStrasse . ' ' . $address->cHausnummer; + $resource->postalCode = $address->cPLZ; + $resource->city = $address->cOrt; + $resource->country = $address->cLand; + + if ( + isset($address->cAdressZusatz) + && trim($address->cAdressZusatz) !== '' + ) { + $resource->streetAdditional = trim($address->cAdressZusatz); + } + + // Validity-Check + // TODO: Check for valid Country Code? + // TODO: Check PostalCode requirement Country? + if (!$resource->streetAndNumber || !$resource->city || !$resource->country) { + throw ResourceValidityException::trigger(ResourceValidityException::ERROR_REQUIRED, ['streetAndNumber', 'city', 'country'], $resource); + } + + return $resource; + } + + +} \ No newline at end of file diff --git a/version/203/class/Checkout/Payment/Amount.php b/version/203/class/Checkout/Payment/Amount.php new file mode 100644 index 0000000..21acef9 --- /dev/null +++ b/version/203/class/Checkout/Payment/Amount.php @@ -0,0 +1,72 @@ + true [5 Rappen Rounding]) + * @return Amount + */ + public static function factory($value, $currency = null, $useRounding = false) + { + + if (!$currency) { + $currency = static::FallbackCurrency()->cISO; + } + + $resource = new static(); + + $resource->currency = $currency; + //$resource->value = number_format(round($useRounding ? $resource->round($value * (float)$currency->fFaktor) : $value * (float)$currency->fFaktor, 2), 2, '.', ''); + $resource->value = number_format(round($useRounding ? $resource->round($value) : $value, 2), 2, '.', ''); + + // Validity Check + // TODO: Check ISO Code? + // TODO: Check Value + if (!$resource->currency || !$resource->value) { + throw ResourceValidityException::trigger(ResourceValidityException::ERROR_REQUIRED, ['currency', 'value'], $resource); + } + return $resource; + } + + /** + * @return \stdClass + */ + public static function FallbackCurrency() + { + return isset($_SESSION['Waehrung']) ? $_SESSION['Waehrung'] : Shop::DB()->select('twaehrung', 'cStandard', 'Y'); + } + + /** + * Check if 5 Rappen rounding is necessary + * + * @return float + */ + protected function round($value) + { + + $conf = Shop::getSettings([CONF_KAUFABWICKLUNG]); + if (isset($conf['kaufabwicklung']['bestellabschluss_runden5']) && (int)$conf['kaufabwicklung']['bestellabschluss_runden5'] === 1) { + $value = round($value * 20) / 20; + } + return $value; + } + + +} \ No newline at end of file diff --git a/version/203/class/Checkout/PaymentCheckout.php b/version/203/class/Checkout/PaymentCheckout.php new file mode 100644 index 0000000..fc88a64 --- /dev/null +++ b/version/203/class/Checkout/PaymentCheckout.php @@ -0,0 +1,209 @@ +getMollie()) { + throw new RuntimeException('Mollie-Order konnte nicht geladen werden: ' . $this->getModel()->kID); + } + if ($force || (int)$this->getBestellung()->cStatus === BESTELLUNG_STATUS_STORNO) { + if ($this->getMollie()->isCancelable) { + $res = $this->API()->Client()->payments->cancel($this->getMollie()->id); + $result = 'Payment cancelled, Status: ' . $res->status; + } else { + $res = $this->API()->Client()->payments->refund($this->getMollie(), ['amount' => $this->getMollie()->amount]); + $result = "Payment Refund initiiert, Status: " . $res->status; + } + $this->PaymentMethod()->Log("PaymentCheckout::cancelOrRefund: " . $result, $this->LogData()); + return $result; + } + throw new RuntimeException('Bestellung ist derzeit nicht storniert, Status: ' . $this->getBestellung()->cStatus); + } + + /** + * @param false $force + * @return Payment|null + */ + public function getMollie($force = false) + { + if ($force || (!$this->getPayment() && $this->getModel()->kID)) { + try { + $this->setPayment($this->API()->Client()->payments->get($this->getModel()->kID, ['embed' => 'refunds'])); + } catch (Exception $e) { + throw new RuntimeException('Mollie-Payment konnte nicht geladen werden: ' . $e->getMessage()); + } + } + return $this->getPayment(); + } + + /** + * @return Payment|null + */ + public function getPayment() + { + return $this->_payment; + } + + /** + * @param $payment + * @return $this + */ + public function setPayment($payment) + { + $this->_payment = $payment; + return $this; + } + + /** + * @param array $paymentOptions + * @return \Mollie\Api\Resources\Order|Payment|\ws_mollie\Model\Payment + */ + public function create(array $paymentOptions = []) + { + if ($this->getModel()->kID) { + try { + $this->setPayment($this->API()->Client()->payments->get($this->getModel()->kID)); + if ($this->getPayment()->status === PaymentStatus::STATUS_PAID) { + throw new RuntimeException(self::Plugin()->oPluginSprachvariableAssoc_arr['errAlreadyPaid']); + } + if ($this->getPayment()->status === PaymentStatus::STATUS_OPEN) { + $this->updateModel()->saveModel(); + return $this->getPayment(); + } + } catch (RuntimeException $e) { + //$this->Log(sprintf("PaymentCheckout::create: Letzte Transaktion '%s' konnte nicht geladen werden: %s", $this->getModel()->kID, $e->getMessage()), LOGLEVEL_ERROR); + throw $e; + } catch (Exception $e) { + $this->Log(sprintf("PaymentCheckout::create: Letzte Transaktion '%s' konnte nicht geladen werden: %s, versuche neue zu erstellen.", $this->getModel()->kID, $e->getMessage()), LOGLEVEL_ERROR); + } + } + + try { + $req = $this->loadRequest($paymentOptions)->jsonSerialize(); + $this->setPayment($this->API()->Client()->payments->create($req)); + $this->Log(sprintf("Payment für '%s' wurde erfolgreich angelegt: %s", $this->getBestellung()->cBestellNr, $this->getPayment()->id)); + $this->updateModel()->saveModel(); + return $this->getPayment(); + } catch (Exception $e) { + $this->Log(sprintf("PaymentCheckout::create: Neue Transaktion für '%s' konnte nicht erstellt werden: %s.", $this->getBestellung()->cBestellNr, $e->getMessage()), LOGLEVEL_ERROR); + throw new RuntimeException(sprintf('Mollie-Payment \'%s\' konnte nicht geladen werden: %s', $this->getBestellung()->cBestellNr, $e->getMessage())); + } + } + + + /** + * @param array $options + * @return $this|PaymentCheckout + */ + public function loadRequest($options = []) + { + + if ($this->getBestellung()->oKunde->nRegistriert + && ($customer = $this->getCustomer( + array_key_exists('mollie_create_customer', $_SESSION['cPost_arr'] ?: []) && $_SESSION['cPost_arr']['mollie_create_customer'] === 'Y') + ) + && isset($customer)) { + $options['customerId'] = $customer->id; + } + + $this->amount = Amount::factory($this->getBestellung()->fGesamtsummeKundenwaehrung, $this->getBestellung()->Waehrung->cISO, true); + $this->description = 'Order ' . $this->getBestellung()->cBestellNr; + $this->redirectUrl = $this->PaymentMethod()->getReturnURL($this->getBestellung()); + $this->webhookUrl = Shop::getURL(true) . '/?mollie=1'; + $this->locale = self::getLocale($_SESSION['cISOSprache'], Session::getInstance()->Customer()->cLand); + $this->metadata = [ + 'kBestellung' => $this->getBestellung()->kBestellung, + 'kKunde' => $this->getBestellung()->kKunde, + 'kKundengruppe' => Session::getInstance()->CustomerGroup()->kKundengruppe, + 'cHash' => $this->getHash(), + ]; + $pm = $this->PaymentMethod(); + $isPayAgain = strpos($_SERVER['PHP_SELF'], 'bestellab_again') !== false; + if ($pm::METHOD !== '' && (self::Plugin()->oPluginEinstellungAssoc_arr['resetMethod'] !== 'Y' || !$isPayAgain)) { + $this->method = $pm::METHOD; + } + foreach ($options as $key => $value) { + $this->$key = $value; + } + + return $this; + } + + /** + * @return object|null + */ + public function getIncomingPayment() + { + if (!$this->getMollie()) { + return null; + } + + if (in_array($this->getMollie()->status, [PaymentStatus::STATUS_AUTHORIZED, PaymentStatus::STATUS_PAID], true)) { + $data = []; + $data['fBetrag'] = (float)$this->getMollie()->amount->value; + $data['cISO'] = $this->getMollie()->amount->currency; + $data['cZahler'] = $this->getMollie()->details->paypalPayerId ?: $this->getMollie()->customerId; + $data['cHinweis'] = $this->getMollie()->details->paypalReference ?: $this->getMollie()->id; + if (isset($this->getMollie()->details, $this->getMollie()->details->paypalFee)) { + $data['fZahlungsgebuehr'] = $this->getMollie()->details->paypalFee->value; + } + return (object)$data; + } + return null; + } + + /** + * @param PaymentCheckout $checkout + * @return Payment + */ + public static function cancel($checkout) + { + if(!$checkout->getMollie()->isCancelable){ + throw new RuntimeException('Zahlung kann nicht abgebrochen werden.'); + } + $payment = $checkout->API()->Client()->payments->cancel($checkout->getMollie()->id); + $checkout->Log('Zahlung wurde manuell abgebrochen.'); + return $payment; + } +} \ No newline at end of file diff --git a/version/203/class/ExclusiveLock.php b/version/203/class/ExclusiveLock.php new file mode 100644 index 0000000..3e481c9 --- /dev/null +++ b/version/203/class/ExclusiveLock.php @@ -0,0 +1,70 @@ +key = $key; + $this->path = rtrim(realpath($path), '/') . '/'; + if (!is_dir($path) || !is_writable($path)) { + throw new RuntimeException("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", 'wb+'); + } + + + public function __destruct() + { + if ($this->own === true) { + $this->unlock(); + } + } + + 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 + } + + 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 + } +} diff --git a/version/203/class/Helper.php b/version/203/class/Helper.php new file mode 100644 index 0000000..5f2a8be --- /dev/null +++ b/version/203/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/203/class/Hook/AbstractHook.php b/version/203/class/Hook/AbstractHook.php new file mode 100644 index 0000000..8dcbbda --- /dev/null +++ b/version/203/class/Hook/AbstractHook.php @@ -0,0 +1,13 @@ +kPlugin)) + && array_key_exists($key, $_SESSION) && !array_key_exists("Zahlungsart", $_SESSION)) { + unset($_SESSION[$key]); + } + + if (!array_key_exists('ws_mollie_applepay_available', $_SESSION)) { + Shop::Smarty()->assign('applePayCheckURL', json_encode(self::Plugin()->cFrontendPfadURLSSL . 'applepay.php')); + pq('body')->append(Shop::Smarty()->fetch(self::Plugin()->cFrontendPfad . 'tpl/applepay.tpl')); + } + + } + + /** + * @return bool + */ + public static function isAvailable() + { + if (array_key_exists('ws_mollie_applepay_available', $_SESSION)) { + return $_SESSION['ws_mollie_applepay_available']; + } + return false; + } + + /** + * @param $status bool + */ + public static function setAvailable($status) + { + $_SESSION['ws_mollie_applepay_available'] = $status; + } + +} \ No newline at end of file diff --git a/version/203/class/Hook/Checkbox.php b/version/203/class/Hook/Checkbox.php new file mode 100644 index 0000000..6df972c --- /dev/null +++ b/version/203/class/Hook/Checkbox.php @@ -0,0 +1,60 @@ +cModulId, 'kPlugin_' . self::Plugin()->kPlugin . '_') === false) { + return; + } + + if (array_key_exists('nAnzeigeOrt', $args_arr) && $args_arr['nAnzeigeOrt'] === CHECKBOX_ORT_BESTELLABSCHLUSS && (int)Session::getInstance()->Customer()->nRegistriert) { + + $mCustomer = Customer::fromID(Session::getInstance()->Customer()->kKunde, 'kKunde'); + + if ($mCustomer->customerId) { + return; + } + + $checkbox = new \CheckBox(); + $checkbox->kLink = 0; + $checkbox->kCheckBox = -1; + $checkbox->kCheckBoxFunktion = 0; + $checkbox->cName = 'MOLLIE SAVE CUSTOMER'; + $checkbox->cKundengruppe = ';1;'; + $checkbox->cAnzeigeOrt = ';2;'; + $checkbox->nAktiv = 1; + $checkbox->nPflicht = 0; + $checkbox->nLogging = 0; + $checkbox->nSort = 999; + $checkbox->dErstellt = date('Y-m-d H:i:s'); + $checkbox->oCheckBoxSprache_arr = []; + + $langs = gibAlleSprachen(); + foreach ($langs as $lang) { + $checkbox->oCheckBoxSprache_arr[$lang->kSprache] = (object)[ + 'cText' => self::Plugin()->oPluginSprachvariableAssoc_arr['checkboxText'], + 'cBeschreibung' => self::Plugin()->oPluginSprachvariableAssoc_arr['checkboxDescr'], + 'kSprache' => $lang->kSprache, + 'kCheckbox' => -1 + ]; + } + + $checkbox->kKundengruppe_arr = [Session::getInstance()->Customer()->kKundengruppe]; + $checkbox->kAnzeigeOrt_arr = [CHECKBOX_ORT_BESTELLABSCHLUSS]; + $checkbox->cID = "mollie_create_customer"; + $checkbox->cLink = ''; + + $args_arr['oCheckBox_arr'][] = $checkbox; + + } + } +} \ No newline at end of file diff --git a/version/203/class/Hook/Queue.php b/version/203/class/Hook/Queue.php new file mode 100644 index 0000000..9dbef9b --- /dev/null +++ b/version/203/class/Hook/Queue.php @@ -0,0 +1,129 @@ +fGesamtsumme > 0 + && self::Plugin()->oPluginEinstellungAssoc_arr['onlyPaid'] === 'Y' + && AbstractCheckout::isMollie((int)$args_arr['oBestellung']->kZahlungsart, true)) { + + $args_arr['oBestellung']->cAbgeholt = 'Y'; + Jtllog::writeLog('Switch cAbgeholt for kBestellung: ' . print_r($args_arr['oBestellung']->kBestellung, 1), JTLLOG_LEVEL_NOTICE); + } + } + + /** + * @param array $args_arr + */ + public static function xmlBestellStatus(array $args_arr) + { + if (AbstractCheckout::isMollie((int)$args_arr['oBestellung']->kBestellung)) { + self::saveToQueue(HOOK_BESTELLUNGEN_XML_BESTELLSTATUS . ':' . (int)$args_arr['oBestellung']->kBestellung, [ + 'kBestellung' => $args_arr['oBestellung']->kBestellung, + 'status' => (int)$args_arr['status'] + ]); + } + } + + /** + * @param $hook + * @param $args_arr + * @param string $type + * @return bool + */ + protected static function saveToQueue($hook, $args_arr, $type = 'hook') + { + $mQueue = new QueueModel(); + $mQueue->cType = $type . ':' . $hook; + $mQueue->cData = serialize($args_arr); + try { + return $mQueue->save(); + } catch (Exception $e) { + Jtllog::writeLog('mollie::saveToQueue: ' . $e->getMessage() . ' - ' . print_r($args_arr, 1)); + return false; + } + } + + /** + * @param array $args_arr + */ + public static function xmlBearbeiteStorno(array $args_arr) + { + if (AbstractCheckout::isMollie((int)$args_arr['oBestellung']->kBestellung)) { + self::saveToQueue(HOOK_BESTELLUNGEN_XML_BEARBEITESTORNO . ':' . $args_arr['oBestellung']->kBestellung, ['kBestellung' => $args_arr['oBestellung']->kBestellung]); + } + } + + /** + * + */ + public static function headPostGet() + { + if (array_key_exists('mollie', $_REQUEST) && (int)$_REQUEST['mollie'] === 1 && array_key_exists('id', $_REQUEST)) { + self::saveToQueue($_REQUEST['id'], $_REQUEST['id'], 'webhook'); + exit(); + } + if (array_key_exists('m_pay', $_REQUEST)) { + try { + $raw = Shop::DB()->executeQueryPrepared('SELECT kID FROM `xplugin_ws_mollie_payments` WHERE dReminder IS NOT NULL AND MD5(CONCAT(kID, "-", kBestellung)) = :md5', [ + ':md5' => $_REQUEST['m_pay'] + ], 1); + + if (!$raw) { + throw new RuntimeException(self::Plugin()->oPluginSprachvariableAssoc_arr['errOrderNotFound']); + } + + if (strpos($raw->cOrderId, 'tr_') === 0) { + $checkout = PaymentCheckout::fromID($raw->kID); + } else { + $checkout = OrderCheckout::fromID($raw->kID); + } + $checkout->getMollie(true); + $checkout->updateModel()->saveModel(); + + if (($checkout->getBestellung()->dBezahltDatum !== null && $checkout->getBestellung()->dBezahltDatum !== '0000-00-00') + || in_array($checkout->getModel()->cStatus, ['completed', 'paid', 'authorized', 'pending'])) { + throw new RuntimeException(self::Plugin()->oPluginSprachvariableAssoc_arr['errAlreadyPaid']); + } + + $options = []; + if (self::Plugin()->oPluginEinstellungAssoc_arr['resetMethod'] !== 'Y') { + $options['method'] = $checkout->getModel()->cMethod; + } + + $mollie = $checkout->create($options); // Order::repayOrder($orderModel->getOrderId(), $options, $api); + $url = $mollie->getCheckoutUrl(); + + header('Location: ' . $url); + exit(); + + } catch (RuntimeException $e) { + // TODO Workaround? + //$alertHelper = Shop::Container()->getAlertService(); + //$alertHelper->addAlert(Alert::TYPE_ERROR, $e->getMessage(), 'mollie_repay', ['dismissable' => true]); + } catch (Exception $e) { + Jtllog::writeLog('mollie:repay:error: ' . $e->getMessage() . "\n" . print_r($_REQUEST, 1)); + } + } + } + +} \ No newline at end of file diff --git a/version/203/class/Model/AbstractModel.php b/version/203/class/Model/AbstractModel.php new file mode 100644 index 0000000..1dc9a47 --- /dev/null +++ b/version/203/class/Model/AbstractModel.php @@ -0,0 +1,92 @@ +data = $data; + if (!$data) { + $this->new = true; + } + } + + public static function fromID($id, $col = 'kID', $failIfNotExists = false) + { + if ($payment = Shop::DB()->executeQueryPrepared("SELECT * FROM " . static::TABLE . " WHERE {$col} = :id", + [':id' => $id], 1)) { + return new static($payment); + } + if ($failIfNotExists) { + throw new RuntimeException(sprintf('Model %s in %s nicht gefunden!', $id, static::TABLE)); + } + return new static(); + } + + /** + * @return mixed|stdClass|null + */ + public function jsonSerialize() + { + return $this->data; + } + + public function __get($name) + { + if (isset($this->data->$name)) { + return $this->data->$name; + } + return null; + } + + public function __set($name, $value) + { + if (!$this->data) { + $this->data = new stdClass(); + } + $this->data->$name = $value; + } + + public function __isset($name) + { + return isset($this->data->$name); + } + + /** + * @return bool + */ + public function save() + { + if (!$this->data) { + throw new RuntimeException('No Data to save!'); + } + + if ($this->new) { + Shop::DB()->insert(static::TABLE, $this->data); + $this->new = false; + return true; + } + Shop::DB()->update(static::TABLE, static::PRIMARY, $this->data->{static::PRIMARY}, $this->data); + return true; + } + +} diff --git a/version/203/class/Model/Customer.php b/version/203/class/Model/Customer.php new file mode 100644 index 0000000..7be9e15 --- /dev/null +++ b/version/203/class/Model/Customer.php @@ -0,0 +1,19 @@ +dCreatedAt) { + $this->dCreatedAt = date('Y-m-d H:i:s'); + } + if($this->new){ + $this->dReminder = self::NULL; + } + return parent::save(); + } +} diff --git a/version/203/class/Model/Queue.php b/version/203/class/Model/Queue.php new file mode 100644 index 0000000..e17a491 --- /dev/null +++ b/version/203/class/Model/Queue.php @@ -0,0 +1,42 @@ +cResult = $result; + $this->dDone = $date ?: date('Y-m-d H:i:s'); + return $this->save(); + } + + public function save() + { + if (!$this->dCreated) { + $this->dCreated = date('Y-m-d H:i:s'); + } + $this->dModified = date('Y-m-d H:i:s'); + return parent::save(); + } + +} \ No newline at end of file diff --git a/version/203/class/Model/Shipment.php b/version/203/class/Model/Shipment.php new file mode 100644 index 0000000..bece7b4 --- /dev/null +++ b/version/203/class/Model/Shipment.php @@ -0,0 +1,28 @@ +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); + } + } + } + } + + 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[] = AbstractCheckout::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/203/class/Queue.php b/version/203/class/Queue.php new file mode 100644 index 0000000..7388e21 --- /dev/null +++ b/version/203/class/Queue.php @@ -0,0 +1,180 @@ +kId, $todo->bLock ?: 'just now')); + continue; + } + Jtllog::writeLog(sprintf('%s was locked.', $todo->kId)); + + if ((list($type, $id) = explode(':', $todo->cType))) { + try { + switch ($type) { + case 'webhook': + self::handleWebhook($id, $todo); + break; + + case 'hook': + self::handleHook((int)$id, $todo); + break; + } + + } catch (Exception $e) { + Jtllog::writeLog($e->getMessage() . " ({$type}, {$id})"); + $todo->done("{$e->getMessage()}\n{$e->getFile()}:{$e->getLine()}\n{$e->getTraceAsString()}"); + } + } + + self::unlock($todo); + + } + } + + /** + * @param $limit + * @return Generator|QueueModel[] + */ + private static function getOpen($limit) + { + /** @noinspection SqlResolve */ + $open = Shop::DB()->executeQueryPrepared(sprintf("SELECT * FROM %s WHERE dDone IS NULL AND `bLock` IS NULL ORDER BY dCreated DESC LIMIT 0, :LIMIT;", QueueModel::TABLE), [ + ':LIMIT' => $limit + ], 2); + + foreach ($open as $_raw) { + yield new QueueModel($_raw); + } + } + + protected static function lock($todo) + { + return $todo->kId && Shop::DB()->executeQueryPrepared(sprintf('UPDATE %s SET `bLock` = NOW() WHERE `bLock` IS NULL AND kId = :kId', QueueModel::TABLE), [ + 'kId' => $todo->kId + ], 3) >= 1; + + } + + protected static function handleWebhook($id, QueueModel $todo) + { + $checkout = AbstractCheckout::fromID($id); + if ($checkout->getBestellung()->kBestellung && $checkout->PaymentMethod()) { + $checkout->handleNotification(); + return $todo->done('Status: ' . $checkout->getMollie()->status); + } + throw new RuntimeException("Bestellung oder Zahlungsart konnte nicht geladen werden: {$id}"); + } + + /** + * @param $hook + * @param QueueModel $todo + * @return bool + * @throws ApiException + * @throws IncompatiblePlatform + */ + protected static function handleHook($hook, QueueModel $todo) + { + $data = unserialize($todo->cData); + if (array_key_exists('kBestellung', $data)) { + switch ($hook) { + case HOOK_BESTELLUNGEN_XML_BESTELLSTATUS: + if ((int)$data['kBestellung']) { + $checkout = AbstractCheckout::fromBestellung($data['kBestellung']); + + $result = ""; + if ((int)$checkout->getBestellung()->cStatus < BESTELLUNG_STATUS_VERSANDT) { + return $todo->done("Bestellung noch nicht versendet: {$checkout->getBestellung()->cStatus}"); + } + + /** @var $method JTLMollie */ + if ((int)$data['status'] + && array_key_exists('status', $data) + && $checkout->PaymentMethod() + && (strpos($checkout->getModel()->kID, 'tr_') === false) + && $checkout->getMollie()) { + /** @var OrderCheckout $checkout */ + $checkout->handleNotification(); + if ($checkout->getMollie()->status === OrderStatus::STATUS_COMPLETED) { + $result = 'Mollie Status already ' . $checkout->getMollie()->status; + } else if ($checkout->getMollie()->isCreated() || $checkout->getMollie()->isPaid() || $checkout->getMollie()->isAuthorized() || $checkout->getMollie()->isShipping() || $checkout->getMollie()->isPending()) { + try { + if ($shipments = Shipment::syncBestellung($checkout)) { + foreach ($shipments as $shipment) { + if (is_string($shipment)) { + $checkout->PaymentMethod()->Log("Shipping-Error: {$shipment}", $checkout->LogData()); + $result .= "Shipping-Error: {$shipment};\n"; + + } else { + $checkout->PaymentMethod()->Log("Order shipped: \n" . print_r($shipment, 1)); + $result .= "Order shipped: {$shipment->id};\n"; + } + } + } else { + $result = 'No Shipments ready!'; + } + } catch (RuntimeException $e) { + $result = $e->getMessage(); + } catch (Exception $e) { + $result = $e->getMessage() . "\n" . $e->getFile() . ":" . $e->getLine() . "\n" . $e->getTraceAsString(); + } + } else { + $result = sprintf('Unerwarteter Mollie Status "%s" für %s', $checkout->getMollie()->status, $checkout->getBestellung()->cBestellNr); + } + } else { + $result = 'Nothing to do.'; + } + } else { + $result = "kBestellung missing"; + } + $checkout->PaymentMethod()->Log("Queue::handleHook: " . $result, $checkout->LogData()); + return $todo->done($result); + + case HOOK_BESTELLUNGEN_XML_BEARBEITESTORNO: + if (self::Plugin()->oPluginEinstellungAssoc_arr['autoRefund'] !== 'Y') { + throw new RuntimeException('Auto-Refund disabled'); + } + + $checkout = AbstractCheckout::fromBestellung((int)$data['kBestellung']); + return $todo->done($checkout->cancelOrRefund()); + } + } + return false; + } + + protected static function unlock($todo) + { + if ($todo->kId && Shop::DB()->executeQueryPrepared(sprintf('UPDATE %s SET `bLock` = NULL WHERE kId = :kId', QueueModel::TABLE), [ + 'kId' => $todo->kId + ], 3) >= 1) { + Jtllog::writeLog(sprintf('%s was unlocked.', $todo->kId)); + } + + } + +} \ No newline at end of file diff --git a/version/203/class/Shipment.php b/version/203/class/Shipment.php new file mode 100644 index 0000000..7152dad --- /dev/null +++ b/version/203/class/Shipment.php @@ -0,0 +1,318 @@ +kLieferschein = $kLieferschein; + if ($checkout) { + $this->checkout = $checkout; + } + + if (!$this->getLieferschein() || !$this->getLieferschein()->getLieferschein()) { + throw new RuntimeException('Lieferschein konnte nicht geladen werden'); + } + + if (!count($this->getLieferschein()->oVersand_arr)) { + throw new RuntimeException('Kein Versand gefunden!'); + } + + if (!$this->getCheckout()->getBestellung()->oKunde->nRegistriert) { + $this->isGuest = true; + } + } + + public function getLieferschein() + { + if (!$this->oLieferschein && $this->kLieferschein) { + $this->oLieferschein = new Lieferschein($this->kLieferschein); + } + return $this->oLieferschein; + } + + /** + * @return OrderCheckout + * @throws Exception + */ + public function getCheckout() + { + if (!$this->checkout) { + //TODO evtl. load by lieferschien + throw new Exception('Should not happen, but it did!'); + } + return $this->checkout; + } + + public static function syncBestellung(OrderCheckout $checkout) + { + $shipments = []; + if ($checkout->getBestellung()->kBestellung) { + + $oKunde = $checkout->getBestellung()->oKunde ?: new Kunde($checkout->getBestellung()->kKunde); + + $shippingActive = Helper::getSetting('shippingActive'); + if ($shippingActive === 'N') { + throw new RuntimeException('Shipping deaktiviert'); + } + + if (($shippingActive === 'K') && ((int)$checkout->getBestellung()->cStatus !== BESTELLUNG_STATUS_VERSANDT) && !$oKunde->nRegistriert) { + throw new RuntimeException('Shipping für Gast-Bestellungen und Teilversand deaktiviert'); + } + + /** @var Lieferschein $oLieferschein */ + foreach ($checkout->getBestellung()->oLieferschein_arr as $oLieferschein) { + + try { + + $shipment = new Shipment($oLieferschein->getLieferschein(), $checkout); + + $mode = self::Plugin()->oPluginEinstellungAssoc_arr['shippingMode']; + switch ($mode) { + case 'A': + // ship directly + if (!$shipment->send() && !$shipment->getShipment()) { + throw new RuntimeException('Shipment konnte nicht gespeichert werden.'); + } + $shipments[] = $shipment->getShipment(); + break; + + case 'B': + // only ship if complete shipping + if ($oKunde->nRegistriert || (int)$checkout->getBestellung()->cStatus === BESTELLUNG_STATUS_VERSANDT) { + if (!$shipment->send() && !$shipment->getShipment()) { + throw new RuntimeException('Shipment konnte nicht gespeichert werden.'); + } + $shipments[] = $shipment->getShipment(); + break; + } + throw new RuntimeException('Gastbestellung noch nicht komplett versendet!'); + } + } catch (RuntimeException $e) { + $shipments[] = $e->getMessage(); + } catch (Exception $e) { + $shipments[] = $e->getMessage(); + $checkout->Log("mollie: Shipment::syncBestellung (BestellNr. {$checkout->getBestellung()->cBestellNr}, Lieferschein: {$shipment->getLieferschein()->getLieferscheinNr()}) - " . $e->getMessage(), LOGLEVEL_ERROR); + } + } + } + return $shipments; + } + + /** + * @return mixed + * @throws ApiException + * @throws IncompatiblePlatform + * @throws Exception + */ + public function send() + { + + if ($this->getShipment()) { + throw new RuntimeException('Lieferschien bereits an Mollie übertragen: ' . $this->getShipment()->id); + } + + if ($this->getCheckout()->getMollie(true)->status === OrderStatus::STATUS_COMPLETED) { + throw new RuntimeException('Bestellung bei Mollie bereits abgeschlossen!'); + } + + $api = $this->getCheckout()->API()->Client(); + $this->shipment = $api->shipments->createForId($this->checkout->getModel()->kID, $this->loadRequest()->jsonSerialize()); + + return $this->updateModel()->saveModel(); + + } + + /** + * @param false $force + * @return BaseResource|\Mollie\Api\Resources\Shipment + * @throws ApiException + * @throws IncompatiblePlatform + * @throws Exception + */ + public function getShipment($force = false) + { + if (($force || !$this->shipment) && $this->getModel() && $this->getModel()->cShipmentId) { + $this->shipment = $this->getCheckout()->API()->Client()->shipments->getForId($this->getModel()->cOrderId, $this->getModel()->cShipmentId); + } + return $this->shipment; + } + + /** + * @return ShipmentModel + * @throws Exception + */ + public function getModel() + { + if (!$this->model && $this->kLieferschein) { + $this->model = ShipmentModel::fromID($this->kLieferschein, 'kLieferschein'); + + if (!$this->model->dCreated) { + $this->model->dCreated = date('Y-m-d H:i:s'); + } + $this->updateModel(); + } + return $this->model; + } + + /** + * @return $this + * @throws Exception + */ + public function updateModel() + { + $this->getModel()->kLieferschein = $this->kLieferschein; + if ($this->getCheckout()) { + $this->getModel()->cOrderId = $this->getCheckout()->getModel()->kID; + $this->getModel()->kBestellung = $this->getCheckout()->getModel()->kBestellung; + } + if ($this->getShipment()) { + $this->getModel()->cShipmentId = $this->getShipment()->id; + $this->getModel()->cUrl = $this->getShipment()->getTrackingUrl() ?: ''; + } + if (isset($this->tracking)) { + $this->getModel()->cCarrier = $this->tracking['carrier'] ?: ''; + $this->getModel()->cCode = $this->tracking['code'] ?: ''; + } + return $this; + } + + /** + * @param array $options + * @return $this + * @throws Exception + */ + public function loadRequest($options = []) + { + /** @var Versand $oVersand */ + $oVersand = $this->getLieferschein()->oVersand_arr[0]; + if ($oVersand->getIdentCode() && $oVersand->getLogistik()) { + $tracking = [ + 'carrier' => $oVersand->getLogistik(), + 'code' => $oVersand->getIdentCode(), + ]; + if ($oVersand->getLogistikVarUrl()) { + $tracking['url'] = $oVersand->getLogistikURL(); + } + $this->tracking = $tracking; + } + + // TODO: Wenn alle Lieferschiene in der WAWI erstellt wurden, aber nicht im Shop, kommt status 4. + if ($this->isGuest || (int)$this->getCheckout()->getBestellung()->cStatus === BESTELLUNG_STATUS_VERSANDT) { + $this->lines = []; + } else { + $this->lines = $this->getOrderLines(); + } + return $this; + } + + /** + * @return array + * @throws Exception + */ + protected function getOrderLines() + { + $lines = []; + + if (!count($this->getLieferschein()->oLieferscheinPos_arr)) { + return $lines; + } + + // Bei Stücklisten, sonst gibt es mehrere OrderLines für die selbe ID + $shippedOrderLines = []; + + /** @var Lieferscheinpos $oLieferscheinPos */ + foreach ($this->getLieferschein()->oLieferscheinPos_arr as $oLieferscheinPos) { + + $wkpos = Shop::DB()->executeQueryPrepared('SELECT * FROM twarenkorbpos WHERE kBestellpos = :kBestellpos', [ + ':kBestellpos' => $oLieferscheinPos->getBestellPos() + ], 1); + + /** @var OrderLine $orderLine */ + foreach ($this->getCheckout()->getMollie()->lines as $orderLine) { + + if ($orderLine->sku === $wkpos->cArtNr && !in_array($orderLine->id, $shippedOrderLines, true)) { + + if ($quantity = min($oLieferscheinPos->getAnzahl(), $orderLine->shippableQuantity)) { + $lines[] = [ + 'id' => $orderLine->id, + 'quantity' => $quantity + ]; + } + $shippedOrderLines[] = $orderLine->id; + break; + } + } + } + return $lines; + } + + /** + * @return bool + * @throws Exception + */ + public function saveModel() + { + return $this->getModel()->save(); + } +} \ No newline at end of file diff --git a/version/203/class/Traits/Jsonable.php b/version/203/class/Traits/Jsonable.php new file mode 100644 index 0000000..afc0988 --- /dev/null +++ b/version/203/class/Traits/Jsonable.php @@ -0,0 +1,20 @@ +jsonSerialize(); + } + + public function jsonSerialize() + { + return array_filter(get_object_vars($this), static function ($value) { + return !($value === null || (is_string($value) && $value === '')); + }); + } +} \ No newline at end of file diff --git a/version/203/class/Traits/Plugin.php b/version/203/class/Traits/Plugin.php new file mode 100644 index 0000000..5b2c3a3 --- /dev/null +++ b/version/203/class/Traits/Plugin.php @@ -0,0 +1,25 @@ +requestData; + } + + public function __get($name) + { + if (!$this->requestData) { + $this->loadRequest(); + } + return is_string($this->requestData[$name]) ? utf8_decode($this->requestData[$name]) : $this->requestData[$name]; + } + + public function __set($name, $value) + { + if (!$this->requestData) { + $this->requestData = []; + } + + $this->requestData[$name] = is_string($value) ? utf8_encode($value) : $value; + + return $this; + } + + /** + * @param array $options + * @return $this + */ + public function loadRequest($options = []) + { + return $this; + } + + + public function __serialize() + { + return $this->requestData ?: []; + } + + public function __isset($name) + { + return $this->requestData[$name] !== null; + } + +} \ No newline at end of file diff --git a/version/203/frontend/.htaccess b/version/203/frontend/.htaccess new file mode 100644 index 0000000..df6c074 --- /dev/null +++ b/version/203/frontend/.htaccess @@ -0,0 +1,9 @@ + + + Require all granted + + + Order Allow,Deny + Allow from all + + diff --git a/version/203/frontend/131_globalinclude.php b/version/203/frontend/131_globalinclude.php new file mode 100644 index 0000000..ea3d301 --- /dev/null +++ b/version/203/frontend/131_globalinclude.php @@ -0,0 +1,34 @@ +append( + << + /* MOLLIE CHECKOUT STYLES*/ + #fieldset-payment .form-group > div:hover, #checkout-shipping-payment .form-group > div:hover { + background-color: #eee; + color: black; + } + {$selector} label { + {$border} + } + + {$selector} label::after { + clear: both; + content: ' '; + display: block; + } + + {$selector} label span small { + line-height: 48px; + } + + {$selector} label img { + float: right; + } + +HTML + ); + +} catch (Exception $e) { + Helper::logExc($e); +} diff --git a/version/203/frontend/180_checkbox.php b/version/203/frontend/180_checkbox.php new file mode 100644 index 0000000..95a070f --- /dev/null +++ b/version/203/frontend/180_checkbox.php @@ -0,0 +1,18 @@ +oPluginEinstellungAssoc_arr['useCustomerAPI'] === 'C') { + \ws_mollie\Hook\Checkbox::execute($args_arr); + } + +} catch (Exception $e) { + Helper::logExc($e); +} \ No newline at end of file diff --git a/version/203/frontend/181_sync.php b/version/203/frontend/181_sync.php new file mode 100644 index 0000000..22022a9 --- /dev/null +++ b/version/203/frontend/181_sync.php @@ -0,0 +1,14 @@ +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 Rmns)TMnX}%M${5 literal 0 HcmV?d00001 diff --git a/version/203/frontend/img/trust_fre.png b/version/203/frontend/img/trust_fre.png new file mode 100644 index 0000000000000000000000000000000000000000..ed1a2f6f03c56f6748aac8af0352de7fc0afd3a4 GIT binary patch literal 17319 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 Mu#8ZJpsxS_1AJc%;s5{u literal 0 HcmV?d00001 diff --git a/version/203/frontend/img/trust_ger.png b/version/203/frontend/img/trust_ger.png new file mode 100644 index 0000000000000000000000000000000000000000..e42821b06709e8f4371c66cfb5759d00df0e1afd GIT binary patch literal 15352 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 + diff --git a/version/203/paymentmethod/JTLMollie.php b/version/203/paymentmethod/JTLMollie.php new file mode 100644 index 0000000..bcefebd --- /dev/null +++ b/version/203/paymentmethod/JTLMollie.php @@ -0,0 +1,264 @@ +cModulId = "kPlugin_" . self::Plugin()->kPlugin . "_mollie" . $moduleID; + } + + /** + * @param Bestellung $order + * @return PaymentMethod + */ + public function setOrderStatusToPaid($order) + { + // If paid already, do nothing + if ((int)$order->cStatus >= BESTELLUNG_STATUS_BEZAHLT) { + return $this; + } + return parent::setOrderStatusToPaid($order); + } + + /** + * Prepares everything so that the Customer can start the Payment Process. + * Tells Template Engine. + * + * @param Bestellung $order + * @return void + */ + public function preparePaymentProcess($order) + { + + parent::preparePaymentProcess($order); + + try { + + if ($this->duringCheckout) { + $this->Log(sprintf("Zahlung vor Bestellabschluss nicht unterstützt (%s)!", $order->cBestellNr), sprintf("#%s", $order->kBestellung), LOGLEVEL_ERROR); + return; + } + + $payable = (float)$order->fGesamtsumme > 0; + if (!$payable) { + $this->Log(sprintf("Bestellung '%s': Gesamtsumme %.2f, keine Zahlung notwendig!", $order->cBestellNr, $order->fGesamtsumme), sprintf("#%s", $order->kBestellung)); + return; + } + + $paymentOptions = []; + + $api = array_key_exists($this->moduleID . '_api', self::Plugin()->oPluginEinstellungAssoc_arr) ? self::Plugin()->oPluginEinstellungAssoc_arr[$this->moduleID . '_api'] : 'order'; + + $paymentOptions = array_merge($paymentOptions, $this->getPaymentOptions($order, $api)); + + if ($api === 'payment') { + $checkout = new PaymentCheckout($order); + $payment = $checkout->create($paymentOptions); + $url = $payment->getCheckoutUrl(); + } else { + $checkout = new OrderCheckout($order); + $mOrder = $checkout->create($paymentOptions); + $url = $mOrder->getCheckoutUrl(); + } + + ifndef('MOLLIE_REDIRECT_DELAY', 3); + $checkoutMode = self::Plugin()->oPluginEinstellungAssoc_arr['checkoutMode']; + Shop::Smarty()->assign('redirect', $url) + ->assign('checkoutMode', $checkoutMode); + if ($checkoutMode === 'Y' && !headers_sent()) { + header('Location: ' . $url); + } + } catch (Exception $e) { + $this->Log('mollie::preparePaymentProcess: ' . $e->getMessage() . ' - ' . print_r(['cBestellNr' => $order->cBestellNr], 1), '#' . $order->kBestellung, LOGLEVEL_ERROR); + Shop::Smarty()->assign('oMollieException', $e) + ->assign('tryAgain', Shop::getURL() . '/bestellab_again.php?kBestellung=' . $order->kBestellung); + } + } + + public function Log($msg, $data = null, $level = LOGLEVEL_NOTICE) + { + ZahlungsLog::add($this->moduleID, "[" . microtime(true) . " - " . $_SERVER['PHP_SELF'] . "] " . $msg, $data, $level); + return $this; + } + + public function getPaymentOptions(Bestellung $order, $apiType) + { + return []; + } + + /** + * @param Bestellung $order + * @param string $hash + * @param array $args + */ + public function handleNotification($order, $hash, $args) + { + parent::handleNotification($order, $hash, $args); + try { + $orderId = $args['id']; + $checkout = null; + if (strpos($orderId, 'tr_') === 0) { + $checkout = new PaymentCheckout($order); + } else { + $checkout = new OrderCheckout($order); + } + $checkout->handleNotification($hash); + + } catch (Exception $e) { + $checkout->Log(sprintf("mollie::handleNotification: Fehler bei Bestellung '%s': %s\n%s", $order->cBestellNr, $e->getMessage(), print_r($args, 1)), LOGLEVEL_ERROR); + } + } + + /** + * @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 (API::getMode()) { + $selectable = trim(self::Plugin()->oPluginEinstellungAssoc_arr['test_api_key']) !== ''; + } else { + $selectable = trim(self::Plugin()->oPluginEinstellungAssoc_arr['api_key']) !== ''; + if (!$selectable) { + Jtllog::writeLog("Live API Key missing!"); + } + } + if ($selectable) { + try { + $locale = AbstractCheckout::getLocale($_SESSION['cISOSprache'], Session::getInstance()->Customer()->cLand); + $amount = Session::getInstance()->Basket()->gibGesamtsummeWarenExt([ + C_WARENKORBPOS_TYP_ARTIKEL, + C_WARENKORBPOS_TYP_KUPON, + C_WARENKORBPOS_TYP_GUTSCHEIN, + C_WARENKORBPOS_TYP_NEUKUNDENKUPON, + ], true) * Session::getInstance()->Currency()->fFaktor; + if ($amount <= 0) { + $amount = 0.01; + } + $selectable = self::isMethodPossible( + static::METHOD, + $locale, + Session::getInstance()->Customer()->cLand, + Session::getInstance()->Currency()->cISO, + $amount + ); + } catch (Exception $e) { + Helper::logExc($e); + $selectable = false; + } + } + return $selectable && parent::isSelectable(); + } + + /** + * @param $method + * @param $locale + * @param $billingCountry + * @param $currency + * @param $amount + * @return bool + * @throws ApiException + */ + protected static function isMethodPossible($method, $locale, $billingCountry, $currency, $amount) + { + + $api = new API(API::getMode()); + + if (!array_key_exists('mollie_possibleMethods', $_SESSION)) { + $_SESSION['mollie_possibleMethods'] = []; + } + + $key = md5(serialize([$locale, $billingCountry, $currency, $amount])); + if (!array_key_exists($key, $_SESSION['mollie_possibleMethods'])) { + $active = $api->Client()->methods->allActive([ + 'locale' => $locale, + 'amount' => [ + 'currency' => $currency, + 'value' => number_format($amount, 2, ".", "") + ], + 'billingCountry' => $billingCountry, + 'resource' => 'orders', + 'includeWallets' => 'applepay', + ]); + foreach($active as $a){ + $_SESSION['mollie_possibleMethods'][$key][] = (object)['id' =>$a->id]; + } + } + + if ($method !== '') { + foreach ($_SESSION['mollie_possibleMethods'][$key] as $m) { + if ($m->id === $method) { + return true; + } + } + } else { + return true; + } + + return false; + + } + + /** + * @param array $args_arr + * @return bool + */ + public function isValidIntern($args_arr = []) + { + return $this->duringCheckout + ? static::ALLOW_PAYMENT_BEFORE_ORDER && parent::isValidIntern($args_arr) + : parent::isValidIntern($args_arr); + } + + /** + * @return int + */ + public function getExpiryDays() + { + return (int)min(abs((int)Helper::oPlugin()->oPluginEinstellungAssoc_arr[$this->cModulId . '_dueDays']), static::MAX_EXPIRY_DAYS) ?: static::MAX_EXPIRY_DAYS; + } + +} diff --git a/version/203/paymentmethod/JTLMollieApplePay.php b/version/203/paymentmethod/JTLMollieApplePay.php new file mode 100644 index 0000000..4b23bf4 --- /dev/null +++ b/version/203/paymentmethod/JTLMollieApplePay.php @@ -0,0 +1,15 @@ +oRechnungsadresse->cMail; + $paymentOptions['locale'] = AbstractCheckout::getLocale($_SESSION['cISOSprache'], $order->oRechnungsadresse->cLand); + } + + $dueDays = $this->getExpiryDays(); + if ($dueDays > 3) { + $paymentOptions['dueDate'] = date('Y-m-d', strtotime("+{$dueDays} DAYS")); + } + return $paymentOptions; + } +} diff --git a/version/203/paymentmethod/JTLMollieBelfius.php b/version/203/paymentmethod/JTLMollieBelfius.php new file mode 100644 index 0000000..91a6169 --- /dev/null +++ b/version/203/paymentmethod/JTLMollieBelfius.php @@ -0,0 +1,8 @@ +clearToken(); + } + + protected function clearToken() + { + $this->unsetCache(self::CACHE_TOKEN) + ->unsetCache(self::CACHE_TOKEN_TIMESTAMP); + return true; + } + + public function handleAdditional($aPost_arr) + { + + $components = self::Plugin()->oPluginEinstellungAssoc_arr[$this->moduleID . '_components']; + $profileId = self::Plugin()->oPluginEinstellungAssoc_arr['profileId']; + + if ($components === 'N' || !$profileId || trim($profileId) === '') { + return parent::handleAdditional($aPost_arr); + } + + $cleared = false; + if (array_key_exists('clear', $aPost_arr) && (int)$aPost_arr['clear']) { + $cleared = $this->clearToken(); + } + + if ($components === 'S' && array_key_exists('skip', $aPost_arr) && (int)$aPost_arr['skip']) { + return parent::handleAdditional($aPost_arr); + } + + try { + $trustBadge = (bool)self::Plugin()->oPluginEinstellungAssoc_arr[$this->moduleID . '_loadTrust']; + $locale = AbstractCheckout::getLocale($_SESSION['cISOSprache'], Session::getInstance()->Customer() ? Session::getInstance()->Customer()->cLand : null); + $mode = API::getMode(); + $errorMessage = json_encode(self::Plugin()->oPluginSprachvariableAssoc_arr['mcErrorMessage']); + } catch (Exception $e) { + Jtllog::writeLog($e->getMessage() . "\n" . print_r(['e' => $e], 1)); + return parent::handleAdditional($aPost_arr); + } + + if (!$cleared && array_key_exists('cardToken', $aPost_arr) && ($token = trim($aPost_arr['cardToken']))) { + return $this->setToken($token) && parent::handleAdditional($aPost_arr); + } + + $token = false; + if (($ctTS = (int)$this->getCache(self::CACHE_TOKEN_TIMESTAMP)) && $ctTS > time()) { + $token = $this->getCache(self::CACHE_TOKEN); + } + + Shop::Smarty()->assign('profileId', $profileId) + ->assign('trustBadge', $trustBadge ? self::Plugin()->cFrontendPfadURLSSL . 'img/trust_' . $_SESSION['cISOSprache'] . '.png' : false) + ->assign('components', $components) + ->assign('locale', $locale ?: 'de_DE') + ->assign('token', $token ?: false) + ->assign('testMode', $mode ?: false) + ->assign('errorMessage', $errorMessage ?: null) + ->assign('mollieLang', self::Plugin()->oPluginSprachvariableAssoc_arr); + + return false; + +// if (array_key_exists('skip', $aPost_arr) && (int)$aPost_arr['skip']) { +// unset($_SESSION['mollieCardToken'], $_SESSION['mollieCardTokenTS']); +// return true; +// } +// +// $profileId = trim(Helper::getSetting('profileId')); +// if ($profileId === '' || strpos($profileId, 'pfl_') !== 0) { +// return true; +// } +// if (array_key_exists('mollieCardTokenTS', $_SESSION) && (int)$_SESSION['mollieCardTokenTS'] > time() +// && array_key_exists('mollieCardToken', $_SESSION) && trim($_SESSION['mollieCardToken']) !== '') { +// return true; +// } +// +// unset($_SESSION['mollieCardToken'], $_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('skipComponents', Helper::getSetting('skipComponents')) +// ->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; + } + + protected function setToken($token) + { + $this->addCache(self::CACHE_TOKEN, $token) + ->addCache(self::CACHE_TOKEN_TIMESTAMP, time() + 3600); + return true; + } + + public function getPaymentOptions(Bestellung $order, $apiType) + { + + $paymentOptions = []; + + if ($apiType === 'payment') { + if ($order->Lieferadresse !== null) { + if (!$order->Lieferadresse->cMail) { + $order->Lieferadresse->cMail = $order->oRechnungsadresse->cMail; + } + $paymentOptions['shippingAddress'] = Address::factory($order->Lieferadresse); + } + + $paymentOptions['billingAddress'] = Address::factory($order->oRechnungsadresse); + } + if ((int)$this->getCache(self::CACHE_TOKEN_TIMESTAMP) > time() && ($token = trim($this->getCache(self::CACHE_TOKEN)))) { + $paymentOptions['cardToken'] = $token; + } + return $paymentOptions; + } + +} diff --git a/version/203/paymentmethod/JTLMollieDirectDebit.php b/version/203/paymentmethod/JTLMollieDirectDebit.php new file mode 100644 index 0000000..7318e8a --- /dev/null +++ b/version/203/paymentmethod/JTLMollieDirectDebit.php @@ -0,0 +1,27 @@ + substr($order->cBestellNr, 0, 13)]; + } +} diff --git a/version/203/paymentmethod/JTLMollieKlarnaPayLater.php b/version/203/paymentmethod/JTLMollieKlarnaPayLater.php new file mode 100644 index 0000000..266953f --- /dev/null +++ b/version/203/paymentmethod/JTLMollieKlarnaPayLater.php @@ -0,0 +1,10 @@ +Lieferadresse !== null) { + if (!$order->Lieferadresse->cMail) { + $order->Lieferadresse->cMail = $order->oRechnungsadresse->cMail; + } + $paymentOptions['shippingAddress'] = Address::factory($order->Lieferadresse); + } + $paymentOptions['description'] = 'Order ' . $order->cBestellNr; + } + + + return $paymentOptions; + } + +} diff --git a/version/203/paymentmethod/JTLMolliePaysafecard.php b/version/203/paymentmethod/JTLMolliePaysafecard.php new file mode 100644 index 0000000..920e0fa --- /dev/null +++ b/version/203/paymentmethod/JTLMolliePaysafecard.php @@ -0,0 +1,13 @@ + $order->oKunde->kKunde] : []; + } +} diff --git a/version/203/paymentmethod/JTLMolliePrzelewy24.php b/version/203/paymentmethod/JTLMolliePrzelewy24.php new file mode 100644 index 0000000..ebd28ed --- /dev/null +++ b/version/203/paymentmethod/JTLMolliePrzelewy24.php @@ -0,0 +1,15 @@ + $order->oRechnungsadresse->cMail] : []; + } + +} diff --git a/version/203/paymentmethod/JTLMollieSofort.php b/version/203/paymentmethod/JTLMollieSofort.php new file mode 100644 index 0000000..c11060b --- /dev/null +++ b/version/203/paymentmethod/JTLMollieSofort.php @@ -0,0 +1,8 @@ +OH(NI>=T42<+x9g>;*Gy9DrKtJl=F((p(~XhRMojR(!TROq)4##x zi;wfn&C+>%^UTiFKSt7JYSXp1>ZPgDP*&5InbUcF<%^K^*xKlsoYHP{(wCajZ*$Ra zbJNPo(OY2BWNFmE!S~qO{POeCTVT|{z|(GX;Bt54e}mdsUi8b(sL>`X0000JbW%=J z01%HLkU-Cn-_OsV&!6AlpP5D4UE1#Sax&aZg(%L>z8x33MOZZ8H?WJ;;n51dMe)(}9UH1j29 ze@0RGfq`^s0!X#X7!_srsUP@btltZoyHfrIVq@*+2f)Ge+&BuBcbdrjKu5}NuE;){Yi3#o7gOK=v6Y0{rAbqNgQSz}}0I~5?ej{GsP%?vN z=_l4!?VPOmM>R@!2oOAkd1t|Pb#@H>-d=$PnbBs7=u%Z>9N;0iml z2#guk2rk-V%mMEvxQCZ1@+-_*(mao=fPWKs%h@Mp0)~gcfgO7j{4M(n<{@x^Z^Hk! ze1;0X32xx)(NPC3aetZbtnBss>W2NT-v%Bch%He^5RXIyLDWRp5;o{lcPr>qmkRZj lpHDtfd;A2~X0zTP_aA;i{an>LN7rz#m}I!{TEUogY_hW!fX z1?mg>C*-erx%(so1LG!77srr_xVP7C<}EQ0XbW_HZ(Bb#ysRpA(wRN~nf+#OlTe%( zXkfncL^KKCCrg-Lh=kEnU|a;ZB9QaR>Td+?i96wEUURmd^*;_;}q*?JtCN zs9v0_oUIYrJ>{ItUF)Suj=nY*E;y-_bg}zQ;ZT|@FU4Qeut^B)WfWUjV9g-3v@K+f-ik;kV{MOr_6wK;GGik>mTp$V%-RtP)+CPEi`n!UgTe~DWM4fFWeR( literal 0 HcmV?d00001 diff --git a/version/203/paymentmethod/img/method/bancontact@2x.png b/version/203/paymentmethod/img/method/bancontact@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..a87af77d20330ab4ee197fd750d0bd39a5b10f90 GIT binary patch literal 582 zcmV-M0=fN(P)lk!lq%lq?@9+Qr z|M>X$=jZ1jWQqR%{`vX&|JVTk=U{-T&j0$~pTFAg&hoWPVjpU$|LlN(mQMfcfPbmZpr$+j>2Uw#P;ZV{AZe)(UZem0@6X@u|MkEB z;XwWU{r~1*Ky`MXzS=N!uW*i8kF?YfT$A7F^MIC5pQk%!Gip%)000nlQchC<&w%eB zkRX4bpb&7+Z;x=Vl85vF00AONL_t(|UhS6GZp0uI1+V+IBnNQY-qL&T?f<_j%Vs4k zWi4ZPi#+c$LIR;fk}z^m8)w(24LdL-qBSjmiImqQ6%1%eKSC_H5hBJOQ3wcbh=A9j z0E`>M;F1Gj9uRN{NX-L}@Ce`*0RKJE1nw{TTbXGF`gs|rT7l!dln0%_EVm0RbGyKB zqJ*zRaiSTxE%@_=;_x?lSs8dz{y6#LPln}z>8GT40dLB`KB#<1qlM(E;D0OsM*0?TeIhg`dn6;Q{6Fh2l%qOS4K%wo8-q7AUD{?yGF(55vm4C&H_FzBH+J=d4+57}kr Up-!czfB*mh07*qoM6N<$g3OCHTL1t6 literal 0 HcmV?d00001 diff --git a/version/203/paymentmethod/img/method/banktransfer@2x.png b/version/203/paymentmethod/img/method/banktransfer@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..c70206bef4893f23fcd59d436273108d2f2eebc7 GIT binary patch literal 801 zcmV++1K#|JP)lk!lq*=;-9+mkX z{{U2_ztrjP@9%)A(*D5?-|6)J(MtZwET6yKpugSt`1lZBsz86cAZf7q`T3Bv*Z%(g z-|F=K#U1|5JO0^dAZoDx_u=pL`RC{7_xJZ;l*j-3@c!I)@AdkSwAlXDS^mf@aG%W2 z;O`J$tN-Md>+9=KiNUYR<6xA=@AUcq@WXGP%>DiS|LnB>%sc+*q+gWBFm$#4l$oJ=bMJL) zN$}UM z^EEI7D0q#*=`w@Mb&#yX6$WP@x&}s<8JvJ@pvqecQO^sez9^Xbs$t>(|Nn0Y_`k@X z`u+Uv`wm6F?mz#2{?4!aFGTBV&I9cbE(!7rW)PTg{{H;_^9ubA3J&Kd+&@2If#l5V zkwEFKo-U3d6>)E`o#Z>Lz~g$+{n^fDUKQE@|Mgd!a9=T#&e{4(sr-HO1o4KQ>uv;= zWX2_)yrQzk;QY@iN0x35n7oK-g-2+63_H(@QU|u6Z>|Z!r6lZ1zes9a?+x$E9%YhzX@O1Ta JS?83{1OT9Jm%RW0 literal 0 HcmV?d00001 diff --git a/version/203/paymentmethod/img/method/creditcard@2x.png b/version/203/paymentmethod/img/method/creditcard@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..b08be792753326b65345c752a6f350182a9393d2 GIT binary patch literal 3125 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 P00000NkvXXu0mjf3Vis# literal 0 HcmV?d00001 diff --git a/version/203/paymentmethod/img/method/directdebit@2x.png b/version/203/paymentmethod/img/method/directdebit@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..514ff845b84d38cd8eb97b9e2c53e5c117967944 GIT binary patch literal 801 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 literal 0 HcmV?d00001 diff --git a/version/203/paymentmethod/img/method/giropay@2x.png b/version/203/paymentmethod/img/method/giropay@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..b787e1fee50c9bcca112f734ef4bcbd4ecfb6d6b GIT binary patch literal 602 zcmV-g0;T5Kx~EOrH!)pASu;4ojd8OQ8=; zpbt!;!_w#B>GK{}r)iJG@bvggdAR@o{+6-TrM%mCn#w$GvMpk*ho#Tb-RaC5+y)hho537JnGBqPA~G@Ik#rt1jWCNmt_X5yY-;OM4Sm|;L0fCz(H!a59C z!6FQJ1`O=K0(U?&WmHmQ%ovl1g=xY%=0>sX7T{!DDr3#1AfT>{>*NQdp;XxeDnn^6 z;Fg|~18)oh=#B%J574HG=ZK=b0(2)=ZWs@6u|Psp2S`Ms-aSCKNc4dZ3ml0Y1JpF0 zACT7(WFOdH$J={=+}Kh?t@=QTh`Y)S;{lL4q2$K&0aK;&(@GqDK&DI^R~^tLy#OA$ z1Nay30gQkc{Q&0jzz(SpmbnlhVhfzVhaBhB0($}wh1S_^$N7}lg}e4p3Ic|F4;Z~b zTY@72isxg1#8BrSfnxv^S{6kiGl4E$H2v|f@*S9m0aJJk172Vm21F3Hg)IO)g#GGT oVe}rh6KIQG--ZM8)e@S10aM=ZI#^TblmGw#07*qoM6N<$f@FIOx&QzG literal 0 HcmV?d00001 diff --git a/version/203/paymentmethod/img/method/ideal@2x.png b/version/203/paymentmethod/img/method/ideal@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..efc4315a96a6b2d9b160578a65fe52206783f2ca GIT binary patch literal 845 zcmV-T1G4;yP)lk!ZZ65OMGC?}UYf;o;!m;NZf-!qXsn`1tsvqob6RlsGvz=jZ45_xJw({`vX& z+CYuwfU@xL?-Nv%`QPmApT=fqW&i*F(b3WK zzuD%1v(zAZ>+9>Xv$F87&$F|$@bK^%8W`-K#nT^p^1s=^!okAA!Tj&_DJdxZ{r%~X zz3Gp=&=7F!pvK@}pYN~F>5#mWl#|_1mb0_6g@uIHFobn>b?J}1M@UB*8yIC~W#VwE zc6N2$P?z9fpjKB^=ker~0000HbW%=J0PlbhkiUP=Adhe$&v1`#zea&7rvLx}*GWV{ zRCr#^*2j+9Fc5%YO7?ntl9{1;aqqou@0;Fxd;j;y*jNN`HV2Bl>~|3_{4oLqkzy%V z*t96C%}2Z9&SQ)86vWClksDVqqe|=&Z3|YQQjA*4CE6Eai>Qp6VzP3=CKt6Gk}WnU zMr|=|2#YGH?I~G;2n`TD#K5)puk^^z67b+ZZd-naz)7$!d_QRdc|mw#b1~<{2k2)FEaYF&OT-`GX$RPM#Nt`QAi#wXJk>zhFTO>59`Wo^#}<>sMjOed(+{-3ru0A7D$0jI558$ z)N0PF!RsCe2|{A+{jU4@5&uc>v9T(>X>= zpc$wJPDAG6XudKWan^4w_bUdHVBPG<>jQiVOn&QMzg?RgEbW=`(e{u7#up5;D^8W3 z2%8R3n@hIHS^6WCiFSq9p;8&OR7*Sn%M-cP>{s2YOOzKYHtDf;#GS4DUiRI4c22NA XzpeJ7+7%dW00000NkvXXu0mjfybi$$ literal 0 HcmV?d00001 diff --git a/version/203/paymentmethod/img/method/inghomepay@2x.png b/version/203/paymentmethod/img/method/inghomepay@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..538f219588886db215757eafd5c5151241f18b5a GIT binary patch literal 1118 zcmV-k1flzhP)`_0RK|}|55<|Q2_r?0RL0~|5E_}r-1)w9RKX&|5E_}=Gy;L z0RR90|6UOPlVJbp-~WC<|J1+#zn}l9fd6P9|A|olb1?tk&;RxB|Mc(wo^bzkF#pQ0 z|Fn<)>fisgkpF2Q|G%LBsek{okpG@<|H-fazM%hUAODC@|H-ibs(=5~!2gtB|K894 zs(@(VAMyYI01|XkPE!C7&ySx#AdugXK#$)bkdUC?LT6GX000A7Nkl+_F4;G0`t->#NE zT;V&r`f!+EySiCj<6V7Pt?{mYTH&4jj{)gM0TN(F3?6st+kjw6 z>LApXPB>Unt8V~;Cik9f49AhQ!$i7^fuL#4vW=&{86JR|lTsG~BRymzfEs|JX9J1K z03Dw$1C&G3WKK=%kB`J1r1*<~s2`z=k6T78&3xGOL&RV&0xXfJ0Ql@xfEn*A1CX9E zQ!WBD5?VbTK7XTsCp`U6crw}TsH%60W z2hoh@0nLYSxRBab{+9<3C+^Mz9xYb&ZxhMVDb+cqriY2<9AG-<8gN)^Cix5?)@kAU z;?6$;-SN`NKvD-cR@w%n?9AWi0I~xRElDnK5^Rh@FtDVHX8@ZJfJl->N&_A{l2bso z2x`kJr-3lmJ%9)DK@>~Q{7brt3fNKr^rbrq+|{-iAekxBG;uoyGqur4Ei0S?0=Yll zF_SR>W}x;7ttLalDFCI-OXsp?(S;*|rkk|uOcTs~fUR;0m?79z>!T@dSC<#zVpen3 zDj@L*GoMZY$tw7C*m%o|vLvel!qz~FMPzph=x6{KTjppdC7aC#VVdHg)$wl$bf*AC z1-Rnnz*LgVO4|B5HX#U@PXUn*;sq_sC5u*2fG7j7o&o~>%Wn3WWcg~#QmPptG|8+k2H7XW|=xVi9nUeg`1*I2IB*YJ(+JNL|VD24JQDXa_~} zqMBf8fF~Vbz5wvk*3xb81`yK5AZAEW$9)?Qt+BO>C3E@1Aktu4fz|6HW^Y;1@lk!lq%mkX z{~%3y0h-K!%;mq#+4%VQ5J7OCv&KMYjPLUG@9*#T_xE6cpCPBxaK_?)nX{kS?7!yn zfSI!2=Is9d{_pwx05oR#`T5`T`RC{7L9^Llzu!=FmQcCekkjew>+3LDf{>=XK(pDe zzt4c0vd`J#Fs;_V%-D~nykNlKAg9yc^7t^U)_~3BfX(J`#^Vv8&k>-{-}3p8(&?|? z?{JN&{r&x)v&FFA?=V_}aEz&7z~7M5=+D{X&+PS}+3awQs351(ptHqzpNxV4000qm zQchCIy&+X> z=*5Ul;OaQ@NK`Vzy8t_g2?_Jis)3C$i910Xw$PIU9&Uk!LpkskEkL9-LfkOWJAbaP zUroip18r(eg}^hN*BXg{sb1!Yfc6S#iGXvxN(6jb7x=sau0_D;#S-`?0_b=FJSG`H zPqbnfvWg$g}i**@5@#v5NT=$lzqSQdXDg|8f zIHlhJQN%Mfm~#2YP9b1YgB(!GAN!r?CIjA)sTANZfG||7{JhG5H)Vm3e?0>E>_vVi zq!;d4SOSQYxt#%m;F70Lx8o{r!Tt9&c8CI14(M}40nf9jzsNQAmkVA7gAM$Z|1+@m z0b{)*&IIp+jVE#-MjL9Dd6xv65#{P&<3u77*DDnbtf@m157r`vbG^_r?Ff8 d>Rr1A+%FMH_Q$8Zwr>Cc002ovPDHLkV1oT`waEYg literal 0 HcmV?d00001 diff --git a/version/203/paymentmethod/img/method/klarna@2x.png b/version/203/paymentmethod/img/method/klarna@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..e28a187b81e7c5a6256fea7382a643762746dd1e GIT binary patch literal 896 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 literal 0 HcmV?d00001 diff --git a/version/203/paymentmethod/img/method/paypal@2x.png b/version/203/paymentmethod/img/method/paypal@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..a816d7201f59ea7cef713f5e7895e66dcd6ee9a7 GIT binary patch literal 626 zcmV-&0*(ENP)zW{Q;0CK+oaK8X?zW{Q<0CB+pa=`#_!2of;na1S+alrro z|IFg@&*bxRu-m`e?~lRb-|hDbcETox$#AdRv()Q`yWm5X&|s$5P@dDD$>-eb_JFwG zpUUS$m(j@K@sPpeFpSLa_WMAU&p?#W{Qdsu^7&w=*MGR*^7#DO>Gd#+%P@?~P@U7S z((9ba=CIQ0sn6-_^!k0a-V=Mp)8_OXfyX(K&a%|&;_mkldc-e_%lZ5LgSp`#gUC6M z&erGk#LeN$0000GbW%=J0M8)rfN+qXfDoX6Z;yYFN6jxl0003wNklC4+MXiktqCYwRgSg6)KJbf z5Lj1?Y5+oU@|#dstX9C|0Ujt`J{M4b8Wr^cdi(ak0iFt>ORE}Nts8qh=FWCkI)}aEnE&{1?2hI?PIY68@ zbOdbw0PvXrf5i!Szy>sZ79ap>ye%)UHj^sMYbqagD6U zaJzaI>n$ypF23oVdS#o6|W|*DFT6j;X_Pjl^+{$7FxcM`F8{J!B6QqfZ6J=?T z0Z*i4z#}$g7~II(N7`*?T& O0000+D{~L?`zkmGy`PKgqj{m>0 z^Z&xI|35zdzp(26fxiDA9{<0v`v1;`{~L<_uT1&>;_Ck$4fn+3S%6jwlmz(&Gn{vr zARutRf5Q2Gh4~8e7rbanOaaP$^>lFzsfc?!?c};<10L727Z_ycPF(r9`v3o4QC^`f zNy*irThr_Lx8*f4F=sBE;Is9vL&{b+wWF_Q`cLpRlDMX^fZ@i14v}pdO3hrZ8V-u{ z6@GBmNPp@1=O;WPYJWl57EYgv)6tK(j<>!KX1Tkg-1yN7-6M=yr*jX!QWr1lo!e&; zepvX8JR>o1saCg`3ZOWgj;^L2z+zGho&3IENy|Lc5*g&izjA{*O9T;DjDIk7S9e6n)( p;e>?q6P^m(l+{vMe5&Mx9fO|m{vZE%WkG?%;OXk;vd$@?2>_eS)Oi2^ literal 0 HcmV?d00001 diff --git a/version/203/paymentmethod/tpl/bestellabschluss.tpl b/version/203/paymentmethod/tpl/bestellabschluss.tpl new file mode 100644 index 0000000..b26d8ef --- /dev/null +++ b/version/203/paymentmethod/tpl/bestellabschluss.tpl @@ -0,0 +1,26 @@ +{if isset($oMollieException)} +
+ {$oMollieException->getMessage()} +
+ +{/if} + +{if isset($redirect) && $redirect != ''} + + {if $checkoutMode == 'D'} + + {/if} +{/if} + diff --git a/version/203/paymentmethod/tpl/mollieComponents.tpl b/version/203/paymentmethod/tpl/mollieComponents.tpl new file mode 100644 index 0000000..38907e0 --- /dev/null +++ b/version/203/paymentmethod/tpl/mollieComponents.tpl @@ -0,0 +1,147 @@ +

{$mollieLang.cctitle}

+ +
+ +
+ + {if $token !== false} + +
+
+ {$mollieLang.clearDescr} +
+
+ +
+
+ + {if $trustBadge} +
+ PCI-DSS SAQ-A compliant +
+ {/if} + + {else} + + +
+ +
+
+
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+ +
+
+ + +
+
+ + {if $trustBadge} +
+ PCI-DSS SAQ-A compliant +
+ {/if} + {if $components == 'S'} + + {/if} +
+ +{/if} + + + + + + \ No newline at end of file diff --git a/version/203/sql/203.sql b/version/203/sql/203.sql new file mode 100644 index 0000000..ee97c3c --- /dev/null +++ b/version/203/sql/203.sql @@ -0,0 +1,2 @@ +ALTER TABLE `xplugin_ws_mollie_queue` + ADD `bLock` datetime NULL DEFAULT NULL; \ No newline at end of file diff --git a/version/203/tpl/_alerts.tpl b/version/203/tpl/_alerts.tpl new file mode 100644 index 0000000..5279fa3 --- /dev/null +++ b/version/203/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} From ecfadf689456c8c099c074254868a2ea7a895f97 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Tue, 11 May 2021 13:39:38 +0200 Subject: [PATCH 215/280] CI, UTF-8 Encoding --- .gitlab-ci.yml | 5 +++-- version/203/class/Checkout/AbstractCheckout.php | 6 +++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 9263194..506fc23 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -38,7 +38,7 @@ pack: script: - rm -rf .gitlab-ci.yml .git/ - cd .. - - compiler $CI_PROJECT_DIR $CI_PROJECT_DIR + - if [ $SKIP_COMPILE = 1 ]; then echo "Skipped Compiler!"; else compiler $CI_PROJECT_DIR $CI_PROJECT_DIR; fi - zip -r $CI_PROJECT_DIR/$CI_PROJECT_NAME-$CI_COMMIT_REF_NAME.zip $CI_PROJECT_NAME artifacts: expire_in: 30 days @@ -52,4 +52,5 @@ upload: - master script: - aws configure set region eu-central-1 - - aws s3 cp $CI_PROJECT_NAME-$CI_COMMIT_REF_NAME.zip s3://$S3_BUCKET/jtl-plugins/$CI_PROJECT_NAME/$CI_PROJECT_NAME-$CI_COMMIT_REF_NAME.zip \ No newline at end of file + - if [ $SKIP_COMPILE = 1 ]; then export SRC_PREFIX="-src"; fi + - aws s3 cp $CI_PROJECT_NAME-$CI_COMMIT_REF_NAME.zip s3://$S3_BUCKET/jtl-plugins/$CI_PROJECT_NAME/$CI_PROJECT_NAME-$CI_COMMIT_REF_NAME$SRC_PREFIX.zip \ No newline at end of file diff --git a/version/203/class/Checkout/AbstractCheckout.php b/version/203/class/Checkout/AbstractCheckout.php index ca15646..3b1cce3 100644 --- a/version/203/class/Checkout/AbstractCheckout.php +++ b/version/203/class/Checkout/AbstractCheckout.php @@ -416,13 +416,13 @@ public function getCustomer($createOrUpdate = false) $oKunde = $this->getBestellung()->oKunde; $customer = [ - 'name' => trim($oKunde->cVorname . ' ' . $oKunde->cNachname), - 'email' => $oKunde->cMail, + 'name' => utf8_encode(trim($oKunde->cVorname . ' ' . $oKunde->cNachname)), + 'email' => utf8_encode($oKunde->cMail), 'locale' => self::getLocale($_SESSION['cISOSprache'], $oKunde->cLand), 'metadata' => (object)[ 'kKunde' => $oKunde->kKunde, 'kKundengruppe' => $oKunde->kKundengruppe, - 'cKundenNr' => $oKunde->cKundenNr, + 'cKundenNr' => utf8_encode($oKunde->cKundenNr), ], ]; From 78f4ef1538a872a5d9374df2c8606f038687e50e Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Tue, 18 May 2021 13:19:57 +0200 Subject: [PATCH 216/280] fix #129 --- version/203/class/Checkout/Order/OrderLine.php | 4 +++- version/203/class/Queue.php | 2 -- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/version/203/class/Checkout/Order/OrderLine.php b/version/203/class/Checkout/Order/OrderLine.php index 7fe7911..ba0c18b 100644 --- a/version/203/class/Checkout/Order/OrderLine.php +++ b/version/203/class/Checkout/Order/OrderLine.php @@ -138,7 +138,9 @@ protected function fill($oPosition, $currency = null) // Fraction? include quantity and unit in name $this->name = $isFrac ? sprintf("%s (%.2f %s)", $oPosition->cName, (float)$oPosition->nAnzahl, $oPosition->cEinheit) : $oPosition->cName; - + if(!$this->name){ + $this->name = '(null)'; + } $this->mapType($oPosition->nPosTyp); //$unitPriceNetto = round(($currency->fFaktor * $netto), 4); diff --git a/version/203/class/Queue.php b/version/203/class/Queue.php index 7388e21..c2f03a1 100644 --- a/version/203/class/Queue.php +++ b/version/203/class/Queue.php @@ -32,7 +32,6 @@ public static function run($limit = 10) Jtllog::writeLog(sprintf('%s already locked since %s', $todo->kId, $todo->bLock ?: 'just now')); continue; } - Jtllog::writeLog(sprintf('%s was locked.', $todo->kId)); if ((list($type, $id) = explode(':', $todo->cType))) { try { @@ -172,7 +171,6 @@ protected static function unlock($todo) if ($todo->kId && Shop::DB()->executeQueryPrepared(sprintf('UPDATE %s SET `bLock` = NULL WHERE kId = :kId', QueueModel::TABLE), [ 'kId' => $todo->kId ], 3) >= 1) { - Jtllog::writeLog(sprintf('%s was unlocked.', $todo->kId)); } } From 831d0adac8a1de3c8d9fcd36f5bdce9b77f6f592 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Tue, 18 May 2021 13:35:59 +0200 Subject: [PATCH 217/280] fix #130 --- info.xml | 94 +++++++++++++++++++++++++++++++++----------------------- 1 file changed, 55 insertions(+), 39 deletions(-) diff --git a/info.xml b/info.xml index 2984237..0c5aaa6 100644 --- a/info.xml +++ b/info.xml @@ -95,10 +95,10 @@ Füge hier deinen mollie API Key ein test_api_key - + Test API als Admin - Wenn diese Einstellung aktiviert ist, wird im Shop automatisch die Test-API verwendet, - wenn man als Admin im Backend eingeloggt ist. + Wenn diese Einstellung aktiviert ist, wird im Shop automatisch die Test-API verwendet, + wenn man als Admin im Backend eingeloggt ist. testAsAdmin @@ -108,15 +108,15 @@ Zahlungserinnerung - Soll bei fehlgeschlagener Zahlung ein Zahlungslink verschickt werden? Angabe in Stunden - nach Bestellung. (0 = deaktiviert) + Soll bei fehlgeschlagener Zahlung ein Zahlungslink verschickt werden? Angabe in Stunden + nach Bestellung. (0 = deaktiviert) reminder Kunden bei Mollie anlegen (Customer API) - Wenn diese Einstellung aktiviert ist, hat der Kunde die Möglichkeit, per Checkbox, - seine Kundendaten bei Mollie zu speichern. Z.B. für Single-Click Checkout benötigt. + Wenn diese Einstellung aktiviert ist, hat der Kunde die Möglichkeit, per Checkbox, + seine Kundendaten bei Mollie zu speichern. Z.B. für Single-Click Checkout benötigt. useCustomerAPI @@ -126,15 +126,15 @@ Profile ID: - Füge hier deinen mollie Profil ID (pfl_) ein. Wird benötigt um mollie Components zu - aktivieren + Füge hier deinen mollie Profil ID (pfl_) ein. Wird benötigt um mollie Components zu + aktivieren profileId Zahlungsart zurücksetzen - Versucht, nach fehlgeschlagener oder abgebrochener Zahlung, die Zahlungsart bei Mollie - zurückzusetzen + Versucht, nach fehlgeschlagener oder abgebrochener Zahlung, die Zahlungsart bei Mollie + zurückzusetzen resetMethod @@ -144,8 +144,8 @@ Nur bezahlte Bestellungen in die WAWI übertragen - Wenn diese Einstellung deaktiviert ist, können alle Bestellungen direkt von der WAWI - abgerufen werden. + Wenn diese Einstellung deaktiviert ist, können alle Bestellungen direkt von der WAWI + abgerufen werden. onlyPaid @@ -174,8 +174,8 @@ Bestellungen automatisch stornieren - Wenn diese Einstellung aktiviert ist, werden komplett Stornierte Bestellungen auch bei - Mollie storniert oder rückerstattet. + Wenn diese Einstellung aktiviert ist, werden komplett Stornierte Bestellungen auch bei + Mollie storniert oder rückerstattet. autoRefund @@ -233,8 +233,8 @@ Artikel mit rationalen Stückzahlen - Artikel mit rationalen Stückzahlen werden dann unterstützt, jedoch als ein Artikel - behandelt. KEIN Teilversand hierfür möglich! + Artikel mit rationalen Stückzahlen werden dann unterstützt, jedoch als ein Artikel + behandelt. KEIN Teilversand hierfür möglich! supportQ @@ -244,8 +244,8 @@ TransaktionsID des Zahlungseingangs: - Welche ID soll an die WAWI übetragen werden? Bei PayPal wird immer die PayPal Referenz - angegeben. + Welche ID soll an die WAWI übetragen werden? Bei PayPal wird immer die PayPal Referenz + angegeben. wawiPaymentID @@ -522,8 +522,8 @@ Mollie Components - Wenn diese Einstellung aktiviert ist, werden die Kreditkarten ggf. bereits im Shop - abgefragt. + Wenn diese Einstellung aktiviert ist, werden die Kreditkarten ggf. bereits im Shop + abgefragt. components @@ -1112,7 +1112,7 @@ From 8c8318e1d828af2c8dec7cc9e518f81f9b1945ca Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Tue, 18 May 2021 13:38:07 +0200 Subject: [PATCH 218/280] fix #123 --- version/203/class/API.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version/203/class/API.php b/version/203/class/API.php index 3ed4f27..235b7cf 100644 --- a/version/203/class/API.php +++ b/version/203/class/API.php @@ -44,7 +44,7 @@ public function __construct($test = null) public static function getMode() { require_once PFAD_ROOT . PFAD_ADMIN . PFAD_INCLUDES . 'benutzerverwaltung_inc.php'; - return self::Plugin()->oPluginEinstellungAssoc_arr["testAsAdmin"] === 'Y' && Shop::isAdmin(); + return self::Plugin()->oPluginEinstellungAssoc_arr["testAsAdmin"] === 'Y' && Shop::isAdmin() && self::Plugin()->oPluginEinstellungAssoc_arr['test_api_key']; } /** From f4f6e1936a839f581626f652567261f02c3ed366 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Tue, 18 May 2021 13:41:04 +0200 Subject: [PATCH 219/280] fix #130, hour to minute --- info.xml | 2 +- version/203/class/Checkout/AbstractCheckout.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/info.xml b/info.xml index 0c5aaa6..d3215e3 100644 --- a/info.xml +++ b/info.xml @@ -108,7 +108,7 @@ Zahlungserinnerung - Soll bei fehlgeschlagener Zahlung ein Zahlungslink verschickt werden? Angabe in Stunden + Soll bei fehlgeschlagener Zahlung ein Zahlungslink verschickt werden? Angabe in Minuten nach Bestellung. (0 = deaktiviert) reminder diff --git a/version/203/class/Checkout/AbstractCheckout.php b/version/203/class/Checkout/AbstractCheckout.php index 3b1cce3..b76e17e 100644 --- a/version/203/class/Checkout/AbstractCheckout.php +++ b/version/203/class/Checkout/AbstractCheckout.php @@ -153,7 +153,7 @@ public static function sendReminders() $sql = "SELECT p.kId FROM xplugin_ws_mollie_payments p JOIN tbestellung b ON b.kBestellung = p.kBestellung " . "WHERE (p.dReminder IS NULL OR p.dReminder = '0000-00-00 00:00:00') " - . "AND p.dCreatedAt < NOW() - INTERVAL :d HOUR AND p.dCreatedAt > NOW() - INTERVAL 7 DAY " + . "AND p.dCreatedAt < NOW() - INTERVAL :d MINUTE AND p.dCreatedAt > NOW() - INTERVAL 7 DAY " . "AND p.cStatus IN ('created','open', 'expired', 'failed', 'canceled') AND NOT b.cStatus = '-1'"; $remindables = Shop::DB()->executeQueryPrepared($sql, [ From 206eea381f407dcafd0d39b7986d3d206d92b2e8 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Tue, 18 May 2021 13:48:32 +0200 Subject: [PATCH 220/280] #124, cc skip link --- info.xml | 8 ++++---- version/203/paymentmethod/tpl/mollieComponents.tpl | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/info.xml b/info.xml index d3215e3..e5cfd5e 100644 --- a/info.xml +++ b/info.xml @@ -265,10 +265,10 @@ skipComponentsLink - - - - + + + + cctitle diff --git a/version/203/paymentmethod/tpl/mollieComponents.tpl b/version/203/paymentmethod/tpl/mollieComponents.tpl index 38907e0..8bcd452 100644 --- a/version/203/paymentmethod/tpl/mollieComponents.tpl +++ b/version/203/paymentmethod/tpl/mollieComponents.tpl @@ -75,7 +75,7 @@ {/if} {if $components == 'S'} {/if}
From 340c238ec485682f294174ce8352414da4e460ad Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Tue, 18 May 2021 14:01:48 +0200 Subject: [PATCH 221/280] fix #126 --- version/203/adminmenu/tpl/orders.tpl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/version/203/adminmenu/tpl/orders.tpl b/version/203/adminmenu/tpl/orders.tpl index 8745a0c..258615b 100644 --- a/version/203/adminmenu/tpl/orders.tpl +++ b/version/203/adminmenu/tpl/orders.tpl @@ -132,7 +132,9 @@ head.appendChild(link); } $(document).ready(function () { - $('.datatable').DataTable(); + $('.datatable').dataTable({ + stateSave: true, + }); });
From beefa1bea93ef633e53c2e42fa26f4a48833c6bd Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Tue, 18 May 2021 16:46:36 +0200 Subject: [PATCH 222/280] #133 --- info.xml | 7 + .../203/class/Checkout/AbstractCheckout.php | 169 +++++++++++++++++- version/203/class/Queue.php | 23 +++ version/203/frontend/131_globalinclude.php | 23 ++- 4 files changed, 212 insertions(+), 10 deletions(-) diff --git a/info.xml b/info.xml index e5cfd5e..c38d935 100644 --- a/info.xml +++ b/info.xml @@ -113,6 +113,13 @@ reminder + + Unbezahlte Bestellungen stornieren + Soll bei fehlgeschlagener Zahlung die Bestellung storniert werden? Angabe in Stunden + nach Bestellung. (0 = deaktiviert) + + autoStorno + Kunden bei Mollie anlegen (Customer API) Wenn diese Einstellung aktiviert ist, hat der Kunde die Möglichkeit, per Checkbox, diff --git a/version/203/class/Checkout/AbstractCheckout.php b/version/203/class/Checkout/AbstractCheckout.php index b76e17e..3710426 100644 --- a/version/203/class/Checkout/AbstractCheckout.php +++ b/version/203/class/Checkout/AbstractCheckout.php @@ -4,7 +4,10 @@ namespace ws_mollie\Checkout; +use Artikel; +use ArtikelHelper; use Bestellung; +use EigenschaftWert; use Exception; use Jtllog; use JTLMollie; @@ -15,7 +18,6 @@ use Mollie\Api\Types\PaymentStatus; use PaymentMethod; use RuntimeException; -use Session; use Shop; use stdClass; use ws_mollie\API; @@ -359,6 +361,171 @@ public static function cancel($checkout) throw new RuntimeException('AbstractCheckout::cancel: Invalid Checkout!'); } + /** + * Storno Order + */ + public function storno() + { + if (in_array((int)$this->getBestellung()->cStatus, [1, 2])) { + + $conf = Shop::getSettings([CONF_GLOBAL, CONF_TRUSTEDSHOPS]); + $nArtikelAnzeigefilter = (int)$conf['global']['artikel_artikelanzeigefilter']; + + foreach ($this->getBestellung()->Positionen as $pos) { + if ($pos->kArtikel && $pos->Artikel && $pos->Artikel->cLagerBeachten === 'Y') { + self::aktualisiereLagerbestand($pos->Artikel, -1 * $pos->nAnzahl, $pos->WarenkorbPosEigenschaftArr, $nArtikelAnzeigefilter); + } + } + + Shop::DB()->executeQueryPrepared('UPDATE tbestellung SET cStatus = :cStatus WHERE kBestellung = :kBestellung', [':cStatus' => '-1', ':kBestellung' => $this->getBestellung()->kBestellung], 3); + } + } + + protected static function aktualisiereLagerbestand($Artikel, $nAnzahl, $WarenkorbPosEigenschaftArr, $nArtikelAnzeigefilter = 1) + { + $artikelBestand = (float)$Artikel->fLagerbestand; + + if (isset($Artikel->cLagerBeachten) && $Artikel->cLagerBeachten === 'Y') { + if ($Artikel->cLagerVariation === 'Y' && + is_array($WarenkorbPosEigenschaftArr) && + count($WarenkorbPosEigenschaftArr) > 0 + ) { + foreach ($WarenkorbPosEigenschaftArr as $eWert) { + $EigenschaftWert = new EigenschaftWert($eWert->kEigenschaftWert); + if ($EigenschaftWert->fPackeinheit == 0) { + $EigenschaftWert->fPackeinheit = 1; + } + Shop::DB()->query( + "UPDATE teigenschaftwert + SET fLagerbestand = fLagerbestand - " . ($nAnzahl * $EigenschaftWert->fPackeinheit) . " + WHERE kEigenschaftWert = " . (int)$eWert->kEigenschaftWert, 4 + ); + } + } elseif ($Artikel->fPackeinheit > 0) { + // Stückliste + if ($Artikel->kStueckliste > 0) { + $artikelBestand = self::aktualisiereStuecklistenLagerbestand($Artikel, $nAnzahl); + } else { + Shop::DB()->query( + "UPDATE tartikel + SET fLagerbestand = IF (fLagerbestand >= " . ($nAnzahl * $Artikel->fPackeinheit) . ", + (fLagerbestand - " . ($nAnzahl * $Artikel->fPackeinheit) . "), fLagerbestand) + WHERE kArtikel = " . (int)$Artikel->kArtikel, 4 + ); + $tmpArtikel = Shop::DB()->select('tartikel', 'kArtikel', (int)$Artikel->kArtikel, null, null, null, null, false, 'fLagerbestand'); + if ($tmpArtikel !== null) { + $artikelBestand = (float)$tmpArtikel->fLagerbestand; + } + // Stücklisten Komponente + if (ArtikelHelper::isStuecklisteKomponente($Artikel->kArtikel)) { + self::aktualisiereKomponenteLagerbestand($Artikel->kArtikel, $artikelBestand, isset($Artikel->cLagerKleinerNull) && $Artikel->cLagerKleinerNull === 'Y' ? true : false); + } + } + // Aktualisiere Merkmale in tartikelmerkmal vom Vaterartikel + if ($Artikel->kVaterArtikel > 0) { + Artikel::beachteVarikombiMerkmalLagerbestand($Artikel->kVaterArtikel, $nArtikelAnzeigefilter); + } + } + } + + return $artikelBestand; + } + + protected static function aktualisiereStuecklistenLagerbestand($oStueckListeArtikel, $nAnzahl) + { + $nAnzahl = (float)$nAnzahl; + $kStueckListe = (int)$oStueckListeArtikel->kStueckliste; + $bestandAlt = (float)$oStueckListeArtikel->fLagerbestand; + $bestandNeu = $bestandAlt; + $bestandUeberverkauf = $bestandAlt; + + if ($nAnzahl > 0) { + // Gibt es lagerrelevante Komponenten in der Stückliste? + $oKomponente_arr = Shop::DB()->query( + "SELECT tstueckliste.kArtikel, tstueckliste.fAnzahl + FROM tstueckliste + JOIN tartikel + ON tartikel.kArtikel = tstueckliste.kArtikel + WHERE tstueckliste.kStueckliste = {$kStueckListe} + AND tartikel.cLagerBeachten = 'Y'", 2 + ); + + if (is_array($oKomponente_arr) && count($oKomponente_arr) > 0) { + // wenn ja, dann wird für diese auch der Bestand aktualisiert + $options = Artikel::getDefaultOptions(); + + $options->nKeineSichtbarkeitBeachten = 1; + + foreach ($oKomponente_arr as $oKomponente) { + $tmpArtikel = new Artikel(); + $tmpArtikel->fuelleArtikel($oKomponente->kArtikel, $options); + + $komponenteBestand = floor(self::aktualisiereLagerbestand($tmpArtikel, $nAnzahl * $oKomponente->fAnzahl, null) / $oKomponente->fAnzahl); + + if ($komponenteBestand < $bestandNeu && $tmpArtikel->cLagerKleinerNull !== 'Y') { + // Neuer Bestand ist der Kleinste Komponententbestand aller Artikel ohne Überverkauf + $bestandNeu = $komponenteBestand; + } elseif ($komponenteBestand < $bestandUeberverkauf) { + // Für Komponenten mit Überverkauf wird der kleinste Bestand ermittelt. + $bestandUeberverkauf = $komponenteBestand; + } + } + } + + // Ist der alte gleich dem neuen Bestand? + if ($bestandAlt === $bestandNeu) { + // Es sind keine lagerrelevanten Komponenten vorhanden, die den Bestand der Stückliste herabsetzen. + if ($bestandUeberverkauf === $bestandNeu) { + // Es gibt auch keine Komponenten mit Überverkäufen, die den Bestand verringern, deshalb wird + // der Bestand des Stücklistenartikels anhand des Verkaufs verringert + $bestandNeu = $bestandNeu - $nAnzahl * $oStueckListeArtikel->fPackeinheit; + } else { + // Da keine lagerrelevanten Komponenten vorhanden sind, wird der kleinste Bestand der + // Komponentent mit Überverkauf verwendet. + $bestandNeu = $bestandUeberverkauf; + } + + Shop::DB()->update('tartikel', 'kArtikel', (int)$oStueckListeArtikel->kArtikel, (object)[ + 'fLagerbestand' => $bestandNeu, + ]); + } + // Kein Lagerbestands-Update für die Stückliste notwendig! Dies erfolgte bereits über die Komponentenabfrage und + // die dortige Lagerbestandsaktualisierung! + } + + return $bestandNeu; + } + + protected static function aktualisiereKomponenteLagerbestand($kKomponenteArtikel, $fLagerbestand, $bLagerKleinerNull) + { + $kKomponenteArtikel = (int)$kKomponenteArtikel; + $fLagerbestand = (float)$fLagerbestand; + + $oStueckliste_arr = Shop::DB()->query( + "SELECT tstueckliste.kStueckliste, tstueckliste.fAnzahl, + tartikel.kArtikel, tartikel.fLagerbestand, tartikel.cLagerKleinerNull + FROM tstueckliste + JOIN tartikel + ON tartikel.kStueckliste = tstueckliste.kStueckliste + WHERE tstueckliste.kArtikel = {$kKomponenteArtikel} + AND tartikel.cLagerBeachten = 'Y'", 2 + ); + + if (is_array($oStueckliste_arr) && count($oStueckliste_arr) > 0) { + foreach ($oStueckliste_arr as $oStueckliste) { + // Ist der aktuelle Bestand der Stückliste größer als dies mit dem Bestand der Komponente möglich wäre? + $maxAnzahl = floor($fLagerbestand / $oStueckliste->fAnzahl); + if ($maxAnzahl < (float)$oStueckliste->fLagerbestand && (!$bLagerKleinerNull || $oStueckliste->cLagerKleinerNull === 'Y')) { + // wenn ja, dann den Bestand der Stückliste entsprechend verringern, aber nur wenn die Komponente nicht + // überberkaufbar ist oder die gesamte Stückliste Überverkäufe zulässt + Shop::DB()->update('tartikel', 'kArtikel', (int)$oStueckliste->kArtikel, (object)[ + 'fLagerbestand' => $maxAnzahl, + ]); + } + } + } + } + /** * @return array|bool|int|object|null */ diff --git a/version/203/class/Queue.php b/version/203/class/Queue.php index c2f03a1..7be72b7 100644 --- a/version/203/class/Queue.php +++ b/version/203/class/Queue.php @@ -23,6 +23,29 @@ class Queue use Plugin; + + public static function storno($delay) + { + if (!$delay) { + return true; + } + + $open = Shop::DB()->executeQueryPrepared("SELECT p.kBestellung, b.cStatus FROM xplugin_ws_mollie_payments p JOIN tbestellung b ON b.kBestellung = p.kBestellung WHERE b.cStatus IN ('1', '2') AND p.dCreatedAt < NOW() - INTERVAL :d HOUR", + [':d' => $delay], 2); + + foreach ($open as $o) { + try { + + $checkout = AbstractCheckout::fromBestellung($o->kBestellung); + $checkout->storno(); + + } catch (Exception $e) { + Helper::logExc($e); + } + } + return true; + } + public static function run($limit = 10) { diff --git a/version/203/frontend/131_globalinclude.php b/version/203/frontend/131_globalinclude.php index ea3d301..3b616f5 100644 --- a/version/203/frontend/131_globalinclude.php +++ b/version/203/frontend/131_globalinclude.php @@ -4,29 +4,34 @@ use ws_mollie\Helper; use ws_mollie\Queue; -//if (strpos($_SERVER['PHP_SELF'], 'bestellabschluss') === false) { -// return; -//} - require_once __DIR__ . '/../class/Helper.php'; - try { Helper::init(); - if(isAjaxRequest()){ - return; + if (isAjaxRequest()) { + return; } + ifndef('MOLLIE_QUEUE_MAX', 3); Queue::run(MOLLIE_QUEUE_MAX); - // TODO: Doku! + + Queue::storno((int)Helper::getSetting('autoStorno')); + ifndef('MOLLIE_REMINDER_PROP', 10); if (mt_rand(1, MOLLIE_REMINDER_PROP) % MOLLIE_REMINDER_PROP === 0) { - AbstractCheckout::sendReminders(); + $lock = new \ws_mollie\ExclusiveLock('mollie_reminder', PFAD_ROOT . PFAD_COMPILEDIR); + if ($lock->lock()) { + // TODO: Doku! + AbstractCheckout::sendReminders(); + $lock->unlock(); + } + } + } catch (Exception $e) { Helper::logExc($e); } From 1ee582116a6cd32993218b55c5e1cb4e205d0502 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Wed, 19 May 2021 15:39:44 +0200 Subject: [PATCH 223/280] #131 --- composer.lock | 89 +++- .../203/class/Checkout/AbstractCheckout.php | 433 ++++++++++++------ version/203/class/Checkout/OrderCheckout.php | 37 +- .../203/class/Checkout/PaymentCheckout.php | 91 ++-- version/203/class/Hook/Queue.php | 9 +- version/203/frontend/131_globalinclude.php | 30 +- version/203/paymentmethod/JTLMollie.php | 6 +- version/203/paymentmethod/JTLMolliePayPal.php | 2 + 8 files changed, 447 insertions(+), 250 deletions(-) diff --git a/composer.lock b/composer.lock index eeace36..ecbc2e2 100644 --- a/composer.lock +++ b/composer.lock @@ -61,6 +61,11 @@ "ssl", "tls" ], + "support": { + "irc": "irc://irc.freenode.org/composer", + "issues": "https://github.com/composer/ca-bundle/issues", + "source": "https://github.com/composer/ca-bundle/tree/1.2.9" + }, "funding": [ { "url": "https://packagist.com", @@ -142,6 +147,10 @@ "rest", "web service" ], + "support": { + "issues": "https://github.com/guzzle/guzzle/issues", + "source": "https://github.com/guzzle/guzzle/tree/6.5" + }, "time": "2020-06-16T21:01:06+00:00" }, { @@ -193,6 +202,10 @@ "keywords": [ "promise" ], + "support": { + "issues": "https://github.com/guzzle/promises/issues", + "source": "https://github.com/guzzle/promises/tree/1.4.1" + }, "time": "2021-03-07T09:25:29+00:00" }, { @@ -264,6 +277,10 @@ "uri", "url" ], + "support": { + "issues": "https://github.com/guzzle/psr7/issues", + "source": "https://github.com/guzzle/psr7/tree/1.8.2" + }, "time": "2021-04-26T09:17:50+00:00" }, { @@ -351,6 +368,10 @@ "sofortbanking", "subscriptions" ], + "support": { + "issues": "https://github.com/mollie/mollie-api-php/issues", + "source": "https://github.com/mollie/mollie-api-php/tree/v2.31.1" + }, "time": "2021-04-26T11:38:41+00:00" }, { @@ -400,6 +421,11 @@ "pseudorandom", "random" ], + "support": { + "email": "info@paragonie.com", + "issues": "https://github.com/paragonie/random_compat/issues", + "source": "https://github.com/paragonie/random_compat" + }, "time": "2021-04-17T09:33:01+00:00" }, { @@ -450,6 +476,9 @@ "request", "response" ], + "support": { + "source": "https://github.com/php-fig/http-message/tree/master" + }, "time": "2016-08-06T14:39:51+00:00" }, { @@ -490,6 +519,10 @@ } ], "description": "A polyfill for getallheaders.", + "support": { + "issues": "https://github.com/ralouphie/getallheaders/issues", + "source": "https://github.com/ralouphie/getallheaders/tree/develop" + }, "time": "2019-03-08T08:55:37+00:00" }, { @@ -561,6 +594,9 @@ "portable", "shim" ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.19.0" + }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -642,6 +678,9 @@ "portable", "shim" ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.19.0" + }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -719,6 +758,9 @@ "portable", "shim" ], + "support": { + "source": "https://github.com/symfony/polyfill-php70/tree/v1.19.0" + }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -792,6 +834,9 @@ "portable", "shim" ], + "support": { + "source": "https://github.com/symfony/polyfill-php72/tree/v1.19.0" + }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -816,12 +861,12 @@ "source": { "type": "git", "url": "https://github.com/Roave/SecurityAdvisories.git", - "reference": "db47aac368cb81bc9d3b09556e63b716be61cf43" + "reference": "42840dcc436945146d79a985240a99ddd3bc5dc7" }, "dist": { "type": "zip", - "url": "https://github.com/gitapi/repos/Roave/SecurityAdvisories/zipball/db47aac368cb81bc9d3b09556e63b716be61cf43", - "reference": "db47aac368cb81bc9d3b09556e63b716be61cf43", + "url": "https://github.com/gitapi/repos/Roave/SecurityAdvisories/zipball/42840dcc436945146d79a985240a99ddd3bc5dc7", + "reference": "42840dcc436945146d79a985240a99ddd3bc5dc7", "shasum": "" }, "conflict": { @@ -839,7 +884,7 @@ "barrelstrength/sprout-forms": "<3.9", "baserproject/basercms": ">=4,<=4.3.6|>=4.4,<4.4.1", "bk2k/bootstrap-package": ">=7.1,<7.1.2|>=8,<8.0.8|>=9,<9.0.4|>=9.1,<9.1.3|>=10,<10.0.10|>=11,<11.0.3", - "bolt/bolt": "<3.7.1", + "bolt/bolt": "<3.7.2", "bolt/core": "<4.1.13", "brightlocal/phpwhois": "<=4.2.5", "buddypress/buddypress": "<5.1.2", @@ -869,8 +914,9 @@ "doctrine/orm": ">=2,<2.4.8|>=2.5,<2.5.1|>=2.8.3,<2.8.4", "dolibarr/dolibarr": "<11.0.4", "dompdf/dompdf": ">=0.6,<0.6.2", - "drupal/core": ">=7,<7.74|>=8,<8.8.11|>=8.9,<8.9.9|>=9,<9.0.8", - "drupal/drupal": ">=7,<7.74|>=8,<8.8.11|>=8.9,<8.9.9|>=9,<9.0.8", + "drupal/core": ">=7,<7.80|>=8,<8.9.14|>=9,<9.0.12|>=9.1,<9.1.7", + "drupal/drupal": ">=7,<7.80|>=8,<8.9.14|>=9,<9.0.12|>=9.1,<9.1.7", + "dweeves/magmi": "<=0.7.24", "endroid/qr-code-bundle": "<3.4.2", "enshrined/svg-sanitize": "<0.13.1", "erusev/parsedown": "<1.7.2", @@ -895,7 +941,9 @@ "flarum/tags": "<=0.1-beta.13", "fluidtypo3/vhs": "<5.1.1", "fooman/tcpdf": "<6.2.22", + "forkcms/forkcms": "<5.8.3", "fossar/tcpdf-parser": "<6.2.22", + "francoisjacquet/rosariosis": "<6.5.1", "friendsofsymfony/oauth2-php": "<1.3", "friendsofsymfony/rest-bundle": ">=1.2,<1.2.2", "friendsofsymfony/user-bundle": ">=1.2,<1.3.5", @@ -926,7 +974,8 @@ "laravel/framework": "<6.20.26|>=7,<8.40", "laravel/socialite": ">=1,<1.0.99|>=2,<2.0.10", "league/commonmark": "<0.18.3", - "librenms/librenms": "<1.53", + "lexik/jwt-authentication-bundle": "<2.10.7|>=2.11,<2.11.3", + "librenms/librenms": "<21.1", "livewire/livewire": ">2.2.4,<2.2.6", "magento/community-edition": ">=2,<2.2.10|>=2.3,<2.3.3", "magento/magento1ce": "<1.9.4.3", @@ -947,11 +996,12 @@ "nystudio107/craft-seomatic": "<3.3", "nzo/url-encryptor-bundle": ">=4,<4.3.2|>=5,<5.0.1", "october/backend": "<1.1.2", - "october/cms": "= 1.0.469|>=1.0.319,<1.0.469", + "october/cms": "= 1.1.1|= 1.0.471|= 1.0.469|>=1.0.319,<1.0.469", "october/october": ">=1.0.319,<1.0.466", "october/rain": "<1.0.472|>=1.1,<1.1.2", "onelogin/php-saml": "<2.10.4", "oneup/uploader-bundle": "<1.9.3|>=2,<2.1.5", + "opencart/opencart": "<=3.0.3.2", "openid/php-openid": "<2.3", "openmage/magento-lts": "<=19.4.12|>=20,<=20.0.8", "orchid/platform": ">=9,<9.4.4", @@ -1045,20 +1095,21 @@ "symfony/http-foundation": ">=2,<2.8.52|>=3,<3.4.35|>=4,<4.2.12|>=4.3,<4.3.8|>=4.4,<4.4.7|>=5,<5.0.7", "symfony/http-kernel": ">=2,<2.8.52|>=3,<3.4.35|>=4,<4.2.12|>=4.3,<4.4.13|>=5,<5.1.5", "symfony/intl": ">=2.7,<2.7.38|>=2.8,<2.8.31|>=3,<3.2.14|>=3.3,<3.3.13", + "symfony/maker-bundle": ">=1.27,<1.29.2|>=1.30,<1.31.1", "symfony/mime": ">=4.3,<4.3.8", "symfony/phpunit-bridge": ">=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", "symfony/polyfill": ">=1,<1.10", "symfony/polyfill-php55": ">=1,<1.10", "symfony/proxy-manager-bridge": ">=2.7,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", "symfony/routing": ">=2,<2.0.19", - "symfony/security": ">=2,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7|>=4.4,<4.4.7|>=5,<5.0.7", + "symfony/security": ">=2,<2.7.51|>=2.8,<3.4.48|>=4,<4.4.23|>=5,<5.2.8", "symfony/security-bundle": ">=2,<2.7.48|>=2.8,<2.8.41|>=3,<3.3.17|>=3.4,<3.4.11|>=4,<4.0.11", - "symfony/security-core": ">=2.4,<2.6.13|>=2.7,<2.7.9|>=2.7.30,<2.7.32|>=2.8,<2.8.37|>=3,<3.3.17|>=3.4,<3.4.7|>=4,<4.0.7", + "symfony/security-core": ">=2.4,<2.6.13|>=2.7,<2.7.9|>=2.7.30,<2.7.32|>=2.8,<3.4.48|>=4,<4.4.23|>=5,<5.2.8", "symfony/security-csrf": ">=2.4,<2.7.48|>=2.8,<2.8.41|>=3,<3.3.17|>=3.4,<3.4.11|>=4,<4.0.11", - "symfony/security-guard": ">=2.8,<2.8.41|>=3,<3.3.17|>=3.4,<3.4.11|>=4,<4.0.11", - "symfony/security-http": ">=2.3,<2.3.41|>=2.4,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.2.12|>=4.3,<4.3.8|>=4.4,<4.4.7|>=5,<5.0.7", + "symfony/security-guard": ">=2.8,<3.4.48|>=4,<4.4.23|>=5,<5.2.8", + "symfony/security-http": ">=2.3,<2.3.41|>=2.4,<2.7.51|>=2.8,<3.4.48|>=4,<4.4.23|>=5,<5.2.8", "symfony/serializer": ">=2,<2.0.11", - "symfony/symfony": ">=2,<2.8.52|>=3,<3.4.35|>=4,<4.2.12|>=4.3,<4.4.13|>=5,<5.1.5", + "symfony/symfony": ">=2,<3.4.48|>=4,<4.4.23|>=5,<5.2.8", "symfony/translation": ">=2,<2.0.17", "symfony/validator": ">=2,<2.0.24|>=2.1,<2.1.12|>=2.2,<2.2.5|>=2.3,<2.3.3", "symfony/var-exporter": ">=4.2,<4.2.12|>=4.3,<4.3.8", @@ -1123,8 +1174,10 @@ "zetacomponents/mail": "<1.8.2", "zf-commons/zfc-user": "<1.2.2", "zfcampus/zf-apigility-doctrine": ">=1,<1.0.3", - "zfr/zfr-oauth2-server-module": "<0.1.2" + "zfr/zfr-oauth2-server-module": "<0.1.2", + "zoujingli/thinkadmin": "<6.0.22" }, + "default-branch": true, "type": "metapackage", "notification-url": "https://packagist.org/downloads/", "license": [ @@ -1143,6 +1196,10 @@ } ], "description": "Prevents installation of composer packages with known security vulnerabilities: no API, simply require it", + "support": { + "issues": "https://github.com/Roave/SecurityAdvisories/issues", + "source": "https://github.com/Roave/SecurityAdvisories/tree/latest" + }, "funding": [ { "url": "https://github.com/Ocramius", @@ -1153,7 +1210,7 @@ "type": "tidelift" } ], - "time": "2021-05-02T09:01:19+00:00" + "time": "2021-05-18T18:23:15+00:00" } ], "aliases": [], @@ -1169,5 +1226,5 @@ "php": ">=5.6" }, "platform-dev": [], - "plugin-api-version": "1.1.0" + "plugin-api-version": "2.0.0" } diff --git a/version/203/class/Checkout/AbstractCheckout.php b/version/203/class/Checkout/AbstractCheckout.php index 3710426..2371066 100644 --- a/version/203/class/Checkout/AbstractCheckout.php +++ b/version/203/class/Checkout/AbstractCheckout.php @@ -18,10 +18,14 @@ use Mollie\Api\Types\PaymentStatus; use PaymentMethod; use RuntimeException; +use Session; use Shop; use stdClass; +use StringHandler; use ws_mollie\API; +use ws_mollie\Checkout\Payment\Amount; use ws_mollie\Helper; +use ws_mollie\Hook\Queue; use ws_mollie\Model\Customer; use ws_mollie\Model\Payment; use ws_mollie\Traits\Plugin; @@ -53,7 +57,6 @@ abstract class AbstractCheckout * @var \Mollie\Api\Resources\Customer|null */ protected $customer; - /** * @var string */ @@ -106,33 +109,107 @@ public static function isMollie($kBestellung, $checkZA = false) ], 1)) && $res->kId; } + public static function finalizeOrder($hash, $id, $test = false) + { + try { + $sessionHash = substr(StringHandler::htmlentities(StringHandler::filterXSS($hash)), 1); + if ($paymentSession = Shop::DB()->select('tzahlungsession', 'cZahlungsID', $sessionHash)) { + if (session_id() !== $paymentSession->cSID) { + session_destroy(); + session_id($paymentSession->cSID); + $session = Session::getInstance(true, true); + } else { + $session = Session::getInstance(false); + } + + if ((!isset($paymentSession->nBezahlt) || !$paymentSession->nBezahlt) + && (!isset($paymentSession->kBestellung) || !$paymentSession->kBestellung) + && isset($_SESSION['Warenkorb']->PositionenArr) + && count($_SESSION['Warenkorb']->PositionenArr)) { + + $paymentSession->cNotifyID = $id; + $paymentSession->dNotify = 'now()'; + Shop::DB()->update('tzahlungsession', 'cZahlungsID', $sessionHash, $paymentSession); + + $api = new API($test); + if (substr($id, 0, 3) === 'tr_') { + $mollie = $api->Client()->payments->get($id); + } else { + $mollie = $api->Client()->orders->get($id); + } + + if (in_array($mollie->status, [OrderStatus::STATUS_PENDING, OrderStatus::STATUS_AUTHORIZED, OrderStatus::STATUS_PAID], true)) { + require_once PFAD_ROOT . PFAD_INCLUDES . 'bestellabschluss_inc.php'; + require_once PFAD_ROOT . PFAD_INCLUDES . 'mailTools.php'; + $order = finalisiereBestellung(); + $session->cleanUp(); + $paymentSession->nBezahlt = 1; + $paymentSession->dZeitBezahlt = 'now()'; + } else { + throw new Exception('Mollie Status invalid: ' . $mollie->status . '\n' . print_r([$hash, $id], 1)); + } + + if ($order->kBestellung) { + + $paymentSession->kBestellung = (int)$order->kBestellung; + Shop::DB()->update('tzahlungsession', 'cZahlungsID', $sessionHash, $paymentSession); + + try { + $checkout = AbstractCheckout::fromID($id, false, $order); + } catch (Exception $e) { + if (substr($id, 0, 3) === 'tr_') { + $checkoutClass = PaymentCheckout::class; + } else { + $checkoutClass = OrderCheckout::class; + } + $checkout = new $checkoutClass($order, $api); + } + $checkout->setMollie($mollie); + $checkout->handleNotification($hash); + } + } else { + Jtllog::writeLog(sprintf('PaymentSession bereits bezahlt: %s - ID: %s => Queue', $sessionHash, $id), JTLLOG_LEVEL_NOTICE); + Queue::saveToQueue($id, $id, 'webhook'); + } + } else { + Jtllog::writeLog(sprintf('PaymentSession nicht gefunden: %s - ID: %s => Queue', $sessionHash, $id), JTLLOG_LEVEL_ERROR); + Queue::saveToQueue($id, $id, 'webhook'); + } + } catch (Exception $e) { + Helper::logExc($e); + } + } + /** - * @param $kBestellung + * @param $id * @return OrderCheckout|PaymentCheckout - * * @throws RuntimeException + * @throws RuntimeException */ - public static function fromBestellung($kBestellung) + public static function fromID($id, $bFill = true, Bestellung $order = null) { - if ($model = Payment::fromID($kBestellung, 'kBestellung')) { - return self::fromModel($model); + if ($model = Payment::fromID($id)) { + return static::fromModel($model, $bFill, $order); } - throw new RuntimeException(sprintf('Error loading Order for Bestellung: %s', $kBestellung)); + throw new RuntimeException(sprintf('Error loading Order: %s', $id)); } /** * @param $model + * @param bool $bFill * @return OrderCheckout|PaymentCheckout - * @throws RuntimeException */ - public static function fromModel($model, $bFill = true) + public static function fromModel($model, $bFill = true, Bestellung $order = null) { if (!$model) { throw new RuntimeException(sprintf('Error loading Order for Model: %s', print_r($model, 1))); } - $oBestellung = new Bestellung($model->kBestellung, $bFill); - if (!$oBestellung->kBestellung) { - throw new RuntimeException(sprintf('Error loading Bestellung: %s', $model->kBestellung)); + $oBestellung = $order; + if ($model->kBestellung && !$order) { + $oBestellung = new Bestellung($model->kBestellung, $bFill); + if (!$oBestellung->kBestellung) { + throw new RuntimeException(sprintf('Error loading Bestellung: %s', $model->kBestellung)); + } } if (strpos($model->kID, 'tr_') !== false) { @@ -145,6 +222,19 @@ public static function fromModel($model, $bFill = true) return $self; } + /** + * @param $kBestellung + * @return OrderCheckout|PaymentCheckout + * * @throws RuntimeException + */ + public static function fromBestellung($kBestellung) + { + if ($model = Payment::fromID($kBestellung, 'kBestellung')) { + return self::fromModel($model); + } + throw new RuntimeException(sprintf('Error loading Order for Bestellung: %s', $kBestellung)); + } + public static function sendReminders() { $reminder = (int)self::Plugin()->oPluginEinstellungAssoc_arr['reminder']; @@ -216,19 +306,6 @@ public static function sendReminder($kID) return $return; } - /** - * @param $id - * @return OrderCheckout|PaymentCheckout - * @throws RuntimeException - */ - public static function fromID($id) - { - if ($model = Payment::fromID($id)) { - return static::fromModel($model); - } - throw new RuntimeException(sprintf('Error loading Order: %s', $id)); - } - /** * @param AbstractCheckout $checkout * @return \Mollie\Api\Resources\BaseResource|\Mollie\Api\Resources\Refund @@ -260,22 +337,53 @@ public static function refund(AbstractCheckout $checkout) } /** - * @param false $force - * @return Order|\Mollie\Api\Resources\Payment|null + * @param $checkout + * @return Order|\Mollie\Api\Resources\Payment + * @throws ApiException */ - abstract public function getMollie($force = false); + public static function cancel($checkout) + { + if ($checkout instanceof OrderCheckout) { + return OrderCheckout::cancel($checkout); + } + if ($checkout instanceof PaymentCheckout) { + return PaymentCheckout::cancel($checkout); + } + throw new RuntimeException('AbstractCheckout::cancel: Invalid Checkout!'); + } - public function Log($msg, $level = LOGLEVEL_NOTICE) + public function loadRequest($options = []) { - $data = ''; if ($this->getBestellung()) { - $data .= '#' . $this->getBestellung()->kBestellung; - } - if ($this->getMollie()) { - $data .= '$' . $this->getMollie()->id; + if ($this->getBestellung()->oKunde->nRegistriert + && ($customer = $this->getCustomer( + array_key_exists('mollie_create_customer', $_SESSION['cPost_arr'] ?: []) && $_SESSION['cPost_arr']['mollie_create_customer'] === 'Y') + ) + && isset($customer)) { + $options['customerId'] = $customer->id; + } + $this->amount = Amount::factory($this->getBestellung()->fGesamtsummeKundenwaehrung, $this->getBestellung()->Waehrung->cISO, true); + $this->redirectUrl = $this->PaymentMethod()->duringCheckout ? Shop::getURL() . '/bestellabschluss.php?' . http_build_query(['hash' => $this->getHash()]) : $this->PaymentMethod()->getReturnURL($this->getBestellung()); + $this->metadata = [ + 'kBestellung' => $this->getBestellung()->kBestellung ?: $this->getBestellung()->cBestellNr, + 'kKunde' => $this->getBestellung()->kKunde, + 'kKundengruppe' => Session::getInstance()->CustomerGroup()->kKundengruppe, + 'cHash' => $this->getHash(), + ]; + } + $this->locale = self::getLocale($_SESSION['cISOSprache'], Session::getInstance()->Customer()->cLand); + $this->webhookUrl = Shop::getURL(true) . '/?' . http_build_query([ + 'mollie' => 1, + 'hash' => $this->getHash(), + 'test' => $this->API()->isTest() ?: null, + ]); + + $pm = $this->PaymentMethod(); + $isPayAgain = strpos($_SERVER['PHP_SELF'], 'bestellab_again') !== false; + if ($pm::METHOD !== '' && (self::Plugin()->oPluginEinstellungAssoc_arr['resetMethod'] !== 'Y' || !$isPayAgain)) { + $this->method = $pm::METHOD; } - ZahlungsLog::add($this->PaymentMethod()->moduleID, "[" . microtime(true) . " - " . $_SERVER['PHP_SELF'] . "] " . $msg, $data, $level); - return $this; + } /** @@ -315,19 +423,64 @@ protected function setModel($model) } /** - * @return JTLMollie + * @return \Mollie\Api\Resources\Customer|null + * @todo: Kunde wieder löschbar machen ?! */ - public function PaymentMethod() + public function getCustomer($createOrUpdate = false) { - if (!$this->paymentMethod) { - if ($this->getBestellung()->Zahlungsart && strpos($this->getBestellung()->Zahlungsart->cModulId, "kPlugin_{$this::Plugin()->kPlugin}_") !== false) { - $this->paymentMethod = PaymentMethod::create($this->getBestellung()->Zahlungsart->cModulId); - } else { - $this->paymentMethod = PaymentMethod::create("kPlugin_{$this::Plugin()->kPlugin}_mollie"); + if (!$this->customer) { + $customerModel = Customer::fromID($this->getBestellung()->oKunde->kKunde, 'kKunde'); + if ($customerModel->customerId) { + try { + $this->customer = $this->API()->Client()->customers->get($customerModel->customerId); + } catch (ApiException $e) { + $this->Log(sprintf("Fehler beim laden des Mollie Customers %s (kKunde: %d): %s", $customerModel->customerId, $customerModel->kKunde, $e->getMessage()), LOGLEVEL_ERROR); + } + } + + if ($createOrUpdate) { + $oKunde = $this->getBestellung()->oKunde; + + $customer = [ + 'name' => utf8_encode(trim($oKunde->cVorname . ' ' . $oKunde->cNachname)), + 'email' => utf8_encode($oKunde->cMail), + 'locale' => self::getLocale($_SESSION['cISOSprache'], $oKunde->cLand), + 'metadata' => (object)[ + 'kKunde' => $oKunde->kKunde, + 'kKundengruppe' => $oKunde->kKundengruppe, + 'cKundenNr' => utf8_encode($oKunde->cKundenNr), + ], + ]; + + if ($this->customer) { // UPDATE + + $this->customer->name = $customer['name']; + $this->customer->email = $customer['email']; + $this->customer->locale = $customer['locale']; + $this->customer->metadata = $customer['metadata']; + + try { + $this->customer->update(); + } catch (Exception $e) { + $this->Log(sprintf("Fehler beim aktualisieren des Mollie Customers %s: %s\n%s", $this->customer->id, $e->getMessage(), print_r($customer, 1)), LOGLEVEL_ERROR); + } + + + } else { // create + + try { + $this->customer = $this->API()->Client()->customers->create($customer); + $customerModel->kKunde = $oKunde->kKunde; + $customerModel->customerId = $this->customer->id; + $customerModel->save(); + $this->Log(sprintf("Customer '%s' für Kunde %s (%d) bei Mollie angelegt.", $this->customer->id, $this->customer->name, $this->getBestellung()->kKunde)); + } catch (Exception $e) { + $this->Log(sprintf("Fehler beim anlegen eines Mollie Customers: %s\n%s", $e->getMessage(), print_r($customer, 1)), LOGLEVEL_ERROR); + } + } } } - /** @noinspection PhpIncompatibleReturnTypeInspection */ - return $this->paymentMethod; + return $this->customer; } /** @@ -345,20 +498,72 @@ public function API() return $this->api; } + public function Log($msg, $level = LOGLEVEL_NOTICE) + { + $data = ''; + if ($this->getBestellung()) { + $data .= '#' . $this->getBestellung()->kBestellung; + } + if ($this->getMollie()) { + $data .= '$' . $this->getMollie()->id; + } + ZahlungsLog::add($this->PaymentMethod()->moduleID, "[" . microtime(true) . " - " . $_SERVER['PHP_SELF'] . "] " . $msg, $data, $level); + return $this; + } + /** - * @param $checkout - * @return Order|\Mollie\Api\Resources\Payment - * @throws ApiException + * @param false $force + * @return Order|\Mollie\Api\Resources\Payment|null */ - public static function cancel($checkout) + abstract public function getMollie($force = false); + + /** + * @return JTLMollie + */ + public function PaymentMethod() { - if ($checkout instanceof OrderCheckout) { - return OrderCheckout::cancel($checkout); + if (!$this->paymentMethod) { + if ($this->getBestellung()->Zahlungsart && strpos($this->getBestellung()->Zahlungsart->cModulId, "kPlugin_{$this::Plugin()->kPlugin}_") !== false) { + $this->paymentMethod = PaymentMethod::create($this->getBestellung()->Zahlungsart->cModulId); + } else { + $this->paymentMethod = PaymentMethod::create("kPlugin_{$this::Plugin()->kPlugin}_mollie"); + } } - if ($checkout instanceof PaymentCheckout) { - return PaymentCheckout::cancel($checkout); + /** @noinspection PhpIncompatibleReturnTypeInspection */ + return $this->paymentMethod; + } + + public static function getLocale($cISOSprache = null, $country = null) + { + + if ($cISOSprache === null) { + $cISOSprache = gibStandardsprache()->cISO; } - throw new RuntimeException('AbstractCheckout::cancel: Invalid Checkout!'); + if (array_key_exists($cISOSprache, self::$localeLangs)) { + $locale = self::$localeLangs[$cISOSprache]['lang']; + if ($country && is_array(self::$localeLangs[$cISOSprache]['country']) && in_array($country, self::$localeLangs[$cISOSprache]['country'], true)) { + $locale .= '_' . strtoupper($country); + } else { + $locale .= '_' . self::$localeLangs[$cISOSprache]['country'][0]; + } + return $locale; + } + + return self::Plugin()->oPluginEinstellungAssoc_arr['fallbackLocale']; + } + + /** + * @return string + */ + public function getHash() + { + if ($this->getModel()->cHash) { + return $this->getModel()->cHash; + } + if (!$this->hash) { + $this->hash = $this->PaymentMethod()->generateHash($this->oBestellung); + } + return $this->hash; } /** @@ -366,18 +571,24 @@ public static function cancel($checkout) */ public function storno() { - if (in_array((int)$this->getBestellung()->cStatus, [1, 2])) { + if (in_array((int)$this->getBestellung()->cStatus, [BESTELLUNG_STATUS_OFFEN, BESTELLUNG_STATUS_IN_BEARBEITUNG], true)) { + + $log = []; $conf = Shop::getSettings([CONF_GLOBAL, CONF_TRUSTEDSHOPS]); $nArtikelAnzeigefilter = (int)$conf['global']['artikel_artikelanzeigefilter']; foreach ($this->getBestellung()->Positionen as $pos) { if ($pos->kArtikel && $pos->Artikel && $pos->Artikel->cLagerBeachten === 'Y') { + $log[] = sprintf('Reset stock of "%s" by %d', $pos->Artikel->cArtNr, -1 * $pos->nAnzahl); self::aktualisiereLagerbestand($pos->Artikel, -1 * $pos->nAnzahl, $pos->WarenkorbPosEigenschaftArr, $nArtikelAnzeigefilter); } } + $log[] = sprintf("Cancel order '%s'.", $this->getBestellung()->cBestellNr); - Shop::DB()->executeQueryPrepared('UPDATE tbestellung SET cStatus = :cStatus WHERE kBestellung = :kBestellung', [':cStatus' => '-1', ':kBestellung' => $this->getBestellung()->kBestellung], 3); + if (Shop::DB()->executeQueryPrepared('UPDATE tbestellung SET cStatus = :cStatus WHERE kBestellung = :kBestellung', [':cStatus' => '-1', ':kBestellung' => $this->getBestellung()->kBestellung], 3)) { + $this->Log(implode('\n', $log)); + } } } @@ -563,86 +774,6 @@ public function LogData() return $data; } - /** - * @return \Mollie\Api\Resources\Customer|null - * @todo: Kunde wieder löschbar machen ?! - */ - public function getCustomer($createOrUpdate = false) - { - if (!$this->customer) { - $customerModel = Customer::fromID($this->getBestellung()->oKunde->kKunde, 'kKunde'); - if ($customerModel->customerId) { - try { - $this->customer = $this->API()->Client()->customers->get($customerModel->customerId); - } catch (ApiException $e) { - $this->Log(sprintf("Fehler beim laden des Mollie Customers %s (kKunde: %d): %s", $customerModel->customerId, $customerModel->kKunde, $e->getMessage()), LOGLEVEL_ERROR); - } - } - - if ($createOrUpdate) { - $oKunde = $this->getBestellung()->oKunde; - - $customer = [ - 'name' => utf8_encode(trim($oKunde->cVorname . ' ' . $oKunde->cNachname)), - 'email' => utf8_encode($oKunde->cMail), - 'locale' => self::getLocale($_SESSION['cISOSprache'], $oKunde->cLand), - 'metadata' => (object)[ - 'kKunde' => $oKunde->kKunde, - 'kKundengruppe' => $oKunde->kKundengruppe, - 'cKundenNr' => utf8_encode($oKunde->cKundenNr), - ], - ]; - - if ($this->customer) { // UPDATE - - $this->customer->name = $customer['name']; - $this->customer->email = $customer['email']; - $this->customer->locale = $customer['locale']; - $this->customer->metadata = $customer['metadata']; - - try { - $this->customer->update(); - } catch (Exception $e) { - $this->Log(sprintf("Fehler beim aktualisieren des Mollie Customers %s: %s\n%s", $this->customer->id, $e->getMessage(), print_r($customer, 1)), LOGLEVEL_ERROR); - } - - - } else { // create - - try { - $this->customer = $this->API()->Client()->customers->create($customer); - $customerModel->kKunde = $oKunde->kKunde; - $customerModel->customerId = $this->customer->id; - $customerModel->save(); - $this->Log(sprintf("Customer '%s' für Kunde %s (%d) bei Mollie angelegt.", $this->customer->id, $this->customer->name, $this->getBestellung()->kKunde)); - } catch (Exception $e) { - $this->Log(sprintf("Fehler beim anlegen eines Mollie Customers: %s\n%s", $e->getMessage(), print_r($customer, 1)), LOGLEVEL_ERROR); - } - } - } - } - return $this->customer; - } - - public static function getLocale($cISOSprache = null, $country = null) - { - - if ($cISOSprache === null) { - $cISOSprache = gibStandardsprache()->cISO; - } - if (array_key_exists($cISOSprache, self::$localeLangs)) { - $locale = self::$localeLangs[$cISOSprache]['lang']; - if ($country && is_array(self::$localeLangs[$cISOSprache]['country']) && in_array($country, self::$localeLangs[$cISOSprache]['country'], true)) { - $locale .= '_' . strtoupper($country); - } else { - $locale .= '_' . self::$localeLangs[$cISOSprache]['country'][0]; - } - return $locale; - } - - return self::Plugin()->oPluginEinstellungAssoc_arr['fallbackLocale']; - } - abstract public function cancelOrRefund($force = false); /** @@ -682,20 +813,6 @@ public function handleNotification($hash = null) } } - /** - * @return string - */ - public function getHash() - { - if ($this->getModel()->cHash) { - return $this->getModel()->cHash; - } - if (!$this->hash) { - $this->hash = $this->PaymentMethod()->generateHash($this->oBestellung); - } - return $this->hash; - } - /** * @return bool */ @@ -785,4 +902,20 @@ public function getRepayURL() return Shop::getURL(true) . '/?m_pay=' . md5($this->getModel()->kID . '-' . $this->getBestellung()->kBestellung); } + /** + * @param Bestellung $oBestellung + * @return $this + */ + protected function setBestellung(Bestellung $oBestellung) + { + $this->oBestellung = $oBestellung; + return $this; + } + + /** + * @param Order|\Mollie\Api\Resources\Payment $model + * @return self + */ + abstract protected function setMollie($model); + } \ No newline at end of file diff --git a/version/203/class/Checkout/OrderCheckout.php b/version/203/class/Checkout/OrderCheckout.php index c2a67bd..fd17e35 100644 --- a/version/203/class/Checkout/OrderCheckout.php +++ b/version/203/class/Checkout/OrderCheckout.php @@ -248,32 +248,9 @@ public function updateModel() public function loadRequest($options = []) { - if ($this->getBestellung()->oKunde->nRegistriert - && ($customer = $this->getCustomer( - array_key_exists('mollie_create_customer', $_SESSION['cPost_arr'] ?: []) && $_SESSION['cPost_arr']['mollie_create_customer'] === 'Y') - ) - && isset($customer)) { - $options['customerId'] = $customer->id; - } + parent::loadRequest($options); - $this->locale = self::getLocale($_SESSION['cISOSprache'], Session::getInstance()->Customer()->cLand); - $this->amount = Amount::factory($this->getBestellung()->fGesamtsummeKundenwaehrung, $this->getBestellung()->Waehrung->cISO, true); $this->orderNumber = $this->getBestellung()->cBestellNr; - $this->metadata = [ - 'kBestellung' => $this->getBestellung()->kBestellung, - 'kKunde' => $this->getBestellung()->kKunde, - 'kKundengruppe' => Session::getInstance()->CustomerGroup()->kKundengruppe, - 'cHash' => $this->getHash(), - ]; - - $this->redirectUrl = $this->PaymentMethod()->getReturnURL($this->getBestellung()); - $this->webhookUrl = Shop::getURL(true) . '/?mollie=1'; - - $pm = $this->PaymentMethod(); - $isPayAgain = strpos($_SERVER['PHP_SELF'], 'bestellab_again') !== false; - if ($pm::METHOD !== '' && (self::Plugin()->oPluginEinstellungAssoc_arr['resetMethod'] !== 'Y' || !$isPayAgain)) { - $this->method = $pm::METHOD; - } $this->billingAddress = Address::factory($this->getBestellung()->oRechnungsadresse); if ($this->getBestellung()->Lieferadresse !== null) { @@ -359,4 +336,16 @@ public function getIncomingPayment() } return null; } + + /** + * @param Order $model + * @return $this|AbstractCheckout + */ + protected function setMollie($model) + { + if ($model instanceof Order) { + $this->order = $model; + } + return $this; + } } \ No newline at end of file diff --git a/version/203/class/Checkout/PaymentCheckout.php b/version/203/class/Checkout/PaymentCheckout.php index fc88a64..52149eb 100644 --- a/version/203/class/Checkout/PaymentCheckout.php +++ b/version/203/class/Checkout/PaymentCheckout.php @@ -10,8 +10,6 @@ use Mollie\Api\Resources\Payment; use Mollie\Api\Types\PaymentStatus; use RuntimeException; -use Session; -use Shop; use ws_mollie\Checkout\Payment\Address; use ws_mollie\Checkout\Payment\Amount; @@ -38,27 +36,17 @@ class PaymentCheckout extends AbstractCheckout protected $_payment; /** - * @return string - * @throws ApiException - * @throws IncompatiblePlatform + * @param PaymentCheckout $checkout + * @return Payment */ - public function cancelOrRefund($force = false) + public static function cancel($checkout) { - if (!$this->getMollie()) { - throw new RuntimeException('Mollie-Order konnte nicht geladen werden: ' . $this->getModel()->kID); - } - if ($force || (int)$this->getBestellung()->cStatus === BESTELLUNG_STATUS_STORNO) { - if ($this->getMollie()->isCancelable) { - $res = $this->API()->Client()->payments->cancel($this->getMollie()->id); - $result = 'Payment cancelled, Status: ' . $res->status; - } else { - $res = $this->API()->Client()->payments->refund($this->getMollie(), ['amount' => $this->getMollie()->amount]); - $result = "Payment Refund initiiert, Status: " . $res->status; - } - $this->PaymentMethod()->Log("PaymentCheckout::cancelOrRefund: " . $result, $this->LogData()); - return $result; + if (!$checkout->getMollie()->isCancelable) { + throw new RuntimeException('Zahlung kann nicht abgebrochen werden.'); } - throw new RuntimeException('Bestellung ist derzeit nicht storniert, Status: ' . $this->getBestellung()->cStatus); + $payment = $checkout->API()->Client()->payments->cancel($checkout->getMollie()->id); + $checkout->Log('Zahlung wurde manuell abgebrochen.'); + return $payment; } /** @@ -95,6 +83,30 @@ public function setPayment($payment) return $this; } + /** + * @return string + * @throws ApiException + * @throws IncompatiblePlatform + */ + public function cancelOrRefund($force = false) + { + if (!$this->getMollie()) { + throw new RuntimeException('Mollie-Order konnte nicht geladen werden: ' . $this->getModel()->kID); + } + if ($force || (int)$this->getBestellung()->cStatus === BESTELLUNG_STATUS_STORNO) { + if ($this->getMollie()->isCancelable) { + $res = $this->API()->Client()->payments->cancel($this->getMollie()->id); + $result = 'Payment cancelled, Status: ' . $res->status; + } else { + $res = $this->API()->Client()->payments->refund($this->getMollie(), ['amount' => $this->getMollie()->amount]); + $result = "Payment Refund initiiert, Status: " . $res->status; + } + $this->PaymentMethod()->Log("PaymentCheckout::cancelOrRefund: " . $result, $this->LogData()); + return $result; + } + throw new RuntimeException('Bestellung ist derzeit nicht storniert, Status: ' . $this->getBestellung()->cStatus); + } + /** * @param array $paymentOptions * @return \Mollie\Api\Resources\Order|Payment|\ws_mollie\Model\Payment @@ -131,7 +143,6 @@ public function create(array $paymentOptions = []) } } - /** * @param array $options * @return $this|PaymentCheckout @@ -139,30 +150,10 @@ public function create(array $paymentOptions = []) public function loadRequest($options = []) { - if ($this->getBestellung()->oKunde->nRegistriert - && ($customer = $this->getCustomer( - array_key_exists('mollie_create_customer', $_SESSION['cPost_arr'] ?: []) && $_SESSION['cPost_arr']['mollie_create_customer'] === 'Y') - ) - && isset($customer)) { - $options['customerId'] = $customer->id; - } + parent::loadRequest($options); - $this->amount = Amount::factory($this->getBestellung()->fGesamtsummeKundenwaehrung, $this->getBestellung()->Waehrung->cISO, true); $this->description = 'Order ' . $this->getBestellung()->cBestellNr; - $this->redirectUrl = $this->PaymentMethod()->getReturnURL($this->getBestellung()); - $this->webhookUrl = Shop::getURL(true) . '/?mollie=1'; - $this->locale = self::getLocale($_SESSION['cISOSprache'], Session::getInstance()->Customer()->cLand); - $this->metadata = [ - 'kBestellung' => $this->getBestellung()->kBestellung, - 'kKunde' => $this->getBestellung()->kKunde, - 'kKundengruppe' => Session::getInstance()->CustomerGroup()->kKundengruppe, - 'cHash' => $this->getHash(), - ]; - $pm = $this->PaymentMethod(); - $isPayAgain = strpos($_SERVER['PHP_SELF'], 'bestellab_again') !== false; - if ($pm::METHOD !== '' && (self::Plugin()->oPluginEinstellungAssoc_arr['resetMethod'] !== 'Y' || !$isPayAgain)) { - $this->method = $pm::METHOD; - } + foreach ($options as $key => $value) { $this->$key = $value; } @@ -194,16 +185,14 @@ public function getIncomingPayment() } /** - * @param PaymentCheckout $checkout - * @return Payment + * @param Payment $model + * @return $this|AbstractCheckout */ - public static function cancel($checkout) + protected function setMollie($model) { - if(!$checkout->getMollie()->isCancelable){ - throw new RuntimeException('Zahlung kann nicht abgebrochen werden.'); + if ($model instanceof Payment) { + $this->setPayment($model); } - $payment = $checkout->API()->Client()->payments->cancel($checkout->getMollie()->id); - $checkout->Log('Zahlung wurde manuell abgebrochen.'); - return $payment; + return $this; } } \ No newline at end of file diff --git a/version/203/class/Hook/Queue.php b/version/203/class/Hook/Queue.php index 9dbef9b..7fbed03 100644 --- a/version/203/class/Hook/Queue.php +++ b/version/203/class/Hook/Queue.php @@ -50,7 +50,7 @@ public static function xmlBestellStatus(array $args_arr) * @param string $type * @return bool */ - protected static function saveToQueue($hook, $args_arr, $type = 'hook') + public static function saveToQueue($hook, $args_arr, $type = 'hook') { $mQueue = new QueueModel(); $mQueue->cType = $type . ':' . $hook; @@ -79,7 +79,12 @@ public static function xmlBearbeiteStorno(array $args_arr) public static function headPostGet() { if (array_key_exists('mollie', $_REQUEST) && (int)$_REQUEST['mollie'] === 1 && array_key_exists('id', $_REQUEST)) { - self::saveToQueue($_REQUEST['id'], $_REQUEST['id'], 'webhook'); + + if (array_key_exists('hash', $_REQUEST)) { + AbstractCheckout::finalizeOrder($_REQUEST['hash'], $_REQUEST['id'], array_key_exists('test', $_REQUEST)); + } else { + self::saveToQueue($_REQUEST['id'], $_REQUEST['id'], 'webhook'); + } exit(); } if (array_key_exists('m_pay', $_REQUEST)) { diff --git a/version/203/frontend/131_globalinclude.php b/version/203/frontend/131_globalinclude.php index 3b616f5..a5cce47 100644 --- a/version/203/frontend/131_globalinclude.php +++ b/version/203/frontend/131_globalinclude.php @@ -13,22 +13,44 @@ return; } - ifndef('MOLLIE_QUEUE_MAX', 3); Queue::run(MOLLIE_QUEUE_MAX); - - Queue::storno((int)Helper::getSetting('autoStorno')); + if (strpos($_SERVER['PHP_SELF'], 'bestellabschluss.php') !== false + && array_key_exists('hash', $_REQUEST)) { + $sessionHash = substr(StringHandler::htmlentities(StringHandler::filterXSS($_REQUEST['hash'])), 1); + $paymentSession = Shop::DB()->select('tzahlungsession', 'cZahlungsID', $sessionHash); + if ($paymentSession && $paymentSession->kBestellung) { + $oBestellung = new Bestellung($paymentSession->kBestellung); + + if (Shopsetting::getInstance()->getValue('kaufabwicklung', 'bestellabschluss_abschlussseite') === 'A') { + $oZahlungsID = Shop::DB()->query(" + SELECT cId + FROM tbestellid + WHERE kBestellung = " . (int)$order->kBestellung, 1 + ); + if (is_object($oZahlungsID)) { + header('Location: ' . Shop::getURL() . '/bestellabschluss.php?i=' . $oZahlungsID->cId); + exit(); + } + } + $bestellstatus = Shop::DB()->select('tbestellstatus', 'kBestellung', (int)$paymentSession->kBestellung); + header('Location: ' . Shop::getURL() . '/status.php?uid=' . $bestellstatus->cUID); + exit(); + } + } ifndef('MOLLIE_REMINDER_PROP', 10); if (mt_rand(1, MOLLIE_REMINDER_PROP) % MOLLIE_REMINDER_PROP === 0) { $lock = new \ws_mollie\ExclusiveLock('mollie_reminder', PFAD_ROOT . PFAD_COMPILEDIR); if ($lock->lock()) { // TODO: Doku! + AbstractCheckout::sendReminders(); + Queue::storno((int)Helper::getSetting('autoStorno')); + $lock->unlock(); } - } diff --git a/version/203/paymentmethod/JTLMollie.php b/version/203/paymentmethod/JTLMollie.php index bcefebd..57ce70a 100644 --- a/version/203/paymentmethod/JTLMollie.php +++ b/version/203/paymentmethod/JTLMollie.php @@ -66,7 +66,7 @@ public function preparePaymentProcess($order) try { - if ($this->duringCheckout) { + if ($this->duringCheckout && !static::ALLOW_PAYMENT_BEFORE_ORDER) { $this->Log(sprintf("Zahlung vor Bestellabschluss nicht unterstützt (%s)!", $order->cBestellNr), sprintf("#%s", $order->kBestellung), LOGLEVEL_ERROR); return; } @@ -223,8 +223,8 @@ protected static function isMethodPossible($method, $locale, $billingCountry, $c 'resource' => 'orders', 'includeWallets' => 'applepay', ]); - foreach($active as $a){ - $_SESSION['mollie_possibleMethods'][$key][] = (object)['id' =>$a->id]; + foreach ($active as $a) { + $_SESSION['mollie_possibleMethods'][$key][] = (object)['id' => $a->id]; } } diff --git a/version/203/paymentmethod/JTLMolliePayPal.php b/version/203/paymentmethod/JTLMolliePayPal.php index dd13aaf..d26096c 100644 --- a/version/203/paymentmethod/JTLMolliePayPal.php +++ b/version/203/paymentmethod/JTLMolliePayPal.php @@ -11,6 +11,8 @@ class JTLMolliePayPal extends JTLMollie { const METHOD = \Mollie\Api\Types\PaymentMethod::PAYPAL; + const ALLOW_PAYMENT_BEFORE_ORDER = true; + /** * @throws ApiException * @throws IncompatiblePlatform From 3c17aa19ea0c51298c6bdc930977d1ad2a34ae7f Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Wed, 19 May 2021 18:49:30 +0200 Subject: [PATCH 224/280] #131 --- .../203/class/Checkout/AbstractCheckout.php | 184 +++++++++--------- version/203/class/Checkout/OrderCheckout.php | 2 +- version/203/class/Hook/Queue.php | 7 +- version/203/class/Model/AbstractModel.php | 4 +- version/203/class/Model/Payment.php | 2 +- 5 files changed, 100 insertions(+), 99 deletions(-) diff --git a/version/203/class/Checkout/AbstractCheckout.php b/version/203/class/Checkout/AbstractCheckout.php index 2371066..a910989 100644 --- a/version/203/class/Checkout/AbstractCheckout.php +++ b/version/203/class/Checkout/AbstractCheckout.php @@ -21,7 +21,6 @@ use Session; use Shop; use stdClass; -use StringHandler; use ws_mollie\API; use ws_mollie\Checkout\Payment\Amount; use ws_mollie\Helper; @@ -109,10 +108,9 @@ public static function isMollie($kBestellung, $checkZA = false) ], 1)) && $res->kId; } - public static function finalizeOrder($hash, $id, $test = false) + public static function finalizeOrder($sessionHash, $id, $test = false) { try { - $sessionHash = substr(StringHandler::htmlentities(StringHandler::filterXSS($hash)), 1); if ($paymentSession = Shop::DB()->select('tzahlungsession', 'cZahlungsID', $sessionHash)) { if (session_id() !== $paymentSession->cSID) { session_destroy(); @@ -146,7 +144,7 @@ public static function finalizeOrder($hash, $id, $test = false) $paymentSession->nBezahlt = 1; $paymentSession->dZeitBezahlt = 'now()'; } else { - throw new Exception('Mollie Status invalid: ' . $mollie->status . '\n' . print_r([$hash, $id], 1)); + throw new Exception('Mollie Status invalid: ' . $mollie->status . '\n' . print_r([$sessionHash, $id], 1)); } if ($order->kBestellung) { @@ -165,7 +163,7 @@ public static function finalizeOrder($hash, $id, $test = false) $checkout = new $checkoutClass($order, $api); } $checkout->setMollie($mollie); - $checkout->handleNotification($hash); + $checkout->handleNotification($sessionHash); } } else { Jtllog::writeLog(sprintf('PaymentSession bereits bezahlt: %s - ID: %s => Queue', $sessionHash, $id), JTLLOG_LEVEL_NOTICE); @@ -205,7 +203,7 @@ public static function fromModel($model, $bFill = true, Bestellung $order = null } $oBestellung = $order; - if ($model->kBestellung && !$order) { + if (!$order) { $oBestellung = new Bestellung($model->kBestellung, $bFill); if (!$oBestellung->kBestellung) { throw new RuntimeException(sprintf('Error loading Bestellung: %s', $model->kBestellung)); @@ -336,6 +334,92 @@ public static function refund(AbstractCheckout $checkout) throw new RuntimeException(sprintf('Unbekannte Resource: %s', $checkout->getMollie()->resource)); } + /** + * @param false $force + * @return Order|\Mollie\Api\Resources\Payment|null + */ + abstract public function getMollie($force = false); + + public function Log($msg, $level = LOGLEVEL_NOTICE) + { + $data = ''; + if ($this->getBestellung()) { + $data .= '#' . $this->getBestellung()->kBestellung; + } + if ($this->getMollie()) { + $data .= '$' . $this->getMollie()->id; + } + ZahlungsLog::add($this->PaymentMethod()->moduleID, "[" . microtime(true) . " - " . $_SERVER['PHP_SELF'] . "] " . $msg, $data, $level); + return $this; + } + + /** + * @return Bestellung + */ + public function getBestellung() + { + if (!$this->oBestellung && $this->getModel()->kBestellung) { + $this->oBestellung = new Bestellung($this->getModel()->kBestellung, true); + } + return $this->oBestellung; + } + + /** + * @return Payment + */ + public function getModel() + { + if (!$this->model) { + $this->model = Payment::fromID($this->oBestellung->kBestellung, 'kBestellung'); + } + return $this->model; + } + + /** + * @param $model + * @return $this + */ + protected function setModel($model) + { + if (!$this->model) { + $this->model = $model; + } else { + throw new RuntimeException('Model already set.'); + } + return $this; + } + + /** + * @return JTLMollie + */ + public function PaymentMethod() + { + if (!$this->paymentMethod) { + if ($this->getBestellung()->Zahlungsart && strpos($this->getBestellung()->Zahlungsart->cModulId, "kPlugin_{$this::Plugin()->kPlugin}_") !== false) { + $this->paymentMethod = PaymentMethod::create($this->getBestellung()->Zahlungsart->cModulId); + } else { + $this->paymentMethod = PaymentMethod::create("kPlugin_{$this::Plugin()->kPlugin}_mollie"); + } + } + /** @noinspection PhpIncompatibleReturnTypeInspection */ + return $this->paymentMethod; + } + + /** + * @return API + */ + public function API() + { + if (!$this->api) { + if ($this->getModel()->kID) { + $this->api = new API($this->getModel()->cMode === 'test'); + } else { + $this->api = new API(API::getMode()); + } + } + return $this->api; + } + /** * @param $checkout * @return Order|\Mollie\Api\Resources\Payment @@ -386,42 +470,6 @@ public function loadRequest($options = []) } - /** - * @return Bestellung - */ - public function getBestellung() - { - if (!$this->oBestellung && $this->getModel()->kBestellung) { - $this->oBestellung = new Bestellung($this->getModel()->kBestellung, true); - } - return $this->oBestellung; - } - - /** - * @return Payment - */ - public function getModel() - { - if (!$this->model) { - $this->model = Payment::fromID($this->oBestellung->kBestellung, 'kBestellung'); - } - return $this->model; - } - - /** - * @param $model - * @return $this - */ - protected function setModel($model) - { - if (!$this->model) { - $this->model = $model; - } else { - throw new RuntimeException('Model already set.'); - } - return $this; - } - /** * @return \Mollie\Api\Resources\Customer|null * @todo: Kunde wieder löschbar machen ?! @@ -483,56 +531,6 @@ public function getCustomer($createOrUpdate = false) return $this->customer; } - /** - * @return API - */ - public function API() - { - if (!$this->api) { - if ($this->getModel()->kID) { - $this->api = new API($this->getModel()->cMode === 'test'); - } else { - $this->api = new API(API::getMode()); - } - } - return $this->api; - } - - public function Log($msg, $level = LOGLEVEL_NOTICE) - { - $data = ''; - if ($this->getBestellung()) { - $data .= '#' . $this->getBestellung()->kBestellung; - } - if ($this->getMollie()) { - $data .= '$' . $this->getMollie()->id; - } - ZahlungsLog::add($this->PaymentMethod()->moduleID, "[" . microtime(true) . " - " . $_SERVER['PHP_SELF'] . "] " . $msg, $data, $level); - return $this; - } - - /** - * @param false $force - * @return Order|\Mollie\Api\Resources\Payment|null - */ - abstract public function getMollie($force = false); - - /** - * @return JTLMollie - */ - public function PaymentMethod() - { - if (!$this->paymentMethod) { - if ($this->getBestellung()->Zahlungsart && strpos($this->getBestellung()->Zahlungsart->cModulId, "kPlugin_{$this::Plugin()->kPlugin}_") !== false) { - $this->paymentMethod = PaymentMethod::create($this->getBestellung()->Zahlungsart->cModulId); - } else { - $this->paymentMethod = PaymentMethod::create("kPlugin_{$this::Plugin()->kPlugin}_mollie"); - } - } - /** @noinspection PhpIncompatibleReturnTypeInspection */ - return $this->paymentMethod; - } - public static function getLocale($cISOSprache = null, $country = null) { @@ -848,7 +846,7 @@ public function updateModel() $this->getModel()->kBestellung = $this->getBestellung()->kBestellung; $this->getModel()->cOrderNumber = $this->getBestellung()->cBestellNr; - $this->getModel()->cHash = $this->getHash(); + $this->getModel()->cHash = trim($this->getHash(), '_'); $this->getModel()->bSynced = $this->getModel()->bSynced !== null ? $this->getModel()->bSynced : Helper::getSetting('onlyPaid') !== 'Y'; return $this; diff --git a/version/203/class/Checkout/OrderCheckout.php b/version/203/class/Checkout/OrderCheckout.php index fd17e35..bc32e90 100644 --- a/version/203/class/Checkout/OrderCheckout.php +++ b/version/203/class/Checkout/OrderCheckout.php @@ -303,7 +303,7 @@ public function loadRequest($options = []) */ public function getIncomingPayment() { - if (!$this->getMollie()) { + if (!$this->getMollie(true)) { return null; } diff --git a/version/203/class/Hook/Queue.php b/version/203/class/Hook/Queue.php index 7fbed03..7e9c578 100644 --- a/version/203/class/Hook/Queue.php +++ b/version/203/class/Hook/Queue.php @@ -8,6 +8,7 @@ use Jtllog; use RuntimeException; use Shop; +use StringHandler; use ws_mollie\Checkout\AbstractCheckout; use ws_mollie\Checkout\OrderCheckout; use ws_mollie\Checkout\PaymentCheckout; @@ -22,6 +23,7 @@ class Queue extends AbstractHook public static function bestellungInDB(array $args_arr) { if (array_key_exists('oBestellung', $args_arr) + && $args_arr['oBestellung']->kBestellung && $args_arr['oBestellung']->fGesamtsumme > 0 && self::Plugin()->oPluginEinstellungAssoc_arr['onlyPaid'] === 'Y' && AbstractCheckout::isMollie((int)$args_arr['oBestellung']->kZahlungsart, true)) { @@ -80,8 +82,9 @@ public static function headPostGet() { if (array_key_exists('mollie', $_REQUEST) && (int)$_REQUEST['mollie'] === 1 && array_key_exists('id', $_REQUEST)) { - if (array_key_exists('hash', $_REQUEST)) { - AbstractCheckout::finalizeOrder($_REQUEST['hash'], $_REQUEST['id'], array_key_exists('test', $_REQUEST)); + if (array_key_exists('hash', $_REQUEST) && $hash = trim(StringHandler::htmlentities(StringHandler::filterXSS($_REQUEST['hash'])), '_')) { + + AbstractCheckout::finalizeOrder($hash, $_REQUEST['id'], array_key_exists('test', $_REQUEST)); } else { self::saveToQueue($_REQUEST['id'], $_REQUEST['id'], 'webhook'); } diff --git a/version/203/class/Model/AbstractModel.php b/version/203/class/Model/AbstractModel.php index 1dc9a47..f543a7e 100644 --- a/version/203/class/Model/AbstractModel.php +++ b/version/203/class/Model/AbstractModel.php @@ -81,11 +81,11 @@ public function save() } if ($this->new) { - Shop::DB()->insert(static::TABLE, $this->data); + Shop::DB()->insertRow(static::TABLE, $this->data); $this->new = false; return true; } - Shop::DB()->update(static::TABLE, static::PRIMARY, $this->data->{static::PRIMARY}, $this->data); + Shop::DB()->updateRow(static::TABLE, static::PRIMARY, $this->data->{static::PRIMARY}, $this->data); return true; } diff --git a/version/203/class/Model/Payment.php b/version/203/class/Model/Payment.php index 80ea0aa..068105f 100644 --- a/version/203/class/Model/Payment.php +++ b/version/203/class/Model/Payment.php @@ -32,7 +32,7 @@ class Payment extends AbstractModel { const TABLE = 'xplugin_ws_mollie_payments'; - const PRIMARY = 'kBestellung'; + const PRIMARY = 'kID'; public function save() { From 54aa4ed896f4449db23d60aa73a73e18917e37f9 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Thu, 20 May 2021 10:44:44 +0200 Subject: [PATCH 225/280] cleaned from old vresions --- info.xml | 21 - version/101/adminmenu/info.php | 53 -- version/101/adminmenu/orders.php | 154 ---- version/101/adminmenu/paymentmethods.php | 34 - version/101/adminmenu/tpl/info.tpl | 41 - .../tpl/mollie-account-erstellen.png | Bin 38998 -> 0 bytes version/101/adminmenu/tpl/order.tpl | 217 ----- version/101/adminmenu/tpl/orders.tpl | 107 --- version/101/adminmenu/tpl/paymentmethods.tpl | 49 -- version/101/class/Helper.php | 299 ------- version/101/class/Model/AbstractModel.php | 7 - version/101/class/Model/Payment.php | 77 -- version/101/class/Mollie.php | 207 ----- version/101/frontend/131_globalinclude.php | 72 -- version/101/frontend/140_smarty.php | 52 -- version/101/frontend/144_notify.php | 31 - version/101/frontend/181_sync.php | 38 - version/101/paymentmethod/JTLMollie.php | 535 ------------ .../101/paymentmethod/JTLMollieBancontact.php | 8 - .../paymentmethod/JTLMollieBanktransfer.php | 8 - .../101/paymentmethod/JTLMollieBelfius.php | 8 - .../101/paymentmethod/JTLMollieBitcoin.php | 8 - .../101/paymentmethod/JTLMollieCreditCard.php | 8 - .../paymentmethod/JTLMollieDirectDebit.php | 8 - version/101/paymentmethod/JTLMollieEPS.php | 8 - .../101/paymentmethod/JTLMollieGiftcard.php | 8 - .../101/paymentmethod/JTLMollieGiropay.php | 8 - version/101/paymentmethod/JTLMollieIDEAL.php | 8 - .../101/paymentmethod/JTLMollieINGHomePay.php | 8 - version/101/paymentmethod/JTLMollieKBC.php | 8 - .../paymentmethod/JTLMollieKlarnaPayLater.php | 8 - .../paymentmethod/JTLMollieKlarnaSliceIt.php | 8 - version/101/paymentmethod/JTLMolliePayPal.php | 8 - .../paymentmethod/JTLMolliePaysafecard.php | 8 - version/101/paymentmethod/JTLMollieSofort.php | 8 - .../paymentmethod/tpl/bestellabschluss.tpl | 5 - version/102/adminmenu/info.php | 51 -- version/102/adminmenu/orders.php | 154 ---- version/102/adminmenu/paymentmethods.php | 56 -- version/102/adminmenu/tpl/info.tpl | 93 --- .../tpl/mollie-account-erstellen.png | Bin 38998 -> 0 bytes version/102/adminmenu/tpl/order.tpl | 217 ----- version/102/adminmenu/tpl/orders.tpl | 107 --- version/102/adminmenu/tpl/paymentmethods.tpl | 92 --- version/102/class/Helper.php | 292 ------- version/102/class/Model/AbstractModel.php | 7 - version/102/class/Model/Payment.php | 77 -- version/102/class/Mollie.php | 421 ---------- version/102/frontend/131_globalinclude.php | 72 -- version/102/frontend/140_smarty.php | 52 -- version/102/frontend/144_notify.php | 31 - version/102/frontend/181_sync.php | 38 - version/102/paymentmethod/JTLMollie.php | 552 ------------- .../102/paymentmethod/JTLMollieBancontact.php | 8 - .../paymentmethod/JTLMollieBanktransfer.php | 8 - .../102/paymentmethod/JTLMollieBelfius.php | 8 - .../102/paymentmethod/JTLMollieBitcoin.php | 8 - .../102/paymentmethod/JTLMollieCreditCard.php | 8 - .../paymentmethod/JTLMollieDirectDebit.php | 8 - version/102/paymentmethod/JTLMollieEPS.php | 8 - .../102/paymentmethod/JTLMollieGiftcard.php | 8 - .../102/paymentmethod/JTLMollieGiropay.php | 8 - version/102/paymentmethod/JTLMollieIDEAL.php | 8 - .../102/paymentmethod/JTLMollieINGHomePay.php | 8 - version/102/paymentmethod/JTLMollieKBC.php | 8 - .../paymentmethod/JTLMollieKlarnaPayLater.php | 8 - .../paymentmethod/JTLMollieKlarnaSliceIt.php | 8 - version/102/paymentmethod/JTLMolliePayPal.php | 8 - .../paymentmethod/JTLMolliePaysafecard.php | 8 - version/102/paymentmethod/JTLMollieSofort.php | 8 - .../paymentmethod/tpl/bestellabschluss.tpl | 5 - version/103/adminmenu/info.php | 51 -- version/103/adminmenu/orders.php | 154 ---- version/103/adminmenu/paymentmethods.php | 57 -- version/103/adminmenu/tpl/info.tpl | 93 --- .../tpl/mollie-account-erstellen.png | Bin 38998 -> 0 bytes version/103/adminmenu/tpl/order.tpl | 265 ------ version/103/adminmenu/tpl/orders.tpl | 107 --- version/103/adminmenu/tpl/paymentmethods.tpl | 92 --- version/103/class/Helper.php | 292 ------- version/103/class/Model/AbstractModel.php | 7 - version/103/class/Model/Payment.php | 77 -- version/103/class/Mollie.php | 441 ---------- version/103/frontend/131_globalinclude.php | 72 -- version/103/frontend/140_smarty.php | 52 -- version/103/frontend/144_notify.php | 31 - version/103/frontend/181_sync.php | 38 - version/103/paymentmethod/JTLMollie.php | 563 ------------- .../103/paymentmethod/JTLMollieApplePay.php | 8 - .../103/paymentmethod/JTLMollieBancontact.php | 8 - .../paymentmethod/JTLMollieBanktransfer.php | 8 - .../103/paymentmethod/JTLMollieBelfius.php | 8 - .../103/paymentmethod/JTLMollieCreditCard.php | 8 - .../paymentmethod/JTLMollieDirectDebit.php | 8 - version/103/paymentmethod/JTLMollieEPS.php | 8 - .../103/paymentmethod/JTLMollieGiftcard.php | 8 - .../103/paymentmethod/JTLMollieGiropay.php | 8 - version/103/paymentmethod/JTLMollieIDEAL.php | 8 - .../103/paymentmethod/JTLMollieINGHomePay.php | 8 - version/103/paymentmethod/JTLMollieKBC.php | 8 - .../paymentmethod/JTLMollieKlarnaPayLater.php | 8 - .../paymentmethod/JTLMollieKlarnaSliceIt.php | 8 - version/103/paymentmethod/JTLMolliePayPal.php | 8 - .../paymentmethod/JTLMolliePaysafecard.php | 8 - version/103/paymentmethod/JTLMollieSofort.php | 8 - .../paymentmethod/tpl/bestellabschluss.tpl | 5 - version/104/adminmenu/info.php | 54 -- version/104/adminmenu/orders.php | 154 ---- version/104/adminmenu/paymentmethods.php | 59 -- version/104/adminmenu/tpl/info.tpl | 93 --- .../tpl/mollie-account-erstellen.png | Bin 38998 -> 0 bytes version/104/adminmenu/tpl/order.tpl | 265 ------ version/104/adminmenu/tpl/orders.tpl | 107 --- version/104/adminmenu/tpl/paymentmethods.tpl | 92 --- version/104/class/Helper.php | 309 ------- version/104/class/Model/AbstractModel.php | 7 - version/104/class/Model/Payment.php | 77 -- version/104/class/Mollie.php | 446 ---------- version/104/frontend/131_globalinclude.php | 72 -- version/104/frontend/140_smarty.php | 52 -- version/104/frontend/144_notify.php | 31 - version/104/frontend/181_sync.php | 38 - version/104/paymentmethod/JTLMollie.php | 558 ------------- .../104/paymentmethod/JTLMollieApplePay.php | 8 - .../104/paymentmethod/JTLMollieBancontact.php | 8 - .../paymentmethod/JTLMollieBanktransfer.php | 8 - .../104/paymentmethod/JTLMollieBelfius.php | 8 - .../104/paymentmethod/JTLMollieCreditCard.php | 8 - .../paymentmethod/JTLMollieDirectDebit.php | 8 - version/104/paymentmethod/JTLMollieEPS.php | 8 - .../104/paymentmethod/JTLMollieGiftcard.php | 8 - .../104/paymentmethod/JTLMollieGiropay.php | 8 - version/104/paymentmethod/JTLMollieIDEAL.php | 8 - .../104/paymentmethod/JTLMollieINGHomePay.php | 8 - version/104/paymentmethod/JTLMollieKBC.php | 8 - .../paymentmethod/JTLMollieKlarnaPayLater.php | 8 - .../paymentmethod/JTLMollieKlarnaSliceIt.php | 8 - version/104/paymentmethod/JTLMolliePayPal.php | 8 - .../paymentmethod/JTLMolliePaysafecard.php | 8 - version/104/paymentmethod/JTLMollieSofort.php | 8 - .../paymentmethod/tpl/bestellabschluss.tpl | 5 - version/105/adminmenu/info.php | 55 -- version/105/adminmenu/orders.php | 154 ---- version/105/adminmenu/paymentmethods.php | 60 -- version/105/adminmenu/tpl/info.tpl | 93 --- .../tpl/mollie-account-erstellen.png | Bin 38998 -> 0 bytes version/105/adminmenu/tpl/order.tpl | 274 ------ version/105/adminmenu/tpl/orders.tpl | 113 --- version/105/adminmenu/tpl/paymentmethods.tpl | 92 --- version/105/class/Helper.php | 311 ------- version/105/class/Model/AbstractModel.php | 7 - version/105/class/Model/Payment.php | 81 -- version/105/class/Mollie.php | 477 ----------- version/105/frontend/131_globalinclude.php | 82 -- version/105/frontend/140_smarty.php | 59 -- version/105/frontend/144_notify.php | 59 -- version/105/frontend/181_sync.php | 43 - version/105/frontend/img/trust_eng.png | Bin 15299 -> 0 bytes version/105/frontend/img/trust_fre.png | Bin 17319 -> 0 bytes version/105/frontend/img/trust_ger.png | Bin 15352 -> 0 bytes version/105/paymentmethod/JTLMollie.php | 613 -------------- .../105/paymentmethod/JTLMollieApplePay.php | 8 - .../105/paymentmethod/JTLMollieBancontact.php | 8 - .../paymentmethod/JTLMollieBanktransfer.php | 8 - .../105/paymentmethod/JTLMollieBelfius.php | 8 - .../105/paymentmethod/JTLMollieCreditCard.php | 36 - .../paymentmethod/JTLMollieDirectDebit.php | 8 - version/105/paymentmethod/JTLMollieEPS.php | 8 - .../105/paymentmethod/JTLMollieGiftcard.php | 8 - .../105/paymentmethod/JTLMollieGiropay.php | 8 - version/105/paymentmethod/JTLMollieIDEAL.php | 8 - .../105/paymentmethod/JTLMollieINGHomePay.php | 8 - version/105/paymentmethod/JTLMollieKBC.php | 8 - .../paymentmethod/JTLMollieKlarnaPayLater.php | 8 - .../paymentmethod/JTLMollieKlarnaSliceIt.php | 8 - version/105/paymentmethod/JTLMolliePayPal.php | 8 - .../paymentmethod/JTLMolliePaysafecard.php | 8 - version/105/paymentmethod/JTLMollieSofort.php | 8 - .../paymentmethod/tpl/bestellabschluss.tpl | 5 - .../paymentmethod/tpl/mollieComponents.tpl | 101 --- version/106/adminmenu/info.php | 64 -- version/106/adminmenu/orders.php | 154 ---- version/106/adminmenu/paymentmethods.php | 60 -- version/106/adminmenu/tpl/info.tpl | 96 --- .../tpl/mollie-account-erstellen.png | Bin 38998 -> 0 bytes version/106/adminmenu/tpl/order.tpl | 286 ------- version/106/adminmenu/tpl/orders.tpl | 116 --- version/106/adminmenu/tpl/paymentmethods.tpl | 97 --- version/106/class/Helper.php | 311 ------- version/106/class/Model/AbstractModel.php | 7 - version/106/class/Model/Payment.php | 84 -- version/106/class/Mollie.php | 508 ------------ version/106/frontend/131_globalinclude.php | 84 -- version/106/frontend/140_smarty.php | 71 -- version/106/frontend/144_notify.php | 57 -- version/106/frontend/181_sync.php | 43 - version/106/frontend/img/trust_eng.png | Bin 15299 -> 0 bytes version/106/frontend/img/trust_fre.png | Bin 17319 -> 0 bytes version/106/frontend/img/trust_ger.png | Bin 15352 -> 0 bytes version/106/paymentmethod/JTLMollie.php | 646 --------------- .../106/paymentmethod/JTLMollieApplePay.php | 8 - .../106/paymentmethod/JTLMollieBancontact.php | 8 - .../paymentmethod/JTLMollieBanktransfer.php | 10 - .../106/paymentmethod/JTLMollieBelfius.php | 8 - .../106/paymentmethod/JTLMollieCreditCard.php | 36 - .../paymentmethod/JTLMollieDirectDebit.php | 8 - version/106/paymentmethod/JTLMollieEPS.php | 8 - .../106/paymentmethod/JTLMollieGiftcard.php | 8 - .../106/paymentmethod/JTLMollieGiropay.php | 8 - version/106/paymentmethod/JTLMollieIDEAL.php | 8 - .../106/paymentmethod/JTLMollieINGHomePay.php | 8 - version/106/paymentmethod/JTLMollieKBC.php | 8 - .../paymentmethod/JTLMollieKlarnaPayLater.php | 8 - .../paymentmethod/JTLMollieKlarnaSliceIt.php | 8 - version/106/paymentmethod/JTLMolliePayPal.php | 8 - .../paymentmethod/JTLMolliePaysafecard.php | 8 - version/106/paymentmethod/JTLMollieSofort.php | 8 - .../paymentmethod/tpl/bestellabschluss.tpl | 5 - .../paymentmethod/tpl/mollieComponents.tpl | 101 --- version/108/adminmenu/info.php | 64 -- version/108/adminmenu/orders.php | 240 ------ version/108/adminmenu/paymentmethods.php | 60 -- version/108/adminmenu/tpl/info.tpl | 96 --- .../tpl/mollie-account-erstellen.png | Bin 38998 -> 0 bytes version/108/adminmenu/tpl/order.tpl | 286 ------- version/108/adminmenu/tpl/orders.tpl | 135 --- version/108/adminmenu/tpl/paymentmethods.tpl | 97 --- version/108/class/ExclusiveLock.php | 76 -- version/108/class/Helper.php | 311 ------- version/108/class/Model/AbstractModel.php | 7 - version/108/class/Model/Payment.php | 84 -- version/108/class/Mollie.php | 548 ------------ version/108/frontend/131_globalinclude.php | 120 --- version/108/frontend/140_smarty.php | 78 -- version/108/frontend/144_notify.php | 63 -- version/108/frontend/181_sync.php | 43 - version/108/frontend/img/trust_eng.png | Bin 15299 -> 0 bytes version/108/frontend/img/trust_fre.png | Bin 17319 -> 0 bytes version/108/frontend/img/trust_ger.png | Bin 15352 -> 0 bytes version/108/paymentmethod/JTLMollie.php | 780 ------------------ .../108/paymentmethod/JTLMollieApplePay.php | 8 - .../108/paymentmethod/JTLMollieBancontact.php | 8 - .../paymentmethod/JTLMollieBanktransfer.php | 10 - .../108/paymentmethod/JTLMollieBelfius.php | 8 - .../108/paymentmethod/JTLMollieCreditCard.php | 43 - .../paymentmethod/JTLMollieDirectDebit.php | 8 - version/108/paymentmethod/JTLMollieEPS.php | 8 - .../108/paymentmethod/JTLMollieGiftcard.php | 8 - .../108/paymentmethod/JTLMollieGiropay.php | 8 - version/108/paymentmethod/JTLMollieIDEAL.php | 8 - .../108/paymentmethod/JTLMollieINGHomePay.php | 8 - version/108/paymentmethod/JTLMollieKBC.php | 8 - .../paymentmethod/JTLMollieKlarnaPayLater.php | 8 - .../paymentmethod/JTLMollieKlarnaSliceIt.php | 8 - version/108/paymentmethod/JTLMollieMyBank.php | 8 - version/108/paymentmethod/JTLMolliePayPal.php | 8 - .../paymentmethod/JTLMolliePaysafecard.php | 8 - .../108/paymentmethod/JTLMolliePrzelewy24.php | 8 - version/108/paymentmethod/JTLMollieSofort.php | 8 - .../paymentmethod/tpl/bestellabschluss.tpl | 5 - .../paymentmethod/tpl/mollieComponents.tpl | 103 --- version/108/sql/107.sql | 4 - 262 files changed, 18864 deletions(-) delete mode 100644 version/101/adminmenu/info.php delete mode 100644 version/101/adminmenu/orders.php delete mode 100644 version/101/adminmenu/paymentmethods.php delete mode 100644 version/101/adminmenu/tpl/info.tpl delete mode 100644 version/101/adminmenu/tpl/mollie-account-erstellen.png delete mode 100644 version/101/adminmenu/tpl/order.tpl delete mode 100644 version/101/adminmenu/tpl/orders.tpl delete mode 100644 version/101/adminmenu/tpl/paymentmethods.tpl delete mode 100644 version/101/class/Helper.php delete mode 100644 version/101/class/Model/AbstractModel.php delete mode 100644 version/101/class/Model/Payment.php delete mode 100644 version/101/class/Mollie.php delete mode 100644 version/101/frontend/131_globalinclude.php delete mode 100644 version/101/frontend/140_smarty.php delete mode 100644 version/101/frontend/144_notify.php delete mode 100644 version/101/frontend/181_sync.php delete mode 100644 version/101/paymentmethod/JTLMollie.php delete mode 100644 version/101/paymentmethod/JTLMollieBancontact.php delete mode 100644 version/101/paymentmethod/JTLMollieBanktransfer.php delete mode 100644 version/101/paymentmethod/JTLMollieBelfius.php delete mode 100644 version/101/paymentmethod/JTLMollieBitcoin.php delete mode 100644 version/101/paymentmethod/JTLMollieCreditCard.php delete mode 100644 version/101/paymentmethod/JTLMollieDirectDebit.php delete mode 100644 version/101/paymentmethod/JTLMollieEPS.php delete mode 100644 version/101/paymentmethod/JTLMollieGiftcard.php delete mode 100644 version/101/paymentmethod/JTLMollieGiropay.php delete mode 100644 version/101/paymentmethod/JTLMollieIDEAL.php delete mode 100644 version/101/paymentmethod/JTLMollieINGHomePay.php delete mode 100644 version/101/paymentmethod/JTLMollieKBC.php delete mode 100644 version/101/paymentmethod/JTLMollieKlarnaPayLater.php delete mode 100644 version/101/paymentmethod/JTLMollieKlarnaSliceIt.php delete mode 100644 version/101/paymentmethod/JTLMolliePayPal.php delete mode 100644 version/101/paymentmethod/JTLMolliePaysafecard.php delete mode 100644 version/101/paymentmethod/JTLMollieSofort.php delete mode 100644 version/101/paymentmethod/tpl/bestellabschluss.tpl delete mode 100644 version/102/adminmenu/info.php delete mode 100644 version/102/adminmenu/orders.php delete mode 100644 version/102/adminmenu/paymentmethods.php delete mode 100644 version/102/adminmenu/tpl/info.tpl delete mode 100644 version/102/adminmenu/tpl/mollie-account-erstellen.png delete mode 100644 version/102/adminmenu/tpl/order.tpl delete mode 100644 version/102/adminmenu/tpl/orders.tpl delete mode 100644 version/102/adminmenu/tpl/paymentmethods.tpl delete mode 100644 version/102/class/Helper.php delete mode 100644 version/102/class/Model/AbstractModel.php delete mode 100644 version/102/class/Model/Payment.php delete mode 100644 version/102/class/Mollie.php delete mode 100644 version/102/frontend/131_globalinclude.php delete mode 100644 version/102/frontend/140_smarty.php delete mode 100644 version/102/frontend/144_notify.php delete mode 100644 version/102/frontend/181_sync.php delete mode 100644 version/102/paymentmethod/JTLMollie.php delete mode 100644 version/102/paymentmethod/JTLMollieBancontact.php delete mode 100644 version/102/paymentmethod/JTLMollieBanktransfer.php delete mode 100644 version/102/paymentmethod/JTLMollieBelfius.php delete mode 100644 version/102/paymentmethod/JTLMollieBitcoin.php delete mode 100644 version/102/paymentmethod/JTLMollieCreditCard.php delete mode 100644 version/102/paymentmethod/JTLMollieDirectDebit.php delete mode 100644 version/102/paymentmethod/JTLMollieEPS.php delete mode 100644 version/102/paymentmethod/JTLMollieGiftcard.php delete mode 100644 version/102/paymentmethod/JTLMollieGiropay.php delete mode 100644 version/102/paymentmethod/JTLMollieIDEAL.php delete mode 100644 version/102/paymentmethod/JTLMollieINGHomePay.php delete mode 100644 version/102/paymentmethod/JTLMollieKBC.php delete mode 100644 version/102/paymentmethod/JTLMollieKlarnaPayLater.php delete mode 100644 version/102/paymentmethod/JTLMollieKlarnaSliceIt.php delete mode 100644 version/102/paymentmethod/JTLMolliePayPal.php delete mode 100644 version/102/paymentmethod/JTLMolliePaysafecard.php delete mode 100644 version/102/paymentmethod/JTLMollieSofort.php delete mode 100644 version/102/paymentmethod/tpl/bestellabschluss.tpl delete mode 100644 version/103/adminmenu/info.php delete mode 100644 version/103/adminmenu/orders.php delete mode 100644 version/103/adminmenu/paymentmethods.php delete mode 100644 version/103/adminmenu/tpl/info.tpl delete mode 100644 version/103/adminmenu/tpl/mollie-account-erstellen.png delete mode 100644 version/103/adminmenu/tpl/order.tpl delete mode 100644 version/103/adminmenu/tpl/orders.tpl delete mode 100644 version/103/adminmenu/tpl/paymentmethods.tpl delete mode 100644 version/103/class/Helper.php delete mode 100644 version/103/class/Model/AbstractModel.php delete mode 100644 version/103/class/Model/Payment.php delete mode 100644 version/103/class/Mollie.php delete mode 100644 version/103/frontend/131_globalinclude.php delete mode 100644 version/103/frontend/140_smarty.php delete mode 100644 version/103/frontend/144_notify.php delete mode 100644 version/103/frontend/181_sync.php delete mode 100644 version/103/paymentmethod/JTLMollie.php delete mode 100644 version/103/paymentmethod/JTLMollieApplePay.php delete mode 100644 version/103/paymentmethod/JTLMollieBancontact.php delete mode 100644 version/103/paymentmethod/JTLMollieBanktransfer.php delete mode 100644 version/103/paymentmethod/JTLMollieBelfius.php delete mode 100644 version/103/paymentmethod/JTLMollieCreditCard.php delete mode 100644 version/103/paymentmethod/JTLMollieDirectDebit.php delete mode 100644 version/103/paymentmethod/JTLMollieEPS.php delete mode 100644 version/103/paymentmethod/JTLMollieGiftcard.php delete mode 100644 version/103/paymentmethod/JTLMollieGiropay.php delete mode 100644 version/103/paymentmethod/JTLMollieIDEAL.php delete mode 100644 version/103/paymentmethod/JTLMollieINGHomePay.php delete mode 100644 version/103/paymentmethod/JTLMollieKBC.php delete mode 100644 version/103/paymentmethod/JTLMollieKlarnaPayLater.php delete mode 100644 version/103/paymentmethod/JTLMollieKlarnaSliceIt.php delete mode 100644 version/103/paymentmethod/JTLMolliePayPal.php delete mode 100644 version/103/paymentmethod/JTLMolliePaysafecard.php delete mode 100644 version/103/paymentmethod/JTLMollieSofort.php delete mode 100644 version/103/paymentmethod/tpl/bestellabschluss.tpl delete mode 100644 version/104/adminmenu/info.php delete mode 100644 version/104/adminmenu/orders.php delete mode 100644 version/104/adminmenu/paymentmethods.php delete mode 100644 version/104/adminmenu/tpl/info.tpl delete mode 100644 version/104/adminmenu/tpl/mollie-account-erstellen.png delete mode 100644 version/104/adminmenu/tpl/order.tpl delete mode 100644 version/104/adminmenu/tpl/orders.tpl delete mode 100644 version/104/adminmenu/tpl/paymentmethods.tpl delete mode 100644 version/104/class/Helper.php delete mode 100644 version/104/class/Model/AbstractModel.php delete mode 100644 version/104/class/Model/Payment.php delete mode 100644 version/104/class/Mollie.php delete mode 100644 version/104/frontend/131_globalinclude.php delete mode 100644 version/104/frontend/140_smarty.php delete mode 100644 version/104/frontend/144_notify.php delete mode 100644 version/104/frontend/181_sync.php delete mode 100644 version/104/paymentmethod/JTLMollie.php delete mode 100644 version/104/paymentmethod/JTLMollieApplePay.php delete mode 100644 version/104/paymentmethod/JTLMollieBancontact.php delete mode 100644 version/104/paymentmethod/JTLMollieBanktransfer.php delete mode 100644 version/104/paymentmethod/JTLMollieBelfius.php delete mode 100644 version/104/paymentmethod/JTLMollieCreditCard.php delete mode 100644 version/104/paymentmethod/JTLMollieDirectDebit.php delete mode 100644 version/104/paymentmethod/JTLMollieEPS.php delete mode 100644 version/104/paymentmethod/JTLMollieGiftcard.php delete mode 100644 version/104/paymentmethod/JTLMollieGiropay.php delete mode 100644 version/104/paymentmethod/JTLMollieIDEAL.php delete mode 100644 version/104/paymentmethod/JTLMollieINGHomePay.php delete mode 100644 version/104/paymentmethod/JTLMollieKBC.php delete mode 100644 version/104/paymentmethod/JTLMollieKlarnaPayLater.php delete mode 100644 version/104/paymentmethod/JTLMollieKlarnaSliceIt.php delete mode 100644 version/104/paymentmethod/JTLMolliePayPal.php delete mode 100644 version/104/paymentmethod/JTLMolliePaysafecard.php delete mode 100644 version/104/paymentmethod/JTLMollieSofort.php delete mode 100644 version/104/paymentmethod/tpl/bestellabschluss.tpl delete mode 100644 version/105/adminmenu/info.php delete mode 100644 version/105/adminmenu/orders.php delete mode 100644 version/105/adminmenu/paymentmethods.php delete mode 100644 version/105/adminmenu/tpl/info.tpl delete mode 100644 version/105/adminmenu/tpl/mollie-account-erstellen.png delete mode 100644 version/105/adminmenu/tpl/order.tpl delete mode 100644 version/105/adminmenu/tpl/orders.tpl delete mode 100644 version/105/adminmenu/tpl/paymentmethods.tpl delete mode 100644 version/105/class/Helper.php delete mode 100644 version/105/class/Model/AbstractModel.php delete mode 100644 version/105/class/Model/Payment.php delete mode 100644 version/105/class/Mollie.php delete mode 100644 version/105/frontend/131_globalinclude.php delete mode 100644 version/105/frontend/140_smarty.php delete mode 100644 version/105/frontend/144_notify.php delete mode 100644 version/105/frontend/181_sync.php delete mode 100644 version/105/frontend/img/trust_eng.png delete mode 100644 version/105/frontend/img/trust_fre.png delete mode 100644 version/105/frontend/img/trust_ger.png delete mode 100644 version/105/paymentmethod/JTLMollie.php delete mode 100644 version/105/paymentmethod/JTLMollieApplePay.php delete mode 100644 version/105/paymentmethod/JTLMollieBancontact.php delete mode 100644 version/105/paymentmethod/JTLMollieBanktransfer.php delete mode 100644 version/105/paymentmethod/JTLMollieBelfius.php delete mode 100644 version/105/paymentmethod/JTLMollieCreditCard.php delete mode 100644 version/105/paymentmethod/JTLMollieDirectDebit.php delete mode 100644 version/105/paymentmethod/JTLMollieEPS.php delete mode 100644 version/105/paymentmethod/JTLMollieGiftcard.php delete mode 100644 version/105/paymentmethod/JTLMollieGiropay.php delete mode 100644 version/105/paymentmethod/JTLMollieIDEAL.php delete mode 100644 version/105/paymentmethod/JTLMollieINGHomePay.php delete mode 100644 version/105/paymentmethod/JTLMollieKBC.php delete mode 100644 version/105/paymentmethod/JTLMollieKlarnaPayLater.php delete mode 100644 version/105/paymentmethod/JTLMollieKlarnaSliceIt.php delete mode 100644 version/105/paymentmethod/JTLMolliePayPal.php delete mode 100644 version/105/paymentmethod/JTLMolliePaysafecard.php delete mode 100644 version/105/paymentmethod/JTLMollieSofort.php delete mode 100644 version/105/paymentmethod/tpl/bestellabschluss.tpl delete mode 100644 version/105/paymentmethod/tpl/mollieComponents.tpl delete mode 100644 version/106/adminmenu/info.php delete mode 100644 version/106/adminmenu/orders.php delete mode 100644 version/106/adminmenu/paymentmethods.php delete mode 100644 version/106/adminmenu/tpl/info.tpl delete mode 100644 version/106/adminmenu/tpl/mollie-account-erstellen.png delete mode 100644 version/106/adminmenu/tpl/order.tpl delete mode 100644 version/106/adminmenu/tpl/orders.tpl delete mode 100644 version/106/adminmenu/tpl/paymentmethods.tpl delete mode 100644 version/106/class/Helper.php delete mode 100644 version/106/class/Model/AbstractModel.php delete mode 100644 version/106/class/Model/Payment.php delete mode 100644 version/106/class/Mollie.php delete mode 100644 version/106/frontend/131_globalinclude.php delete mode 100644 version/106/frontend/140_smarty.php delete mode 100644 version/106/frontend/144_notify.php delete mode 100644 version/106/frontend/181_sync.php delete mode 100644 version/106/frontend/img/trust_eng.png delete mode 100644 version/106/frontend/img/trust_fre.png delete mode 100644 version/106/frontend/img/trust_ger.png delete mode 100644 version/106/paymentmethod/JTLMollie.php delete mode 100644 version/106/paymentmethod/JTLMollieApplePay.php delete mode 100644 version/106/paymentmethod/JTLMollieBancontact.php delete mode 100644 version/106/paymentmethod/JTLMollieBanktransfer.php delete mode 100644 version/106/paymentmethod/JTLMollieBelfius.php delete mode 100644 version/106/paymentmethod/JTLMollieCreditCard.php delete mode 100644 version/106/paymentmethod/JTLMollieDirectDebit.php delete mode 100644 version/106/paymentmethod/JTLMollieEPS.php delete mode 100644 version/106/paymentmethod/JTLMollieGiftcard.php delete mode 100644 version/106/paymentmethod/JTLMollieGiropay.php delete mode 100644 version/106/paymentmethod/JTLMollieIDEAL.php delete mode 100644 version/106/paymentmethod/JTLMollieINGHomePay.php delete mode 100644 version/106/paymentmethod/JTLMollieKBC.php delete mode 100644 version/106/paymentmethod/JTLMollieKlarnaPayLater.php delete mode 100644 version/106/paymentmethod/JTLMollieKlarnaSliceIt.php delete mode 100644 version/106/paymentmethod/JTLMolliePayPal.php delete mode 100644 version/106/paymentmethod/JTLMolliePaysafecard.php delete mode 100644 version/106/paymentmethod/JTLMollieSofort.php delete mode 100644 version/106/paymentmethod/tpl/bestellabschluss.tpl delete mode 100644 version/106/paymentmethod/tpl/mollieComponents.tpl delete mode 100644 version/108/adminmenu/info.php delete mode 100644 version/108/adminmenu/orders.php delete mode 100644 version/108/adminmenu/paymentmethods.php delete mode 100644 version/108/adminmenu/tpl/info.tpl delete mode 100644 version/108/adminmenu/tpl/mollie-account-erstellen.png delete mode 100644 version/108/adminmenu/tpl/order.tpl delete mode 100644 version/108/adminmenu/tpl/orders.tpl delete mode 100644 version/108/adminmenu/tpl/paymentmethods.tpl delete mode 100644 version/108/class/ExclusiveLock.php delete mode 100644 version/108/class/Helper.php delete mode 100644 version/108/class/Model/AbstractModel.php delete mode 100644 version/108/class/Model/Payment.php delete mode 100644 version/108/class/Mollie.php delete mode 100644 version/108/frontend/131_globalinclude.php delete mode 100644 version/108/frontend/140_smarty.php delete mode 100644 version/108/frontend/144_notify.php delete mode 100644 version/108/frontend/181_sync.php delete mode 100644 version/108/frontend/img/trust_eng.png delete mode 100644 version/108/frontend/img/trust_fre.png delete mode 100644 version/108/frontend/img/trust_ger.png delete mode 100644 version/108/paymentmethod/JTLMollie.php delete mode 100644 version/108/paymentmethod/JTLMollieApplePay.php delete mode 100644 version/108/paymentmethod/JTLMollieBancontact.php delete mode 100644 version/108/paymentmethod/JTLMollieBanktransfer.php delete mode 100644 version/108/paymentmethod/JTLMollieBelfius.php delete mode 100644 version/108/paymentmethod/JTLMollieCreditCard.php delete mode 100644 version/108/paymentmethod/JTLMollieDirectDebit.php delete mode 100644 version/108/paymentmethod/JTLMollieEPS.php delete mode 100644 version/108/paymentmethod/JTLMollieGiftcard.php delete mode 100644 version/108/paymentmethod/JTLMollieGiropay.php delete mode 100644 version/108/paymentmethod/JTLMollieIDEAL.php delete mode 100644 version/108/paymentmethod/JTLMollieINGHomePay.php delete mode 100644 version/108/paymentmethod/JTLMollieKBC.php delete mode 100644 version/108/paymentmethod/JTLMollieKlarnaPayLater.php delete mode 100644 version/108/paymentmethod/JTLMollieKlarnaSliceIt.php delete mode 100644 version/108/paymentmethod/JTLMollieMyBank.php delete mode 100644 version/108/paymentmethod/JTLMolliePayPal.php delete mode 100644 version/108/paymentmethod/JTLMolliePaysafecard.php delete mode 100644 version/108/paymentmethod/JTLMolliePrzelewy24.php delete mode 100644 version/108/paymentmethod/JTLMollieSofort.php delete mode 100644 version/108/paymentmethod/tpl/bestellabschluss.tpl delete mode 100644 version/108/paymentmethod/tpl/mollieComponents.tpl delete mode 100644 version/108/sql/107.sql diff --git a/info.xml b/info.xml index c38d935..c99e2e2 100644 --- a/info.xml +++ b/info.xml @@ -12,31 +12,10 @@ 100.sql 2019-02-11 - - 2019-02-26 - - - 2019-04-23 - - - 2019-05-22 - - - 2019-07-12 - - - 2019-11-26 - - - 2019-12-18 - 107.sql 2020-03-02 - - 2020-04-24 - 109.sql 2020-08-17 diff --git a/version/101/adminmenu/info.php b/version/101/adminmenu/info.php deleted file mode 100644 index 4cfb99b..0000000 --- a/version/101/adminmenu/info.php +++ /dev/null @@ -1,53 +0,0 @@ -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, - 'd' => Helper::getDomain(), - 'php' => PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION . '.' . PHP_RELEASE_VERSION, - ]); - - echo ""; - echo "
" . - "
" . - " " . - " Lizenz Informationen" . - ' ' . - '
' . - "
" . - " " . - " Update Informationen" . - ' ' . - '
' . - "
" . - " " . - " Plugin informationen" . - ' ' . - '
' . - '
'; - - 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'); -} catch (Exception $e) { - echo "
Fehler: {$e->getMessage()}
"; - Helper::logExc($e); -} diff --git a/version/101/adminmenu/orders.php b/version/101/adminmenu/orders.php deleted file mode 100644 index 891f42a..0000000 --- a/version/101/adminmenu/orders.php +++ /dev/null @@ -1,154 +0,0 @@ - 'danger', 'text' => 'Keine ID angeben!']; - break; - } - $payment = Payment::getPaymentMollie($_REQUEST['id']); - if (!$payment) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; - break; - } - - $order = JTLMollie::API()->orders->get($_REQUEST['id']); - if ($order->status == OrderStatus::STATUS_CANCELED) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung bereits storniert']; - 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; - break; - - case 'cancel': - if (!array_key_exists('id', $_REQUEST)) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; - break; - } - $payment = Payment::getPaymentMollie($_REQUEST['id']); - if (!$payment) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; - break; - } - $order = JTLMollie::API()->orders->get($_REQUEST['id']); - if ($order->status == OrderStatus::STATUS_CANCELED) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung bereits storniert']; - 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; - break; - - case 'capture': - if (!array_key_exists('id', $_REQUEST)) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; - break; - } - $payment = Payment::getPaymentMollie($_REQUEST['id']); - if (!$payment) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; - break; - } - $order = JTLMollie::API()->orders->get($_REQUEST['id']); - if ($order->status !== OrderStatus::STATUS_AUTHORIZED && $order->status !== OrderStatus::STATUS_SHIPPING) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Nur autorisierte Zahlungen können erfasst werden!']; - break; - } - - $oBestellung = new Bestellung($payment->kBestellung, true); - if (!$oBestellung->kBestellung) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung konnte nicht geladen werden!']; - break; - } - - $logData = '#' . $payment->kBestellung . '$' . $payment->kID . "§" . $oBestellung->cBestellNr; - - $options = ['lines' => []]; - if ($oBestellung->cTracking) { - $tracking = new stdClass(); - $tracking->carrier = $oBestellung->cVersandartName; - $tracking->url = $oBestellung->cTrackingURL; - $tracking->code = $oBestellung->cTracking; - $options['tracking'] = $tracking; - } - - // CAPTURE ALL - $shipment = JTLMollie::API()->shipments->createFor($order, $options); - $ordersMsgs[] = (object)['type' => 'success', 'text' => 'Zahlung wurde erfolgreich erfasst!']; - Mollie::JTLMollie()->doLog('Shipment created
' . print_r(['options' => $options, 'shipment' => $shipment], 1) . '
', $logData); - goto order; - - case 'order': - order: - if (!array_key_exists('id', $_REQUEST)) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; - break; - } - - $order = JTLMollie::API()->orders->get($_REQUEST['id']); - $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", [ - ':kBestellung' => '%#' . ($payment->kBestellung ?: '##') . '%', - ':cBestellNr' => '%§' . ($payment->cOrderNumber ?: '§§') . '%', - ':MollieID' => '%$' . ($payment->kID ?: '$$') . '%', - ], 2); - - Shop::Smarty()->assign('payment', $payment) - ->assign('oBestellung', $oBestellung) - ->assign('order', $order) - ->assign('logs', $logs) - ->assign('ordersMsgs', $ordersMsgs); - Shop::Smarty()->display($oPlugin->cAdminmenuPfad . '/tpl/order.tpl'); - return; - } - } - - - $payments = Shop::DB()->executeQueryPrepared("SELECT * FROM xplugin_ws_mollie_payments WHERE kBestellung IS NOT NULL AND cStatus != 'created'", [], 2); - foreach ($payments as $i => $payment) { - $payments[$i]->oBestellung = new Bestellung($payment->kBestellung, false); - } - - Shop::Smarty()->assign('payments', $payments) - ->assign('ordersMsgs', $ordersMsgs) - ->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/101/adminmenu/paymentmethods.php b/version/101/adminmenu/paymentmethods.php deleted file mode 100644 index b345dbf..0000000 --- a/version/101/adminmenu/paymentmethods.php +++ /dev/null @@ -1,34 +0,0 @@ -setApiKey(Helper::getSetting("api_key")); - - $profile = $mollie->profiles->get('me'); - /* $methods = $mollie->methods->all([ - //'locale' => 'de_DE', - 'include' => 'pricing', - ]);*/ - - $allMethods = $mollie->performHttpCall('GET', 'methods/all?locale=de_DE&include=pricing'); - - Shop::Smarty()->assign('profile', $profile) - //->assign('methods', $methods) - ->assign('allMethods', $allMethods); - Shop::Smarty()->display($oPlugin->cAdminmenuPfad . '/tpl/paymentmethods.tpl'); -} catch (Exception $e) { - echo "
{$e->getMessage()}
"; - Helper::logExc($e); -} diff --git a/version/101/adminmenu/tpl/info.tpl b/version/101/adminmenu/tpl/info.tpl deleted file mode 100644 index 16afe75..0000000 --- a/version/101/adminmenu/tpl/info.tpl +++ /dev/null @@ -1,41 +0,0 @@ -
-
-
- {if isset($update)} - -
-

Update auf Version {$update->version} verfügbar!

-
-
-
-
Version:
-
{$update->version}
-
-
-
Erschienen:
-
{$update->create_date}
-
-
-
Changelog:
-
- -
-
- -
-
- -
-
- {/if} -
-
\ No newline at end of file diff --git a/version/101/adminmenu/tpl/mollie-account-erstellen.png b/version/101/adminmenu/tpl/mollie-account-erstellen.png deleted file mode 100644 index fc1819255ef725fa214cf2bf028cf3428794ecee..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 38998 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 -

- « - 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} -

- -{if count($ordersMsgs)} - {foreach from=$ordersMsgs item=alert} -
{$alert->text}
- {/foreach} -
-{/if} - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Mollie ID:{$payment->kID}Mode:{$order->mode}Status:{$order->status}
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)}
- -

Positionen:

- -
- {if ($order->status === 'authorized' || $order->status === 'shipping') && $oBestellung->cStatus|intval >= 3} - - Zahlung erfassen1 - - {/if} - {if $order->amount->value > $order->amountRefunded->value && $order->amountCaptured->value > 0} - Rckerstatten2 - - {/if} - {if $order->isCancelable} - Stornieren3 - - {/if} -
- - - - - - - - - - - - - - - - - - {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} - - - - - - - - - - - - - {/foreach} - - - - - - - - - - -
StatusSKUNameTypAnzahlMwStSteuerNettoBrutto 
- {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*} -
{$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} - - - - - - - {/foreach} -
- {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}
- - diff --git a/version/101/adminmenu/tpl/orders.tpl b/version/101/adminmenu/tpl/orders.tpl deleted file mode 100644 index 3956ef5..0000000 --- a/version/101/adminmenu/tpl/orders.tpl +++ /dev/null @@ -1,107 +0,0 @@ - -{if count($ordersMsgs)} - {foreach from=$ordersMsgs item=alert} -
{$alert->text}
- {/foreach} -
-{/if} - -{if $hasAPIKey == false} - - Jetzt kostenlos Mollie Account eröffnen! - -{else} - - - - - - - - - - - - - - - - {foreach from=$payments item=payment} - - - - - - - - - - - - {/foreach} - -
BestellNr.IDMollie StatusJTL StatusBetragWährungLocaleMethodeErstellt
- {$payment->cOrderNumber} - {if $payment->cMode == 'test'} - TEST - {/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->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)}
- - -{/if} \ No newline at end of file diff --git a/version/101/adminmenu/tpl/paymentmethods.tpl b/version/101/adminmenu/tpl/paymentmethods.tpl deleted file mode 100644 index 3daee0e..0000000 --- a/version/101/adminmenu/tpl/paymentmethods.tpl +++ /dev/null @@ -1,49 +0,0 @@ -

Account Status

- - - - - - - - - -
Mode:{$profile->mode}Status:{$profile->status}Review:{$profile->review->status}
- -
- -{if $allMethods && $allMethods|count} - - - - - - - - - - - {foreach from=$allMethods->_embedded->methods item=method} - - - - - - - {/foreach} - -
BildIDNamePreise
{$method->description|utf8_decode}{$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} -
-
-{else} -
Es konnten keine Methoden abgerufen werden.
-{/if} \ No newline at end of file diff --git a/version/101/class/Helper.php b/version/101/class/Helper.php deleted file mode 100644 index b617edf..0000000 --- a/version/101/class/Helper.php +++ /dev/null @@ -1,299 +0,0 @@ -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); - 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(); - } - - /** - * 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); - } elseif (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); - } - - /** - * @return mixed - */ - private static function _masterMail() - { - $settings = Shop::getSettings(array(CONF_EMAILS)); - return $settings['emails']['email_master_absender']; - } - - /** - * @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/101/class/Model/AbstractModel.php b/version/101/class/Model/AbstractModel.php deleted file mode 100644 index 5638700..0000000 --- a/version/101/class/Model/AbstractModel.php +++ /dev/null @@ -1,7 +0,0 @@ - $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, - ]; - 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; - } - - 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/101/class/Mollie.php b/version/101/class/Mollie.php deleted file mode 100644 index e499cee..0000000 --- a/version/101/class/Mollie.php +++ /dev/null @@ -1,207 +0,0 @@ -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) { - header('Location: ' . $url); - 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; - } - - switch ((int)$newStatus) { - case BESTELLUNG_STATUS_VERSANDT: - $options['lines'] = []; - break; - case BESTELLUNG_STATUS_TEILVERSANDT: - $lines = []; - foreach ($order->lines as $i => $line) { - if (($quantity = Mollie::getBestellPosSent($line->sku, $oBestellung)) !== false && ($quantity - $line->quantityShipped) > 0) { - $x = $quantity - $line->quantityShipped; - $lines[] = (object)[ - 'id' => $line->id, - 'quantity' => $x, - 'amount' => (object)[ - 'currency' => $line->totalAmount->currency, - 'value' => number_format($x * $line->unitPrice->value, 2), - ], - ]; - } - } - if (count($lines)) { - $options['lines'] = $lines; - } - break; - case BESTELLUNG_STATUS_STORNO: - $options = null; - break; - } - - return $options; - } - - /** - * 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; - } - - /** - * @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) { - $order->orderNumber = $oBestellung->cBestellNr; - Payment::updateFromPayment($order, $kBestellung); - - $oIncomingPayment = Shop::DB()->executeQueryPrepared("SELECT * FROM tzahlungseingang WHERE cHinweis = :cHinweis AND kBestellung = :kBestellung", [':cHinweis' => $order->id, ':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: - $oIncomingPayment->fBetrag = $order->amount->value; - $oIncomingPayment->cISO = $order->amount->curreny; - $oIncomingPayment->cHinweis = $order->id; - Mollie::JTLMollie()->addIncomingPayment($oBestellung, $oIncomingPayment); - Mollie::JTLMollie()->setOrderStatusToPaid($oBestellung); - Mollie::JTLMollie()->doLog('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('PaymentStatus: ' . $order->status . ' => Bestellung bezahlt, KEIN Zahlungseingang', $logData, LOGLEVEL_NOTICE); - break; - case OrderStatus::STATUS_CANCELED: - case OrderStatus::STATUS_EXPIRED: - Mollie::JTLMollie()->doLog('PaymentStatus: ' . $order->status, $logData, LOGLEVEL_ERROR); - break; - } - return true; - } - return false; - } - - /** - * @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; - } -} diff --git a/version/101/frontend/131_globalinclude.php b/version/101/frontend/131_globalinclude.php deleted file mode 100644 index 45d4c6f..0000000 --- a/version/101/frontend/131_globalinclude.php +++ /dev/null @@ -1,72 +0,0 @@ -executeQueryPrepared("SELECT * FROM " . \ws_mollie\Model\Payment::TABLE . " WHERE cHash = :cHash", [':cHash' => $_REQUEST['mollie']], 1); - // Bestellung finalized, redirect to status/completion page - if ((int)$payment->kBestellung) { - $logData = '$' . $payment->kID . '#' . $payment->kBestellung . "§" . $payment->cOrderNumber; - Mollie::JTLMollie()->doLog('Bestellung finalized => redirect abschluss/status', $logData); - $order = JTLMollie::API()->orders->get($payment->kID, ['embed' => 'payments']); - Mollie::handleOrder($order, $payment->kBestellung); - Mollie::getOrderCompletedRedirect($payment->kBestellung, true); - } elseif ($payment) { // payment, but no order => finalize it - require_once __DIR__ . '/../paymentmethod/JTLMollie.php'; - $order = JTLMollie::API()->orders->get($payment->kID, ['embed' => 'payments']); - $logData = '$' . $order->id . '#' . $payment->kBestellung . "§" . $payment->cOrderNumber; - - // GET NEWEST PAYMENT: - /** @var Payment $_payment */ - $_payment = null; - if ($order->payments()) { - /** @var Payment $p */ - foreach ($order->payments() as $p) { - if (!$_payment) { - $_payment = $p; - continue; - } - if (strtotime($p->createdAt) > strtotime($_payment->createdAt)) { - $_payment = $p; - } - } - } - - // finalize only, if order is not canceld/expired - if ($order && !$order->isCanceled() && !$order->isExpired()) { - // finalize only if payment is not expired/canceled,failed or open - if ($_payment && !in_array($_payment->status, [PaymentStatus::STATUS_EXPIRED, PaymentStatus::STATUS_CANCELED, PaymentStatus::STATUS_OPEN, PaymentStatus::STATUS_FAILED, PaymentStatus::STATUS_CANCELED])) { - Mollie::JTLMollie()->doLog('Bestellung open => finalize', $logData); - $session = Session::getInstance(); - /** @noinspection PhpIncludeInspection */ - require_once PFAD_ROOT . 'includes/bestellabschluss_inc.php'; - /** @noinspection PhpIncludeInspection */ - require_once PFAD_ROOT . 'includes/mailTools.php'; - $oBestellung = fakeBestellung(); - $oBestellung = finalisiereBestellung(); - Mollie::JTLMollie()->doLog('Bestellung finalized => redirect
' . print_r($order, 1) . '
', $logData, LOGLEVEL_DEBUG); - Mollie::handleOrder($order, $oBestellung->kBestellung); - Mollie::getOrderCompletedRedirect($oBestellung->kBestellung, true); - } else { - Mollie::JTLMollie()->doLog('Invalid Payment
' . print_r($payment, 1) . '
', $logData, LOGLEVEL_ERROR); - } - } else { - Mollie::JTLMollie()->doLog('Invalid Order
' . print_r($order, 1) . '
', $logData, LOGLEVEL_ERROR); - } - } - } - ob_end_flush(); -} catch (Exception $e) { - Helper::logExc($e); -} diff --git a/version/101/frontend/140_smarty.php b/version/101/frontend/140_smarty.php deleted file mode 100644 index 56a6400..0000000 --- a/version/101/frontend/140_smarty.php +++ /dev/null @@ -1,52 +0,0 @@ -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/101/frontend/144_notify.php b/version/101/frontend/144_notify.php deleted file mode 100644 index a2af9f2..0000000 --- a/version/101/frontend/144_notify.php +++ /dev/null @@ -1,31 +0,0 @@ - Update Payment, stop skript - * - ELSE weiter mit der notify.php - */ - -use ws_mollie\Helper; -use ws_mollie\Model\Payment; -use ws_mollie\Mollie; - -if (array_key_exists('hash', $_REQUEST)) { - require_once __DIR__ . '/../class/Helper.php'; - try { - Helper::init(); - $payment = Payment::getPaymentHash($_REQUEST['hash']); - // If Bestellung already exists, treat as Notification - if ($payment && $payment->kBestellung) { - require_once __DIR__ . '/../paymentmethod/JTLMollie.php'; - $order = JTLMollie::API()->orders->get($payment->kID); - $logData = '#' . $payment->kBestellung . '$' . $payment->kID; - Mollie::JTLMollie()->doLog('Received Notification
' . print_r([$order, $payment], 1) . '
', $logData); - Mollie::handleOrder($order, $payment->kBestellung); - // exit to stop execution of notify.php - exit(); - } - } catch (Exception $e) { - Helper::logExc($e); - } -} diff --git a/version/101/frontend/181_sync.php b/version/101/frontend/181_sync.php deleted file mode 100644 index 5fb008e..0000000 --- a/version/101/frontend/181_sync.php +++ /dev/null @@ -1,38 +0,0 @@ -kBestellung && $payment = Payment::getPayment($oBestellung->kBestellung)) { - $logData = '#' . $payment->kBestellung . '$' . $payment->kID . "§" . $oBestellung->cBestellNr; - Mollie::JTLMollie()->doLog("WAWI Abgleich: HOOK_BESTELLUNGEN_XML_BESTELLSTATUS", $logData); - 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()) { - Mollie::JTLMollie()->doLog("Create Shippment:
" . print_r($args_arr, 1) . '
', $logData, LOGLEVEL_DEBUG); - $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); - } else { - 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/101/paymentmethod/JTLMollie.php b/version/101/paymentmethod/JTLMollie.php deleted file mode 100644 index b96f6a0..0000000 --- a/version/101/paymentmethod/JTLMollie.php +++ /dev/null @@ -1,535 +0,0 @@ - (int)$order->kBestellung, - 'cZahlungsanbieter' => empty($order->cZahlungsartName) ? $this->name : $order->cZahlungsartName, - 'fBetrag' => 0, - 'fZahlungsgebuehr' => 0, - 'cISO' => $_SESSION['Waehrung']->cISO, - 'cEmpfaenger' => '', - 'cZahler' => '', - 'dZeit' => 'now()', - 'cHinweis' => '', - 'cAbgeholt' => 'N' - ], (array)$payment); - if (isset($model->kZahlungseingang) && $model->kZahlungseingang > 0) { - Shop::DB()->update('tzahlungseingang', 'kZahlungseingang', $model->kZahlungseingang, $model); - } else { - Shop::DB()->insert('tzahlungseingang', $model); - } - - 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; - } - parent::setOrderStatusToPaid($order); - } - - /** - * Prepares everything so that the Customer can start the Payment Process. - * Tells Template Engine. - * - * @param Bestellung $order - */ - public function preparePaymentProcess($order) - { - $logData = '#' . $order->kBestellung . "" . $order->cBestellNr; - try { - $payment = Payment::getPayment($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); - exit(); - } - } catch (Exception $e) { - $this->doLog("Get Payment Error: " . $e->getMessage() . ". Create new ORDER...", $logData); - } - - try { - $hash = $this->generateHash($order); - $oMolliePayment = self::API()->orders->create($this->getOrderData($order, $hash)); - $_SESSION['oMolliePayment'] = $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($hash)); - Shop::Smarty()->assign('oMolliePayment', $oMolliePayment); - if (!$this->duringCheckout) { - Session::getInstance()->cleanUp(); - } - header('Location: ' . $oMolliePayment->getCheckoutUrl()); - exit(); - } catch (ApiException $e) { - Shop::Smarty()->assign('oMollieException', $e); - $this->doLog("Create Payment Error: " . $e->getMessage() . '
' . print_r($e->getTrace(), 1) . '
', $logData); - } - } - - /** - * @param string $msg - * @param null $data - * @param int $level - * @return $this - */ - public function doLog($msg, $data = null, $level = LOGLEVEL_NOTICE) - { - ZahlungsLog::add($this->moduleID, $msg, $data, $level); - - return $this; - } - - /** - * @return MollieApiClient - * @throws ApiException - * @throws IncompatiblePlatform - */ - public static function API() - { - if (self::$_mollie === null) { - self::$_mollie = new MollieApiClient(); - 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); - $data = [ - 'locale' => $locale ?: 'de_DE', - 'amount' => (object)[ - 'currency' => $order->Waehrung->cISO, - 'value' => number_format($order->fGesamtsummeKundenwaehrung, 2, '.', ''), - ], - 'orderNumber' => $order->cBestellNr, - 'lines' => [], - 'billingAddress' => new stdClass(), - 'shippingAddress' => new stdClass(), - 'redirectUrl' => (int)$this->duringCheckout ? Shop::getURL() . '/bestellabschluss.php?mollie=' . md5($hash) : $this->getReturnURL($order), - 'webhookUrl' => $this->getNotificationURL($hash) . '&hash=' . md5($hash), - ]; - - if (static::MOLLIE_METHOD !== '') { - $data['method'] = static::MOLLIE_METHOD; - } - $data['billingAddress']->organizationName = utf8_encode($order->oRechnungsadresse->cFirma); - $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 = $order->oRechnungsadresse->cMail; - $data['billingAddress']->streetAndNumber = utf8_encode($order->oRechnungsadresse->cStrasse . ' ' . $order->oRechnungsadresse->cHausnummer); - $data['billingAddress']->postalCode = $order->oRechnungsadresse->cPLZ; - $data['billingAddress']->city = utf8_encode($order->oRechnungsadresse->cOrt); - $data['billingAddress']->country = $order->oRechnungsadresse->cLand; - - //if ((int)$order->kLieferadresse) { - $data['shippingAddress']->organizationName = utf8_encode($order->Lieferadresse->cFirma); - $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 = $order->oRechnungsadresse->cMail; - $data['shippingAddress']->streetAndNumber = utf8_encode($order->Lieferadresse->cStrasse . ' ' . $order->Lieferadresse->cHausnummer); - $data['shippingAddress']->postalCode = $order->Lieferadresse->cPLZ; - $data['shippingAddress']->city = utf8_encode($order->Lieferadresse->cOrt); - $data['shippingAddress']->country = $order->Lieferadresse->cLand; - //} - - /** @var WarenkorbPos $oPosition */ - foreach ($order->Positionen as $oPosition) { - $line = new stdClass(); - $line->name = utf8_encode($oPosition->cName); - $line->quantity = $oPosition->nAnzahl; - $line->unitPrice = (object)[ - 'value' => number_format($order->Waehrung->fFaktor * ($oPosition->fPreis * ((float)$oPosition->fMwSt / 100 + 1)), 2, '.', ''), - 'currency' => $order->Waehrung->cISO, - ]; - $line->totalAmount = (object)[ - 'value' => number_format($oPosition->nAnzahl * (float)$line->unitPrice->value, 2, '.', ''), - 'currency' => $order->Waehrung->cISO, - ]; - $line->vatRate = $oPosition->fMwSt; - $line->vatAmount = (object)[ - 'value' => number_format($line->totalAmount->value - ($line->totalAmount->value / (1 + (float)$oPosition->fMwSt / 100)), 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 = $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->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->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 "eng": - return "en_US"; - 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"; - } - } - - /** - * @param Bestellung $order - * @param string $hash - * @param array $args - */ - public function handleNotification($order, $hash, $args) - { - Helper::autoload(); - $logData = '#' . $order->kBestellung . "" . $order->cBestellNr; - $this->doLog('Received Notification
' . print_r([$hash, $args], 1) . '
', $logData, LOGLEVEL_NOTICE); - - try { - $oMolliePayment = self::API()->orders->get($args['id']); - Mollie::handleOrder($oMolliePayment, $order->kBestellung); - } catch (Exception $e) { - $this->doLog('handleNotification: ' . $e->getMessage(), $logData); - } - } - - /** - * @param Bestellung $order - * @param string $hash - * @param array $args - * - * @return true, if $order should be finalized - */ - public function finalizeOrder($order, $hash, $args) - { - $logData = '#' . $order->kBestellung . "" . $order->cBestellNr; - try { - Helper::autoload(); - $oMolliePayment = self::API()->orders->get($args['id'], ['embed' => 'payments']); - $logData .= '$' . $oMolliePayment->id; - $this->doLog('Received Notification Finalize Order
' . print_r([$hash, $args, $oMolliePayment], 1) . '
', $logData, LOGLEVEL_DEBUG); - Payment::updateFromPayment($oMolliePayment, $order->kBestellung); - return in_array($oMolliePayment->status, [OrderStatus::STATUS_PAID, OrderStatus::STATUS_AUTHORIZED, OrderStatus::STATUS_PENDING, OrderStatus::STATUS_COMPLETED]); - } catch (Exception $e) { - $this->doLog($e->getMessage(), $logData); - } - return false; - } - - /** - * @return bool - */ - public function canPayAgain() - { - return true; - } - - /** - * determines, if the payment method can be selected in the checkout process - * - * @return bool - */ - public function isSelectable() - { - $locale = self::getLocale($_SESSION['cISOSprache'], $_SESSION['Kunde']->cLand); - if (static::MOLLIE_METHOD !== '') { - try { - /** @var Warenkorb $wk */ - $wk = $_SESSION['Warenkorb']; - $method = self::PossiblePaymentMethods(static::MOLLIE_METHOD, $locale, $_SESSION['Kunde']->cLand, $_SESSION['Waehrung']->cISO, $wk->gibGesamtsummeWaren() * $_SESSION['Waehrung']->fFaktor); - if ($method !== null) { - $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; - } - } - return true; - } - - /** - * @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, '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 (ws_mollie\Helper::getSetting('paymentmethod_sync') === 'N') { - return; - } - $size = ws_mollie\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 object $customer - * @param Warenkorb $cart - * @return bool - true, if $customer with $cart may use Payment Method - */ - public function isValid($customer, $cart) - { - if (Helper::init() && Helper::getSetting("api_key")) { - return true; - } - $this->doLog("isValdid failed: init failed or no API Key given. Try clear the Cache."); - return false; - } - - /** - * @param array $args_arr - * @return bool - */ - public function isValidIntern($args_arr = []) - { - if (Helper::init() && 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/101/paymentmethod/JTLMollieBancontact.php b/version/101/paymentmethod/JTLMollieBancontact.php deleted file mode 100644 index 0e5eeed..0000000 --- a/version/101/paymentmethod/JTLMollieBancontact.php +++ /dev/null @@ -1,8 +0,0 @@ - - {$oMollieException->getMessage()} -
-{/if} \ No newline at end of file diff --git a/version/102/adminmenu/info.php b/version/102/adminmenu/info.php deleted file mode 100644 index 975d723..0000000 --- a/version/102/adminmenu/info.php +++ /dev/null @@ -1,51 +0,0 @@ -assign('defaultTabbertab', \ws_mollie\Helper::getAdminmenu('Info')); - \ws_mollie\Helper::selfupdate(); - } - - $svgQuery = http_build_query([ - 'p' => \ws_mollie\Helper::oPlugin()->cPluginID, - 'v' => \ws_mollie\Helper::oPlugin()->nVersion, - 's' => defined('APPLICATION_VERSION') ? APPLICATION_VERSION : JTL_VERSION, - 'd' => \ws_mollie\Helper::getDomain(), - 'php' => PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION . '.' . PHP_RELEASE_VERSION, - ]); - - echo ""; - echo "
" . - "
" . - " " . - " Lizenz Informationen" . - ' ' . - '
' . - "
" . - " " . - " Update Informationen" . - ' ' . - '
' . - "
" . - " " . - " Plugin informationen" . - ' ' . - '
' . - '
'; - - try { - $latestRelease = \ws_mollie\Helper::getLatestRelease(array_key_exists('update', $_REQUEST)); - if ((int)\ws_mollie\Helper::oPlugin()->nVersion < (int)$latestRelease->version) { - Shop::Smarty()->assign('update', $latestRelease); - } - } catch (\Exception $e) { - } - - Shop::Smarty()->display(\ws_mollie\Helper::oPlugin()->cAdminmenuPfad . '/tpl/info.tpl'); -} catch (Exception $e) { - echo "
Fehler: {$e->getMessage()}
"; - \ws_mollie\Helper::logExc($e); -} diff --git a/version/102/adminmenu/orders.php b/version/102/adminmenu/orders.php deleted file mode 100644 index 891f42a..0000000 --- a/version/102/adminmenu/orders.php +++ /dev/null @@ -1,154 +0,0 @@ - 'danger', 'text' => 'Keine ID angeben!']; - break; - } - $payment = Payment::getPaymentMollie($_REQUEST['id']); - if (!$payment) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; - break; - } - - $order = JTLMollie::API()->orders->get($_REQUEST['id']); - if ($order->status == OrderStatus::STATUS_CANCELED) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung bereits storniert']; - 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; - break; - - case 'cancel': - if (!array_key_exists('id', $_REQUEST)) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; - break; - } - $payment = Payment::getPaymentMollie($_REQUEST['id']); - if (!$payment) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; - break; - } - $order = JTLMollie::API()->orders->get($_REQUEST['id']); - if ($order->status == OrderStatus::STATUS_CANCELED) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung bereits storniert']; - 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; - break; - - case 'capture': - if (!array_key_exists('id', $_REQUEST)) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; - break; - } - $payment = Payment::getPaymentMollie($_REQUEST['id']); - if (!$payment) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; - break; - } - $order = JTLMollie::API()->orders->get($_REQUEST['id']); - if ($order->status !== OrderStatus::STATUS_AUTHORIZED && $order->status !== OrderStatus::STATUS_SHIPPING) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Nur autorisierte Zahlungen können erfasst werden!']; - break; - } - - $oBestellung = new Bestellung($payment->kBestellung, true); - if (!$oBestellung->kBestellung) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung konnte nicht geladen werden!']; - break; - } - - $logData = '#' . $payment->kBestellung . '$' . $payment->kID . "§" . $oBestellung->cBestellNr; - - $options = ['lines' => []]; - if ($oBestellung->cTracking) { - $tracking = new stdClass(); - $tracking->carrier = $oBestellung->cVersandartName; - $tracking->url = $oBestellung->cTrackingURL; - $tracking->code = $oBestellung->cTracking; - $options['tracking'] = $tracking; - } - - // CAPTURE ALL - $shipment = JTLMollie::API()->shipments->createFor($order, $options); - $ordersMsgs[] = (object)['type' => 'success', 'text' => 'Zahlung wurde erfolgreich erfasst!']; - Mollie::JTLMollie()->doLog('Shipment created
' . print_r(['options' => $options, 'shipment' => $shipment], 1) . '
', $logData); - goto order; - - case 'order': - order: - if (!array_key_exists('id', $_REQUEST)) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; - break; - } - - $order = JTLMollie::API()->orders->get($_REQUEST['id']); - $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", [ - ':kBestellung' => '%#' . ($payment->kBestellung ?: '##') . '%', - ':cBestellNr' => '%§' . ($payment->cOrderNumber ?: '§§') . '%', - ':MollieID' => '%$' . ($payment->kID ?: '$$') . '%', - ], 2); - - Shop::Smarty()->assign('payment', $payment) - ->assign('oBestellung', $oBestellung) - ->assign('order', $order) - ->assign('logs', $logs) - ->assign('ordersMsgs', $ordersMsgs); - Shop::Smarty()->display($oPlugin->cAdminmenuPfad . '/tpl/order.tpl'); - return; - } - } - - - $payments = Shop::DB()->executeQueryPrepared("SELECT * FROM xplugin_ws_mollie_payments WHERE kBestellung IS NOT NULL AND cStatus != 'created'", [], 2); - foreach ($payments as $i => $payment) { - $payments[$i]->oBestellung = new Bestellung($payment->kBestellung, false); - } - - Shop::Smarty()->assign('payments', $payments) - ->assign('ordersMsgs', $ordersMsgs) - ->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/102/adminmenu/paymentmethods.php b/version/102/adminmenu/paymentmethods.php deleted file mode 100644 index b31532b..0000000 --- a/version/102/adminmenu/paymentmethods.php +++ /dev/null @@ -1,56 +0,0 @@ -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) { - $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/102/adminmenu/tpl/info.tpl b/version/102/adminmenu/tpl/info.tpl deleted file mode 100644 index 6995522..0000000 --- a/version/102/adminmenu/tpl/info.tpl +++ /dev/null @@ -1,93 +0,0 @@ -
-
-
- - - -
-
- - - -
- - {if isset($update)} -
- -
-

Update auf Version {$update->version} verfügbar!

-
-
-
-
Version:
-
{$update->version}
-
-
-
Erschienen:
-
{$update->create_date}
-
-
-
Changelog:
-
- -
-
- -
-
- -
-
-
- {else} -
- - - -
- {/if} - -
-
-
- - - -
-
- - - -
- -
-
-
- - - -
-
- - - -
-
- - - -
-
-
diff --git a/version/102/adminmenu/tpl/mollie-account-erstellen.png b/version/102/adminmenu/tpl/mollie-account-erstellen.png deleted file mode 100644 index fc1819255ef725fa214cf2bf028cf3428794ecee..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 38998 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 -

- « - 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} -

- -{if count($ordersMsgs)} - {foreach from=$ordersMsgs item=alert} -
{$alert->text}
- {/foreach} -
-{/if} - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Mollie ID:{$payment->kID}Mode:{$order->mode}Status:{$order->status}
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)}
- -

Positionen:

- -
- {if ($order->status === 'authorized' || $order->status === 'shipping') && $oBestellung->cStatus|intval >= 3} - - Zahlung erfassen1 - - {/if} - {if $order->amount->value > $order->amountRefunded->value && $order->amountCaptured->value > 0} - Rckerstatten2 - - {/if} - {if $order->isCancelable} - Stornieren3 - - {/if} -
- - - - - - - - - - - - - - - - - - {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} - - - - - - - - - - - - - {/foreach} - - - - - - - - - - -
StatusSKUNameTypAnzahlMwStSteuerNettoBrutto 
- {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*} -
{$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} - - - - - - - {/foreach} -
- {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}
- - diff --git a/version/102/adminmenu/tpl/orders.tpl b/version/102/adminmenu/tpl/orders.tpl deleted file mode 100644 index 3956ef5..0000000 --- a/version/102/adminmenu/tpl/orders.tpl +++ /dev/null @@ -1,107 +0,0 @@ - -{if count($ordersMsgs)} - {foreach from=$ordersMsgs item=alert} -
{$alert->text}
- {/foreach} -
-{/if} - -{if $hasAPIKey == false} - - Jetzt kostenlos Mollie Account eröffnen! - -{else} - - - - - - - - - - - - - - - - {foreach from=$payments item=payment} - - - - - - - - - - - - {/foreach} - -
BestellNr.IDMollie StatusJTL StatusBetragWährungLocaleMethodeErstellt
- {$payment->cOrderNumber} - {if $payment->cMode == 'test'} - TEST - {/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->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)}
- - -{/if} \ No newline at end of file diff --git a/version/102/adminmenu/tpl/paymentmethods.tpl b/version/102/adminmenu/tpl/paymentmethods.tpl deleted file mode 100644 index 260290f..0000000 --- a/version/102/adminmenu/tpl/paymentmethods.tpl +++ /dev/null @@ -1,92 +0,0 @@ -

Account Status

- - - - - - - - - -
Mode:{$profile->mode}Status:{$profile->status}Review:{$profile->review->status}
- -
- -
-
- - -
- - - -
-
- - -
-
- - -
-
- - - reset -
-
-
- - -{if $allMethods && $allMethods|count} - - - - - - - - - - - - {foreach from=$allMethods item=method} - - - - - - - - {/foreach} - -
BildIDNamePreiseInfos
{$method->description|utf8_decode}{$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} -
-{else} -
Es konnten keine Methoden abgerufen werden.
-{/if} \ No newline at end of file diff --git a/version/102/class/Helper.php b/version/102/class/Helper.php deleted file mode 100644 index 69b0e2e..0000000 --- a/version/102/class/Helper.php +++ /dev/null @@ -1,292 +0,0 @@ -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); - 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(); - } - - /** - * 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); - } elseif (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); - } - - /** - * @return mixed - */ - private static function _masterMail() - { - $settings = \Shop::getSettings(array(CONF_EMAILS)); - return $settings['emails']['email_master_absender']; - } - - /** - * @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/102/class/Model/AbstractModel.php b/version/102/class/Model/AbstractModel.php deleted file mode 100644 index 5638700..0000000 --- a/version/102/class/Model/AbstractModel.php +++ /dev/null @@ -1,7 +0,0 @@ - $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, - ]; - 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; - } - - 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/102/class/Mollie.php b/version/102/class/Mollie.php deleted file mode 100644 index 48c865f..0000000 --- a/version/102/class/Mollie.php +++ /dev/null @@ -1,421 +0,0 @@ -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) { - header('Location: ' . $url); - 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; - } - - switch ((int)$newStatus) { - case BESTELLUNG_STATUS_VERSANDT: - $options['lines'] = []; - break; - case BESTELLUNG_STATUS_TEILVERSANDT: - $lines = []; - foreach ($order->lines as $i => $line) { - if (($quantity = Mollie::getBestellPosSent($line->sku, $oBestellung)) !== false && ($quantity - $line->quantityShipped) > 0) { - $x = $quantity - $line->quantityShipped; - $lines[] = (object)[ - 'id' => $line->id, - 'quantity' => $x, - 'amount' => (object)[ - 'currency' => $line->totalAmount->currency, - 'value' => number_format($x * $line->unitPrice->value, 2), - ], - ]; - } - } - if (count($lines)) { - $options['lines'] = $lines; - } - break; - case BESTELLUNG_STATUS_STORNO: - $options = null; - break; - } - - return $options; - } - - /** - * 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; - } - - /** - * @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) { - $order->orderNumber = $oBestellung->cBestellNr; - Payment::updateFromPayment($order, $kBestellung); - - $oIncomingPayment = Shop::DB()->executeQueryPrepared("SELECT * FROM tzahlungseingang WHERE cHinweis = :cHinweis AND kBestellung = :kBestellung", [':cHinweis' => $order->id, ':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: - $oIncomingPayment->fBetrag = $order->amount->value; - $oIncomingPayment->cISO = $order->amount->currency; - $oIncomingPayment->cHinweis = $order->id; - Mollie::JTLMollie()->addIncomingPayment($oBestellung, $oIncomingPayment); - Mollie::JTLMollie()->setOrderStatusToPaid($oBestellung); - Mollie::JTLMollie()->doLog('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('PaymentStatus: ' . $order->status . ' => Bestellung bezahlt, KEIN Zahlungseingang', $logData, LOGLEVEL_NOTICE); - break; - case OrderStatus::STATUS_CANCELED: - case OrderStatus::STATUS_EXPIRED: - Mollie::JTLMollie()->doLog('PaymentStatus: ' . $order->status, $logData, LOGLEVEL_ERROR); - break; - } - return true; - } - return false; - } - - /** - * @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; - } - - 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/102/frontend/131_globalinclude.php b/version/102/frontend/131_globalinclude.php deleted file mode 100644 index 45d4c6f..0000000 --- a/version/102/frontend/131_globalinclude.php +++ /dev/null @@ -1,72 +0,0 @@ -executeQueryPrepared("SELECT * FROM " . \ws_mollie\Model\Payment::TABLE . " WHERE cHash = :cHash", [':cHash' => $_REQUEST['mollie']], 1); - // Bestellung finalized, redirect to status/completion page - if ((int)$payment->kBestellung) { - $logData = '$' . $payment->kID . '#' . $payment->kBestellung . "§" . $payment->cOrderNumber; - Mollie::JTLMollie()->doLog('Bestellung finalized => redirect abschluss/status', $logData); - $order = JTLMollie::API()->orders->get($payment->kID, ['embed' => 'payments']); - Mollie::handleOrder($order, $payment->kBestellung); - Mollie::getOrderCompletedRedirect($payment->kBestellung, true); - } elseif ($payment) { // payment, but no order => finalize it - require_once __DIR__ . '/../paymentmethod/JTLMollie.php'; - $order = JTLMollie::API()->orders->get($payment->kID, ['embed' => 'payments']); - $logData = '$' . $order->id . '#' . $payment->kBestellung . "§" . $payment->cOrderNumber; - - // GET NEWEST PAYMENT: - /** @var Payment $_payment */ - $_payment = null; - if ($order->payments()) { - /** @var Payment $p */ - foreach ($order->payments() as $p) { - if (!$_payment) { - $_payment = $p; - continue; - } - if (strtotime($p->createdAt) > strtotime($_payment->createdAt)) { - $_payment = $p; - } - } - } - - // finalize only, if order is not canceld/expired - if ($order && !$order->isCanceled() && !$order->isExpired()) { - // finalize only if payment is not expired/canceled,failed or open - if ($_payment && !in_array($_payment->status, [PaymentStatus::STATUS_EXPIRED, PaymentStatus::STATUS_CANCELED, PaymentStatus::STATUS_OPEN, PaymentStatus::STATUS_FAILED, PaymentStatus::STATUS_CANCELED])) { - Mollie::JTLMollie()->doLog('Bestellung open => finalize', $logData); - $session = Session::getInstance(); - /** @noinspection PhpIncludeInspection */ - require_once PFAD_ROOT . 'includes/bestellabschluss_inc.php'; - /** @noinspection PhpIncludeInspection */ - require_once PFAD_ROOT . 'includes/mailTools.php'; - $oBestellung = fakeBestellung(); - $oBestellung = finalisiereBestellung(); - Mollie::JTLMollie()->doLog('Bestellung finalized => redirect
' . print_r($order, 1) . '
', $logData, LOGLEVEL_DEBUG); - Mollie::handleOrder($order, $oBestellung->kBestellung); - Mollie::getOrderCompletedRedirect($oBestellung->kBestellung, true); - } else { - Mollie::JTLMollie()->doLog('Invalid Payment
' . print_r($payment, 1) . '
', $logData, LOGLEVEL_ERROR); - } - } else { - Mollie::JTLMollie()->doLog('Invalid Order
' . print_r($order, 1) . '
', $logData, LOGLEVEL_ERROR); - } - } - } - ob_end_flush(); -} catch (Exception $e) { - Helper::logExc($e); -} diff --git a/version/102/frontend/140_smarty.php b/version/102/frontend/140_smarty.php deleted file mode 100644 index 56a6400..0000000 --- a/version/102/frontend/140_smarty.php +++ /dev/null @@ -1,52 +0,0 @@ -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/102/frontend/144_notify.php b/version/102/frontend/144_notify.php deleted file mode 100644 index a2af9f2..0000000 --- a/version/102/frontend/144_notify.php +++ /dev/null @@ -1,31 +0,0 @@ - Update Payment, stop skript - * - ELSE weiter mit der notify.php - */ - -use ws_mollie\Helper; -use ws_mollie\Model\Payment; -use ws_mollie\Mollie; - -if (array_key_exists('hash', $_REQUEST)) { - require_once __DIR__ . '/../class/Helper.php'; - try { - Helper::init(); - $payment = Payment::getPaymentHash($_REQUEST['hash']); - // If Bestellung already exists, treat as Notification - if ($payment && $payment->kBestellung) { - require_once __DIR__ . '/../paymentmethod/JTLMollie.php'; - $order = JTLMollie::API()->orders->get($payment->kID); - $logData = '#' . $payment->kBestellung . '$' . $payment->kID; - Mollie::JTLMollie()->doLog('Received Notification
' . print_r([$order, $payment], 1) . '
', $logData); - Mollie::handleOrder($order, $payment->kBestellung); - // exit to stop execution of notify.php - exit(); - } - } catch (Exception $e) { - Helper::logExc($e); - } -} diff --git a/version/102/frontend/181_sync.php b/version/102/frontend/181_sync.php deleted file mode 100644 index 5fb008e..0000000 --- a/version/102/frontend/181_sync.php +++ /dev/null @@ -1,38 +0,0 @@ -kBestellung && $payment = Payment::getPayment($oBestellung->kBestellung)) { - $logData = '#' . $payment->kBestellung . '$' . $payment->kID . "§" . $oBestellung->cBestellNr; - Mollie::JTLMollie()->doLog("WAWI Abgleich: HOOK_BESTELLUNGEN_XML_BESTELLSTATUS", $logData); - 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()) { - Mollie::JTLMollie()->doLog("Create Shippment:
" . print_r($args_arr, 1) . '
', $logData, LOGLEVEL_DEBUG); - $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); - } else { - 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/102/paymentmethod/JTLMollie.php b/version/102/paymentmethod/JTLMollie.php deleted file mode 100644 index 372452c..0000000 --- a/version/102/paymentmethod/JTLMollie.php +++ /dev/null @@ -1,552 +0,0 @@ - (int)$order->kBestellung, - 'cZahlungsanbieter' => empty($order->cZahlungsartName) ? $this->name : $order->cZahlungsartName, - 'fBetrag' => 0, - 'fZahlungsgebuehr' => 0, - 'cISO' => $_SESSION['Waehrung']->cISO, - 'cEmpfaenger' => '', - 'cZahler' => '', - 'dZeit' => 'now()', - 'cHinweis' => '', - 'cAbgeholt' => 'N' - ], (array)$payment); - if (isset($model->kZahlungseingang) && $model->kZahlungseingang > 0) { - Shop::DB()->update('tzahlungseingang', 'kZahlungseingang', $model->kZahlungseingang, $model); - } else { - Shop::DB()->insert('tzahlungseingang', $model); - } - - 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; - } - parent::setOrderStatusToPaid($order); - } - - /** - * Prepares everything so that the Customer can start the Payment Process. - * Tells Template Engine. - * - * @param Bestellung $order - */ - public function preparePaymentProcess($order) - { - $logData = '#' . $order->kBestellung . "" . $order->cBestellNr; - try { - $payment = Payment::getPayment($order->kBestellung); - $oMolliePayment = self::API()->orders->get($payment->kID); - 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); - exit(); - } - } catch (Exception $e) { - $this->doLog("Get Payment Error: " . $e->getMessage() . ". Create new ORDER...", $logData); - } - - try { - $hash = $this->generateHash($order); - $oMolliePayment = self::API()->orders->create($this->getOrderData($order, $hash)); - $_SESSION['oMolliePayment'] = $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($hash)); - Shop::Smarty()->assign('oMolliePayment', $oMolliePayment); - if (!$this->duringCheckout) { - Session::getInstance()->cleanUp(); - } - header('Location: ' . $oMolliePayment->getCheckoutUrl()); - exit(); - } catch (ApiException $e) { - Shop::Smarty()->assign('oMollieException', $e); - $this->doLog("Create Payment Error: " . $e->getMessage() . '
' . print_r($e->getTrace(), 1) . '
', $logData); - } - } - - /** - * @return MollieApiClient - * @throws ApiException - * @throws IncompatiblePlatform - */ - public static function API() - { - if (self::$_mollie === null) { - self::$_mollie = new MollieApiClient(); - 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 string $msg - * @param null $data - * @param int $level - * @return $this - */ - public function doLog($msg, $data = null, $level = LOGLEVEL_NOTICE) - { - ZahlungsLog::add($this->moduleID, $msg, $data, $level); - - return $this; - } - - /** - * @param Bestellung $order - * @param $hash - * @return array - */ - protected function getOrderData(Bestellung $order, $hash) - { - $locale = self::getLocale($_SESSION['cISOSprache'], $_SESSION['Kunde']->cLand); - $data = [ - 'locale' => $locale ?: 'de_DE', - 'amount' => (object)[ - 'currency' => $order->Waehrung->cISO, - 'value' => number_format($order->fGesamtsummeKundenwaehrung, 2, '.', ''), - ], - 'orderNumber' => $order->cBestellNr, - 'lines' => [], - 'billingAddress' => new stdClass(), - - 'redirectUrl' => (int)$this->duringCheckout ? Shop::getURL() . '/bestellabschluss.php?mollie=' . md5($hash) : $this->getReturnURL($order), - 'webhookUrl' => $this->getNotificationURL($hash) . '&hash=' . md5($hash), - ]; - - if (static::MOLLIE_METHOD !== '') { - $data['method'] = static::MOLLIE_METHOD; - } - 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 = $order->oRechnungsadresse->cMail; - $data['billingAddress']->streetAndNumber = utf8_encode($order->oRechnungsadresse->cStrasse . ' ' . $order->oRechnungsadresse->cHausnummer); - $data['billingAddress']->postalCode = $order->oRechnungsadresse->cPLZ; - $data['billingAddress']->city = utf8_encode($order->oRechnungsadresse->cOrt); - $data['billingAddress']->country = $order->oRechnungsadresse->cLand; - - 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 = $order->oRechnungsadresse->cMail; - $data['shippingAddress']->streetAndNumber = utf8_encode($order->Lieferadresse->cStrasse . ' ' . $order->Lieferadresse->cHausnummer); - $data['shippingAddress']->postalCode = $order->Lieferadresse->cPLZ; - $data['shippingAddress']->city = utf8_encode($order->Lieferadresse->cOrt); - $data['shippingAddress']->country = $order->Lieferadresse->cLand; - } - - /** @var WarenkorbPos $oPosition */ - foreach ($order->Positionen as $oPosition) { - $unitPrice = berechneBrutto($order->Waehrung->fFaktor * $oPosition->fPreis, $oPosition->fMwSt, 4); - $totalAmount = $oPosition->nAnzahl * $unitPrice; - - $line = new stdClass(); - $line->name = utf8_encode($oPosition->cName); - $line->quantity = $oPosition->nAnzahl; - $line->unitPrice = (object)[ - 'value' => number_format(round($unitPrice, 2), 2, '.', ''), - 'currency' => $order->Waehrung->cISO, - ]; - $line->totalAmount = (object)[ - 'value' => number_format(round($totalAmount, 2), 2, '.', ''), - 'currency' => $order->Waehrung->cISO, - ]; - $line->vatRate = $oPosition->fMwSt; - $x = $totalAmount - (berechneNetto($unitPrice, $oPosition->fMwSt, 4) * $oPosition->nAnzahl); - $line->vatAmount = (object)[ - 'value' => number_format(round($x, 2), 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 = $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->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->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 "eng": - return "en_US"; - 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"; - } - } - - /** - * @param Bestellung $order - * @param string $hash - * @param array $args - */ - public function handleNotification($order, $hash, $args) - { - Helper::autoload(); - $logData = '#' . $order->kBestellung . "" . $order->cBestellNr; - $this->doLog('Received Notification
' . print_r([$hash, $args], 1) . '
', $logData, LOGLEVEL_NOTICE); - - try { - $oMolliePayment = self::API()->orders->get($args['id']); - Mollie::handleOrder($oMolliePayment, $order->kBestellung); - } catch (Exception $e) { - $this->doLog('handleNotification: ' . $e->getMessage(), $logData); - } - } - - /** - * @param Bestellung $order - * @param string $hash - * @param array $args - * - * @return true, if $order should be finalized - */ - public function finalizeOrder($order, $hash, $args) - { - $logData = '#' . $order->kBestellung . "" . $order->cBestellNr; - try { - Helper::autoload(); - $oMolliePayment = self::API()->orders->get($args['id'], ['embed' => 'payments']); - $logData .= '$' . $oMolliePayment->id; - $this->doLog('Received Notification Finalize Order
' . print_r([$hash, $args, $oMolliePayment], 1) . '
', $logData, LOGLEVEL_DEBUG); - Payment::updateFromPayment($oMolliePayment, $order->kBestellung); - return in_array($oMolliePayment->status, [OrderStatus::STATUS_PAID, OrderStatus::STATUS_AUTHORIZED, OrderStatus::STATUS_PENDING, OrderStatus::STATUS_COMPLETED]); - } catch (Exception $e) { - $this->doLog($e->getMessage(), $logData); - } - return false; - } - - /** - * @return bool - */ - public function canPayAgain() - { - return true; - } - - /** - * determines, if the payment method can be selected in the checkout process - * - * @return bool - */ - public function isSelectable() - { - /** @var Warenkorb $wk */ - $wk = $_SESSION['Warenkorb']; - foreach ($wk->PositionenArr as $oPosition) { - if ($oPosition->Artikel->cTeilbar === 'Y' && fmod($oPosition->nAnzahl, 1) !== 0) { - return false; - } - } - - $locale = self::getLocale($_SESSION['cISOSprache'], $_SESSION['Kunde']->cLand); - if (static::MOLLIE_METHOD !== '') { - try { - $method = self::PossiblePaymentMethods(static::MOLLIE_METHOD, $locale, $_SESSION['Kunde']->cLand, $_SESSION['Waehrung']->cISO, $wk->gibGesamtsummeWaren() * $_SESSION['Waehrung']->fFaktor); - if ($method !== null) { - $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; - } - } - return true; - } - - /** - * @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, '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 (ws_mollie\Helper::getSetting('paymentmethod_sync') === 'N') { - return; - } - $size = ws_mollie\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 object $customer - * @param Warenkorb $cart - * @return bool - true, if $customer with $cart may use Payment Method - */ - public function isValid($customer, $cart) - { - if (Helper::init() && Helper::getSetting("api_key")) { - return true; - } - $this->doLog("isValdid failed: init failed or no API Key given. Try clear the Cache."); - return false; - } - - /** - * @param array $args_arr - * @return bool - */ - public function isValidIntern($args_arr = []) - { - if (Helper::init() && 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/102/paymentmethod/JTLMollieBancontact.php b/version/102/paymentmethod/JTLMollieBancontact.php deleted file mode 100644 index 0e5eeed..0000000 --- a/version/102/paymentmethod/JTLMollieBancontact.php +++ /dev/null @@ -1,8 +0,0 @@ - - {$oMollieException->getMessage()} - -{/if} \ No newline at end of file diff --git a/version/103/adminmenu/info.php b/version/103/adminmenu/info.php deleted file mode 100644 index 975d723..0000000 --- a/version/103/adminmenu/info.php +++ /dev/null @@ -1,51 +0,0 @@ -assign('defaultTabbertab', \ws_mollie\Helper::getAdminmenu('Info')); - \ws_mollie\Helper::selfupdate(); - } - - $svgQuery = http_build_query([ - 'p' => \ws_mollie\Helper::oPlugin()->cPluginID, - 'v' => \ws_mollie\Helper::oPlugin()->nVersion, - 's' => defined('APPLICATION_VERSION') ? APPLICATION_VERSION : JTL_VERSION, - 'd' => \ws_mollie\Helper::getDomain(), - 'php' => PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION . '.' . PHP_RELEASE_VERSION, - ]); - - echo ""; - echo "
" . - "
" . - " " . - " Lizenz Informationen" . - ' ' . - '
' . - "
" . - " " . - " Update Informationen" . - ' ' . - '
' . - "
" . - " " . - " Plugin informationen" . - ' ' . - '
' . - '
'; - - try { - $latestRelease = \ws_mollie\Helper::getLatestRelease(array_key_exists('update', $_REQUEST)); - if ((int)\ws_mollie\Helper::oPlugin()->nVersion < (int)$latestRelease->version) { - Shop::Smarty()->assign('update', $latestRelease); - } - } catch (\Exception $e) { - } - - Shop::Smarty()->display(\ws_mollie\Helper::oPlugin()->cAdminmenuPfad . '/tpl/info.tpl'); -} catch (Exception $e) { - echo "
Fehler: {$e->getMessage()}
"; - \ws_mollie\Helper::logExc($e); -} diff --git a/version/103/adminmenu/orders.php b/version/103/adminmenu/orders.php deleted file mode 100644 index 99603ed..0000000 --- a/version/103/adminmenu/orders.php +++ /dev/null @@ -1,154 +0,0 @@ - 'danger', 'text' => 'Keine ID angeben!']; - break; - } - $payment = Payment::getPaymentMollie($_REQUEST['id']); - if (!$payment) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; - break; - } - - $order = JTLMollie::API()->orders->get($_REQUEST['id']); - if ($order->status == OrderStatus::STATUS_CANCELED) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung bereits storniert']; - 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; - break; - - case 'cancel': - if (!array_key_exists('id', $_REQUEST)) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; - break; - } - $payment = Payment::getPaymentMollie($_REQUEST['id']); - if (!$payment) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; - break; - } - $order = JTLMollie::API()->orders->get($_REQUEST['id']); - if ($order->status == OrderStatus::STATUS_CANCELED) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung bereits storniert']; - 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; - break; - - case 'capture': - if (!array_key_exists('id', $_REQUEST)) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; - break; - } - $payment = Payment::getPaymentMollie($_REQUEST['id']); - if (!$payment) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; - break; - } - $order = JTLMollie::API()->orders->get($_REQUEST['id']); - if ($order->status !== OrderStatus::STATUS_AUTHORIZED && $order->status !== OrderStatus::STATUS_SHIPPING) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Nur autorisierte Zahlungen können erfasst werden!']; - break; - } - - $oBestellung = new Bestellung($payment->kBestellung, true); - if (!$oBestellung->kBestellung) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung konnte nicht geladen werden!']; - break; - } - - $logData = '#' . $payment->kBestellung . '$' . $payment->kID . "§" . $oBestellung->cBestellNr; - - $options = ['lines' => []]; - if ($oBestellung->cTracking) { - $tracking = new stdClass(); - $tracking->carrier = $oBestellung->cVersandartName; - $tracking->url = $oBestellung->cTrackingURL; - $tracking->code = $oBestellung->cTracking; - $options['tracking'] = $tracking; - } - - // CAPTURE ALL - $shipment = JTLMollie::API()->shipments->createFor($order, $options); - $ordersMsgs[] = (object)['type' => 'success', 'text' => 'Zahlung wurde erfolgreich erfasst!']; - Mollie::JTLMollie()->doLog('Shipment created
' . print_r(['options' => $options, 'shipment' => $shipment], 1) . '
', $logData); - goto order; - - case 'order': - order: - if (!array_key_exists('id', $_REQUEST)) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; - 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", [ - ':kBestellung' => '%#' . ($payment->kBestellung ?: '##') . '%', - ':cBestellNr' => '%§' . ($payment->cOrderNumber ?: '§§') . '%', - ':MollieID' => '%$' . ($payment->kID ?: '$$') . '%', - ], 2); - - Shop::Smarty()->assign('payment', $payment) - ->assign('oBestellung', $oBestellung) - ->assign('order', $order) - ->assign('logs', $logs) - ->assign('ordersMsgs', $ordersMsgs); - Shop::Smarty()->display($oPlugin->cAdminmenuPfad . '/tpl/order.tpl'); - return; - } - } - - - $payments = Shop::DB()->executeQueryPrepared("SELECT * FROM xplugin_ws_mollie_payments WHERE kBestellung IS NOT NULL AND cStatus != 'created'", [], 2); - foreach ($payments as $i => $payment) { - $payments[$i]->oBestellung = new Bestellung($payment->kBestellung, false); - } - - Shop::Smarty()->assign('payments', $payments) - ->assign('ordersMsgs', $ordersMsgs) - ->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/103/adminmenu/paymentmethods.php b/version/103/adminmenu/paymentmethods.php deleted file mode 100644 index a40dc23..0000000 --- a/version/103/adminmenu/paymentmethods.php +++ /dev/null @@ -1,57 +0,0 @@ -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; - $params['includeWallets'] = 'applepay'; - } - - 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/103/adminmenu/tpl/info.tpl b/version/103/adminmenu/tpl/info.tpl deleted file mode 100644 index da2a55a..0000000 --- a/version/103/adminmenu/tpl/info.tpl +++ /dev/null @@ -1,93 +0,0 @@ -
-
-
- - - -
-
- - - -
- - {if isset($update)} -
- -
-

Update auf Version {$update->version} verfügbar!

-
-
-
-
Version:
-
{$update->version}
-
-
-
Erschienen:
-
{$update->create_date}
-
-
-
Changelog:
-
- -
-
- -
-
- -
-
-
- {else} -
- - - -
- {/if} - -
-
-
- - - -
-
- - - -
- -
-
-
- - - -
-
- - - -
-
- - - -
-
-
diff --git a/version/103/adminmenu/tpl/mollie-account-erstellen.png b/version/103/adminmenu/tpl/mollie-account-erstellen.png deleted file mode 100644 index fc1819255ef725fa214cf2bf028cf3428794ecee..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 38998 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 -

- « - 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} -

- -{if count($ordersMsgs)} - {foreach from=$ordersMsgs item=alert} -
{$alert->text}
- {/foreach} -
-{/if} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Mollie ID:{$payment->kID}Mode:{$order->mode}Status:{$order->status}
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

- - - - - - - - - - - - - - {foreach from=$order->payments() item=payment} - - - - - - - - - - - {/foreach} -
IDStatusMethodeAmountSettlementRefundedRemainingDetails
{$payment->id}{$payment->status}{$payment->method}{$payment->amount->value} {$payment->amount->currency}{$payment->settlementAmount->value} {$payment->settlementAmount->currency}{$payment->amountRefunded->value} {$payment->amountRefunded->currency}{$payment->amountRemaining->value} {$payment->amountRemaining->currency} -
    - {foreach from=$payment->details item=value key=key} -
  • {$key}: {$value}
  • - {/foreach} -
-
-{/if} - - -

Positionen:

- -
- {if ($order->status === 'authorized' || $order->status === 'shipping') && $oBestellung->cStatus|intval >= 3} - - Zahlung erfassen1 - - {/if} - {if $order->amount->value > $order->amountRefunded->value && $order->amountCaptured->value > 0} - Rckerstatten2 - - {/if} - {if $order->isCancelable} - Stornieren3 - - {/if} -
- - - - - - - - - - - - - - - - - - {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} - - - - - - - - - - - - - {/foreach} - - - - - - - - - - -
StatusSKUNameTypAnzahlMwStSteuerNettoBrutto 
- {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*} -
{$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} - - - - - - - {/foreach} -
- {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}
- - diff --git a/version/103/adminmenu/tpl/orders.tpl b/version/103/adminmenu/tpl/orders.tpl deleted file mode 100644 index 3956ef5..0000000 --- a/version/103/adminmenu/tpl/orders.tpl +++ /dev/null @@ -1,107 +0,0 @@ - -{if count($ordersMsgs)} - {foreach from=$ordersMsgs item=alert} -
{$alert->text}
- {/foreach} -
-{/if} - -{if $hasAPIKey == false} - - Jetzt kostenlos Mollie Account eröffnen! - -{else} - - - - - - - - - - - - - - - - {foreach from=$payments item=payment} - - - - - - - - - - - - {/foreach} - -
BestellNr.IDMollie StatusJTL StatusBetragWährungLocaleMethodeErstellt
- {$payment->cOrderNumber} - {if $payment->cMode == 'test'} - TEST - {/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->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)}
- - -{/if} \ No newline at end of file diff --git a/version/103/adminmenu/tpl/paymentmethods.tpl b/version/103/adminmenu/tpl/paymentmethods.tpl deleted file mode 100644 index 260290f..0000000 --- a/version/103/adminmenu/tpl/paymentmethods.tpl +++ /dev/null @@ -1,92 +0,0 @@ -

Account Status

- - - - - - - - - -
Mode:{$profile->mode}Status:{$profile->status}Review:{$profile->review->status}
- -
- -
-
- - -
- - - -
-
- - -
-
- - -
-
- - - reset -
-
-
- - -{if $allMethods && $allMethods|count} - - - - - - - - - - - - {foreach from=$allMethods item=method} - - - - - - - - {/foreach} - -
BildIDNamePreiseInfos
{$method->description|utf8_decode}{$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} -
-{else} -
Es konnten keine Methoden abgerufen werden.
-{/if} \ No newline at end of file diff --git a/version/103/class/Helper.php b/version/103/class/Helper.php deleted file mode 100644 index 69b0e2e..0000000 --- a/version/103/class/Helper.php +++ /dev/null @@ -1,292 +0,0 @@ -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); - 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(); - } - - /** - * 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); - } elseif (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); - } - - /** - * @return mixed - */ - private static function _masterMail() - { - $settings = \Shop::getSettings(array(CONF_EMAILS)); - return $settings['emails']['email_master_absender']; - } - - /** - * @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/103/class/Model/AbstractModel.php b/version/103/class/Model/AbstractModel.php deleted file mode 100644 index 5638700..0000000 --- a/version/103/class/Model/AbstractModel.php +++ /dev/null @@ -1,7 +0,0 @@ - $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, - ]; - 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; - } - - 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/103/class/Mollie.php b/version/103/class/Mollie.php deleted file mode 100644 index a1fab4c..0000000 --- a/version/103/class/Mollie.php +++ /dev/null @@ -1,441 +0,0 @@ -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) { - header('Location: ' . $url); - 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; - } - - switch ((int)$newStatus) { - case BESTELLUNG_STATUS_VERSANDT: - $options['lines'] = []; - break; - case BESTELLUNG_STATUS_TEILVERSANDT: - $lines = []; - foreach ($order->lines as $i => $line) { - if (($quantity = Mollie::getBestellPosSent($line->sku, $oBestellung)) !== false && ($quantity - $line->quantityShipped) > 0) { - $x = $quantity - $line->quantityShipped; - $lines[] = (object)[ - 'id' => $line->id, - 'quantity' => $x, - 'amount' => (object)[ - 'currency' => $line->totalAmount->currency, - 'value' => number_format($x * $line->unitPrice->value, 2), - ], - ]; - } - } - if (count($lines)) { - $options['lines'] = $lines; - } - break; - case BESTELLUNG_STATUS_STORNO: - $options = null; - break; - } - - return $options; - } - - /** - * 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; - } - - /** - * @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) { - 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('handleOrder: ' . $e->getMessage(), $logData); - } - - - $order->orderNumber = $oBestellung->cBestellNr; - Payment::updateFromPayment($order, $kBestellung); - - $oIncomingPayment = Shop::DB()->executeQueryPrepared("SELECT * FROM tzahlungseingang WHERE cHinweis LIKE :cHinweis AND kBestellung = :kBestellung", [':cHinweis' => '%' . $order->id . '%', ':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 ($payments = $order->payments()) { - /** @var \Mollie\Api\Resources\Payment $payment */ - foreach ($payments as $payment) { - if (in_array($payment->status, [PaymentStatus::STATUS_AUTHORIZED, PaymentStatus::STATUS_PAID])) { - $cHinweis .= ' / ' . $payment->id; - } - } - } - $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('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('PaymentStatus: ' . $order->status . ' => Bestellung bezahlt, KEIN Zahlungseingang', $logData, LOGLEVEL_NOTICE); - break; - case OrderStatus::STATUS_CANCELED: - case OrderStatus::STATUS_EXPIRED: - Mollie::JTLMollie()->doLog('PaymentStatus: ' . $order->status, $logData, LOGLEVEL_ERROR); - break; - } - return true; - } - return false; - } - - /** - * @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; - } - - 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/103/frontend/131_globalinclude.php b/version/103/frontend/131_globalinclude.php deleted file mode 100644 index 45d4c6f..0000000 --- a/version/103/frontend/131_globalinclude.php +++ /dev/null @@ -1,72 +0,0 @@ -executeQueryPrepared("SELECT * FROM " . \ws_mollie\Model\Payment::TABLE . " WHERE cHash = :cHash", [':cHash' => $_REQUEST['mollie']], 1); - // Bestellung finalized, redirect to status/completion page - if ((int)$payment->kBestellung) { - $logData = '$' . $payment->kID . '#' . $payment->kBestellung . "§" . $payment->cOrderNumber; - Mollie::JTLMollie()->doLog('Bestellung finalized => redirect abschluss/status', $logData); - $order = JTLMollie::API()->orders->get($payment->kID, ['embed' => 'payments']); - Mollie::handleOrder($order, $payment->kBestellung); - Mollie::getOrderCompletedRedirect($payment->kBestellung, true); - } elseif ($payment) { // payment, but no order => finalize it - require_once __DIR__ . '/../paymentmethod/JTLMollie.php'; - $order = JTLMollie::API()->orders->get($payment->kID, ['embed' => 'payments']); - $logData = '$' . $order->id . '#' . $payment->kBestellung . "§" . $payment->cOrderNumber; - - // GET NEWEST PAYMENT: - /** @var Payment $_payment */ - $_payment = null; - if ($order->payments()) { - /** @var Payment $p */ - foreach ($order->payments() as $p) { - if (!$_payment) { - $_payment = $p; - continue; - } - if (strtotime($p->createdAt) > strtotime($_payment->createdAt)) { - $_payment = $p; - } - } - } - - // finalize only, if order is not canceld/expired - if ($order && !$order->isCanceled() && !$order->isExpired()) { - // finalize only if payment is not expired/canceled,failed or open - if ($_payment && !in_array($_payment->status, [PaymentStatus::STATUS_EXPIRED, PaymentStatus::STATUS_CANCELED, PaymentStatus::STATUS_OPEN, PaymentStatus::STATUS_FAILED, PaymentStatus::STATUS_CANCELED])) { - Mollie::JTLMollie()->doLog('Bestellung open => finalize', $logData); - $session = Session::getInstance(); - /** @noinspection PhpIncludeInspection */ - require_once PFAD_ROOT . 'includes/bestellabschluss_inc.php'; - /** @noinspection PhpIncludeInspection */ - require_once PFAD_ROOT . 'includes/mailTools.php'; - $oBestellung = fakeBestellung(); - $oBestellung = finalisiereBestellung(); - Mollie::JTLMollie()->doLog('Bestellung finalized => redirect
' . print_r($order, 1) . '
', $logData, LOGLEVEL_DEBUG); - Mollie::handleOrder($order, $oBestellung->kBestellung); - Mollie::getOrderCompletedRedirect($oBestellung->kBestellung, true); - } else { - Mollie::JTLMollie()->doLog('Invalid Payment
' . print_r($payment, 1) . '
', $logData, LOGLEVEL_ERROR); - } - } else { - Mollie::JTLMollie()->doLog('Invalid Order
' . print_r($order, 1) . '
', $logData, LOGLEVEL_ERROR); - } - } - } - ob_end_flush(); -} catch (Exception $e) { - Helper::logExc($e); -} diff --git a/version/103/frontend/140_smarty.php b/version/103/frontend/140_smarty.php deleted file mode 100644 index 56a6400..0000000 --- a/version/103/frontend/140_smarty.php +++ /dev/null @@ -1,52 +0,0 @@ -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/103/frontend/144_notify.php b/version/103/frontend/144_notify.php deleted file mode 100644 index a2af9f2..0000000 --- a/version/103/frontend/144_notify.php +++ /dev/null @@ -1,31 +0,0 @@ - Update Payment, stop skript - * - ELSE weiter mit der notify.php - */ - -use ws_mollie\Helper; -use ws_mollie\Model\Payment; -use ws_mollie\Mollie; - -if (array_key_exists('hash', $_REQUEST)) { - require_once __DIR__ . '/../class/Helper.php'; - try { - Helper::init(); - $payment = Payment::getPaymentHash($_REQUEST['hash']); - // If Bestellung already exists, treat as Notification - if ($payment && $payment->kBestellung) { - require_once __DIR__ . '/../paymentmethod/JTLMollie.php'; - $order = JTLMollie::API()->orders->get($payment->kID); - $logData = '#' . $payment->kBestellung . '$' . $payment->kID; - Mollie::JTLMollie()->doLog('Received Notification
' . print_r([$order, $payment], 1) . '
', $logData); - Mollie::handleOrder($order, $payment->kBestellung); - // exit to stop execution of notify.php - exit(); - } - } catch (Exception $e) { - Helper::logExc($e); - } -} diff --git a/version/103/frontend/181_sync.php b/version/103/frontend/181_sync.php deleted file mode 100644 index 5fb008e..0000000 --- a/version/103/frontend/181_sync.php +++ /dev/null @@ -1,38 +0,0 @@ -kBestellung && $payment = Payment::getPayment($oBestellung->kBestellung)) { - $logData = '#' . $payment->kBestellung . '$' . $payment->kID . "§" . $oBestellung->cBestellNr; - Mollie::JTLMollie()->doLog("WAWI Abgleich: HOOK_BESTELLUNGEN_XML_BESTELLSTATUS", $logData); - 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()) { - Mollie::JTLMollie()->doLog("Create Shippment:
" . print_r($args_arr, 1) . '
', $logData, LOGLEVEL_DEBUG); - $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); - } else { - 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/103/paymentmethod/JTLMollie.php b/version/103/paymentmethod/JTLMollie.php deleted file mode 100644 index 7733a27..0000000 --- a/version/103/paymentmethod/JTLMollie.php +++ /dev/null @@ -1,563 +0,0 @@ - (int)$order->kBestellung, - 'cZahlungsanbieter' => empty($order->cZahlungsartName) ? $this->name : $order->cZahlungsartName, - 'fBetrag' => 0, - 'fZahlungsgebuehr' => 0, - 'cISO' => $_SESSION['Waehrung']->cISO, - 'cEmpfaenger' => '', - 'cZahler' => '', - 'dZeit' => 'now()', - 'cHinweis' => '', - 'cAbgeholt' => 'N' - ], (array)$payment); - if (isset($model->kZahlungseingang) && $model->kZahlungseingang > 0) { - Shop::DB()->update('tzahlungseingang', 'kZahlungseingang', $model->kZahlungseingang, $model); - } else { - Shop::DB()->insert('tzahlungseingang', $model); - } - - 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; - } - parent::setOrderStatusToPaid($order); - } - - /** - * Prepares everything so that the Customer can start the Payment Process. - * Tells Template Engine. - * - * @param Bestellung $order - */ - public function preparePaymentProcess($order) - { - $logData = '#' . $order->kBestellung . "" . $order->cBestellNr; - try { - if ($order->kBestellung) { - $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(); - } - } - } catch (Exception $e) { - $this->doLog("Get Payment Error: " . $e->getMessage() . ". Create new ORDER...", $logData); - } - - try { - if (!array_key_exists('oMolliePayment', $_SESSION) || !($_SESSION['oMolliePayment'] instanceof \Mollie\Api\Resources\Order)) { - $hash = $this->generateHash($order); - $orderData = $this->getOrderData($order, $hash); - $oMolliePayment = self::API()->orders->create($orderData); - $_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(); - } - header('Location: ' . $oMolliePayment->getCheckoutUrl()); - unset($_SESSION['oMolliePayment']); - echo "redirect to payment ..."; - exit(); - } catch (ApiException $e) { - Shop::Smarty()->assign('oMollieException', $e); - $this->doLog("Create Payment Error: " . $e->getMessage() . '
' . print_r($e->getTrace(), 1) . '
', $logData); - } - } - - /** - * @return MollieApiClient - * @throws ApiException - * @throws IncompatiblePlatform - */ - public static function API() - { - if (self::$_mollie === null) { - self::$_mollie = new MollieApiClient(); - 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 string $msg - * @param null $data - * @param int $level - * @return $this - */ - public function doLog($msg, $data = null, $level = LOGLEVEL_NOTICE) - { - ZahlungsLog::add($this->moduleID, $msg, $data, $level); - - return $this; - } - - /** - * @param Bestellung $order - * @param $hash - * @return array - */ - protected function getOrderData(Bestellung $order, $hash) - { - $locale = self::getLocale($_SESSION['cISOSprache'], $_SESSION['Kunde']->cLand); - $data = [ - 'locale' => $locale ?: 'de_DE', - 'amount' => (object)[ - 'currency' => $order->Waehrung->cISO, - 'value' => number_format($order->fGesamtsummeKundenwaehrung, 2, '.', ''), - ], - 'orderNumber' => $order->cBestellNr, - 'lines' => [], - 'billingAddress' => new stdClass(), - - 'redirectUrl' => (int)$this->duringCheckout ? Shop::getURL() . '/bestellabschluss.php?mollie=' . md5($hash) : $this->getReturnURL($order), - 'webhookUrl' => $this->getNotificationURL($hash) . '&hash=' . md5($hash), - ]; - - if (static::MOLLIE_METHOD !== '') { - $data['method'] = static::MOLLIE_METHOD; - } - 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 = $order->oRechnungsadresse->cMail; - $data['billingAddress']->streetAndNumber = utf8_encode($order->oRechnungsadresse->cStrasse . ' ' . $order->oRechnungsadresse->cHausnummer); - $data['billingAddress']->postalCode = $order->oRechnungsadresse->cPLZ; - $data['billingAddress']->city = utf8_encode($order->oRechnungsadresse->cOrt); - $data['billingAddress']->country = $order->oRechnungsadresse->cLand; - - 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 = $order->oRechnungsadresse->cMail; - $data['shippingAddress']->streetAndNumber = utf8_encode($order->Lieferadresse->cStrasse . ' ' . $order->Lieferadresse->cHausnummer); - $data['shippingAddress']->postalCode = $order->Lieferadresse->cPLZ; - $data['shippingAddress']->city = utf8_encode($order->Lieferadresse->cOrt); - $data['shippingAddress']->country = $order->Lieferadresse->cLand; - } - - /** @var WarenkorbPos $oPosition */ - foreach ($order->Positionen as $oPosition) { - $unitPrice = berechneBrutto($order->Waehrung->fFaktor * $oPosition->fPreis, $oPosition->fMwSt, 4); - $totalAmount = $oPosition->nAnzahl * $unitPrice; - - $line = new stdClass(); - $line->name = utf8_encode($oPosition->cName); - $line->quantity = $oPosition->nAnzahl; - $line->unitPrice = (object)[ - 'value' => number_format(round($unitPrice, 2), 2, '.', ''), - 'currency' => $order->Waehrung->cISO, - ]; - $line->totalAmount = (object)[ - 'value' => number_format(round($totalAmount, 2), 2, '.', ''), - 'currency' => $order->Waehrung->cISO, - ]; - $line->vatRate = $oPosition->fMwSt; - $x = $totalAmount - (berechneNetto($unitPrice, $oPosition->fMwSt, 4) * $oPosition->nAnzahl); - $line->vatAmount = (object)[ - 'value' => number_format(round($x, 2), 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 = $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->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->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 "eng": - return "en_US"; - 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"; - } - } - - /** - * @param Bestellung $order - * @param string $hash - * @param array $args - */ - public function handleNotification($order, $hash, $args) - { - Helper::autoload(); - $logData = '#' . $order->kBestellung . "" . $order->cBestellNr; - $this->doLog('Received Notification
' . print_r([$hash, $args], 1) . '
', $logData, LOGLEVEL_NOTICE); - - try { - $oMolliePayment = self::API()->orders->get($args['id'], ['embed' => 'payments']); - Mollie::handleOrder($oMolliePayment, $order->kBestellung); - } catch (Exception $e) { - $this->doLog('handleNotification: ' . $e->getMessage(), $logData); - } - } - - /** - * @param Bestellung $order - * @param string $hash - * @param array $args - * - * @return true, if $order should be finalized - */ - public function finalizeOrder($order, $hash, $args) - { - $logData = '#' . $order->kBestellung . "" . $order->cBestellNr; - try { - Helper::autoload(); - $oMolliePayment = self::API()->orders->get($args['id'], ['embed' => 'payments']); - $logData .= '$' . $oMolliePayment->id; - $this->doLog('Received Notification Finalize Order
' . print_r([$hash, $args, $oMolliePayment], 1) . '
', $logData, LOGLEVEL_DEBUG); - Payment::updateFromPayment($oMolliePayment, $order->kBestellung); - return in_array($oMolliePayment->status, [OrderStatus::STATUS_PAID, OrderStatus::STATUS_AUTHORIZED, OrderStatus::STATUS_PENDING, OrderStatus::STATUS_COMPLETED]); - } catch (Exception $e) { - $this->doLog($e->getMessage(), $logData); - } - return false; - } - - /** - * @return bool - */ - public function canPayAgain() - { - return true; - } - - /** - * determines, if the payment method can be selected in the checkout process - * - * @return bool - */ - public function isSelectable() - { - /** @var Warenkorb $wk */ - $wk = $_SESSION['Warenkorb']; - foreach ($wk->PositionenArr as $oPosition) { - if ($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 { - $method = self::PossiblePaymentMethods(static::MOLLIE_METHOD, $locale, $_SESSION['Kunde']->cLand, $_SESSION['Waehrung']->cISO, $wk->gibGesamtsummeWaren() * $_SESSION['Waehrung']->fFaktor); - if ($method !== null) { - $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; - } - } - return true; - } - - /** - * @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 (ws_mollie\Helper::getSetting('paymentmethod_sync') === 'N') { - return; - } - $size = ws_mollie\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 object $customer - * @param Warenkorb $cart - * @return bool - true, if $customer with $cart may use Payment Method - */ - public function isValid($customer, $cart) - { - if (Helper::init() && Helper::getSetting("api_key")) { - return true; - } - $this->doLog("isValdid failed: init failed or no API Key given. Try clear the Cache."); - return false; - } - - /** - * @param array $args_arr - * @return bool - */ - public function isValidIntern($args_arr = []) - { - if (Helper::init() && 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/103/paymentmethod/JTLMollieApplePay.php b/version/103/paymentmethod/JTLMollieApplePay.php deleted file mode 100644 index ecf20a8..0000000 --- a/version/103/paymentmethod/JTLMollieApplePay.php +++ /dev/null @@ -1,8 +0,0 @@ - - {$oMollieException->getMessage()} - -{/if} \ No newline at end of file diff --git a/version/104/adminmenu/info.php b/version/104/adminmenu/info.php deleted file mode 100644 index cb28294..0000000 --- a/version/104/adminmenu/info.php +++ /dev/null @@ -1,54 +0,0 @@ -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, - 'd' => Helper::getDomain(), - 'm' => base64_encode(Helper::getMasterMail(true)), - 'php' => PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION . '.' . PHP_RELEASE_VERSION, - ]); - - echo ""; - echo "
" . - "
" . - " " . - " Lizenz Informationen" . - ' ' . - '
' . - "
" . - " " . - " Update Informationen" . - ' ' . - '
' . - "
" . - " " . - " Plugin informationen" . - ' ' . - '
' . - '
'; - - 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'); -} catch (Exception $e) { - echo "
Fehler: {$e->getMessage()}
"; - Helper::logExc($e); -} diff --git a/version/104/adminmenu/orders.php b/version/104/adminmenu/orders.php deleted file mode 100644 index 99603ed..0000000 --- a/version/104/adminmenu/orders.php +++ /dev/null @@ -1,154 +0,0 @@ - 'danger', 'text' => 'Keine ID angeben!']; - break; - } - $payment = Payment::getPaymentMollie($_REQUEST['id']); - if (!$payment) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; - break; - } - - $order = JTLMollie::API()->orders->get($_REQUEST['id']); - if ($order->status == OrderStatus::STATUS_CANCELED) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung bereits storniert']; - 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; - break; - - case 'cancel': - if (!array_key_exists('id', $_REQUEST)) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; - break; - } - $payment = Payment::getPaymentMollie($_REQUEST['id']); - if (!$payment) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; - break; - } - $order = JTLMollie::API()->orders->get($_REQUEST['id']); - if ($order->status == OrderStatus::STATUS_CANCELED) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung bereits storniert']; - 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; - break; - - case 'capture': - if (!array_key_exists('id', $_REQUEST)) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; - break; - } - $payment = Payment::getPaymentMollie($_REQUEST['id']); - if (!$payment) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; - break; - } - $order = JTLMollie::API()->orders->get($_REQUEST['id']); - if ($order->status !== OrderStatus::STATUS_AUTHORIZED && $order->status !== OrderStatus::STATUS_SHIPPING) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Nur autorisierte Zahlungen können erfasst werden!']; - break; - } - - $oBestellung = new Bestellung($payment->kBestellung, true); - if (!$oBestellung->kBestellung) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung konnte nicht geladen werden!']; - break; - } - - $logData = '#' . $payment->kBestellung . '$' . $payment->kID . "§" . $oBestellung->cBestellNr; - - $options = ['lines' => []]; - if ($oBestellung->cTracking) { - $tracking = new stdClass(); - $tracking->carrier = $oBestellung->cVersandartName; - $tracking->url = $oBestellung->cTrackingURL; - $tracking->code = $oBestellung->cTracking; - $options['tracking'] = $tracking; - } - - // CAPTURE ALL - $shipment = JTLMollie::API()->shipments->createFor($order, $options); - $ordersMsgs[] = (object)['type' => 'success', 'text' => 'Zahlung wurde erfolgreich erfasst!']; - Mollie::JTLMollie()->doLog('Shipment created
' . print_r(['options' => $options, 'shipment' => $shipment], 1) . '
', $logData); - goto order; - - case 'order': - order: - if (!array_key_exists('id', $_REQUEST)) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; - 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", [ - ':kBestellung' => '%#' . ($payment->kBestellung ?: '##') . '%', - ':cBestellNr' => '%§' . ($payment->cOrderNumber ?: '§§') . '%', - ':MollieID' => '%$' . ($payment->kID ?: '$$') . '%', - ], 2); - - Shop::Smarty()->assign('payment', $payment) - ->assign('oBestellung', $oBestellung) - ->assign('order', $order) - ->assign('logs', $logs) - ->assign('ordersMsgs', $ordersMsgs); - Shop::Smarty()->display($oPlugin->cAdminmenuPfad . '/tpl/order.tpl'); - return; - } - } - - - $payments = Shop::DB()->executeQueryPrepared("SELECT * FROM xplugin_ws_mollie_payments WHERE kBestellung IS NOT NULL AND cStatus != 'created'", [], 2); - foreach ($payments as $i => $payment) { - $payments[$i]->oBestellung = new Bestellung($payment->kBestellung, false); - } - - Shop::Smarty()->assign('payments', $payments) - ->assign('ordersMsgs', $ordersMsgs) - ->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/104/adminmenu/paymentmethods.php b/version/104/adminmenu/paymentmethods.php deleted file mode 100644 index 5a36d27..0000000 --- a/version/104/adminmenu/paymentmethods.php +++ /dev/null @@ -1,59 +0,0 @@ -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', 'resource' => 'orders']; - if ($amount && $currency && $locale) { - $params['amount'] = ['value' => number_format($amount, 2, '.', ''), 'currency' => $currency]; - $params['locale'] = $locale; - if ($active) { - $params['includeWallets'] = 'applepay'; - } - } - - 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/104/adminmenu/tpl/info.tpl b/version/104/adminmenu/tpl/info.tpl deleted file mode 100644 index da2a55a..0000000 --- a/version/104/adminmenu/tpl/info.tpl +++ /dev/null @@ -1,93 +0,0 @@ -
-
-
- - - -
-
- - - -
- - {if isset($update)} -
- -
-

Update auf Version {$update->version} verfügbar!

-
-
-
-
Version:
-
{$update->version}
-
-
-
Erschienen:
-
{$update->create_date}
-
-
-
Changelog:
-
- -
-
- -
-
- -
-
-
- {else} -
- - - -
- {/if} - -
-
-
- - - -
-
- - - -
- -
-
-
- - - -
-
- - - -
-
- - - -
-
-
diff --git a/version/104/adminmenu/tpl/mollie-account-erstellen.png b/version/104/adminmenu/tpl/mollie-account-erstellen.png deleted file mode 100644 index fc1819255ef725fa214cf2bf028cf3428794ecee..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 38998 zcmaHScOYEP*Y_^M3StQ%QFa#*T@cZCSv^`p^cKDM&gvUIY={;uM2KiX^p+?=2+=#y zd$(9+y}r-$`#tab$NPKckDa-5&pC7EoO92;GxOQ#=jw_Sw;$XF000!qN^+V203j3r zAkYI5-t?4yc1PY+_dVtHJhfb`J$=mFtpGBXF6LHHWhXNmD@`jiOFy?BE6E!!cDt8) zo_cDk;ubDWd}ja9@cBBq-f#l|k_cZ{GYbbRPpG+-jh(X;%U)wE3)Ie1ibYpg?XjAx ztd*^ulE1r^mcRN-3x5X-F-sN%94hH6ej~ui%F_($>*VO{A?_>1@?UbrZ`%KK^Rqzz zi^S7GisiqR(o=g5m348qf(r9J<+TuaA`BG~;}du)^h8XI2P*hjK$QQnD8GOZufS9B zCy&Ji1)={cEH|UMTUv{2$|?M7teYz-7F$nGS8;xRA0Hn+A0a*$cN=~IF)=az$AbKV zg1k2rydHkeo@Tzh&K|7)mLO;4Vc~A)>S^cV4E;x+JC_ zGu;@B-`C8QUx4rNKU4ZQp_*kC%R~R{WY)9xh()7B`Nw zX8mUF|Q_m?g%j{mmeb6Xcr7Y|z(SE#J)KUNcia_HJQTe|poaQ+vMnwq$> zvxlddvxSwioD|EA6h1pUOK}+mc{u_3r$|Bh$4CJIc`>A*jEF2!Oh!)hvApaPA(4Oc z%DGs0IaxV-{+rkG|MJTIN8W$J!O8VzWH~E$J8vsX1$P%G=zmRH-0nZ?BK9BU{fpP~ zKkFj%A9?w2l;Qu!x&M!||J`*HLH{)WCv-)tB-y z0|eF|rmj9_o0*wWGP8{Vk&}~?`0mdIg}7_q><9NwuiqM8JJtZ>@s}k%0N?9t4dAsi z=V=BbVM;_~bo9pN=4Jn%@%7{4KbNZn3_w-KzOkb(!|evi@>k2lmdV8cqq63f7EI5% zvHqFl*Ve70i<6TRZH<_#jkV;y8X^Jd<(<>Kyu7Q))kkmez+C)owU39V^H-J+dRC*# zW;M=Qskq$hGCn_aZ8;&5(F-l^teoh++&(zDxO!C7dvtPX>LZTF9%wTg(AjdMOGT@krWO5A0v>0eNZ`S~Ef7ft>unGO;gTO}3P z%=_{cK;nII=ijSSoTP(X&#zxQ`+IXL@7^`e(QADYvGA;@`sQ0?GtFhkVOs3%7kGMc zm|5GO1@~Hb=9`wDzUuN`Lgcilq!g@{_d}Oq`Bg5xf$z^Sx{I4~eN!&3|GRZlUtgd@ z&Ph$ao}ZuJB&M5tF9}P90e~cNWjUFbzEj&-Z-R%%a3|59ewob;6&#TjPZK?=-ZXne z7Ge58Q*->50P_7?M+e*QCNYY}IwEGDDhVhnu;qwTvBVPA4Myb}+S}VLa9(9cef}}r zW=r{z|Bn$84w@MLD*}QrBn-+y^WW8o%bh6aEy;w-c*Z5{Oupb4%}^fxF<@ z$EqytqOHZD78ByF{Hh{M&BV6{jzEEiYiHWcDHiKLRsQ$|>8n-@4UmBe6hA(n;l5YA zzg7Rv)c^hp%L`l+eXi%XWX+;apO?pv8rBGtf1O`tuK#h-(b3@&Az9N7BBiI~#-W08 z^K!-oj#K&Hgia9`o%ee9o4>6b;n?2ZrlIE60ZNk(f8KTK--d*o*u=+#d-z_q)zjIS z^72C<5PtsF_q+uB(ZRZ|Q>6yFLs9vTiei*GhgeF zWaJ`Q*XMk#^gcv(9;=<6+-QCU2&E4IfpO7q_zeqsa zRsNz?K{eJJhox7)7j@du>qH4FOY>slCfU5~Omd!Dx|Q!GJ@b`?AKDFZGNZ{=?y*Ft z&PH;36veWBTGe4@H}v<4QMASrDq?XoGHe@)(eE2iJGU3=%F}ddI(WZFo&ij08 zXe5eS?;*%zFzie>1Vpf&VgG*3wA~nequ_?~G2z{Nh$63=9gHwh<`vdQ9s^$^eT?E? zE47i%{JxaW`EbmBu8qaMetAWhusWQa&*?aSF;N^)Z%N2UQ=Bz>+B`LDr)pf%6hePK z_hZtke9YO2UEd$LIk_~C^ODS17wGfWU_SrkMg0c$4m4^hXR35qw&icNYcA~}k|e3n znlpd`KWBe|^psj#Bg|8R4etH2yaRga!!jRagc#4kr%yJK$_}=_eRPqA!$9V<9kWKnkt(qm`w5SBvI7v{U|o2C=4ak z62^I34Gwt{!Dcz?<$U=SlwPSWA?iY&N;W^-eLq1cv3WN}cmx-8lguPE{EtMtH#+m`>2ci;n$+ zgz`O&tr2;wt_m>+VgzC~rCssFF3=0a*j-njAXn556Wnf@@m@*^3 zm-Gzdrx`1p^UO+cV~6wH>b~0c=fT+^nEyM34Qcv5uI%ESQ{cXo~%nU)&@xU{ySt`&8aN5*Pi~!!ZO7R%Gw&AHhOCA*7yC9VClL83#UNqRmV5uTODa3lu}P2 zN#a;nIHSU@7My+83wic@XJcLMv%L1cDvMyW)_7MG zB*|Jo!pz8a+vCD?hfdXF%M}5Zi_#ML*@RIF4ni?PEt@RpsZiuVO!=Oc67=``61AJ) zy)ayHm(_^CxZ&t?z_WV;Fm;}nf=714szADB(=B0EEg$jLBw%FE{=o(Wapi$T%NY^0uYR-))35S`ex5J%mU zPsjE9z`nE|pLuxDg$O!7pi>sbas;OOvk`lAd`_tIm3bM{Al$}K z|GflE#jnvbRGf;^_nhIcX4%;f$d2+;8`B3ccy`=Q!Ce_!l6MuE{`3%Y>ba@T{xNRXa zDs$=YpA419eATno1{hRwf^ZL4!odVlGzFVi@Sq@J@03p@IOv;IIW=m5&7xI1tK3P) zY=hu{pONbokm$V2&4gU^%p1gWqZm$sLMdEp(gnbk?FAR;ji!40I@(b&{Y z_~=|G%KmMCV(J^Ngeu%!3Ga;}MgySj7q4XT2i2%+JkgSD7{2M1d;&k>mcE&#MIk~A zmUJjU49h(682XW)uCB}D0nb4&Wd(Fjxx-~;mA6}(&wD{|4%jdb!*LBnIr8q5?e3AB4#_9K-}M?;t}9+*pFdx>}ETN=k-}50;Pr)f<_R zNb-Obrt{@i9%%}X@)Z4&?D{de47`QS(=p_F0ti9k&o2t`PkIkw=kV9OUyH^eHX($zYHxAhnjN9U&NRcCxJksS?!t|26qSe|#SB)%&%OiR9Y%~7 zcVS`T3rm7@nCdDuO`7vjWPAPZ&MU(tQEb|kN=mFXcGU6U^+0q7E794yG3lZVX)ea- zZNmdJShGw1?Ckx>;jbZO&f*u4p?F!)K#s16l1X)iRt!IEv^mBP&Xm6was$j8gr!bCx;_5{WBw#^RHdcd?84s z)~{OozF6O8br8g6#MOhPJLt!k@8T0%jWU*jsKPP^N{f@$&DJz2lNKV%c{)dMv}_bD zq6|c|uyn9QGEa?E%Enf!a#u#U*N!CH8;k9pfwK`VJb|PO7DaucCrrq01v8dHcsc?y zP;_yTim7;UbpPu**-7t_-%#&Wxc{7}+Q0yR8riokmJL)T2DZ03i0)Xj;3~vFehS&! z6Bh~3+DCU_=uvvVml>tUc=*m0YsX@Do#v*Fgi|x+#j*5wl-~(0?%<2PPO38WK#U5h zlz+V*jRQzCBLb(cYQ~z8fuM)zSA)FDvLGITEb*0g-R)X$_-nL%k5;t`2zQaHVt7{+ z8x$-KU$oQ@J%DfuCb1|NI@SU=#=OO~ax~tKd1~f*H5lji2hP2J>HwFDVv$QYhP*(_ zof^gMLmFQP`Sqla5IJisXy&?{@R!Cfjd;nr8yx^JYK+Y+mgesVFu| zC7K?gaI4YyU zE#Ft)y%VfG2jzJ}FoI!oxJ+j}!)e>cX9@8oVloy!>7HIB^o6Z-9&r{UYqNVYej?#n zE)VRAf6`HxdCrEvluNPdSY_=fqBMy(%8jhekp)avy6QELd@x~(tJj~!_7T&lgNj-! zxeG)?`u;pv-kj?@pTwJ`t2H#61Ug-Dd_zi)6CSnSY9>jee1J4b>tsQZD3_`8^TIwW8(cL3}b`<-->JzIT>DyR~mC{m;ilP3zqUtUvY2pSWL9m6V z`SZ)2375ZBT-VLi*V{% zl~q+zr{r&vc(FuM+b0OK#14^3j2qnIUM$)*o*jJiNAY6ee98(4O#yB|b_N{FOi#3J zcKn*pWdxQVH^_v`reQhajc|gcIzcat;3g+B)kdJ3wS|Zw5lZBk7K0ElK!@vZR<)wV_8Mk}mKzuVeLI_vea zmWQ8UwZsogz9(rR6r=*{WG#1^Hk_u4iDH7pb2O-!5AC=&><#XqOM)u`-&fWa=@GL# zBE_zr*#5cs5JvB#lw=s4v44mhynHNtM%gV%1-T1P?0vd;F23H*=>EauVsZ~q>Ae-T zpPO2oPwg9A^&BofG4Io^JRLg^X05ERtDi_N!#vwQeHJ4shh#(TJ_q!`iwQA(&wy+~|1+@I}Aq0~{bSnz-tt-#&p$=B{(_+&KvqtOG<0MnJ&B2;6cK2)SFW@j4Pj1_dbO{3NFqh~hQ%N-S$>ZGOyyUS}6- z8H3315F#CXPsjN8=!z9>9BLIp-r4k{q-ttZ7n0>9JgX2Yx`+@-vY9#n2At!3NBs#5 zIxl&?`twnaT3)EF!4O11+sgz1#S2T!|vKbp9sF+!Ejv=pIP<-i$k&{Ki-D^MLrH@W{Wl{s{tLWS8yGb3jcQ#;OIzOfx+SHCEJRKNIu(tl5KF_jz zOvvgn-XWIqB9L|p|3VKQ)cF#_8*V|jY>CWpe(-CFic*Ar@XT$A3bvfVa42$(KgwyW zrL!|m@gB0T_BVKi{7}Y4jFuppCG7UDs&_&YQm0rP@QMS8FnXcEhqO`m_9?&07)9Mx z(e&Uh7-#}{lmrRUZks2T$#y?pXDEs+csr2q!pGw{{b)w@?uv4Da;}H-{Z?TuDWg`DL(aroudhpiIl$bH3U^+Ip!LB+tye<_ZWWh{^7q4(CLQ~jTe(`O zwY^Eha*Jx2&nCZ;0!7ym-o|4&uy{QwjeHY+m3w0cR4ip(L-qIX0hjll6m)jRyk!6VvayB|sCve<1O)%MdaU>c3YWeU!!|iaIc{@e&9|pZc5!jbd~H18 zLEz!fLEbx1#h+&(jD&Z+KPAg|^2lMnu2RFG58+U@#`DWTiU-E<`u(1diaD1IEK0S* z;XK?KE5A8JoH;qQ_RhN#}^P zrS}WwktT;j!B3!dj5-&Jwbs8PX)xII-|fxmLfl7Ohd;H|sAb}97D{#b`&zVq%ZnfJ zX%Iz0!@z-9v1r(L;z8Z-kvfD=m?i&wlLJgP$i45&u+xBF1#c90ggNfp*RlhMF8#g` z09j4VSh_Q_ z_`6ZidFe2(k15UWEBU?s+uwaLGif1zA}|_=ny&yt0yz58{|!-!%9Q|+D$P?fRQ^L+ z)fi_ct6ZPV3_x2Q7s$}{cq3mY=D6;cthklq@KcY<{U1oUP>#KU=ww#4stcs60uUVs z8?R#z6r?=FUq}-b{h6J}&0-3{xNDD;)fv(cgqQ5l!J6NTO}pG|t=Rw+a`iqlmzvJa zb0?{5Qe1yVHk$rAtJcdW)Hz7QbMPdcmsEa^b{)~Q1+|t=GfKCdx02-qV=3fUj>z%_ zw-}1EivxzXQrPhM&BhCLoIw(~qg$JMu@LGl8O4$z%dPfp{5)oYbB?Wu=Kc~9n-Lk>L{ONH&-YdUdR9pSRo~%O@iM!=sk?8xj2Fd>8S6^hB=hbeP z#a(x&bAyu6QSI81BrpNOPO9f2h@D|kCUR-iT!v@e#fg^Ec?bKuZNbFP<=U}T4=$&GvF6ERc3O ztQsT>s()${JoidPe8Y5T{)iw-oEqPmS?tb_jnTnI?XgBDqfk5bNoSbS+dQXm z@5T?hB4)9h(i|5w}imG|J=-Aq#in()lYd4yi8D!V1eUJg?j zziF$aY<47t2?aj|bmh-nQ&;GAOdH^4qj!sW;KYt2dUMDY4al2@Ewid5Faz(I1|E@O z*RD@-kDd%utFC+putZX%Q%8V>u#jg;r_(MD)h<1@Jb!|NOsI%4ZUILIS6?;nL2GWM z_m=m)rT~#{v@wyxzQqP~0&U<{R6LHI%m>+i8&kbEP>f}=sXR8iJR+W?$E!SU|7;!j7ifC^kwl~g zcY7Vmw8$K)98DnCzl!`B{^yp5FW>Uu7>T->g z?)EYPkTOvY?I&!9 z#jkk&zI{th6WKL0L{-a(R1Xf?Yko8zv^6w%b%NMC0FtVGEqTTs6zMZXo(K_pd-)qR z;ae2BzK>`%K6-Ux2fMxt!H8N6;baSJAG*wy{kiS7=DB1&lIE$N znEbSld?GGRs5gLk#&7tE=6&(|m@LyQgL~*F+zP5wAGUVfNEg24Ma~~eCsu!xXXy7y zRgj|RlSgBssA?_6RzG@OryW;aOH1C^O$15`-<6*PIr?U^wlI_6lw0pbnB{~n!un2c3=mcBq*%t(O$F9!K#i#A&ud) z+|rY^zqjH^qJ@g1L%@j^gAFD1_0N6ODWaIgmXty;xNo?}LOG{#l8@5I+6d&{`h_Kk zJxGJ+unQe47DBpy zE?X4JiMBPE8-mG8afbqn;(C_n-CuLigLMPWI_$7^7?=hceJ zg$fFn=r?KWO9~T;GdMagF)+(-V(5=7)Vp6M+4+kFy;Gv}h=#(m=&!dx{q}TixrJQkkDiv*?cRclkOZX_K7Ytxus+BxF|XSJhWP|Os+D| zi7wD9PMt8n_3|B=(3XB>abXpIPWd4` zy|9xjfM6Q0EU$fr9UvQR`xYa~O4RUN4PzH9bbG31Dhu2v{7vZ1#E|$f;`^^yw6vkuNmbIe(p< zuf{DxLWTabUx8e8h>}=JC_9A^sJ2SN&Nt|~`-pSVBR>j7dL|5ue?QhL3gNUfV4AOm zHSzrUEUP2E&u9?<%lc)xs%&V^)$E#d|Fd%w&0XqutzkY-9;M(HI}>!vjT?im+Fp~5 zmzy?vpDJFx=KHe!@Jd#34CN)l2l<-gzCfMc=(tI^;_+qq>WPTpEduPzcC%e=|aMs1Ef7`9AYLqTTC1Gp8%R^FVw91K*{O z(;2rSkWsJ!Qf5H+5eX%8Aa+Zal3A*mst&S7eiJlx5x zq@VCMZCx7NnP)%tb18LJg9dE*=HsB~mwWxf86Fij9Rx&cK`d+LTRr^SN?!3=kG6aW z?uyWDe;V(8%+>HhO4gdWn%w~^Y~;8rdsx=MT8WC9OIVW4(`od&68qzdeGu9{h;`64 zMiQuJjqKj@o=->-30i;sX%;cze@z)YVf>|1o(@E+ZnC3R71Q*lNP%#?;q_iH;u6c<@In-7 za-ExDKY-9Qwy&_$!GJARY>LV8$HR9G*n)o{$YUWRHkWhU9MjHoc_gH;S)caV`h@Y-H6g++g_0O-596bw5<$C^;~o$U73bWga>W-L z`8p~i7?&k}|Kh;hMuZq*=s4K?q^*5y_fAHQV<;u5Dx*(LuqYR?cE5NnI-#;BWj4H8 z!Y8{vtTpJ>80A74*!_|#F+s3hG2jTN7$g<+%hJy}!%}}BMIW(tC#3XiPPZ#;MF^u z1S-!>&Y=SJP4_LkM5j-+;o*wseFDedawwx%I8%{c!LL}~IV$MxMp_b(ojWfLXA$)sWWCuEgSj4)W9uE4Rhm%m|Nz4cC!7Lw-J*d40 zp-dkxafY{20hWJy4ETN4fCL}EJ<-?*Jsxj``{E@ZfD;fRJv49HKYYu6psw^#_?b<% zQQy%a_sL}cLOY8bWl!a5!D_pP(w|5aMqKJslI7ctg;lzHm$BajX3;$lBJ(55HJFiq zvlG-nhQXg&FAt_}WtSNXn}WD^NH+O{s294;jURKYm1-bkM-Fo(Zl2HgXpAG9B0 zJBqggwv2-NQ+fp>DXHbME4Cuzs-HE?=P;md4yl}yyf$lHE{}4q2SYF6AGKJg#sAs<=lAloniu z6rL*2W~aaF)8CP-zwjhD`|yg}n&Jz%kZ-viyT$_FrqA=p5*OGUojtX+N$yfFE?7Vp z!>Jcj4gj!xg;WB9vdjW~^X|Pga?mLGOBlwP)WRU;DIczEGY`yfK3uuAq4V+vfZB!KaJL* z9GxyZ7g+(_kfyE3bvh+JT1Vd2YD85(b}hT%6J)nU>Mqq`;5#kKgSCUReQM;P6jUyt zAJ{=B6G7R8&)h;Nz|qFM2GUUHx(=IL7&!;3H2S&3TylgHljx!hvB?IqpVxpT|9zN-2iE# zGQ|%Vl7|OBx2tx3TeSxS&n28d2nwBlvMiGo4Bq6hmMIg~d$6EjJRJ#T5Ygo4J1>)g z9V~1y3D}Pj8`w360pyC?=D}uV6IOSJ11{>N@7T%%hw?zo@R=~SY35jP!ZpC-=4<5u z7A{c5lW^@zzlty)wR&5Fak3%4E2wD?(=NB+I;Tew-JEhx%}wBEwnj*nz>BAASLA#tX`v~ydQU|NJ{ zAP;=;RQ&#YPS>tiVh;v%_yZ+AFlH(hH=y`|kK2++y9xi01$pkaSs8Ur54!XNW3&Sf zSpO2r1!Nh$vM)GmzKL|odu_bAh}NU4MH4@VVxt+O;GfisZkq&1$t#s}ivy~4FG1)> zS3<%9OPreuqzeB_r5nl>v7UrGatp}vJ)@87iX7cyLpAUSh6)Qk10UwQoqd>{r!zmp zL|@|4&}W_x5AR{EI-Fv}Vf&F@_& zYZhZxYHv;5rex35XLW-KgV9-_9>F$UO zn4slaePqkhCB4dap$;`u*Ier((N`pNw^a*X=4p6?E|?j|pO3fNpN6B)G8;&!1P8nV z%&)0h`M9mGMl}%Ems+Y2>a?>!c=PX952kYxRz~(#*pJtch0NQ(8hb}fUj#GX>F&-k zL|ukbd*?QMv#9$t&cVn8pmBK0=#c8Nv*#oqckQZKMCkq4+{^l%mETrncbt0*&Nso7 zmh}=xVIB5DrS??yE~p;1?v*!hi27a=WaNj@&g%-E@V&&2n<6gv+f9S7irFK@y+HIK zM4W*A#%I3i?Te)Y4s^?di@H!$5l|GD?7Z2eK6R%+*yuTQN_-xPF+!*8&mjW@YvAP3PBcu}82 z`7EltC}SsSH=M-V|C7{i3bDYI*x!TPkEYlDrrRSua$!zkQ4jf<7x1WlO~%4Ib_Ov_ zQra6`8}oR}{w%wPQ$?poMSeEEyi8`hGM<;0TsP?>H9XUOApPS)Y{04e7eDc|6iU+o z5Gl*YYNU>?2%j*$p~_}?9qQ7m=xf!&>Dp5WpnLcA=H|Th?QBx-}>!!dZfi!#v_*fz$D;NL8Kww}QQ?iyuryyQRHh4liQAg9eKy&D(`$Zx;sl98G6L z1_Wr(H=9 zTgOQSa#m($1LSv3g!@KDnLEPqq3i-hrLULBpx50|JY`)%O?K@ZVsC+F~uLK-z z5(~F|*Sivt`~h8)gD~a61bh~`m22M z2vQkzsbE;tiCT8yvh;?j_0}+#8O6D8KB3ueGhlo~EY0Od*9$yQrm2Fx))e=B~ewee>+&t(W&L=P3=Ac!0OU*Gx{oH1C9zI5a z;uzP%;>OhkX1TJi-b!@mvu+XqQm8nn`pca#R9y%d={Y~eFeh9q`!l#i$}squW<{mG zB=r7-kIzYQpm@RT?+V94W-oG+>sk4q7fJmMBF+deTwSw|@3aV>;P%Ty z8+bcLA1>FK8h|zjSTmm(--!)u6(BME0ibR%Cs!<`HwPAm;q(1WZrgmOd^(l96a0%rc zd27Kj`;ct07q`%8{$J4U@}ZOWAkSZ-w|kM|S&Q0UI18nHaT7<6E1a>Q;fn2MPGiCS z2++nfgZN!95F~h_w4wSK2-lOIn+Ihb8tm3RDM>Mt}t^p06|cal}Ku zEA}*rot8h^lfsSjdn7*qvqZsitEy$=VwRW8f}B^Lyu;+UoUo3m{1qj0P06b0+$>Iwk!&Rd`{cHQPwCw8tQNZ={pkeMo*@UpjKL+~0^S@g56KTdbihAQwzhiBZ3|hDm(3HjGk7_bN=&>W$042+gj0 zGf?gH^n`YS5&%@AqH1|#y z%CUvwS!d@L5~0AC6mC6&+UkVo6#UTh++l-OpNpSPub*%Y*}sY?Su->H)%W_L9)WZa z#nU36jt@zzETl$lH+`IYWMHN)l1Q zTYE@klo?m8U*NNQlca04cXHy-eDO4YA1U9z{8^wMd+Q*t-&&DTdiVNfwVRbd(*2d& zTl`AKB+c~gMo?+PWbkj}OWc}iwj?f4B{2Y{l0z4XY4I1x3mX4=XNgCb#dT9-)pMb3 zumKu^0csb;IgQeF8w`^D9@IRLRN?m)zge%apdDSW8kn93H3b;cAk!M=CV-Ycc7@MU zw8j<5+G(uuV1n)ohBj=b=UqlnYj95xRrcaP+gg*KD|_tnL_w>Tf05{0v3(Amgv&LB zguPm~qwb()prm83-g?UDJ65S*;c{KoggySyE*%sit~SEO>)QnYROKanp6esQ-%O?s zmP~P|P1EK32*paiP%5E>q7aI?kC^~u3UVjNMDI7I5v}dN< zaUh}xF!W#Pj%2M7U$AtUX|qb8c#?bP=|+Qd6hZgyr--VTiJLqF->NQxK+wj#Z6?V- z?6uLZJNJ$2O2wC89V4|5M%xM1yX!q{UeK<%Sv$X-w>#xbvS8w4Ho!A}oj}hMW0Ivz z(H^fp4iwl(4P{EmJAUAk4BI*8xWQ7MKtzb|Vb5#;~17|=tWLS4sM zRnMQ_Th+Vz5%WFAp(Dre`Q>GAYf!}*;A3WTz$N_AV%xMvXB>pGNK53k`c?E-t`GC7 zuhpqY?2=`uo{4+}^pFATA5579UG2^`j+ecqEhrNMS{af@txuZJ0xDlvM}~gMkHgk_ zdv}gDK?gTCU&);09ISrE@Ae11s6F2eqjbyk&yk~)N$UBL%}KC4=Oi<5B5&h2*tY1j zC=qq-dr9>M3N9IunIFdo8Q#2RU1S*H_~XKJ$w*AAJDjCjK18yQ?5f^*j&19qB+hSl zk^kC%v1D#AsR|{%N*ws&YG|P8*)(nWbx5lQZ=tg=WA-6PSy;ZS?mjWd_&SCCCB{J> z$YQ{tn*iu2``zH5`ZUal>#Z|3&$u{Md=J$u+)2nbPwwstq*w~tbTr%Avq`KQZV&>1_Lh-HF3A>iv_1c zfE)RFI~BzHwe+ttTyu|dAKz`&sJZeel2GX|`Lrtc$0^|MdS8YcH!zTPV==V2T#?qZ7)dl$;^*VR=<<-%$;!GGuf*L%40+;xiy%Di7{2D2sf|{p$l1F;;Tm5s(p+W-m z>J7T&fE9-3(e~XjU7zvlfD&n(ip2qZxLVJkD>i8GJd8o3}qvd2PC zF3A!^ia(xsJWzU?9C0V2tBWKp<$$FdabG$UtV!ts)zLD$q;Yuoh$29z#DTNE{t+MZ zUi0Zi5{bL=^Sy_0P%cVv@yPop4U#bY%s`}%R7p38MZLl{Yz2TMt+*5T>j-<706AZ8 zjaR}w{t>J98$G^fl5r0_M28`=Nyk$Td&YqPHXj_w+iiJz>qBIP@F$Bbt zTxb*r#$q7ZR7f5b3bd<~(hEJ`*jib|5A$Zsc{ytVi3>*M< zmJlcF&VldOgPp@}g+!?}aD;vSuBb8W&rNrYMZ5J#>1z^&fTW^=-cDElDl5wi{oy!; z65ZO(F1tLO6J?gO9fE~81}w?XvMc-%euxMqsSs~6eFR(HycUWp9xuQ06-I;ip$+Sk zEey7o6Nef#Z@H7RcdvISoBT>F#>|WGI&PXnq{OeDwp`4`JVaw8KJt*wEl!?aeffH? z_$z%|*G_v4)6Z@Rv}6zv5bm937p3GqCT)srSdbx($Zz$U`{8=kksQcM!< zxFwfTg6I99K19Y^XkN!Fcy0e!JZ*9;!nowIaP!Fnb|ZLp6cnw*@n!WjwM)i>T7HZ7 zEp1mse^|>psdbL#gx?hV@XFOtfMB}i4Muq_4m-e@S{bRL zHO{$2nsR!INa||}J5lnhS9YR2YJU9>djf{!c>5hv?AvqOGTpp6y6W08*_7+YPrmlp zySg*c0{sYYt<<;AaW_86f?^l%O7cUxO@I>B65YTN)JAFW)y3E>@WIKXumPPkVvU?^=c||mg zvo~9G!pwV%5M8vRORUouj-tO`lQb>ofIsQVRN~ zqMH@!LJhTcdD$gOfJW2mC;t7}s}6(SLMB>r!@@O`ED2i~=xO5yX|VdOm|TV0b>bv;cEUV)2O<#AFfS*u4G>BoHc}}St<^kL$tTcTXT8@c)Ma~c zr-!h^gZG#1%KZD@E(sdxIbrGUR((onzClz?!aGZe2I-;-g9-8X$k^%UyAvWc?Lf;8 z#a_Np`!TLTXFu%D_f{CE-0^d?_Cr9FAWPe?*YwP`O252z+IRpRoS3htJY9K)kN$YQ zHRErwfynL*3f*B$B#F8GdDra8d7`07pv1n*=eX>hAdy!)EL)ivE5+^R<(VjUT=cspfR6%d@El%*@#T|-kX>o_(4k_-%-HU4}4lNWf z6n87`dU8MSIpZ7eJD%tJ#yI2rI{A}i?X}mQd#%0aoY!1yUTdm9yFN0*Cx$ojgI9XY zEq%jl)FVzT9OA>0nJv|Lso|s;QxwwB^Ee?wPY8Leckg&Jm|R2){YVB~SF+g!LxM}L zE5;;SH*NcHFwlvynQE$HH zFV~g&#?Pr=$As2B04hQ<@!n4tfPFPP9g)fHS`!j)HC2Eg&c-_M!a*D3F&&^Hye>gt#NT8)H=~|-g@~n=5*(iCkx zo)p!ESV1D{PY9qdv5>!sg7USMy5+Kk+0jugj3FR&uWENq(P-f|juKUN6BXbvI406f z>5vvmUlph4Pi|9mQ||!CVH92#`wqmmdyWQ4V>TE5Q*CLg1OALfbg8g2P2p1Ebd*Vc z7$F=g30stf!5xjYCcd6a8{Ck-y!H$aMH6q8uQ?YOL-k@55d3q?G3$e8mi_Blq;5G) z=OWzH*2hWH|I)yFdT%!HpB5Bh>elO2^ZDQHk!X>$Wye4o?Zh@0aiV|DM}v>NY*x}@ zbJJ^mY^tUVN;j=<`*|@f;{B}3eU!-^{w&pA2sTLpI(Z5Z|Km|HE~&uYZq1LCm^M+D zGf?mxQ5?6I|93=_vKh71*RPuokzzk8QMf#n5v9T%j6lMTdHvSuSztkf>MJgR&qR0K zf8|8W_)FAgg2VwdyhJ0HSyHe?5X>r>&iqWTL34O0&yvTE<Dkcp zW!~(>lztB7M_+#l==s}e+)(~dsu{|ndy-KzQFm)g53N+G;`b^IF4TU&XF?Bpv6lH- z0`Tfd(ME8ENyT;MyHNq$!`@gCTel^YGV(CuC=rJ_*8b6XCFq^(dD5YWNU&K{Z&P!k zGPfyVlAR?^_nKJ_jxpG`VR)dL7uBmz(>R+{(v0)G$Vy0aL0=>gBHzr2{rbn#b%pow z;Eh}bn`|E8Ex|wrM{}0F;&EnsV}9v~?`$N~vl*vRo=@SgR%T?7L*wsJy;y}?tgtf$rZEDA8QNs^g7c`pH<%(sx5D~ zjVGgp7IV4OeU|>Zze#^7 zn}*TA6!_WsZWRJS55iav!pIL=B1au@2fTo54@aVEi^G0ggh8wkM*kFF0sIwt-3_K~ zt_uEX77L>G(na9q*%qqF?^x);|J8VaI1JTesM^`6M*mgFEN#P~waeUmfp|15n=mQV z4*RX~=Pg|~KZx6Ei*&^!4}vtyKcjE8%w{*2Uks?oaON#L8`5ngoh{PbX-b!GpMFmU zb1X=D`QYG`XWG?OTkvKPj=nB587D+J9I89|a=N1Ou>FX|U9Q6bzuwNv5tbrL?wK)h zVDn&Voa~NHf4#lJIgwvH8y{BJ+I6{J&NX3U-JQLjCBOpx5i$!qTh4g1rOk|PCNRaf z5p_mDPxuhm=cBxa^;zF-AbDDj3YkT5_|I{&om_E6X2=uq2O;~Higj#Y0c^DKq@Moo zG0|YSqjwlCSrh)TSBA&DfaAdC;xR%EE!WDpe`wW53N|9>D=BLq-HS@ZXT*Z@QNzKY zxRl4|O6*G%I1K!|XsRZNy82>MlsxWPy$nRD`2t{K^O+{E&hx!`;qm7AtS3$T|sPETbJBH zk|Ubh$3|~nd*QZrFgzD1dBD2+K6|rCqgAy`m<#KJ(O0+(^8KJrfiU!T*XoYmmK7#s ziPBNUndYP7eV7vHW^({qr#~}}{yp*{E1?l8Qx$J_cDT(aBE!^dih%hH_9sXBkZCg- zs9GsgY5Z;o-y)giAi*eUPRAQbsntmiMKo}0XFOz`cfUCdL7!yoVe8}kGJk}JoIRV# z_*`ax{iB59m#2_7>9`{dGhM0AiI6?{*r%UW2Qr#UpEBpD7V}%^y|nW#1mr*McpnzT z{}dFLkm9(v$8b{$+ew7M>u(a`VF`cr`z5@@aBjAP4L83zY z-~BbSj3R8ZC+=j@C?Ibrtc6y-8KBd9z(5`ZX-T2 zzL+XN=Mh$DHYX-fpj3QBfbzf4p;_X?{7Qnqylfp|zm>S)0MLmhAXmnj`w-*iQEBWM zn;_ny-PF+Pdp-2^pP-)CzLMM$7aLK~R1i}2s#-UU%MqVx8>R7?VY{M)715K%DXyDR`;>M*##m+!r~v{31gG z?WBYT)@%-EI-cytTZy!|dl4buVk3_&^uM@X2M)M1th7a-u8k3vIVk3_UNAW}-*n^}z_4MCCaNj&;_sC#M!5GCo(F8OnX zYuJ0>s;k}REN7y+=pF2b7-v}6JU;2H{rn~9<#_4( zi0N~?XxrqrpIf@Ir;=62fH6LV^ZHnhd$<}~nFl#4HINsbo_|9c2QTN>pS(*xyr4Fj zTzKU~BF}hSrL1spYj|lCkEhXSw4u{l+-??K=W4^kE`R?}Lp34if8)XVA1LmB3)uc| zO!sd9+yCAM{dbG>uYdpJvj0}3|C22LZ|osGv{&P|Md^8iYMD#!lCaxP`1V7|Dr5;7>a-d-#Ck5=vD zZrANQW*f6szFYO*qU-LB4V%Jfs>~tXb5}F*5U5VmWO;UVpCIQ|gCn~}_i_o#*tlI0@1;lwm#sw3AJhrEbRWa)@4UD>X^l*rCC zc)?v=Aq9W1q z>2p|(a4sn-NW^{rQR6c3$V-__LoUqK!pJ82S{k&4k<1v|f$_VN;kE-4Ao;?kG@fo_ zU(K{bmk@f9`Cci!W}B>p_mf?V$%ovi%3q5wd~|GU8mDds7rA7=a=z@s>3pPtd2+kE z_WtlU-Deg~ohPZ6mV5nK0biJfI!@E}Jml=S_?vWuYP@;yY!UsXF7J)?*71NnZ-SRZ zp(+&DkBx!+#bL-(Xd1hVoWU?SF`I{3E-49mD98?VHI56>Rot<1Hf7G`El3P*6#PV^ zSrGKeGLyZ1J?=IdeH51x?HMgwBuO`p-B16m zu&LvLcN3(C%-+^z4d$2gyM39(q4J1eB5b6-$-sZoDjwYtUr^GvN-FY?s5*OQHW#Pq z9Y&@$&-X1oevf28SA6NZP8}~Qf5~z7&Y2FPffH=f){x&nP)?mrVFHdbh)u_w>K3!j zzVHesX6zc~tai-jlHUT2?Nj1~zhl{e;dn4R7R`mip?RVc@nqaEr={%*H`n|dAB4pd z%E8XW#-vGE$|iDF4$sK~*ZnlLsks!7Q2vI~I~NMT0t*(hIx`wj(?K-i;Zgy@W~kkI zy3Ounea5@DyZu%scK6-}4dJdds3_K|@KQQFT(z>_!Kje=7U=LXMei}Y!{fy?IW~OS zMyByjd{l3>oSYdD^so<$DjL@(+yT%=1CCKqY|qosINUHl2~5b%*FAJ0T%|!g=_;k4 zn{;ml2xbYbZPf0hrP{s{L4{jQ_&ymT>BqFJnj8To*TBKg$X~Ul6|0Z`B}Dx;!>uQ& zpq`UNw%VtyCJM>a^emhAvjLxeZ)H-6TYz_T8QApdOnu zOC>L7+U56NtWE*Og5;iRlp`L^Rn8KCoaBPp4%o3@JrE{T#1nxpfi+To8N>49Ex%`T zFrrNa=J*P*gY$=08`kpu4JI|z;89NmCeU^9!U)~r#<{7tKf=D5z&duM1`+1=6hQyU zFw0f+6%@JqCusl|t^|O~WMJr3?5O+$yq&PjqDaenOK`A3s|!P3p&4&%4?=ulLebaW zFw%k0Vuzzb?LvdzG#6zqJ4+E5-xfp7hrcE;IN+0elu`{}=96V^IafE;G~4E>_Da;U z?Y(ml_sy!8F=OU~db{umI>Np2WHE=scKn|F254P#UQ7$i&}Hxc-Z1Z7V4f`1dm|Bv z3*Kt;w7cv=#T24HSf2a->#o4sD3@-!P4w> zWn-E_?4*BD{#!YOqGt||97m1AYQI7oeACLPG@<)UXcH zxW6$i+agQ9eceX6*6I0f1;k17GsSU}Q$)x{83Wl~@mtUCut}67N0tet?gY{>fd~Gq zj++0d@(pB{r-DL1hT0H6omqmZ;sZV84<@mbrkChzP}KD5mAUXN-~q%{*Na2 zAt-ke1b(V{w@8G-u$^w`=pRXa55eF?=6_1sRQ~bl-=dr#*pW0!`Zkq+75`IXphxwI z`MB?Cyx)n?B;8s+sVoW&Bk4aTa8oG#t|;T7uvp6eC`mTGJ%s||10HC(pHi?z(h64I zDX|7k_O)gi;z|2IU%`5N77h1jLd5EV@Oi|UBnF=qDZ>`CwRb!mS6DsdTc-eA{?%i$S4M_(NNpR-X)#RwJl7g zoOSNK;hTm19ZQ|IIT+TpRS%F6U3q74Vi?<&s}uU-@4WB};+F$THic>RZW^^CvEFFY zw$n%6Pa%hU)4}ww2Qfe=qBwADxw>34*;l&&{5X0P#f3C_Z+qgNoWu)5HPDOb4-BtOn*_ zzu=ih;=Xv^FXn^cmn}8a$Z{80v>}0)a8|rZhUMd@;ufkBi^qN4KO_n-VBS@KK3kvDq^6sl4hfZ&X9C?zEbxN-!6F3Y_7XTR@j1nTof{@em zr6ysaM2he+#6b-e%4Kt79`i1h#(j#1G!FW0qTisGM1e-kTqJzSdGjwVPmCS5Wd_QTcTj98 zD#JA$_xV@t9#)+Xr0=|~@ZNomQ2VAngZSlG`Z>An=|cTZ(vw&640B;(>9}8aw>JoW zcFSqrf3zIHpx-)JaN?$e6-#KDmyx}dS1vTC9I`uaLtGikpvESAasp1$V1^Z$GhOCV zK_M!b;1!47<_OzjZI4c~pllZg zw@j+sZDWpqzwtM6<6q;$7{B}Xd;eYH8Yv?~E<>8fmwP_1s0??!+|IW&MQ%B}RAQ8W z;ZOEeg}8UJ}wyqyqCLE#TpVF0ToPb zN2AaUH6{9Mg9^U3ql3kUG~qpg-8KgKdbbM|XCO7=|6zIkk1+G!nS=j1WBDKO+tq2KrAj*zW2X^M&qCf& zN`YE%#dFhE>Y8$TUMw@3Evel9kn!lad}M$D^q5hn+Yn1kHJPDwZ8D!)q%XT3EXkyU zN~n4l7<2CK4-EO~R%ylu-ARIS@e)Vg5dmmFyCu*#VW0exmry>at2NV6e*yH^0(=$< z7C(Ak_q5?18b;ky5+olA`M^IiOMS^?)r$lwQi=VbxL3x5k8}s^cKg6-U-1XifKDob z$4m? z`N7oc*ccp)N=c_!iZ+em#Bz4gCSZ@(|jDG5R01 z%Qh0?#{Z5f3Qm7s@j{Stm7#1bHFS0aDdJ5dQ{uA1uT5tzmc)SnONF6%hTP(>B@c@@ z+1=;(Ryo;_3i=AoQWaPTaY9SXG|Qkcv2DV5bs4jx>|n!>oOxRpnzt&;V*&{ShpePG zSs;e+j!lm|rg}sZF&bRHuuMbHQhcQHO#%beDrB+jEj8=Zl;-KOU}0~;O0NH zeSP-`J0HYBA4YzBeT+Jp9B;UHjD4xBlD5AP(j|PLPb6Z zgpH;v;pltWuK<6(9C4z3WKWKzXoeS=;$&9{^84>S@mbZ(x?l^jQn{q!pbzRdrR`xH zyb#?{R&U|Bd@A1zQt*F!h zgw9_=*v6DvB?0HD3 zX*UMqcPP&a{YK0ot=t%bS<@VtLBwwni3LVzodU#Tv*(u3w3!4cQ4?wny6m2N41)0{ zz#aTqUJ?0jDn-E-od(bVhUA{Ml!6UQsouHNQk>`F_?!bkrM;kbTFvo6mwl+piIE+; zKfAGBP6%1b%9JQ|j1d_Sel`{#Kn(_nm!(hTY__51Ml7|=n-R?R?fwQB#duH9*FT^K zEqV@syjSe;!(VM;`zHGV5=c7Z#N zk=C%7u3BDVAAh(99h=+W+U$OkK8(3@B()mhJ`$sjn_?sTRo?ae=m?F|@|`^CyzFq+e zY9LLjTX|>e0eIB~#M@9I82kDKVJ1H)Tcg{ZL&+#0A#3Z8_1P*iQ+1qYobT2CfJF1U zk3d=VAH&$mxi|^#k7tP3{pz(IG+f9~l@F?i7Qd>sm}UMbxA~IfhZ62d9IbV&7m@G@ z<`$as+n0iH6>lQwLb}t080hPy|NUTtShg58+WLx{-vfwm9se-+XFLAwiM3 zTV>qUFjr73#62B?T#|d)oX2cn9T&T~o|QYfKF^5`29{9*OPQRqWbYoS? zB-=jUoMlkL<|6MN{~zbu{!h`(fAGqGn_>Gm|Nf)dX(vZ)qmknDCdd58wJ-k*`TX~* zczy+peaPJUy!6?$E$ff-gVwQbN9l~)iyIFVdp0H|o5}MnH{MTpdRv#lJ9#RcRsP>k zg~XSp`F%C2HlDW}6FX-aJyk0|I|T)O8)GKDjOb;(^W@k_Hk59LtBY_-GgE#jP`6=W zy*_U{xP}$f`ie3MoTdMh3Hh_jBhd)d*DWXV#i)3D%LNaWi*K6UAXfTtl98pI&(4b@ zC@2`*6QKcsbn}#YrN6$#%Dzv{TV1B0>il%jJF7K3+~40nJX~cF`AvRx=}Crb*>oZg zEz2L35i}xknbyp&lbTptFmS@mrkt-m2S!@@a23yJ&eiu*mXWepL<^IN<&1=s)~brKY0eQ?G~IE*@Ky86l_CAzRd`8rV(4I!Vdm=R)W>fs zJ|a>O*&CJI%>$p~nmo>fCv&n``plZBJnN}T%8COHAgyODV!Kb%Ve=_s1?(%#$Ihhd z>5`|S|B$IQ?1fF;ZRb{(qopdZm;~{G<@};dHl>OC1af=rH^#)=9`38*<3pqI_$}|+ znZX+8&!x!4t|7-P0=L)3^3tcu)s0N;85<`wq{Ho#>ug!QUb<|OA;R@+3T6;D-|Ecfr1zL{Y3Fu(mED{!OO>}YYAFI{j%TK6$vQm+s^lZL-OPEC zG?y-I&&S`-nQQ=icmll<2xO1kQ*?0x>L6suXDIb76qOe$8xXXO27cb+7V`Z6U!>&% zZnPai;IVUvh!vh}w%Iw>wTCGAxu=gvypm-ct>m*)U=Xt`p9{05xJV(R8G2ZaOOx-l zBbY|R=?3>j(2*FpM9FC9{V~n3xH$1Zt<@bwQ6n{qaOL*Y40~tKnwt8XG;8LdI-V1a z8kTrmQw&6e*l{<<8zSBiwF3nDQT1WbnCTXAoNUSVLH>LhZfMe(o>a=bauU0PM<9Jg zGh*qz!RuO7BD<;T9pm$rW+DUmtQM~`OC<2diZ<64`>8`oP8{bbeFu)*_CJtwDa5NW$5~*qGZ(Sri-h6B>c42h>Dm?sZBUTzH_eSKe6y=1f~ z-2%fz*0+UpAZ(QmD2{%vWhl=0@l`(J+gB7TwQvw=A(WngdZG`))*0txa&^@|b6MoF zn|o6R{f86y6$1^0U)J0kV8mn_rP4{CtBuH11|~9j#yPG+@PZzS~uzl*`Q(8z&%KLtg2 zv8ZwoM0n`S*C2%}@0t4tp?GD>6T%6Xxu5wuI@N3NA)W>%rP{L;Z-te~wUbv;ctDtf zDJLU!9f$mvZSg2nIh925BV>qSea|`r#pOi&LbUJ{#U!sU!pPKfI4U~8{`^T`+nXSL$mPfaIqN!QX_B|+9LxCLa1dD;hpjpj!5tR>| zsFnQBpkjEb>#jXVTNBgfJE)w=z0s~u>bNp{wzk-30^whb6saV{PuS!yI}4{ek?$A2 zOqR&Z7%3_bxO*!|qNucIUZ)anK4XTa7CsT&-T6x-aXyJIyl-@JeRaCouP@2yuzU0T z*mRtIm@5i5+Q^{KSp7H=I0PL{am-38wXEZhzEhx$jk1imV25@rjgM*!~6JK8v zdFSC*rf5%vPdCEF*$=7xy+p zg*Np}ynx@Zf_LVNn#jXdzq059Ep`#r#;99z>Bh-O-!4zkwuP}1CSXMp`86-ZC4N|D zZ-O61r@ZDq%@bKAL{8aB#x$Jk9W-`)ZfO+nhoazGN|p(Vnlc$U-Mar?5Ut#KC%8S# zDQYk`yGq2Z*-Z8&)&U#)%8BgFj|nwX}D~Rv~ol1hy{i_6I>oHd89??U_kqQT_xzt`^f08Ejk5KE6SSXehqXDzs zqHg+RN&l{qBiK7-6Zazol|J++`oVH7sjvS0gBab-uedlFOFJv*m`RDG{4WV49TtDY z*mI?9IQrglHFR5%$NhKy|ulcF3Ke2pnC#E z2V9>Jn+-hPd#!H_>z#!*oj2R)#`@iZ`+4ZDKm5H2noo)af>+i@Yrf@E;1no0P-$>@ zih2!soAD?ph9AxuI&O4fp#9cL5kvwH)Hx8tAImW}{}>tqd< z{Ihd4l z#`4qYF=sv<;f*P|GuZcRFIMU8@FdOpBO7%G_R6_m&~Tq2a~l3Qr=-NUe$CRT_%Es< zB^tRniq#WyhN7MQiIbgiB(*!S5JHisC$innC>C_H#mcGsT}Xhp&^jotnPs^myI@N7 z(mG~p#y)S-XFB;uPt@7D_WpQ|t#Ru0(c(eKOsVt>J= zlRsbNT^y}lge^TlvP3u)A8~*5JIAT)|AE5|+Y?ngGexKsN(A@htKYJcVTMyRico4) z58bzx=Nbj&jx`Y#6+~)#6BDj!g}{I=O1Tyn2q5*ueL<=nP z9}unePjD>r#C{Z-!uCwqq!PU*DbkngBYsW0u+#AFC11=`E^+fCUG~W$tH$s!OH$hI-uhH)nHa+a_-~ zhw0e2diw|FZydayX$%Y~SIw!H`ia?&Kk&^{y}_+xjTN%saNMhk^DxU<&&A9v?_%OV zx-WYll=)&yb|B*JfI;b=C?;K3A3F`WV5j}+tch54$a5g-Dxmwx&>ZsQsMdMO8=l~~ zB{zcgd26%_L8?gcv`|jHERgH%xW*qIC_l~f&RUQf1q{R!kWq=@`1V{n&ZXtAu5i4q zEE*`NX|ubz9xIH{Mw}yB8}Em)9s6dK`Jf-k+TY5Q*yd-Up-xVr;Rb4DjX=oc?uSpP z6j~7_XQp8d0-Nx9ZmOkdLgMwchm?x9BP|p9b3DOu>KjcV zQk>9Md}xmPD&jL ziejY+dY;$KEkbp7+D50QQB&U5Vk+|1MOWc8?caxg8^&NZXan;3rO zFl1nu`*5|_d1C!j5w3QS!mM9pEs~pmF;qfo60qhW3|29_tekfEp^R7ctIw(I1%2ej z`s(+gu=j7_5z*%+)yX0L65N!Iyn?%5VjrJqWD0$h6W5Vc)@rw@eD?!HgS%7tR7{KQ z@Tl9YG4bi29or9B&?GKSOsdK!x`NG`vgQFg%WkvgVP?ocr9Pp$Yu=+*6Y~FXor4VT z%1Ok{2&U&Bs5uEpm_;{TNut+WTMbgluT}Xy1o48Ze>Txkhts%J3)n+WIvw%AZPie| z%BU8xwDDT@4-DTk|B`fdCcKyI8aoJ+m9$ZSg}~80=T*Lu&*f?`eA){oWe5{Od2Tzb z={V?@Ms^1175(`NKss_}8IF07!FMc%pdtzNnq~%7EZdy4Dh}-+g+R-xXhV(0=zKJ` zStu5rjyp4e{_C{32%I}wY}r#xvB7osyyHdq6y>$#iah67J4N}#D~Z+vP1ce8+d4i4 zxURb;5w|DvimCl$*ZhFzDhAGH@m!=8;ixfs*~!&%{z8LGStAp^EXLC+n2Ho3+s~4f z%o`$h`LX3x2(1d%nhA_nSPYa=UJhUu{~}Mc)TTRY4OZ@N9>jcPDGJC>kPr#Ks9O9nJ*;L=k z-=JkB4mR?SV)KC^2$JFx0P$hf9GOH)71q3j$I112(X z9%rIMWk0M;4uzan(y%|iLieE_S*zD;v0ttQ46f3OpA|i&|4`42_9{0r=!_cs3+JW* z7xrH7xze6A0B+GArI!dIbgIzgcvjqKBbfR_sccI86MR_5iPm0qMqU-eQQ%axX!(1Q z>8rcYiJ7A3I~#ue^~{s+#*zT&?!m0)8&^Wz~NY5@Q(zQxPsK>TAl z#Al1gZ~grtKZvEfyWTTD;Z85Is*@MO34=^Iv_76Tx zl#N&le)QB~U`q=2Zo02+`_<1q?jH(*O_QAw?`X4CyM9fwePZue0Rtpllf~sV3pl+t zp_W%Rl0T*1{jtMK0!;_@avTi?aWDLmA@mYre;qm(yWvB>-g`0-DeC*s+@6(PQ$Exm z7#J8IVGDidrHKb_#8|)_&}?oi7zTd6*7gpMK>&zPkCNj+wm?51d9ip)1O4;Vw-l>V z+oskV*{wbF2^jG?6P)Omcm~*^nybez_pmrZkC?YDgLi(Ezss<>v4bakq{&n)V!86q z6WtFw0ur^SKnMxT^wz3jraG9>=8Bi6A#bSJUV1M?zhV(3ho;=35t#UA!q|{{xcTJG zp|&mwbo|J*GzrA7%FiJXNGf{Q%|*$?g!ah^H?}mrbwZy~mFZ0G`{ZxW$=2V`42DR7 zzllB8n&^lIQodqS4pCNO{8SSY2yvi@{Dew!Sl6-{J9osPbZPRk0+N7E)=06C1op&4 z3)-kRtz^KxCm*mRsi|6`emEv(zPOSu6@M#~{%pJFzk>%GQ0tD(Yv(2v5{-&4d~% zIH|%lyA6d7Q-~M}QR*5LTA&vUP!NOU@`Y;zYi}>|XWR!OAP(8dgy5&FCZzJp!7a)z zVI5Z|dD`4C@N6U)n5uPDas8@8bfm{K(c_smk(h7}8@BjF&}2Z*&+V5|v}TGQvfa^v zPZRdK+*u7{uoR;SjGmG~-a=vUu0V(gG+rELCX2-QG&i+VLSI-?nnZx2FAqKjge_ll zdCEetpn|WQ8)WI86=P6MPuR3q=4Oo6%aQr!)b|1N3kV4YSh$QaDim1zz6A`7Gl;{e zj)7u_yE_lu^&EsDRQrdbS7_|;+rQZEIwT}*;f`o%aU&B6*HS_~LbExwDnpMqd$FY# zMj(1(Neu3fz+7g7R3(?&ySCduw3JH-#3JC$_h-)xa80zQS}hRCHyQ}SZ8ypyB=-Ux z?PVxh*jpM9OrR0iQ~F(eOHS>jc=3y7K?qcU8p1{PUZ2dmqW&rT4KuVEmZO3@pOU2& zHKXN1j_W9ZY1GoeQ)i!o8|h(bj}i7QU|Gi};tl%mZ(nh|)v3_PT3Zu`{4kKKq=i3* zY0^dSV}Fq(Ks^kd_nsmUB7}wC-ZQiG1xPA%5qu<#sf~r?L~fwdlYjqd`=0)j9~0x) zuzFu;-t1A*AQo9_Eiotg2A7~Q$NEz5cdjHXnny)k@kqDEXHTu}D1*QuZulyui9Nlm zptzjw5;Q2QiD0wmePO|iny1?k-r1opEeaO#LZ?hT@W9S*22ZVMc{*zgu}V`P&8wC7 zHJJSCfLdh_ZNmi_xeFs90PYEhqI{#D#L0>J&%PO!bf5wO7_1m{cNG|p0fzjdxjLXF zOJex|gQ3$>qG^Mrdgj%hi_y})f4iK|aaA9U7Umo!XWW|zI!Ne{a@uUVf>s9Qb=8K) zYm}S+wxz%V^-P4YJ4)UB^wfn8)68&dSWS5nP)Un{r4)1@I8Yr1~#+{UFfz^A=ZESVqw zlNyuJ?07Fv8y6S%zLiQ5+*aTa$HK+v;V`lCUWL6HL$~JnADuGmkhx+8+w*i!_SxTq zzm6Fhy6jXP)WWLA*UtoGKlHl{Hf0F(ddACpjNG@-j|3{PJF$Zcv#9_yDHuSK+K)i) zw|B>;UNN{~GF189%`3dTMt+xSw^f0=7cwKE! ze7)4dVC4jM!c~eVGNBsj9cnyeyn5KJFOXIP3IS#k8|uipL_0TxCTk_QO3eA8ScL^e z3K?YU0%jttVi0SSNplE48SS?X3C+kU zqGzWuiN#JXAEaw7DmNHd#&y|`YCP@cJN>AC_Osr3z%*_q?(g}b(%i#2^6*v`7ERJC zZRz7RWp_hL1x9QZ#l9G$F+!PWpfJ1f%ct5A(4Y9a9%82?M3n;6ZBK{Utx$?rihf~* zQF^hFPEmEG`<>-VyH=hV~-vJRNiUWWF2FL6ziAWM~768@E|hOLmho29N|8 zFHF3OP9v_0lQsZ>YZL~2PWKPdo|bV^z4Lj9Eg~!~Vt9_CA?K#GO(jl)&|N)a$iLs6 zTI;W>CdVByqTUR~H2Y;^_?3Xo3S=US4CAK$%o_xkYg%9oN@^-C}Rd&TCHR0uYWJX)fOadK&Q&^o7A&gI{oT~G?rej(ARI@ig+r75j(@-2-p zY}q1sMvQkFJik8~Mckxo^GdU+ByZKM+wfwV$Y7dqHDRa7bddN1KXoflJapNNp{m_x zbzSN zalXVB)?vfbx8!inY65ufiBgNE%{UoWO!ZrCl8VH)|57`;>y*5&E-zATaUlAkYoO-P zn|5cKpjJD=*`61%+4!gi8z3G;g0UPC`B$hPQiMf0&A$bu}pW zJ$zp~r5bI5A0@-CY1DnqXp=cAQ%Uo2*iq8c`X<8_{=oNK_T(4iy) z*-4y(#DJQS7bUxYT>G(c$>JuiOPsO0_q3$!LN8YHNu3R9#6!Nd`!(1Gwj8&lAYxD`7~R`l(}XW z>`aHpO*fx;LWSvK_~z_=3IST}T^X)gz>Q!6x@pJLc6W@8)5&BKFf9OFG6E-hMJ zTpPyXLIU;F$;3a|th&+upm!eg5QNjQpXYj4k(vxvtd{^n6_K3;S6e7^1kGOi?-gjmNW;*k{ zrwSylapKSsp%}eyLMIsZcVg*xox0ha_IuaQ$s|717M{JS?z`pCsc7m_k{K}ycIVT6!|al?YpgEFGMXc1tBDEI)qHOZ zwd7P9inZUC)edQ9v*|0lU}dGmz8Rji+JC%U8oQZ`O|cDt^H$J1U1Q zG-vI_N0H~$1Yr7|G2IH4vgpE<0MEzO%(djBiRy^k2rko;KGKKK6UKVqna zJZ~@l=8efdCHl@l9}GKt*+-?DK-Zf|Q-@K#Y(Lj+%kra{O=~-p@M78^ z=YH?V;OjmwPh)a$;y$Lmz<@<7WuP37J_lPDSIlQq)|&6;A#d8G`JZT!QdCSCS2^UM z_Wql7nSbr)`8dw-?s$EWF^fqVktpBC>i`MhkKM7?yJ=u`sd-xX`wvbryp&JSRZp=t z?45YVJv24+JS{KL-`c2g=Tv-fyVGiWP&@D4XnWvS626#%S?c%0)+{KXQJB+mL2$&K zzw>i!t>@ z4GS0N{J)OOh*q|<3VNA*#P#JU^IC1rD=%yQ5audrb=Hq8eC(`HDw@@M26iBau^|G+%kMoHwx8q9!auzx?rynO*C?y=3deKO_+KYVh(szz!zhz+Q`y zC_i$cAg4LXAXEU8chYM4aS$Ajtdgv$zL)rfY@N}xYQ2YVK0|~V`5IqW9}@cORcSnD z#h540HZ7i#ec3;?weORP`<-|iX4&LSvfu6BDjZ1dAFnWU zh#)mqw^5Vjdj3w%-ab^VtSmUOKpAOTqePg@)W2a7bMJ|Tl2ka!i`#iS zOQLS_=CUag61A-ggC(lHMUklM#8;=-g0EoWpRhC@r5vE*b~kss;bDaI>$QjGI~N6* zQkUL*uc&1s37Mcva}9Mw3(r?aPIYkUJ%|>6=$3UyP*hV}T7txX&$wl&CLfK}oH`ge zYjc*N8BX&M-D~8QFz&}XLsAImtLe0Md7=x9UWD-Y7Fe5zAR&K~P`A{aLO2lu zHr3G%`CYcFp*r?(cL~{c`+oC@R^+G}Uk_~uH4uIg*8uT{{T)>H;fEjvhN7o;Cn`T4 zO-@!o>w32j5bmIk1VOzHO~Uo2oB5}Do{gXRQB>i5@+I$0Trkn35s{zw@5CEuQ1v+j?S0o2O;6=yO)-7K-^#(Asml-vb79g5 z`SWJ&&?}~%lF?8zEElj*i989^^}|T4J%Hbdh`gv1C(tx(7b(nazi}XD|A0L zL({0XdvR6ytCN_;CCWV0%NlZ4b$4QXS$jvks{G|vYqxP`>%l|^#Wyepso?YfzXIJ5 zBJca3_Nzy&sqXzTKa`KG*nr%Y5JsO95Bp&eLPS+3gXnWHAa@tGdln4=0U;c#-|%bN zMfD{jeQqaYa2>+vb0XB|4jt0_U5pFNm&gI3eE8AlEFqI#I^-+)KtjmCggEqv2OlOO zBBhRcBX!a1It-@_b5;ZBbIn_S2$Z_vi;#aZNnam)IHJ9}FG8I9{Fg2sd<&9KcV=f9 zKukis_{g?D4Cn7ayEh7F(Ca2ZZHArq3BdCYl2gV$&ZWj=lLn z9nu-l%d+W@J(>RS70be0$X0iP33f`wgV}62MF!x*rPTdIdwuJ3yHf8ALWonJGkkCW zLAkHZHfI??C?Rqa;$NTJlsYr^#D`MH`b59_gRj&($9<-F8XfpJ@T<@5vNwAa4n&pE7NS-D+EJ7?m z_&P+?{{bGnOrJZHI`i5)=D+{LFCR`qntehzfSBT??(Za}Qbm}+fuYpVwc z-t$06M#2ZHKZ;`gfhCJVr7qu_?p2qA;(55H9>x7X)> zt4_ip-3W%`Tc#EX`;K1;mAY5eiA|pyzWFefI`OB}?e!%|2Olm#rp?w`HL%la!uNFn zL9Zz$CS69?df+7Ke@4{;4J5$JOcAPZgl5%|x| zLJMB7dw^ijNT}3Z^(B0Lp4m9d)f0(&?oFQ`-%8zAeTgqZh)IYGkip|u@~V@Lm;E4Q zAU^z8oeZweeOH}?!)QUii-r_7ezoVH4_7Qp(m~~~zC=Wb<|meg`lBPz=Wak2tmQ|* z2OL^;GQ>ot_|+xY|G`376zcPhH;G!ZSWLzWxigj!n^G4LVyiFF2I9k2b<)8uTvx-? z$jIRV88CijC#2(LL&)v)`Jh!NHaj0Bfd85d5S;_@L$QaUVM5R{DHE zLLBj{X%`=MKukU~%7y~uS8xJr#}Rz_2Laaus$C!mh~0> z6(=9USL%-VRsI+E;puaW4LZ~CKyzy!Q`Evh=H z&2W|$4$8;!dabrDQ|ip%cgn|H`@na7$;-;KXU{4x-Gn%lx(yMWbKShP{_r2m@)^H+ z|KY=XpE|@f_&plhVlefs&j(WK&nIuG&xK0eUCLW!;#X9k%K_=>bCZv6DPcqD>21A# z_v&hE2cXDUaAY2?)oVqM{*SIJwZk?erUN}M%O1Y=fdd)C^ zkYz#D33;B_WwRf1yAz|{{T~({&pv;?ckkZk&(A6&Ql$`^I3+z&L-5|BVPHv5=^_#U^y`>ud;#aTV6goJ1L``<* zp=_MlVp&XrwKR6!8;Ny#Iy08+>kqy@KR;YwKX>v$2@xrEqxrGDyKA{umBaR#A1Bri4-eZDA4iF8 zijPEpyzJva5vfQj7pWCNMkpq;gyln`&m)of(b0p^(Rn4}S#^Sl;0&K2oQN{NVjC2+ z=fMa3&JsdcM@_Sal;Dh#lx@6E=XQKJt4>gSCMP$ahoURVtxpxYz5NHh)<$}Kr1Di%_RQUvA?23pT9dU z>>L-3Ms8zcW5>LE(}{j4%ibSCe;3jzC6mdL>7YpS=jRC(pF>h=toQVX<^}|Hi0v9z z8s5K6bb{=&=45<4yJtV2UrPEzC<(6jXqH;chq5w?(}gOPiG#iQaWAD#jS=aT;h-E~ zuc3+g==E>uG8@8DNJ!bd2GML|igV6J8Tdb^*PsjN_D@0 zQ-8uib4Hf5>cr%tdzh^v9RF(5_|t~Sl0Pp?cv}hi06?f`rKQue9XB6+K#&mP*u7!j zxh?7c$eiVl(G^P?u^sflUT@UX8trNC`&gDz_qqnJemB8re=OErUO(>hv0iJeJNiSU zm+;`D^4SH*y=Sgi)~w+*X?I@C$Jn@0OGx;zb;qyx zB82;Npnv6#U!jJ_aTTWRz`1d$aybKUxcFcIk#9_(d^E)I-9T?pDW=#n8}Dj_ZjL_7oXH4rT_efU=QSoD z*Gw!gpIdws0gc3{Q>h=%dR$|)ElG8_4T#%>e5rht6N32*5g(I}E0vQ;11Ezj^9Svb zk;jt)LWq2$2vOd9=nvaWQ~@FKr3?c9DrD_Mpd;fbEb&k%$P0BjZHW8#xZL9E^G%#q z*&F?{X&5p@u(nq^iCV(Px7Bn%O7G%>1>|mCI`W!mwVbH`W8+Q2x=N`)Wyi)l^ntV( zYe6U>$Fe&MH4Z0#zGK_VP`H17-0AZHUu)XZA>e*Vw=x*b2?-xBIR?aSLU3Y`^cmR` z+YjL5k+Bl_{pilo@1G*6$3Td{hDfKigN^d!V^4|9Uq}i0u%dbFOW-IAbEdVf(Cwa~ zEyLg%k3LOh*)=ZR^WnNy0WV@vfd<8RA|Zqj=~|zuU&MgqOZ{=}ET zz()oNv34`W>R@F+gy7zUV&k3TJ2qrX4e45EPQE;0TYz@FUNG&4Rx|lXJ4MTmDqSA* zs4}1d0YF?C!{JF8=$bMv;^X5;<-kyWHwPa6el&jZc%<@(uhhjGIqA~2poov|p#2MQ z!QRj7y-f|=WQiu(cBbtGx%t7Mj+0!1bXZ)Mlwe2+@i`H$jkW?&xq-m{g=;V1}%7nVB*sWe%1Akk9Uv`dcyRnEn>< zk@`3?d|<|&j=+R`82>P?OpFXq3T23d!S^2eT*u2Cjqgd7`umg&5QRSg3)iy6k)2RV zH_9Q@B=Pdr#n#?RhzC?qY^KQ7mM8(Tv}vv;F~7c~GavA9+7dfi`h{4aSM$@VrgvTV zOCZGVVA%m-I@R42Vtk4pz^c~@Z(eVlbqP@$$H#Q;9OglskA5vNA-XZT&Z{X&umk6d zjpH64=f?m)I%V)4>t-cX@lt2wt=NFP{Oz~Dqy7N-(iSTnt)mG2D;)Q0#%6zyjDPs> z>FDU2gW-`AzNA;gCPbSZ_lWQ6=4HC;N(4&%C_;pbqlv(PU_(_fY)SPv?uw3=d#mDk zl3uKI#0I2C2tHtG$ucN^ZZ3&T2ovk|Z9uBi+i6^pi>4OHN!2s3ANaa%fIBg7!ZQo6CjF*zF>iCK{! zXG|veMZ3q0kJU&tOnnYm6yUuMcxC4a_!(I1QxL5^7pDj*9ws1J7a|-$MovT!5+aZk zEFZrg9gUBFqPOg)N5dl@6+tpY2q8B`$msJP9~VkQktp>eMRfOSosg(Pk){Q4JsTAw z>_lQPAv{qp0>ooP+>#`rL%#!>8XrnS6jyo)|gd*PMuN zUM=X;e(X`DZU~k7kuVgXm4ng|ao|?z6roVr3lK#J$P;P4d}(uYb8!(jOf7Z|%9a=q z(QA8J07yQ`wt>##J*E}6tKu*(9MN`lkRbIl-i+$k8}%45Yj;71bd|b>)UMBvr!Hq&p6*Q+!O(_ zrwH{qF;;M2!qJDw_^02Gy4yQWMke@xL^_%%zVv|?w4Jx>5BT`PRO)8p@PbE3uq?X9 ziVP6C|CTyb;A?pSBHE2hJOHtxSx+`;5@bJQm|Z|3kcQcSWm2{J{*0D1S65&Vi6f2 zd!n1S%mbt=(D!uL2$A9xrjEnSbW(ces$*pqC54uQ>k;L{fAosVmeshvzdToX}VA((!UB2 z>R$mL`kzP$t}0wy{I38~t>#r5AdNsh_a9dt9Rc}&0t^85-wV#7O22Uc0000 -

- « - 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} -

- -{if count($ordersMsgs)} - {foreach from=$ordersMsgs item=alert} -
{$alert->text}
- {/foreach} -
-{/if} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Mollie ID:{$payment->kID}Mode:{$order->mode}Status:{$order->status}
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

- - - - - - - - - - - - - - {foreach from=$order->payments() item=payment} - - - - - - - - - - - {/foreach} -
IDStatusMethodeAmountSettlementRefundedRemainingDetails
{$payment->id}{$payment->status}{$payment->method}{$payment->amount->value} {$payment->amount->currency}{$payment->settlementAmount->value} {$payment->settlementAmount->currency}{$payment->amountRefunded->value} {$payment->amountRefunded->currency}{$payment->amountRemaining->value} {$payment->amountRemaining->currency} -
    - {foreach from=$payment->details item=value key=key} -
  • {$key}: {$value}
  • - {/foreach} -
-
-{/if} - - -

Positionen:

- -
- {if ($order->status === 'authorized' || $order->status === 'shipping') && $oBestellung->cStatus|intval >= 3} - - Zahlung erfassen1 - - {/if} - {if $order->amount->value > $order->amountRefunded->value && $order->amountCaptured->value > 0} - Rckerstatten2 - - {/if} - {if $order->isCancelable} - Stornieren3 - - {/if} -
- - - - - - - - - - - - - - - - - - {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} - - - - - - - - - - - - - {/foreach} - - - - - - - - - - -
StatusSKUNameTypAnzahlMwStSteuerNettoBrutto 
- {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*} -
{$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} - - - - - - - {/foreach} -
- {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}
- - diff --git a/version/104/adminmenu/tpl/orders.tpl b/version/104/adminmenu/tpl/orders.tpl deleted file mode 100644 index 3956ef5..0000000 --- a/version/104/adminmenu/tpl/orders.tpl +++ /dev/null @@ -1,107 +0,0 @@ - -{if count($ordersMsgs)} - {foreach from=$ordersMsgs item=alert} -
{$alert->text}
- {/foreach} -
-{/if} - -{if $hasAPIKey == false} - - Jetzt kostenlos Mollie Account eröffnen! - -{else} - - - - - - - - - - - - - - - - {foreach from=$payments item=payment} - - - - - - - - - - - - {/foreach} - -
BestellNr.IDMollie StatusJTL StatusBetragWährungLocaleMethodeErstellt
- {$payment->cOrderNumber} - {if $payment->cMode == 'test'} - TEST - {/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->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)}
- - -{/if} \ No newline at end of file diff --git a/version/104/adminmenu/tpl/paymentmethods.tpl b/version/104/adminmenu/tpl/paymentmethods.tpl deleted file mode 100644 index 260290f..0000000 --- a/version/104/adminmenu/tpl/paymentmethods.tpl +++ /dev/null @@ -1,92 +0,0 @@ -

Account Status

- - - - - - - - - -
Mode:{$profile->mode}Status:{$profile->status}Review:{$profile->review->status}
- -
- -
-
- - -
- - - -
-
- - -
-
- - -
-
- - - reset -
-
-
- - -{if $allMethods && $allMethods|count} - - - - - - - - - - - - {foreach from=$allMethods item=method} - - - - - - - - {/foreach} - -
BildIDNamePreiseInfos
{$method->description|utf8_decode}{$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} -
-{else} -
Es konnten keine Methoden abgerufen werden.
-{/if} \ No newline at end of file diff --git a/version/104/class/Helper.php b/version/104/class/Helper.php deleted file mode 100644 index a159878..0000000 --- a/version/104/class/Helper.php +++ /dev/null @@ -1,309 +0,0 @@ -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); - 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(); - } - - /** - * 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); - } elseif (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/104/class/Model/AbstractModel.php b/version/104/class/Model/AbstractModel.php deleted file mode 100644 index 5638700..0000000 --- a/version/104/class/Model/AbstractModel.php +++ /dev/null @@ -1,7 +0,0 @@ - $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, - ]; - 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; - } - - 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/104/class/Mollie.php b/version/104/class/Mollie.php deleted file mode 100644 index c10b8ad..0000000 --- a/version/104/class/Mollie.php +++ /dev/null @@ -1,446 +0,0 @@ -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) { - header('Location: ' . $url); - 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; - } - - switch ((int)$newStatus) { - case BESTELLUNG_STATUS_VERSANDT: - Mollie::JTLMollie()->doLog('181_sync: Bestellung versandt', '#' . $oBestellung->kBestellung . '§' . $oBestellung->cBestellNr, LOGLEVEL_DEBUG); - $options['lines'] = []; - break; - case BESTELLUNG_STATUS_TEILVERSANDT: - $lines = []; - foreach ($order->lines as $i => $line) { - if (($quantity = Mollie::getBestellPosSent($line->sku, $oBestellung)) !== false && ($quantity - $line->quantityShipped) > 0) { - $x = $quantity - $line->quantityShipped; - $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', '#' . $oBestellung->kBestellung . '§' . $oBestellung->cBestellNr, LOGLEVEL_DEBUG); - if (count($lines)) { - $options['lines'] = $lines; - } - break; - case BESTELLUNG_STATUS_STORNO: - Mollie::JTLMollie()->doLog('181_sync: Bestellung storniert', '#' . $oBestellung->kBestellung . '§' . $oBestellung->cBestellNr, LOGLEVEL_DEBUG); - $options = null; - break; - default: - Mollie::JTLMollie()->doLog('181_sync: Bestellungstatus unbekannt: ' . $newStatus . '/' . $oBestellung->cStatus, '#' . $oBestellung->kBestellung . '§' . $oBestellung->cBestellNr, 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; - } - - /** - * @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) { - 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('handleOrder: ' . $e->getMessage(), $logData); - } - - - $order->orderNumber = $oBestellung->cBestellNr; - Payment::updateFromPayment($order, $kBestellung); - - $oIncomingPayment = Shop::DB()->executeQueryPrepared("SELECT * FROM tzahlungseingang WHERE cHinweis LIKE :cHinweis AND kBestellung = :kBestellung", [':cHinweis' => '%' . $order->id . '%', ':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 ($payments = $order->payments()) { - /** @var \Mollie\Api\Resources\Payment $payment */ - foreach ($payments as $payment) { - if (in_array($payment->status, [PaymentStatus::STATUS_AUTHORIZED, PaymentStatus::STATUS_PAID])) { - $cHinweis .= ' / ' . $payment->id; - } - } - } - $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('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('PaymentStatus: ' . $order->status . ' => Bestellung bezahlt, KEIN Zahlungseingang', $logData, LOGLEVEL_NOTICE); - break; - case OrderStatus::STATUS_CANCELED: - case OrderStatus::STATUS_EXPIRED: - Mollie::JTLMollie()->doLog('PaymentStatus: ' . $order->status, $logData, LOGLEVEL_ERROR); - break; - } - return true; - } - return false; - } - - 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/104/frontend/131_globalinclude.php b/version/104/frontend/131_globalinclude.php deleted file mode 100644 index 45d4c6f..0000000 --- a/version/104/frontend/131_globalinclude.php +++ /dev/null @@ -1,72 +0,0 @@ -executeQueryPrepared("SELECT * FROM " . \ws_mollie\Model\Payment::TABLE . " WHERE cHash = :cHash", [':cHash' => $_REQUEST['mollie']], 1); - // Bestellung finalized, redirect to status/completion page - if ((int)$payment->kBestellung) { - $logData = '$' . $payment->kID . '#' . $payment->kBestellung . "§" . $payment->cOrderNumber; - Mollie::JTLMollie()->doLog('Bestellung finalized => redirect abschluss/status', $logData); - $order = JTLMollie::API()->orders->get($payment->kID, ['embed' => 'payments']); - Mollie::handleOrder($order, $payment->kBestellung); - Mollie::getOrderCompletedRedirect($payment->kBestellung, true); - } elseif ($payment) { // payment, but no order => finalize it - require_once __DIR__ . '/../paymentmethod/JTLMollie.php'; - $order = JTLMollie::API()->orders->get($payment->kID, ['embed' => 'payments']); - $logData = '$' . $order->id . '#' . $payment->kBestellung . "§" . $payment->cOrderNumber; - - // GET NEWEST PAYMENT: - /** @var Payment $_payment */ - $_payment = null; - if ($order->payments()) { - /** @var Payment $p */ - foreach ($order->payments() as $p) { - if (!$_payment) { - $_payment = $p; - continue; - } - if (strtotime($p->createdAt) > strtotime($_payment->createdAt)) { - $_payment = $p; - } - } - } - - // finalize only, if order is not canceld/expired - if ($order && !$order->isCanceled() && !$order->isExpired()) { - // finalize only if payment is not expired/canceled,failed or open - if ($_payment && !in_array($_payment->status, [PaymentStatus::STATUS_EXPIRED, PaymentStatus::STATUS_CANCELED, PaymentStatus::STATUS_OPEN, PaymentStatus::STATUS_FAILED, PaymentStatus::STATUS_CANCELED])) { - Mollie::JTLMollie()->doLog('Bestellung open => finalize', $logData); - $session = Session::getInstance(); - /** @noinspection PhpIncludeInspection */ - require_once PFAD_ROOT . 'includes/bestellabschluss_inc.php'; - /** @noinspection PhpIncludeInspection */ - require_once PFAD_ROOT . 'includes/mailTools.php'; - $oBestellung = fakeBestellung(); - $oBestellung = finalisiereBestellung(); - Mollie::JTLMollie()->doLog('Bestellung finalized => redirect
' . print_r($order, 1) . '
', $logData, LOGLEVEL_DEBUG); - Mollie::handleOrder($order, $oBestellung->kBestellung); - Mollie::getOrderCompletedRedirect($oBestellung->kBestellung, true); - } else { - Mollie::JTLMollie()->doLog('Invalid Payment
' . print_r($payment, 1) . '
', $logData, LOGLEVEL_ERROR); - } - } else { - Mollie::JTLMollie()->doLog('Invalid Order
' . print_r($order, 1) . '
', $logData, LOGLEVEL_ERROR); - } - } - } - ob_end_flush(); -} catch (Exception $e) { - Helper::logExc($e); -} diff --git a/version/104/frontend/140_smarty.php b/version/104/frontend/140_smarty.php deleted file mode 100644 index 56a6400..0000000 --- a/version/104/frontend/140_smarty.php +++ /dev/null @@ -1,52 +0,0 @@ -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/104/frontend/144_notify.php b/version/104/frontend/144_notify.php deleted file mode 100644 index a2af9f2..0000000 --- a/version/104/frontend/144_notify.php +++ /dev/null @@ -1,31 +0,0 @@ - Update Payment, stop skript - * - ELSE weiter mit der notify.php - */ - -use ws_mollie\Helper; -use ws_mollie\Model\Payment; -use ws_mollie\Mollie; - -if (array_key_exists('hash', $_REQUEST)) { - require_once __DIR__ . '/../class/Helper.php'; - try { - Helper::init(); - $payment = Payment::getPaymentHash($_REQUEST['hash']); - // If Bestellung already exists, treat as Notification - if ($payment && $payment->kBestellung) { - require_once __DIR__ . '/../paymentmethod/JTLMollie.php'; - $order = JTLMollie::API()->orders->get($payment->kID); - $logData = '#' . $payment->kBestellung . '$' . $payment->kID; - Mollie::JTLMollie()->doLog('Received Notification
' . print_r([$order, $payment], 1) . '
', $logData); - Mollie::handleOrder($order, $payment->kBestellung); - // exit to stop execution of notify.php - exit(); - } - } catch (Exception $e) { - Helper::logExc($e); - } -} diff --git a/version/104/frontend/181_sync.php b/version/104/frontend/181_sync.php deleted file mode 100644 index 30d3279..0000000 --- a/version/104/frontend/181_sync.php +++ /dev/null @@ -1,38 +0,0 @@ -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()) { - Mollie::JTLMollie()->doLog("Create Shippment:
" . print_r($args_arr, 1) . '
', $logData, LOGLEVEL_DEBUG); - $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/104/paymentmethod/JTLMollie.php b/version/104/paymentmethod/JTLMollie.php deleted file mode 100644 index f19bf28..0000000 --- a/version/104/paymentmethod/JTLMollie.php +++ /dev/null @@ -1,558 +0,0 @@ - (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); - - - if (isset($model->kZahlungseingang) && $model->kZahlungseingang > 0) { - Shop::DB()->update('tzahlungseingang', 'kZahlungseingang', $model->kZahlungseingang, $model); - } else { - Shop::DB()->insert('tzahlungseingang', $model); - } - - 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 - */ - public function preparePaymentProcess($order) - { - $logData = '#' . $order->kBestellung . "" . $order->cBestellNr; - try { - if ($order->kBestellung) { - $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(); - } - } - } catch (Exception $e) { - $this->doLog("Get Payment Error: " . $e->getMessage() . ". Create new ORDER...", $logData); - } - - try { - if (!array_key_exists('oMolliePayment', $_SESSION) || !($_SESSION['oMolliePayment'] instanceof \Mollie\Api\Resources\Order)) { - $hash = $this->generateHash($order); - $orderData = $this->getOrderData($order, $hash); - $oMolliePayment = self::API()->orders->create($orderData); - $_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($hash)); - Shop::Smarty()->assign('oMolliePayment', $oMolliePayment); - if (!$this->duringCheckout) { - Session::getInstance()->cleanUp(); - } - header('Location: ' . $oMolliePayment->getCheckoutUrl()); - unset($_SESSION['oMolliePayment']); - echo "redirect to payment ..."; - exit(); - } catch (ApiException $e) { - Shop::Smarty()->assign('oMollieException', $e); - $this->doLog("Create Payment Error: " . $e->getMessage() . '
' . print_r($e->getTrace(), 1) . '
', $logData); - } - } - - /** - * @return MollieApiClient - * @throws ApiException - * @throws IncompatiblePlatform - */ - public static function API() - { - if (self::$_mollie === null) { - self::$_mollie = new MollieApiClient(); - 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 string $msg - * @param null $data - * @param int $level - * @return $this - */ - public function doLog($msg, $data = null, $level = LOGLEVEL_NOTICE) - { - ZahlungsLog::add($this->moduleID, $msg, $data, $level); - - return $this; - } - - /** - * @param Bestellung $order - * @param $hash - * @return array - */ - protected function getOrderData(Bestellung $order, $hash) - { - $locale = self::getLocale($_SESSION['cISOSprache'], $_SESSION['Kunde']->cLand); - $data = [ - 'locale' => $locale ?: 'de_DE', - 'amount' => (object)[ - 'currency' => $order->Waehrung->cISO, - 'value' => number_format($order->fGesamtsummeKundenwaehrung, 2, '.', ''), - ], - 'orderNumber' => utf8_encode($order->cBestellNr), - 'lines' => [], - 'billingAddress' => new stdClass(), - - 'redirectUrl' => (int)$this->duringCheckout ? Shop::getURL() . '/bestellabschluss.php?mollie=' . md5($hash) : $this->getReturnURL($order), - 'webhookUrl' => $this->getNotificationURL($hash) . '&hash=' . md5($hash), - ]; - - if (static::MOLLIE_METHOD !== '') { - $data['method'] = static::MOLLIE_METHOD; - } - 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 ($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; - } - - /** @var WarenkorbPos $oPosition */ - foreach ($order->Positionen as $oPosition) { - - $_currencyFactor = (float)$order->Waehrung->fFaktor; // EUR => 1 - $_netto = round($oPosition->fPreis,2); // 13.45378 => 13.45 - $_vatRate = (float)$oPosition->fMwSt / 100; // 0.19 - $_amount = (float)$oPosition->nAnzahl; // 3 - - $unitPriceNetto = round(($_currencyFactor * $_netto), 2); // => 13.45 - $unitPrice = round($unitPriceNetto * (1 + $_vatRate), 2); // 13.45 * 1.19 => 16.01 - - $totalAmount = round($_amount * $unitPrice, 2); // 16.01 * 3 => 48.03 - //$vatAmount = ($unitPrice - $unitPriceNetto) * $_amount; // (16.01 - 13.45) * 3 => 7.68 - $vatAmount = round($totalAmount - ($totalAmount / (1+$_vatRate)), 2); // 48.03 - (48.03 / 1.19) => 7.67 - - $line = new stdClass(); - $line->name = utf8_encode($oPosition->cName); - $line->quantity = $oPosition->nAnzahl; - $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 = $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->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->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"; - } - } - - /** - * @param Bestellung $order - * @param string $hash - * @param array $args - */ - public function handleNotification($order, $hash, $args) - { - Helper::autoload(); - $logData = '#' . $order->kBestellung . "" . $order->cBestellNr; - $this->doLog('Received Notification
' . print_r([$hash, $args], 1) . '
', $logData, LOGLEVEL_NOTICE); - - try { - $oMolliePayment = self::API()->orders->get($args['id'], ['embed' => 'payments']); - Mollie::handleOrder($oMolliePayment, $order->kBestellung); - } catch (Exception $e) { - $this->doLog('handleNotification: ' . $e->getMessage(), $logData); - } - } - - /** - * @param Bestellung $order - * @param string $hash - * @param array $args - * - * @return true, if $order should be finalized - */ - public function finalizeOrder($order, $hash, $args) - { - $logData = '#' . $order->kBestellung . "" . $order->cBestellNr; - try { - Helper::autoload(); - $oMolliePayment = self::API()->orders->get($args['id'], ['embed' => 'payments']); - $logData .= '$' . $oMolliePayment->id; - $this->doLog('Received Notification Finalize Order
' . print_r([$hash, $args, $oMolliePayment], 1) . '
', $logData, LOGLEVEL_DEBUG); - Payment::updateFromPayment($oMolliePayment, $order->kBestellung); - return in_array($oMolliePayment->status, [OrderStatus::STATUS_PAID, OrderStatus::STATUS_AUTHORIZED, OrderStatus::STATUS_PENDING, OrderStatus::STATUS_COMPLETED]); - } catch (Exception $e) { - $this->doLog($e->getMessage(), $logData); - } - return false; - } - - /** - * @return bool - */ - public function canPayAgain() - { - return true; - } - - /** - * determines, if the payment method can be selected in the checkout process - * - * @return bool - */ - public function isSelectable() - { - /** @var Warenkorb $wk */ - $wk = $_SESSION['Warenkorb']; - foreach ($wk->PositionenArr as $oPosition) { - if ($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 { - $method = self::PossiblePaymentMethods(static::MOLLIE_METHOD, $locale, $_SESSION['Kunde']->cLand, $_SESSION['Waehrung']->cISO, $wk->gibGesamtsummeWaren(true) * $_SESSION['Waehrung']->fFaktor); - if ($method !== null) { - $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; - } - } - return true; - } - - /** - * @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 (ws_mollie\Helper::getSetting('paymentmethod_sync') === 'N') { - return; - } - $size = ws_mollie\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::init() && 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/104/paymentmethod/JTLMollieApplePay.php b/version/104/paymentmethod/JTLMollieApplePay.php deleted file mode 100644 index ecf20a8..0000000 --- a/version/104/paymentmethod/JTLMollieApplePay.php +++ /dev/null @@ -1,8 +0,0 @@ - - {$oMollieException->getMessage()} - -{/if} \ No newline at end of file diff --git a/version/105/adminmenu/info.php b/version/105/adminmenu/info.php deleted file mode 100644 index d7c5e2b..0000000 --- a/version/105/adminmenu/info.php +++ /dev/null @@ -1,55 +0,0 @@ -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, - 'd' => Helper::getDomain(), - 'm' => base64_encode(Helper::getMasterMail(true)), - 'php' => PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION . '.' . PHP_RELEASE_VERSION, - ]); - - echo ""; - echo "
" . - "
" . - " " . - " Lizenz Informationen" . - ' ' . - '
' . - "
" . - " " . - " Update Informationen" . - ' ' . - '
' . - "
" . - " " . - " Plugin informationen" . - ' ' . - '
' . - '
'; - - 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'); -} catch (Exception $e) { - echo "
Fehler: {$e->getMessage()}
"; - Helper::logExc($e); -} \ No newline at end of file diff --git a/version/105/adminmenu/orders.php b/version/105/adminmenu/orders.php deleted file mode 100644 index 99603ed..0000000 --- a/version/105/adminmenu/orders.php +++ /dev/null @@ -1,154 +0,0 @@ - 'danger', 'text' => 'Keine ID angeben!']; - break; - } - $payment = Payment::getPaymentMollie($_REQUEST['id']); - if (!$payment) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; - break; - } - - $order = JTLMollie::API()->orders->get($_REQUEST['id']); - if ($order->status == OrderStatus::STATUS_CANCELED) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung bereits storniert']; - 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; - break; - - case 'cancel': - if (!array_key_exists('id', $_REQUEST)) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; - break; - } - $payment = Payment::getPaymentMollie($_REQUEST['id']); - if (!$payment) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; - break; - } - $order = JTLMollie::API()->orders->get($_REQUEST['id']); - if ($order->status == OrderStatus::STATUS_CANCELED) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung bereits storniert']; - 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; - break; - - case 'capture': - if (!array_key_exists('id', $_REQUEST)) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; - break; - } - $payment = Payment::getPaymentMollie($_REQUEST['id']); - if (!$payment) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; - break; - } - $order = JTLMollie::API()->orders->get($_REQUEST['id']); - if ($order->status !== OrderStatus::STATUS_AUTHORIZED && $order->status !== OrderStatus::STATUS_SHIPPING) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Nur autorisierte Zahlungen können erfasst werden!']; - break; - } - - $oBestellung = new Bestellung($payment->kBestellung, true); - if (!$oBestellung->kBestellung) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung konnte nicht geladen werden!']; - break; - } - - $logData = '#' . $payment->kBestellung . '$' . $payment->kID . "§" . $oBestellung->cBestellNr; - - $options = ['lines' => []]; - if ($oBestellung->cTracking) { - $tracking = new stdClass(); - $tracking->carrier = $oBestellung->cVersandartName; - $tracking->url = $oBestellung->cTrackingURL; - $tracking->code = $oBestellung->cTracking; - $options['tracking'] = $tracking; - } - - // CAPTURE ALL - $shipment = JTLMollie::API()->shipments->createFor($order, $options); - $ordersMsgs[] = (object)['type' => 'success', 'text' => 'Zahlung wurde erfolgreich erfasst!']; - Mollie::JTLMollie()->doLog('Shipment created
' . print_r(['options' => $options, 'shipment' => $shipment], 1) . '
', $logData); - goto order; - - case 'order': - order: - if (!array_key_exists('id', $_REQUEST)) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; - 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", [ - ':kBestellung' => '%#' . ($payment->kBestellung ?: '##') . '%', - ':cBestellNr' => '%§' . ($payment->cOrderNumber ?: '§§') . '%', - ':MollieID' => '%$' . ($payment->kID ?: '$$') . '%', - ], 2); - - Shop::Smarty()->assign('payment', $payment) - ->assign('oBestellung', $oBestellung) - ->assign('order', $order) - ->assign('logs', $logs) - ->assign('ordersMsgs', $ordersMsgs); - Shop::Smarty()->display($oPlugin->cAdminmenuPfad . '/tpl/order.tpl'); - return; - } - } - - - $payments = Shop::DB()->executeQueryPrepared("SELECT * FROM xplugin_ws_mollie_payments WHERE kBestellung IS NOT NULL AND cStatus != 'created'", [], 2); - foreach ($payments as $i => $payment) { - $payments[$i]->oBestellung = new Bestellung($payment->kBestellung, false); - } - - Shop::Smarty()->assign('payments', $payments) - ->assign('ordersMsgs', $ordersMsgs) - ->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/105/adminmenu/paymentmethods.php b/version/105/adminmenu/paymentmethods.php deleted file mode 100644 index 1782978..0000000 --- a/version/105/adminmenu/paymentmethods.php +++ /dev/null @@ -1,60 +0,0 @@ -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/105/adminmenu/tpl/info.tpl b/version/105/adminmenu/tpl/info.tpl deleted file mode 100644 index da2a55a..0000000 --- a/version/105/adminmenu/tpl/info.tpl +++ /dev/null @@ -1,93 +0,0 @@ -
-
-
- - - -
-
- - - -
- - {if isset($update)} -
- -
-

Update auf Version {$update->version} verfügbar!

-
-
-
-
Version:
-
{$update->version}
-
-
-
Erschienen:
-
{$update->create_date}
-
-
-
Changelog:
-
- -
-
- -
-
- -
-
-
- {else} -
- - - -
- {/if} - -
-
-
- - - -
-
- - - -
- -
-
-
- - - -
-
- - - -
-
- - - -
-
-
diff --git a/version/105/adminmenu/tpl/mollie-account-erstellen.png b/version/105/adminmenu/tpl/mollie-account-erstellen.png deleted file mode 100644 index fc1819255ef725fa214cf2bf028cf3428794ecee..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 38998 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 -

- « - 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} -

- -{if count($ordersMsgs)} - {foreach from=$ordersMsgs item=alert} -
{$alert->text}
- {/foreach} -
-{/if} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
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

- - - - - - - - - - - - - - {foreach from=$order->payments() item=payment} - - - - - - - - - - - {/foreach} -
IDStatusMethodeAmountSettlementRefundedRemainingDetails
{$payment->id}{$payment->status}{$payment->method}{$payment->amount->value} {$payment->amount->currency}{$payment->settlementAmount->value} {$payment->settlementAmount->currency}{$payment->amountRefunded->value} {$payment->amountRefunded->currency}{$payment->amountRemaining->value} {$payment->amountRemaining->currency} -
    - {foreach from=$payment->details item=value key=key} -
  • {$key}: {$value}
  • - {/foreach} -
-
-{/if} - - -

Positionen:

- -
- {if ($order->status === 'authorized' || $order->status === 'shipping') && $oBestellung->cStatus|intval >= 3} - - Zahlung erfassen1 - - {/if} - {if $order->amount->value > $order->amountRefunded->value && $order->amountCaptured->value > 0} - Rckerstatten2 - - {/if} - {if $order->isCancelable} - Stornieren3 - - {/if} -
- - - - - - - - - - - - - - - - - - {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} - - - - - - - - - - - - - {/foreach} - - - - - - - - - - -
StatusSKUNameTypAnzahlMwStSteuerNettoBrutto 
- {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*} -
{$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} - - - - - - - {/foreach} -
- {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}
- - diff --git a/version/105/adminmenu/tpl/orders.tpl b/version/105/adminmenu/tpl/orders.tpl deleted file mode 100644 index df024b4..0000000 --- a/version/105/adminmenu/tpl/orders.tpl +++ /dev/null @@ -1,113 +0,0 @@ - -{if count($ordersMsgs)} - {foreach from=$ordersMsgs item=alert} -
{$alert->text}
- {/foreach} -
-{/if} - -{if $hasAPIKey == false} - - Jetzt kostenlos Mollie Account eröffnen! - -{else} - - - - - - - - - - - - - - - - {foreach from=$payments item=payment} - - - - - - - - - - - - {/foreach} - -
BestellNr.IDMollie StatusJTL StatusBetragWährungLocaleMethodeErstellt
- {$payment->cOrderNumber} - {if $payment->cMode == 'test'} - TEST - {/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)}
- - -{/if} - diff --git a/version/105/adminmenu/tpl/paymentmethods.tpl b/version/105/adminmenu/tpl/paymentmethods.tpl deleted file mode 100644 index bd65a11..0000000 --- a/version/105/adminmenu/tpl/paymentmethods.tpl +++ /dev/null @@ -1,92 +0,0 @@ -

Account Status

- - - - - - - - - -
Mode:{$profile->mode}Status:{$profile->status}Review:{$profile->review->status}
- -
- -
-
- - -
- - - -
-
- - -
-
- - -
-
- - - reset -
-
-
- - -{if $allMethods && $allMethods|count} - - - - - - - - - - - - {foreach from=$allMethods item=method} - - - - - - - - {/foreach} - -
BildIDNamePreiseInfos
{$method->description|utf8_decode}{$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} -
-{else} -
Es konnten keine Methoden abgerufen werden.
-{/if} \ No newline at end of file diff --git a/version/105/class/Helper.php b/version/105/class/Helper.php deleted file mode 100644 index 8f4772c..0000000 --- a/version/105/class/Helper.php +++ /dev/null @@ -1,311 +0,0 @@ -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(); - } - - /** - * 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/105/class/Model/AbstractModel.php b/version/105/class/Model/AbstractModel.php deleted file mode 100644 index 5638700..0000000 --- a/version/105/class/Model/AbstractModel.php +++ /dev/null @@ -1,7 +0,0 @@ - $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, - ]; - 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/105/class/Mollie.php b/version/105/class/Mollie.php deleted file mode 100644 index 7b96c3b..0000000 --- a/version/105/class/Mollie.php +++ /dev/null @@ -1,477 +0,0 @@ -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) { - header('Location: ' . $url); - 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; - } - - switch ((int)$newStatus) { - case BESTELLUNG_STATUS_VERSANDT: - Mollie::JTLMollie()->doLog('181_sync: Bestellung versandt', '#' . $oBestellung->kBestellung . '§' . $oBestellung->cBestellNr, LOGLEVEL_DEBUG); - $options['lines'] = []; - break; - case BESTELLUNG_STATUS_TEILVERSANDT: - $lines = []; - foreach ($order->lines as $i => $line) { - if (($quantity = Mollie::getBestellPosSent($line->sku, $oBestellung)) !== false && ($quantity - $line->quantityShipped) > 0) { - $x = $quantity - $line->quantityShipped; - $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', '#' . $oBestellung->kBestellung . '§' . $oBestellung->cBestellNr, LOGLEVEL_DEBUG); - if (count($lines)) { - $options['lines'] = $lines; - } - break; - case BESTELLUNG_STATUS_STORNO: - Mollie::JTLMollie()->doLog('181_sync: Bestellung storniert', '#' . $oBestellung->kBestellung . '§' . $oBestellung->cBestellNr, LOGLEVEL_DEBUG); - $options = null; - break; - default: - Mollie::JTLMollie()->doLog('181_sync: Bestellungstatus unbekannt: ' . $newStatus . '/' . $oBestellung->cStatus, '#' . $oBestellung->kBestellung . '§' . $oBestellung->cBestellNr, 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; - } - - /** - * @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); - - $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); - } - - - $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; - } - - $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; - } - - 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/105/frontend/131_globalinclude.php b/version/105/frontend/131_globalinclude.php deleted file mode 100644 index c125319..0000000 --- a/version/105/frontend/131_globalinclude.php +++ /dev/null @@ -1,82 +0,0 @@ -executeQueryPrepared("SELECT * FROM " . \ws_mollie\Model\Payment::TABLE . " WHERE cHash = :cHash", [':cHash' => $_REQUEST['mollie']], 1); - // Bestellung finalized, redirect to status/completion page - if ((int)$payment->kBestellung) { - $logData = '$' . $payment->kID . '#' . $payment->kBestellung . "§" . $payment->cOrderNumber; - Mollie::JTLMollie()->doLog('Hook 131/kBestellung => bestellabschluss', $logData); - $order = JTLMollie::API()->orders->get($payment->kID, ['embed' => 'payments']); - Mollie::handleOrder($order, $payment->kBestellung); - Mollie::getOrderCompletedRedirect($payment->kBestellung, true); - } elseif ($payment) { // payment, but no order => finalize it - require_once __DIR__ . '/../paymentmethod/JTLMollie.php'; - $order = JTLMollie::API()->orders->get($payment->kID, ['embed' => 'payments']); - $logData = '$' . $order->id . '#' . $payment->kBestellung . "§" . $payment->cOrderNumber; - - // GET NEWEST PAYMENT: - /** @var Payment $_payment */ - $_payment = null; - if ($order->payments()) { - /** @var Payment $p */ - foreach ($order->payments() as $p) { - if (!$_payment) { - $_payment = $p; - continue; - } - if (strtotime($p->createdAt) > strtotime($_payment->createdAt)) { - $_payment = $p; - } - } - } - - // finalize only, if order is not canceld/expired - if ($order && !$order->isCanceled() && !$order->isExpired()) { - // finalize only if payment is not expired/canceled,failed or open - if ($_payment && !in_array($_payment->status, [PaymentStatus::STATUS_EXPIRED, PaymentStatus::STATUS_CANCELED, PaymentStatus::STATUS_OPEN, PaymentStatus::STATUS_FAILED])) { - - Mollie::JTLMollie()->doLog('Hook 131/open => finalize', $logData, LOGLEVEL_DEBUG); - /** @noinspection PhpIncludeInspection */ - require_once PFAD_ROOT . 'includes/bestellabschluss_inc.php'; - /** @noinspection PhpIncludeInspection */ - require_once PFAD_ROOT . 'includes/mailTools.php'; - $session = Session::getInstance(); - $oBestellung = fakeBestellung(); - $oBestellung = finalisiereBestellung(); - $session->cleanUp(); - - Mollie::JTLMollie()->doLog('Hook 131/finalized => bestellabschluss
' . print_r($order, 1) . '
', $logData); - Mollie::handleOrder($order, $oBestellung->kBestellung); - JTLMollie::API()->performHttpCall('PATCH', sprintf('payments/%s', $_payment->id), json_encode(['description' => $oBestellung->cBestellNr])); - - return Mollie::getOrderCompletedRedirect($oBestellung->kBestellung, true); - - } else { - Mollie::JTLMollie()->doLog('Hook 131/Invalid Payment
' . print_r($payment, 1) . '
', $logData, LOGLEVEL_ERROR); - header('Location: ' . Shop::getURL() . '/bestellvorgang.php?editZahlungsart=1&mollieStatus=' . $_payment->status); - exit(); - } - } else { - Mollie::JTLMollie()->doLog('Hook 131/Invalid Order
' . print_r($order, 1) . '
', $logData, LOGLEVEL_ERROR); - header('Location: ' . Shop::getURL() . '/bestellvorgang.php?editZahlungsart=1&mollieStatus=' . $order->status); - exit(); - } - } - } - ob_end_flush(); -} catch (Exception $e) { - Helper::logExc($e); -} diff --git a/version/105/frontend/140_smarty.php b/version/105/frontend/140_smarty.php deleted file mode 100644 index 53360d6..0000000 --- a/version/105/frontend/140_smarty.php +++ /dev/null @@ -1,59 +0,0 @@ -oPluginSprachvariableAssoc_arr['error_' . $status]; - pq('#fieldset-payment')->prepend('
' . $text . '
'); - } - - 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/105/frontend/144_notify.php b/version/105/frontend/144_notify.php deleted file mode 100644 index fe19c10..0000000 --- a/version/105/frontend/144_notify.php +++ /dev/null @@ -1,59 +0,0 @@ - Update Payment, stop skript - * - ELSE weiter mit der notify.php - */ - -use Mollie\Api\Types\PaymentStatus; -use ws_mollie\Helper; -use ws_mollie\Model\Payment; -use ws_mollie\Mollie; - -if (array_key_exists('hash', $_REQUEST)) { - require_once __DIR__ . '/../class/Helper.php'; - try { - Helper::init(); - $payment = Payment::getPaymentHash($_REQUEST['hash']); - // If Bestellung already exists, treat as Notification - if ($payment && $payment->kBestellung) { - require_once __DIR__ . '/../paymentmethod/JTLMollie.php'; - $order = JTLMollie::API()->orders->get($payment->kID, ['embed' => 'payments']); - $logData = '#' . $payment->kBestellung . '$' . $payment->kID; - Mollie::JTLMollie()->doLog('Notify/Hook 144/kBestellung>0
' . print_r([$order, $payment], 1) . '
', $logData); - Mollie::handleOrder($order, $payment->kBestellung); - // exit to stop execution of notify.php - - // GET NEWEST PAYMENT: - /** @var \Mollie\Api\Resources\Payment $_payment */ - $_payment = null; - if ($order->payments()) { - /** @var \Mollie\Api\Resources\Payment $p */ - foreach ($order->payments() as $p) { - if (!in_array($p->status, [PaymentStatus::STATUS_AUTHORIZED, PaymentStatus::STATUS_PAID, PaymentStatus::STATUS_PENDING])) { - continue; - } - if (!$_payment) { - $_payment = $p; - continue; - } - if (strtotime($p->createdAt) > strtotime($_payment->createdAt)) { - $_payment = $p; - } - } - } - - if ($payment->oBestellung instanceof Bestellung) { - JTLMollie::API()->performHttpCall('PATCH', sprintf('payments/%s', $_payment->id), json_encode(['description' => $payment->oBestellung->cBestellNr])); - } - - exit(); - }else if($payment){ - $logData = '$' . $payment->kID; - Mollie::JTLMollie()->doLog('Notify/Hook 144/continue
' . print_r([$order, $payment], 1) . '
', $logData); - } - } catch (Exception $e) { - Helper::logExc($e); - } -} diff --git a/version/105/frontend/181_sync.php b/version/105/frontend/181_sync.php deleted file mode 100644 index 86c610c..0000000 --- a/version/105/frontend/181_sync.php +++ /dev/null @@ -1,43 +0,0 @@ -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/105/frontend/img/trust_eng.png b/version/105/frontend/img/trust_eng.png deleted file mode 100644 index 3d0177359de7fa93833765ac05d8b218fa1550f2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15299 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 Rmns)TMnX}%M${5 diff --git a/version/105/frontend/img/trust_fre.png b/version/105/frontend/img/trust_fre.png deleted file mode 100644 index ed1a2f6f03c56f6748aac8af0352de7fc0afd3a4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17319 zcmeIaWm{d#(l&}rVB!{B1Hml>cM0wg+}+*XC3tZ6;O_1g+}+*X{miwVy`H`IIp+tw zAKovs$2G4pYIIlC=&tJft`3!x5k-WXlNj7k?iufmqH+8N*koC2! zvmJh3R`?W79|~N)N*|nxgjgE3JwO7U=U3pbw+W9c8DnD;7ZcVr!_NoYvfr2*H(bug z+a6XOCi>*CzgaEUJ>H+KJWNbXboLzF}|hnF@qh`<|_#%8k)v)1A?a+efU31|zB7h0(C?H&)T#+b}Ums`C@ExH{AkB_brVq(PUJJEPK z?~b?}aDP4fw+Q|teqRi%Kt63Hd7n`nN(Khm3=2RqlcBBW1sn!-*}R@#)Mr>Y3u%$v z{r&ZlBpZIQ;drXNKjPVfWSajT0|1;DEH*YHLzj<`7UKLGvM`1sv;ot}TG@9)Mol3zw9iiG-4*B2wM%1Pz}vMjB8 z2>mng$#heDh&0d>pFUGK|Jqgmcb9tv!QhZ>;cXEp1-m%9cus?!%;Z4EO7b%zkd`qN zA4E#gg#Wje^iaEEC*I#)67=X2J%*DQY%Kc(mM{_F5cKQE#GCE+`qqC}9ZGutZP5Se zkq{UhiY+3r35NYAM^27Fx3d2Fb1hn{Q{R3cLQML9h?f7HZKdG4H!w&qnR-n3Cm1>i zlEN=tw=oL44|C4ymp#<~xCuyVR|FV43`iib>1WgrK+qiZSsgm7sjSf7FZ`E3QPKmL zAHcBmWTv6-sQr6_sm<45WET4<8=9;`W=a3YY5r0-KiDcHKAP&zR=H{QdARX@isyI-XZhbZRwyrf)tUFFL(if6_S|Opj-aMOKwmw1gw^ z*pwHRmX>Ze1CXa5Hhg5uH5v;(-Y$F;+ufZ=t?JT0!3!)^8^E+bAD1#44S!OvHI6*? z$P2<{k2khz1LnWq#UYTwZbyQM{nZ!buqH=0+x_9NK9z0P zaFMtyVf3x1-z3{K|E)&;UDU^|5F*+jnJnIn>+9>>aiUbc0DUv7Kze=|`p#E-VVP{Y zr>BD~vyb<;W8?!K_ggtTv4A>~|4?-u(D8V7NI{_0`7AdoJ=;%MM6Rj~atu~ud%8-m z*YtXKXtrE~jasE5{kfMT(KFNg*(?FtEQUf;Z{sZt+#f3SL(bqBs#>iN<#jzoaXTeSgsN$tM#jdbBAuH()en#mLSffN zb$x$2DAwup9&X!CcNov9HW(B!QVF*Vg<+*oo%h?{eSf(?UUVx9>P|i=t?W>6rk3Tt z66&h!Cg}pIRBE3kePLvbNo6(@B;a!X{qfTIkvE(`^OA3e2Nv*KAON~}*R=@|pMBCw zSzHAIh|lTx^YXi42%q`c-EnCpy`OSZX^m_auleh?%grE>kB}uRBx$pb&zlkpgh8Y8 z+44EABYr{4L8ixH`@=eudtzduh)KF#aLYjLPO3#kj#8;|u?07i_sba@>DiSt$XZ!zXEXkK?0Y+)A z43Th5I=EK2n+S`EOdh=?2X4baXjldXY*pdXF5u~2l8!Qy@f%6lK!YGtNWSc!?f@8A z16H)yloas*7~}#}QW45nOzGXEQq;>_nt-sxf~V7LlI!n$yI%o-Y$^8l2y(yJA}djl zqulI|k+#izwXRaa;?f^|=ahp6k}E^9S}ta9PtVL8#s84GlEfcw89%`g=mB&e2PUJz00Krdb6K&S6sg}is;&lXkV(7y-Kq)o zK>UKXM|q|3SSqhKBZfiw)DMgok;}OfrIEo@2qFuk+(NyN29V*9J1J*fy{`JP-l`t2 z28kj~AZ7Vqx5H_&*}sO~+sSLHwibtkhDN^yJgV*#tjoHJ9`TVQ^3D&J>Ms`lj26$T z)b9@yX_Hx~()&)d!WC2&^%nEEh|tZzH>{^{_Hy2Ofj@G%(b-9c97jq@z+j`Xot%tk zM=9HgI=Iyvf@ilMm*xFDG`NqRSjS1U+^-QgHbm-N;U?af-!>L z9*kIkbBbJR3%n*~82(x3c)ptQ7?dB@KOHExg`(S|(gYF4{_t|qS$Ti|0Gj%KT7->n z%W@ul>9LF;5_0T;r4Z601=;s-DK~EalgOQV`nHp%JW)7goGB5OaAft$wS&F=Ed7sU zB7O^9EYnZf!XFbp@83-_oG^K=|ByfJm|8N)vRbTKIuUN2e4xnkoF>GmKKaRTwd%SPDPe?b z4R5z25ADn%q@FDi(q*auPpJ77^LanbW)=yKJu<)#e|fS*i6%pepth#w5F|?J09z4c z_v*epTI?-7akIVQ1OO>FH;OKd?!&YRJ^Vl`cKV|E+d-BOnqq)!wYKAwaLMb_%|U6# zcX&)%;@cd_Bzi!!pI;(`+(0s;0q}@1Tcg2J9Q1k7-<_|mOlxa;zTGV_yPRusKJCWM zAz#-oXp^!(c1NSV4I;yzP4(1D?=^~C&HC%0RDm5npo*}ZW@{5ZfYotVL^-X`Xn@un<*R_C|;!S~aNE<&c9<6}^03;hYpR%WK(KL#`*J)7+qpd-6_y@+W93cmAG;VyUmxSh^spu$ z-WiB=_>sPxGr0T-0@K(pk{n@Y4R{G=*HvA#2U<2+*PUAEDRC~xyW8jd?>C<&mPuL8 z9bNmP)DzIC))3f68>s%7v*-$>-iEB7o&QBgV)jTlG4(5)mpy!I9x90 z%-c)H8)z_dxHcKA+fE$pnXcQRybY<1zuA)Rdf*uzUE8M^E*`ITyxQ`YLK>1sdO1E+ zy+*I;jJEw@S{1~XXLeF`ICp+J1{uDSYE_|E8o8cv9gCz*i5BwesrkazP6=rTuuNaUPXHGvxK|Xe7PMS4 zkQ78C8CUq8Tnm57Lo2qZJK~ZHbBYnP>ux$B2(pYZ5$Ew3BP?PL45mU!YCveY7B8GV z!YX3*tgV}P4{_d)txoVCNXgMj+iDbY#I02CVaCx^Gzs2?xbUWy${$G4M|RNbbgZIX z?7b5kd>H`QYXHzQ$f_&y!o08QZ!~RWMnk`dIdZk+=lM9c=;QI+h<^I8ry~9fEYtAu z(a6#*`f7JPWP`+JP-&#VZ{4JfPM#cK8DH+LvF|uEG{l?vh{Ljzp&K>GvC>dvf+m~n zb?V$Tc%R~JmduW0^r;^W*+PWY>Dy<;0(48Pyknz1zi5iXMCLNLTTq5JWU8Vk%gg{? z8(D-HMsR6c+3qZd9v?#JE_NsS5T4Q$U60Faym<`MlM1mzHl_~57)V9Bn}obn{V~IU zx_-C$0{Va>3X**sjs5-WC6t4TYpS$Ey8COt5uIwgvX=E+K?-}*?bq=0>vHwBMtYWs zUsbDUCBQH^)PXw#EEi992$;;J711%*^K-+0h?dc8i$=JzhTZD5yDilibu_NKkGS$z zagN7|el*2Io4oV>BAIWav=6@f5ol13>J^wxP$qnRg=vu&*)%}py@;~NeW{QUc2J(d z%T4Tubt)*QJyRg<)8!)6cpjQAf`nlo=3uBK8FvXYJ0i{A05PGWFKwFRBa^5 z`-P*wj3lvXJ?{0?j=o#>GA+=$T5mqt$gtV(ijjt{HS8p6STknUa-t4bHNs37&qzS>96^?DoPkpclE`cUc4) z%=b!uqfTEyinR6e4}l!+D+^Lu_^pDZZ#_p`$AjTGXMm;YFG7tNLKt?BGkv9104Sp?XJw)nlc_muQ7@uV zKtDY6R)hdgRHoZLP96a}_|+bnOx{MK*orXwUG7iaok8UwJDhQ^`II}GjJX}oKkViZ z{x1fEm0~C|8Cwx_vlwu3wm=E?2MV;Eo>$KR=q2u{?>bjf0nT8_2KL!ONd-#SnRE9C zgg~(AG@Z#mg+5%}-a0LwY@*KMx^3AxcbjC0otDXtDWNc#Z?5wzP;oL2oG73y|EqyOCWtu*XkrAoBHFE>GMX#Xo#XjYr13QoZrib8VwJzo& z&L&MP%GuWu{Ah=={?s6yQ*#fTo=rOyJk%3r_qP=BSR|79c*+%`TXsDy{ni z!jH{h(-_k-XCJE(muXP}8&=@MZT{RnycG+f2PdG#b8#H(J6)B{HcsiXL~$Wa1H>I^`U`rfot`yv1lN@m6MUwbZ90tKSf;ngCI{jR`s36$ zz6X>E2J-~oNv5Tf3rURqOJoht`mgf#b$8#J8q9>$$@QYfG1N-)!WBfxt&jhV*kb0X zVXvf)Fq!n+>-1UZq4EFG`Q%?dTg5jGp&^G2$@SK41QTbM5#QEE8X@&rhQ#^{UTz0T zbTINKo=bTggc5$VbimeEq#!?H1jVfoC^jIWZT;n_dKNTy4=O%@{&LG|p58sl_a4z8 zx)E=MMB8UejcClx5gTEn?vPdYvL|^|d{Yf$d)EfK!}RoJb88Vki`+LR)!Uan!2;PJ zGN$Go`YGT8vF)(_ilS6xj;H#dTE~NmG`-^l>zgOS<>{bydrNSR zD-KSwh>2#e(cN2LE;CdU_+GuCf3;=b0>{hb^=jF<|K@?yG|vV2dIMBq6B8B`^v_S` z4_Jx)M<%ts+Hbu;`B;hj>dkg6zYwMBn>8cQ1Yx`1uiSsJ*&m0-d9oTYmSlNRJdhzW zWZ4-{roH zwndbYbGyozNB(N|^dcO;kUXF}&vSOmIqA2~*ZoTg$cYP*=~^>Tr;^j~4|bw*tLq4+ z=$CW^+9wJc_m{s|ZG8G!*&F@K?RB3Y_4GW{#eZgA`4e~36sSz2AF+Pdg0+J61mh6$*uIdxA%F@lL@vspBu zk4)_n#d23%2xCbhf>@y~z>pl2eOWY?k$ybHWL7aunr3@PP)P2L+m zp?-B>{srDDe%BfR=%@A7uFFOdzHWK)6)R|ym)`-2NCG7pu$j4-<-J$g&=?8B`aR$KCq}D)VWrmwg7YwQOi=~Dv z;WG_B^>@}IKnF)~5g$SN1BUCekS&fZZC2 z8OwFE*9>uZ65sq~%o^kns7H51>uvJjc|DuIIJBS$_4MmC~HnQ$-jX@pH_h4ZiHz(Vu6u&% zsi|v$%lFgEwyJj-ifF=nR#_7tHKcuAeN^LMbR`0{vhn6Ka;cKnsJ+*#lA;oHkLx7V zZGb)l{GJ{><8`$tpQd`?+$A;Ais4ufGIgE|YunuwJ^tQAJMU|!DpcDc1jvt2qb4FA{DnIm+QVR{qWVQ1 zZ)W-9qTmK_#%ns#kVL<)dU@I9ZcYV{*S4;bATWjO(|}m%OmZWRM?c5{hIr_C42$DP zKE&>$`mbF?QFvGC48sVl-u`o-kVV9;sj+E7yAg-fhTSQcsR3jItFqT=g*V?y()F=I zZxw8pOK|_Mw=qewQ#~L<+(q9T@JhGKV)Z@2&^RL zhQGpRd|3O_MFC1E4sncSPWIDv1}YlHulxGNU*>8^=tTZeS581-0#`;0PKPGt?>Q* z?bVbHTOZavB100aVSrfL70$4CJ4ixua^s-gT(8Tf;*+m&M32(Vx6_i5>>1Duy2i`* z#_ZZ2biEcE@>I1xM3ry2<2jC80#*Eg48Ys0p=4pm4do+L7fWTDMomx;cBm6BlYl^z z3PM|iKs>UErLkb}{SKS%dlmL{5L)G3Zkz57g{s%q>Ol|6r#iB9&R!gioUeW}-%!wb z&TadIf>@A(NtxKc*M=|rJ+XRsba#It_gQZIv^=^@LWJ*84L!fENR*!Pd3{y%mx*>F zTaW8d?_Uw)Ac=qg#iQiV@QQ1d3rYHHcWpuR9k|I%@?S}OxWH`Tfnh=QO1>4(l!dTa`B{YRnS?-*Qk1*lWq&HNf%mVT`DMz zjn$&z_IXrlo>^~=*|>dFPzOu7;>h%>(K^eh52D$kttpqzANgS44I z&IfhS+A~;#blGzajnIFIg}~sghkBa42?J&@P<)Z|yhpZ91FbzkJp26B(D2~Luo$wz zeB1p+eunn(+#WO@A7|tYWBSXfVpLLJ>)!={J*3;XKe*vkyORxmv5^d7Mc@se-qAzIiGX4QE}4TSe= zS(K0?bjB-ev;jwZ4$j|75?7qGRCE2fV1b^#Tk7zZXOl#&o6V7X7M>2k)~{Qn2qG<} zShDJ6GB0lUxHuoA^Av2^s=`Go&Q zv@WB3Q9fNHizEH}FG_vDc6gH~mG=L@J=yV}!MM;LdHp}tdnr=|G$=Z$SjtJvoh6R{ zFWxv6>ARRM^zarl5Bm?emX8ZwEkHHbsKd$d4?HDA0U;=td($CS`oD0ALZmNByn@$D z{>?wI1ivE*F@TKoBD_xGAGC>b4ha0eqWu0()fK;I@wr#L^LnEb-k$dj%id_ZG>1=F z_A8>sP?AI7_H>DY;0U?m{w-3x>s9}!w8Z^INS%4-VGX{7>yOm$qRvLYE++YeI=I8= zeq`uVv*tCW5>Qr5J$=&X$TaYV{qzr{D1qyj3_=&4CVxsKP$xKQNO-+Ht+-6)U}l`myrV?KG9d?1K+zoRAEmeKKs^jY~mw^Gq+p&i7oG@72kI9RhL%(^7nYc9uphU1gCR+EO)o8vP zt+#X7QlSl<7qbnT0Lm-c++;Y>wxpQGq#B=7S#g4_yvJLb_Je5Ks1Kww{%}m2e4JXg zsR_Qy{C1DG!7;Xt^4ttA(t)qCu!U36H_v=XIpMjB?0SyH6r+#mA=y7FXS1^Hw(4zM03 z=Dh|#2@IJy-_1u@dB1&yY2)(J;P=;;IdJSCW=bMwSe9;IQFIP#2#ieK`p9kkvKdZ% zgXb~*YoR!lF+TN^Xz9I%_zfFgt?6Zv6SKPp-@ZC z4yIK%UG~5igMcLYjeT82+Sfx{N&?(CuFmIJZLN;g&#bPKv1O2Tf#PF7UR^}P9o;)b zWy2zO(GNC`L+I3`=t@-zKhmekT?4|{mCa;&zEGH|doF+&DhEeT&fa1JSC$p&tuO)Y z8XOL;#gzF-{c|Ul(bV%NySqZ1JGbt~7wcSH(=Hp8`7t)*c~azGjGy#}!+Zfo(@8X= z;&V?%Nd-S>Cnm3Iv>JMzV*|(w%;FSDC&DX7L5T6%Sc^u13e$CpEUWeMj+o3Z>y~Oaw$+X0g4MRu_i9 z0BNPPJdPNgaJ5=vf*U};nyB_4uFLn=C%qVSk9r2Wk?iVl%*6mw=ePGD&7@6D%`NAOgvbGos@bhGcU&<#^0S66nkJGtby*YH@6EU~%x38lp&up3KF@CL7WV$n>IEu;-Lm9T2vXw? z4%en@&zFf*Z`9PmzKw+;gy`H9IgGVseG`&1-p?l}W2)5*ripf)M$a*TLIl4%9GT*P z5WTr#rL~&dr7n^9?QAMHH*Ipntk)!+&qNdJ0&HA?Nuf7WP2iD5y`keHdfre8HNJEj z4UlfLn$OSK1!Pdvx0Nx=qvER-;6TKA*rYN)-|?6qAZ8d-v{lSo3U zn5V-LwxR1`0Rm+zY3L4!;#$esmyoiOQoI&G=V!`>V5BSOz&E%EOY~OmJvsx_LhE_v zgyWjA!F{@Uti|KG6h*T7vi$oYopJ?rG>6S*6SnOXAsmc4=H3so)b-qw7|+|}pn+yy zj%Fvs{BpDDrm$(x*S868?e!%AzSpM2X${4xp$Jk-*{X<7Qi*o&1CfFZW&oNz_U%L~ z4xy~dr3)3M2lt`dw*p$p$JWlXY%Yc(@u9XaXi;s$%fU=(9Hj@DszRrMAnz3*WmNU%1<^t$PfP-79p1CY-RC+8n0C9B0q@a6nTAxmd4$$ z<6!5Og(;G1WXYzVbc-qa(&FPoU#__)tDfa^&t0OLqg&>CT4$=AK;K!Gt?7`mab5EX z!Lpt|01^>0(W#DBqa(w;TF<&}q_y*L2g?5XbkFJN1*=@rEDdRY=HSLHbj%~lE;bmEkk{`9T7`AqR? zAgfNZn5hRP>B0S(pGNq=s)*WXKlnvf*^$h(pc7QNlOBamZmjChm6a(%v0O(cne<{| zPn(jvNfL+neM9T8(wu0r8Loa`i}v7ZIz(&zxj!RuXZ4xNQGv`SuW!NIp4Hc9FlY5d z#@;znH!ERfMK$>(ZM;|jIaBRx=BSa@)0TUS=Pd5BPv6G_+v_SWb5WWDuLI7M?fV4Z z$0WKew*ZLrL_NR1%T$`iPv-y0RP@_-b5*-#%V**VBOJv zlk!}%7|p?Cf>AQQhzlZYCev*5oV=boD;>mi`WS@RzG>#uRS4bFbrrevo1aLo53x5~ z7#)eA*Vf*cp0#KVu*m4fYjnQLCwRyWUNiG&xCWa8bgksV^rzN>9S9fMZNQZGm z^6Fd${IIsz7AMo)rKmU)4DEIYSo4-jff(wU^zUSa(w(eqr6`suR|OjP?-1; zg;e49nw$B21uf}dVl$%L@Wn6D+;JPgdfwD5>4baTk4f-5Dlh4@;KgNE)w!{3@7rKS z6+M%li?q-DY+L)HkA}CePEbDKEnO&!M$T{Le!#JJtP@2adeVH(nTNws2AOheP=IBY z_oQF?>Pj)(noBibHjg23krxn^R3=uAqpA+TW)s@jIsIS{pG0jq9d>K!)xB> z<*czTVS`LuT>LLen!7oqr7F2>rWA;`LSs>LeY6`VTd>~lF#{qD8BioOJda8J#-qFHHlKn_|C`)4ZmNM!%dQ`zqW(wM z9Vj|dl!nginxp+uAeHlE$+cW#BzX+t4RA;-0V1&(1?MtiV+D_njvQC48s$MgLwgjq zO|lIzN*TJOR6x{juk1=Lt}-gfl1qGUFcoNY<_w@txXS{^Z18M+a(D+?=b@COt9r{< zv9S&scC4xv(7)Cp{J3_ZLuN9WGJ<3@b=5agZ*1_@wOsGh_`S5ACzS$NZco#RU}96n z{S_N4v^K#r1>|b+7zo2jG{22_2}DObe7(VavXb9VAnj?`u_>&`IjP_XdVa9z7aCBr z;@P?}67gcE(&3Gfxljyglr$;*=J+MigWs_3UL-_x0pAsi4t23+1_+ zgs{X5NffK0+Tb!*8|^317D$$gbD3bY&xkt1%sDpgQX7jE9^#3{gs=Xs6b-6yAL3cb z<;8*yWB@x`+Pn4hv_!NIvWNsL8K!noGQ;XK+E z)wgbe>uv`G@Si4sZz5|1x1+>^mdhAIpI5scXAL?KFPIVZ`ww~=U!L#s_DQPZS0CLVa zP#}>`qu^RPjaAwzWPSpVw6=HX_Gku!qXk5J#IVC-vrdnJ>pOXS*eI0cdsECWR;H^n zwtl%k6VbWoc(La5_kR|NCM<8zNP~rQ=F}6#{F#{;1doNbd;=orEg=LLlCViO%H zSfN*B_g@gYi%z;0{;5{cmR=mdkJ4?mmw;W)NM1pBxC@F&CUzM=*du3W?s1{K#-#}{ z=Z2~0s!t5c_GK?qYt?Aq?R+-Q&)VPF4p05&Mg?Ym^zCC0hD)Gn=RT?~B1vbSgMGC3 zJd15Tb#S2C;&AUni+`?^Oye0W_I5|sf=>EQf!^E<#uZoxd>VNrrL^4n^WTtwei#+RCVquXqBv%wJ>)A{*41`-c( zue5j-A?Uz@y5YZ|cqy<`>{Z7ZX$d^A@*b~;wZh!$vcRMxHIoeC#c%1!$)*#Sx6ghs zgxSG}c+~!r{uH@*td`kH+U}wJ3WRREsODqu^_(u}_;sM&!0J8h-QR9E`?r(dk&Acs z$I@U^13{E7ahy3puGrLLn;(I^0jnUhh9D7e3K4lfe)a+p>;Pz&Acp9SQIZyBowvho zAT0W)B|)`G2=M6QABEI{Fc2`(!6|LYH<_w&Gp$waPi#Jj(6(cpql}6%7>i;Q8=pD!z}!&p|si*TIaeX%@VZ|9=ZZ$txqJayAz0CV)7oDAPY zFhek2t-4?cNp28t)lhc6+;pYE>K4Q+{)>A18rEZvv|ZW!=UW36)gIxukdJ1Ge6QUX8?&(r2$s%LhiF{_pu-(Z-$z};kuinb@pQ0?xRFDL1uX0S)_$P^Px;c|FJS6A$ znmHBIx7M?bOe35~5!kuIL~{_FDr6FPBfW8&)LxUr3+g9XSw_5^7X>*!WMn9Q!tat! zHe`t^SE|LISd7vyPVc^QKH^&v5tf9$*bNm?t9tj{z|^mEcn*G>z3nFRmL8y2XjQo3 znRj3HkT3tmWprFXK6O`4Go^7VK2KZ8B+z_RhI@OC;1dCzg`w|xeUn>cM1hC$;AX}0 zR?St_a_!}8s}e)d{C08t3|3!6nEQkNd=2UqtI=ic4 zuYmEy6bWxMb?hq};>bbv(sbqFPKkM8p4EZtjsw40i5^Q9 z`KDpt6l3)CDz_G1Tk75xJHQ>4wz7!@;ZDIiyH2&o4$YLO&i9M%6U8rDEq6u9@I8!0 z-9;#M$e#pw8RMa}{Be*|&QzRMMWoATLIv4QoOiQ7l<;)%eteoPQ)9|6?~cVhb>GZ` z7U@y7Zn_u$>YD|n>*Rz1q1y(fW!%QvBTvmA7^E?=y=x%{+*LzWE4o74FM=)f?TY!8 zW1<9&K0dbJtsDp|4-5vQlv0U)q0?IE6(YZDd)+D3M;Nhwx>s*VyR|0AvmR!gt}DfR zN)a671f_+fZrAG(ie82H#rw3(?}XE9I*S;hhN<4qtVr$Z$q|r<4cV;LB^?f|uEJf= ze^rl4RIKh&4Ko|K4o0l`sW;sT^nUefZVf5K+m6xZ&2-OHr!sValPym#?HVWdB(@#q zq=^wUxAb^V?_9b$VnJLg=;7mAU60N{*LqNItU<8B?+VxYI7<4)OvEWg6#fG*cjaKO z$^FiJaMzfwHIGMb!YX?;9jF8TNcyg|cbu4w55(TTtgQQ{ytvIvP`$Wrg2J0@0A`nXvv zA=F-Cdd|yI9hVHbIk0B^R^@Zck->Wj>FGRg%yx;oxCAXZN|5SysO-u2>b>%17`8L2 z3TBF0X;FM1^u3<}ov?M?uWJMjY3cZN`Gr`c=Yz7EB5~vldEw(Wxy-nCCrWa>3im{R zayTr*uLm^V4IAFfM28+-SLXE{+H=OQgm+C*O<~qEcVu_R%jAPo7Z7+H-cKji>Q)9K zuM&1D#>yM`W!`u?m7vU%QpIipJmYPFFVf<+>JHUdhdt1HSK=C!pWJSrN_7Um-a1Cv=^quq>@6N(?Kqu}$SzDORL;oj1z&;-AdCLZ9~to1&3qo%uUIO3KRJ<4bTm06OnpRE)xv3hEY*Y#SKUSPHF7A2 zUYsvx6bsA*miHQWbCtQ(Lij`Eg5kwZ8DJLkIj9#pJW4g!*hp&s7~hd?sI2+YJs!!w zvGnwk1zG3g(>*Q6j5F+g^+L~=MSi&Wvvel@Kvj~0fPUC}RD<)tSY4lY3mI&_7=L*H zIvMduJ!8Li#Fe5r5#{^a;#LZtUAHW-;j=X$>WE*C5W6#FUDK3hSJ>NBlJ_)8#N=w6 zgs!S}sf8lxGLo=Xw@_h&(c-A}v$WvyRPqhM$N>%xj(L(yHt%MTNuqkadGXRS+lFTz z5DXZE)jfi>3*Pagt^sCzo>`zfDp}6IyneAIe2sB2HG+WIy_E?F$xJgzyh)~o4-pH1 z)F@vPShLNB(FboE^_GOFFSOqqZZpfK*DGZnh6tS*aoQP-HsMovH^6H`B;wV?A#gcc zPB34nC=Xj0zqQq4BSBL1Y1%@ipfvqsRhT6Zr(BWE$Ahc5#5Dy133!&;4-@g|EwpO} zvKhH`6-3)5xLS2gE?P=YNKc~VMm^tkH_cvm!}S&(=G4*@fM?<<^p!&O_d)>>jSqf6 z38IjTolVjJV+CJ(T-Kt#lMyHe844n*7TyV6-P0psFh1;qSn>P zoD!NmEN*pg#R*E6vr|K1sf}ntek59BjM@ATy(ZLTZxrxm4bpa^p zb^|yie8dvOUc?ktPTi~~(#(SOP(mjIcs7QSm-s>bRE6oe4e$n%EU(R*+R2?k05kv* zJ+TmI(C2itchXtBT1r7{62@avMbEvVChtUU;&f?Joe0=Mvh`M#i5_k9lM#s3BF?;V z#%t_>C0{{75J#uFQ%m_wim-fL;kTU$t|aPqzVtsqElb6lZ8*)2t{fW!ir&;o4?a~~ zdvP2ohe)V9?xY;6X$O8?Hu3z?F2YIGhC750Bj0;) z6l=-)RDQwSs05!u(DfspGW3^U9(-FPM@+HiiOYxat}+*NELd3dYG1O;KpI3Hftb)y zi>}zNBwm5?)}r?^z$jliw;o-(!MbD7Oa?KZAC84}W}TKsVElZcA)OgfTvP5y7FhzZ zXq-p*AtCJjYc^dGC0VVlMC72;W4b#adHH-{{=lBoFk{-b?eG2`lhj!I9h3--i-dw< zYO|RJ*abWQ-;S1Q3)A!!aZfwk&YKTrV-cOL1tg*DArKM&VE0*u`@iR8f%5$y_ffV8 zF!)ui@ETPD>tX8pt{LJujDhM&@Qt5C+75ne>Yd89G!kDR%^RmKgUE|#BZSg3W~J6Z84E$-Mbpk z0O6RgYmtU`ciRWZax(P0^4WT9O7#Wd@bnORnm#sx&GaWm9Jvf0kq4vn(f*z@xF)sAUao zt|;smg=bGg^AnNJwI=SV@}OC+Y2c%lr?WKnv7+eu?n>}k%thSliQZ-yr1c;(c?&st zCTn%I_~hKwEW5mpekw6L-3WAkDXbYATllaNVWDP^#^^-IrvzJWQ=HY?!=LGYZfFF?+={U6?LA*>3)0<@Mgxl5GuI8?BIm+@{s z3U`HO<9D{-U8Imx3hM`K>tqBr2@n^EI8i_J+{BL_H)tw%?v18OH%qEa#@uNPxll%L zdSN21Z+?ebi8oL?Gf7O|HIHB1qmnS?ioc$hCG$+cCVKy|F|YS} ztEx@-Zuv`*oQy1AE?8)gKw|pye=uN_0acQ)t)YuAR;(ZW)D%!vshFt$5D`Gcf$ZNX ze-$ZzNt~m^G5xtDASuow^un)0ZR_g3-b^1K8l4VL(LLGB&SzIVTt8st z1~29KfTY$xlp0@R+t<%v=Q(Gx$#JV;grNHI4N&@0Pcf{D`TivQ4-ew6di4J-Gp_-= z!`0c{amre6JKyQWMd?tcB>9KN1FAvhmnQ`q2R{c#f}qbmVFF47!C@%hsE~@1KuAG{ z{2|W!g0AVF?s(!VL%81+!h|4V+rY8k6}SJz#ri8a9%!& z8^5Q?&!U+`r;!*N8*5AbUwvN$cI^u>oV=Ezn2k$vwVpyfo5}qGgH0Km4H<@7pae>Z zHV{K1qW;?(F2j7arx|17j5cv)b^%6Q=5nJ6#zsbwf5yhz6Oud?)!7|reiTG_J}n}| z{>KpjzN8SU<3r=)tgoQ5e*aYnr=qf!{`FL6s=`eEAIo;6 zh91!b(#@Fvc2RhUvL^N(F8_m@4Y~Q$(MBQYX4^Ue*my#yUcPq_7jdL&>XhGD@W+zO z9>aX5;ddi+%B;YDA79XQ6%Ez|#tz;D&JNK8!4BCJfMpNy`<-aOnojJ>Qg94(@&=f= Mu#8ZJpsxS_1AJc%;s5{u diff --git a/version/105/frontend/img/trust_ger.png b/version/105/frontend/img/trust_ger.png deleted file mode 100644 index e42821b06709e8f4371c66cfb5759d00df0e1afd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15352 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 (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); - - - if (isset($model->kZahlungseingang) && $model->kZahlungseingang > 0) { - Shop::DB()->update('tzahlungseingang', 'kZahlungseingang', $model->kZahlungseingang, $model); - } else { - Shop::DB()->insert('tzahlungseingang', $model); - } - - 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 - */ - public function preparePaymentProcess($order) - { - $logData = '#' . $order->kBestellung . "" . $order->cBestellNr; - try { - if ($order->kBestellung) { - $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(); - } - } - } catch (Exception $e) { - $this->doLog("Get Payment Error: " . $e->getMessage() . ". Create new ORDER...", $logData, LOGLEVEL_ERROR); - } - - try { - if (!array_key_exists('oMolliePayment', $_SESSION) || !($_SESSION['oMolliePayment'] instanceof \Mollie\Api\Resources\Order)) { - $hash = $this->generateHash($order); - $orderData = $this->getOrderData($order, $hash); - $oMolliePayment = self::API()->orders->create($orderData); - $_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($hash)); - Shop::Smarty()->assign('oMolliePayment', $oMolliePayment); - if (!$this->duringCheckout) { - Session::getInstance()->cleanUp(); - } - header('Location: ' . $oMolliePayment->getCheckoutUrl()); - unset($_SESSION['oMolliePayment']); - echo "redirect to payment ..."; - 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'); - exit(); - } - } - - /** - * @return MollieApiClient - * @throws ApiException - * @throws IncompatiblePlatform - */ - public static function API() - { - if (self::$_mollie === null) { - self::$_mollie = new MollieApiClient(); - 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 string $msg - * @param null $data - * @param int $level - * @return $this - */ - public function doLog($msg, $data = null, $level = LOGLEVEL_NOTICE) - { - ZahlungsLog::add($this->moduleID, $msg, $data, $level); - - return $this; - } - - /** - * @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(), - - 'redirectUrl' => (int)$this->duringCheckout ? Shop::getURL() . '/bestellabschluss.php?mollie=' . md5($hash) : $this->getReturnURL($order), - 'webhookUrl' => $this->getNotificationURL($hash) . '&hash=' . md5($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 ($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 ($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; - } - - - /** @var WarenkorbPos $oPosition */ - foreach ($order->Positionen as $oPosition) { - - // EUR => 1 - $_netto = round($oPosition->fPreis, 2); // 13.45378 => 13.45 - $_vatRate = (float)$oPosition->fMwSt / 100; // 0.19 - $_amount = (float)$oPosition->nAnzahl; // 3 - - $unitPriceNetto = round(($_currencyFactor * $_netto), 2); // => 13.45 - $unitPrice = round($unitPriceNetto * (1 + $_vatRate), 2); // 13.45 * 1.19 => 16.01 - - $totalAmount = round($_amount * $unitPrice, 2); // 16.01 * 3 => 48.03 - //$vatAmount = ($unitPrice - $unitPriceNetto) * $_amount; // (16.01 - 13.45) * 3 => 7.68 - $vatAmount = round($totalAmount - ($totalAmount / (1 + $_vatRate)), 2); // 48.03 - (48.03 / 1.19) => 7.67 - - $line = new stdClass(); - $line->name = utf8_encode($oPosition->cName); - $line->quantity = $oPosition->nAnzahl; - $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 = $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->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->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 function optionaleRundung($gesamtsumme) - { - $conf = Shop::getSettings([CONF_KAUFABWICKLUNG]); - if (isset($conf['kaufabwicklung']['bestellabschluss_runden5']) && $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 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"; - } - } - - /** - * @param Bestellung $order - * @param string $hash - * @param array $args - */ - public function handleNotification($order, $hash, $args) - { - Helper::autoload(); - $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); - - // GET NEWEST PAYMENT: - /** @var \Mollie\Api\Resources\Payment $_payment */ - $_payment = null; - if ($oMolliePayment->payments()) { - /** @var \Mollie\Api\Resources\Payment $p */ - foreach ($oMolliePayment->payments() as $p) { - if (!in_array($p->status, [PaymentStatus::STATUS_AUTHORIZED, PaymentStatus::STATUS_PAID, PaymentStatus::STATUS_PENDING])) { - continue; - } - if (!$_payment) { - $_payment = $p; - continue; - } - if (strtotime($p->createdAt) > strtotime($_payment->createdAt)) { - $_payment = $p; - } - } - } - - JTLMollie::API()->performHttpCall('PATCH', sprintf('payments/%s', $_payment->id), json_encode(['description' => $order->cBestellNr])); - - } catch (Exception $e) { - $this->doLog('JTLMollie::handleNotification: ' . $e->getMessage(), $logData); - } - } - - /** - * @param Bestellung $order - * @param string $hash - * @param array $args - * - * @return true, if $order should be finalized - */ - public function finalizeOrder($order, $hash, $args) - { - $logData = '#' . $order->kBestellung . "" . $order->cBestellNr; - try { - Helper::autoload(); - $oMolliePayment = self::API()->orders->get($args['id'], ['embed' => 'payments']); - $logData .= '$' . $oMolliePayment->id; - $this->doLog('JTLMollie::finalizeOrder
' . print_r([$hash, $args, $oMolliePayment], 1) . '
', $logData, LOGLEVEL_DEBUG); - Payment::updateFromPayment($oMolliePayment, $order->kBestellung); - return in_array($oMolliePayment->status, [OrderStatus::STATUS_PAID, OrderStatus::STATUS_AUTHORIZED, OrderStatus::STATUS_PENDING, OrderStatus::STATUS_COMPLETED]); - } catch (Exception $e) { - $this->doLog('JTLMollie::finalizeOrder: ' . $e->getMessage(), $logData); - } - return false; - } - - /** - * @return bool - */ - public function canPayAgain() - { - return true; - } - - /** - * determines, if the payment method can be selected in the checkout process - * - * @return bool - */ - public function isSelectable() - { - /** @var Warenkorb $wk */ - $wk = $_SESSION['Warenkorb']; - 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 { - $method = self::PossiblePaymentMethods(static::MOLLIE_METHOD, $locale, $_SESSION['Kunde']->cLand, $_SESSION['Waehrung']->cISO, $wk->gibGesamtsummeWaren(true) * $_SESSION['Waehrung']->fFaktor); - if ($method !== null) { - $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; - } - } - return true; - } - - /** - * @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 (ws_mollie\Helper::getSetting('paymentmethod_sync') === 'N') { - return; - } - $size = ws_mollie\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::init() && 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/105/paymentmethod/JTLMollieApplePay.php b/version/105/paymentmethod/JTLMollieApplePay.php deleted file mode 100644 index ecf20a8..0000000 --- a/version/105/paymentmethod/JTLMollieApplePay.php +++ /dev/null @@ -1,8 +0,0 @@ -assign('profileId', trim(Helper::getSetting('profileId'))) - ->assign('locale', self::getLocale($_SESSION['cISOSprache'], $_SESSION['Kunde']->cLand)) - ->assign('testmode', strpos(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/105/paymentmethod/JTLMollieDirectDebit.php b/version/105/paymentmethod/JTLMollieDirectDebit.php deleted file mode 100644 index ce0441d..0000000 --- a/version/105/paymentmethod/JTLMollieDirectDebit.php +++ /dev/null @@ -1,8 +0,0 @@ - - {$oMollieException->getMessage()} - -{/if} \ No newline at end of file diff --git a/version/105/paymentmethod/tpl/mollieComponents.tpl b/version/105/paymentmethod/tpl/mollieComponents.tpl deleted file mode 100644 index 6b7693f..0000000 --- a/version/105/paymentmethod/tpl/mollieComponents.tpl +++ /dev/null @@ -1,101 +0,0 @@ -

{$mollieLang.cctitle}

-
-
-
- -
-
-
-
-
- -
-
-
-
-
- -
-
-
-
-
- -
-
- - -
- -
- {if $trustBadge} -
- PCI-DSS SAQ-A compliant -
- {/if} -
- - - - - \ No newline at end of file diff --git a/version/106/adminmenu/info.php b/version/106/adminmenu/info.php deleted file mode 100644 index 292064e..0000000 --- a/version/106/adminmenu/info.php +++ /dev/null @@ -1,64 +0,0 @@ -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 "
" . - "
" . - " " . - " Lizenz Informationen" . - ' ' . - '
' . - "
" . - " " . - " Update Informationen" . - ' ' . - '
' . - "
" . - " " . - " Plugin informationen" . - ' ' . - '
' . - '
'; - - 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/106/adminmenu/orders.php b/version/106/adminmenu/orders.php deleted file mode 100644 index e34ac14..0000000 --- a/version/106/adminmenu/orders.php +++ /dev/null @@ -1,154 +0,0 @@ - 'danger', 'text' => 'Keine ID angeben!']; - break; - } - $payment = Payment::getPaymentMollie($_REQUEST['id']); - if (!$payment) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; - break; - } - - $order = JTLMollie::API()->orders->get($_REQUEST['id']); - if ($order->status == OrderStatus::STATUS_CANCELED) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung bereits storniert']; - 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; - break; - - case 'cancel': - if (!array_key_exists('id', $_REQUEST)) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; - break; - } - $payment = Payment::getPaymentMollie($_REQUEST['id']); - if (!$payment) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; - break; - } - $order = JTLMollie::API()->orders->get($_REQUEST['id']); - if ($order->status == OrderStatus::STATUS_CANCELED) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung bereits storniert']; - 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; - break; - - case 'capture': - if (!array_key_exists('id', $_REQUEST)) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; - break; - } - $payment = Payment::getPaymentMollie($_REQUEST['id']); - if (!$payment) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; - break; - } - $order = JTLMollie::API()->orders->get($_REQUEST['id']); - if ($order->status !== OrderStatus::STATUS_AUTHORIZED && $order->status !== OrderStatus::STATUS_SHIPPING) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Nur autorisierte Zahlungen können erfasst werden!']; - break; - } - - $oBestellung = new Bestellung($payment->kBestellung, true); - if (!$oBestellung->kBestellung) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung konnte nicht geladen werden!']; - break; - } - - $logData = '#' . $payment->kBestellung . '$' . $payment->kID . "§" . $oBestellung->cBestellNr; - - $options = ['lines' => []]; - if ($oBestellung->cTracking) { - $tracking = new stdClass(); - $tracking->carrier = $oBestellung->cVersandartName; - $tracking->url = $oBestellung->cTrackingURL; - $tracking->code = $oBestellung->cTracking; - $options['tracking'] = $tracking; - } - - // CAPTURE ALL - $shipment = JTLMollie::API()->shipments->createFor($order, $options); - $ordersMsgs[] = (object)['type' => 'success', 'text' => 'Zahlung wurde erfolgreich erfasst!']; - Mollie::JTLMollie()->doLog('Shipment created
' . print_r(['options' => $options, 'shipment' => $shipment], 1) . '
', $logData); - goto order; - - case 'order': - order: - if (!array_key_exists('id', $_REQUEST)) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; - 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", [ - ':kBestellung' => '%#' . ($payment->kBestellung ?: '##') . '%', - ':cBestellNr' => '%§' . ($payment->cOrderNumber ?: '§§') . '%', - ':MollieID' => '%$' . ($payment->kID ?: '$$') . '%', - ], 2); - - Shop::Smarty()->assign('payment', $payment) - ->assign('oBestellung', $oBestellung) - ->assign('order', $order) - ->assign('logs', $logs) - ->assign('ordersMsgs', $ordersMsgs); - Shop::Smarty()->display($oPlugin->cAdminmenuPfad . '/tpl/order.tpl'); - return; - } - } - - - $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('ordersMsgs', $ordersMsgs) - ->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/106/adminmenu/paymentmethods.php b/version/106/adminmenu/paymentmethods.php deleted file mode 100644 index 1782978..0000000 --- a/version/106/adminmenu/paymentmethods.php +++ /dev/null @@ -1,60 +0,0 @@ -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/106/adminmenu/tpl/info.tpl b/version/106/adminmenu/tpl/info.tpl deleted file mode 100644 index 77a48dc..0000000 --- a/version/106/adminmenu/tpl/info.tpl +++ /dev/null @@ -1,96 +0,0 @@ -
-
-
- - - -
-
- - - -
- - {if isset($update)} -
- -
-

Update auf Version {$update->version} verfügbar!

-
-
-
-
Version:
-
{$update->version}
-
-
-
Erschienen:
-
{$update->create_date}
-
-
-
Changelog:
-
- -
-
- -
-
- -
-
-
- {else} -
- - - -
- {/if} - -
-
-
- - - -
-
- - - -
- -
-
-
- - - -
-
- - - -
-
- - - -
-
-
-{if file_exists("{$smarty['current_dir']}/_addon.tpl")} - {include file="{$smarty['current_dir']}/_addon.tpl"} -{/if} \ No newline at end of file diff --git a/version/106/adminmenu/tpl/mollie-account-erstellen.png b/version/106/adminmenu/tpl/mollie-account-erstellen.png deleted file mode 100644 index fc1819255ef725fa214cf2bf028cf3428794ecee..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 38998 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 -

- « - 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} -

- -{if count($ordersMsgs)} - {foreach from=$ordersMsgs item=alert} -
{$alert->text}
- {/foreach} -
-{/if} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
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

- - - - - - - - - - - - - - {foreach from=$order->payments() item=payment} - - - - - - - - - - - {/foreach} -
IDStatusMethodeAmountSettlementRefundedRemainingDetails
{$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} -
-
-{/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} -
- - - - - - - - - - - - - - - - - - {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} - - - - - - - - - - - - - {/foreach} - - - - - - - - - - -
StatusSKUNameTypAnzahlMwStSteuerNettoBrutto 
- {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*} -
{$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} - - - - - - - {/foreach} -
- {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}
- - diff --git a/version/106/adminmenu/tpl/orders.tpl b/version/106/adminmenu/tpl/orders.tpl deleted file mode 100644 index fd1c5a8..0000000 --- a/version/106/adminmenu/tpl/orders.tpl +++ /dev/null @@ -1,116 +0,0 @@ - -{if count($ordersMsgs)} - {foreach from=$ordersMsgs item=alert} -
{$alert->text}
- {/foreach} -
-{/if} - -{if $hasAPIKey == false} - - Jetzt kostenlos Mollie Account eröffnen! - -{else} - - - - - - - - - - - - - - - - {foreach from=$payments item=payment} - - - - - - - - - - - - {/foreach} - -
BestellNr.IDMollie StatusJTL StatusBetragWährungLocaleMethodeErstellt
- {$payment->cOrderNumber} - {if $payment->cMode == 'test'} - TEST - {/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)}
- {if $payments|count > 900} -
Hier werden nur die letzten 1000 Ergebnisse angezeigt.
- {/if} - - -{/if} - diff --git a/version/106/adminmenu/tpl/paymentmethods.tpl b/version/106/adminmenu/tpl/paymentmethods.tpl deleted file mode 100644 index 4c37e02..0000000 --- a/version/106/adminmenu/tpl/paymentmethods.tpl +++ /dev/null @@ -1,97 +0,0 @@ -

Account Status

- - - - - - - {if $profile->review} - - - {/if} - -
Mode:{$profile->mode}Status:{$profile->status}Review:{$profile->review->status}
- -
- -
-
- - -
- - - -
-
- - -
-
- - -
-
- - - reset -
-
-
- - -{if $allMethods && $allMethods|count} - - - - - - - - - - - - {foreach from=$allMethods item=method} - - - - - - - - {/foreach} - -
BildIDNamePreiseInfos
{$method->description|utf8_decode}{$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} -
-{else} -
Es konnten keine Methoden abgerufen werden.
-{/if} \ No newline at end of file diff --git a/version/106/class/Helper.php b/version/106/class/Helper.php deleted file mode 100644 index 8f4772c..0000000 --- a/version/106/class/Helper.php +++ /dev/null @@ -1,311 +0,0 @@ -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(); - } - - /** - * 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/106/class/Model/AbstractModel.php b/version/106/class/Model/AbstractModel.php deleted file mode 100644 index 5638700..0000000 --- a/version/106/class/Model/AbstractModel.php +++ /dev/null @@ -1,7 +0,0 @@ -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/106/class/Mollie.php b/version/106/class/Mollie.php deleted file mode 100644 index 9e5520e..0000000 --- a/version/106/class/Mollie.php +++ /dev/null @@ -1,508 +0,0 @@ -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; - } - - switch ((int)$newStatus) { - case BESTELLUNG_STATUS_VERSANDT: - Mollie::JTLMollie()->doLog('181_sync: Bestellung versandt', '#' . $oBestellung->kBestellung . '§' . $oBestellung->cBestellNr, LOGLEVEL_DEBUG); - $options['lines'] = []; - break; - case BESTELLUNG_STATUS_TEILVERSANDT: - $lines = []; - foreach ($order->lines as $i => $line) { - if (($quantity = Mollie::getBestellPosSent($line->sku, $oBestellung)) !== false && ($quantity - $line->quantityShipped) > 0) { - $x = $quantity - $line->quantityShipped; - $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', '#' . $oBestellung->kBestellung . '§' . $oBestellung->cBestellNr, LOGLEVEL_DEBUG); - if (count($lines)) { - $options['lines'] = $lines; - } - break; - case BESTELLUNG_STATUS_STORNO: - Mollie::JTLMollie()->doLog('181_sync: Bestellung storniert', '#' . $oBestellung->kBestellung . '§' . $oBestellung->cBestellNr, LOGLEVEL_DEBUG); - $options = null; - break; - default: - Mollie::JTLMollie()->doLog('181_sync: Bestellungstatus unbekannt: ' . $newStatus . '/' . $oBestellung->cStatus, '#' . $oBestellung->kBestellung . '§' . $oBestellung->cBestellNr, 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; - } - - /** - * @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); - - $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; - } - - $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/106/frontend/131_globalinclude.php b/version/106/frontend/131_globalinclude.php deleted file mode 100644 index 514cbea..0000000 --- a/version/106/frontend/131_globalinclude.php +++ /dev/null @@ -1,84 +0,0 @@ -cNotifyID; - - if (!(int)$oZahlungSession->kBestellung && $oZahlungSession->cNotifyID) { - // Bestellung noch nicht finalisiert - $mOrder = JTLMollie::API()->orders->get($oZahlungSession->cNotifyID, ['embed' => 'payments']); - if ($mOrder && $mOrder->id === $oZahlungSession->cNotifyID) { - - 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) { - session_destroy(); - session_id($oZahlungSession->cSID); - $session = Session::getInstance(true, true); - } else { - $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(); - - if ($order->kBestellung > 0) { - $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: 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(); - } - } - return Mollie::getOrderCompletedRedirect((int)$oZahlungSession->kBestellung, true); - } - } - ob_end_flush(); -} catch (Exception $e) { - Helper::logExc($e); -} - diff --git a/version/106/frontend/140_smarty.php b/version/106/frontend/140_smarty.php deleted file mode 100644 index 0213117..0000000 --- a/version/106/frontend/140_smarty.php +++ /dev/null @@ -1,71 +0,0 @@ -oPluginSprachvariableAssoc_arr['error_' . $status]; - pq('#fieldset-payment')->prepend('
' . $text . '
'); - } - - $applePayId = "kPlugin_".Helper::oPlugin()->kPlugin."_mollieapplepay"; -pq('body')->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/106/frontend/144_notify.php b/version/106/frontend/144_notify.php deleted file mode 100644 index 65e24e3..0000000 --- a/version/106/frontend/144_notify.php +++ /dev/null @@ -1,57 +0,0 @@ - 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 ((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/106/frontend/181_sync.php b/version/106/frontend/181_sync.php deleted file mode 100644 index 86c610c..0000000 --- a/version/106/frontend/181_sync.php +++ /dev/null @@ -1,43 +0,0 @@ -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/106/frontend/img/trust_eng.png b/version/106/frontend/img/trust_eng.png deleted file mode 100644 index 3d0177359de7fa93833765ac05d8b218fa1550f2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15299 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 Rmns)TMnX}%M${5 diff --git a/version/106/frontend/img/trust_fre.png b/version/106/frontend/img/trust_fre.png deleted file mode 100644 index ed1a2f6f03c56f6748aac8af0352de7fc0afd3a4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17319 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 Mu#8ZJpsxS_1AJc%;s5{u diff --git a/version/106/frontend/img/trust_ger.png b/version/106/frontend/img/trust_ger.png deleted file mode 100644 index e42821b06709e8f4371c66cfb5759d00df0e1afd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15352 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 (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, $msg, $data, $level); - ZahlungsLog::add($this->moduleID, "[" . $_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; - - 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 \Mollie\Api\Resources\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(); - } - header('Location: ' . $oMolliePayment->getCheckoutUrl()); - unset($_SESSION['oMolliePayment']); - echo "redirect to payment ..."; - 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(); - } - } - - /** - * @return MollieApiClient - * @throws ApiException - * @throws IncompatiblePlatform - */ - public static function API() - { - Helper::init(); - if (self::$_mollie === null) { - self::$_mollie = new MollieApiClient(); - 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(), - - '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 ($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 ($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; - } - - - /** @var WarenkorbPos $oPosition */ - foreach ($order->Positionen as $oPosition) { - - // EUR => 1 - $_netto = round($oPosition->fPreis, 2); - $_vatRate = (float)$oPosition->fMwSt / 100; - $_amount = (float)$oPosition->nAnzahl; - - $unitPriceNetto = round(($_currencyFactor * $_netto), 2); - $unitPrice = round($unitPriceNetto * (1 + $_vatRate), 2); - $totalAmount = round($_amount * $unitPrice, 2); - $vatAmount = round($totalAmount - ($totalAmount / (1 + $_vatRate)), 2); - - $line = new stdClass(); - $line->name = utf8_encode($oPosition->cName); - $line->quantity = $oPosition->nAnzahl; - $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 = $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->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->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']) && $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 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 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) { - $oOrder = self::API()->orders->get($args['id'], ['embed' => 'payments']); - $logData = '$' . $oOrder->id; - $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() - { - /** @var Warenkorb $wk */ - $wk = $_SESSION['Warenkorb']; - 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 { - $method = self::PossiblePaymentMethods(static::MOLLIE_METHOD, $locale, $_SESSION['Kunde']->cLand, $_SESSION['Waehrung']->cISO, $wk->gibGesamtsummeWaren(true) * $_SESSION['Waehrung']->fFaktor); - 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 { - $this->doLog("Global mollie PaymentMethod cannot be used for payments directly."); - } - 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/106/paymentmethod/JTLMollieApplePay.php b/version/106/paymentmethod/JTLMollieApplePay.php deleted file mode 100644 index ecf20a8..0000000 --- a/version/106/paymentmethod/JTLMollieApplePay.php +++ /dev/null @@ -1,8 +0,0 @@ -assign('profileId',$profileId) - ->assign('locale', self::getLocale($_SESSION['cISOSprache'], $_SESSION['Kunde']->cLand)) - ->assign('testmode', strpos(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/106/paymentmethod/JTLMollieDirectDebit.php b/version/106/paymentmethod/JTLMollieDirectDebit.php deleted file mode 100644 index ce0441d..0000000 --- a/version/106/paymentmethod/JTLMollieDirectDebit.php +++ /dev/null @@ -1,8 +0,0 @@ - - {$oMollieException->getMessage()} - -{/if} \ No newline at end of file diff --git a/version/106/paymentmethod/tpl/mollieComponents.tpl b/version/106/paymentmethod/tpl/mollieComponents.tpl deleted file mode 100644 index 9ad70bc..0000000 --- a/version/106/paymentmethod/tpl/mollieComponents.tpl +++ /dev/null @@ -1,101 +0,0 @@ -

{$mollieLang.cctitle}

-
-
-
- -
-
-
-
-
- -
-
-
-
-
- -
-
-
-
-
- -
-
- - -
- -
- {if $trustBadge} -
- PCI-DSS SAQ-A compliant -
- {/if} -
- - - - - \ No newline at end of file diff --git a/version/108/adminmenu/info.php b/version/108/adminmenu/info.php deleted file mode 100644 index 292064e..0000000 --- a/version/108/adminmenu/info.php +++ /dev/null @@ -1,64 +0,0 @@ -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 "
" . - "
" . - " " . - " Lizenz Informationen" . - ' ' . - '
' . - "
" . - " " . - " Update Informationen" . - ' ' . - '
' . - "
" . - " " . - " Plugin informationen" . - ' ' . - '
' . - '
'; - - 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/108/adminmenu/orders.php b/version/108/adminmenu/orders.php deleted file mode 100644 index 1704bf2..0000000 --- a/version/108/adminmenu/orders.php +++ /dev/null @@ -1,240 +0,0 @@ -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) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Fehler:' . $e->getMessage()]; - } - break; - - case 'refund': - if (!array_key_exists('id', $_REQUEST)) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; - break; - } - $payment = Payment::getPaymentMollie($_REQUEST['id']); - if (!$payment) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; - break; - } - - $order = JTLMollie::API()->orders->get($_REQUEST['id']); - if ($order->status == OrderStatus::STATUS_CANCELED) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung bereits storniert']; - 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; - break; - - case 'cancel': - if (!array_key_exists('id', $_REQUEST)) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; - break; - } - $payment = Payment::getPaymentMollie($_REQUEST['id']); - if (!$payment) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; - break; - } - $order = JTLMollie::API()->orders->get($_REQUEST['id']); - if ($order->status == OrderStatus::STATUS_CANCELED) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung bereits storniert']; - 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; - break; - - case 'capture': - if (!array_key_exists('id', $_REQUEST)) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; - break; - } - $payment = Payment::getPaymentMollie($_REQUEST['id']); - if (!$payment) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; - break; - } - $order = JTLMollie::API()->orders->get($_REQUEST['id']); - if ($order->status !== OrderStatus::STATUS_AUTHORIZED && $order->status !== OrderStatus::STATUS_SHIPPING) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Nur autorisierte Zahlungen können erfasst werden!']; - break; - } - - $oBestellung = new Bestellung($payment->kBestellung, true); - if (!$oBestellung->kBestellung) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung konnte nicht geladen werden!']; - 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); - $ordersMsgs[] = (object)['type' => 'success', 'text' => 'Zahlung wurde erfolgreich erfasst!']; - Mollie::JTLMollie()->doLog('Shipment created
' . print_r(['options' => $options, 'shipment' => $shipment], 1) . '
', $logData); - goto order; - - case 'order': - order: - if (!array_key_exists('id', $_REQUEST)) { - $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; - 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) - ->assign('ordersMsgs', $ordersMsgs); - 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('ordersMsgs', $ordersMsgs) - ->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/108/adminmenu/paymentmethods.php b/version/108/adminmenu/paymentmethods.php deleted file mode 100644 index 1782978..0000000 --- a/version/108/adminmenu/paymentmethods.php +++ /dev/null @@ -1,60 +0,0 @@ -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/108/adminmenu/tpl/info.tpl b/version/108/adminmenu/tpl/info.tpl deleted file mode 100644 index 77a48dc..0000000 --- a/version/108/adminmenu/tpl/info.tpl +++ /dev/null @@ -1,96 +0,0 @@ -
-
-
- - - -
-
- - - -
- - {if isset($update)} -
- -
-

Update auf Version {$update->version} verfügbar!

-
-
-
-
Version:
-
{$update->version}
-
-
-
Erschienen:
-
{$update->create_date}
-
-
-
Changelog:
-
- -
-
- -
-
- -
-
-
- {else} -
- - - -
- {/if} - -
-
-
- - - -
-
- - - -
- -
-
-
- - - -
-
- - - -
-
- - - -
-
-
-{if file_exists("{$smarty['current_dir']}/_addon.tpl")} - {include file="{$smarty['current_dir']}/_addon.tpl"} -{/if} \ No newline at end of file diff --git a/version/108/adminmenu/tpl/mollie-account-erstellen.png b/version/108/adminmenu/tpl/mollie-account-erstellen.png deleted file mode 100644 index fc1819255ef725fa214cf2bf028cf3428794ecee..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 38998 zcmaHScOYEP*Y_^M3StQ%QFa#*T@cZCSv^`p^cKDM&gvUIY={;uM2KiX^p+?=2+=#y zd$(9+y}r-$`#tab$NPKckDa-5&pC7EoO92;GxOQ#=jw_Sw;$XF000!qN^+V203j3r zAkYI5-t?4yc1PY+_dVtHJhfb`J$=mFtpGBXF6LHHWhXNmD@`jiOFy?BE6E!!cDt8) zo_cDk;ubDWd}ja9@cBBq-f#l|k_cZ{GYbbRPpG+-jh(X;%U)wE3)Ie1ibYpg?XjAx ztd*^ulE1r^mcRN-3x5X-F-sN%94hH6ej~ui%F_($>*VO{A?_>1@?UbrZ`%KK^Rqzz zi^S7GisiqR(o=g5m348qf(r9J<+TuaA`BG~;}du)^h8XI2P*hjK$QQnD8GOZufS9B zCy&Ji1)={cEH|UMTUv{2$|?M7teYz-7F$nGS8;xRA0Hn+A0a*$cN=~IF)=az$AbKV zg1k2rydHkeo@Tzh&K|7)mLO;4Vc~A)>S^cV4E;x+JC_ zGu;@B-`C8QUx4rNKU4ZQp_*kC%R~R{WY)9xh()7B`Nw zX8mUF|Q_m?g%j{mmeb6Xcr7Y|z(SE#J)KUNcia_HJQTe|poaQ+vMnwq$> zvxlddvxSwioD|EA6h1pUOK}+mc{u_3r$|Bh$4CJIc`>A*jEF2!Oh!)hvApaPA(4Oc z%DGs0IaxV-{+rkG|MJTIN8W$J!O8VzWH~E$J8vsX1$P%G=zmRH-0nZ?BK9BU{fpP~ zKkFj%A9?w2l;Qu!x&M!||J`*HLH{)WCv-)tB-y z0|eF|rmj9_o0*wWGP8{Vk&}~?`0mdIg}7_q><9NwuiqM8JJtZ>@s}k%0N?9t4dAsi z=V=BbVM;_~bo9pN=4Jn%@%7{4KbNZn3_w-KzOkb(!|evi@>k2lmdV8cqq63f7EI5% zvHqFl*Ve70i<6TRZH<_#jkV;y8X^Jd<(<>Kyu7Q))kkmez+C)owU39V^H-J+dRC*# zW;M=Qskq$hGCn_aZ8;&5(F-l^teoh++&(zDxO!C7dvtPX>LZTF9%wTg(AjdMOGT@krWO5A0v>0eNZ`S~Ef7ft>unGO;gTO}3P z%=_{cK;nII=ijSSoTP(X&#zxQ`+IXL@7^`e(QADYvGA;@`sQ0?GtFhkVOs3%7kGMc zm|5GO1@~Hb=9`wDzUuN`Lgcilq!g@{_d}Oq`Bg5xf$z^Sx{I4~eN!&3|GRZlUtgd@ z&Ph$ao}ZuJB&M5tF9}P90e~cNWjUFbzEj&-Z-R%%a3|59ewob;6&#TjPZK?=-ZXne z7Ge58Q*->50P_7?M+e*QCNYY}IwEGDDhVhnu;qwTvBVPA4Myb}+S}VLa9(9cef}}r zW=r{z|Bn$84w@MLD*}QrBn-+y^WW8o%bh6aEy;w-c*Z5{Oupb4%}^fxF<@ z$EqytqOHZD78ByF{Hh{M&BV6{jzEEiYiHWcDHiKLRsQ$|>8n-@4UmBe6hA(n;l5YA zzg7Rv)c^hp%L`l+eXi%XWX+;apO?pv8rBGtf1O`tuK#h-(b3@&Az9N7BBiI~#-W08 z^K!-oj#K&Hgia9`o%ee9o4>6b;n?2ZrlIE60ZNk(f8KTK--d*o*u=+#d-z_q)zjIS z^72C<5PtsF_q+uB(ZRZ|Q>6yFLs9vTiei*GhgeF zWaJ`Q*XMk#^gcv(9;=<6+-QCU2&E4IfpO7q_zeqsa zRsNz?K{eJJhox7)7j@du>qH4FOY>slCfU5~Omd!Dx|Q!GJ@b`?AKDFZGNZ{=?y*Ft z&PH;36veWBTGe4@H}v<4QMASrDq?XoGHe@)(eE2iJGU3=%F}ddI(WZFo&ij08 zXe5eS?;*%zFzie>1Vpf&VgG*3wA~nequ_?~G2z{Nh$63=9gHwh<`vdQ9s^$^eT?E? zE47i%{JxaW`EbmBu8qaMetAWhusWQa&*?aSF;N^)Z%N2UQ=Bz>+B`LDr)pf%6hePK z_hZtke9YO2UEd$LIk_~C^ODS17wGfWU_SrkMg0c$4m4^hXR35qw&icNYcA~}k|e3n znlpd`KWBe|^psj#Bg|8R4etH2yaRga!!jRagc#4kr%yJK$_}=_eRPqA!$9V<9kWKnkt(qm`w5SBvI7v{U|o2C=4ak z62^I34Gwt{!Dcz?<$U=SlwPSWA?iY&N;W^-eLq1cv3WN}cmx-8lguPE{EtMtH#+m`>2ci;n$+ zgz`O&tr2;wt_m>+VgzC~rCssFF3=0a*j-njAXn556Wnf@@m@*^3 zm-Gzdrx`1p^UO+cV~6wH>b~0c=fT+^nEyM34Qcv5uI%ESQ{cXo~%nU)&@xU{ySt`&8aN5*Pi~!!ZO7R%Gw&AHhOCA*7yC9VClL83#UNqRmV5uTODa3lu}P2 zN#a;nIHSU@7My+83wic@XJcLMv%L1cDvMyW)_7MG zB*|Jo!pz8a+vCD?hfdXF%M}5Zi_#ML*@RIF4ni?PEt@RpsZiuVO!=Oc67=``61AJ) zy)ayHm(_^CxZ&t?z_WV;Fm;}nf=714szADB(=B0EEg$jLBw%FE{=o(Wapi$T%NY^0uYR-))35S`ex5J%mU zPsjE9z`nE|pLuxDg$O!7pi>sbas;OOvk`lAd`_tIm3bM{Al$}K z|GflE#jnvbRGf;^_nhIcX4%;f$d2+;8`B3ccy`=Q!Ce_!l6MuE{`3%Y>ba@T{xNRXa zDs$=YpA419eATno1{hRwf^ZL4!odVlGzFVi@Sq@J@03p@IOv;IIW=m5&7xI1tK3P) zY=hu{pONbokm$V2&4gU^%p1gWqZm$sLMdEp(gnbk?FAR;ji!40I@(b&{Y z_~=|G%KmMCV(J^Ngeu%!3Ga;}MgySj7q4XT2i2%+JkgSD7{2M1d;&k>mcE&#MIk~A zmUJjU49h(682XW)uCB}D0nb4&Wd(Fjxx-~;mA6}(&wD{|4%jdb!*LBnIr8q5?e3AB4#_9K-}M?;t}9+*pFdx>}ETN=k-}50;Pr)f<_R zNb-Obrt{@i9%%}X@)Z4&?D{de47`QS(=p_F0ti9k&o2t`PkIkw=kV9OUyH^eHX($zYHxAhnjN9U&NRcCxJksS?!t|26qSe|#SB)%&%OiR9Y%~7 zcVS`T3rm7@nCdDuO`7vjWPAPZ&MU(tQEb|kN=mFXcGU6U^+0q7E794yG3lZVX)ea- zZNmdJShGw1?Ckx>;jbZO&f*u4p?F!)K#s16l1X)iRt!IEv^mBP&Xm6was$j8gr!bCx;_5{WBw#^RHdcd?84s z)~{OozF6O8br8g6#MOhPJLt!k@8T0%jWU*jsKPP^N{f@$&DJz2lNKV%c{)dMv}_bD zq6|c|uyn9QGEa?E%Enf!a#u#U*N!CH8;k9pfwK`VJb|PO7DaucCrrq01v8dHcsc?y zP;_yTim7;UbpPu**-7t_-%#&Wxc{7}+Q0yR8riokmJL)T2DZ03i0)Xj;3~vFehS&! z6Bh~3+DCU_=uvvVml>tUc=*m0YsX@Do#v*Fgi|x+#j*5wl-~(0?%<2PPO38WK#U5h zlz+V*jRQzCBLb(cYQ~z8fuM)zSA)FDvLGITEb*0g-R)X$_-nL%k5;t`2zQaHVt7{+ z8x$-KU$oQ@J%DfuCb1|NI@SU=#=OO~ax~tKd1~f*H5lji2hP2J>HwFDVv$QYhP*(_ zof^gMLmFQP`Sqla5IJisXy&?{@R!Cfjd;nr8yx^JYK+Y+mgesVFu| zC7K?gaI4YyU zE#Ft)y%VfG2jzJ}FoI!oxJ+j}!)e>cX9@8oVloy!>7HIB^o6Z-9&r{UYqNVYej?#n zE)VRAf6`HxdCrEvluNPdSY_=fqBMy(%8jhekp)avy6QELd@x~(tJj~!_7T&lgNj-! zxeG)?`u;pv-kj?@pTwJ`t2H#61Ug-Dd_zi)6CSnSY9>jee1J4b>tsQZD3_`8^TIwW8(cL3}b`<-->JzIT>DyR~mC{m;ilP3zqUtUvY2pSWL9m6V z`SZ)2375ZBT-VLi*V{% zl~q+zr{r&vc(FuM+b0OK#14^3j2qnIUM$)*o*jJiNAY6ee98(4O#yB|b_N{FOi#3J zcKn*pWdxQVH^_v`reQhajc|gcIzcat;3g+B)kdJ3wS|Zw5lZBk7K0ElK!@vZR<)wV_8Mk}mKzuVeLI_vea zmWQ8UwZsogz9(rR6r=*{WG#1^Hk_u4iDH7pb2O-!5AC=&><#XqOM)u`-&fWa=@GL# zBE_zr*#5cs5JvB#lw=s4v44mhynHNtM%gV%1-T1P?0vd;F23H*=>EauVsZ~q>Ae-T zpPO2oPwg9A^&BofG4Io^JRLg^X05ERtDi_N!#vwQeHJ4shh#(TJ_q!`iwQA(&wy+~|1+@I}Aq0~{bSnz-tt-#&p$=B{(_+&KvqtOG<0MnJ&B2;6cK2)SFW@j4Pj1_dbO{3NFqh~hQ%N-S$>ZGOyyUS}6- z8H3315F#CXPsjN8=!z9>9BLIp-r4k{q-ttZ7n0>9JgX2Yx`+@-vY9#n2At!3NBs#5 zIxl&?`twnaT3)EF!4O11+sgz1#S2T!|vKbp9sF+!Ejv=pIP<-i$k&{Ki-D^MLrH@W{Wl{s{tLWS8yGb3jcQ#;OIzOfx+SHCEJRKNIu(tl5KF_jz zOvvgn-XWIqB9L|p|3VKQ)cF#_8*V|jY>CWpe(-CFic*Ar@XT$A3bvfVa42$(KgwyW zrL!|m@gB0T_BVKi{7}Y4jFuppCG7UDs&_&YQm0rP@QMS8FnXcEhqO`m_9?&07)9Mx z(e&Uh7-#}{lmrRUZks2T$#y?pXDEs+csr2q!pGw{{b)w@?uv4Da;}H-{Z?TuDWg`DL(aroudhpiIl$bH3U^+Ip!LB+tye<_ZWWh{^7q4(CLQ~jTe(`O zwY^Eha*Jx2&nCZ;0!7ym-o|4&uy{QwjeHY+m3w0cR4ip(L-qIX0hjll6m)jRyk!6VvayB|sCve<1O)%MdaU>c3YWeU!!|iaIc{@e&9|pZc5!jbd~H18 zLEz!fLEbx1#h+&(jD&Z+KPAg|^2lMnu2RFG58+U@#`DWTiU-E<`u(1diaD1IEK0S* z;XK?KE5A8JoH;qQ_RhN#}^P zrS}WwktT;j!B3!dj5-&Jwbs8PX)xII-|fxmLfl7Ohd;H|sAb}97D{#b`&zVq%ZnfJ zX%Iz0!@z-9v1r(L;z8Z-kvfD=m?i&wlLJgP$i45&u+xBF1#c90ggNfp*RlhMF8#g` z09j4VSh_Q_ z_`6ZidFe2(k15UWEBU?s+uwaLGif1zA}|_=ny&yt0yz58{|!-!%9Q|+D$P?fRQ^L+ z)fi_ct6ZPV3_x2Q7s$}{cq3mY=D6;cthklq@KcY<{U1oUP>#KU=ww#4stcs60uUVs z8?R#z6r?=FUq}-b{h6J}&0-3{xNDD;)fv(cgqQ5l!J6NTO}pG|t=Rw+a`iqlmzvJa zb0?{5Qe1yVHk$rAtJcdW)Hz7QbMPdcmsEa^b{)~Q1+|t=GfKCdx02-qV=3fUj>z%_ zw-}1EivxzXQrPhM&BhCLoIw(~qg$JMu@LGl8O4$z%dPfp{5)oYbB?Wu=Kc~9n-Lk>L{ONH&-YdUdR9pSRo~%O@iM!=sk?8xj2Fd>8S6^hB=hbeP z#a(x&bAyu6QSI81BrpNOPO9f2h@D|kCUR-iT!v@e#fg^Ec?bKuZNbFP<=U}T4=$&GvF6ERc3O ztQsT>s()${JoidPe8Y5T{)iw-oEqPmS?tb_jnTnI?XgBDqfk5bNoSbS+dQXm z@5T?hB4)9h(i|5w}imG|J=-Aq#in()lYd4yi8D!V1eUJg?j zziF$aY<47t2?aj|bmh-nQ&;GAOdH^4qj!sW;KYt2dUMDY4al2@Ewid5Faz(I1|E@O z*RD@-kDd%utFC+putZX%Q%8V>u#jg;r_(MD)h<1@Jb!|NOsI%4ZUILIS6?;nL2GWM z_m=m)rT~#{v@wyxzQqP~0&U<{R6LHI%m>+i8&kbEP>f}=sXR8iJR+W?$E!SU|7;!j7ifC^kwl~g zcY7Vmw8$K)98DnCzl!`B{^yp5FW>Uu7>T->g z?)EYPkTOvY?I&!9 z#jkk&zI{th6WKL0L{-a(R1Xf?Yko8zv^6w%b%NMC0FtVGEqTTs6zMZXo(K_pd-)qR z;ae2BzK>`%K6-Ux2fMxt!H8N6;baSJAG*wy{kiS7=DB1&lIE$N znEbSld?GGRs5gLk#&7tE=6&(|m@LyQgL~*F+zP5wAGUVfNEg24Ma~~eCsu!xXXy7y zRgj|RlSgBssA?_6RzG@OryW;aOH1C^O$15`-<6*PIr?U^wlI_6lw0pbnB{~n!un2c3=mcBq*%t(O$F9!K#i#A&ud) z+|rY^zqjH^qJ@g1L%@j^gAFD1_0N6ODWaIgmXty;xNo?}LOG{#l8@5I+6d&{`h_Kk zJxGJ+unQe47DBpy zE?X4JiMBPE8-mG8afbqn;(C_n-CuLigLMPWI_$7^7?=hceJ zg$fFn=r?KWO9~T;GdMagF)+(-V(5=7)Vp6M+4+kFy;Gv}h=#(m=&!dx{q}TixrJQkkDiv*?cRclkOZX_K7Ytxus+BxF|XSJhWP|Os+D| zi7wD9PMt8n_3|B=(3XB>abXpIPWd4` zy|9xjfM6Q0EU$fr9UvQR`xYa~O4RUN4PzH9bbG31Dhu2v{7vZ1#E|$f;`^^yw6vkuNmbIe(p< zuf{DxLWTabUx8e8h>}=JC_9A^sJ2SN&Nt|~`-pSVBR>j7dL|5ue?QhL3gNUfV4AOm zHSzrUEUP2E&u9?<%lc)xs%&V^)$E#d|Fd%w&0XqutzkY-9;M(HI}>!vjT?im+Fp~5 zmzy?vpDJFx=KHe!@Jd#34CN)l2l<-gzCfMc=(tI^;_+qq>WPTpEduPzcC%e=|aMs1Ef7`9AYLqTTC1Gp8%R^FVw91K*{O z(;2rSkWsJ!Qf5H+5eX%8Aa+Zal3A*mst&S7eiJlx5x zq@VCMZCx7NnP)%tb18LJg9dE*=HsB~mwWxf86Fij9Rx&cK`d+LTRr^SN?!3=kG6aW z?uyWDe;V(8%+>HhO4gdWn%w~^Y~;8rdsx=MT8WC9OIVW4(`od&68qzdeGu9{h;`64 zMiQuJjqKj@o=->-30i;sX%;cze@z)YVf>|1o(@E+ZnC3R71Q*lNP%#?;q_iH;u6c<@In-7 za-ExDKY-9Qwy&_$!GJARY>LV8$HR9G*n)o{$YUWRHkWhU9MjHoc_gH;S)caV`h@Y-H6g++g_0O-596bw5<$C^;~o$U73bWga>W-L z`8p~i7?&k}|Kh;hMuZq*=s4K?q^*5y_fAHQV<;u5Dx*(LuqYR?cE5NnI-#;BWj4H8 z!Y8{vtTpJ>80A74*!_|#F+s3hG2jTN7$g<+%hJy}!%}}BMIW(tC#3XiPPZ#;MF^u z1S-!>&Y=SJP4_LkM5j-+;o*wseFDedawwx%I8%{c!LL}~IV$MxMp_b(ojWfLXA$)sWWCuEgSj4)W9uE4Rhm%m|Nz4cC!7Lw-J*d40 zp-dkxafY{20hWJy4ETN4fCL}EJ<-?*Jsxj``{E@ZfD;fRJv49HKYYu6psw^#_?b<% zQQy%a_sL}cLOY8bWl!a5!D_pP(w|5aMqKJslI7ctg;lzHm$BajX3;$lBJ(55HJFiq zvlG-nhQXg&FAt_}WtSNXn}WD^NH+O{s294;jURKYm1-bkM-Fo(Zl2HgXpAG9B0 zJBqggwv2-NQ+fp>DXHbME4Cuzs-HE?=P;md4yl}yyf$lHE{}4q2SYF6AGKJg#sAs<=lAloniu z6rL*2W~aaF)8CP-zwjhD`|yg}n&Jz%kZ-viyT$_FrqA=p5*OGUojtX+N$yfFE?7Vp z!>Jcj4gj!xg;WB9vdjW~^X|Pga?mLGOBlwP)WRU;DIczEGY`yfK3uuAq4V+vfZB!KaJL* z9GxyZ7g+(_kfyE3bvh+JT1Vd2YD85(b}hT%6J)nU>Mqq`;5#kKgSCUReQM;P6jUyt zAJ{=B6G7R8&)h;Nz|qFM2GUUHx(=IL7&!;3H2S&3TylgHljx!hvB?IqpVxpT|9zN-2iE# zGQ|%Vl7|OBx2tx3TeSxS&n28d2nwBlvMiGo4Bq6hmMIg~d$6EjJRJ#T5Ygo4J1>)g z9V~1y3D}Pj8`w360pyC?=D}uV6IOSJ11{>N@7T%%hw?zo@R=~SY35jP!ZpC-=4<5u z7A{c5lW^@zzlty)wR&5Fak3%4E2wD?(=NB+I;Tew-JEhx%}wBEwnj*nz>BAASLA#tX`v~ydQU|NJ{ zAP;=;RQ&#YPS>tiVh;v%_yZ+AFlH(hH=y`|kK2++y9xi01$pkaSs8Ur54!XNW3&Sf zSpO2r1!Nh$vM)GmzKL|odu_bAh}NU4MH4@VVxt+O;GfisZkq&1$t#s}ivy~4FG1)> zS3<%9OPreuqzeB_r5nl>v7UrGatp}vJ)@87iX7cyLpAUSh6)Qk10UwQoqd>{r!zmp zL|@|4&}W_x5AR{EI-Fv}Vf&F@_& zYZhZxYHv;5rex35XLW-KgV9-_9>F$UO zn4slaePqkhCB4dap$;`u*Ier((N`pNw^a*X=4p6?E|?j|pO3fNpN6B)G8;&!1P8nV z%&)0h`M9mGMl}%Ems+Y2>a?>!c=PX952kYxRz~(#*pJtch0NQ(8hb}fUj#GX>F&-k zL|ukbd*?QMv#9$t&cVn8pmBK0=#c8Nv*#oqckQZKMCkq4+{^l%mETrncbt0*&Nso7 zmh}=xVIB5DrS??yE~p;1?v*!hi27a=WaNj@&g%-E@V&&2n<6gv+f9S7irFK@y+HIK zM4W*A#%I3i?Te)Y4s^?di@H!$5l|GD?7Z2eK6R%+*yuTQN_-xPF+!*8&mjW@YvAP3PBcu}82 z`7EltC}SsSH=M-V|C7{i3bDYI*x!TPkEYlDrrRSua$!zkQ4jf<7x1WlO~%4Ib_Ov_ zQra6`8}oR}{w%wPQ$?poMSeEEyi8`hGM<;0TsP?>H9XUOApPS)Y{04e7eDc|6iU+o z5Gl*YYNU>?2%j*$p~_}?9qQ7m=xf!&>Dp5WpnLcA=H|Th?QBx-}>!!dZfi!#v_*fz$D;NL8Kww}QQ?iyuryyQRHh4liQAg9eKy&D(`$Zx;sl98G6L z1_Wr(H=9 zTgOQSa#m($1LSv3g!@KDnLEPqq3i-hrLULBpx50|JY`)%O?K@ZVsC+F~uLK-z z5(~F|*Sivt`~h8)gD~a61bh~`m22M z2vQkzsbE;tiCT8yvh;?j_0}+#8O6D8KB3ueGhlo~EY0Od*9$yQrm2Fx))e=B~ewee>+&t(W&L=P3=Ac!0OU*Gx{oH1C9zI5a z;uzP%;>OhkX1TJi-b!@mvu+XqQm8nn`pca#R9y%d={Y~eFeh9q`!l#i$}squW<{mG zB=r7-kIzYQpm@RT?+V94W-oG+>sk4q7fJmMBF+deTwSw|@3aV>;P%Ty z8+bcLA1>FK8h|zjSTmm(--!)u6(BME0ibR%Cs!<`HwPAm;q(1WZrgmOd^(l96a0%rc zd27Kj`;ct07q`%8{$J4U@}ZOWAkSZ-w|kM|S&Q0UI18nHaT7<6E1a>Q;fn2MPGiCS z2++nfgZN!95F~h_w4wSK2-lOIn+Ihb8tm3RDM>Mt}t^p06|cal}Ku zEA}*rot8h^lfsSjdn7*qvqZsitEy$=VwRW8f}B^Lyu;+UoUo3m{1qj0P06b0+$>Iwk!&Rd`{cHQPwCw8tQNZ={pkeMo*@UpjKL+~0^S@g56KTdbihAQwzhiBZ3|hDm(3HjGk7_bN=&>W$042+gj0 zGf?gH^n`YS5&%@AqH1|#y z%CUvwS!d@L5~0AC6mC6&+UkVo6#UTh++l-OpNpSPub*%Y*}sY?Su->H)%W_L9)WZa z#nU36jt@zzETl$lH+`IYWMHN)l1Q zTYE@klo?m8U*NNQlca04cXHy-eDO4YA1U9z{8^wMd+Q*t-&&DTdiVNfwVRbd(*2d& zTl`AKB+c~gMo?+PWbkj}OWc}iwj?f4B{2Y{l0z4XY4I1x3mX4=XNgCb#dT9-)pMb3 zumKu^0csb;IgQeF8w`^D9@IRLRN?m)zge%apdDSW8kn93H3b;cAk!M=CV-Ycc7@MU zw8j<5+G(uuV1n)ohBj=b=UqlnYj95xRrcaP+gg*KD|_tnL_w>Tf05{0v3(Amgv&LB zguPm~qwb()prm83-g?UDJ65S*;c{KoggySyE*%sit~SEO>)QnYROKanp6esQ-%O?s zmP~P|P1EK32*paiP%5E>q7aI?kC^~u3UVjNMDI7I5v}dN< zaUh}xF!W#Pj%2M7U$AtUX|qb8c#?bP=|+Qd6hZgyr--VTiJLqF->NQxK+wj#Z6?V- z?6uLZJNJ$2O2wC89V4|5M%xM1yX!q{UeK<%Sv$X-w>#xbvS8w4Ho!A}oj}hMW0Ivz z(H^fp4iwl(4P{EmJAUAk4BI*8xWQ7MKtzb|Vb5#;~17|=tWLS4sM zRnMQ_Th+Vz5%WFAp(Dre`Q>GAYf!}*;A3WTz$N_AV%xMvXB>pGNK53k`c?E-t`GC7 zuhpqY?2=`uo{4+}^pFATA5579UG2^`j+ecqEhrNMS{af@txuZJ0xDlvM}~gMkHgk_ zdv}gDK?gTCU&);09ISrE@Ae11s6F2eqjbyk&yk~)N$UBL%}KC4=Oi<5B5&h2*tY1j zC=qq-dr9>M3N9IunIFdo8Q#2RU1S*H_~XKJ$w*AAJDjCjK18yQ?5f^*j&19qB+hSl zk^kC%v1D#AsR|{%N*ws&YG|P8*)(nWbx5lQZ=tg=WA-6PSy;ZS?mjWd_&SCCCB{J> z$YQ{tn*iu2``zH5`ZUal>#Z|3&$u{Md=J$u+)2nbPwwstq*w~tbTr%Avq`KQZV&>1_Lh-HF3A>iv_1c zfE)RFI~BzHwe+ttTyu|dAKz`&sJZeel2GX|`Lrtc$0^|MdS8YcH!zTPV==V2T#?qZ7)dl$;^*VR=<<-%$;!GGuf*L%40+;xiy%Di7{2D2sf|{p$l1F;;Tm5s(p+W-m z>J7T&fE9-3(e~XjU7zvlfD&n(ip2qZxLVJkD>i8GJd8o3}qvd2PC zF3A!^ia(xsJWzU?9C0V2tBWKp<$$FdabG$UtV!ts)zLD$q;Yuoh$29z#DTNE{t+MZ zUi0Zi5{bL=^Sy_0P%cVv@yPop4U#bY%s`}%R7p38MZLl{Yz2TMt+*5T>j-<706AZ8 zjaR}w{t>J98$G^fl5r0_M28`=Nyk$Td&YqPHXj_w+iiJz>qBIP@F$Bbt zTxb*r#$q7ZR7f5b3bd<~(hEJ`*jib|5A$Zsc{ytVi3>*M< zmJlcF&VldOgPp@}g+!?}aD;vSuBb8W&rNrYMZ5J#>1z^&fTW^=-cDElDl5wi{oy!; z65ZO(F1tLO6J?gO9fE~81}w?XvMc-%euxMqsSs~6eFR(HycUWp9xuQ06-I;ip$+Sk zEey7o6Nef#Z@H7RcdvISoBT>F#>|WGI&PXnq{OeDwp`4`JVaw8KJt*wEl!?aeffH? z_$z%|*G_v4)6Z@Rv}6zv5bm937p3GqCT)srSdbx($Zz$U`{8=kksQcM!< zxFwfTg6I99K19Y^XkN!Fcy0e!JZ*9;!nowIaP!Fnb|ZLp6cnw*@n!WjwM)i>T7HZ7 zEp1mse^|>psdbL#gx?hV@XFOtfMB}i4Muq_4m-e@S{bRL zHO{$2nsR!INa||}J5lnhS9YR2YJU9>djf{!c>5hv?AvqOGTpp6y6W08*_7+YPrmlp zySg*c0{sYYt<<;AaW_86f?^l%O7cUxO@I>B65YTN)JAFW)y3E>@WIKXumPPkVvU?^=c||mg zvo~9G!pwV%5M8vRORUouj-tO`lQb>ofIsQVRN~ zqMH@!LJhTcdD$gOfJW2mC;t7}s}6(SLMB>r!@@O`ED2i~=xO5yX|VdOm|TV0b>bv;cEUV)2O<#AFfS*u4G>BoHc}}St<^kL$tTcTXT8@c)Ma~c zr-!h^gZG#1%KZD@E(sdxIbrGUR((onzClz?!aGZe2I-;-g9-8X$k^%UyAvWc?Lf;8 z#a_Np`!TLTXFu%D_f{CE-0^d?_Cr9FAWPe?*YwP`O252z+IRpRoS3htJY9K)kN$YQ zHRErwfynL*3f*B$B#F8GdDra8d7`07pv1n*=eX>hAdy!)EL)ivE5+^R<(VjUT=cspfR6%d@El%*@#T|-kX>o_(4k_-%-HU4}4lNWf z6n87`dU8MSIpZ7eJD%tJ#yI2rI{A}i?X}mQd#%0aoY!1yUTdm9yFN0*Cx$ojgI9XY zEq%jl)FVzT9OA>0nJv|Lso|s;QxwwB^Ee?wPY8Leckg&Jm|R2){YVB~SF+g!LxM}L zE5;;SH*NcHFwlvynQE$HH zFV~g&#?Pr=$As2B04hQ<@!n4tfPFPP9g)fHS`!j)HC2Eg&c-_M!a*D3F&&^Hye>gt#NT8)H=~|-g@~n=5*(iCkx zo)p!ESV1D{PY9qdv5>!sg7USMy5+Kk+0jugj3FR&uWENq(P-f|juKUN6BXbvI406f z>5vvmUlph4Pi|9mQ||!CVH92#`wqmmdyWQ4V>TE5Q*CLg1OALfbg8g2P2p1Ebd*Vc z7$F=g30stf!5xjYCcd6a8{Ck-y!H$aMH6q8uQ?YOL-k@55d3q?G3$e8mi_Blq;5G) z=OWzH*2hWH|I)yFdT%!HpB5Bh>elO2^ZDQHk!X>$Wye4o?Zh@0aiV|DM}v>NY*x}@ zbJJ^mY^tUVN;j=<`*|@f;{B}3eU!-^{w&pA2sTLpI(Z5Z|Km|HE~&uYZq1LCm^M+D zGf?mxQ5?6I|93=_vKh71*RPuokzzk8QMf#n5v9T%j6lMTdHvSuSztkf>MJgR&qR0K zf8|8W_)FAgg2VwdyhJ0HSyHe?5X>r>&iqWTL34O0&yvTE<Dkcp zW!~(>lztB7M_+#l==s}e+)(~dsu{|ndy-KzQFm)g53N+G;`b^IF4TU&XF?Bpv6lH- z0`Tfd(ME8ENyT;MyHNq$!`@gCTel^YGV(CuC=rJ_*8b6XCFq^(dD5YWNU&K{Z&P!k zGPfyVlAR?^_nKJ_jxpG`VR)dL7uBmz(>R+{(v0)G$Vy0aL0=>gBHzr2{rbn#b%pow z;Eh}bn`|E8Ex|wrM{}0F;&EnsV}9v~?`$N~vl*vRo=@SgR%T?7L*wsJy;y}?tgtf$rZEDA8QNs^g7c`pH<%(sx5D~ zjVGgp7IV4OeU|>Zze#^7 zn}*TA6!_WsZWRJS55iav!pIL=B1au@2fTo54@aVEi^G0ggh8wkM*kFF0sIwt-3_K~ zt_uEX77L>G(na9q*%qqF?^x);|J8VaI1JTesM^`6M*mgFEN#P~waeUmfp|15n=mQV z4*RX~=Pg|~KZx6Ei*&^!4}vtyKcjE8%w{*2Uks?oaON#L8`5ngoh{PbX-b!GpMFmU zb1X=D`QYG`XWG?OTkvKPj=nB587D+J9I89|a=N1Ou>FX|U9Q6bzuwNv5tbrL?wK)h zVDn&Voa~NHf4#lJIgwvH8y{BJ+I6{J&NX3U-JQLjCBOpx5i$!qTh4g1rOk|PCNRaf z5p_mDPxuhm=cBxa^;zF-AbDDj3YkT5_|I{&om_E6X2=uq2O;~Higj#Y0c^DKq@Moo zG0|YSqjwlCSrh)TSBA&DfaAdC;xR%EE!WDpe`wW53N|9>D=BLq-HS@ZXT*Z@QNzKY zxRl4|O6*G%I1K!|XsRZNy82>MlsxWPy$nRD`2t{K^O+{E&hx!`;qm7AtS3$T|sPETbJBH zk|Ubh$3|~nd*QZrFgzD1dBD2+K6|rCqgAy`m<#KJ(O0+(^8KJrfiU!T*XoYmmK7#s ziPBNUndYP7eV7vHW^({qr#~}}{yp*{E1?l8Qx$J_cDT(aBE!^dih%hH_9sXBkZCg- zs9GsgY5Z;o-y)giAi*eUPRAQbsntmiMKo}0XFOz`cfUCdL7!yoVe8}kGJk}JoIRV# z_*`ax{iB59m#2_7>9`{dGhM0AiI6?{*r%UW2Qr#UpEBpD7V}%^y|nW#1mr*McpnzT z{}dFLkm9(v$8b{$+ew7M>u(a`VF`cr`z5@@aBjAP4L83zY z-~BbSj3R8ZC+=j@C?Ibrtc6y-8KBd9z(5`ZX-T2 zzL+XN=Mh$DHYX-fpj3QBfbzf4p;_X?{7Qnqylfp|zm>S)0MLmhAXmnj`w-*iQEBWM zn;_ny-PF+Pdp-2^pP-)CzLMM$7aLK~R1i}2s#-UU%MqVx8>R7?VY{M)715K%DXyDR`;>M*##m+!r~v{31gG z?WBYT)@%-EI-cytTZy!|dl4buVk3_&^uM@X2M)M1th7a-u8k3vIVk3_UNAW}-*n^}z_4MCCaNj&;_sC#M!5GCo(F8OnX zYuJ0>s;k}REN7y+=pF2b7-v}6JU;2H{rn~9<#_4( zi0N~?XxrqrpIf@Ir;=62fH6LV^ZHnhd$<}~nFl#4HINsbo_|9c2QTN>pS(*xyr4Fj zTzKU~BF}hSrL1spYj|lCkEhXSw4u{l+-??K=W4^kE`R?}Lp34if8)XVA1LmB3)uc| zO!sd9+yCAM{dbG>uYdpJvj0}3|C22LZ|osGv{&P|Md^8iYMD#!lCaxP`1V7|Dr5;7>a-d-#Ck5=vD zZrANQW*f6szFYO*qU-LB4V%Jfs>~tXb5}F*5U5VmWO;UVpCIQ|gCn~}_i_o#*tlI0@1;lwm#sw3AJhrEbRWa)@4UD>X^l*rCC zc)?v=Aq9W1q z>2p|(a4sn-NW^{rQR6c3$V-__LoUqK!pJ82S{k&4k<1v|f$_VN;kE-4Ao;?kG@fo_ zU(K{bmk@f9`Cci!W}B>p_mf?V$%ovi%3q5wd~|GU8mDds7rA7=a=z@s>3pPtd2+kE z_WtlU-Deg~ohPZ6mV5nK0biJfI!@E}Jml=S_?vWuYP@;yY!UsXF7J)?*71NnZ-SRZ zp(+&DkBx!+#bL-(Xd1hVoWU?SF`I{3E-49mD98?VHI56>Rot<1Hf7G`El3P*6#PV^ zSrGKeGLyZ1J?=IdeH51x?HMgwBuO`p-B16m zu&LvLcN3(C%-+^z4d$2gyM39(q4J1eB5b6-$-sZoDjwYtUr^GvN-FY?s5*OQHW#Pq z9Y&@$&-X1oevf28SA6NZP8}~Qf5~z7&Y2FPffH=f){x&nP)?mrVFHdbh)u_w>K3!j zzVHesX6zc~tai-jlHUT2?Nj1~zhl{e;dn4R7R`mip?RVc@nqaEr={%*H`n|dAB4pd z%E8XW#-vGE$|iDF4$sK~*ZnlLsks!7Q2vI~I~NMT0t*(hIx`wj(?K-i;Zgy@W~kkI zy3Ounea5@DyZu%scK6-}4dJdds3_K|@KQQFT(z>_!Kje=7U=LXMei}Y!{fy?IW~OS zMyByjd{l3>oSYdD^so<$DjL@(+yT%=1CCKqY|qosINUHl2~5b%*FAJ0T%|!g=_;k4 zn{;ml2xbYbZPf0hrP{s{L4{jQ_&ymT>BqFJnj8To*TBKg$X~Ul6|0Z`B}Dx;!>uQ& zpq`UNw%VtyCJM>a^emhAvjLxeZ)H-6TYz_T8QApdOnu zOC>L7+U56NtWE*Og5;iRlp`L^Rn8KCoaBPp4%o3@JrE{T#1nxpfi+To8N>49Ex%`T zFrrNa=J*P*gY$=08`kpu4JI|z;89NmCeU^9!U)~r#<{7tKf=D5z&duM1`+1=6hQyU zFw0f+6%@JqCusl|t^|O~WMJr3?5O+$yq&PjqDaenOK`A3s|!P3p&4&%4?=ulLebaW zFw%k0Vuzzb?LvdzG#6zqJ4+E5-xfp7hrcE;IN+0elu`{}=96V^IafE;G~4E>_Da;U z?Y(ml_sy!8F=OU~db{umI>Np2WHE=scKn|F254P#UQ7$i&}Hxc-Z1Z7V4f`1dm|Bv z3*Kt;w7cv=#T24HSf2a->#o4sD3@-!P4w> zWn-E_?4*BD{#!YOqGt||97m1AYQI7oeACLPG@<)UXcH zxW6$i+agQ9eceX6*6I0f1;k17GsSU}Q$)x{83Wl~@mtUCut}67N0tet?gY{>fd~Gq zj++0d@(pB{r-DL1hT0H6omqmZ;sZV84<@mbrkChzP}KD5mAUXN-~q%{*Na2 zAt-ke1b(V{w@8G-u$^w`=pRXa55eF?=6_1sRQ~bl-=dr#*pW0!`Zkq+75`IXphxwI z`MB?Cyx)n?B;8s+sVoW&Bk4aTa8oG#t|;T7uvp6eC`mTGJ%s||10HC(pHi?z(h64I zDX|7k_O)gi;z|2IU%`5N77h1jLd5EV@Oi|UBnF=qDZ>`CwRb!mS6DsdTc-eA{?%i$S4M_(NNpR-X)#RwJl7g zoOSNK;hTm19ZQ|IIT+TpRS%F6U3q74Vi?<&s}uU-@4WB};+F$THic>RZW^^CvEFFY zw$n%6Pa%hU)4}ww2Qfe=qBwADxw>34*;l&&{5X0P#f3C_Z+qgNoWu)5HPDOb4-BtOn*_ zzu=ih;=Xv^FXn^cmn}8a$Z{80v>}0)a8|rZhUMd@;ufkBi^qN4KO_n-VBS@KK3kvDq^6sl4hfZ&X9C?zEbxN-!6F3Y_7XTR@j1nTof{@em zr6ysaM2he+#6b-e%4Kt79`i1h#(j#1G!FW0qTisGM1e-kTqJzSdGjwVPmCS5Wd_QTcTj98 zD#JA$_xV@t9#)+Xr0=|~@ZNomQ2VAngZSlG`Z>An=|cTZ(vw&640B;(>9}8aw>JoW zcFSqrf3zIHpx-)JaN?$e6-#KDmyx}dS1vTC9I`uaLtGikpvESAasp1$V1^Z$GhOCV zK_M!b;1!47<_OzjZI4c~pllZg zw@j+sZDWpqzwtM6<6q;$7{B}Xd;eYH8Yv?~E<>8fmwP_1s0??!+|IW&MQ%B}RAQ8W z;ZOEeg}8UJ}wyqyqCLE#TpVF0ToPb zN2AaUH6{9Mg9^U3ql3kUG~qpg-8KgKdbbM|XCO7=|6zIkk1+G!nS=j1WBDKO+tq2KrAj*zW2X^M&qCf& zN`YE%#dFhE>Y8$TUMw@3Evel9kn!lad}M$D^q5hn+Yn1kHJPDwZ8D!)q%XT3EXkyU zN~n4l7<2CK4-EO~R%ylu-ARIS@e)Vg5dmmFyCu*#VW0exmry>at2NV6e*yH^0(=$< z7C(Ak_q5?18b;ky5+olA`M^IiOMS^?)r$lwQi=VbxL3x5k8}s^cKg6-U-1XifKDob z$4m? z`N7oc*ccp)N=c_!iZ+em#Bz4gCSZ@(|jDG5R01 z%Qh0?#{Z5f3Qm7s@j{Stm7#1bHFS0aDdJ5dQ{uA1uT5tzmc)SnONF6%hTP(>B@c@@ z+1=;(Ryo;_3i=AoQWaPTaY9SXG|Qkcv2DV5bs4jx>|n!>oOxRpnzt&;V*&{ShpePG zSs;e+j!lm|rg}sZF&bRHuuMbHQhcQHO#%beDrB+jEj8=Zl;-KOU}0~;O0NH zeSP-`J0HYBA4YzBeT+Jp9B;UHjD4xBlD5AP(j|PLPb6Z zgpH;v;pltWuK<6(9C4z3WKWKzXoeS=;$&9{^84>S@mbZ(x?l^jQn{q!pbzRdrR`xH zyb#?{R&U|Bd@A1zQt*F!h zgw9_=*v6DvB?0HD3 zX*UMqcPP&a{YK0ot=t%bS<@VtLBwwni3LVzodU#Tv*(u3w3!4cQ4?wny6m2N41)0{ zz#aTqUJ?0jDn-E-od(bVhUA{Ml!6UQsouHNQk>`F_?!bkrM;kbTFvo6mwl+piIE+; zKfAGBP6%1b%9JQ|j1d_Sel`{#Kn(_nm!(hTY__51Ml7|=n-R?R?fwQB#duH9*FT^K zEqV@syjSe;!(VM;`zHGV5=c7Z#N zk=C%7u3BDVAAh(99h=+W+U$OkK8(3@B()mhJ`$sjn_?sTRo?ae=m?F|@|`^CyzFq+e zY9LLjTX|>e0eIB~#M@9I82kDKVJ1H)Tcg{ZL&+#0A#3Z8_1P*iQ+1qYobT2CfJF1U zk3d=VAH&$mxi|^#k7tP3{pz(IG+f9~l@F?i7Qd>sm}UMbxA~IfhZ62d9IbV&7m@G@ z<`$as+n0iH6>lQwLb}t080hPy|NUTtShg58+WLx{-vfwm9se-+XFLAwiM3 zTV>qUFjr73#62B?T#|d)oX2cn9T&T~o|QYfKF^5`29{9*OPQRqWbYoS? zB-=jUoMlkL<|6MN{~zbu{!h`(fAGqGn_>Gm|Nf)dX(vZ)qmknDCdd58wJ-k*`TX~* zczy+peaPJUy!6?$E$ff-gVwQbN9l~)iyIFVdp0H|o5}MnH{MTpdRv#lJ9#RcRsP>k zg~XSp`F%C2HlDW}6FX-aJyk0|I|T)O8)GKDjOb;(^W@k_Hk59LtBY_-GgE#jP`6=W zy*_U{xP}$f`ie3MoTdMh3Hh_jBhd)d*DWXV#i)3D%LNaWi*K6UAXfTtl98pI&(4b@ zC@2`*6QKcsbn}#YrN6$#%Dzv{TV1B0>il%jJF7K3+~40nJX~cF`AvRx=}Crb*>oZg zEz2L35i}xknbyp&lbTptFmS@mrkt-m2S!@@a23yJ&eiu*mXWepL<^IN<&1=s)~brKY0eQ?G~IE*@Ky86l_CAzRd`8rV(4I!Vdm=R)W>fs zJ|a>O*&CJI%>$p~nmo>fCv&n``plZBJnN}T%8COHAgyODV!Kb%Ve=_s1?(%#$Ihhd z>5`|S|B$IQ?1fF;ZRb{(qopdZm;~{G<@};dHl>OC1af=rH^#)=9`38*<3pqI_$}|+ znZX+8&!x!4t|7-P0=L)3^3tcu)s0N;85<`wq{Ho#>ug!QUb<|OA;R@+3T6;D-|Ecfr1zL{Y3Fu(mED{!OO>}YYAFI{j%TK6$vQm+s^lZL-OPEC zG?y-I&&S`-nQQ=icmll<2xO1kQ*?0x>L6suXDIb76qOe$8xXXO27cb+7V`Z6U!>&% zZnPai;IVUvh!vh}w%Iw>wTCGAxu=gvypm-ct>m*)U=Xt`p9{05xJV(R8G2ZaOOx-l zBbY|R=?3>j(2*FpM9FC9{V~n3xH$1Zt<@bwQ6n{qaOL*Y40~tKnwt8XG;8LdI-V1a z8kTrmQw&6e*l{<<8zSBiwF3nDQT1WbnCTXAoNUSVLH>LhZfMe(o>a=bauU0PM<9Jg zGh*qz!RuO7BD<;T9pm$rW+DUmtQM~`OC<2diZ<64`>8`oP8{bbeFu)*_CJtwDa5NW$5~*qGZ(Sri-h6B>c42h>Dm?sZBUTzH_eSKe6y=1f~ z-2%fz*0+UpAZ(QmD2{%vWhl=0@l`(J+gB7TwQvw=A(WngdZG`))*0txa&^@|b6MoF zn|o6R{f86y6$1^0U)J0kV8mn_rP4{CtBuH11|~9j#yPG+@PZzS~uzl*`Q(8z&%KLtg2 zv8ZwoM0n`S*C2%}@0t4tp?GD>6T%6Xxu5wuI@N3NA)W>%rP{L;Z-te~wUbv;ctDtf zDJLU!9f$mvZSg2nIh925BV>qSea|`r#pOi&LbUJ{#U!sU!pPKfI4U~8{`^T`+nXSL$mPfaIqN!QX_B|+9LxCLa1dD;hpjpj!5tR>| zsFnQBpkjEb>#jXVTNBgfJE)w=z0s~u>bNp{wzk-30^whb6saV{PuS!yI}4{ek?$A2 zOqR&Z7%3_bxO*!|qNucIUZ)anK4XTa7CsT&-T6x-aXyJIyl-@JeRaCouP@2yuzU0T z*mRtIm@5i5+Q^{KSp7H=I0PL{am-38wXEZhzEhx$jk1imV25@rjgM*!~6JK8v zdFSC*rf5%vPdCEF*$=7xy+p zg*Np}ynx@Zf_LVNn#jXdzq059Ep`#r#;99z>Bh-O-!4zkwuP}1CSXMp`86-ZC4N|D zZ-O61r@ZDq%@bKAL{8aB#x$Jk9W-`)ZfO+nhoazGN|p(Vnlc$U-Mar?5Ut#KC%8S# zDQYk`yGq2Z*-Z8&)&U#)%8BgFj|nwX}D~Rv~ol1hy{i_6I>oHd89??U_kqQT_xzt`^f08Ejk5KE6SSXehqXDzs zqHg+RN&l{qBiK7-6Zazol|J++`oVH7sjvS0gBab-uedlFOFJv*m`RDG{4WV49TtDY z*mI?9IQrglHFR5%$NhKy|ulcF3Ke2pnC#E z2V9>Jn+-hPd#!H_>z#!*oj2R)#`@iZ`+4ZDKm5H2noo)af>+i@Yrf@E;1no0P-$>@ zih2!soAD?ph9AxuI&O4fp#9cL5kvwH)Hx8tAImW}{}>tqd< z{Ihd4l z#`4qYF=sv<;f*P|GuZcRFIMU8@FdOpBO7%G_R6_m&~Tq2a~l3Qr=-NUe$CRT_%Es< zB^tRniq#WyhN7MQiIbgiB(*!S5JHisC$innC>C_H#mcGsT}Xhp&^jotnPs^myI@N7 z(mG~p#y)S-XFB;uPt@7D_WpQ|t#Ru0(c(eKOsVt>J= zlRsbNT^y}lge^TlvP3u)A8~*5JIAT)|AE5|+Y?ngGexKsN(A@htKYJcVTMyRico4) z58bzx=Nbj&jx`Y#6+~)#6BDj!g}{I=O1Tyn2q5*ueL<=nP z9}unePjD>r#C{Z-!uCwqq!PU*DbkngBYsW0u+#AFC11=`E^+fCUG~W$tH$s!OH$hI-uhH)nHa+a_-~ zhw0e2diw|FZydayX$%Y~SIw!H`ia?&Kk&^{y}_+xjTN%saNMhk^DxU<&&A9v?_%OV zx-WYll=)&yb|B*JfI;b=C?;K3A3F`WV5j}+tch54$a5g-Dxmwx&>ZsQsMdMO8=l~~ zB{zcgd26%_L8?gcv`|jHERgH%xW*qIC_l~f&RUQf1q{R!kWq=@`1V{n&ZXtAu5i4q zEE*`NX|ubz9xIH{Mw}yB8}Em)9s6dK`Jf-k+TY5Q*yd-Up-xVr;Rb4DjX=oc?uSpP z6j~7_XQp8d0-Nx9ZmOkdLgMwchm?x9BP|p9b3DOu>KjcV zQk>9Md}xmPD&jL ziejY+dY;$KEkbp7+D50QQB&U5Vk+|1MOWc8?caxg8^&NZXan;3rO zFl1nu`*5|_d1C!j5w3QS!mM9pEs~pmF;qfo60qhW3|29_tekfEp^R7ctIw(I1%2ej z`s(+gu=j7_5z*%+)yX0L65N!Iyn?%5VjrJqWD0$h6W5Vc)@rw@eD?!HgS%7tR7{KQ z@Tl9YG4bi29or9B&?GKSOsdK!x`NG`vgQFg%WkvgVP?ocr9Pp$Yu=+*6Y~FXor4VT z%1Ok{2&U&Bs5uEpm_;{TNut+WTMbgluT}Xy1o48Ze>Txkhts%J3)n+WIvw%AZPie| z%BU8xwDDT@4-DTk|B`fdCcKyI8aoJ+m9$ZSg}~80=T*Lu&*f?`eA){oWe5{Od2Tzb z={V?@Ms^1175(`NKss_}8IF07!FMc%pdtzNnq~%7EZdy4Dh}-+g+R-xXhV(0=zKJ` zStu5rjyp4e{_C{32%I}wY}r#xvB7osyyHdq6y>$#iah67J4N}#D~Z+vP1ce8+d4i4 zxURb;5w|DvimCl$*ZhFzDhAGH@m!=8;ixfs*~!&%{z8LGStAp^EXLC+n2Ho3+s~4f z%o`$h`LX3x2(1d%nhA_nSPYa=UJhUu{~}Mc)TTRY4OZ@N9>jcPDGJC>kPr#Ks9O9nJ*;L=k z-=JkB4mR?SV)KC^2$JFx0P$hf9GOH)71q3j$I112(X z9%rIMWk0M;4uzan(y%|iLieE_S*zD;v0ttQ46f3OpA|i&|4`42_9{0r=!_cs3+JW* z7xrH7xze6A0B+GArI!dIbgIzgcvjqKBbfR_sccI86MR_5iPm0qMqU-eQQ%axX!(1Q z>8rcYiJ7A3I~#ue^~{s+#*zT&?!m0)8&^Wz~NY5@Q(zQxPsK>TAl z#Al1gZ~grtKZvEfyWTTD;Z85Is*@MO34=^Iv_76Tx zl#N&le)QB~U`q=2Zo02+`_<1q?jH(*O_QAw?`X4CyM9fwePZue0Rtpllf~sV3pl+t zp_W%Rl0T*1{jtMK0!;_@avTi?aWDLmA@mYre;qm(yWvB>-g`0-DeC*s+@6(PQ$Exm z7#J8IVGDidrHKb_#8|)_&}?oi7zTd6*7gpMK>&zPkCNj+wm?51d9ip)1O4;Vw-l>V z+oskV*{wbF2^jG?6P)Omcm~*^nybez_pmrZkC?YDgLi(Ezss<>v4bakq{&n)V!86q z6WtFw0ur^SKnMxT^wz3jraG9>=8Bi6A#bSJUV1M?zhV(3ho;=35t#UA!q|{{xcTJG zp|&mwbo|J*GzrA7%FiJXNGf{Q%|*$?g!ah^H?}mrbwZy~mFZ0G`{ZxW$=2V`42DR7 zzllB8n&^lIQodqS4pCNO{8SSY2yvi@{Dew!Sl6-{J9osPbZPRk0+N7E)=06C1op&4 z3)-kRtz^KxCm*mRsi|6`emEv(zPOSu6@M#~{%pJFzk>%GQ0tD(Yv(2v5{-&4d~% zIH|%lyA6d7Q-~M}QR*5LTA&vUP!NOU@`Y;zYi}>|XWR!OAP(8dgy5&FCZzJp!7a)z zVI5Z|dD`4C@N6U)n5uPDas8@8bfm{K(c_smk(h7}8@BjF&}2Z*&+V5|v}TGQvfa^v zPZRdK+*u7{uoR;SjGmG~-a=vUu0V(gG+rELCX2-QG&i+VLSI-?nnZx2FAqKjge_ll zdCEetpn|WQ8)WI86=P6MPuR3q=4Oo6%aQr!)b|1N3kV4YSh$QaDim1zz6A`7Gl;{e zj)7u_yE_lu^&EsDRQrdbS7_|;+rQZEIwT}*;f`o%aU&B6*HS_~LbExwDnpMqd$FY# zMj(1(Neu3fz+7g7R3(?&ySCduw3JH-#3JC$_h-)xa80zQS}hRCHyQ}SZ8ypyB=-Ux z?PVxh*jpM9OrR0iQ~F(eOHS>jc=3y7K?qcU8p1{PUZ2dmqW&rT4KuVEmZO3@pOU2& zHKXN1j_W9ZY1GoeQ)i!o8|h(bj}i7QU|Gi};tl%mZ(nh|)v3_PT3Zu`{4kKKq=i3* zY0^dSV}Fq(Ks^kd_nsmUB7}wC-ZQiG1xPA%5qu<#sf~r?L~fwdlYjqd`=0)j9~0x) zuzFu;-t1A*AQo9_Eiotg2A7~Q$NEz5cdjHXnny)k@kqDEXHTu}D1*QuZulyui9Nlm zptzjw5;Q2QiD0wmePO|iny1?k-r1opEeaO#LZ?hT@W9S*22ZVMc{*zgu}V`P&8wC7 zHJJSCfLdh_ZNmi_xeFs90PYEhqI{#D#L0>J&%PO!bf5wO7_1m{cNG|p0fzjdxjLXF zOJex|gQ3$>qG^Mrdgj%hi_y})f4iK|aaA9U7Umo!XWW|zI!Ne{a@uUVf>s9Qb=8K) zYm}S+wxz%V^-P4YJ4)UB^wfn8)68&dSWS5nP)Un{r4)1@I8Yr1~#+{UFfz^A=ZESVqw zlNyuJ?07Fv8y6S%zLiQ5+*aTa$HK+v;V`lCUWL6HL$~JnADuGmkhx+8+w*i!_SxTq zzm6Fhy6jXP)WWLA*UtoGKlHl{Hf0F(ddACpjNG@-j|3{PJF$Zcv#9_yDHuSK+K)i) zw|B>;UNN{~GF189%`3dTMt+xSw^f0=7cwKE! ze7)4dVC4jM!c~eVGNBsj9cnyeyn5KJFOXIP3IS#k8|uipL_0TxCTk_QO3eA8ScL^e z3K?YU0%jttVi0SSNplE48SS?X3C+kU zqGzWuiN#JXAEaw7DmNHd#&y|`YCP@cJN>AC_Osr3z%*_q?(g}b(%i#2^6*v`7ERJC zZRz7RWp_hL1x9QZ#l9G$F+!PWpfJ1f%ct5A(4Y9a9%82?M3n;6ZBK{Utx$?rihf~* zQF^hFPEmEG`<>-VyH=hV~-vJRNiUWWF2FL6ziAWM~768@E|hOLmho29N|8 zFHF3OP9v_0lQsZ>YZL~2PWKPdo|bV^z4Lj9Eg~!~Vt9_CA?K#GO(jl)&|N)a$iLs6 zTI;W>CdVByqTUR~H2Y;^_?3Xo3S=US4CAK$%o_xkYg%9oN@^-C}Rd&TCHR0uYWJX)fOadK&Q&^o7A&gI{oT~G?rej(ARI@ig+r75j(@-2-p zY}q1sMvQkFJik8~Mckxo^GdU+ByZKM+wfwV$Y7dqHDRa7bddN1KXoflJapNNp{m_x zbzSN zalXVB)?vfbx8!inY65ufiBgNE%{UoWO!ZrCl8VH)|57`;>y*5&E-zATaUlAkYoO-P zn|5cKpjJD=*`61%+4!gi8z3G;g0UPC`B$hPQiMf0&A$bu}pW zJ$zp~r5bI5A0@-CY1DnqXp=cAQ%Uo2*iq8c`X<8_{=oNK_T(4iy) z*-4y(#DJQS7bUxYT>G(c$>JuiOPsO0_q3$!LN8YHNu3R9#6!Nd`!(1Gwj8&lAYxD`7~R`l(}XW z>`aHpO*fx;LWSvK_~z_=3IST}T^X)gz>Q!6x@pJLc6W@8)5&BKFf9OFG6E-hMJ zTpPyXLIU;F$;3a|th&+upm!eg5QNjQpXYj4k(vxvtd{^n6_K3;S6e7^1kGOi?-gjmNW;*k{ zrwSylapKSsp%}eyLMIsZcVg*xox0ha_IuaQ$s|717M{JS?z`pCsc7m_k{K}ycIVT6!|al?YpgEFGMXc1tBDEI)qHOZ zwd7P9inZUC)edQ9v*|0lU}dGmz8Rji+JC%U8oQZ`O|cDt^H$J1U1Q zG-vI_N0H~$1Yr7|G2IH4vgpE<0MEzO%(djBiRy^k2rko;KGKKK6UKVqna zJZ~@l=8efdCHl@l9}GKt*+-?DK-Zf|Q-@K#Y(Lj+%kra{O=~-p@M78^ z=YH?V;OjmwPh)a$;y$Lmz<@<7WuP37J_lPDSIlQq)|&6;A#d8G`JZT!QdCSCS2^UM z_Wql7nSbr)`8dw-?s$EWF^fqVktpBC>i`MhkKM7?yJ=u`sd-xX`wvbryp&JSRZp=t z?45YVJv24+JS{KL-`c2g=Tv-fyVGiWP&@D4XnWvS626#%S?c%0)+{KXQJB+mL2$&K zzw>i!t>@ z4GS0N{J)OOh*q|<3VNA*#P#JU^IC1rD=%yQ5audrb=Hq8eC(`HDw@@M26iBau^|G+%kMoHwx8q9!auzx?rynO*C?y=3deKO_+KYVh(szz!zhz+Q`y zC_i$cAg4LXAXEU8chYM4aS$Ajtdgv$zL)rfY@N}xYQ2YVK0|~V`5IqW9}@cORcSnD z#h540HZ7i#ec3;?weORP`<-|iX4&LSvfu6BDjZ1dAFnWU zh#)mqw^5Vjdj3w%-ab^VtSmUOKpAOTqePg@)W2a7bMJ|Tl2ka!i`#iS zOQLS_=CUag61A-ggC(lHMUklM#8;=-g0EoWpRhC@r5vE*b~kss;bDaI>$QjGI~N6* zQkUL*uc&1s37Mcva}9Mw3(r?aPIYkUJ%|>6=$3UyP*hV}T7txX&$wl&CLfK}oH`ge zYjc*N8BX&M-D~8QFz&}XLsAImtLe0Md7=x9UWD-Y7Fe5zAR&K~P`A{aLO2lu zHr3G%`CYcFp*r?(cL~{c`+oC@R^+G}Uk_~uH4uIg*8uT{{T)>H;fEjvhN7o;Cn`T4 zO-@!o>w32j5bmIk1VOzHO~Uo2oB5}Do{gXRQB>i5@+I$0Trkn35s{zw@5CEuQ1v+j?S0o2O;6=yO)-7K-^#(Asml-vb79g5 z`SWJ&&?}~%lF?8zEElj*i989^^}|T4J%Hbdh`gv1C(tx(7b(nazi}XD|A0L zL({0XdvR6ytCN_;CCWV0%NlZ4b$4QXS$jvks{G|vYqxP`>%l|^#Wyepso?YfzXIJ5 zBJca3_Nzy&sqXzTKa`KG*nr%Y5JsO95Bp&eLPS+3gXnWHAa@tGdln4=0U;c#-|%bN zMfD{jeQqaYa2>+vb0XB|4jt0_U5pFNm&gI3eE8AlEFqI#I^-+)KtjmCggEqv2OlOO zBBhRcBX!a1It-@_b5;ZBbIn_S2$Z_vi;#aZNnam)IHJ9}FG8I9{Fg2sd<&9KcV=f9 zKukis_{g?D4Cn7ayEh7F(Ca2ZZHArq3BdCYl2gV$&ZWj=lLn z9nu-l%d+W@J(>RS70be0$X0iP33f`wgV}62MF!x*rPTdIdwuJ3yHf8ALWonJGkkCW zLAkHZHfI??C?Rqa;$NTJlsYr^#D`MH`b59_gRj&($9<-F8XfpJ@T<@5vNwAa4n&pE7NS-D+EJ7?m z_&P+?{{bGnOrJZHI`i5)=D+{LFCR`qntehzfSBT??(Za}Qbm}+fuYpVwc z-t$06M#2ZHKZ;`gfhCJVr7qu_?p2qA;(55H9>x7X)> zt4_ip-3W%`Tc#EX`;K1;mAY5eiA|pyzWFefI`OB}?e!%|2Olm#rp?w`HL%la!uNFn zL9Zz$CS69?df+7Ke@4{;4J5$JOcAPZgl5%|x| zLJMB7dw^ijNT}3Z^(B0Lp4m9d)f0(&?oFQ`-%8zAeTgqZh)IYGkip|u@~V@Lm;E4Q zAU^z8oeZweeOH}?!)QUii-r_7ezoVH4_7Qp(m~~~zC=Wb<|meg`lBPz=Wak2tmQ|* z2OL^;GQ>ot_|+xY|G`376zcPhH;G!ZSWLzWxigj!n^G4LVyiFF2I9k2b<)8uTvx-? z$jIRV88CijC#2(LL&)v)`Jh!NHaj0Bfd85d5S;_@L$QaUVM5R{DHE zLLBj{X%`=MKukU~%7y~uS8xJr#}Rz_2Laaus$C!mh~0> z6(=9USL%-VRsI+E;puaW4LZ~CKyzy!Q`Evh=H z&2W|$4$8;!dabrDQ|ip%cgn|H`@na7$;-;KXU{4x-Gn%lx(yMWbKShP{_r2m@)^H+ z|KY=XpE|@f_&plhVlefs&j(WK&nIuG&xK0eUCLW!;#X9k%K_=>bCZv6DPcqD>21A# z_v&hE2cXDUaAY2?)oVqM{*SIJwZk?erUN}M%O1Y=fdd)C^ zkYz#D33;B_WwRf1yAz|{{T~({&pv;?ckkZk&(A6&Ql$`^I3+z&L-5|BVPHv5=^_#U^y`>ud;#aTV6goJ1L``<* zp=_MlVp&XrwKR6!8;Ny#Iy08+>kqy@KR;YwKX>v$2@xrEqxrGDyKA{umBaR#A1Bri4-eZDA4iF8 zijPEpyzJva5vfQj7pWCNMkpq;gyln`&m)of(b0p^(Rn4}S#^Sl;0&K2oQN{NVjC2+ z=fMa3&JsdcM@_Sal;Dh#lx@6E=XQKJt4>gSCMP$ahoURVtxpxYz5NHh)<$}Kr1Di%_RQUvA?23pT9dU z>>L-3Ms8zcW5>LE(}{j4%ibSCe;3jzC6mdL>7YpS=jRC(pF>h=toQVX<^}|Hi0v9z z8s5K6bb{=&=45<4yJtV2UrPEzC<(6jXqH;chq5w?(}gOPiG#iQaWAD#jS=aT;h-E~ zuc3+g==E>uG8@8DNJ!bd2GML|igV6J8Tdb^*PsjN_D@0 zQ-8uib4Hf5>cr%tdzh^v9RF(5_|t~Sl0Pp?cv}hi06?f`rKQue9XB6+K#&mP*u7!j zxh?7c$eiVl(G^P?u^sflUT@UX8trNC`&gDz_qqnJemB8re=OErUO(>hv0iJeJNiSU zm+;`D^4SH*y=Sgi)~w+*X?I@C$Jn@0OGx;zb;qyx zB82;Npnv6#U!jJ_aTTWRz`1d$aybKUxcFcIk#9_(d^E)I-9T?pDW=#n8}Dj_ZjL_7oXH4rT_efU=QSoD z*Gw!gpIdws0gc3{Q>h=%dR$|)ElG8_4T#%>e5rht6N32*5g(I}E0vQ;11Ezj^9Svb zk;jt)LWq2$2vOd9=nvaWQ~@FKr3?c9DrD_Mpd;fbEb&k%$P0BjZHW8#xZL9E^G%#q z*&F?{X&5p@u(nq^iCV(Px7Bn%O7G%>1>|mCI`W!mwVbH`W8+Q2x=N`)Wyi)l^ntV( zYe6U>$Fe&MH4Z0#zGK_VP`H17-0AZHUu)XZA>e*Vw=x*b2?-xBIR?aSLU3Y`^cmR` z+YjL5k+Bl_{pilo@1G*6$3Td{hDfKigN^d!V^4|9Uq}i0u%dbFOW-IAbEdVf(Cwa~ zEyLg%k3LOh*)=ZR^WnNy0WV@vfd<8RA|Zqj=~|zuU&MgqOZ{=}ET zz()oNv34`W>R@F+gy7zUV&k3TJ2qrX4e45EPQE;0TYz@FUNG&4Rx|lXJ4MTmDqSA* zs4}1d0YF?C!{JF8=$bMv;^X5;<-kyWHwPa6el&jZc%<@(uhhjGIqA~2poov|p#2MQ z!QRj7y-f|=WQiu(cBbtGx%t7Mj+0!1bXZ)Mlwe2+@i`H$jkW?&xq-m{g=;V1}%7nVB*sWe%1Akk9Uv`dcyRnEn>< zk@`3?d|<|&j=+R`82>P?OpFXq3T23d!S^2eT*u2Cjqgd7`umg&5QRSg3)iy6k)2RV zH_9Q@B=Pdr#n#?RhzC?qY^KQ7mM8(Tv}vv;F~7c~GavA9+7dfi`h{4aSM$@VrgvTV zOCZGVVA%m-I@R42Vtk4pz^c~@Z(eVlbqP@$$H#Q;9OglskA5vNA-XZT&Z{X&umk6d zjpH64=f?m)I%V)4>t-cX@lt2wt=NFP{Oz~Dqy7N-(iSTnt)mG2D;)Q0#%6zyjDPs> z>FDU2gW-`AzNA;gCPbSZ_lWQ6=4HC;N(4&%C_;pbqlv(PU_(_fY)SPv?uw3=d#mDk zl3uKI#0I2C2tHtG$ucN^ZZ3&T2ovk|Z9uBi+i6^pi>4OHN!2s3ANaa%fIBg7!ZQo6CjF*zF>iCK{! zXG|veMZ3q0kJU&tOnnYm6yUuMcxC4a_!(I1QxL5^7pDj*9ws1J7a|-$MovT!5+aZk zEFZrg9gUBFqPOg)N5dl@6+tpY2q8B`$msJP9~VkQktp>eMRfOSosg(Pk){Q4JsTAw z>_lQPAv{qp0>ooP+>#`rL%#!>8XrnS6jyo)|gd*PMuN zUM=X;e(X`DZU~k7kuVgXm4ng|ao|?z6roVr3lK#J$P;P4d}(uYb8!(jOf7Z|%9a=q z(QA8J07yQ`wt>##J*E}6tKu*(9MN`lkRbIl-i+$k8}%45Yj;71bd|b>)UMBvr!Hq&p6*Q+!O(_ zrwH{qF;;M2!qJDw_^02Gy4yQWMke@xL^_%%zVv|?w4Jx>5BT`PRO)8p@PbE3uq?X9 ziVP6C|CTyb;A?pSBHE2hJOHtxSx+`;5@bJQm|Z|3kcQcSWm2{J{*0D1S65&Vi6f2 zd!n1S%mbt=(D!uL2$A9xrjEnSbW(ces$*pqC54uQ>k;L{fAosVmeshvzdToX}VA((!UB2 z>R$mL`kzP$t}0wy{I38~t>#r5AdNsh_a9dt9Rc}&0t^85-wV#7O22Uc0000 -

- « - 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} -

- -{if count($ordersMsgs)} - {foreach from=$ordersMsgs item=alert} -
{$alert->text}
- {/foreach} -
-{/if} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
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

- - - - - - - - - - - - - - {foreach from=$order->payments() item=payment} - - - - - - - - - - - {/foreach} -
IDStatusMethodeAmountSettlementRefundedRemainingDetails
{$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} -
-
-{/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} -
- - - - - - - - - - - - - - - - - - {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} - - - - - - - - - - - - - {/foreach} - - - - - - - - - - -
StatusSKUNameTypAnzahlMwStSteuerNettoBrutto 
- {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*} -
{$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} - - - - - - - {/foreach} -
- {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}
- - diff --git a/version/108/adminmenu/tpl/orders.tpl b/version/108/adminmenu/tpl/orders.tpl deleted file mode 100644 index 4ec7af3..0000000 --- a/version/108/adminmenu/tpl/orders.tpl +++ /dev/null @@ -1,135 +0,0 @@ - -{if count($ordersMsgs)} - {foreach from=$ordersMsgs item=alert} -
{$alert->text}
- {/foreach} -
-{/if} - -{if $hasAPIKey == false} - - Jetzt kostenlos Mollie Account eröffnen! - -{else} - - - - - - - - - - - - - - - - {foreach from=$payments item=payment} - - - - - - - - - - - - {/foreach} - -
BestellNr.IDMollie StatusJTL StatusBetragWährungLocaleMethodeErstellt
- {$payment->cOrderNumber} - {if $payment->cMode == 'test'} - TEST - {/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)}
- {if $payments|count > 900} -
Hier werden nur die letzten 1000 Ergebnisse angezeigt.
- {/if} - - -
-
-

Export:

-
- -
- - - - - -
-
- -{/if} - diff --git a/version/108/adminmenu/tpl/paymentmethods.tpl b/version/108/adminmenu/tpl/paymentmethods.tpl deleted file mode 100644 index 4c37e02..0000000 --- a/version/108/adminmenu/tpl/paymentmethods.tpl +++ /dev/null @@ -1,97 +0,0 @@ -

Account Status

- - - - - - - {if $profile->review} - - - {/if} - -
Mode:{$profile->mode}Status:{$profile->status}Review:{$profile->review->status}
- -
- -
-
- - -
- - - -
-
- - -
-
- - -
-
- - - reset -
-
-
- - -{if $allMethods && $allMethods|count} - - - - - - - - - - - - {foreach from=$allMethods item=method} - - - - - - - - {/foreach} - -
BildIDNamePreiseInfos
{$method->description|utf8_decode}{$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} -
-{else} -
Es konnten keine Methoden abgerufen werden.
-{/if} \ No newline at end of file diff --git a/version/108/class/ExclusiveLock.php b/version/108/class/ExclusiveLock.php deleted file mode 100644 index 834e00f..0000000 --- a/version/108/class/ExclusiveLock.php +++ /dev/null @@ -1,76 +0,0 @@ -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/108/class/Helper.php b/version/108/class/Helper.php deleted file mode 100644 index 8f4772c..0000000 --- a/version/108/class/Helper.php +++ /dev/null @@ -1,311 +0,0 @@ -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(); - } - - /** - * 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/108/class/Model/AbstractModel.php b/version/108/class/Model/AbstractModel.php deleted file mode 100644 index 5638700..0000000 --- a/version/108/class/Model/AbstractModel.php +++ /dev/null @@ -1,7 +0,0 @@ -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/108/class/Mollie.php b/version/108/class/Mollie.php deleted file mode 100644 index 6d0fd4c..0000000 --- a/version/108/class/Mollie.php +++ /dev/null @@ -1,548 +0,0 @@ -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; - $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; - } - - $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/108/frontend/131_globalinclude.php b/version/108/frontend/131_globalinclude.php deleted file mode 100644 index 5778e21..0000000 --- a/version/108/frontend/131_globalinclude.php +++ /dev/null @@ -1,120 +0,0 @@ -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/108/frontend/140_smarty.php b/version/108/frontend/140_smarty.php deleted file mode 100644 index ac119c6..0000000 --- a/version/108/frontend/140_smarty.php +++ /dev/null @@ -1,78 +0,0 @@ -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/108/frontend/144_notify.php b/version/108/frontend/144_notify.php deleted file mode 100644 index d1826a4..0000000 --- a/version/108/frontend/144_notify.php +++ /dev/null @@ -1,63 +0,0 @@ - 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/108/frontend/181_sync.php b/version/108/frontend/181_sync.php deleted file mode 100644 index 86c610c..0000000 --- a/version/108/frontend/181_sync.php +++ /dev/null @@ -1,43 +0,0 @@ -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/108/frontend/img/trust_eng.png b/version/108/frontend/img/trust_eng.png deleted file mode 100644 index 3d0177359de7fa93833765ac05d8b218fa1550f2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15299 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 Rmns)TMnX}%M${5 diff --git a/version/108/frontend/img/trust_fre.png b/version/108/frontend/img/trust_fre.png deleted file mode 100644 index ed1a2f6f03c56f6748aac8af0352de7fc0afd3a4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17319 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 Mu#8ZJpsxS_1AJc%;s5{u diff --git a/version/108/frontend/img/trust_ger.png b/version/108/frontend/img/trust_ger.png deleted file mode 100644 index e42821b06709e8f4371c66cfb5759d00df0e1afd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15352 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 (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) - { - 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; - } - - 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 static function getMollieCustomerId($kKunde) - { - if ($row = Shop::DB()->select('xplugin_ws_mollie_kunde', 'kKunde', (int)$kKunde)) { - return $row->customerId; - } - return false; - } - - /** - * @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)); - } - } - - /** @var WarenkorbPos $oPosition */ - 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->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->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 function optionaleRundung($gesamtsumme) - { - $conf = Shop::getSettings([CONF_KAUFABWICKLUNG]); - if (isset($conf['kaufabwicklung']['bestellabschluss_runden5']) && $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 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 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); - 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/108/paymentmethod/JTLMollieApplePay.php b/version/108/paymentmethod/JTLMollieApplePay.php deleted file mode 100644 index ecf20a8..0000000 --- a/version/108/paymentmethod/JTLMollieApplePay.php +++ /dev/null @@ -1,8 +0,0 @@ - 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/108/paymentmethod/JTLMollieDirectDebit.php b/version/108/paymentmethod/JTLMollieDirectDebit.php deleted file mode 100644 index ce0441d..0000000 --- a/version/108/paymentmethod/JTLMollieDirectDebit.php +++ /dev/null @@ -1,8 +0,0 @@ - - {$oMollieException->getMessage()} - -{/if} \ No newline at end of file diff --git a/version/108/paymentmethod/tpl/mollieComponents.tpl b/version/108/paymentmethod/tpl/mollieComponents.tpl deleted file mode 100644 index 825bc9f..0000000 --- a/version/108/paymentmethod/tpl/mollieComponents.tpl +++ /dev/null @@ -1,103 +0,0 @@ -

{$mollieLang.cctitle}

-
-
-
- -
-
-
-
-
- -
-
-
-
-
- -
-
-
-
-
- -
-
- - -
- -
- {if $trustBadge} -
- PCI-DSS SAQ-A compliant -
- {/if} -
- - - - - \ No newline at end of file diff --git a/version/108/sql/107.sql b/version/108/sql/107.sql deleted file mode 100644 index debecf2..0000000 --- a/version/108/sql/107.sql +++ /dev/null @@ -1,4 +0,0 @@ -CREATE TABLE `xplugin_ws_mollie_kunde` ( - `kKunde` int NOT NULL PRIMARY KEY, - `customerId` varchar(32) NOT NULL -); \ No newline at end of file From e4c75d2077886e4fb9faff6b3143b06b31ece819 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Fri, 21 May 2021 00:22:39 +0200 Subject: [PATCH 226/280] auto storno, pay pre order --- version/203/adminmenu/paymentmethods.php | 6 ++- version/203/adminmenu/tpl/paymentmethods.tpl | 48 ++++++++++--------- .../203/class/Checkout/AbstractCheckout.php | 21 ++++++-- version/203/class/Checkout/OrderCheckout.php | 17 +++++++ .../203/class/Checkout/PaymentCheckout.php | 17 +++++++ version/203/class/Hook/Queue.php | 2 +- version/203/class/Queue.php | 15 +++++- version/203/paymentmethod/JTLMollie.php | 2 + .../203/paymentmethod/JTLMollieBancontact.php | 5 ++ .../203/paymentmethod/JTLMollieBelfius.php | 5 ++ version/203/paymentmethod/JTLMollieEPS.php | 4 ++ .../203/paymentmethod/JTLMollieGiropay.php | 4 ++ version/203/paymentmethod/JTLMollieIDEAL.php | 5 ++ version/203/paymentmethod/JTLMollieKBC.php | 4 ++ .../paymentmethod/JTLMollieKlarnaPayLater.php | 4 ++ .../paymentmethod/JTLMollieKlarnaSliceIt.php | 4 ++ version/203/paymentmethod/JTLMollieMyBank.php | 5 ++ version/203/paymentmethod/JTLMolliePayPal.php | 2 + .../paymentmethod/JTLMolliePaysafecard.php | 2 + .../203/paymentmethod/JTLMolliePrzelewy24.php | 3 ++ version/203/paymentmethod/JTLMollieSofort.php | 5 ++ 21 files changed, 148 insertions(+), 32 deletions(-) diff --git a/version/203/adminmenu/paymentmethods.php b/version/203/adminmenu/paymentmethods.php index d7e11c4..f447846 100644 --- a/version/203/adminmenu/paymentmethods.php +++ b/version/203/adminmenu/paymentmethods.php @@ -73,11 +73,12 @@ $shop = $oPlugin->oPluginZahlungsmethodeAssoc_arr[$key]; } - $maxExpiryDays = $oClass ? $oClass->getExpiryDays() : null; $allMethods[$method->id] = (object)[ 'mollie' => $method, 'class' => $class, + 'allowPreOrder' => $oClass ? $oClass::ALLOW_PAYMENT_BEFORE_ORDER : false, + 'allowAutoStorno' => $oClass ? $oClass::ALLOW_AUTO_STORNO : false, 'oClass' => $oClass, 'shop' => $shop, 'maxExpiryDays' => $oClass ? $maxExpiryDays : null, @@ -90,7 +91,8 @@ Shop::Smarty()->assign('profile', $profile) ->assign('currencies', Mollie::getCurrencies()) ->assign('locales', Mollie::getLocales()) - ->assign('allMethods', $allMethods); + ->assign('allMethods', $allMethods) + ->assign('settings', $oPlugin->oPluginEinstellungAssoc_arr); Shop::Smarty()->display($oPlugin->cAdminmenuPfad . '/tpl/paymentmethods.tpl'); } catch (Exception $e) { echo "
{$e->getMessage()}
"; diff --git a/version/203/adminmenu/tpl/paymentmethods.tpl b/version/203/adminmenu/tpl/paymentmethods.tpl index 9f0dbf1..6b5bff6 100644 --- a/version/203/adminmenu/tpl/paymentmethods.tpl +++ b/version/203/adminmenu/tpl/paymentmethods.tpl @@ -91,31 +91,33 @@ {if $method->shop && $method->oClass} - - {if intval($method->shop->nWaehrendBestellung) === 1} - Zahlung VOR Bestellabschluss nicht unterstützt! - {/if} - - {*if $method->shop->nWaehrendBestellung} - Zahlung - VOR - Bestellabschluss - {if $method->warning} -
- - - Gültigkeit ist länger als Session-Laufzeit ({$method->session}). - - {/if} + {if intval($method->shop->nWaehrendBestellung) === 1 && !$method->allowPreOrder} +
Zahlung VOR Bestellabschluss nicht unterstützt!
{else} - Zahlung - NACH - Bestellabschluss - {/if*} -
- Gültigkeit - : {$method->maxExpiryDays} Tage +
+ Bestellabschluss: + {if intval($method->shop->nWaehrendBestellung) === 1} + VOR Zahlung + {else} + NACH Zahlung + {/if} +
+ {/if} + {if intval($settings.autoStorno) > 0} +
+ Unbez. Bestellung stornieren: + {if $method->allowAutoStorno} +
auto
+ {else} +
manual
+ {/if} +
+ {/if} +
+ Gültigkeit: + {$method->maxExpiryDays} Tage +
{else} Derzeit nicht unterstützt. {/if} diff --git a/version/203/class/Checkout/AbstractCheckout.php b/version/203/class/Checkout/AbstractCheckout.php index a910989..8d36b72 100644 --- a/version/203/class/Checkout/AbstractCheckout.php +++ b/version/203/class/Checkout/AbstractCheckout.php @@ -163,6 +163,7 @@ public static function finalizeOrder($sessionHash, $id, $test = false) $checkout = new $checkoutClass($order, $api); } $checkout->setMollie($mollie); + $checkout->updateOrderNumber(); $checkout->handleNotification($sessionHash); } } else { @@ -179,7 +180,9 @@ public static function finalizeOrder($sessionHash, $id, $test = false) } /** - * @param $id + * @param string $id + * @param bool $bFill + * @param Bestellung|null $order * @return OrderCheckout|PaymentCheckout * @throws RuntimeException */ @@ -192,8 +195,9 @@ public static function fromID($id, $bFill = true, Bestellung $order = null) } /** - * @param $model + * @param Order|\Mollie\Api\Resources\Payment $model * @param bool $bFill + * @param Bestellung|null $order * @return OrderCheckout|PaymentCheckout */ public static function fromModel($model, $bFill = true, Bestellung $order = null) @@ -241,7 +245,7 @@ public static function sendReminders() return; } - $sql = "SELECT p.kId FROM xplugin_ws_mollie_payments p JOIN tbestellung b ON b.kBestellung = p.kBestellung " + $sql = "SELECT p.kID FROM xplugin_ws_mollie_payments p JOIN tbestellung b ON b.kBestellung = p.kBestellung " . "WHERE (p.dReminder IS NULL OR p.dReminder = '0000-00-00 00:00:00') " . "AND p.dCreatedAt < NOW() - INTERVAL :d MINUTE AND p.dCreatedAt > NOW() - INTERVAL 7 DAY " . "AND p.cStatus IN ('created','open', 'expired', 'failed', 'canceled') AND NOT b.cStatus = '-1'"; @@ -251,13 +255,17 @@ public static function sendReminders() ], 2); foreach ($remindables as $remindable) { try { - self::sendReminder($remindable->kId); + self::sendReminder($remindable->kID); } catch (Exception $e) { Jtllog::writeLog("AbstractCheckout::sendReminders: " . $e->getMessage()); } } } + /** + * @param $kID + * @return bool + */ public static function sendReminder($kID) { @@ -584,7 +592,7 @@ public function storno() } $log[] = sprintf("Cancel order '%s'.", $this->getBestellung()->cBestellNr); - if (Shop::DB()->executeQueryPrepared('UPDATE tbestellung SET cStatus = :cStatus WHERE kBestellung = :kBestellung', [':cStatus' => '-1', ':kBestellung' => $this->getBestellung()->kBestellung], 3)) { + if (Shop::DB()->executeQueryPrepared('UPDATE tbestellung SET cAbgeholt = "N", cStatus = :cStatus WHERE kBestellung = :kBestellung', [':cStatus' => '-1', ':kBestellung' => $this->getBestellung()->kBestellung], 3)) { $this->Log(implode('\n', $log)); } } @@ -782,6 +790,7 @@ abstract public function create(array $paymentOptions = []); /** * @param null $hash + * @throws Exception */ public function handleNotification($hash = null) { @@ -900,6 +909,8 @@ public function getRepayURL() return Shop::getURL(true) . '/?m_pay=' . md5($this->getModel()->kID . '-' . $this->getBestellung()->kBestellung); } + abstract protected function updateOrderNumber(); + /** * @param Bestellung $oBestellung * @return $this diff --git a/version/203/class/Checkout/OrderCheckout.php b/version/203/class/Checkout/OrderCheckout.php index bc32e90..df10f7f 100644 --- a/version/203/class/Checkout/OrderCheckout.php +++ b/version/203/class/Checkout/OrderCheckout.php @@ -337,6 +337,23 @@ public function getIncomingPayment() return null; } + /** + * @return $this + */ + protected function updateOrderNumber() + { + try { + if ($this->getMollie()) { + $this->getMollie()->orderNumber = $this->getBestellung()->cBestellNr; + $this->getMollie()->webhookUrl = \Shop::getURL() . '/?mollie=1'; + $this->getMollie()->update(); + } + } catch (Exception $e) { + $this->Log('OrderCheckout::updateOrderNumber:' . $e->getMessage(), LOGLEVEL_ERROR); + } + return $this; + } + /** * @param Order $model * @return $this|AbstractCheckout diff --git a/version/203/class/Checkout/PaymentCheckout.php b/version/203/class/Checkout/PaymentCheckout.php index 52149eb..f8fce8f 100644 --- a/version/203/class/Checkout/PaymentCheckout.php +++ b/version/203/class/Checkout/PaymentCheckout.php @@ -195,4 +195,21 @@ protected function setMollie($model) } return $this; } + + /** + * @return $this + */ + protected function updateOrderNumber(){ + try { + if ($this->getMollie()) { + $this->getMollie()->description = 'Order ' . $this->getBestellung()->cBestellNr; + $this->getMollie()->webhookUrl = \Shop::getURL() . '/?mollie=1'; + $this->getMollie()->update(); + } + } catch (Exception $e) { + $this->Log('OrderCheckout::updateOrderNumber:' . $e->getMessage(), LOGLEVEL_ERROR); + } + return $this; + } + } \ No newline at end of file diff --git a/version/203/class/Hook/Queue.php b/version/203/class/Hook/Queue.php index 7e9c578..8e3bbcf 100644 --- a/version/203/class/Hook/Queue.php +++ b/version/203/class/Hook/Queue.php @@ -23,7 +23,7 @@ class Queue extends AbstractHook public static function bestellungInDB(array $args_arr) { if (array_key_exists('oBestellung', $args_arr) - && $args_arr['oBestellung']->kBestellung + && $_SESSION['Zahlungsart'] && (int)$_SESSION['Zahlungsart']->nWaehrendBestellung === 0 && $args_arr['oBestellung']->fGesamtsumme > 0 && self::Plugin()->oPluginEinstellungAssoc_arr['onlyPaid'] === 'Y' && AbstractCheckout::isMollie((int)$args_arr['oBestellung']->kZahlungsart, true)) { diff --git a/version/203/class/Queue.php b/version/203/class/Queue.php index 7be72b7..692fda1 100644 --- a/version/203/class/Queue.php +++ b/version/203/class/Queue.php @@ -37,7 +37,20 @@ public static function storno($delay) try { $checkout = AbstractCheckout::fromBestellung($o->kBestellung); - $checkout->storno(); + $pm = $checkout->PaymentMethod(); + if ($pm::ALLOW_AUTO_STORNO && $pm::METHOD === $checkout->getMollie()->method) { + if ($checkout->getBestellung()->cAbgeholt === 'Y' && (bool)$checkout->getModel()->bSynced === false) { + if (!in_array($checkout->getMollie()->status, [OrderStatus::STATUS_PAID, OrderStatus::STATUS_PAID, OrderStatus::STATUS_COMPLETED, OrderStatus::STATUS_AUTHORIZED], true)) { + $checkout->storno(); + } else { + $checkout->Log(sprintf('AutoStorno: Bestellung bezahlt? %s - Method: %s', $checkout->getMollie()->status, $checkout->getMollie()->method), LOGLEVEL_ERROR); + } + } else { + $checkout->Log('AutoStorno: bereits zur WAWI synchronisiert.', LOGLEVEL_ERROR); + } + } else { + $checkout->Log(sprintf('AutoStorno aktiv: %d (%s) - Method: %s', (int)$pm::ALLOW_AUTO_STORNO, $pm::METHOD, $checkout->getMollie()->method), LOGLEVEL_ERROR); + } } catch (Exception $e) { Helper::logExc($e); diff --git a/version/203/paymentmethod/JTLMollie.php b/version/203/paymentmethod/JTLMollie.php index 57ce70a..4b15d2a 100644 --- a/version/203/paymentmethod/JTLMollie.php +++ b/version/203/paymentmethod/JTLMollie.php @@ -20,6 +20,8 @@ class JTLMollie extends PaymentMethod const MAX_EXPIRY_DAYS = 100; + const ALLOW_AUTO_STORNO = false; + const ALLOW_PAYMENT_BEFORE_ORDER = false; /** diff --git a/version/203/paymentmethod/JTLMollieBancontact.php b/version/203/paymentmethod/JTLMollieBancontact.php index 2cd8366..1488372 100644 --- a/version/203/paymentmethod/JTLMollieBancontact.php +++ b/version/203/paymentmethod/JTLMollieBancontact.php @@ -4,5 +4,10 @@ class JTLMollieBancontact extends JTLMollie { + + const ALLOW_PAYMENT_BEFORE_ORDER = true; + + const ALLOW_AUTO_STORNO = true; + const METHOD = \Mollie\Api\Types\PaymentMethod::BANCONTACT; } diff --git a/version/203/paymentmethod/JTLMollieBelfius.php b/version/203/paymentmethod/JTLMollieBelfius.php index 91a6169..00c8e7c 100644 --- a/version/203/paymentmethod/JTLMollieBelfius.php +++ b/version/203/paymentmethod/JTLMollieBelfius.php @@ -4,5 +4,10 @@ class JTLMollieBelfius extends JTLMollie { + + const ALLOW_PAYMENT_BEFORE_ORDER = true; + + const ALLOW_AUTO_STORNO = true; + const METHOD = \Mollie\Api\Types\PaymentMethod::BELFIUS; } diff --git a/version/203/paymentmethod/JTLMollieEPS.php b/version/203/paymentmethod/JTLMollieEPS.php index df52c5e..df84b89 100644 --- a/version/203/paymentmethod/JTLMollieEPS.php +++ b/version/203/paymentmethod/JTLMollieEPS.php @@ -4,5 +4,9 @@ class JTLMollieEPS extends JTLMollie { + const ALLOW_PAYMENT_BEFORE_ORDER = true; + + const ALLOW_AUTO_STORNO = true; + const METHOD = \Mollie\Api\Types\PaymentMethod::EPS; } diff --git a/version/203/paymentmethod/JTLMollieGiropay.php b/version/203/paymentmethod/JTLMollieGiropay.php index 071e259..c0bbd8d 100644 --- a/version/203/paymentmethod/JTLMollieGiropay.php +++ b/version/203/paymentmethod/JTLMollieGiropay.php @@ -4,5 +4,9 @@ class JTLMollieGiropay extends JTLMollie { + const ALLOW_PAYMENT_BEFORE_ORDER = true; + + const ALLOW_AUTO_STORNO = true; + const METHOD = \Mollie\Api\Types\PaymentMethod::GIROPAY; } diff --git a/version/203/paymentmethod/JTLMollieIDEAL.php b/version/203/paymentmethod/JTLMollieIDEAL.php index b08d852..ba0b2df 100644 --- a/version/203/paymentmethod/JTLMollieIDEAL.php +++ b/version/203/paymentmethod/JTLMollieIDEAL.php @@ -4,5 +4,10 @@ class JTLMollieIDEAL extends JTLMollie { + + const ALLOW_PAYMENT_BEFORE_ORDER = true; + + const ALLOW_AUTO_STORNO = true; + const METHOD = \Mollie\Api\Types\PaymentMethod::IDEAL; } diff --git a/version/203/paymentmethod/JTLMollieKBC.php b/version/203/paymentmethod/JTLMollieKBC.php index 20d11fb..1a29e54 100644 --- a/version/203/paymentmethod/JTLMollieKBC.php +++ b/version/203/paymentmethod/JTLMollieKBC.php @@ -6,6 +6,10 @@ class JTLMollieKBC extends JTLMollie { const METHOD = \Mollie\Api\Types\PaymentMethod::KBC; + const ALLOW_PAYMENT_BEFORE_ORDER = true; + + const ALLOW_AUTO_STORNO = true; + public function getPaymentOptions(Bestellung $order, $apiType) { return ['description' => substr($order->cBestellNr, 0, 13)]; diff --git a/version/203/paymentmethod/JTLMollieKlarnaPayLater.php b/version/203/paymentmethod/JTLMollieKlarnaPayLater.php index 266953f..cb1438d 100644 --- a/version/203/paymentmethod/JTLMollieKlarnaPayLater.php +++ b/version/203/paymentmethod/JTLMollieKlarnaPayLater.php @@ -6,5 +6,9 @@ class JTLMollieKlarnaPayLater extends JTLMollie { const MAX_EXPIRY_DAYS = 28; + const ALLOW_PAYMENT_BEFORE_ORDER = true; + + const ALLOW_AUTO_STORNO = true; + const METHOD = \Mollie\Api\Types\PaymentMethod::KLARNA_PAY_LATER; } diff --git a/version/203/paymentmethod/JTLMollieKlarnaSliceIt.php b/version/203/paymentmethod/JTLMollieKlarnaSliceIt.php index 25289e2..d9a0482 100644 --- a/version/203/paymentmethod/JTLMollieKlarnaSliceIt.php +++ b/version/203/paymentmethod/JTLMollieKlarnaSliceIt.php @@ -6,5 +6,9 @@ class JTLMollieKlarnaSliceIt extends JTLMollie { const MAX_EXPIRY_DAYS = 28; + const ALLOW_PAYMENT_BEFORE_ORDER = true; + + const ALLOW_AUTO_STORNO = true; + const METHOD = \Mollie\Api\Types\PaymentMethod::KLARNA_SLICE_IT; } diff --git a/version/203/paymentmethod/JTLMollieMyBank.php b/version/203/paymentmethod/JTLMollieMyBank.php index def7553..bfec451 100644 --- a/version/203/paymentmethod/JTLMollieMyBank.php +++ b/version/203/paymentmethod/JTLMollieMyBank.php @@ -4,5 +4,10 @@ class JTLMollieMyBank extends JTLMollie { + + const ALLOW_PAYMENT_BEFORE_ORDER = true; + + const ALLOW_AUTO_STORNO = true; + const METHOD = \Mollie\Api\Types\PaymentMethod::MYBANK; } diff --git a/version/203/paymentmethod/JTLMolliePayPal.php b/version/203/paymentmethod/JTLMolliePayPal.php index d26096c..b3ef9cb 100644 --- a/version/203/paymentmethod/JTLMolliePayPal.php +++ b/version/203/paymentmethod/JTLMolliePayPal.php @@ -13,6 +13,8 @@ class JTLMolliePayPal extends JTLMollie const ALLOW_PAYMENT_BEFORE_ORDER = true; + const ALLOW_AUTO_STORNO = true; + /** * @throws ApiException * @throws IncompatiblePlatform diff --git a/version/203/paymentmethod/JTLMolliePaysafecard.php b/version/203/paymentmethod/JTLMolliePaysafecard.php index 920e0fa..272b799 100644 --- a/version/203/paymentmethod/JTLMolliePaysafecard.php +++ b/version/203/paymentmethod/JTLMolliePaysafecard.php @@ -6,6 +6,8 @@ class JTLMolliePaysafecard extends JTLMollie { const METHOD = \Mollie\Api\Types\PaymentMethod::PAYSAFECARD; + const ALLOW_AUTO_STORNO = true; + public function getPaymentOptions(Bestellung $order, $apiType) { return $apiType === 'payment' ? ['customerReference' => $order->oKunde->kKunde] : []; diff --git a/version/203/paymentmethod/JTLMolliePrzelewy24.php b/version/203/paymentmethod/JTLMolliePrzelewy24.php index ebd28ed..355ecdf 100644 --- a/version/203/paymentmethod/JTLMolliePrzelewy24.php +++ b/version/203/paymentmethod/JTLMolliePrzelewy24.php @@ -6,6 +6,9 @@ class JTLMolliePrzelewy24 extends JTLMollie { const METHOD = \Mollie\Api\Types\PaymentMethod::PRZELEWY24; + const ALLOW_PAYMENT_BEFORE_ORDER = true; + + const ALLOW_AUTO_STORNO = true; public function getPaymentOptions(Bestellung $order, $apiType) { diff --git a/version/203/paymentmethod/JTLMollieSofort.php b/version/203/paymentmethod/JTLMollieSofort.php index c11060b..0a4d191 100644 --- a/version/203/paymentmethod/JTLMollieSofort.php +++ b/version/203/paymentmethod/JTLMollieSofort.php @@ -4,5 +4,10 @@ class JTLMollieSofort extends JTLMollie { + + const ALLOW_PAYMENT_BEFORE_ORDER = true; + + const ALLOW_AUTO_STORNO = true; + const METHOD = \Mollie\Api\Types\PaymentMethod::SOFORT; } From 36488789faa283e3bc59144326fd36f1b877b308 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Fri, 21 May 2021 16:16:58 +0200 Subject: [PATCH 227/280] CreditCard Konstanten --- version/203/paymentmethod/JTLMollieCreditCard.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/version/203/paymentmethod/JTLMollieCreditCard.php b/version/203/paymentmethod/JTLMollieCreditCard.php index 7288926..84bde3d 100644 --- a/version/203/paymentmethod/JTLMollieCreditCard.php +++ b/version/203/paymentmethod/JTLMollieCreditCard.php @@ -10,6 +10,9 @@ class JTLMollieCreditCard extends JTLMollie { const METHOD = \Mollie\Api\Types\PaymentMethod::CREDITCARD; + const ALLOW_AUTO_STORNO = true; + const ALLOW_PAYMENT_BEFORE_ORDER = false; + const CACHE_TOKEN = 'creditcard:token'; const CACHE_TOKEN_TIMESTAMP = 'creditcard:token:timestamp'; From 3f609f3015434ba0fb8c9f9ecb99193608fbc06a Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Tue, 25 May 2021 12:51:05 +0200 Subject: [PATCH 228/280] cleanup --- version/203/adminmenu/info.php | 2 +- version/203/adminmenu/paymentmethods.php | 4 +- version/203/adminmenu/tpl/info.tpl | 6 +-- version/203/adminmenu/tpl/order.tpl | 4 +- version/203/adminmenu/tpl/orders.tpl | 8 +-- version/203/adminmenu/tpl/paymentmethods.tpl | 4 +- .../203/class/Checkout/AbstractCheckout.php | 35 ++++++------- .../203/class/Checkout/Order/OrderLine.php | 6 +-- version/203/class/Checkout/OrderCheckout.php | 31 ++++++------ version/203/class/Checkout/Payment/Amount.php | 3 +- .../203/class/Checkout/PaymentCheckout.php | 13 +++-- version/203/class/ExclusiveLock.php | 10 +--- version/203/class/Helper.php | 18 +++---- version/203/class/Hook/Checkbox.php | 2 +- version/203/class/Model/AbstractModel.php | 8 ++- version/203/class/Mollie.php | 16 +----- version/203/class/Queue.php | 49 +++++++++++++------ version/203/class/Shipment.php | 10 ++-- version/203/class/Traits/RequestData.php | 2 +- version/203/frontend/131_globalinclude.php | 5 +- version/203/frontend/140_smarty.php | 10 ++-- version/203/paymentmethod/JTLMollie.php | 2 + .../paymentmethod/JTLMollieBanktransfer.php | 2 +- .../203/paymentmethod/JTLMollieCreditCard.php | 37 -------------- version/203/paymentmethod/JTLMolliePayPal.php | 5 +- 25 files changed, 136 insertions(+), 156 deletions(-) diff --git a/version/203/adminmenu/info.php b/version/203/adminmenu/info.php index 817c5db..0430c6e 100644 --- a/version/203/adminmenu/info.php +++ b/version/203/adminmenu/info.php @@ -46,7 +46,7 @@ Shop::Smarty()->assign('update', $latestRelease); } - } catch (\Exception $e) { + } catch (Exception $e) { } Shop::Smarty()->display(Helper::oPlugin()->cAdminmenuPfad . '/tpl/info.tpl'); diff --git a/version/203/adminmenu/paymentmethods.php b/version/203/adminmenu/paymentmethods.php index f447846..18adb1e 100644 --- a/version/203/adminmenu/paymentmethods.php +++ b/version/203/adminmenu/paymentmethods.php @@ -57,13 +57,13 @@ foreach ($_allMethods as $method) { $id = $method->id === 'creditcard' ? 'kreditkarte' : $method->id; - $key = "kPlugin_{$oPlugin->kPlugin}_mollie{$id}"; + $key = "kPlugin_{$oPlugin->kPlugin}_mollie$id"; $class = null; $shop = null; $oClass = null; - if (!in_array($id, ['voucher', 'giftcard', 'directdebit'], true) && array_key_exists($key, $oPlugin->oPluginZahlungsKlasseAssoc_arr)) { + if (array_key_exists($key, $oPlugin->oPluginZahlungsKlasseAssoc_arr) && !in_array($id, ['voucher', 'giftcard', 'directdebit'], true)) { $class = $oPlugin->oPluginZahlungsKlasseAssoc_arr[$key]; include_once($oPlugin->cPluginPfad . 'paymentmethod/' . $class->cClassPfad); /** @var JTLMollie $oClass */ diff --git a/version/203/adminmenu/tpl/info.tpl b/version/203/adminmenu/tpl/info.tpl index 2952fc6..2d41c95 100644 --- a/version/203/adminmenu/tpl/info.tpl +++ b/version/203/adminmenu/tpl/info.tpl @@ -100,10 +100,10 @@ $(function () { $(document).on('click', '.nav-tabs .tab a', function () { - var target = $(this).attr('href'); - var res = target.match(/plugin-tab-(\d+)/); + const target = $(this).attr('href'); + const res = target.match(/plugin-tab-(\d+)/); if (res !== null) { - var kAdminMenu = parseInt(res[res.index]); + const kAdminMenu = parseInt(res[res.index]); history.replaceState(null, 'emarketing', 'plugin.php?kPlugin={$oPlugin->kPlugin}&kPluginAdminMenu=' + kAdminMenu); } }); diff --git a/version/203/adminmenu/tpl/order.tpl b/version/203/adminmenu/tpl/order.tpl index 7bacde9..aad5810 100644 --- a/version/203/adminmenu/tpl/order.tpl +++ b/version/203/adminmenu/tpl/order.tpl @@ -88,9 +88,9 @@ n/a {/if} - RePay-URL: + - + diff --git a/version/203/adminmenu/tpl/orders.tpl b/version/203/adminmenu/tpl/orders.tpl index 258615b..a499f32 100644 --- a/version/203/adminmenu/tpl/orders.tpl +++ b/version/203/adminmenu/tpl/orders.tpl @@ -143,10 +143,10 @@
- - - - + + + +
diff --git a/version/203/adminmenu/tpl/paymentmethods.tpl b/version/203/adminmenu/tpl/paymentmethods.tpl index 6b5bff6..7aedaab 100644 --- a/version/203/adminmenu/tpl/paymentmethods.tpl +++ b/version/203/adminmenu/tpl/paymentmethods.tpl @@ -10,12 +10,12 @@ {$profile->review->status} {/if} {if $profile->_links->checkoutPreviewUrl->href} - + Checkout Preview {/if} - + Mollie Dashboard diff --git a/version/203/class/Checkout/AbstractCheckout.php b/version/203/class/Checkout/AbstractCheckout.php index 8d36b72..2995254 100644 --- a/version/203/class/Checkout/AbstractCheckout.php +++ b/version/203/class/Checkout/AbstractCheckout.php @@ -13,7 +13,9 @@ use JTLMollie; use Kunde; use Mollie\Api\Exceptions\ApiException; +use Mollie\Api\Resources\BaseResource; use Mollie\Api\Resources\Order; +use Mollie\Api\Resources\Refund; use Mollie\Api\Types\OrderStatus; use Mollie\Api\Types\PaymentStatus; use PaymentMethod; @@ -79,7 +81,7 @@ abstract class AbstractCheckout /** * AbstractCheckout constructor. - * @param $oBestellung + * @param Bestellung $oBestellung * @param null $api */ public function __construct(Bestellung $oBestellung, $api = null) @@ -100,7 +102,7 @@ public static function isMollie($kBestellung, $checkZA = false) ':kZahlungsart' => $kBestellung, ':cModulId' => 'kPlugin_' . self::Plugin()->kPlugin . '_%' ], 1); - return $res ? true : false; + return (bool)$res; } return ($res = Shop::DB()->executeQueryPrepared('SELECT kId FROM xplugin_ws_mollie_payments WHERE kBestellung = :kBestellung;', [ @@ -130,7 +132,7 @@ public static function finalizeOrder($sessionHash, $id, $test = false) Shop::DB()->update('tzahlungsession', 'cZahlungsID', $sessionHash, $paymentSession); $api = new API($test); - if (substr($id, 0, 3) === 'tr_') { + if (strpos($id, 'tr_') === 0) { $mollie = $api->Client()->payments->get($id); } else { $mollie = $api->Client()->orders->get($id); @@ -149,13 +151,13 @@ public static function finalizeOrder($sessionHash, $id, $test = false) if ($order->kBestellung) { - $paymentSession->kBestellung = (int)$order->kBestellung; + $paymentSession->kBestellung = $order->kBestellung; Shop::DB()->update('tzahlungsession', 'cZahlungsID', $sessionHash, $paymentSession); try { - $checkout = AbstractCheckout::fromID($id, false, $order); + $checkout = self::fromID($id, false, $order); } catch (Exception $e) { - if (substr($id, 0, 3) === 'tr_') { + if (strpos($id, 'tr_') === 0) { $checkoutClass = PaymentCheckout::class; } else { $checkoutClass = OrderCheckout::class; @@ -188,14 +190,14 @@ public static function finalizeOrder($sessionHash, $id, $test = false) */ public static function fromID($id, $bFill = true, Bestellung $order = null) { - if ($model = Payment::fromID($id)) { + if (($model = Payment::fromID($id))) { return static::fromModel($model, $bFill, $order); } throw new RuntimeException(sprintf('Error loading Order: %s', $id)); } /** - * @param Order|\Mollie\Api\Resources\Payment $model + * @param Payment $model * @param bool $bFill * @param Bestellung|null $order * @return OrderCheckout|PaymentCheckout @@ -232,7 +234,7 @@ public static function fromModel($model, $bFill = true, Bestellung $order = null public static function fromBestellung($kBestellung) { if ($model = Payment::fromID($kBestellung, 'kBestellung')) { - return self::fromModel($model); + return static::fromModel($model); } throw new RuntimeException(sprintf('Error loading Order for Bestellung: %s', $kBestellung)); } @@ -314,7 +316,7 @@ public static function sendReminder($kID) /** * @param AbstractCheckout $checkout - * @return \Mollie\Api\Resources\BaseResource|\Mollie\Api\Resources\Refund + * @return BaseResource|Refund * @throws ApiException */ public static function refund(AbstractCheckout $checkout) @@ -409,7 +411,6 @@ public function PaymentMethod() $this->paymentMethod = PaymentMethod::create("kPlugin_{$this::Plugin()->kPlugin}_mollie"); } } - /** @noinspection PhpIncompatibleReturnTypeInspection */ return $this->paymentMethod; } @@ -444,7 +445,7 @@ public static function cancel($checkout) throw new RuntimeException('AbstractCheckout::cancel: Invalid Checkout!'); } - public function loadRequest($options = []) + public function loadRequest(&$options = []) { if ($this->getBestellung()) { if ($this->getBestellung()->oKunde->nRegistriert @@ -609,7 +610,7 @@ protected static function aktualisiereLagerbestand($Artikel, $nAnzahl, $Warenkor ) { foreach ($WarenkorbPosEigenschaftArr as $eWert) { $EigenschaftWert = new EigenschaftWert($eWert->kEigenschaftWert); - if ($EigenschaftWert->fPackeinheit == 0) { + if ($EigenschaftWert->fPackeinheit === .0) { $EigenschaftWert->fPackeinheit = 1; } Shop::DB()->query( @@ -635,7 +636,7 @@ protected static function aktualisiereLagerbestand($Artikel, $nAnzahl, $Warenkor } // Stücklisten Komponente if (ArtikelHelper::isStuecklisteKomponente($Artikel->kArtikel)) { - self::aktualisiereKomponenteLagerbestand($Artikel->kArtikel, $artikelBestand, isset($Artikel->cLagerKleinerNull) && $Artikel->cLagerKleinerNull === 'Y' ? true : false); + self::aktualisiereKomponenteLagerbestand($Artikel->kArtikel, $artikelBestand, isset($Artikel->cLagerKleinerNull) && $Artikel->cLagerKleinerNull === 'Y'); } } // Aktualisiere Merkmale in tartikelmerkmal vom Vaterartikel @@ -663,7 +664,7 @@ protected static function aktualisiereStuecklistenLagerbestand($oStueckListeArti FROM tstueckliste JOIN tartikel ON tartikel.kArtikel = tstueckliste.kArtikel - WHERE tstueckliste.kStueckliste = {$kStueckListe} + WHERE tstueckliste.kStueckliste = $kStueckListe AND tartikel.cLagerBeachten = 'Y'", 2 ); @@ -724,7 +725,7 @@ protected static function aktualisiereKomponenteLagerbestand($kKomponenteArtikel FROM tstueckliste JOIN tartikel ON tartikel.kStueckliste = tstueckliste.kStueckliste - WHERE tstueckliste.kArtikel = {$kKomponenteArtikel} + WHERE tstueckliste.kArtikel = $kKomponenteArtikel AND tartikel.cLagerBeachten = 'Y'", 2 ); @@ -895,7 +896,7 @@ public function completlyPaid() if ($row = Shop::DB()->executeQueryPrepared("SELECT SUM(fBetrag) as fBetragSumme FROM tzahlungseingang WHERE kBestellung = :kBestellung", [ ':kBestellung' => $this->getBestellung()->kBestellung ], 1)) { - return $row->fBetragSumme >= round($this->getBestellung()->fGesamtsumme * (float)$this->getBestellung()->fWaehrungsFaktor, 2); + return $row->fBetragSumme >= round($this->getBestellung()->fGesamtsumme * $this->getBestellung()->fWaehrungsFaktor, 2); } return false; diff --git a/version/203/class/Checkout/Order/OrderLine.php b/version/203/class/Checkout/Order/OrderLine.php index ba0c18b..9b9dec4 100644 --- a/version/203/class/Checkout/Order/OrderLine.php +++ b/version/203/class/Checkout/Order/OrderLine.php @@ -94,7 +94,7 @@ public static function getCredit(Bestellung $oBestellung) public static function factory($oPosition, $currency = null) { if (!$oPosition) { - throw new RuntimeException('$oPosition invalid:', print_r($oPosition)); + throw new RuntimeException('$oPosition invalid:', print_r($oPosition,1)); } $resource = new static(); @@ -167,8 +167,8 @@ protected function fill($oPosition, $currency = null) /** @var WarenkorbPosEigenschaft $warenkorbPosEigenschaft */ foreach ($oPosition->WarenkorbPosEigenschaftArr as $warenkorbPosEigenschaft) { $metadata['properties'][] = [ - 'kEigenschaft' => (int)$warenkorbPosEigenschaft->kEigenschaft, - 'kEigenschaftWert' => (int)$warenkorbPosEigenschaft->kEigenschaftWert, + 'kEigenschaft' => $warenkorbPosEigenschaft->kEigenschaft, + 'kEigenschaftWert' => $warenkorbPosEigenschaft->kEigenschaftWert, 'name' => utf8_encode($warenkorbPosEigenschaft->cEigenschaftName), 'value' => utf8_encode($warenkorbPosEigenschaft->cEigenschaftWertName), ]; diff --git a/version/203/class/Checkout/OrderCheckout.php b/version/203/class/Checkout/OrderCheckout.php index df10f7f..c717fd3 100644 --- a/version/203/class/Checkout/OrderCheckout.php +++ b/version/203/class/Checkout/OrderCheckout.php @@ -4,8 +4,11 @@ namespace ws_mollie\Checkout; +use DateTime; +use DateTimeZone; use Exception; use Mollie\Api\Exceptions\ApiException; +use Mollie\Api\Exceptions\IncompatiblePlatform; use Mollie\Api\Resources\Order; use Mollie\Api\Resources\Payment; use Mollie\Api\Types\OrderStatus; @@ -54,7 +57,7 @@ class OrderCheckout extends AbstractCheckout * @param OrderCheckout $checkout * @return string * @throws ApiException - * @throws \Mollie\Api\Exceptions\IncompatiblePlatform + * @throws IncompatiblePlatform */ public static function capture(OrderCheckout $checkout) { @@ -89,7 +92,7 @@ public function getMollie($force = false) */ public static function cancel($checkout) { - if (!$checkout->getMollie()->isCancelable) { + if (!$checkout->getMollie() || !$checkout->getMollie()->isCancelable) { throw new RuntimeException('Bestellung kann nicht abgebrochen werden.'); } $order = $checkout->getMollie()->cancel(); @@ -99,12 +102,13 @@ public static function cancel($checkout) /** * @return array + * @throws Exception */ public function getShipments() { $shipments = []; $lieferschien_arr = Shop::DB()->executeQueryPrepared("SELECT kLieferschein FROM tlieferschein WHERE kInetBestellung = :kBestellung", [ - ':kBestellung' => (int)$this->getBestellung()->kBestellung + ':kBestellung' => $this->getBestellung()->kBestellung ], 2); foreach ($lieferschien_arr as $lieferschein) { @@ -138,7 +142,7 @@ public function cancelOrRefund($force = false) /** * @param array $paymentOptions - * @return Order|Payment + * @return Order */ public function create(array $paymentOptions = []) { @@ -189,7 +193,7 @@ public function create(array $paymentOptions = []) */ public function getPayment($search = false) { - if (!$this->_payment && $search) { + if (!$this->_payment && $search && $this->getMollie()) { foreach ($this->getMollie()->payments() as $payment) { if (in_array($payment->status, [ PaymentStatus::STATUS_AUTHORIZED, @@ -245,7 +249,7 @@ public function updateModel() * @param array $options * @return $this|OrderCheckout */ - public function loadRequest($options = []) + public function loadRequest(&$options = []) { parent::loadRequest($options); @@ -285,7 +289,7 @@ public function loadRequest($options = []) if ($dueDays = $this->PaymentMethod()->getExpiryDays()) { try { $max = $this->method && strpos($this->method, 'klarna') !== false ? 28 : 100; - $date = new \DateTime(sprintf("+%d DAYS", min($dueDays, $max)), new \DateTimeZone('UTC')); + $date = new DateTime(sprintf("+%d DAYS", min($dueDays, $max)), new DateTimeZone('UTC')); $this->expiresAt = $date->format('Y-m-d'); //date('Y-m-d', strtotime(sprintf("+%d DAYS", min($dueDays, $max)))); } catch (Exception $e) { @@ -307,17 +311,16 @@ public function getIncomingPayment() return null; } + $cHinweis = sprintf("%s / %s", $this->getMollie()->id, $this->getPayment(true)->id); if (Helper::getSetting('wawiPaymentID') === 'ord') { $cHinweis = $this->getMollie()->id; - } else { - if (Helper::getSetting('wawiPaymentID') === 'tr') { - $cHinweis = $this->getPayment(true)->id; - } else { - $cHinweis = sprintf("%s / %s", $this->getMollie()->id, $this->getPayment(true)->id); - } + } else if (Helper::getSetting('wawiPaymentID') === 'tr') { + $cHinweis = $this->getPayment(true)->id; } + /** @var Payment $payment */ + /** @noinspection NullPointerExceptionInspection */ foreach ($this->getMollie()->payments() as $payment) { if (in_array($payment->status, [PaymentStatus::STATUS_AUTHORIZED, PaymentStatus::STATUS_PAID], true)) { @@ -345,7 +348,7 @@ protected function updateOrderNumber() try { if ($this->getMollie()) { $this->getMollie()->orderNumber = $this->getBestellung()->cBestellNr; - $this->getMollie()->webhookUrl = \Shop::getURL() . '/?mollie=1'; + $this->getMollie()->webhookUrl = Shop::getURL() . '/?mollie=1'; $this->getMollie()->update(); } } catch (Exception $e) { diff --git a/version/203/class/Checkout/Payment/Amount.php b/version/203/class/Checkout/Payment/Amount.php index 21acef9..125829d 100644 --- a/version/203/class/Checkout/Payment/Amount.php +++ b/version/203/class/Checkout/Payment/Amount.php @@ -4,6 +4,7 @@ namespace ws_mollie\Checkout\Payment; use Shop; +use stdClass; use ws_mollie\Checkout\AbstractResource; use ws_mollie\Checkout\Exception\ResourceValidityException; @@ -46,7 +47,7 @@ public static function factory($value, $currency = null, $useRounding = false) } /** - * @return \stdClass + * @return stdClass */ public static function FallbackCurrency() { diff --git a/version/203/class/Checkout/PaymentCheckout.php b/version/203/class/Checkout/PaymentCheckout.php index f8fce8f..f11e22b 100644 --- a/version/203/class/Checkout/PaymentCheckout.php +++ b/version/203/class/Checkout/PaymentCheckout.php @@ -7,9 +7,11 @@ use Exception; use Mollie\Api\Exceptions\ApiException; use Mollie\Api\Exceptions\IncompatiblePlatform; +use Mollie\Api\Resources\Order; use Mollie\Api\Resources\Payment; use Mollie\Api\Types\PaymentStatus; use RuntimeException; +use Shop; use ws_mollie\Checkout\Payment\Address; use ws_mollie\Checkout\Payment\Amount; @@ -38,6 +40,8 @@ class PaymentCheckout extends AbstractCheckout /** * @param PaymentCheckout $checkout * @return Payment + * @throws ApiException + * @throws IncompatiblePlatform */ public static function cancel($checkout) { @@ -109,7 +113,7 @@ public function cancelOrRefund($force = false) /** * @param array $paymentOptions - * @return \Mollie\Api\Resources\Order|Payment|\ws_mollie\Model\Payment + * @return Payment */ public function create(array $paymentOptions = []) { @@ -147,7 +151,7 @@ public function create(array $paymentOptions = []) * @param array $options * @return $this|PaymentCheckout */ - public function loadRequest($options = []) + public function loadRequest(&$options = []) { parent::loadRequest($options); @@ -199,11 +203,12 @@ protected function setMollie($model) /** * @return $this */ - protected function updateOrderNumber(){ + protected function updateOrderNumber() + { try { if ($this->getMollie()) { $this->getMollie()->description = 'Order ' . $this->getBestellung()->cBestellNr; - $this->getMollie()->webhookUrl = \Shop::getURL() . '/?mollie=1'; + $this->getMollie()->webhookUrl = Shop::getURL() . '/?mollie=1'; $this->getMollie()->update(); } } catch (Exception $e) { diff --git a/version/203/class/ExclusiveLock.php b/version/203/class/ExclusiveLock.php index 3e481c9..f3d3d95 100644 --- a/version/203/class/ExclusiveLock.php +++ b/version/203/class/ExclusiveLock.php @@ -18,7 +18,7 @@ public function __construct($key, $path = "") $this->key = $key; $this->path = rtrim(realpath($path), '/') . '/'; if (!is_dir($path) || !is_writable($path)) { - throw new RuntimeException("Lock Path '{$path}' doesn't exist, or is not writable!"); + throw new RuntimeException("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", 'wb+'); @@ -32,6 +32,7 @@ public function __destruct() } } + /** @noinspection ForgottenDebugOutputInspection */ public function unlock() { $key = $this->key; @@ -40,8 +41,6 @@ public function unlock() 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; @@ -54,13 +53,8 @@ public function 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); diff --git a/version/203/class/Helper.php b/version/203/class/Helper.php index 5f2a8be..514f1c5 100644 --- a/version/203/class/Helper.php +++ b/version/203/class/Helper.php @@ -8,6 +8,7 @@ use PclZip; use Plugin; use Shop; + use SmartyException; use stdClass; if (!class_exists('ws_mollie\Helper')) { @@ -42,7 +43,7 @@ public static function autoload() require_once __DIR__ . '/../../../vendor/autoload.php'; } - self::$_autoload = spl_autoload_register(function ($class) { + self::$_autoload = spl_autoload_register(static function ($class) { $prefix = 'ws_mollie\\'; $baseDir = __DIR__ . DIRECTORY_SEPARATOR; @@ -93,10 +94,8 @@ public static function selfupdate() 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!"); - } + if (file_exists($tmpDir . $filename) && !unlink($tmpDir . $filename)) { + throw new Exception("Temporäre Datei '" . $tmpDir . $filename . "' konnte nicht gelöscht werden!"); } // 2. DOWNLOAD @@ -165,9 +164,8 @@ public static function getLatestRelease($force = false) 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); } + return json_decode($lastRelease); } /** @@ -211,7 +209,7 @@ public static function addAlert($content, $type, $namespace) * * @param $namespace * @return string - * @throws \SmartyException + * @throws SmartyException */ public static function showAlerts($namespace) { @@ -255,7 +253,7 @@ public static function setSetting($name, $value) public static function oPlugin($force = false) { if ($force === true) { - self::$oPlugin = new Plugin(self::oPlugin(false)->kPlugin, true); + self::$oPlugin = new Plugin(self::oPlugin()->kPlugin, true); } else if (null === self::$oPlugin) { self::$oPlugin = Plugin::getPluginById(__NAMESPACE__); } @@ -300,7 +298,7 @@ public static function getMasterMail($e = false) if ($e === true && $mail != '') { $mail = base64_encode($mail); $eMail = ""; - foreach (str_split($mail, 1) as $c) { + foreach (str_split($mail) as $c) { $eMail .= chr(ord($c) ^ 0x00100110); } return base64_encode($eMail); diff --git a/version/203/class/Hook/Checkbox.php b/version/203/class/Hook/Checkbox.php index 6df972c..9ab5ca8 100644 --- a/version/203/class/Hook/Checkbox.php +++ b/version/203/class/Hook/Checkbox.php @@ -16,7 +16,7 @@ public static function execute(&$args_arr) return; } - if (array_key_exists('nAnzeigeOrt', $args_arr) && $args_arr['nAnzeigeOrt'] === CHECKBOX_ORT_BESTELLABSCHLUSS && (int)Session::getInstance()->Customer()->nRegistriert) { + if (array_key_exists('nAnzeigeOrt', $args_arr) && $args_arr['nAnzeigeOrt'] === CHECKBOX_ORT_BESTELLABSCHLUSS && Session::getInstance()->Customer()->nRegistriert) { $mCustomer = Customer::fromID(Session::getInstance()->Customer()->kKunde, 'kKunde'); diff --git a/version/203/class/Model/AbstractModel.php b/version/203/class/Model/AbstractModel.php index f543a7e..e041d4e 100644 --- a/version/203/class/Model/AbstractModel.php +++ b/version/203/class/Model/AbstractModel.php @@ -30,9 +30,15 @@ public function __construct($data = null) } } + /** + * @param $id + * @param string $col + * @param false $failIfNotExists + * @return static + */ public static function fromID($id, $col = 'kID', $failIfNotExists = false) { - if ($payment = Shop::DB()->executeQueryPrepared("SELECT * FROM " . static::TABLE . " WHERE {$col} = :id", + if ($payment = Shop::DB()->executeQueryPrepared("SELECT * FROM " . static::TABLE . " WHERE `$col` = :id", [':id' => $id], 1)) { return new static($payment); } diff --git a/version/203/class/Mollie.php b/version/203/class/Mollie.php index c618408..0381cdc 100644 --- a/version/203/class/Mollie.php +++ b/version/203/class/Mollie.php @@ -1,6 +1,4 @@ kPlugin; - if ((int)$kPlugin) { + if ($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", [ @@ -96,7 +84,7 @@ public static function getLocales() $result[] = AbstractCheckout::getLocale($sS->cISO, $land); } } - return array_unique($result); + return array_intersect(array_unique($result), $locales); } public static function getCurrencies() diff --git a/version/203/class/Queue.php b/version/203/class/Queue.php index 692fda1..82b5ba9 100644 --- a/version/203/class/Queue.php +++ b/version/203/class/Queue.php @@ -23,7 +23,10 @@ class Queue use Plugin; - + /** + * @param $delay + * @return bool + */ public static function storno($delay) { if (!$delay) { @@ -40,7 +43,7 @@ public static function storno($delay) $pm = $checkout->PaymentMethod(); if ($pm::ALLOW_AUTO_STORNO && $pm::METHOD === $checkout->getMollie()->method) { if ($checkout->getBestellung()->cAbgeholt === 'Y' && (bool)$checkout->getModel()->bSynced === false) { - if (!in_array($checkout->getMollie()->status, [OrderStatus::STATUS_PAID, OrderStatus::STATUS_PAID, OrderStatus::STATUS_COMPLETED, OrderStatus::STATUS_AUTHORIZED], true)) { + if (!in_array($checkout->getMollie()->status, [OrderStatus::STATUS_PAID, OrderStatus::STATUS_COMPLETED, OrderStatus::STATUS_AUTHORIZED], true)) { $checkout->storno(); } else { $checkout->Log(sprintf('AutoStorno: Bestellung bezahlt? %s - Method: %s', $checkout->getMollie()->status, $checkout->getMollie()->method), LOGLEVEL_ERROR); @@ -59,6 +62,9 @@ public static function storno($delay) return true; } + /** + * @param int $limit + */ public static function run($limit = 10) { @@ -82,7 +88,7 @@ public static function run($limit = 10) } } catch (Exception $e) { - Jtllog::writeLog($e->getMessage() . " ({$type}, {$id})"); + Jtllog::writeLog($e->getMessage() . " ($type, $id)"); $todo->done("{$e->getMessage()}\n{$e->getFile()}:{$e->getLine()}\n{$e->getTraceAsString()}"); } } @@ -95,10 +101,11 @@ public static function run($limit = 10) /** * @param $limit * @return Generator|QueueModel[] + * @noinspection PhpReturnDocTypeMismatchInspection + * @noinspection SqlResolve */ private static function getOpen($limit) { - /** @noinspection SqlResolve */ $open = Shop::DB()->executeQueryPrepared(sprintf("SELECT * FROM %s WHERE dDone IS NULL AND `bLock` IS NULL ORDER BY dCreated DESC LIMIT 0, :LIMIT;", QueueModel::TABLE), [ ':LIMIT' => $limit ], 2); @@ -108,6 +115,11 @@ private static function getOpen($limit) } } + /** + * @param $todo + * @return bool + * @noinspection SqlResolve + */ protected static function lock($todo) { return $todo->kId && Shop::DB()->executeQueryPrepared(sprintf('UPDATE %s SET `bLock` = NOW() WHERE `bLock` IS NULL AND kId = :kId', QueueModel::TABLE), [ @@ -116,6 +128,12 @@ protected static function lock($todo) } + /** + * @param $id + * @param QueueModel $todo + * @return bool + * @throws Exception + */ protected static function handleWebhook($id, QueueModel $todo) { $checkout = AbstractCheckout::fromID($id); @@ -123,7 +141,7 @@ protected static function handleWebhook($id, QueueModel $todo) $checkout->handleNotification(); return $todo->done('Status: ' . $checkout->getMollie()->status); } - throw new RuntimeException("Bestellung oder Zahlungsart konnte nicht geladen werden: {$id}"); + throw new RuntimeException("Bestellung oder Zahlungsart konnte nicht geladen werden: $id"); } /** @@ -132,6 +150,7 @@ protected static function handleWebhook($id, QueueModel $todo) * @return bool * @throws ApiException * @throws IncompatiblePlatform + * @throws Exception */ protected static function handleHook($hook, QueueModel $todo) { @@ -150,8 +169,8 @@ protected static function handleHook($hook, QueueModel $todo) /** @var $method JTLMollie */ if ((int)$data['status'] && array_key_exists('status', $data) - && $checkout->PaymentMethod() && (strpos($checkout->getModel()->kID, 'tr_') === false) + && $checkout->PaymentMethod() && $checkout->getMollie()) { /** @var OrderCheckout $checkout */ $checkout->handleNotification(); @@ -162,12 +181,12 @@ protected static function handleHook($hook, QueueModel $todo) if ($shipments = Shipment::syncBestellung($checkout)) { foreach ($shipments as $shipment) { if (is_string($shipment)) { - $checkout->PaymentMethod()->Log("Shipping-Error: {$shipment}", $checkout->LogData()); - $result .= "Shipping-Error: {$shipment};\n"; + $checkout->PaymentMethod()->Log("Shipping-Error: $shipment", $checkout->LogData()); + $result .= "Shipping-Error: $shipment;\n"; } else { $checkout->PaymentMethod()->Log("Order shipped: \n" . print_r($shipment, 1)); - $result .= "Order shipped: {$shipment->id};\n"; + $result .= "Order shipped: $shipment->id;\n"; } } } else { @@ -184,10 +203,10 @@ protected static function handleHook($hook, QueueModel $todo) } else { $result = 'Nothing to do.'; } + $checkout->PaymentMethod()->Log("Queue::handleHook: " . $result, $checkout->LogData()); } else { $result = "kBestellung missing"; } - $checkout->PaymentMethod()->Log("Queue::handleHook: " . $result, $checkout->LogData()); return $todo->done($result); case HOOK_BESTELLUNGEN_XML_BEARBEITESTORNO: @@ -202,13 +221,15 @@ protected static function handleHook($hook, QueueModel $todo) return false; } + /** + * @param $todo + * @return bool + */ protected static function unlock($todo) { - if ($todo->kId && Shop::DB()->executeQueryPrepared(sprintf('UPDATE %s SET `bLock` = NULL WHERE kId = :kId', QueueModel::TABLE), [ + return $todo->kId && Shop::DB()->executeQueryPrepared(sprintf('UPDATE %s SET `bLock` = NULL WHERE kId = :kId', QueueModel::TABLE), [ 'kId' => $todo->kId - ], 3) >= 1) { - } - + ], 3) >= 1; } } \ No newline at end of file diff --git a/version/203/class/Shipment.php b/version/203/class/Shipment.php index 7152dad..24aa6c7 100644 --- a/version/203/class/Shipment.php +++ b/version/203/class/Shipment.php @@ -62,6 +62,7 @@ class Shipment extends AbstractResource * Shipment constructor. * @param $kLieferschein * @param OrderCheckout|null $checkout + * @throws Exception */ public function __construct($kLieferschein, OrderCheckout $checkout = null) { @@ -116,17 +117,14 @@ public static function syncBestellung(OrderCheckout $checkout) throw new RuntimeException('Shipping deaktiviert'); } - if (($shippingActive === 'K') && ((int)$checkout->getBestellung()->cStatus !== BESTELLUNG_STATUS_VERSANDT) && !$oKunde->nRegistriert) { + if ($shippingActive === 'K' && !$oKunde->nRegistriert && (int)$checkout->getBestellung()->cStatus !== BESTELLUNG_STATUS_VERSANDT) { throw new RuntimeException('Shipping für Gast-Bestellungen und Teilversand deaktiviert'); } /** @var Lieferschein $oLieferschein */ foreach ($checkout->getBestellung()->oLieferschein_arr as $oLieferschein) { - try { - $shipment = new Shipment($oLieferschein->getLieferschein(), $checkout); - $mode = self::Plugin()->oPluginEinstellungAssoc_arr['shippingMode']; switch ($mode) { case 'A': @@ -152,7 +150,7 @@ public static function syncBestellung(OrderCheckout $checkout) $shipments[] = $e->getMessage(); } catch (Exception $e) { $shipments[] = $e->getMessage(); - $checkout->Log("mollie: Shipment::syncBestellung (BestellNr. {$checkout->getBestellung()->cBestellNr}, Lieferschein: {$shipment->getLieferschein()->getLieferscheinNr()}) - " . $e->getMessage(), LOGLEVEL_ERROR); + $checkout->Log("mollie: Shipment::syncBestellung (BestellNr. {$checkout->getBestellung()->cBestellNr}, Lieferschein: {$oLieferschein->getLieferscheinNr()}) - " . $e->getMessage(), LOGLEVEL_ERROR); } } } @@ -160,7 +158,7 @@ public static function syncBestellung(OrderCheckout $checkout) } /** - * @return mixed + * @return bool * @throws ApiException * @throws IncompatiblePlatform * @throws Exception diff --git a/version/203/class/Traits/RequestData.php b/version/203/class/Traits/RequestData.php index f56f6ef..72eda6b 100644 --- a/version/203/class/Traits/RequestData.php +++ b/version/203/class/Traits/RequestData.php @@ -40,7 +40,7 @@ public function __set($name, $value) * @param array $options * @return $this */ - public function loadRequest($options = []) + public function loadRequest(&$options = []) { return $this; } diff --git a/version/203/frontend/131_globalinclude.php b/version/203/frontend/131_globalinclude.php index a5cce47..2861d31 100644 --- a/version/203/frontend/131_globalinclude.php +++ b/version/203/frontend/131_globalinclude.php @@ -16,8 +16,7 @@ ifndef('MOLLIE_QUEUE_MAX', 3); Queue::run(MOLLIE_QUEUE_MAX); - if (strpos($_SERVER['PHP_SELF'], 'bestellabschluss.php') !== false - && array_key_exists('hash', $_REQUEST)) { + if (array_key_exists('hash', $_REQUEST) && strpos($_SERVER['PHP_SELF'], 'bestellabschluss.php') !== false) { $sessionHash = substr(StringHandler::htmlentities(StringHandler::filterXSS($_REQUEST['hash'])), 1); $paymentSession = Shop::DB()->select('tzahlungsession', 'cZahlungsID', $sessionHash); if ($paymentSession && $paymentSession->kBestellung) { @@ -27,7 +26,7 @@ $oZahlungsID = Shop::DB()->query(" SELECT cId FROM tbestellid - WHERE kBestellung = " . (int)$order->kBestellung, 1 + WHERE kBestellung = " . (int)$paymentSession->kBestellung, 1 ); if (is_object($oZahlungsID)) { header('Location: ' . Shop::getURL() . '/bestellabschluss.php?i=' . $oZahlungsID->cId); diff --git a/version/203/frontend/140_smarty.php b/version/203/frontend/140_smarty.php index c067251..78bbcaa 100644 --- a/version/203/frontend/140_smarty.php +++ b/version/203/frontend/140_smarty.php @@ -32,21 +32,21 @@ background-color: #eee; color: black; } - {$selector} label { - {$border} + $selector label { + $border } - {$selector} label::after { + $selector label::after { clear: both; content: ' '; display: block; } - {$selector} label span small { + $selector label span small { line-height: 48px; } - {$selector} label img { + $selector label img { float: right; } diff --git a/version/203/paymentmethod/JTLMollie.php b/version/203/paymentmethod/JTLMollie.php index 4b15d2a..27bfaea 100644 --- a/version/203/paymentmethod/JTLMollie.php +++ b/version/203/paymentmethod/JTLMollie.php @@ -88,10 +88,12 @@ public function preparePaymentProcess($order) if ($api === 'payment') { $checkout = new PaymentCheckout($order); $payment = $checkout->create($paymentOptions); + /** @noinspection NullPointerExceptionInspection */ $url = $payment->getCheckoutUrl(); } else { $checkout = new OrderCheckout($order); $mOrder = $checkout->create($paymentOptions); + /** @noinspection NullPointerExceptionInspection */ $url = $mOrder->getCheckoutUrl(); } diff --git a/version/203/paymentmethod/JTLMollieBanktransfer.php b/version/203/paymentmethod/JTLMollieBanktransfer.php index 90022ea..3fcaada 100644 --- a/version/203/paymentmethod/JTLMollieBanktransfer.php +++ b/version/203/paymentmethod/JTLMollieBanktransfer.php @@ -21,7 +21,7 @@ public function getPaymentOptions(Bestellung $order, $apiType) $dueDays = $this->getExpiryDays(); if ($dueDays > 3) { - $paymentOptions['dueDate'] = date('Y-m-d', strtotime("+{$dueDays} DAYS")); + $paymentOptions['dueDate'] = date('Y-m-d', strtotime("+$dueDays DAYS")); } return $paymentOptions; } diff --git a/version/203/paymentmethod/JTLMollieCreditCard.php b/version/203/paymentmethod/JTLMollieCreditCard.php index 84bde3d..578c163 100644 --- a/version/203/paymentmethod/JTLMollieCreditCard.php +++ b/version/203/paymentmethod/JTLMollieCreditCard.php @@ -16,11 +16,6 @@ class JTLMollieCreditCard extends JTLMollie const CACHE_TOKEN = 'creditcard:token'; const CACHE_TOKEN_TIMESTAMP = 'creditcard:token:timestamp'; - public function handleNotification($order, $hash, $args) - { - parent::handleNotification($order, $hash, $args); - } - public function preparePaymentProcess($order) { parent::preparePaymentProcess($order); @@ -82,38 +77,6 @@ public function handleAdditional($aPost_arr) ->assign('mollieLang', self::Plugin()->oPluginSprachvariableAssoc_arr); return false; - -// if (array_key_exists('skip', $aPost_arr) && (int)$aPost_arr['skip']) { -// unset($_SESSION['mollieCardToken'], $_SESSION['mollieCardTokenTS']); -// return true; -// } -// -// $profileId = trim(Helper::getSetting('profileId')); -// if ($profileId === '' || strpos($profileId, 'pfl_') !== 0) { -// return true; -// } -// if (array_key_exists('mollieCardTokenTS', $_SESSION) && (int)$_SESSION['mollieCardTokenTS'] > time() -// && array_key_exists('mollieCardToken', $_SESSION) && trim($_SESSION['mollieCardToken']) !== '') { -// return true; -// } -// -// unset($_SESSION['mollieCardToken'], $_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('skipComponents', Helper::getSetting('skipComponents')) -// ->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; } protected function setToken($token) diff --git a/version/203/paymentmethod/JTLMolliePayPal.php b/version/203/paymentmethod/JTLMolliePayPal.php index b3ef9cb..5046b71 100644 --- a/version/203/paymentmethod/JTLMolliePayPal.php +++ b/version/203/paymentmethod/JTLMolliePayPal.php @@ -16,8 +16,9 @@ class JTLMolliePayPal extends JTLMollie const ALLOW_AUTO_STORNO = true; /** - * @throws ApiException - * @throws IncompatiblePlatform + * @param Bestellung $order + * @param $apiType + * @return array */ public function getPaymentOptions(Bestellung $order, $apiType) { From b4b6793e5a75c70bebae898d02ecbce388f2f069 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Tue, 25 May 2021 13:04:15 +0200 Subject: [PATCH 229/280] bump version release date --- info.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/info.xml b/info.xml index c99e2e2..f21a50b 100644 --- a/info.xml +++ b/info.xml @@ -37,7 +37,7 @@ 2021-05-06 - 2021-05-11 + 2021-05-25 203.sql From 2d4298ad57f2ce2ad4b562a31c9ad10bb0b5f89f Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Wed, 26 May 2021 12:08:44 +0200 Subject: [PATCH 230/280] shipping utf8 --- info.xml | 2 +- version/203/class/Shipment.php | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/info.xml b/info.xml index f21a50b..24d0df4 100644 --- a/info.xml +++ b/info.xml @@ -37,7 +37,7 @@ 2021-05-06 - 2021-05-25 + 2021-05-26 203.sql diff --git a/version/203/class/Shipment.php b/version/203/class/Shipment.php index 24aa6c7..0268423 100644 --- a/version/203/class/Shipment.php +++ b/version/203/class/Shipment.php @@ -246,11 +246,11 @@ public function loadRequest($options = []) $oVersand = $this->getLieferschein()->oVersand_arr[0]; if ($oVersand->getIdentCode() && $oVersand->getLogistik()) { $tracking = [ - 'carrier' => $oVersand->getLogistik(), - 'code' => $oVersand->getIdentCode(), + 'carrier' => utf8_encode($oVersand->getLogistik()), + 'code' => utf8_encode($oVersand->getIdentCode()), ]; if ($oVersand->getLogistikVarUrl()) { - $tracking['url'] = $oVersand->getLogistikURL(); + $tracking['url'] = utf8_encode($oVersand->getLogistikURL()); } $this->tracking = $tracking; } From da29229a83965f55c0929063e05e134abafcb734 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Wed, 26 May 2021 12:17:55 +0200 Subject: [PATCH 231/280] ci --- .gitlab-ci.yml | 42 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 506fc23..46fde07 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -11,6 +11,15 @@ sast: include: - template: Security/SAST.gitlab-ci.yml +phpunit: + image: registry.webstollen.com:443/docker/jtl-plugin-ci:php56 + stage: test + only: + - tags + - master + script: + - if [ -f "phpunit.xml" ]; then composer install -o && ./vendor/bin/phpunit; else echo "Skipped PHPUnit, no phpunit.xml"; fi + composer: stage: build @@ -25,18 +34,47 @@ composer: - vendor policy: pull script: - - composer install --no-dev -o + - if [ -f "composer.json" ]; then composer install --no-dev -o; else echo "Skipped Composer, no composer.json"; fi artifacts: expire_in: 3 days untracked: true +node: + stage: build + only: + - tags + - master + cache: + key: + files: + - adminmenu/app/yarn.lock + paths: + - adminmenu/app/node_modules + - adminmenu/app/.yarn-cache + policy: pull + script: + - npm config set "@fortawesome:registry" https://npm.fontawesome.com/ + - npm config set "//npm.fontawesome.com/:_authToken" $FONT_AWESOME_TOKEN + - npm config set "@dash.bar:registry" https://gitlab.webstollen.com/api/v4/packages/npm/ + - npm config set "@webstollen:registry" https://gitlab.webstollen.com/api/v4/packages/npm/ + - npm config set "//gitlab.webstollen.com/api/v4/packages/npm/:_authToken" $CI_JOB_TOKEN + - npm config set "//gitlab.webstollen.com/api/v4/projects/444/packages/npm/:_authToken" + $CI_JOB_TOKEN + - if [ -f "adminmenu/app/package.json" ]; then cd adminmenu/app && yarn install --frozen-lockfile --cache-folder .yarn-cache && yarn build; else echo "Skipped Yarn build, no packages.json"; fi + artifacts: + expire_in: 3 days + untracked: false + paths: + - adminmenu/app/build + pack: stage: finalize only: - tags - master script: - - rm -rf .gitlab-ci.yml .git/ + - rm -rf .git/ adminmenu/app/src/ adminmenu/app/test/ adminmenu/app/public/ tests/ + - rm -f .gitlab-ci.yml phpunit.xml adminmenu/app/*.js* adminmenu/app/yarn.lock adminmenu/app/README.md adminmenu/cra.sh - cd .. - if [ $SKIP_COMPILE = 1 ]; then echo "Skipped Compiler!"; else compiler $CI_PROJECT_DIR $CI_PROJECT_DIR; fi - zip -r $CI_PROJECT_DIR/$CI_PROJECT_NAME-$CI_COMMIT_REF_NAME.zip $CI_PROJECT_NAME From 1f83269b110a515142f0650b2b0179852c6d8a5e Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Wed, 26 May 2021 12:26:26 +0200 Subject: [PATCH 232/280] ci --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 46fde07..1b8fb18 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -76,7 +76,7 @@ pack: - rm -rf .git/ adminmenu/app/src/ adminmenu/app/test/ adminmenu/app/public/ tests/ - rm -f .gitlab-ci.yml phpunit.xml adminmenu/app/*.js* adminmenu/app/yarn.lock adminmenu/app/README.md adminmenu/cra.sh - cd .. - - if [ $SKIP_COMPILE = 1 ]; then echo "Skipped Compiler!"; else compiler $CI_PROJECT_DIR $CI_PROJECT_DIR; fi + - if [ $SKIP_COMPILE = 1 ]; then echo "Skipped Compiler."; else compiler $CI_PROJECT_DIR $CI_PROJECT_DIR; fi - zip -r $CI_PROJECT_DIR/$CI_PROJECT_NAME-$CI_COMMIT_REF_NAME.zip $CI_PROJECT_NAME artifacts: expire_in: 30 days From 686e5f51270e0fd4ac1376b680bd262b00905ea7 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Wed, 26 May 2021 14:49:20 +0000 Subject: [PATCH 233/280] Add changelog for version 2.0.3 --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..f5b4325 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,3 @@ +## 2.0.3 (2021-05-26) + +No changes. From 2e25a8075b6bc42890749c445cdcd7a238f08108 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Wed, 26 May 2021 17:00:10 +0200 Subject: [PATCH 234/280] ci --- .gitlab-ci.yml | 4 ++-- CHANGELOG.md | 3 --- 2 files changed, 2 insertions(+), 5 deletions(-) delete mode 100644 CHANGELOG.md diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 1b8fb18..5066cef 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -76,7 +76,7 @@ pack: - rm -rf .git/ adminmenu/app/src/ adminmenu/app/test/ adminmenu/app/public/ tests/ - rm -f .gitlab-ci.yml phpunit.xml adminmenu/app/*.js* adminmenu/app/yarn.lock adminmenu/app/README.md adminmenu/cra.sh - cd .. - - if [ $SKIP_COMPILE = 1 ]; then echo "Skipped Compiler."; else compiler $CI_PROJECT_DIR $CI_PROJECT_DIR; fi + - if [[ $SKIP_COMPILE = 1 ]]; then echo "Skipped Compiler."; else compiler $CI_PROJECT_DIR $CI_PROJECT_DIR; fi - zip -r $CI_PROJECT_DIR/$CI_PROJECT_NAME-$CI_COMMIT_REF_NAME.zip $CI_PROJECT_NAME artifacts: expire_in: 30 days @@ -90,5 +90,5 @@ upload: - master script: - aws configure set region eu-central-1 - - if [ $SKIP_COMPILE = 1 ]; then export SRC_PREFIX="-src"; fi + - if [[ $SKIP_COMPILE = 1 ]]; then export SRC_PREFIX="-src"; fi - aws s3 cp $CI_PROJECT_NAME-$CI_COMMIT_REF_NAME.zip s3://$S3_BUCKET/jtl-plugins/$CI_PROJECT_NAME/$CI_PROJECT_NAME-$CI_COMMIT_REF_NAME$SRC_PREFIX.zip \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index f5b4325..0000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,3 +0,0 @@ -## 2.0.3 (2021-05-26) - -No changes. From a33ecd5f5c604258ffeb6089e67a2ac074f599bf Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Thu, 27 May 2021 09:39:52 +0000 Subject: [PATCH 235/280] Update .gitlab-ci.yml file --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 5066cef..ebb47ac 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -91,4 +91,4 @@ upload: script: - aws configure set region eu-central-1 - if [[ $SKIP_COMPILE = 1 ]]; then export SRC_PREFIX="-src"; fi - - aws s3 cp $CI_PROJECT_NAME-$CI_COMMIT_REF_NAME.zip s3://$S3_BUCKET/jtl-plugins/$CI_PROJECT_NAME/$CI_PROJECT_NAME-$CI_COMMIT_REF_NAME$SRC_PREFIX.zip \ No newline at end of file + - if [[ $S3_BUCKET ]]; then aws s3 cp $CI_PROJECT_NAME-$CI_COMMIT_REF_NAME.zip s3://$S3_BUCKET/jtl-plugins/$CI_PROJECT_NAME/$CI_PROJECT_NAME-$CI_COMMIT_REF_NAME$SRC_PREFIX.zip; fi \ No newline at end of file From a78ee751fb0b5d1fb4b7fa2f6438d16748b74d90 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Tue, 1 Jun 2021 10:47:58 +0200 Subject: [PATCH 236/280] fix #134 --- info.xml | 2 +- version/203/class/Queue.php | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/info.xml b/info.xml index 24d0df4..79adbd8 100644 --- a/info.xml +++ b/info.xml @@ -37,7 +37,7 @@ 2021-05-06 - 2021-05-26 + 2021-06-01 203.sql diff --git a/version/203/class/Queue.php b/version/203/class/Queue.php index 82b5ba9..404cf5f 100644 --- a/version/203/class/Queue.php +++ b/version/203/class/Queue.php @@ -33,7 +33,9 @@ public static function storno($delay) return true; } - $open = Shop::DB()->executeQueryPrepared("SELECT p.kBestellung, b.cStatus FROM xplugin_ws_mollie_payments p JOIN tbestellung b ON b.kBestellung = p.kBestellung WHERE b.cStatus IN ('1', '2') AND p.dCreatedAt < NOW() - INTERVAL :d HOUR", + $open = Shop::DB()->executeQueryPrepared("SELECT p.kBestellung, b.cStatus FROM xplugin_ws_mollie_payments p " + . "JOIN tbestellung b ON b.kBestellung = p.kBestellung " + . "WHERE b.cAbgeholt = 'Y' AND NOT p.bSynced AND b.cStatus IN ('1', '2') AND p.dCreatedAt < NOW() - INTERVAL :d HOUR", [':d' => $delay], 2); foreach ($open as $o) { @@ -51,8 +53,6 @@ public static function storno($delay) } else { $checkout->Log('AutoStorno: bereits zur WAWI synchronisiert.', LOGLEVEL_ERROR); } - } else { - $checkout->Log(sprintf('AutoStorno aktiv: %d (%s) - Method: %s', (int)$pm::ALLOW_AUTO_STORNO, $pm::METHOD, $checkout->getMollie()->method), LOGLEVEL_ERROR); } } catch (Exception $e) { From 7a996a2dbfde59b79fd3fed66891bb04691a0938 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Wed, 2 Jun 2021 14:28:06 +0200 Subject: [PATCH 237/280] fix auto strono --- info.xml | 2 +- version/203/class/Checkout/AbstractCheckout.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/info.xml b/info.xml index 79adbd8..df3869f 100644 --- a/info.xml +++ b/info.xml @@ -37,7 +37,7 @@ 2021-05-06 - 2021-06-01 + 2021-06-02 203.sql diff --git a/version/203/class/Checkout/AbstractCheckout.php b/version/203/class/Checkout/AbstractCheckout.php index 2995254..939d06e 100644 --- a/version/203/class/Checkout/AbstractCheckout.php +++ b/version/203/class/Checkout/AbstractCheckout.php @@ -593,7 +593,7 @@ public function storno() } $log[] = sprintf("Cancel order '%s'.", $this->getBestellung()->cBestellNr); - if (Shop::DB()->executeQueryPrepared('UPDATE tbestellung SET cAbgeholt = "N", cStatus = :cStatus WHERE kBestellung = :kBestellung', [':cStatus' => '-1', ':kBestellung' => $this->getBestellung()->kBestellung], 3)) { + if (Shop::DB()->executeQueryPrepared('UPDATE tbestellung SET cAbgeholt = "Y", cStatus = :cStatus WHERE kBestellung = :kBestellung', [':cStatus' => '-1', ':kBestellung' => $this->getBestellung()->kBestellung], 3)) { $this->Log(implode('\n', $log)); } } From fd67466da82c2cda325a9b2d0d1b740dd2e1a60a Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Tue, 8 Jun 2021 10:40:30 +0200 Subject: [PATCH 238/280] fix #139 --- version/203/class/Checkout/OrderCheckout.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version/203/class/Checkout/OrderCheckout.php b/version/203/class/Checkout/OrderCheckout.php index c717fd3..f58764b 100644 --- a/version/203/class/Checkout/OrderCheckout.php +++ b/version/203/class/Checkout/OrderCheckout.php @@ -177,7 +177,7 @@ public function create(array $paymentOptions = []) } try { - $req = $this->loadRequest()->jsonSerialize(); + $req = $this->loadRequest($paymentOptions)->jsonSerialize(); $this->order = $this->API()->Client()->orders->create($req); $this->Log(sprintf("Order für '%s' wurde erfolgreich angelegt: %s", $this->getBestellung()->cBestellNr, $this->order->id)); $this->updateModel()->saveModel(); From 0dbb3c77197e601f1f1f8665a4210d05ab48e1f5 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Tue, 8 Jun 2021 10:41:11 +0200 Subject: [PATCH 239/280] bumped CreateDate --- info.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/info.xml b/info.xml index df3869f..e885f77 100644 --- a/info.xml +++ b/info.xml @@ -37,7 +37,7 @@ 2021-05-06 - 2021-06-02 + 2021-06-08 203.sql From 5fbb278104891351e012102eb34dcb50e051b39e Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Tue, 8 Jun 2021 14:26:57 +0200 Subject: [PATCH 240/280] ini 204 --- info.xml | 24 +- version/201/sql/200.sql | 31 - version/202/sql/200.sql | 31 - .../203/class/Checkout/AbstractCheckout.php | 21 +- version/203/class/Queue.php | 7 +- version/204/adminmenu/info.php | 64 ++ version/204/adminmenu/orders.php | 238 +++++ version/204/adminmenu/paymentmethods.php | 100 ++ version/204/adminmenu/tpl/_addon.tpl | 6 + version/204/adminmenu/tpl/info.tpl | 114 +++ .../tpl/mollie-account-erstellen.png | Bin 0 -> 38998 bytes version/204/adminmenu/tpl/order.tpl | 344 +++++++ version/204/adminmenu/tpl/orders.tpl | 160 +++ version/204/adminmenu/tpl/paymentmethods.tpl | 148 +++ version/204/class/API.php | 78 ++ .../204/class/Checkout/AbstractCheckout.php | 940 ++++++++++++++++++ .../204/class/Checkout/AbstractResource.php | 18 + .../Exception/ResourceValidityException.php | 23 + version/204/class/Checkout/Order/Address.php | 44 + .../204/class/Checkout/Order/OrderLine.php | 227 +++++ version/204/class/Checkout/OrderCheckout.php | 371 +++++++ .../204/class/Checkout/Payment/Address.php | 54 + version/204/class/Checkout/Payment/Amount.php | 73 ++ .../204/class/Checkout/PaymentCheckout.php | 220 ++++ version/204/class/ExclusiveLock.php | 64 ++ version/204/class/Helper.php | 350 +++++++ version/204/class/Hook/AbstractHook.php | 13 + version/204/class/Hook/ApplePay.php | 56 ++ version/204/class/Hook/Checkbox.php | 60 ++ version/204/class/Hook/Queue.php | 137 +++ version/204/class/Model/AbstractModel.php | 98 ++ version/204/class/Model/Customer.php | 19 + version/204/class/Model/Payment.php | 47 + version/204/class/Model/Queue.php | 42 + version/204/class/Model/Shipment.php | 28 + version/204/class/Mollie.php | 262 +++++ version/204/class/Queue.php | 234 +++++ version/204/class/Shipment.php | 316 ++++++ version/204/class/Traits/Jsonable.php | 20 + version/204/class/Traits/Plugin.php | 25 + version/204/class/Traits/RequestData.php | 59 ++ version/204/frontend/.htaccess | 9 + version/204/frontend/131_globalinclude.php | 60 ++ version/204/frontend/132_headPostGet.php | 17 + version/204/frontend/140_smarty.php | 58 ++ version/204/frontend/180_checkbox.php | 18 + version/204/frontend/181_sync.php | 14 + version/204/frontend/210_storno.php | 17 + version/204/frontend/75_bestellungInDb.php | 17 + version/204/frontend/applepay.php | 18 + version/204/frontend/img/trust_eng.png | Bin 0 -> 15299 bytes version/204/frontend/img/trust_fre.png | Bin 0 -> 17319 bytes version/204/frontend/img/trust_ger.png | Bin 0 -> 15352 bytes version/204/frontend/tpl/applepay.tpl | 15 + version/204/paymentmethod/JTLMollie.php | 268 +++++ .../204/paymentmethod/JTLMollieApplePay.php | 15 + .../204/paymentmethod/JTLMollieBancontact.php | 13 + .../paymentmethod/JTLMollieBanktransfer.php | 28 + .../204/paymentmethod/JTLMollieBelfius.php | 13 + .../204/paymentmethod/JTLMollieCreditCard.php | 110 ++ .../paymentmethod/JTLMollieDirectDebit.php | 27 + version/204/paymentmethod/JTLMollieEPS.php | 12 + .../204/paymentmethod/JTLMollieGiftcard.php | 27 + .../204/paymentmethod/JTLMollieGiropay.php | 12 + version/204/paymentmethod/JTLMollieIDEAL.php | 13 + .../204/paymentmethod/JTLMollieINGHomePay.php | 28 + version/204/paymentmethod/JTLMollieKBC.php | 17 + .../paymentmethod/JTLMollieKlarnaPayLater.php | 14 + .../paymentmethod/JTLMollieKlarnaSliceIt.php | 14 + version/204/paymentmethod/JTLMollieMyBank.php | 13 + version/204/paymentmethod/JTLMolliePayPal.php | 41 + .../paymentmethod/JTLMolliePaysafecard.php | 15 + .../204/paymentmethod/JTLMolliePrzelewy24.php | 18 + version/204/paymentmethod/JTLMollieSofort.php | 13 + .../img/method/Przelewy24@2x.png | Bin 0 -> 859 bytes .../paymentmethod/img/method/applepay@2x.png | Bin 0 -> 656 bytes .../img/method/bancontact@2x.png | Bin 0 -> 582 bytes .../img/method/banktransfer@2x.png | Bin 0 -> 801 bytes .../paymentmethod/img/method/belfius@2x.png | Bin 0 -> 377 bytes .../img/method/creditcard@2x.png | Bin 0 -> 3125 bytes .../img/method/directdebit@2x.png | Bin 0 -> 801 bytes .../204/paymentmethod/img/method/eps@2x.png | Bin 0 -> 536 bytes .../paymentmethod/img/method/giftcard@2x.png | Bin 0 -> 2218 bytes .../paymentmethod/img/method/giropay@2x.png | Bin 0 -> 602 bytes .../204/paymentmethod/img/method/ideal@2x.png | Bin 0 -> 845 bytes .../img/method/inghomepay@2x.png | Bin 0 -> 1118 bytes .../204/paymentmethod/img/method/kbc@2x.png | Bin 0 -> 799 bytes .../paymentmethod/img/method/klarna@2x.png | Bin 0 -> 896 bytes .../paymentmethod/img/method/mollie@2x.png | Bin 0 -> 5366 bytes .../paymentmethod/img/method/mybank@2x.png | Bin 0 -> 2111 bytes .../paymentmethod/img/method/paypal@2x.png | Bin 0 -> 626 bytes .../img/method/paysafecard@2x.png | Bin 0 -> 420 bytes .../paymentmethod/img/method/sofort@2x.png | Bin 0 -> 453 bytes .../paymentmethod/tpl/bestellabschluss.tpl | 26 + .../paymentmethod/tpl/mollieComponents.tpl | 147 +++ version/204/sql/204.sql | 2 + version/204/tpl/_alerts.tpl | 10 + 97 files changed, 6223 insertions(+), 82 deletions(-) delete mode 100644 version/201/sql/200.sql delete mode 100644 version/202/sql/200.sql create mode 100644 version/204/adminmenu/info.php create mode 100644 version/204/adminmenu/orders.php create mode 100644 version/204/adminmenu/paymentmethods.php create mode 100644 version/204/adminmenu/tpl/_addon.tpl create mode 100644 version/204/adminmenu/tpl/info.tpl create mode 100644 version/204/adminmenu/tpl/mollie-account-erstellen.png create mode 100644 version/204/adminmenu/tpl/order.tpl create mode 100644 version/204/adminmenu/tpl/orders.tpl create mode 100644 version/204/adminmenu/tpl/paymentmethods.tpl create mode 100644 version/204/class/API.php create mode 100644 version/204/class/Checkout/AbstractCheckout.php create mode 100644 version/204/class/Checkout/AbstractResource.php create mode 100644 version/204/class/Checkout/Exception/ResourceValidityException.php create mode 100644 version/204/class/Checkout/Order/Address.php create mode 100644 version/204/class/Checkout/Order/OrderLine.php create mode 100644 version/204/class/Checkout/OrderCheckout.php create mode 100644 version/204/class/Checkout/Payment/Address.php create mode 100644 version/204/class/Checkout/Payment/Amount.php create mode 100644 version/204/class/Checkout/PaymentCheckout.php create mode 100644 version/204/class/ExclusiveLock.php create mode 100644 version/204/class/Helper.php create mode 100644 version/204/class/Hook/AbstractHook.php create mode 100644 version/204/class/Hook/ApplePay.php create mode 100644 version/204/class/Hook/Checkbox.php create mode 100644 version/204/class/Hook/Queue.php create mode 100644 version/204/class/Model/AbstractModel.php create mode 100644 version/204/class/Model/Customer.php create mode 100644 version/204/class/Model/Payment.php create mode 100644 version/204/class/Model/Queue.php create mode 100644 version/204/class/Model/Shipment.php create mode 100644 version/204/class/Mollie.php create mode 100644 version/204/class/Queue.php create mode 100644 version/204/class/Shipment.php create mode 100644 version/204/class/Traits/Jsonable.php create mode 100644 version/204/class/Traits/Plugin.php create mode 100644 version/204/class/Traits/RequestData.php create mode 100644 version/204/frontend/.htaccess create mode 100644 version/204/frontend/131_globalinclude.php create mode 100644 version/204/frontend/132_headPostGet.php create mode 100644 version/204/frontend/140_smarty.php create mode 100644 version/204/frontend/180_checkbox.php create mode 100644 version/204/frontend/181_sync.php create mode 100644 version/204/frontend/210_storno.php create mode 100644 version/204/frontend/75_bestellungInDb.php create mode 100644 version/204/frontend/applepay.php create mode 100644 version/204/frontend/img/trust_eng.png create mode 100644 version/204/frontend/img/trust_fre.png create mode 100644 version/204/frontend/img/trust_ger.png create mode 100644 version/204/frontend/tpl/applepay.tpl create mode 100644 version/204/paymentmethod/JTLMollie.php create mode 100644 version/204/paymentmethod/JTLMollieApplePay.php create mode 100644 version/204/paymentmethod/JTLMollieBancontact.php create mode 100644 version/204/paymentmethod/JTLMollieBanktransfer.php create mode 100644 version/204/paymentmethod/JTLMollieBelfius.php create mode 100644 version/204/paymentmethod/JTLMollieCreditCard.php create mode 100644 version/204/paymentmethod/JTLMollieDirectDebit.php create mode 100644 version/204/paymentmethod/JTLMollieEPS.php create mode 100644 version/204/paymentmethod/JTLMollieGiftcard.php create mode 100644 version/204/paymentmethod/JTLMollieGiropay.php create mode 100644 version/204/paymentmethod/JTLMollieIDEAL.php create mode 100644 version/204/paymentmethod/JTLMollieINGHomePay.php create mode 100644 version/204/paymentmethod/JTLMollieKBC.php create mode 100644 version/204/paymentmethod/JTLMollieKlarnaPayLater.php create mode 100644 version/204/paymentmethod/JTLMollieKlarnaSliceIt.php create mode 100644 version/204/paymentmethod/JTLMollieMyBank.php create mode 100644 version/204/paymentmethod/JTLMolliePayPal.php create mode 100644 version/204/paymentmethod/JTLMolliePaysafecard.php create mode 100644 version/204/paymentmethod/JTLMolliePrzelewy24.php create mode 100644 version/204/paymentmethod/JTLMollieSofort.php create mode 100644 version/204/paymentmethod/img/method/Przelewy24@2x.png create mode 100644 version/204/paymentmethod/img/method/applepay@2x.png create mode 100644 version/204/paymentmethod/img/method/bancontact@2x.png create mode 100644 version/204/paymentmethod/img/method/banktransfer@2x.png create mode 100644 version/204/paymentmethod/img/method/belfius@2x.png create mode 100644 version/204/paymentmethod/img/method/creditcard@2x.png create mode 100644 version/204/paymentmethod/img/method/directdebit@2x.png create mode 100644 version/204/paymentmethod/img/method/eps@2x.png create mode 100644 version/204/paymentmethod/img/method/giftcard@2x.png create mode 100644 version/204/paymentmethod/img/method/giropay@2x.png create mode 100644 version/204/paymentmethod/img/method/ideal@2x.png create mode 100644 version/204/paymentmethod/img/method/inghomepay@2x.png create mode 100644 version/204/paymentmethod/img/method/kbc@2x.png create mode 100644 version/204/paymentmethod/img/method/klarna@2x.png create mode 100644 version/204/paymentmethod/img/method/mollie@2x.png create mode 100644 version/204/paymentmethod/img/method/mybank@2x.png create mode 100644 version/204/paymentmethod/img/method/paypal@2x.png create mode 100644 version/204/paymentmethod/img/method/paysafecard@2x.png create mode 100644 version/204/paymentmethod/img/method/sofort@2x.png create mode 100644 version/204/paymentmethod/tpl/bestellabschluss.tpl create mode 100644 version/204/paymentmethod/tpl/mollieComponents.tpl create mode 100644 version/204/sql/204.sql create mode 100644 version/204/tpl/_alerts.tpl diff --git a/info.xml b/info.xml index e885f77..e7bf955 100644 --- a/info.xml +++ b/info.xml @@ -40,6 +40,10 @@ 2021-06-08 203.sql + + 2021-06-08 + 204.sql + 75_bestellungInDb.php 131_globalinclude.php @@ -66,12 +70,12 @@ Einstellungen Live API Key: - Füge hier deinen mollie API Key ein + Füge hier deinen Mollie API Key ein api_key Test API Key: - Füge hier deinen mollie API Key ein + Füge hier deinen Mollie API Key ein test_api_key @@ -112,7 +116,7 @@ Profile ID: - Füge hier deinen mollie Profil ID (pfl_) ein. Wird benötigt um mollie Components zu + Füge hier deinen Mollie Profil ID (pfl_) ein. Wird benötigt um Mollie Components zu aktivieren profileId @@ -224,8 +228,8 @@ supportQ - - + + @@ -714,7 +718,7 @@ tpl/bestellabschluss.tpl EPS - mollie + Mollie Bezahlen Sie bequem mit EPS. @@ -836,7 +840,7 @@ tpl/bestellabschluss.tpl ING HomePay - mollie + Mollie Bezahlen Sie bequem mit ING HomePay.
@@ -977,7 +981,7 @@ - mollie Klarna Pay Later + Mollie Klarna Pay Later img/method/klarna@2x.png 16 1 @@ -992,7 +996,7 @@ tpl/bestellabschluss.tpl Klarna Pay Later - mollie + Mollie Bezahlen Sie bequem mit Klarna Pay Later. @@ -1042,7 +1046,7 @@ tpl/bestellabschluss.tpl Przelewy24 - mollie + Mollie Bezahlen Sie bequem mit Przelewy24. diff --git a/version/201/sql/200.sql b/version/201/sql/200.sql deleted file mode 100644 index 0d28bdc..0000000 --- a/version/201/sql/200.sql +++ /dev/null @@ -1,31 +0,0 @@ -CREATE TABLE IF NOT EXISTS `xplugin_ws_mollie_queue` ( - `kId` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY, - `cType` VARCHAR(32) NOT NULL, - `cData` TEXT DEFAULT '', - `cResult` TEXT NULL DEFAULT NULL, - `dDone` DATETIME NULL DEFAULT NULL, - `dCreated` DATETIME NOT NULL, - `dModified` DATETIME NULL DEFAULT NULL -); - -ALTER TABLE `xplugin_ws_mollie_payments` - ADD `dReminder` datetime NULL; -ALTER TABLE `xplugin_ws_mollie_payments` - ADD `cTransactionId` VARCHAR(32) DEFAULT ''; -ALTER TABLE `xplugin_ws_mollie_payments` - ADD `bSynced` TINYINT(1) NOT NULL; - -UPDATE `xplugin_ws_mollie_payments` -SET `bSynced` = true; - -CREATE TABLE IF NOT EXISTS `xplugin_ws_mollie_shipments` ( - `kLieferschien` int(11) NOT NULL PRIMARY KEY, - `kBestellung` int(11) NOT NULL, - `cOrderId` VARCHAR(32) NOT NULL, - `cShipmentId` VARCHAR(32) NOT NULL, - `cCarrier` VARCHAR(255) DEFAULT '', - `cCode` VARCHAR(255) DEFAULT '', - `cUrl` VARCHAR(512) DEFAULT '', - `dCreated` DATETIME NOT NULL, - `dModified` DATETIME NULL DEFAULT NULL -); \ No newline at end of file diff --git a/version/202/sql/200.sql b/version/202/sql/200.sql deleted file mode 100644 index 0d28bdc..0000000 --- a/version/202/sql/200.sql +++ /dev/null @@ -1,31 +0,0 @@ -CREATE TABLE IF NOT EXISTS `xplugin_ws_mollie_queue` ( - `kId` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY, - `cType` VARCHAR(32) NOT NULL, - `cData` TEXT DEFAULT '', - `cResult` TEXT NULL DEFAULT NULL, - `dDone` DATETIME NULL DEFAULT NULL, - `dCreated` DATETIME NOT NULL, - `dModified` DATETIME NULL DEFAULT NULL -); - -ALTER TABLE `xplugin_ws_mollie_payments` - ADD `dReminder` datetime NULL; -ALTER TABLE `xplugin_ws_mollie_payments` - ADD `cTransactionId` VARCHAR(32) DEFAULT ''; -ALTER TABLE `xplugin_ws_mollie_payments` - ADD `bSynced` TINYINT(1) NOT NULL; - -UPDATE `xplugin_ws_mollie_payments` -SET `bSynced` = true; - -CREATE TABLE IF NOT EXISTS `xplugin_ws_mollie_shipments` ( - `kLieferschien` int(11) NOT NULL PRIMARY KEY, - `kBestellung` int(11) NOT NULL, - `cOrderId` VARCHAR(32) NOT NULL, - `cShipmentId` VARCHAR(32) NOT NULL, - `cCarrier` VARCHAR(255) DEFAULT '', - `cCode` VARCHAR(255) DEFAULT '', - `cUrl` VARCHAR(512) DEFAULT '', - `dCreated` DATETIME NOT NULL, - `dModified` DATETIME NULL DEFAULT NULL -); \ No newline at end of file diff --git a/version/203/class/Checkout/AbstractCheckout.php b/version/203/class/Checkout/AbstractCheckout.php index 939d06e..47287bb 100644 --- a/version/203/class/Checkout/AbstractCheckout.php +++ b/version/203/class/Checkout/AbstractCheckout.php @@ -447,10 +447,15 @@ public static function cancel($checkout) public function loadRequest(&$options = []) { + + $oKunde = !$this->getBestellung()->oKunde && $this->PaymentMethod()->duringCheckout ? $_SESSION['Kunde'] : $this->getBestellung()->oKunde; if ($this->getBestellung()) { - if ($this->getBestellung()->oKunde->nRegistriert + if ($oKunde->nRegistriert && ($customer = $this->getCustomer( - array_key_exists('mollie_create_customer', $_SESSION['cPost_arr'] ?: []) && $_SESSION['cPost_arr']['mollie_create_customer'] === 'Y') + array_key_exists( + 'mollie_create_customer', + $_SESSION['cPost_arr'] ?: []) && $_SESSION['cPost_arr']['mollie_create_customer'] === 'Y', + $oKunde) ) && isset($customer)) { $options['customerId'] = $customer->id; @@ -464,6 +469,7 @@ public function loadRequest(&$options = []) 'cHash' => $this->getHash(), ]; } + $this->locale = self::getLocale($_SESSION['cISOSprache'], Session::getInstance()->Customer()->cLand); $this->webhookUrl = Shop::getURL(true) . '/?' . http_build_query([ 'mollie' => 1, @@ -483,10 +489,15 @@ public function loadRequest(&$options = []) * @return \Mollie\Api\Resources\Customer|null * @todo: Kunde wieder löschbar machen ?! */ - public function getCustomer($createOrUpdate = false) + public function getCustomer($createOrUpdate = false, $oKunde = null) { + + if (!$oKunde) { + $oKunde = $this->getBestellung()->oKunde; + } + if (!$this->customer) { - $customerModel = Customer::fromID($this->getBestellung()->oKunde->kKunde, 'kKunde'); + $customerModel = Customer::fromID($oKunde->kKunde, 'kKunde'); if ($customerModel->customerId) { try { $this->customer = $this->API()->Client()->customers->get($customerModel->customerId); @@ -496,8 +507,6 @@ public function getCustomer($createOrUpdate = false) } if ($createOrUpdate) { - $oKunde = $this->getBestellung()->oKunde; - $customer = [ 'name' => utf8_encode(trim($oKunde->cVorname . ' ' . $oKunde->cNachname)), 'email' => utf8_encode($oKunde->cMail), diff --git a/version/203/class/Queue.php b/version/203/class/Queue.php index 404cf5f..7340260 100644 --- a/version/203/class/Queue.php +++ b/version/203/class/Queue.php @@ -161,15 +161,14 @@ protected static function handleHook($hook, QueueModel $todo) if ((int)$data['kBestellung']) { $checkout = AbstractCheckout::fromBestellung($data['kBestellung']); + $status = array_key_exists('status', $data) ? (int)$data['status'] : 0; $result = ""; - if ((int)$checkout->getBestellung()->cStatus < BESTELLUNG_STATUS_VERSANDT) { + if (!$status || $status < BESTELLUNG_STATUS_VERSANDT) { return $todo->done("Bestellung noch nicht versendet: {$checkout->getBestellung()->cStatus}"); } /** @var $method JTLMollie */ - if ((int)$data['status'] - && array_key_exists('status', $data) - && (strpos($checkout->getModel()->kID, 'tr_') === false) + if ((strpos($checkout->getModel()->kID, 'tr_') === false) && $checkout->PaymentMethod() && $checkout->getMollie()) { /** @var OrderCheckout $checkout */ diff --git a/version/204/adminmenu/info.php b/version/204/adminmenu/info.php new file mode 100644 index 0000000..0430c6e --- /dev/null +++ b/version/204/adminmenu/info.php @@ -0,0 +1,64 @@ +assign('defaultTabbertab', Helper::getAdminmenu('Info') + Helper::getAdminmenu('Support')); + 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 "
" . + "
" . + " " . + " Lizenz Informationen" . + ' ' . + '
' . + "
" . + " " . + " Update Informationen" . + ' ' . + '
' . + "
" . + " " . + " Plugin informationen" . + ' ' . + '
' . + '
'; + + 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/204/adminmenu/orders.php b/version/204/adminmenu/orders.php new file mode 100644 index 0000000..af6af9f --- /dev/null +++ b/version/204/adminmenu/orders.php @@ -0,0 +1,238 @@ +getModel()->kID)) { + Helper::addAlert('Zahlungserinnerung wurde verschickt.', 'success', 'orders'); + } else { + Helper::addAlert('Es ist ein Fehler aufgetreten, prüfe den Log.', 'danger', 'orders'); + } + } else { + Helper::addAlert('Bestellung konnte nicht geladen werden.', 'danger', 'orders'); + } + + + break; + + case "fetchable": + + if (array_key_exists('kBestellung', $_REQUEST) && ($checkout = AbstractCheckout::fromBestellung((int)$_REQUEST['kBestellung']))) { + if (AbstractCheckout::makeFetchable($checkout->getBestellung(), $checkout->getModel())) { + Helper::addAlert('Bestellung kann jetzt von der WAWI abgeholt werden.', 'success', 'orders'); + } else { + Helper::addAlert('Es ist ein Fehler aufgetreten, prüfe den Log.', 'danger', 'orders'); + } + } else { + Helper::addAlert('Bestellung konnte nicht geladen werden.', 'danger', 'orders'); + } + + break; + + 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); + + + 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', 'wb'); + + + fputcsv($out, [ + 'kBestellung', + 'OrderID', + 'Status (mollie)', + 'BestellNr', + 'Status (JTL)', + 'Mode', + 'OriginalOrderNumber', + 'Currency', + 'Amount', + 'Method', + 'PaymentID', + 'Created' + ]); + + + foreach ($orders as $order) { + $order = new ws_mollie\Model\Payment($order); + $checkout = AbstractCheckout::fromModel($order); + + $tmp = [ + 'kBestellung' => $order->kBestellung, + 'cOrderId' => $order->kID, + 'cStatus' => $checkout->getMollie() ? $checkout->getMollie()->status : $order->cStatus, + 'cBestellNr' => $checkout->getBestellung() ? $checkout->getBestellung()->cBestellNr : $order->cOrderNumber, + 'nStatus' => $checkout->getBestellung() ? $checkout->getBestellung()->cStatus : 0, + 'cMode' => $order->cMode, + 'cOriginalOrderNumber' => $checkout->getMollie() && isset($checkout->getMollie()->metadata->originalOrderNumber) ? $checkout->getMollie()->metadata->originalOrderNumber : '', + 'cCurrency' => $order->cCurrency, + 'fAmount' => $order->fAmount, + 'cMethod' => $order->cMethod, + 'cPaymentId' => $order->cTransactionId, + 'dCreated' => $order->dCreatedAt, + ]; + + try { + if ($checkout->getMollie() && $checkout->getMollie()->resource === 'order') { + foreach ($checkout->getMollie()->payments() as $payment) { + if ($payment->status === 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': + try { + if (!array_key_exists('id', $_REQUEST)) { + throw new InvalidArgumentException('Keine ID angegeben!', 'danger', 'orders'); + } + $checkout = AbstractCheckout::fromID($_REQUEST['id']); + if ($refund = $checkout::refund($checkout)) { + Helper::addAlert(sprintf('Bestellung wurde zurückerstattet (%s).', $refund->id), 'success', 'orders'); + } + goto order; + } catch (InvalidArgumentException $e) { + Helper::addAlert('Fehler: ' . $e->getMessage(), 'danger', 'orders'); + } catch (Exception $e) { + Helper::addAlert('Fehler: ' . $e->getMessage(), 'danger', 'orders'); + goto order; + } + break; + + case 'cancel': + try { + if (!array_key_exists('id', $_REQUEST)) { + throw new InvalidArgumentException('Keine ID angeben!'); + } + $checkout = AbstractCheckout::fromID($_REQUEST['id']); + if ($checkout::cancel($checkout)) { + Helper::addAlert('Bestellung wurde abgebrochen.', 'success', 'orders'); + } + goto order; + } catch (InvalidArgumentException $e) { + Helper::addAlert('Fehler: ' . $e->getMessage(), 'danger', 'orders'); + } catch (Exception $e) { + Helper::addAlert('Fehler: ' . $e->getMessage(), 'danger', 'orders'); + goto order; + } + break; + + case 'capture': + try { + if (!array_key_exists('id', $_REQUEST)) { + throw new InvalidArgumentException('Keine ID angeben!'); + } + $checkout = AbstractCheckout::fromID($_REQUEST['id']); + if ($shipmentId = OrderCheckout::capture($checkout)) { + Helper::addAlert(sprintf('Zahlung erfolgreich erfasst/versandt (%s).', $shipmentId), 'success', 'orders'); + } + goto order; + } catch (InvalidArgumentException $e) { + Helper::addAlert('Fehler: ' . $e->getMessage(), 'danger', 'orders'); + } catch (Exception $e) { + Helper::addAlert('Fehler: ' . $e->getMessage(), 'danger', 'orders'); + goto order; + } + break; + + case 'order': + order: + try { + + if (!array_key_exists('id', $_REQUEST)) { + throw new InvalidArgumentException('Keine ID angeben!'); + } + + $checkout = AbstractCheckout::fromID($_REQUEST['id']); + + if ($checkout instanceof OrderCheckout) { + Shop::Smarty()->assign('shipments', $checkout->getShipments()); + } + + Shop::Smarty()->assign('payment', $checkout->getModel()) + ->assign('oBestellung', $checkout->getBestellung()) + ->assign('order', $checkout->getMollie()) + ->assign('checkout', $checkout) + ->assign('logs', $checkout->getLogs()); + Shop::Smarty()->display($oPlugin->cAdminmenuPfad . '/tpl/order.tpl'); + return; + } catch (Exception $e) { + Helper::addAlert('Fehler: ' . $e->getMessage(), 'danger', 'orders'); + } + break; + } + } + + Mollie::fixZahlungsarten(); + + $checkouts = []; + $payments = Shop::DB()->executeQueryPrepared("SELECT * FROM xplugin_ws_mollie_payments WHERE kBestellung IS NOT NULL ORDER BY dCreatedAt DESC LIMIT 1000;", [], 2); + foreach ($payments as $i => $payment) { + $payment = new Payment($payment); + try { + $checkouts[$payment->kBestellung] = AbstractCheckout::fromModel($payment, false); + } catch (Exception $e) { + //Helper::addAlert($e->getMessage(), 'danger', 'orders'); + } + } + + Shop::Smarty()->assign('payments', $payments) + ->assign('checkouts', $checkouts) + ->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/204/adminmenu/paymentmethods.php b/version/204/adminmenu/paymentmethods.php new file mode 100644 index 0000000..18adb1e --- /dev/null +++ b/version/204/adminmenu/paymentmethods.php @@ -0,0 +1,100 @@ +setApiKey(Helper::getSetting("api_key")); + + $profile = $mollie->profiles->get('me'); + + $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}$/']]) ?: AbstractCheckout::getLocale(); + $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', + 'locale' => $locale + ]; + if ($amount && $currency) { + $params['amount'] = ['value' => number_format($amount, 2, '.', ''), 'currency' => $currency]; + if ($active) { + $params['includeWallets'] = 'applepay'; + //$params['resource'] = 'orders'; + } + } + + $allMethods = []; + if ($active) { + $_allMethods = $mollie->methods->allActive($params); + } else { + $_allMethods = $mollie->methods->allAvailable($params); + } + + $sessionLife = (int)ini_get('session.gc_maxlifetime'); + + /** @var Method $method */ + foreach ($_allMethods as $method) { + + $id = $method->id === 'creditcard' ? 'kreditkarte' : $method->id; + $key = "kPlugin_{$oPlugin->kPlugin}_mollie$id"; + + $class = null; + $shop = null; + $oClass = null; + + if (array_key_exists($key, $oPlugin->oPluginZahlungsKlasseAssoc_arr) && !in_array($id, ['voucher', 'giftcard', 'directdebit'], true)) { + $class = $oPlugin->oPluginZahlungsKlasseAssoc_arr[$key]; + include_once($oPlugin->cPluginPfad . 'paymentmethod/' . $class->cClassPfad); + /** @var JTLMollie $oClass */ + $oClass = new $class->cClassName($id); + } + if (array_key_exists($key, $oPlugin->oPluginZahlungsmethodeAssoc_arr)) { + $shop = $oPlugin->oPluginZahlungsmethodeAssoc_arr[$key]; + } + + $maxExpiryDays = $oClass ? $oClass->getExpiryDays() : null; + $allMethods[$method->id] = (object)[ + 'mollie' => $method, + 'class' => $class, + 'allowPreOrder' => $oClass ? $oClass::ALLOW_PAYMENT_BEFORE_ORDER : false, + 'allowAutoStorno' => $oClass ? $oClass::ALLOW_AUTO_STORNO : false, + 'oClass' => $oClass, + 'shop' => $shop, + 'maxExpiryDays' => $oClass ? $maxExpiryDays : null, + 'warning' => $oClass && ($maxExpiryDays * 24 * 60 * 60) > $sessionLife, + 'session' => round($sessionLife / 60 / 60, 2) . 'h' + ]; + + } + + Shop::Smarty()->assign('profile', $profile) + ->assign('currencies', Mollie::getCurrencies()) + ->assign('locales', Mollie::getLocales()) + ->assign('allMethods', $allMethods) + ->assign('settings', $oPlugin->oPluginEinstellungAssoc_arr); + Shop::Smarty()->display($oPlugin->cAdminmenuPfad . '/tpl/paymentmethods.tpl'); +} catch (Exception $e) { + echo "
{$e->getMessage()}
"; + Helper::logExc($e); +} diff --git a/version/204/adminmenu/tpl/_addon.tpl b/version/204/adminmenu/tpl/_addon.tpl new file mode 100644 index 0000000..6539757 --- /dev/null +++ b/version/204/adminmenu/tpl/_addon.tpl @@ -0,0 +1,6 @@ + \ No newline at end of file diff --git a/version/204/adminmenu/tpl/info.tpl b/version/204/adminmenu/tpl/info.tpl new file mode 100644 index 0000000..2d41c95 --- /dev/null +++ b/version/204/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}
+
+
+
Changelog:
+
+ +
+
+ +
+
+ +
+
+
+ {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/204/adminmenu/tpl/mollie-account-erstellen.png b/version/204/adminmenu/tpl/mollie-account-erstellen.png new file mode 100644 index 0000000000000000000000000000000000000000..fc1819255ef725fa214cf2bf028cf3428794ecee GIT binary patch literal 38998 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 +

+ « + 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 isset($order->customerId)} + ID: + {$order->customerId} +
+ {/if} + {if isset($order->billingAddress, $order->billingAddress->organizationName)} + {$order->billingAddress->organizationName} + {elseif isset($order->billingAddress)} + {$order->billingAddress->title} {$order->billingAddress->givenName} {$order->billingAddress->familyName} + {/if} +
Mollie Checkout: + {if $order->getCheckoutURL()} + mollie.com/... + {else} + n/a + {/if} + + +
+{if $order->id|strpos:"ord_" !== false && $order->payments()->count > 0} +

Zahlungen

+ + + + + + + + + + + + + + {foreach from=$order->payments() item=payment} + + + + + + + + + + + {/foreach} +
IDStatusMethodeAmountSettlementRefundedRemainingDetails
{$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} +
+
+{/if} + +
+ {if ($order->status === 'authorized' || $order->status === 'shipping') && $oBestellung->cStatus|intval >= 3} + + Zahlung erfassen1 + + {/if} + {if !$order->amountRefunded || ($order->amount->value > $order->amountRefunded->value)} + Rückerstatten2 + + {/if} + {if $order->isCancelable} + Abbrechen3 + + {/if} +
+ +{if $order->id|strpos:"ord_" !== false} +

Positionen:

+ + + + + + + + + + + + + + + + + {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} + + + + + + + + + + + + + {/foreach} + + + + + + + + + + +
StatusSKUNameTypAnzahlMwStSteuerNettoBrutto 
+ {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'} + abgebrochen + {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*} +
{$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.
+
+{/if} + +{if isset($shipments) && $shipments|count} +

Shipmets

+ + + + + + + + + + + {foreach from=$shipments item=shipment} + + + + + + + {/foreach} + +
Lieferschein Nr.Mollie IDCarrierCode
{$shipment->getLieferschein()->getLieferscheinNr()}{$shipment->getShipment()->id} + {if isset($shipment->getShipment()->tracking)} + {$shipment->getShipment()->tracking->carrier} + {else} + - + {/if} + {if isset($shipment->getShipment()->tracking)} + {if isset($shipment->getShipment()->tracking->url)} + + {$shipment->getShipment()->tracking->code} + + {else} + {$shipment->getShipment()->tracking->code} + {/if} + {else} + - + {/if} +
+{/if} + +

Log

+ + {foreach from=$logs item=log} + + + + + + + {/foreach} +
+ {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}
+ + diff --git a/version/204/adminmenu/tpl/orders.tpl b/version/204/adminmenu/tpl/orders.tpl new file mode 100644 index 0000000..a499f32 --- /dev/null +++ b/version/204/adminmenu/tpl/orders.tpl @@ -0,0 +1,160 @@ +{ws_mollie\Helper::showAlerts('orders')} + +{if $hasAPIKey == false} + + Jetzt kostenlos Mollie Account eröffnen! + +{else} + + + + + + + + + + + + + + + {foreach from=$checkouts item=checkout} + + + + + + + + + + + + + + + {/foreach} + +
BestellNr.IDMollie StatusJTL StatusBetragMethodeErstellt 
+ {if $checkout->getModel()->bSynced == false && $checkout->getBestellung()->cAbgeholt === 'Y'} + * + {/if} + {$checkout->getModel()->cOrderNumber} + {if $checkout->getModel()->cMode == 'test'} + TEST + {/if} + {if $checkout->getModel()->bLockTimeout} + LOCK TIMEOUT + {/if} + {if $checkout->getModel()->dReminder && $checkout->getModel()->dReminder !== '0000-00-00 00:00:00'} + getModel()->dReminder|strtotime}}"> + {/if} + + {$checkout->getModel()->kID} + + {if $checkout->getModel()->cStatus == 'created' || $checkout->getModel()->cStatus == 'open'} + erstellt + {elseif $checkout->getModel()->cStatus == 'pending'} + austehend + {elseif $checkout->getModel()->cStatus == 'paid'} + bezahlt + {elseif $checkout->getModel()->cStatus == 'authorized'} + autorisiert + {elseif $checkout->getModel()->cStatus == 'shipping'} + versendet + {elseif $checkout->getModel()->cStatus == 'completed'} + abgeschlossen + {elseif $checkout->getModel()->cStatus == 'expired'} + abgelaufen + {elseif $checkout->getModel()->cStatus == 'canceled'} + abgebrochen + {else} + Unbekannt: {$checkout->getModel()->cStatus} + {/if} + {if $checkout->getModel()->fAmountRefunded && $checkout->getModel()->fAmountRefunded == $checkout->getModel()->fAmount} + (total refund) + {elseif $checkout->getModel()->fAmountRefunded && $checkout->getModel()->fAmountRefunded > 0} + (partly refund) + {/if} + + + {if $checkout->getBestellung()->cStatus|intval == 1} + OFFEN + {elseif $checkout->getBestellung()->cStatus|intval == 2} + IN BEARBEITUNG + {elseif $checkout->getBestellung()->cStatus|intval == 3} + BEZAHLT + {elseif $checkout->getBestellung()->cStatus|intval == 4} + VERSANDT + {elseif $checkout->getBestellung()->cStatus|intval == 5} + TEILVERSANDT + {elseif $checkout->getBestellung()->cStatus|intval == -1} + STORNO + {else} + n/a + {/if} + {$checkout->getModel()->fAmount|number_format:2:',':''} {$checkout->getModel()->cCurrency}{$checkout->getModel()->cMethod}{"d. M Y H:i"|date:{$checkout->getModel()->dCreatedAt|strtotime}} +
+ +
+ {if $checkout->getModel()->bSynced == false && $checkout->getBestellung()->cAbgeholt === 'Y'} + + {/if} + {if $checkout->remindable()} + + {/if} +
+
+
+ {if $payments|count > 900} +
Hier werden nur die letzten 1000 Ergebnisse angezeigt.
+ {/if} + + +
+
+

Export:

+
+ +
+ + + + + +
+
+ +{/if} + diff --git a/version/204/adminmenu/tpl/paymentmethods.tpl b/version/204/adminmenu/tpl/paymentmethods.tpl new file mode 100644 index 0000000..7aedaab --- /dev/null +++ b/version/204/adminmenu/tpl/paymentmethods.tpl @@ -0,0 +1,148 @@ +

Account Status

+ + + + + + + {if $profile->review} + + + {/if} + {if $profile->_links->checkoutPreviewUrl->href} + + {/if} + + +
Mode:{$profile->mode}Status:{$profile->status}Review:{$profile->review->status} + Checkout + Preview + + Mollie Dashboard +
+
+
+
+ + +
+ + + +
+
+ + +
+
+ + +
+
+ + + reset +
+
+
+
+{if $allMethods && $allMethods|count} + + + + + + + + + + + + {foreach from=$allMethods item=method} + + + + + + + + {/foreach} + +
BildName / IDInfoPreiseLimits
{$method->mollie->description|utf8_decode} + {if $method->mollie->status === 'activated'} + + {else} + + {/if} + {$method->mollie->description|utf8_decode}
+ {$method->mollie->id} +
+ {if $method->shop && $method->oClass} + {if intval($method->shop->nWaehrendBestellung) === 1 && !$method->allowPreOrder} +
Zahlung VOR Bestellabschluss nicht unterstützt!
+ {else} +
+ Bestellabschluss: + {if intval($method->shop->nWaehrendBestellung) === 1} + VOR Zahlung + {else} + NACH Zahlung + {/if} +
+ {/if} + + {if intval($settings.autoStorno) > 0} +
+ Unbez. Bestellung stornieren: + {if $method->allowAutoStorno} +
auto
+ {else} +
manual
+ {/if} +
+ {/if} +
+ Gültigkeit: + {$method->maxExpiryDays} Tage +
+ {else} + Derzeit nicht unterstützt. + {/if} +
+
    + {foreach from=$method->mollie->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->mollie->minimumAmount}{$method->mollie->minimumAmount->value} {$method->mollie->minimumAmount->currency}{else}n/a{/if} +
+ Max: {if $method->mollie->maximumAmount}{$method->mollie->maximumAmount->value} {$method->mollie->maximumAmount->currency}{else}n/a{/if} +
+{else} +
Es konnten keine Methoden abgerufen werden.
+{/if} \ No newline at end of file diff --git a/version/204/class/API.php b/version/204/class/API.php new file mode 100644 index 0000000..235b7cf --- /dev/null +++ b/version/204/class/API.php @@ -0,0 +1,78 @@ +test = $test === null ? self::getMode() : $test; + } + + /** + * @return bool + */ + public static function getMode() + { + require_once PFAD_ROOT . PFAD_ADMIN . PFAD_INCLUDES . 'benutzerverwaltung_inc.php'; + return self::Plugin()->oPluginEinstellungAssoc_arr["testAsAdmin"] === 'Y' && Shop::isAdmin() && self::Plugin()->oPluginEinstellungAssoc_arr['test_api_key']; + } + + /** + * @return MollieApiClient + * @throws ApiException + * @throws IncompatiblePlatform + */ + public function Client() + { + if (!$this->client) { + $this->client = new MollieApiClient(new Client([ + RequestOptions::VERIFY => CaBundle::getBundledCaBundlePath(), + RequestOptions::TIMEOUT => 60 + ])); + $this->client->setApiKey($this->isTest() ? self::Plugin()->oPluginEinstellungAssoc_arr['test_api_key'] : self::Plugin()->oPluginEinstellungAssoc_arr['api_key']) + ->addVersionString('JTL-Shop/' . JTL_VERSION . JTL_MINOR_VERSION) + ->addVersionString('ws_mollie/' . self::Plugin()->nVersion); + } + return $this->client; + } + + /** + * @return bool + */ + public function isTest() + { + return $this->test; + } + + +} \ No newline at end of file diff --git a/version/204/class/Checkout/AbstractCheckout.php b/version/204/class/Checkout/AbstractCheckout.php new file mode 100644 index 0000000..47287bb --- /dev/null +++ b/version/204/class/Checkout/AbstractCheckout.php @@ -0,0 +1,940 @@ + ['lang' => 'de', 'country' => ['DE', 'AT', 'CH']], + 'fre' => ['lang' => 'fr', 'country' => ['BE', 'FR']], + 'dut' => ['lang' => 'nl', 'country' => ['BE', 'NL']], + 'spa' => ['lang' => 'es', 'country' => ['ES']], + 'ita' => ['lang' => 'it', 'country' => ['IT']], + 'pol' => ['lang' => 'pl', 'country' => ['PL']], + 'hun' => ['lang' => 'hu', 'country' => ['HU']], + 'por' => ['lang' => 'pt', 'country' => ['PT']], + 'nor' => ['lang' => 'nb', 'country' => ['NO']], + 'swe' => ['lang' => 'sv', 'country' => ['SE']], + 'fin' => ['lang' => 'fi', 'country' => ['FI']], + 'dan' => ['lang' => 'da', 'country' => ['DK']], + 'ice' => ['lang' => 'is', 'country' => ['IS']], + 'eng' => ['lang' => 'en', 'country' => ['GB', 'US']], + ]; + /** + * @var \Mollie\Api\Resources\Customer|null + */ + protected $customer; + /** + * @var string + */ + private $hash; + /** + * @var API + */ + private $api; + /** + * @var JTLMollie + */ + private $paymentMethod; + /** + * @var Bestellung + */ + private $oBestellung; + /** + * @var Payment + */ + private $model; + + /** + * AbstractCheckout constructor. + * @param Bestellung $oBestellung + * @param null $api + */ + public function __construct(Bestellung $oBestellung, $api = null) + { + $this->api = $api; + $this->oBestellung = $oBestellung; + } + + /** + * @param int $kBestellung + * @param bool $checkZA + * @return bool + */ + public static function isMollie($kBestellung, $checkZA = false) + { + if ($checkZA) { + $res = Shop::DB()->executeQueryPrepared('SELECT * FROM tzahlungsart WHERE cModulId LIKE :cModulId AND kZahlungsart = :kZahlungsart', [ + ':kZahlungsart' => $kBestellung, + ':cModulId' => 'kPlugin_' . self::Plugin()->kPlugin . '_%' + ], 1); + return (bool)$res; + } + + return ($res = Shop::DB()->executeQueryPrepared('SELECT kId FROM xplugin_ws_mollie_payments WHERE kBestellung = :kBestellung;', [ + ':kBestellung' => $kBestellung, + ], 1)) && $res->kId; + } + + public static function finalizeOrder($sessionHash, $id, $test = false) + { + try { + if ($paymentSession = Shop::DB()->select('tzahlungsession', 'cZahlungsID', $sessionHash)) { + if (session_id() !== $paymentSession->cSID) { + session_destroy(); + session_id($paymentSession->cSID); + $session = Session::getInstance(true, true); + } else { + $session = Session::getInstance(false); + } + + if ((!isset($paymentSession->nBezahlt) || !$paymentSession->nBezahlt) + && (!isset($paymentSession->kBestellung) || !$paymentSession->kBestellung) + && isset($_SESSION['Warenkorb']->PositionenArr) + && count($_SESSION['Warenkorb']->PositionenArr)) { + + $paymentSession->cNotifyID = $id; + $paymentSession->dNotify = 'now()'; + Shop::DB()->update('tzahlungsession', 'cZahlungsID', $sessionHash, $paymentSession); + + $api = new API($test); + if (strpos($id, 'tr_') === 0) { + $mollie = $api->Client()->payments->get($id); + } else { + $mollie = $api->Client()->orders->get($id); + } + + if (in_array($mollie->status, [OrderStatus::STATUS_PENDING, OrderStatus::STATUS_AUTHORIZED, OrderStatus::STATUS_PAID], true)) { + require_once PFAD_ROOT . PFAD_INCLUDES . 'bestellabschluss_inc.php'; + require_once PFAD_ROOT . PFAD_INCLUDES . 'mailTools.php'; + $order = finalisiereBestellung(); + $session->cleanUp(); + $paymentSession->nBezahlt = 1; + $paymentSession->dZeitBezahlt = 'now()'; + } else { + throw new Exception('Mollie Status invalid: ' . $mollie->status . '\n' . print_r([$sessionHash, $id], 1)); + } + + if ($order->kBestellung) { + + $paymentSession->kBestellung = $order->kBestellung; + Shop::DB()->update('tzahlungsession', 'cZahlungsID', $sessionHash, $paymentSession); + + try { + $checkout = self::fromID($id, false, $order); + } catch (Exception $e) { + if (strpos($id, 'tr_') === 0) { + $checkoutClass = PaymentCheckout::class; + } else { + $checkoutClass = OrderCheckout::class; + } + $checkout = new $checkoutClass($order, $api); + } + $checkout->setMollie($mollie); + $checkout->updateOrderNumber(); + $checkout->handleNotification($sessionHash); + } + } else { + Jtllog::writeLog(sprintf('PaymentSession bereits bezahlt: %s - ID: %s => Queue', $sessionHash, $id), JTLLOG_LEVEL_NOTICE); + Queue::saveToQueue($id, $id, 'webhook'); + } + } else { + Jtllog::writeLog(sprintf('PaymentSession nicht gefunden: %s - ID: %s => Queue', $sessionHash, $id), JTLLOG_LEVEL_ERROR); + Queue::saveToQueue($id, $id, 'webhook'); + } + } catch (Exception $e) { + Helper::logExc($e); + } + } + + /** + * @param string $id + * @param bool $bFill + * @param Bestellung|null $order + * @return OrderCheckout|PaymentCheckout + * @throws RuntimeException + */ + public static function fromID($id, $bFill = true, Bestellung $order = null) + { + if (($model = Payment::fromID($id))) { + return static::fromModel($model, $bFill, $order); + } + throw new RuntimeException(sprintf('Error loading Order: %s', $id)); + } + + /** + * @param Payment $model + * @param bool $bFill + * @param Bestellung|null $order + * @return OrderCheckout|PaymentCheckout + */ + public static function fromModel($model, $bFill = true, Bestellung $order = null) + { + if (!$model) { + throw new RuntimeException(sprintf('Error loading Order for Model: %s', print_r($model, 1))); + } + + $oBestellung = $order; + if (!$order) { + $oBestellung = new Bestellung($model->kBestellung, $bFill); + if (!$oBestellung->kBestellung) { + throw new RuntimeException(sprintf('Error loading Bestellung: %s', $model->kBestellung)); + } + } + + if (strpos($model->kID, 'tr_') !== false) { + $self = new PaymentCheckout($oBestellung); + } else { + $self = new OrderCheckout($oBestellung); + } + + $self->setModel($model); + return $self; + } + + /** + * @param $kBestellung + * @return OrderCheckout|PaymentCheckout + * * @throws RuntimeException + */ + public static function fromBestellung($kBestellung) + { + if ($model = Payment::fromID($kBestellung, 'kBestellung')) { + return static::fromModel($model); + } + throw new RuntimeException(sprintf('Error loading Order for Bestellung: %s', $kBestellung)); + } + + public static function sendReminders() + { + $reminder = (int)self::Plugin()->oPluginEinstellungAssoc_arr['reminder']; + + if (!$reminder) { + return; + } + + $sql = "SELECT p.kID FROM xplugin_ws_mollie_payments p JOIN tbestellung b ON b.kBestellung = p.kBestellung " + . "WHERE (p.dReminder IS NULL OR p.dReminder = '0000-00-00 00:00:00') " + . "AND p.dCreatedAt < NOW() - INTERVAL :d MINUTE AND p.dCreatedAt > NOW() - INTERVAL 7 DAY " + . "AND p.cStatus IN ('created','open', 'expired', 'failed', 'canceled') AND NOT b.cStatus = '-1'"; + + $remindables = Shop::DB()->executeQueryPrepared($sql, [ + ':d' => $reminder + ], 2); + foreach ($remindables as $remindable) { + try { + self::sendReminder($remindable->kID); + } catch (Exception $e) { + Jtllog::writeLog("AbstractCheckout::sendReminders: " . $e->getMessage()); + } + } + } + + /** + * @param $kID + * @return bool + */ + public static function sendReminder($kID) + { + + $checkout = self::fromID($kID); + $return = true; + try { + $repayURL = Shop::getURL() . '/?m_pay=' . md5($checkout->getModel()->kID . '-' . $checkout->getBestellung()->kBestellung); + + $data = new stdClass(); + $data->tkunde = new Kunde($checkout->getBestellung()->oKunde->kKunde); + if ($data->tkunde->kKunde) { + + $data->Bestellung = $checkout->getBestellung(); + $data->PayURL = $repayURL; + $data->Amount = gibPreisStringLocalized($checkout->getModel()->fAmount, $checkout->getBestellung()->Waehrung); //Preise::getLocalizedPriceString($order->getAmount(), Currency::fromISO($order->getCurrency()), false); + + require_once PFAD_ROOT . PFAD_INCLUDES . 'mailTools.php'; + + $mail = new stdClass(); + $mail->toEmail = $data->tkunde->cMail; + $mail->toName = trim((isset($data->tKunde->cVorname) + ? $data->tKunde->cVorname + : '') . ' ' . ( + isset($data->tKunde->cNachname) + ? $data->tKunde->cNachname + : '' + )) ?: $mail->toEmail; + $data->mail = $mail; + if (!($sentMail = sendeMail('kPlugin_' . self::Plugin()->kPlugin . '_zahlungserinnerung', $data))) { + $checkout->Log(sprintf("Zahlungserinnerung konnte nicht versand werden: %s\n%s", isset($sentMail->cFehler) ?: print_r($sentMail, 1), print_r($data, 1)), LOGLEVEL_ERROR); + $return = false; + } else { + $checkout->Log(sprintf("Zahlungserinnerung für %s verschickt.", $checkout->getBestellung()->cBestellNr)); + } + } else { + $checkout->Log("Kunde '{$checkout->getBestellung()->oKunde->kKunde}' nicht gefunden.", LOGLEVEL_ERROR); + } + } catch (Exception $e) { + $checkout->Log(sprintf("AbstractCheckout::sendReminder: Zahlungserinnerung für %s fehlgeschlagen: %s", $checkout->getBestellung()->cBestellNr, $e->getMessage())); + $return = false; + } + $checkout->getModel()->dReminder = date('Y-m-d H:i:s'); + $checkout->getModel()->save(); + return $return; + } + + /** + * @param AbstractCheckout $checkout + * @return BaseResource|Refund + * @throws ApiException + */ + public static function refund(AbstractCheckout $checkout) + { + if ($checkout->getMollie()->resource === 'order') { + /** @var Order $order */ + $order = $checkout->getMollie(); + if (in_array($order->status, [OrderStatus::STATUS_CANCELED, OrderStatus::STATUS_EXPIRED, OrderStatus::STATUS_CREATED], true)) { + throw new RuntimeException('Bestellung kann derzeit nicht zurückerstattet werden.'); + } + $refund = $order->refundAll(); + $checkout->Log(sprintf('Bestellung wurde manuell zurückerstattet: %s', $refund->id)); + return $refund; + } + if ($checkout->getMollie()->resource === 'payment') { + /** @var \Mollie\Api\Resources\Payment $payment */ + $payment = $checkout->getMollie(); + if (in_array($payment->status, [PaymentStatus::STATUS_CANCELED, PaymentStatus::STATUS_EXPIRED, PaymentStatus::STATUS_OPEN], true)) { + throw new RuntimeException('Zahlung kann derzeit nicht zurückerstattet werden.'); + } + $refund = $checkout->API()->Client()->payments->refund($checkout->getMollie(), ['amount' => $checkout->getMollie()->amount]); + $checkout->Log(sprintf('Zahlung wurde manuell zurückerstattet: %s', $refund->id)); + return $refund; + } + throw new RuntimeException(sprintf('Unbekannte Resource: %s', $checkout->getMollie()->resource)); + } + + /** + * @param false $force + * @return Order|\Mollie\Api\Resources\Payment|null + */ + abstract public function getMollie($force = false); + + public function Log($msg, $level = LOGLEVEL_NOTICE) + { + $data = ''; + if ($this->getBestellung()) { + $data .= '#' . $this->getBestellung()->kBestellung; + } + if ($this->getMollie()) { + $data .= '$' . $this->getMollie()->id; + } + ZahlungsLog::add($this->PaymentMethod()->moduleID, "[" . microtime(true) . " - " . $_SERVER['PHP_SELF'] . "] " . $msg, $data, $level); + return $this; + } + + /** + * @return Bestellung + */ + public function getBestellung() + { + if (!$this->oBestellung && $this->getModel()->kBestellung) { + $this->oBestellung = new Bestellung($this->getModel()->kBestellung, true); + } + return $this->oBestellung; + } + + /** + * @return Payment + */ + public function getModel() + { + if (!$this->model) { + $this->model = Payment::fromID($this->oBestellung->kBestellung, 'kBestellung'); + } + return $this->model; + } + + /** + * @param $model + * @return $this + */ + protected function setModel($model) + { + if (!$this->model) { + $this->model = $model; + } else { + throw new RuntimeException('Model already set.'); + } + return $this; + } + + /** + * @return JTLMollie + */ + public function PaymentMethod() + { + if (!$this->paymentMethod) { + if ($this->getBestellung()->Zahlungsart && strpos($this->getBestellung()->Zahlungsart->cModulId, "kPlugin_{$this::Plugin()->kPlugin}_") !== false) { + $this->paymentMethod = PaymentMethod::create($this->getBestellung()->Zahlungsart->cModulId); + } else { + $this->paymentMethod = PaymentMethod::create("kPlugin_{$this::Plugin()->kPlugin}_mollie"); + } + } + return $this->paymentMethod; + } + + /** + * @return API + */ + public function API() + { + if (!$this->api) { + if ($this->getModel()->kID) { + $this->api = new API($this->getModel()->cMode === 'test'); + } else { + $this->api = new API(API::getMode()); + } + } + return $this->api; + } + + /** + * @param $checkout + * @return Order|\Mollie\Api\Resources\Payment + * @throws ApiException + */ + public static function cancel($checkout) + { + if ($checkout instanceof OrderCheckout) { + return OrderCheckout::cancel($checkout); + } + if ($checkout instanceof PaymentCheckout) { + return PaymentCheckout::cancel($checkout); + } + throw new RuntimeException('AbstractCheckout::cancel: Invalid Checkout!'); + } + + public function loadRequest(&$options = []) + { + + $oKunde = !$this->getBestellung()->oKunde && $this->PaymentMethod()->duringCheckout ? $_SESSION['Kunde'] : $this->getBestellung()->oKunde; + if ($this->getBestellung()) { + if ($oKunde->nRegistriert + && ($customer = $this->getCustomer( + array_key_exists( + 'mollie_create_customer', + $_SESSION['cPost_arr'] ?: []) && $_SESSION['cPost_arr']['mollie_create_customer'] === 'Y', + $oKunde) + ) + && isset($customer)) { + $options['customerId'] = $customer->id; + } + $this->amount = Amount::factory($this->getBestellung()->fGesamtsummeKundenwaehrung, $this->getBestellung()->Waehrung->cISO, true); + $this->redirectUrl = $this->PaymentMethod()->duringCheckout ? Shop::getURL() . '/bestellabschluss.php?' . http_build_query(['hash' => $this->getHash()]) : $this->PaymentMethod()->getReturnURL($this->getBestellung()); + $this->metadata = [ + 'kBestellung' => $this->getBestellung()->kBestellung ?: $this->getBestellung()->cBestellNr, + 'kKunde' => $this->getBestellung()->kKunde, + 'kKundengruppe' => Session::getInstance()->CustomerGroup()->kKundengruppe, + 'cHash' => $this->getHash(), + ]; + } + + $this->locale = self::getLocale($_SESSION['cISOSprache'], Session::getInstance()->Customer()->cLand); + $this->webhookUrl = Shop::getURL(true) . '/?' . http_build_query([ + 'mollie' => 1, + 'hash' => $this->getHash(), + 'test' => $this->API()->isTest() ?: null, + ]); + + $pm = $this->PaymentMethod(); + $isPayAgain = strpos($_SERVER['PHP_SELF'], 'bestellab_again') !== false; + if ($pm::METHOD !== '' && (self::Plugin()->oPluginEinstellungAssoc_arr['resetMethod'] !== 'Y' || !$isPayAgain)) { + $this->method = $pm::METHOD; + } + + } + + /** + * @return \Mollie\Api\Resources\Customer|null + * @todo: Kunde wieder löschbar machen ?! + */ + public function getCustomer($createOrUpdate = false, $oKunde = null) + { + + if (!$oKunde) { + $oKunde = $this->getBestellung()->oKunde; + } + + if (!$this->customer) { + $customerModel = Customer::fromID($oKunde->kKunde, 'kKunde'); + if ($customerModel->customerId) { + try { + $this->customer = $this->API()->Client()->customers->get($customerModel->customerId); + } catch (ApiException $e) { + $this->Log(sprintf("Fehler beim laden des Mollie Customers %s (kKunde: %d): %s", $customerModel->customerId, $customerModel->kKunde, $e->getMessage()), LOGLEVEL_ERROR); + } + } + + if ($createOrUpdate) { + $customer = [ + 'name' => utf8_encode(trim($oKunde->cVorname . ' ' . $oKunde->cNachname)), + 'email' => utf8_encode($oKunde->cMail), + 'locale' => self::getLocale($_SESSION['cISOSprache'], $oKunde->cLand), + 'metadata' => (object)[ + 'kKunde' => $oKunde->kKunde, + 'kKundengruppe' => $oKunde->kKundengruppe, + 'cKundenNr' => utf8_encode($oKunde->cKundenNr), + ], + ]; + + if ($this->customer) { // UPDATE + + $this->customer->name = $customer['name']; + $this->customer->email = $customer['email']; + $this->customer->locale = $customer['locale']; + $this->customer->metadata = $customer['metadata']; + + try { + $this->customer->update(); + } catch (Exception $e) { + $this->Log(sprintf("Fehler beim aktualisieren des Mollie Customers %s: %s\n%s", $this->customer->id, $e->getMessage(), print_r($customer, 1)), LOGLEVEL_ERROR); + } + + + } else { // create + + try { + $this->customer = $this->API()->Client()->customers->create($customer); + $customerModel->kKunde = $oKunde->kKunde; + $customerModel->customerId = $this->customer->id; + $customerModel->save(); + $this->Log(sprintf("Customer '%s' für Kunde %s (%d) bei Mollie angelegt.", $this->customer->id, $this->customer->name, $this->getBestellung()->kKunde)); + } catch (Exception $e) { + $this->Log(sprintf("Fehler beim anlegen eines Mollie Customers: %s\n%s", $e->getMessage(), print_r($customer, 1)), LOGLEVEL_ERROR); + } + } + } + } + return $this->customer; + } + + public static function getLocale($cISOSprache = null, $country = null) + { + + if ($cISOSprache === null) { + $cISOSprache = gibStandardsprache()->cISO; + } + if (array_key_exists($cISOSprache, self::$localeLangs)) { + $locale = self::$localeLangs[$cISOSprache]['lang']; + if ($country && is_array(self::$localeLangs[$cISOSprache]['country']) && in_array($country, self::$localeLangs[$cISOSprache]['country'], true)) { + $locale .= '_' . strtoupper($country); + } else { + $locale .= '_' . self::$localeLangs[$cISOSprache]['country'][0]; + } + return $locale; + } + + return self::Plugin()->oPluginEinstellungAssoc_arr['fallbackLocale']; + } + + /** + * @return string + */ + public function getHash() + { + if ($this->getModel()->cHash) { + return $this->getModel()->cHash; + } + if (!$this->hash) { + $this->hash = $this->PaymentMethod()->generateHash($this->oBestellung); + } + return $this->hash; + } + + /** + * Storno Order + */ + public function storno() + { + if (in_array((int)$this->getBestellung()->cStatus, [BESTELLUNG_STATUS_OFFEN, BESTELLUNG_STATUS_IN_BEARBEITUNG], true)) { + + $log = []; + + $conf = Shop::getSettings([CONF_GLOBAL, CONF_TRUSTEDSHOPS]); + $nArtikelAnzeigefilter = (int)$conf['global']['artikel_artikelanzeigefilter']; + + foreach ($this->getBestellung()->Positionen as $pos) { + if ($pos->kArtikel && $pos->Artikel && $pos->Artikel->cLagerBeachten === 'Y') { + $log[] = sprintf('Reset stock of "%s" by %d', $pos->Artikel->cArtNr, -1 * $pos->nAnzahl); + self::aktualisiereLagerbestand($pos->Artikel, -1 * $pos->nAnzahl, $pos->WarenkorbPosEigenschaftArr, $nArtikelAnzeigefilter); + } + } + $log[] = sprintf("Cancel order '%s'.", $this->getBestellung()->cBestellNr); + + if (Shop::DB()->executeQueryPrepared('UPDATE tbestellung SET cAbgeholt = "Y", cStatus = :cStatus WHERE kBestellung = :kBestellung', [':cStatus' => '-1', ':kBestellung' => $this->getBestellung()->kBestellung], 3)) { + $this->Log(implode('\n', $log)); + } + } + } + + protected static function aktualisiereLagerbestand($Artikel, $nAnzahl, $WarenkorbPosEigenschaftArr, $nArtikelAnzeigefilter = 1) + { + $artikelBestand = (float)$Artikel->fLagerbestand; + + if (isset($Artikel->cLagerBeachten) && $Artikel->cLagerBeachten === 'Y') { + if ($Artikel->cLagerVariation === 'Y' && + is_array($WarenkorbPosEigenschaftArr) && + count($WarenkorbPosEigenschaftArr) > 0 + ) { + foreach ($WarenkorbPosEigenschaftArr as $eWert) { + $EigenschaftWert = new EigenschaftWert($eWert->kEigenschaftWert); + if ($EigenschaftWert->fPackeinheit === .0) { + $EigenschaftWert->fPackeinheit = 1; + } + Shop::DB()->query( + "UPDATE teigenschaftwert + SET fLagerbestand = fLagerbestand - " . ($nAnzahl * $EigenschaftWert->fPackeinheit) . " + WHERE kEigenschaftWert = " . (int)$eWert->kEigenschaftWert, 4 + ); + } + } elseif ($Artikel->fPackeinheit > 0) { + // Stückliste + if ($Artikel->kStueckliste > 0) { + $artikelBestand = self::aktualisiereStuecklistenLagerbestand($Artikel, $nAnzahl); + } else { + Shop::DB()->query( + "UPDATE tartikel + SET fLagerbestand = IF (fLagerbestand >= " . ($nAnzahl * $Artikel->fPackeinheit) . ", + (fLagerbestand - " . ($nAnzahl * $Artikel->fPackeinheit) . "), fLagerbestand) + WHERE kArtikel = " . (int)$Artikel->kArtikel, 4 + ); + $tmpArtikel = Shop::DB()->select('tartikel', 'kArtikel', (int)$Artikel->kArtikel, null, null, null, null, false, 'fLagerbestand'); + if ($tmpArtikel !== null) { + $artikelBestand = (float)$tmpArtikel->fLagerbestand; + } + // Stücklisten Komponente + if (ArtikelHelper::isStuecklisteKomponente($Artikel->kArtikel)) { + self::aktualisiereKomponenteLagerbestand($Artikel->kArtikel, $artikelBestand, isset($Artikel->cLagerKleinerNull) && $Artikel->cLagerKleinerNull === 'Y'); + } + } + // Aktualisiere Merkmale in tartikelmerkmal vom Vaterartikel + if ($Artikel->kVaterArtikel > 0) { + Artikel::beachteVarikombiMerkmalLagerbestand($Artikel->kVaterArtikel, $nArtikelAnzeigefilter); + } + } + } + + return $artikelBestand; + } + + protected static function aktualisiereStuecklistenLagerbestand($oStueckListeArtikel, $nAnzahl) + { + $nAnzahl = (float)$nAnzahl; + $kStueckListe = (int)$oStueckListeArtikel->kStueckliste; + $bestandAlt = (float)$oStueckListeArtikel->fLagerbestand; + $bestandNeu = $bestandAlt; + $bestandUeberverkauf = $bestandAlt; + + if ($nAnzahl > 0) { + // Gibt es lagerrelevante Komponenten in der Stückliste? + $oKomponente_arr = Shop::DB()->query( + "SELECT tstueckliste.kArtikel, tstueckliste.fAnzahl + FROM tstueckliste + JOIN tartikel + ON tartikel.kArtikel = tstueckliste.kArtikel + WHERE tstueckliste.kStueckliste = $kStueckListe + AND tartikel.cLagerBeachten = 'Y'", 2 + ); + + if (is_array($oKomponente_arr) && count($oKomponente_arr) > 0) { + // wenn ja, dann wird für diese auch der Bestand aktualisiert + $options = Artikel::getDefaultOptions(); + + $options->nKeineSichtbarkeitBeachten = 1; + + foreach ($oKomponente_arr as $oKomponente) { + $tmpArtikel = new Artikel(); + $tmpArtikel->fuelleArtikel($oKomponente->kArtikel, $options); + + $komponenteBestand = floor(self::aktualisiereLagerbestand($tmpArtikel, $nAnzahl * $oKomponente->fAnzahl, null) / $oKomponente->fAnzahl); + + if ($komponenteBestand < $bestandNeu && $tmpArtikel->cLagerKleinerNull !== 'Y') { + // Neuer Bestand ist der Kleinste Komponententbestand aller Artikel ohne Überverkauf + $bestandNeu = $komponenteBestand; + } elseif ($komponenteBestand < $bestandUeberverkauf) { + // Für Komponenten mit Überverkauf wird der kleinste Bestand ermittelt. + $bestandUeberverkauf = $komponenteBestand; + } + } + } + + // Ist der alte gleich dem neuen Bestand? + if ($bestandAlt === $bestandNeu) { + // Es sind keine lagerrelevanten Komponenten vorhanden, die den Bestand der Stückliste herabsetzen. + if ($bestandUeberverkauf === $bestandNeu) { + // Es gibt auch keine Komponenten mit Überverkäufen, die den Bestand verringern, deshalb wird + // der Bestand des Stücklistenartikels anhand des Verkaufs verringert + $bestandNeu = $bestandNeu - $nAnzahl * $oStueckListeArtikel->fPackeinheit; + } else { + // Da keine lagerrelevanten Komponenten vorhanden sind, wird der kleinste Bestand der + // Komponentent mit Überverkauf verwendet. + $bestandNeu = $bestandUeberverkauf; + } + + Shop::DB()->update('tartikel', 'kArtikel', (int)$oStueckListeArtikel->kArtikel, (object)[ + 'fLagerbestand' => $bestandNeu, + ]); + } + // Kein Lagerbestands-Update für die Stückliste notwendig! Dies erfolgte bereits über die Komponentenabfrage und + // die dortige Lagerbestandsaktualisierung! + } + + return $bestandNeu; + } + + protected static function aktualisiereKomponenteLagerbestand($kKomponenteArtikel, $fLagerbestand, $bLagerKleinerNull) + { + $kKomponenteArtikel = (int)$kKomponenteArtikel; + $fLagerbestand = (float)$fLagerbestand; + + $oStueckliste_arr = Shop::DB()->query( + "SELECT tstueckliste.kStueckliste, tstueckliste.fAnzahl, + tartikel.kArtikel, tartikel.fLagerbestand, tartikel.cLagerKleinerNull + FROM tstueckliste + JOIN tartikel + ON tartikel.kStueckliste = tstueckliste.kStueckliste + WHERE tstueckliste.kArtikel = $kKomponenteArtikel + AND tartikel.cLagerBeachten = 'Y'", 2 + ); + + if (is_array($oStueckliste_arr) && count($oStueckliste_arr) > 0) { + foreach ($oStueckliste_arr as $oStueckliste) { + // Ist der aktuelle Bestand der Stückliste größer als dies mit dem Bestand der Komponente möglich wäre? + $maxAnzahl = floor($fLagerbestand / $oStueckliste->fAnzahl); + if ($maxAnzahl < (float)$oStueckliste->fLagerbestand && (!$bLagerKleinerNull || $oStueckliste->cLagerKleinerNull === 'Y')) { + // wenn ja, dann den Bestand der Stückliste entsprechend verringern, aber nur wenn die Komponente nicht + // überberkaufbar ist oder die gesamte Stückliste Überverkäufe zulässt + Shop::DB()->update('tartikel', 'kArtikel', (int)$oStueckliste->kArtikel, (object)[ + 'fLagerbestand' => $maxAnzahl, + ]); + } + } + } + } + + /** + * @return array|bool|int|object|null + */ + public function getLogs() + { + return 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' => '%#' . ($this->getBestellung()->kBestellung ?: '##') . '%', + ':cBestellNr' => '%§' . ($this->getBestellung()->cBestellNr ?: '§§') . '%', + ':MollieID' => '%$' . ($this->getMollie()->id ?: '$$') . '%', + ], 2); + } + + /** + * @return bool + */ + public function remindable() + { + return (int)$this->getBestellung()->cStatus !== BESTELLUNG_STATUS_STORNO && !in_array($this->getModel()->cStatus, [PaymentStatus::STATUS_PAID, PaymentStatus::STATUS_AUTHORIZED, PaymentStatus::STATUS_PENDING, OrderStatus::STATUS_COMPLETED, OrderStatus::STATUS_SHIPPING], true); + } + + /** + * @return string + */ + public function LogData() + { + + $data = ''; + if ($this->getBestellung()->kBestellung) { + $data .= '#' . $this->getBestellung()->kBestellung; + } + if ($this->getMollie()) { + $data .= '$' . $this->getMollie()->id; + } + + return $data; + } + + abstract public function cancelOrRefund($force = false); + + /** + * @param array $paymentOptions + * @return Payment|Order + */ + abstract public function create(array $paymentOptions = []); + + /** + * @param null $hash + * @throws Exception + */ + public function handleNotification($hash = null) + { + if (!$this->getHash()) { + $this->getModel()->cHash = $hash; + } + + $this->updateModel()->saveModel(); + if (!$this->getBestellung()->dBezahltDatum || $this->getBestellung()->dBezahltDatum === '0000-00-00') { + if ($incoming = $this->getIncomingPayment()) { + $this->PaymentMethod()->addIncomingPayment($this->getBestellung(), $incoming); + + $this->PaymentMethod()->setOrderStatusToPaid($this->getBestellung()); + static::makeFetchable($this->getBestellung(), $this->getModel()); + $this->PaymentMethod()->deletePaymentHash($this->getHash()); + $this->Log(sprintf("Checkout::handleNotification: Bestellung '%s' als bezahlt markiert: %.2f %s", $this->getBestellung()->cBestellNr, (float)$incoming->fBetrag, $incoming->cISO)); + + $oZahlungsart = Shop::DB()->selectSingleRow('tzahlungsart', 'cModulId', $this->PaymentMethod()->moduleID); + if ($oZahlungsart && (int)$oZahlungsart->nMailSenden === 1) { + require_once PFAD_ROOT . 'includes/mailTools.php'; + $this->PaymentMethod()->sendConfirmationMail($this->getBestellung()); + } + if (!$this->completlyPaid()) { + $this->Log(sprintf("Checkout::handleNotification: Bestellung '%s': nicht komplett bezahlt: %.2f %s", $this->getBestellung()->cBestellNr, (float)$incoming->fBetrag, $incoming->cISO), LOGLEVEL_ERROR); + } + } + } + } + + /** + * @return bool + */ + public function saveModel() + { + return $this->getModel()->save(); + } + + /** + * @return $this + */ + public function updateModel() + { + + if ($this->getMollie()) { + $this->getModel()->kID = $this->getMollie()->id; + $this->getModel()->cLocale = $this->getMollie()->locale; + $this->getModel()->fAmount = (float)$this->getMollie()->amount->value; + $this->getModel()->cMethod = $this->getMollie()->method; + $this->getModel()->cCurrency = $this->getMollie()->amount->currency; + $this->getModel()->cStatus = $this->getMollie()->status; + if ($this->getMollie()->amountRefunded) { + $this->getModel()->fAmountRefunded = $this->getMollie()->amountRefunded->value; + } + if ($this->getMollie()->amountCaptured) { + $this->getModel()->fAmountCaptured = $this->getMollie()->amountCaptured->value; + } + $this->getModel()->cMode = $this->getMollie()->mode ?: null; + $this->getModel()->cRedirectURL = $this->getMollie()->redirectUrl; + $this->getModel()->cWebhookURL = $this->getMollie()->webhookUrl; + $this->getModel()->cCheckoutURL = $this->getMollie()->getCheckoutUrl(); + } + + $this->getModel()->kBestellung = $this->getBestellung()->kBestellung; + $this->getModel()->cOrderNumber = $this->getBestellung()->cBestellNr; + $this->getModel()->cHash = trim($this->getHash(), '_'); + + $this->getModel()->bSynced = $this->getModel()->bSynced !== null ? $this->getModel()->bSynced : Helper::getSetting('onlyPaid') !== 'Y'; + return $this; + } + + /** + * @return stdClass + */ + abstract public function getIncomingPayment(); + + /** + * @param Bestellung $oBestellung + * @param Payment $model + * @return bool + */ + public static function makeFetchable(Bestellung $oBestellung, Payment $model) + { + // TODO: force ? + if ($oBestellung->cAbgeholt === 'Y' && !$model->bSynced) { + Shop::DB()->update('tbestellung', 'kBestellung', $oBestellung->kBestellung, (object)['cAbgeholt' => 'N']); + } + $model->bSynced = true; + try { + return $model->save(); + } catch (Exception $e) { + Jtllog::writeLog(sprintf("Fehler beim speichern des Models: %s / Bestellung: %s", $model->kID, $oBestellung->cBestellNr)); + } + return false; + } + + /** + * @return bool + */ + public function completlyPaid() + { + + if ($row = Shop::DB()->executeQueryPrepared("SELECT SUM(fBetrag) as fBetragSumme FROM tzahlungseingang WHERE kBestellung = :kBestellung", [ + ':kBestellung' => $this->getBestellung()->kBestellung + ], 1)) { + return $row->fBetragSumme >= round($this->getBestellung()->fGesamtsumme * $this->getBestellung()->fWaehrungsFaktor, 2); + } + return false; + + } + + /** + * @return string + */ + public function getRepayURL() + { + return Shop::getURL(true) . '/?m_pay=' . md5($this->getModel()->kID . '-' . $this->getBestellung()->kBestellung); + } + + abstract protected function updateOrderNumber(); + + /** + * @param Bestellung $oBestellung + * @return $this + */ + protected function setBestellung(Bestellung $oBestellung) + { + $this->oBestellung = $oBestellung; + return $this; + } + + /** + * @param Order|\Mollie\Api\Resources\Payment $model + * @return self + */ + abstract protected function setMollie($model); + +} \ No newline at end of file diff --git a/version/204/class/Checkout/AbstractResource.php b/version/204/class/Checkout/AbstractResource.php new file mode 100644 index 0000000..7ca9813 --- /dev/null +++ b/version/204/class/Checkout/AbstractResource.php @@ -0,0 +1,18 @@ +title = trim(($address->cAnrede === 'm' ? Shop::Lang()->get('mr') : Shop::Lang()->get('mrs')) . ' ' . $address->cTitel) ?: null; + $resource->givenName = $address->cVorname; + $resource->familyName = $address->cNachname; + $resource->email = $address->cMail ?: null; + + if ($organizationName = trim($address->cFirma)) { + $resource->organizationName = $organizationName; + } + + // Validity-Check + // TODO: Phone, with E.164 check + // TODO: Is Email-Format Check needed? + if (!$resource->givenName || !$resource->familyName || !$resource->email) { + throw ResourceValidityException::trigger(ResourceValidityException::ERROR_REQUIRED, ['givenName', 'familyName', 'email'], $resource); + } + return $resource; + } + +} \ No newline at end of file diff --git a/version/204/class/Checkout/Order/OrderLine.php b/version/204/class/Checkout/Order/OrderLine.php new file mode 100644 index 0000000..9b9dec4 --- /dev/null +++ b/version/204/class/Checkout/Order/OrderLine.php @@ -0,0 +1,227 @@ +totalAmount->value; + } + if (abs($sum - (float)$amount->value) > 0) { + $diff = (round((float)$amount->value - $sum, 2)); + if ($diff !== 0.0) { + $line = new self(); + $line->type = $diff > 0 ? OrderLineType::TYPE_SURCHARGE : OrderLineType::TYPE_DISCOUNT; + // TODO: Translation needed? + $line->name = 'Rundungsausgleich'; + $line->quantity = 1; + $line->unitPrice = Amount::factory($diff, $currency); + $line->totalAmount = Amount::factory($diff, $currency); + $line->vatRate = "0.00"; + $line->vatAmount = Amount::factory(0, $currency); + return $line; + } + } + return null; + } + + /** + * @param Bestellung $oBestellung + * @return OrderLine + */ + public static function getCredit(Bestellung $oBestellung) + { + $line = new self(); + $line->type = OrderLineType::TYPE_STORE_CREDIT; + $line->name = 'Guthaben'; + $line->quantity = 1; + // TODO: check currency of Guthaben + $line->unitPrice = Amount::factory($oBestellung->fGuthaben, $oBestellung->Waehrung->cISO); + $line->totalAmount = $line->unitPrice; + $line->vatRate = "0.00"; + $line->vatAmount = Amount::factory(0, $oBestellung->Waehrung->cISO); + + return $line; + } + + /** + * @param stdClass|WarenkorbPos $oPosition + * @param null $currency + * @return OrderLine + */ + public static function factory($oPosition, $currency = null) + { + if (!$oPosition) { + throw new RuntimeException('$oPosition invalid:', print_r($oPosition,1)); + } + + $resource = new static(); + + $resource->fill($oPosition, $currency); + + // Validity Check + if (!$resource->name || !$resource->quantity || !$resource->unitPrice || !$resource->totalAmount + || !$resource->vatRate || !$resource->vatAmount) { + throw ResourceValidityException::trigger(ResourceValidityException::ERROR_REQUIRED, + ['name', 'quantity', 'unitPrice', 'totalAmount', 'vatRate', 'vatAmount'], $resource); + } + + return $resource; + + } + + /** + * @param WarenkorbPos|stdClass $oPosition + * @param null|stdClass $currency + * @return $this + * @todo Setting for Fraction handling needed? + */ + protected function fill($oPosition, $currency = null) + { + + if (!$currency) { + $currency = Amount::FallbackCurrency(); + } + + $isKupon = (int)$oPosition->nPosTyp === (int)C_WARENKORBPOS_TYP_KUPON; + $isFrac = fmod($oPosition->nAnzahl, 1) !== 0.0; + + // Kupon? set vatRate to 0 and adjust netto + $vatRate = $isKupon ? 0 : (float)$oPosition->fMwSt / 100; + $netto = $isKupon ? round($oPosition->fPreis * (1 + $vatRate), 4) : round($oPosition->fPreis, 4); + + // Fraction? transform, as it were 1, and set quantity to 1 + $netto = round(($isFrac ? $netto * (float)$oPosition->nAnzahl : $netto) * $currency->fFaktor, 4); + $this->quantity = $isFrac ? 1 : (int)$oPosition->nAnzahl; + + // Fraction? include quantity and unit in name + $this->name = $isFrac ? sprintf("%s (%.2f %s)", $oPosition->cName, (float)$oPosition->nAnzahl, $oPosition->cEinheit) : $oPosition->cName; + if(!$this->name){ + $this->name = '(null)'; + } + $this->mapType($oPosition->nPosTyp); + + //$unitPriceNetto = round(($currency->fFaktor * $netto), 4); + + $this->unitPrice = Amount::factory(round($netto * (1 + $vatRate), 2), $currency->cISO, false); + $this->totalAmount = Amount::factory(round($this->quantity * $this->unitPrice->value, 2), $currency->cISO, false); + + $this->vatRate = number_format($vatRate * 100, 2); + $this->vatAmount = Amount::factory(round($this->totalAmount->value - ($this->totalAmount->value / (1 + $vatRate)), 2), $currency->cISO, false); + + $metadata = []; + + // Is Artikel ? + if (isset($oPosition->Artikel)) { + $this->sku = $oPosition->Artikel->cArtNr; + $metadata['kArtikel'] = $oPosition->kArtikel; + if ($oPosition->cUnique !== '') { + $metadata['cUnique'] = utf8_encode($oPosition->cUnique); + } + } + + if (isset($oPosition->WarenkorbPosEigenschaftArr) && is_array($oPosition->WarenkorbPosEigenschaftArr) && count($oPosition->WarenkorbPosEigenschaftArr)) { + $metadata['properties'] = []; + /** @var WarenkorbPosEigenschaft $warenkorbPosEigenschaft */ + foreach ($oPosition->WarenkorbPosEigenschaftArr as $warenkorbPosEigenschaft) { + $metadata['properties'][] = [ + 'kEigenschaft' => $warenkorbPosEigenschaft->kEigenschaft, + 'kEigenschaftWert' => $warenkorbPosEigenschaft->kEigenschaftWert, + 'name' => utf8_encode($warenkorbPosEigenschaft->cEigenschaftName), + 'value' => utf8_encode($warenkorbPosEigenschaft->cEigenschaftWertName), + ]; + if (strlen(json_encode($metadata)) > 1000) { + array_pop($metadata['properties']); + break; + } + } + + } + if (json_encode($metadata) !== false) { + $this->metadata = $metadata; + } + + return $this; + + + } + + /** + * @param $nPosTyp + * @return OrderLine + */ + protected function mapType($nPosTyp) + { + switch ($nPosTyp) { + case C_WARENKORBPOS_TYP_ARTIKEL: + case C_WARENKORBPOS_TYP_GRATISGESCHENK: + // TODO: digital / Download Artikel? + $this->type = OrderLineType::TYPE_PHYSICAL; + return $this; + + case C_WARENKORBPOS_TYP_VERSANDPOS: + $this->type = OrderLineType::TYPE_SHIPPING_FEE; + return $this; + + case C_WARENKORBPOS_TYP_VERPACKUNG: + case C_WARENKORBPOS_TYP_VERSANDZUSCHLAG: + case C_WARENKORBPOS_TYP_ZAHLUNGSART: + case C_WARENKORBPOS_TYP_VERSAND_ARTIKELABHAENGIG: + case C_WARENKORBPOS_TYP_NACHNAHMEGEBUEHR: + $this->type = OrderLineType::TYPE_SURCHARGE; + return $this; + + case C_WARENKORBPOS_TYP_GUTSCHEIN: + case C_WARENKORBPOS_TYP_KUPON: + case C_WARENKORBPOS_TYP_NEUKUNDENKUPON: + $this->type = OrderLineType::TYPE_DISCOUNT; + return $this; + + } + + throw new RuntimeException('Unknown PosTyp.', (int)$nPosTyp); + } + +} \ No newline at end of file diff --git a/version/204/class/Checkout/OrderCheckout.php b/version/204/class/Checkout/OrderCheckout.php new file mode 100644 index 0000000..f58764b --- /dev/null +++ b/version/204/class/Checkout/OrderCheckout.php @@ -0,0 +1,371 @@ +getMollie()->status !== OrderStatus::STATUS_AUTHORIZED && $checkout->getMollie()->status !== OrderStatus::STATUS_SHIPPING) { + throw new RuntimeException('Nur autorisierte Zahlungen können erfasst werden!'); + } + $shipment = $checkout->API()->Client()->shipments->createFor($checkout->getMollie(), ['lines' => []]); + $checkout->Log(sprintf('Bestellung wurde manuell erfasst/versandt: %s', $shipment->id)); + return $shipment->id; + } + + /** + * @param false $force + * @return Order|null + */ + public function getMollie($force = false) + { + if ($force || (!$this->order && $this->getModel()->kID)) { + try { + $this->order = $this->API()->Client()->orders->get($this->getModel()->kID, ['embed' => 'payments,shipments,refunds']); + } catch (Exception $e) { + throw new RuntimeException(sprintf('Mollie-Order \'%s\' konnte nicht geladen werden: %s', $this->getModel()->kID, $e->getMessage())); + } + } + return $this->order; + } + + /** + * @param OrderCheckout $checkout + * @return Order + * @throws ApiException + */ + public static function cancel($checkout) + { + if (!$checkout->getMollie() || !$checkout->getMollie()->isCancelable) { + throw new RuntimeException('Bestellung kann nicht abgebrochen werden.'); + } + $order = $checkout->getMollie()->cancel(); + $checkout->Log('Bestellung wurde manuell abgebrochen.'); + return $order; + } + + /** + * @return array + * @throws Exception + */ + public function getShipments() + { + $shipments = []; + $lieferschien_arr = Shop::DB()->executeQueryPrepared("SELECT kLieferschein FROM tlieferschein WHERE kInetBestellung = :kBestellung", [ + ':kBestellung' => $this->getBestellung()->kBestellung + ], 2); + + foreach ($lieferschien_arr as $lieferschein) { + $shipments[] = new Shipment($lieferschein->kLieferschein, $this); + } + return $shipments; + } + + /** + * @return string + * @throws ApiException + */ + public function cancelOrRefund($force = false) + { + if (!$this->getMollie()) { + throw new RuntimeException('Mollie-Order konnte nicht geladen werden: ' . $this->getModel()->kID); + } + if ($force || (int)$this->getBestellung()->cStatus === BESTELLUNG_STATUS_STORNO) { + if ($this->getMollie()->isCancelable) { + $res = $this->getMollie()->cancel(); + $result = 'Order cancelled, Status: ' . $res->status; + } else { + $res = $this->getMollie()->refundAll(); + $result = "Order Refund initiiert, Status: " . $res->status; + } + $this->PaymentMethod()->Log("OrderCheckout::cancelOrRefund: " . $result, $this->LogData()); + return $result; + } + throw new RuntimeException('Bestellung ist derzeit nicht storniert, Status: ' . $this->getBestellung()->cStatus); + } + + /** + * @param array $paymentOptions + * @return Order + */ + public function create(array $paymentOptions = []) + { + if ($this->getModel()->kID) { + try { + $this->order = $this->API()->Client()->orders->get($this->getModel()->kID, ['embed' => 'payments']); + if (in_array($this->order->status, [OrderStatus::STATUS_COMPLETED, OrderStatus::STATUS_PAID, OrderStatus::STATUS_AUTHORIZED, OrderStatus::STATUS_PENDING], true)) { + $this->handleNotification(); + throw new RuntimeException(self::Plugin()->oPluginSprachvariableAssoc_arr['errAlreadyPaid']); + } + if ($this->order->status === OrderStatus::STATUS_CREATED) { + if ($this->order->payments()) { + /** @var Payment $payment */ + foreach ($this->order->payments() as $payment) { + if ($payment->status === PaymentStatus::STATUS_OPEN) { + $this->setPayment($payment); + break; + } + } + } + if (!$this->getPayment()) { + $this->setPayment($this->API()->Client()->orderPayments->createForId($this->getModel()->kID, $paymentOptions)); + } + $this->updateModel()->saveModel(); + return $this->getMollie(true); + } + } catch (RuntimeException $e) { + throw $e; + } catch (Exception $e) { + $this->Log(sprintf("OrderCheckout::create: Letzte Order '%s' konnte nicht geladen werden: %s, versuche neue zu erstellen.", $this->getModel()->kID, $e->getMessage()), LOGLEVEL_ERROR); + } + } + + try { + $req = $this->loadRequest($paymentOptions)->jsonSerialize(); + $this->order = $this->API()->Client()->orders->create($req); + $this->Log(sprintf("Order für '%s' wurde erfolgreich angelegt: %s", $this->getBestellung()->cBestellNr, $this->order->id)); + $this->updateModel()->saveModel(); + return $this->order; + } catch (Exception $e) { + $this->Log(sprintf("OrderCheckout::create: Neue Order '%s' konnte nicht erstellt werden: %s.", $this->getBestellung()->cBestellNr, $e->getMessage()), LOGLEVEL_ERROR); + throw new RuntimeException(sprintf("Order für '%s' konnte nicht angelegt werden: %s", $this->getBestellung()->cBestellNr, $e->getMessage())); + } + } + + /** + * @return Payment|null + */ + public function getPayment($search = false) + { + if (!$this->_payment && $search && $this->getMollie()) { + foreach ($this->getMollie()->payments() as $payment) { + if (in_array($payment->status, [ + PaymentStatus::STATUS_AUTHORIZED, + PaymentStatus::STATUS_PAID, + PaymentStatus::STATUS_PENDING, + ], true)) { + $this->_payment = $payment; + break; + } + } + } + return $this->_payment; + } + + /** + * @param $payment + * @return $this + */ + public function setPayment($payment) + { + $this->_payment = $payment; + return $this; + } + + /** + * @return $this|OrderCheckout + */ + public function updateModel() + { + parent::updateModel(); + + if (!$this->getPayment() && $this->getMollie() && $this->getMollie()->payments()) { + /** @var Payment $payment */ + foreach ($this->getMollie()->payments() as $payment) { + if (in_array($payment->status, [PaymentStatus::STATUS_OPEN, PaymentStatus::STATUS_PENDING, PaymentStatus::STATUS_AUTHORIZED, PaymentStatus::STATUS_PAID], true)) { + $this->setPayment($payment); + break; + } + } + } + if ($this->getPayment()) { + $this->getModel()->cTransactionId = $this->getPayment()->id; + } + if ($this->getMollie()) { + $this->getModel()->cCheckoutURL = $this->getMollie()->getCheckoutUrl(); + $this->getModel()->cWebhookURL = $this->getMollie()->webhookUrl; + $this->getModel()->cRedirectURL = $this->getMollie()->redirectUrl; + } + return $this; + } + + /** + * @param array $options + * @return $this|OrderCheckout + */ + public function loadRequest(&$options = []) + { + + parent::loadRequest($options); + + $this->orderNumber = $this->getBestellung()->cBestellNr; + + $this->billingAddress = Address::factory($this->getBestellung()->oRechnungsadresse); + if ($this->getBestellung()->Lieferadresse !== null) { + if (!$this->getBestellung()->Lieferadresse->cMail) { + $this->getBestellung()->Lieferadresse->cMail = $this->getBestellung()->oRechnungsadresse->cMail; + } + $this->shippingAddress = Address::factory($this->getBestellung()->Lieferadresse); + } + + if ( + !empty(Session::getInstance()->Customer()->dGeburtstag) + && Session::getInstance()->Customer()->dGeburtstag !== '0000-00-00' + && preg_match('/^\d{4}-\d{2}-\d{2}$/', trim(Session::getInstance()->Customer()->dGeburtstag)) + ) { + $this->consumerDateOfBirth = trim(Session::getInstance()->Customer()->dGeburtstag); + } + + $lines = []; + foreach ($this->getBestellung()->Positionen as $oPosition) { + $lines[] = OrderLine::factory($oPosition, $this->getBestellung()->Waehrung); + } + + if ($this->getBestellung()->GuthabenNutzen && $this->getBestellung()->fGuthaben > 0) { + $lines[] = OrderLine::getCredit($this->getBestellung()); + } + + if ($comp = OrderLine::getRoundingCompensation($lines, $this->amount, $this->getBestellung()->Waehrung->cISO)) { + $lines[] = $comp; + } + $this->lines = $lines; + + if ($dueDays = $this->PaymentMethod()->getExpiryDays()) { + try { + $max = $this->method && strpos($this->method, 'klarna') !== false ? 28 : 100; + $date = new DateTime(sprintf("+%d DAYS", min($dueDays, $max)), new DateTimeZone('UTC')); + $this->expiresAt = $date->format('Y-m-d'); + //date('Y-m-d', strtotime(sprintf("+%d DAYS", min($dueDays, $max)))); + } catch (Exception $e) { + $this->Log($e->getMessage(), LOGLEVEL_ERROR); + } + } + + $this->payment = $options; + + return $this; + } + + /** + * @return object|null + */ + public function getIncomingPayment() + { + if (!$this->getMollie(true)) { + return null; + } + + $cHinweis = sprintf("%s / %s", $this->getMollie()->id, $this->getPayment(true)->id); + if (Helper::getSetting('wawiPaymentID') === 'ord') { + $cHinweis = $this->getMollie()->id; + } else if (Helper::getSetting('wawiPaymentID') === 'tr') { + $cHinweis = $this->getPayment(true)->id; + } + + + /** @var Payment $payment */ + /** @noinspection NullPointerExceptionInspection */ + foreach ($this->getMollie()->payments() as $payment) { + if (in_array($payment->status, + [PaymentStatus::STATUS_AUTHORIZED, PaymentStatus::STATUS_PAID], true)) { + $this->setPayment($payment); + $data = (object)[ + 'fBetrag' => (float)$payment->amount->value, + 'cISO' => $payment->amount->currency, + 'cZahler' => $payment->details->paypalPayerId ?: $payment->customerId, + 'cHinweis' => $payment->details->paypalReference ?: $cHinweis, + ]; + if (isset($payment->details, $payment->details->paypalFee)) { + $data->fZahlungsgebuehr = $payment->details->paypalFee->value; + } + return $data; + } + } + return null; + } + + /** + * @return $this + */ + protected function updateOrderNumber() + { + try { + if ($this->getMollie()) { + $this->getMollie()->orderNumber = $this->getBestellung()->cBestellNr; + $this->getMollie()->webhookUrl = Shop::getURL() . '/?mollie=1'; + $this->getMollie()->update(); + } + } catch (Exception $e) { + $this->Log('OrderCheckout::updateOrderNumber:' . $e->getMessage(), LOGLEVEL_ERROR); + } + return $this; + } + + /** + * @param Order $model + * @return $this|AbstractCheckout + */ + protected function setMollie($model) + { + if ($model instanceof Order) { + $this->order = $model; + } + return $this; + } +} \ No newline at end of file diff --git a/version/204/class/Checkout/Payment/Address.php b/version/204/class/Checkout/Payment/Address.php new file mode 100644 index 0000000..ea460c1 --- /dev/null +++ b/version/204/class/Checkout/Payment/Address.php @@ -0,0 +1,54 @@ +streetAndNumber = $address->cStrasse . ' ' . $address->cHausnummer; + $resource->postalCode = $address->cPLZ; + $resource->city = $address->cOrt; + $resource->country = $address->cLand; + + if ( + isset($address->cAdressZusatz) + && trim($address->cAdressZusatz) !== '' + ) { + $resource->streetAdditional = trim($address->cAdressZusatz); + } + + // Validity-Check + // TODO: Check for valid Country Code? + // TODO: Check PostalCode requirement Country? + if (!$resource->streetAndNumber || !$resource->city || !$resource->country) { + throw ResourceValidityException::trigger(ResourceValidityException::ERROR_REQUIRED, ['streetAndNumber', 'city', 'country'], $resource); + } + + return $resource; + } + + +} \ No newline at end of file diff --git a/version/204/class/Checkout/Payment/Amount.php b/version/204/class/Checkout/Payment/Amount.php new file mode 100644 index 0000000..125829d --- /dev/null +++ b/version/204/class/Checkout/Payment/Amount.php @@ -0,0 +1,73 @@ + true [5 Rappen Rounding]) + * @return Amount + */ + public static function factory($value, $currency = null, $useRounding = false) + { + + if (!$currency) { + $currency = static::FallbackCurrency()->cISO; + } + + $resource = new static(); + + $resource->currency = $currency; + //$resource->value = number_format(round($useRounding ? $resource->round($value * (float)$currency->fFaktor) : $value * (float)$currency->fFaktor, 2), 2, '.', ''); + $resource->value = number_format(round($useRounding ? $resource->round($value) : $value, 2), 2, '.', ''); + + // Validity Check + // TODO: Check ISO Code? + // TODO: Check Value + if (!$resource->currency || !$resource->value) { + throw ResourceValidityException::trigger(ResourceValidityException::ERROR_REQUIRED, ['currency', 'value'], $resource); + } + return $resource; + } + + /** + * @return stdClass + */ + public static function FallbackCurrency() + { + return isset($_SESSION['Waehrung']) ? $_SESSION['Waehrung'] : Shop::DB()->select('twaehrung', 'cStandard', 'Y'); + } + + /** + * Check if 5 Rappen rounding is necessary + * + * @return float + */ + protected function round($value) + { + + $conf = Shop::getSettings([CONF_KAUFABWICKLUNG]); + if (isset($conf['kaufabwicklung']['bestellabschluss_runden5']) && (int)$conf['kaufabwicklung']['bestellabschluss_runden5'] === 1) { + $value = round($value * 20) / 20; + } + return $value; + } + + +} \ No newline at end of file diff --git a/version/204/class/Checkout/PaymentCheckout.php b/version/204/class/Checkout/PaymentCheckout.php new file mode 100644 index 0000000..f11e22b --- /dev/null +++ b/version/204/class/Checkout/PaymentCheckout.php @@ -0,0 +1,220 @@ +getMollie()->isCancelable) { + throw new RuntimeException('Zahlung kann nicht abgebrochen werden.'); + } + $payment = $checkout->API()->Client()->payments->cancel($checkout->getMollie()->id); + $checkout->Log('Zahlung wurde manuell abgebrochen.'); + return $payment; + } + + /** + * @param false $force + * @return Payment|null + */ + public function getMollie($force = false) + { + if ($force || (!$this->getPayment() && $this->getModel()->kID)) { + try { + $this->setPayment($this->API()->Client()->payments->get($this->getModel()->kID, ['embed' => 'refunds'])); + } catch (Exception $e) { + throw new RuntimeException('Mollie-Payment konnte nicht geladen werden: ' . $e->getMessage()); + } + } + return $this->getPayment(); + } + + /** + * @return Payment|null + */ + public function getPayment() + { + return $this->_payment; + } + + /** + * @param $payment + * @return $this + */ + public function setPayment($payment) + { + $this->_payment = $payment; + return $this; + } + + /** + * @return string + * @throws ApiException + * @throws IncompatiblePlatform + */ + public function cancelOrRefund($force = false) + { + if (!$this->getMollie()) { + throw new RuntimeException('Mollie-Order konnte nicht geladen werden: ' . $this->getModel()->kID); + } + if ($force || (int)$this->getBestellung()->cStatus === BESTELLUNG_STATUS_STORNO) { + if ($this->getMollie()->isCancelable) { + $res = $this->API()->Client()->payments->cancel($this->getMollie()->id); + $result = 'Payment cancelled, Status: ' . $res->status; + } else { + $res = $this->API()->Client()->payments->refund($this->getMollie(), ['amount' => $this->getMollie()->amount]); + $result = "Payment Refund initiiert, Status: " . $res->status; + } + $this->PaymentMethod()->Log("PaymentCheckout::cancelOrRefund: " . $result, $this->LogData()); + return $result; + } + throw new RuntimeException('Bestellung ist derzeit nicht storniert, Status: ' . $this->getBestellung()->cStatus); + } + + /** + * @param array $paymentOptions + * @return Payment + */ + public function create(array $paymentOptions = []) + { + if ($this->getModel()->kID) { + try { + $this->setPayment($this->API()->Client()->payments->get($this->getModel()->kID)); + if ($this->getPayment()->status === PaymentStatus::STATUS_PAID) { + throw new RuntimeException(self::Plugin()->oPluginSprachvariableAssoc_arr['errAlreadyPaid']); + } + if ($this->getPayment()->status === PaymentStatus::STATUS_OPEN) { + $this->updateModel()->saveModel(); + return $this->getPayment(); + } + } catch (RuntimeException $e) { + //$this->Log(sprintf("PaymentCheckout::create: Letzte Transaktion '%s' konnte nicht geladen werden: %s", $this->getModel()->kID, $e->getMessage()), LOGLEVEL_ERROR); + throw $e; + } catch (Exception $e) { + $this->Log(sprintf("PaymentCheckout::create: Letzte Transaktion '%s' konnte nicht geladen werden: %s, versuche neue zu erstellen.", $this->getModel()->kID, $e->getMessage()), LOGLEVEL_ERROR); + } + } + + try { + $req = $this->loadRequest($paymentOptions)->jsonSerialize(); + $this->setPayment($this->API()->Client()->payments->create($req)); + $this->Log(sprintf("Payment für '%s' wurde erfolgreich angelegt: %s", $this->getBestellung()->cBestellNr, $this->getPayment()->id)); + $this->updateModel()->saveModel(); + return $this->getPayment(); + } catch (Exception $e) { + $this->Log(sprintf("PaymentCheckout::create: Neue Transaktion für '%s' konnte nicht erstellt werden: %s.", $this->getBestellung()->cBestellNr, $e->getMessage()), LOGLEVEL_ERROR); + throw new RuntimeException(sprintf('Mollie-Payment \'%s\' konnte nicht geladen werden: %s', $this->getBestellung()->cBestellNr, $e->getMessage())); + } + } + + /** + * @param array $options + * @return $this|PaymentCheckout + */ + public function loadRequest(&$options = []) + { + + parent::loadRequest($options); + + $this->description = 'Order ' . $this->getBestellung()->cBestellNr; + + foreach ($options as $key => $value) { + $this->$key = $value; + } + + return $this; + } + + /** + * @return object|null + */ + public function getIncomingPayment() + { + if (!$this->getMollie()) { + return null; + } + + if (in_array($this->getMollie()->status, [PaymentStatus::STATUS_AUTHORIZED, PaymentStatus::STATUS_PAID], true)) { + $data = []; + $data['fBetrag'] = (float)$this->getMollie()->amount->value; + $data['cISO'] = $this->getMollie()->amount->currency; + $data['cZahler'] = $this->getMollie()->details->paypalPayerId ?: $this->getMollie()->customerId; + $data['cHinweis'] = $this->getMollie()->details->paypalReference ?: $this->getMollie()->id; + if (isset($this->getMollie()->details, $this->getMollie()->details->paypalFee)) { + $data['fZahlungsgebuehr'] = $this->getMollie()->details->paypalFee->value; + } + return (object)$data; + } + return null; + } + + /** + * @param Payment $model + * @return $this|AbstractCheckout + */ + protected function setMollie($model) + { + if ($model instanceof Payment) { + $this->setPayment($model); + } + return $this; + } + + /** + * @return $this + */ + protected function updateOrderNumber() + { + try { + if ($this->getMollie()) { + $this->getMollie()->description = 'Order ' . $this->getBestellung()->cBestellNr; + $this->getMollie()->webhookUrl = Shop::getURL() . '/?mollie=1'; + $this->getMollie()->update(); + } + } catch (Exception $e) { + $this->Log('OrderCheckout::updateOrderNumber:' . $e->getMessage(), LOGLEVEL_ERROR); + } + return $this; + } + +} \ No newline at end of file diff --git a/version/204/class/ExclusiveLock.php b/version/204/class/ExclusiveLock.php new file mode 100644 index 0000000..f3d3d95 --- /dev/null +++ b/version/204/class/ExclusiveLock.php @@ -0,0 +1,64 @@ +key = $key; + $this->path = rtrim(realpath($path), '/') . '/'; + if (!is_dir($path) || !is_writable($path)) { + throw new RuntimeException("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", 'wb+'); + } + + + public function __destruct() + { + if ($this->own === true) { + $this->unlock(); + } + } + + /** @noinspection ForgottenDebugOutputInspection */ + 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; + } + 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 + } + + public function lock() + { + if (!flock($this->file, LOCK_EX | LOCK_NB)) { //failed + return false; + } + fwrite($this->file, "Locked - " . microtime(true) . "\n"); + fflush($this->file); + + $this->own = true; + return true; // success + } +} diff --git a/version/204/class/Helper.php b/version/204/class/Helper.php new file mode 100644 index 0000000..514f1c5 --- /dev/null +++ b/version/204/class/Helper.php @@ -0,0 +1,350 @@ +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) && !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; + } + 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()->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) 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/204/class/Hook/AbstractHook.php b/version/204/class/Hook/AbstractHook.php new file mode 100644 index 0000000..8dcbbda --- /dev/null +++ b/version/204/class/Hook/AbstractHook.php @@ -0,0 +1,13 @@ +kPlugin)) + && array_key_exists($key, $_SESSION) && !array_key_exists("Zahlungsart", $_SESSION)) { + unset($_SESSION[$key]); + } + + if (!array_key_exists('ws_mollie_applepay_available', $_SESSION)) { + Shop::Smarty()->assign('applePayCheckURL', json_encode(self::Plugin()->cFrontendPfadURLSSL . 'applepay.php')); + pq('body')->append(Shop::Smarty()->fetch(self::Plugin()->cFrontendPfad . 'tpl/applepay.tpl')); + } + + } + + /** + * @return bool + */ + public static function isAvailable() + { + if (array_key_exists('ws_mollie_applepay_available', $_SESSION)) { + return $_SESSION['ws_mollie_applepay_available']; + } + return false; + } + + /** + * @param $status bool + */ + public static function setAvailable($status) + { + $_SESSION['ws_mollie_applepay_available'] = $status; + } + +} \ No newline at end of file diff --git a/version/204/class/Hook/Checkbox.php b/version/204/class/Hook/Checkbox.php new file mode 100644 index 0000000..9ab5ca8 --- /dev/null +++ b/version/204/class/Hook/Checkbox.php @@ -0,0 +1,60 @@ +cModulId, 'kPlugin_' . self::Plugin()->kPlugin . '_') === false) { + return; + } + + if (array_key_exists('nAnzeigeOrt', $args_arr) && $args_arr['nAnzeigeOrt'] === CHECKBOX_ORT_BESTELLABSCHLUSS && Session::getInstance()->Customer()->nRegistriert) { + + $mCustomer = Customer::fromID(Session::getInstance()->Customer()->kKunde, 'kKunde'); + + if ($mCustomer->customerId) { + return; + } + + $checkbox = new \CheckBox(); + $checkbox->kLink = 0; + $checkbox->kCheckBox = -1; + $checkbox->kCheckBoxFunktion = 0; + $checkbox->cName = 'MOLLIE SAVE CUSTOMER'; + $checkbox->cKundengruppe = ';1;'; + $checkbox->cAnzeigeOrt = ';2;'; + $checkbox->nAktiv = 1; + $checkbox->nPflicht = 0; + $checkbox->nLogging = 0; + $checkbox->nSort = 999; + $checkbox->dErstellt = date('Y-m-d H:i:s'); + $checkbox->oCheckBoxSprache_arr = []; + + $langs = gibAlleSprachen(); + foreach ($langs as $lang) { + $checkbox->oCheckBoxSprache_arr[$lang->kSprache] = (object)[ + 'cText' => self::Plugin()->oPluginSprachvariableAssoc_arr['checkboxText'], + 'cBeschreibung' => self::Plugin()->oPluginSprachvariableAssoc_arr['checkboxDescr'], + 'kSprache' => $lang->kSprache, + 'kCheckbox' => -1 + ]; + } + + $checkbox->kKundengruppe_arr = [Session::getInstance()->Customer()->kKundengruppe]; + $checkbox->kAnzeigeOrt_arr = [CHECKBOX_ORT_BESTELLABSCHLUSS]; + $checkbox->cID = "mollie_create_customer"; + $checkbox->cLink = ''; + + $args_arr['oCheckBox_arr'][] = $checkbox; + + } + } +} \ No newline at end of file diff --git a/version/204/class/Hook/Queue.php b/version/204/class/Hook/Queue.php new file mode 100644 index 0000000..8e3bbcf --- /dev/null +++ b/version/204/class/Hook/Queue.php @@ -0,0 +1,137 @@ +nWaehrendBestellung === 0 + && $args_arr['oBestellung']->fGesamtsumme > 0 + && self::Plugin()->oPluginEinstellungAssoc_arr['onlyPaid'] === 'Y' + && AbstractCheckout::isMollie((int)$args_arr['oBestellung']->kZahlungsart, true)) { + + $args_arr['oBestellung']->cAbgeholt = 'Y'; + Jtllog::writeLog('Switch cAbgeholt for kBestellung: ' . print_r($args_arr['oBestellung']->kBestellung, 1), JTLLOG_LEVEL_NOTICE); + } + } + + /** + * @param array $args_arr + */ + public static function xmlBestellStatus(array $args_arr) + { + if (AbstractCheckout::isMollie((int)$args_arr['oBestellung']->kBestellung)) { + self::saveToQueue(HOOK_BESTELLUNGEN_XML_BESTELLSTATUS . ':' . (int)$args_arr['oBestellung']->kBestellung, [ + 'kBestellung' => $args_arr['oBestellung']->kBestellung, + 'status' => (int)$args_arr['status'] + ]); + } + } + + /** + * @param $hook + * @param $args_arr + * @param string $type + * @return bool + */ + public static function saveToQueue($hook, $args_arr, $type = 'hook') + { + $mQueue = new QueueModel(); + $mQueue->cType = $type . ':' . $hook; + $mQueue->cData = serialize($args_arr); + try { + return $mQueue->save(); + } catch (Exception $e) { + Jtllog::writeLog('mollie::saveToQueue: ' . $e->getMessage() . ' - ' . print_r($args_arr, 1)); + return false; + } + } + + /** + * @param array $args_arr + */ + public static function xmlBearbeiteStorno(array $args_arr) + { + if (AbstractCheckout::isMollie((int)$args_arr['oBestellung']->kBestellung)) { + self::saveToQueue(HOOK_BESTELLUNGEN_XML_BEARBEITESTORNO . ':' . $args_arr['oBestellung']->kBestellung, ['kBestellung' => $args_arr['oBestellung']->kBestellung]); + } + } + + /** + * + */ + public static function headPostGet() + { + if (array_key_exists('mollie', $_REQUEST) && (int)$_REQUEST['mollie'] === 1 && array_key_exists('id', $_REQUEST)) { + + if (array_key_exists('hash', $_REQUEST) && $hash = trim(StringHandler::htmlentities(StringHandler::filterXSS($_REQUEST['hash'])), '_')) { + + AbstractCheckout::finalizeOrder($hash, $_REQUEST['id'], array_key_exists('test', $_REQUEST)); + } else { + self::saveToQueue($_REQUEST['id'], $_REQUEST['id'], 'webhook'); + } + exit(); + } + if (array_key_exists('m_pay', $_REQUEST)) { + try { + $raw = Shop::DB()->executeQueryPrepared('SELECT kID FROM `xplugin_ws_mollie_payments` WHERE dReminder IS NOT NULL AND MD5(CONCAT(kID, "-", kBestellung)) = :md5', [ + ':md5' => $_REQUEST['m_pay'] + ], 1); + + if (!$raw) { + throw new RuntimeException(self::Plugin()->oPluginSprachvariableAssoc_arr['errOrderNotFound']); + } + + if (strpos($raw->cOrderId, 'tr_') === 0) { + $checkout = PaymentCheckout::fromID($raw->kID); + } else { + $checkout = OrderCheckout::fromID($raw->kID); + } + $checkout->getMollie(true); + $checkout->updateModel()->saveModel(); + + if (($checkout->getBestellung()->dBezahltDatum !== null && $checkout->getBestellung()->dBezahltDatum !== '0000-00-00') + || in_array($checkout->getModel()->cStatus, ['completed', 'paid', 'authorized', 'pending'])) { + throw new RuntimeException(self::Plugin()->oPluginSprachvariableAssoc_arr['errAlreadyPaid']); + } + + $options = []; + if (self::Plugin()->oPluginEinstellungAssoc_arr['resetMethod'] !== 'Y') { + $options['method'] = $checkout->getModel()->cMethod; + } + + $mollie = $checkout->create($options); // Order::repayOrder($orderModel->getOrderId(), $options, $api); + $url = $mollie->getCheckoutUrl(); + + header('Location: ' . $url); + exit(); + + } catch (RuntimeException $e) { + // TODO Workaround? + //$alertHelper = Shop::Container()->getAlertService(); + //$alertHelper->addAlert(Alert::TYPE_ERROR, $e->getMessage(), 'mollie_repay', ['dismissable' => true]); + } catch (Exception $e) { + Jtllog::writeLog('mollie:repay:error: ' . $e->getMessage() . "\n" . print_r($_REQUEST, 1)); + } + } + } + +} \ No newline at end of file diff --git a/version/204/class/Model/AbstractModel.php b/version/204/class/Model/AbstractModel.php new file mode 100644 index 0000000..e041d4e --- /dev/null +++ b/version/204/class/Model/AbstractModel.php @@ -0,0 +1,98 @@ +data = $data; + if (!$data) { + $this->new = true; + } + } + + /** + * @param $id + * @param string $col + * @param false $failIfNotExists + * @return static + */ + public static function fromID($id, $col = 'kID', $failIfNotExists = false) + { + if ($payment = Shop::DB()->executeQueryPrepared("SELECT * FROM " . static::TABLE . " WHERE `$col` = :id", + [':id' => $id], 1)) { + return new static($payment); + } + if ($failIfNotExists) { + throw new RuntimeException(sprintf('Model %s in %s nicht gefunden!', $id, static::TABLE)); + } + return new static(); + } + + /** + * @return mixed|stdClass|null + */ + public function jsonSerialize() + { + return $this->data; + } + + public function __get($name) + { + if (isset($this->data->$name)) { + return $this->data->$name; + } + return null; + } + + public function __set($name, $value) + { + if (!$this->data) { + $this->data = new stdClass(); + } + $this->data->$name = $value; + } + + public function __isset($name) + { + return isset($this->data->$name); + } + + /** + * @return bool + */ + public function save() + { + if (!$this->data) { + throw new RuntimeException('No Data to save!'); + } + + if ($this->new) { + Shop::DB()->insertRow(static::TABLE, $this->data); + $this->new = false; + return true; + } + Shop::DB()->updateRow(static::TABLE, static::PRIMARY, $this->data->{static::PRIMARY}, $this->data); + return true; + } + +} diff --git a/version/204/class/Model/Customer.php b/version/204/class/Model/Customer.php new file mode 100644 index 0000000..7be9e15 --- /dev/null +++ b/version/204/class/Model/Customer.php @@ -0,0 +1,19 @@ +dCreatedAt) { + $this->dCreatedAt = date('Y-m-d H:i:s'); + } + if($this->new){ + $this->dReminder = self::NULL; + } + return parent::save(); + } +} diff --git a/version/204/class/Model/Queue.php b/version/204/class/Model/Queue.php new file mode 100644 index 0000000..e17a491 --- /dev/null +++ b/version/204/class/Model/Queue.php @@ -0,0 +1,42 @@ +cResult = $result; + $this->dDone = $date ?: date('Y-m-d H:i:s'); + return $this->save(); + } + + public function save() + { + if (!$this->dCreated) { + $this->dCreated = date('Y-m-d H:i:s'); + } + $this->dModified = date('Y-m-d H:i:s'); + return parent::save(); + } + +} \ No newline at end of file diff --git a/version/204/class/Model/Shipment.php b/version/204/class/Model/Shipment.php new file mode 100644 index 0000000..bece7b4 --- /dev/null +++ b/version/204/class/Model/Shipment.php @@ -0,0 +1,28 @@ +kPlugin; + if ($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); + } + } + } + } + + 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[] = AbstractCheckout::getLocale($sS->cISO, $land); + } + } + return array_intersect(array_unique($result), $locales); + } + + 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/204/class/Queue.php b/version/204/class/Queue.php new file mode 100644 index 0000000..7340260 --- /dev/null +++ b/version/204/class/Queue.php @@ -0,0 +1,234 @@ +executeQueryPrepared("SELECT p.kBestellung, b.cStatus FROM xplugin_ws_mollie_payments p " + . "JOIN tbestellung b ON b.kBestellung = p.kBestellung " + . "WHERE b.cAbgeholt = 'Y' AND NOT p.bSynced AND b.cStatus IN ('1', '2') AND p.dCreatedAt < NOW() - INTERVAL :d HOUR", + [':d' => $delay], 2); + + foreach ($open as $o) { + try { + + $checkout = AbstractCheckout::fromBestellung($o->kBestellung); + $pm = $checkout->PaymentMethod(); + if ($pm::ALLOW_AUTO_STORNO && $pm::METHOD === $checkout->getMollie()->method) { + if ($checkout->getBestellung()->cAbgeholt === 'Y' && (bool)$checkout->getModel()->bSynced === false) { + if (!in_array($checkout->getMollie()->status, [OrderStatus::STATUS_PAID, OrderStatus::STATUS_COMPLETED, OrderStatus::STATUS_AUTHORIZED], true)) { + $checkout->storno(); + } else { + $checkout->Log(sprintf('AutoStorno: Bestellung bezahlt? %s - Method: %s', $checkout->getMollie()->status, $checkout->getMollie()->method), LOGLEVEL_ERROR); + } + } else { + $checkout->Log('AutoStorno: bereits zur WAWI synchronisiert.', LOGLEVEL_ERROR); + } + } + + } catch (Exception $e) { + Helper::logExc($e); + } + } + return true; + } + + /** + * @param int $limit + */ + public static function run($limit = 10) + { + + foreach (self::getOpen($limit) as $todo) { + + if (!self::lock($todo)) { + Jtllog::writeLog(sprintf('%s already locked since %s', $todo->kId, $todo->bLock ?: 'just now')); + continue; + } + + if ((list($type, $id) = explode(':', $todo->cType))) { + try { + switch ($type) { + case 'webhook': + self::handleWebhook($id, $todo); + break; + + case 'hook': + self::handleHook((int)$id, $todo); + break; + } + + } catch (Exception $e) { + Jtllog::writeLog($e->getMessage() . " ($type, $id)"); + $todo->done("{$e->getMessage()}\n{$e->getFile()}:{$e->getLine()}\n{$e->getTraceAsString()}"); + } + } + + self::unlock($todo); + + } + } + + /** + * @param $limit + * @return Generator|QueueModel[] + * @noinspection PhpReturnDocTypeMismatchInspection + * @noinspection SqlResolve + */ + private static function getOpen($limit) + { + $open = Shop::DB()->executeQueryPrepared(sprintf("SELECT * FROM %s WHERE dDone IS NULL AND `bLock` IS NULL ORDER BY dCreated DESC LIMIT 0, :LIMIT;", QueueModel::TABLE), [ + ':LIMIT' => $limit + ], 2); + + foreach ($open as $_raw) { + yield new QueueModel($_raw); + } + } + + /** + * @param $todo + * @return bool + * @noinspection SqlResolve + */ + protected static function lock($todo) + { + return $todo->kId && Shop::DB()->executeQueryPrepared(sprintf('UPDATE %s SET `bLock` = NOW() WHERE `bLock` IS NULL AND kId = :kId', QueueModel::TABLE), [ + 'kId' => $todo->kId + ], 3) >= 1; + + } + + /** + * @param $id + * @param QueueModel $todo + * @return bool + * @throws Exception + */ + protected static function handleWebhook($id, QueueModel $todo) + { + $checkout = AbstractCheckout::fromID($id); + if ($checkout->getBestellung()->kBestellung && $checkout->PaymentMethod()) { + $checkout->handleNotification(); + return $todo->done('Status: ' . $checkout->getMollie()->status); + } + throw new RuntimeException("Bestellung oder Zahlungsart konnte nicht geladen werden: $id"); + } + + /** + * @param $hook + * @param QueueModel $todo + * @return bool + * @throws ApiException + * @throws IncompatiblePlatform + * @throws Exception + */ + protected static function handleHook($hook, QueueModel $todo) + { + $data = unserialize($todo->cData); + if (array_key_exists('kBestellung', $data)) { + switch ($hook) { + case HOOK_BESTELLUNGEN_XML_BESTELLSTATUS: + if ((int)$data['kBestellung']) { + $checkout = AbstractCheckout::fromBestellung($data['kBestellung']); + + $status = array_key_exists('status', $data) ? (int)$data['status'] : 0; + $result = ""; + if (!$status || $status < BESTELLUNG_STATUS_VERSANDT) { + return $todo->done("Bestellung noch nicht versendet: {$checkout->getBestellung()->cStatus}"); + } + + /** @var $method JTLMollie */ + if ((strpos($checkout->getModel()->kID, 'tr_') === false) + && $checkout->PaymentMethod() + && $checkout->getMollie()) { + /** @var OrderCheckout $checkout */ + $checkout->handleNotification(); + if ($checkout->getMollie()->status === OrderStatus::STATUS_COMPLETED) { + $result = 'Mollie Status already ' . $checkout->getMollie()->status; + } else if ($checkout->getMollie()->isCreated() || $checkout->getMollie()->isPaid() || $checkout->getMollie()->isAuthorized() || $checkout->getMollie()->isShipping() || $checkout->getMollie()->isPending()) { + try { + if ($shipments = Shipment::syncBestellung($checkout)) { + foreach ($shipments as $shipment) { + if (is_string($shipment)) { + $checkout->PaymentMethod()->Log("Shipping-Error: $shipment", $checkout->LogData()); + $result .= "Shipping-Error: $shipment;\n"; + + } else { + $checkout->PaymentMethod()->Log("Order shipped: \n" . print_r($shipment, 1)); + $result .= "Order shipped: $shipment->id;\n"; + } + } + } else { + $result = 'No Shipments ready!'; + } + } catch (RuntimeException $e) { + $result = $e->getMessage(); + } catch (Exception $e) { + $result = $e->getMessage() . "\n" . $e->getFile() . ":" . $e->getLine() . "\n" . $e->getTraceAsString(); + } + } else { + $result = sprintf('Unerwarteter Mollie Status "%s" für %s', $checkout->getMollie()->status, $checkout->getBestellung()->cBestellNr); + } + } else { + $result = 'Nothing to do.'; + } + $checkout->PaymentMethod()->Log("Queue::handleHook: " . $result, $checkout->LogData()); + } else { + $result = "kBestellung missing"; + } + return $todo->done($result); + + case HOOK_BESTELLUNGEN_XML_BEARBEITESTORNO: + if (self::Plugin()->oPluginEinstellungAssoc_arr['autoRefund'] !== 'Y') { + throw new RuntimeException('Auto-Refund disabled'); + } + + $checkout = AbstractCheckout::fromBestellung((int)$data['kBestellung']); + return $todo->done($checkout->cancelOrRefund()); + } + } + return false; + } + + /** + * @param $todo + * @return bool + */ + protected static function unlock($todo) + { + return $todo->kId && Shop::DB()->executeQueryPrepared(sprintf('UPDATE %s SET `bLock` = NULL WHERE kId = :kId', QueueModel::TABLE), [ + 'kId' => $todo->kId + ], 3) >= 1; + } + +} \ No newline at end of file diff --git a/version/204/class/Shipment.php b/version/204/class/Shipment.php new file mode 100644 index 0000000..0268423 --- /dev/null +++ b/version/204/class/Shipment.php @@ -0,0 +1,316 @@ +kLieferschein = $kLieferschein; + if ($checkout) { + $this->checkout = $checkout; + } + + if (!$this->getLieferschein() || !$this->getLieferschein()->getLieferschein()) { + throw new RuntimeException('Lieferschein konnte nicht geladen werden'); + } + + if (!count($this->getLieferschein()->oVersand_arr)) { + throw new RuntimeException('Kein Versand gefunden!'); + } + + if (!$this->getCheckout()->getBestellung()->oKunde->nRegistriert) { + $this->isGuest = true; + } + } + + public function getLieferschein() + { + if (!$this->oLieferschein && $this->kLieferschein) { + $this->oLieferschein = new Lieferschein($this->kLieferschein); + } + return $this->oLieferschein; + } + + /** + * @return OrderCheckout + * @throws Exception + */ + public function getCheckout() + { + if (!$this->checkout) { + //TODO evtl. load by lieferschien + throw new Exception('Should not happen, but it did!'); + } + return $this->checkout; + } + + public static function syncBestellung(OrderCheckout $checkout) + { + $shipments = []; + if ($checkout->getBestellung()->kBestellung) { + + $oKunde = $checkout->getBestellung()->oKunde ?: new Kunde($checkout->getBestellung()->kKunde); + + $shippingActive = Helper::getSetting('shippingActive'); + if ($shippingActive === 'N') { + throw new RuntimeException('Shipping deaktiviert'); + } + + if ($shippingActive === 'K' && !$oKunde->nRegistriert && (int)$checkout->getBestellung()->cStatus !== BESTELLUNG_STATUS_VERSANDT) { + throw new RuntimeException('Shipping für Gast-Bestellungen und Teilversand deaktiviert'); + } + + /** @var Lieferschein $oLieferschein */ + foreach ($checkout->getBestellung()->oLieferschein_arr as $oLieferschein) { + try { + $shipment = new Shipment($oLieferschein->getLieferschein(), $checkout); + $mode = self::Plugin()->oPluginEinstellungAssoc_arr['shippingMode']; + switch ($mode) { + case 'A': + // ship directly + if (!$shipment->send() && !$shipment->getShipment()) { + throw new RuntimeException('Shipment konnte nicht gespeichert werden.'); + } + $shipments[] = $shipment->getShipment(); + break; + + case 'B': + // only ship if complete shipping + if ($oKunde->nRegistriert || (int)$checkout->getBestellung()->cStatus === BESTELLUNG_STATUS_VERSANDT) { + if (!$shipment->send() && !$shipment->getShipment()) { + throw new RuntimeException('Shipment konnte nicht gespeichert werden.'); + } + $shipments[] = $shipment->getShipment(); + break; + } + throw new RuntimeException('Gastbestellung noch nicht komplett versendet!'); + } + } catch (RuntimeException $e) { + $shipments[] = $e->getMessage(); + } catch (Exception $e) { + $shipments[] = $e->getMessage(); + $checkout->Log("mollie: Shipment::syncBestellung (BestellNr. {$checkout->getBestellung()->cBestellNr}, Lieferschein: {$oLieferschein->getLieferscheinNr()}) - " . $e->getMessage(), LOGLEVEL_ERROR); + } + } + } + return $shipments; + } + + /** + * @return bool + * @throws ApiException + * @throws IncompatiblePlatform + * @throws Exception + */ + public function send() + { + + if ($this->getShipment()) { + throw new RuntimeException('Lieferschien bereits an Mollie übertragen: ' . $this->getShipment()->id); + } + + if ($this->getCheckout()->getMollie(true)->status === OrderStatus::STATUS_COMPLETED) { + throw new RuntimeException('Bestellung bei Mollie bereits abgeschlossen!'); + } + + $api = $this->getCheckout()->API()->Client(); + $this->shipment = $api->shipments->createForId($this->checkout->getModel()->kID, $this->loadRequest()->jsonSerialize()); + + return $this->updateModel()->saveModel(); + + } + + /** + * @param false $force + * @return BaseResource|\Mollie\Api\Resources\Shipment + * @throws ApiException + * @throws IncompatiblePlatform + * @throws Exception + */ + public function getShipment($force = false) + { + if (($force || !$this->shipment) && $this->getModel() && $this->getModel()->cShipmentId) { + $this->shipment = $this->getCheckout()->API()->Client()->shipments->getForId($this->getModel()->cOrderId, $this->getModel()->cShipmentId); + } + return $this->shipment; + } + + /** + * @return ShipmentModel + * @throws Exception + */ + public function getModel() + { + if (!$this->model && $this->kLieferschein) { + $this->model = ShipmentModel::fromID($this->kLieferschein, 'kLieferschein'); + + if (!$this->model->dCreated) { + $this->model->dCreated = date('Y-m-d H:i:s'); + } + $this->updateModel(); + } + return $this->model; + } + + /** + * @return $this + * @throws Exception + */ + public function updateModel() + { + $this->getModel()->kLieferschein = $this->kLieferschein; + if ($this->getCheckout()) { + $this->getModel()->cOrderId = $this->getCheckout()->getModel()->kID; + $this->getModel()->kBestellung = $this->getCheckout()->getModel()->kBestellung; + } + if ($this->getShipment()) { + $this->getModel()->cShipmentId = $this->getShipment()->id; + $this->getModel()->cUrl = $this->getShipment()->getTrackingUrl() ?: ''; + } + if (isset($this->tracking)) { + $this->getModel()->cCarrier = $this->tracking['carrier'] ?: ''; + $this->getModel()->cCode = $this->tracking['code'] ?: ''; + } + return $this; + } + + /** + * @param array $options + * @return $this + * @throws Exception + */ + public function loadRequest($options = []) + { + /** @var Versand $oVersand */ + $oVersand = $this->getLieferschein()->oVersand_arr[0]; + if ($oVersand->getIdentCode() && $oVersand->getLogistik()) { + $tracking = [ + 'carrier' => utf8_encode($oVersand->getLogistik()), + 'code' => utf8_encode($oVersand->getIdentCode()), + ]; + if ($oVersand->getLogistikVarUrl()) { + $tracking['url'] = utf8_encode($oVersand->getLogistikURL()); + } + $this->tracking = $tracking; + } + + // TODO: Wenn alle Lieferschiene in der WAWI erstellt wurden, aber nicht im Shop, kommt status 4. + if ($this->isGuest || (int)$this->getCheckout()->getBestellung()->cStatus === BESTELLUNG_STATUS_VERSANDT) { + $this->lines = []; + } else { + $this->lines = $this->getOrderLines(); + } + return $this; + } + + /** + * @return array + * @throws Exception + */ + protected function getOrderLines() + { + $lines = []; + + if (!count($this->getLieferschein()->oLieferscheinPos_arr)) { + return $lines; + } + + // Bei Stücklisten, sonst gibt es mehrere OrderLines für die selbe ID + $shippedOrderLines = []; + + /** @var Lieferscheinpos $oLieferscheinPos */ + foreach ($this->getLieferschein()->oLieferscheinPos_arr as $oLieferscheinPos) { + + $wkpos = Shop::DB()->executeQueryPrepared('SELECT * FROM twarenkorbpos WHERE kBestellpos = :kBestellpos', [ + ':kBestellpos' => $oLieferscheinPos->getBestellPos() + ], 1); + + /** @var OrderLine $orderLine */ + foreach ($this->getCheckout()->getMollie()->lines as $orderLine) { + + if ($orderLine->sku === $wkpos->cArtNr && !in_array($orderLine->id, $shippedOrderLines, true)) { + + if ($quantity = min($oLieferscheinPos->getAnzahl(), $orderLine->shippableQuantity)) { + $lines[] = [ + 'id' => $orderLine->id, + 'quantity' => $quantity + ]; + } + $shippedOrderLines[] = $orderLine->id; + break; + } + } + } + return $lines; + } + + /** + * @return bool + * @throws Exception + */ + public function saveModel() + { + return $this->getModel()->save(); + } +} \ No newline at end of file diff --git a/version/204/class/Traits/Jsonable.php b/version/204/class/Traits/Jsonable.php new file mode 100644 index 0000000..afc0988 --- /dev/null +++ b/version/204/class/Traits/Jsonable.php @@ -0,0 +1,20 @@ +jsonSerialize(); + } + + public function jsonSerialize() + { + return array_filter(get_object_vars($this), static function ($value) { + return !($value === null || (is_string($value) && $value === '')); + }); + } +} \ No newline at end of file diff --git a/version/204/class/Traits/Plugin.php b/version/204/class/Traits/Plugin.php new file mode 100644 index 0000000..5b2c3a3 --- /dev/null +++ b/version/204/class/Traits/Plugin.php @@ -0,0 +1,25 @@ +requestData; + } + + public function __get($name) + { + if (!$this->requestData) { + $this->loadRequest(); + } + return is_string($this->requestData[$name]) ? utf8_decode($this->requestData[$name]) : $this->requestData[$name]; + } + + public function __set($name, $value) + { + if (!$this->requestData) { + $this->requestData = []; + } + + $this->requestData[$name] = is_string($value) ? utf8_encode($value) : $value; + + return $this; + } + + /** + * @param array $options + * @return $this + */ + public function loadRequest(&$options = []) + { + return $this; + } + + + public function __serialize() + { + return $this->requestData ?: []; + } + + public function __isset($name) + { + return $this->requestData[$name] !== null; + } + +} \ No newline at end of file diff --git a/version/204/frontend/.htaccess b/version/204/frontend/.htaccess new file mode 100644 index 0000000..df6c074 --- /dev/null +++ b/version/204/frontend/.htaccess @@ -0,0 +1,9 @@ + + + Require all granted + + + Order Allow,Deny + Allow from all + + diff --git a/version/204/frontend/131_globalinclude.php b/version/204/frontend/131_globalinclude.php new file mode 100644 index 0000000..2861d31 --- /dev/null +++ b/version/204/frontend/131_globalinclude.php @@ -0,0 +1,60 @@ +select('tzahlungsession', 'cZahlungsID', $sessionHash); + if ($paymentSession && $paymentSession->kBestellung) { + $oBestellung = new Bestellung($paymentSession->kBestellung); + + if (Shopsetting::getInstance()->getValue('kaufabwicklung', 'bestellabschluss_abschlussseite') === 'A') { + $oZahlungsID = Shop::DB()->query(" + SELECT cId + FROM tbestellid + WHERE kBestellung = " . (int)$paymentSession->kBestellung, 1 + ); + if (is_object($oZahlungsID)) { + header('Location: ' . Shop::getURL() . '/bestellabschluss.php?i=' . $oZahlungsID->cId); + exit(); + } + } + $bestellstatus = Shop::DB()->select('tbestellstatus', 'kBestellung', (int)$paymentSession->kBestellung); + header('Location: ' . Shop::getURL() . '/status.php?uid=' . $bestellstatus->cUID); + exit(); + } + } + + ifndef('MOLLIE_REMINDER_PROP', 10); + if (mt_rand(1, MOLLIE_REMINDER_PROP) % MOLLIE_REMINDER_PROP === 0) { + $lock = new \ws_mollie\ExclusiveLock('mollie_reminder', PFAD_ROOT . PFAD_COMPILEDIR); + if ($lock->lock()) { + // TODO: Doku! + + AbstractCheckout::sendReminders(); + Queue::storno((int)Helper::getSetting('autoStorno')); + + $lock->unlock(); + } + } + + +} catch (Exception $e) { + Helper::logExc($e); +} + + diff --git a/version/204/frontend/132_headPostGet.php b/version/204/frontend/132_headPostGet.php new file mode 100644 index 0000000..94afd33 --- /dev/null +++ b/version/204/frontend/132_headPostGet.php @@ -0,0 +1,17 @@ +append( + << + /* MOLLIE CHECKOUT STYLES*/ + #fieldset-payment .form-group > div:hover, #checkout-shipping-payment .form-group > div:hover { + background-color: #eee; + color: black; + } + $selector label { + $border + } + + $selector label::after { + clear: both; + content: ' '; + display: block; + } + + $selector label span small { + line-height: 48px; + } + + $selector label img { + float: right; + } + +HTML + ); + +} catch (Exception $e) { + Helper::logExc($e); +} diff --git a/version/204/frontend/180_checkbox.php b/version/204/frontend/180_checkbox.php new file mode 100644 index 0000000..95a070f --- /dev/null +++ b/version/204/frontend/180_checkbox.php @@ -0,0 +1,18 @@ +oPluginEinstellungAssoc_arr['useCustomerAPI'] === 'C') { + \ws_mollie\Hook\Checkbox::execute($args_arr); + } + +} catch (Exception $e) { + Helper::logExc($e); +} \ No newline at end of file diff --git a/version/204/frontend/181_sync.php b/version/204/frontend/181_sync.php new file mode 100644 index 0000000..22022a9 --- /dev/null +++ b/version/204/frontend/181_sync.php @@ -0,0 +1,14 @@ +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 Rmns)TMnX}%M${5 literal 0 HcmV?d00001 diff --git a/version/204/frontend/img/trust_fre.png b/version/204/frontend/img/trust_fre.png new file mode 100644 index 0000000000000000000000000000000000000000..ed1a2f6f03c56f6748aac8af0352de7fc0afd3a4 GIT binary patch literal 17319 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 Mu#8ZJpsxS_1AJc%;s5{u literal 0 HcmV?d00001 diff --git a/version/204/frontend/img/trust_ger.png b/version/204/frontend/img/trust_ger.png new file mode 100644 index 0000000000000000000000000000000000000000..e42821b06709e8f4371c66cfb5759d00df0e1afd GIT binary patch literal 15352 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 + diff --git a/version/204/paymentmethod/JTLMollie.php b/version/204/paymentmethod/JTLMollie.php new file mode 100644 index 0000000..27bfaea --- /dev/null +++ b/version/204/paymentmethod/JTLMollie.php @@ -0,0 +1,268 @@ +cModulId = "kPlugin_" . self::Plugin()->kPlugin . "_mollie" . $moduleID; + } + + /** + * @param Bestellung $order + * @return PaymentMethod + */ + public function setOrderStatusToPaid($order) + { + // If paid already, do nothing + if ((int)$order->cStatus >= BESTELLUNG_STATUS_BEZAHLT) { + return $this; + } + return parent::setOrderStatusToPaid($order); + } + + /** + * Prepares everything so that the Customer can start the Payment Process. + * Tells Template Engine. + * + * @param Bestellung $order + * @return void + */ + public function preparePaymentProcess($order) + { + + parent::preparePaymentProcess($order); + + try { + + if ($this->duringCheckout && !static::ALLOW_PAYMENT_BEFORE_ORDER) { + $this->Log(sprintf("Zahlung vor Bestellabschluss nicht unterstützt (%s)!", $order->cBestellNr), sprintf("#%s", $order->kBestellung), LOGLEVEL_ERROR); + return; + } + + $payable = (float)$order->fGesamtsumme > 0; + if (!$payable) { + $this->Log(sprintf("Bestellung '%s': Gesamtsumme %.2f, keine Zahlung notwendig!", $order->cBestellNr, $order->fGesamtsumme), sprintf("#%s", $order->kBestellung)); + return; + } + + $paymentOptions = []; + + $api = array_key_exists($this->moduleID . '_api', self::Plugin()->oPluginEinstellungAssoc_arr) ? self::Plugin()->oPluginEinstellungAssoc_arr[$this->moduleID . '_api'] : 'order'; + + $paymentOptions = array_merge($paymentOptions, $this->getPaymentOptions($order, $api)); + + if ($api === 'payment') { + $checkout = new PaymentCheckout($order); + $payment = $checkout->create($paymentOptions); + /** @noinspection NullPointerExceptionInspection */ + $url = $payment->getCheckoutUrl(); + } else { + $checkout = new OrderCheckout($order); + $mOrder = $checkout->create($paymentOptions); + /** @noinspection NullPointerExceptionInspection */ + $url = $mOrder->getCheckoutUrl(); + } + + ifndef('MOLLIE_REDIRECT_DELAY', 3); + $checkoutMode = self::Plugin()->oPluginEinstellungAssoc_arr['checkoutMode']; + Shop::Smarty()->assign('redirect', $url) + ->assign('checkoutMode', $checkoutMode); + if ($checkoutMode === 'Y' && !headers_sent()) { + header('Location: ' . $url); + } + } catch (Exception $e) { + $this->Log('mollie::preparePaymentProcess: ' . $e->getMessage() . ' - ' . print_r(['cBestellNr' => $order->cBestellNr], 1), '#' . $order->kBestellung, LOGLEVEL_ERROR); + Shop::Smarty()->assign('oMollieException', $e) + ->assign('tryAgain', Shop::getURL() . '/bestellab_again.php?kBestellung=' . $order->kBestellung); + } + } + + public function Log($msg, $data = null, $level = LOGLEVEL_NOTICE) + { + ZahlungsLog::add($this->moduleID, "[" . microtime(true) . " - " . $_SERVER['PHP_SELF'] . "] " . $msg, $data, $level); + return $this; + } + + public function getPaymentOptions(Bestellung $order, $apiType) + { + return []; + } + + /** + * @param Bestellung $order + * @param string $hash + * @param array $args + */ + public function handleNotification($order, $hash, $args) + { + parent::handleNotification($order, $hash, $args); + try { + $orderId = $args['id']; + $checkout = null; + if (strpos($orderId, 'tr_') === 0) { + $checkout = new PaymentCheckout($order); + } else { + $checkout = new OrderCheckout($order); + } + $checkout->handleNotification($hash); + + } catch (Exception $e) { + $checkout->Log(sprintf("mollie::handleNotification: Fehler bei Bestellung '%s': %s\n%s", $order->cBestellNr, $e->getMessage(), print_r($args, 1)), LOGLEVEL_ERROR); + } + } + + /** + * @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 (API::getMode()) { + $selectable = trim(self::Plugin()->oPluginEinstellungAssoc_arr['test_api_key']) !== ''; + } else { + $selectable = trim(self::Plugin()->oPluginEinstellungAssoc_arr['api_key']) !== ''; + if (!$selectable) { + Jtllog::writeLog("Live API Key missing!"); + } + } + if ($selectable) { + try { + $locale = AbstractCheckout::getLocale($_SESSION['cISOSprache'], Session::getInstance()->Customer()->cLand); + $amount = Session::getInstance()->Basket()->gibGesamtsummeWarenExt([ + C_WARENKORBPOS_TYP_ARTIKEL, + C_WARENKORBPOS_TYP_KUPON, + C_WARENKORBPOS_TYP_GUTSCHEIN, + C_WARENKORBPOS_TYP_NEUKUNDENKUPON, + ], true) * Session::getInstance()->Currency()->fFaktor; + if ($amount <= 0) { + $amount = 0.01; + } + $selectable = self::isMethodPossible( + static::METHOD, + $locale, + Session::getInstance()->Customer()->cLand, + Session::getInstance()->Currency()->cISO, + $amount + ); + } catch (Exception $e) { + Helper::logExc($e); + $selectable = false; + } + } + return $selectable && parent::isSelectable(); + } + + /** + * @param $method + * @param $locale + * @param $billingCountry + * @param $currency + * @param $amount + * @return bool + * @throws ApiException + */ + protected static function isMethodPossible($method, $locale, $billingCountry, $currency, $amount) + { + + $api = new API(API::getMode()); + + if (!array_key_exists('mollie_possibleMethods', $_SESSION)) { + $_SESSION['mollie_possibleMethods'] = []; + } + + $key = md5(serialize([$locale, $billingCountry, $currency, $amount])); + if (!array_key_exists($key, $_SESSION['mollie_possibleMethods'])) { + $active = $api->Client()->methods->allActive([ + 'locale' => $locale, + 'amount' => [ + 'currency' => $currency, + 'value' => number_format($amount, 2, ".", "") + ], + 'billingCountry' => $billingCountry, + 'resource' => 'orders', + 'includeWallets' => 'applepay', + ]); + foreach ($active as $a) { + $_SESSION['mollie_possibleMethods'][$key][] = (object)['id' => $a->id]; + } + } + + if ($method !== '') { + foreach ($_SESSION['mollie_possibleMethods'][$key] as $m) { + if ($m->id === $method) { + return true; + } + } + } else { + return true; + } + + return false; + + } + + /** + * @param array $args_arr + * @return bool + */ + public function isValidIntern($args_arr = []) + { + return $this->duringCheckout + ? static::ALLOW_PAYMENT_BEFORE_ORDER && parent::isValidIntern($args_arr) + : parent::isValidIntern($args_arr); + } + + /** + * @return int + */ + public function getExpiryDays() + { + return (int)min(abs((int)Helper::oPlugin()->oPluginEinstellungAssoc_arr[$this->cModulId . '_dueDays']), static::MAX_EXPIRY_DAYS) ?: static::MAX_EXPIRY_DAYS; + } + +} diff --git a/version/204/paymentmethod/JTLMollieApplePay.php b/version/204/paymentmethod/JTLMollieApplePay.php new file mode 100644 index 0000000..4b23bf4 --- /dev/null +++ b/version/204/paymentmethod/JTLMollieApplePay.php @@ -0,0 +1,15 @@ +oRechnungsadresse->cMail; + $paymentOptions['locale'] = AbstractCheckout::getLocale($_SESSION['cISOSprache'], $order->oRechnungsadresse->cLand); + } + + $dueDays = $this->getExpiryDays(); + if ($dueDays > 3) { + $paymentOptions['dueDate'] = date('Y-m-d', strtotime("+$dueDays DAYS")); + } + return $paymentOptions; + } +} diff --git a/version/204/paymentmethod/JTLMollieBelfius.php b/version/204/paymentmethod/JTLMollieBelfius.php new file mode 100644 index 0000000..00c8e7c --- /dev/null +++ b/version/204/paymentmethod/JTLMollieBelfius.php @@ -0,0 +1,13 @@ +clearToken(); + } + + protected function clearToken() + { + $this->unsetCache(self::CACHE_TOKEN) + ->unsetCache(self::CACHE_TOKEN_TIMESTAMP); + return true; + } + + public function handleAdditional($aPost_arr) + { + + $components = self::Plugin()->oPluginEinstellungAssoc_arr[$this->moduleID . '_components']; + $profileId = self::Plugin()->oPluginEinstellungAssoc_arr['profileId']; + + if ($components === 'N' || !$profileId || trim($profileId) === '') { + return parent::handleAdditional($aPost_arr); + } + + $cleared = false; + if (array_key_exists('clear', $aPost_arr) && (int)$aPost_arr['clear']) { + $cleared = $this->clearToken(); + } + + if ($components === 'S' && array_key_exists('skip', $aPost_arr) && (int)$aPost_arr['skip']) { + return parent::handleAdditional($aPost_arr); + } + + try { + $trustBadge = (bool)self::Plugin()->oPluginEinstellungAssoc_arr[$this->moduleID . '_loadTrust']; + $locale = AbstractCheckout::getLocale($_SESSION['cISOSprache'], Session::getInstance()->Customer() ? Session::getInstance()->Customer()->cLand : null); + $mode = API::getMode(); + $errorMessage = json_encode(self::Plugin()->oPluginSprachvariableAssoc_arr['mcErrorMessage']); + } catch (Exception $e) { + Jtllog::writeLog($e->getMessage() . "\n" . print_r(['e' => $e], 1)); + return parent::handleAdditional($aPost_arr); + } + + if (!$cleared && array_key_exists('cardToken', $aPost_arr) && ($token = trim($aPost_arr['cardToken']))) { + return $this->setToken($token) && parent::handleAdditional($aPost_arr); + } + + $token = false; + if (($ctTS = (int)$this->getCache(self::CACHE_TOKEN_TIMESTAMP)) && $ctTS > time()) { + $token = $this->getCache(self::CACHE_TOKEN); + } + + Shop::Smarty()->assign('profileId', $profileId) + ->assign('trustBadge', $trustBadge ? self::Plugin()->cFrontendPfadURLSSL . 'img/trust_' . $_SESSION['cISOSprache'] . '.png' : false) + ->assign('components', $components) + ->assign('locale', $locale ?: 'de_DE') + ->assign('token', $token ?: false) + ->assign('testMode', $mode ?: false) + ->assign('errorMessage', $errorMessage ?: null) + ->assign('mollieLang', self::Plugin()->oPluginSprachvariableAssoc_arr); + + return false; + } + + protected function setToken($token) + { + $this->addCache(self::CACHE_TOKEN, $token) + ->addCache(self::CACHE_TOKEN_TIMESTAMP, time() + 3600); + return true; + } + + public function getPaymentOptions(Bestellung $order, $apiType) + { + + $paymentOptions = []; + + if ($apiType === 'payment') { + if ($order->Lieferadresse !== null) { + if (!$order->Lieferadresse->cMail) { + $order->Lieferadresse->cMail = $order->oRechnungsadresse->cMail; + } + $paymentOptions['shippingAddress'] = Address::factory($order->Lieferadresse); + } + + $paymentOptions['billingAddress'] = Address::factory($order->oRechnungsadresse); + } + if ((int)$this->getCache(self::CACHE_TOKEN_TIMESTAMP) > time() && ($token = trim($this->getCache(self::CACHE_TOKEN)))) { + $paymentOptions['cardToken'] = $token; + } + return $paymentOptions; + } + +} diff --git a/version/204/paymentmethod/JTLMollieDirectDebit.php b/version/204/paymentmethod/JTLMollieDirectDebit.php new file mode 100644 index 0000000..7318e8a --- /dev/null +++ b/version/204/paymentmethod/JTLMollieDirectDebit.php @@ -0,0 +1,27 @@ + substr($order->cBestellNr, 0, 13)]; + } +} diff --git a/version/204/paymentmethod/JTLMollieKlarnaPayLater.php b/version/204/paymentmethod/JTLMollieKlarnaPayLater.php new file mode 100644 index 0000000..cb1438d --- /dev/null +++ b/version/204/paymentmethod/JTLMollieKlarnaPayLater.php @@ -0,0 +1,14 @@ +Lieferadresse !== null) { + if (!$order->Lieferadresse->cMail) { + $order->Lieferadresse->cMail = $order->oRechnungsadresse->cMail; + } + $paymentOptions['shippingAddress'] = Address::factory($order->Lieferadresse); + } + $paymentOptions['description'] = 'Order ' . $order->cBestellNr; + } + + + return $paymentOptions; + } + +} diff --git a/version/204/paymentmethod/JTLMolliePaysafecard.php b/version/204/paymentmethod/JTLMolliePaysafecard.php new file mode 100644 index 0000000..272b799 --- /dev/null +++ b/version/204/paymentmethod/JTLMolliePaysafecard.php @@ -0,0 +1,15 @@ + $order->oKunde->kKunde] : []; + } +} diff --git a/version/204/paymentmethod/JTLMolliePrzelewy24.php b/version/204/paymentmethod/JTLMolliePrzelewy24.php new file mode 100644 index 0000000..355ecdf --- /dev/null +++ b/version/204/paymentmethod/JTLMolliePrzelewy24.php @@ -0,0 +1,18 @@ + $order->oRechnungsadresse->cMail] : []; + } + +} diff --git a/version/204/paymentmethod/JTLMollieSofort.php b/version/204/paymentmethod/JTLMollieSofort.php new file mode 100644 index 0000000..0a4d191 --- /dev/null +++ b/version/204/paymentmethod/JTLMollieSofort.php @@ -0,0 +1,13 @@ +OH(NI>=T42<+x9g>;*Gy9DrKtJl=F((p(~XhRMojR(!TROq)4##x zi;wfn&C+>%^UTiFKSt7JYSXp1>ZPgDP*&5InbUcF<%^K^*xKlsoYHP{(wCajZ*$Ra zbJNPo(OY2BWNFmE!S~qO{POeCTVT|{z|(GX;Bt54e}mdsUi8b(sL>`X0000JbW%=J z01%HLkU-Cn-_OsV&!6AlpP5D4UE1#Sax&aZg(%L>z8x33MOZZ8H?WJ;;n51dMe)(}9UH1j29 ze@0RGfq`^s0!X#X7!_srsUP@btltZoyHfrIVq@*+2f)Ge+&BuBcbdrjKu5}NuE;){Yi3#o7gOK=v6Y0{rAbqNgQSz}}0I~5?ej{GsP%?vN z=_l4!?VPOmM>R@!2oOAkd1t|Pb#@H>-d=$PnbBs7=u%Z>9N;0iml z2#guk2rk-V%mMEvxQCZ1@+-_*(mao=fPWKs%h@Mp0)~gcfgO7j{4M(n<{@x^Z^Hk! ze1;0X32xx)(NPC3aetZbtnBss>W2NT-v%Bch%He^5RXIyLDWRp5;o{lcPr>qmkRZj lpHDtfd;A2~X0zTP_aA;i{an>LN7rz#m}I!{TEUogY_hW!fX z1?mg>C*-erx%(so1LG!77srr_xVP7C<}EQ0XbW_HZ(Bb#ysRpA(wRN~nf+#OlTe%( zXkfncL^KKCCrg-Lh=kEnU|a;ZB9QaR>Td+?i96wEUURmd^*;_;}q*?JtCN zs9v0_oUIYrJ>{ItUF)Suj=nY*E;y-_bg}zQ;ZT|@FU4Qeut^B)WfWUjV9g-3v@K+f-ik;kV{MOr_6wK;GGik>mTp$V%-RtP)+CPEi`n!UgTe~DWM4fFWeR( literal 0 HcmV?d00001 diff --git a/version/204/paymentmethod/img/method/bancontact@2x.png b/version/204/paymentmethod/img/method/bancontact@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..a87af77d20330ab4ee197fd750d0bd39a5b10f90 GIT binary patch literal 582 zcmV-M0=fN(P)lk!lq%lq?@9+Qr z|M>X$=jZ1jWQqR%{`vX&|JVTk=U{-T&j0$~pTFAg&hoWPVjpU$|LlN(mQMfcfPbmZpr$+j>2Uw#P;ZV{AZe)(UZem0@6X@u|MkEB z;XwWU{r~1*Ky`MXzS=N!uW*i8kF?YfT$A7F^MIC5pQk%!Gip%)000nlQchC<&w%eB zkRX4bpb&7+Z;x=Vl85vF00AONL_t(|UhS6GZp0uI1+V+IBnNQY-qL&T?f<_j%Vs4k zWi4ZPi#+c$LIR;fk}z^m8)w(24LdL-qBSjmiImqQ6%1%eKSC_H5hBJOQ3wcbh=A9j z0E`>M;F1Gj9uRN{NX-L}@Ce`*0RKJE1nw{TTbXGF`gs|rT7l!dln0%_EVm0RbGyKB zqJ*zRaiSTxE%@_=;_x?lSs8dz{y6#LPln}z>8GT40dLB`KB#<1qlM(E;D0OsM*0?TeIhg`dn6;Q{6Fh2l%qOS4K%wo8-q7AUD{?yGF(55vm4C&H_FzBH+J=d4+57}kr Up-!czfB*mh07*qoM6N<$g3OCHTL1t6 literal 0 HcmV?d00001 diff --git a/version/204/paymentmethod/img/method/banktransfer@2x.png b/version/204/paymentmethod/img/method/banktransfer@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..c70206bef4893f23fcd59d436273108d2f2eebc7 GIT binary patch literal 801 zcmV++1K#|JP)lk!lq*=;-9+mkX z{{U2_ztrjP@9%)A(*D5?-|6)J(MtZwET6yKpugSt`1lZBsz86cAZf7q`T3Bv*Z%(g z-|F=K#U1|5JO0^dAZoDx_u=pL`RC{7_xJZ;l*j-3@c!I)@AdkSwAlXDS^mf@aG%W2 z;O`J$tN-Md>+9=KiNUYR<6xA=@AUcq@WXGP%>DiS|LnB>%sc+*q+gWBFm$#4l$oJ=bMJL) zN$}UM z^EEI7D0q#*=`w@Mb&#yX6$WP@x&}s<8JvJ@pvqecQO^sez9^Xbs$t>(|Nn0Y_`k@X z`u+Uv`wm6F?mz#2{?4!aFGTBV&I9cbE(!7rW)PTg{{H;_^9ubA3J&Kd+&@2If#l5V zkwEFKo-U3d6>)E`o#Z>Lz~g$+{n^fDUKQE@|Mgd!a9=T#&e{4(sr-HO1o4KQ>uv;= zWX2_)yrQzk;QY@iN0x35n7oK-g-2+63_H(@QU|u6Z>|Z!r6lZ1zes9a?+x$E9%YhzX@O1Ta JS?83{1OT9Jm%RW0 literal 0 HcmV?d00001 diff --git a/version/204/paymentmethod/img/method/creditcard@2x.png b/version/204/paymentmethod/img/method/creditcard@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..b08be792753326b65345c752a6f350182a9393d2 GIT binary patch literal 3125 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 P00000NkvXXu0mjf3Vis# literal 0 HcmV?d00001 diff --git a/version/204/paymentmethod/img/method/directdebit@2x.png b/version/204/paymentmethod/img/method/directdebit@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..514ff845b84d38cd8eb97b9e2c53e5c117967944 GIT binary patch literal 801 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 literal 0 HcmV?d00001 diff --git a/version/204/paymentmethod/img/method/giropay@2x.png b/version/204/paymentmethod/img/method/giropay@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..b787e1fee50c9bcca112f734ef4bcbd4ecfb6d6b GIT binary patch literal 602 zcmV-g0;T5Kx~EOrH!)pASu;4ojd8OQ8=; zpbt!;!_w#B>GK{}r)iJG@bvggdAR@o{+6-TrM%mCn#w$GvMpk*ho#Tb-RaC5+y)hho537JnGBqPA~G@Ik#rt1jWCNmt_X5yY-;OM4Sm|;L0fCz(H!a59C z!6FQJ1`O=K0(U?&WmHmQ%ovl1g=xY%=0>sX7T{!DDr3#1AfT>{>*NQdp;XxeDnn^6 z;Fg|~18)oh=#B%J574HG=ZK=b0(2)=ZWs@6u|Psp2S`Ms-aSCKNc4dZ3ml0Y1JpF0 zACT7(WFOdH$J={=+}Kh?t@=QTh`Y)S;{lL4q2$K&0aK;&(@GqDK&DI^R~^tLy#OA$ z1Nay30gQkc{Q&0jzz(SpmbnlhVhfzVhaBhB0($}wh1S_^$N7}lg}e4p3Ic|F4;Z~b zTY@72isxg1#8BrSfnxv^S{6kiGl4E$H2v|f@*S9m0aJJk172Vm21F3Hg)IO)g#GGT oVe}rh6KIQG--ZM8)e@S10aM=ZI#^TblmGw#07*qoM6N<$f@FIOx&QzG literal 0 HcmV?d00001 diff --git a/version/204/paymentmethod/img/method/ideal@2x.png b/version/204/paymentmethod/img/method/ideal@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..efc4315a96a6b2d9b160578a65fe52206783f2ca GIT binary patch literal 845 zcmV-T1G4;yP)lk!ZZ65OMGC?}UYf;o;!m;NZf-!qXsn`1tsvqob6RlsGvz=jZ45_xJw({`vX& z+CYuwfU@xL?-Nv%`QPmApT=fqW&i*F(b3WK zzuD%1v(zAZ>+9>Xv$F87&$F|$@bK^%8W`-K#nT^p^1s=^!okAA!Tj&_DJdxZ{r%~X zz3Gp=&=7F!pvK@}pYN~F>5#mWl#|_1mb0_6g@uIHFobn>b?J}1M@UB*8yIC~W#VwE zc6N2$P?z9fpjKB^=ker~0000HbW%=J0PlbhkiUP=Adhe$&v1`#zea&7rvLx}*GWV{ zRCr#^*2j+9Fc5%YO7?ntl9{1;aqqou@0;Fxd;j;y*jNN`HV2Bl>~|3_{4oLqkzy%V z*t96C%}2Z9&SQ)86vWClksDVqqe|=&Z3|YQQjA*4CE6Eai>Qp6VzP3=CKt6Gk}WnU zMr|=|2#YGH?I~G;2n`TD#K5)puk^^z67b+ZZd-naz)7$!d_QRdc|mw#b1~<{2k2)FEaYF&OT-`GX$RPM#Nt`QAi#wXJk>zhFTO>59`Wo^#}<>sMjOed(+{-3ru0A7D$0jI558$ z)N0PF!RsCe2|{A+{jU4@5&uc>v9T(>X>= zpc$wJPDAG6XudKWan^4w_bUdHVBPG<>jQiVOn&QMzg?RgEbW=`(e{u7#up5;D^8W3 z2%8R3n@hIHS^6WCiFSq9p;8&OR7*Sn%M-cP>{s2YOOzKYHtDf;#GS4DUiRI4c22NA XzpeJ7+7%dW00000NkvXXu0mjfybi$$ literal 0 HcmV?d00001 diff --git a/version/204/paymentmethod/img/method/inghomepay@2x.png b/version/204/paymentmethod/img/method/inghomepay@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..538f219588886db215757eafd5c5151241f18b5a GIT binary patch literal 1118 zcmV-k1flzhP)`_0RK|}|55<|Q2_r?0RL0~|5E_}r-1)w9RKX&|5E_}=Gy;L z0RR90|6UOPlVJbp-~WC<|J1+#zn}l9fd6P9|A|olb1?tk&;RxB|Mc(wo^bzkF#pQ0 z|Fn<)>fisgkpF2Q|G%LBsek{okpG@<|H-fazM%hUAODC@|H-ibs(=5~!2gtB|K894 zs(@(VAMyYI01|XkPE!C7&ySx#AdugXK#$)bkdUC?LT6GX000A7Nkl+_F4;G0`t->#NE zT;V&r`f!+EySiCj<6V7Pt?{mYTH&4jj{)gM0TN(F3?6st+kjw6 z>LApXPB>Unt8V~;Cik9f49AhQ!$i7^fuL#4vW=&{86JR|lTsG~BRymzfEs|JX9J1K z03Dw$1C&G3WKK=%kB`J1r1*<~s2`z=k6T78&3xGOL&RV&0xXfJ0Ql@xfEn*A1CX9E zQ!WBD5?VbTK7XTsCp`U6crw}TsH%60W z2hoh@0nLYSxRBab{+9<3C+^Mz9xYb&ZxhMVDb+cqriY2<9AG-<8gN)^Cix5?)@kAU z;?6$;-SN`NKvD-cR@w%n?9AWi0I~xRElDnK5^Rh@FtDVHX8@ZJfJl->N&_A{l2bso z2x`kJr-3lmJ%9)DK@>~Q{7brt3fNKr^rbrq+|{-iAekxBG;uoyGqur4Ei0S?0=Yll zF_SR>W}x;7ttLalDFCI-OXsp?(S;*|rkk|uOcTs~fUR;0m?79z>!T@dSC<#zVpen3 zDj@L*GoMZY$tw7C*m%o|vLvel!qz~FMPzph=x6{KTjppdC7aC#VVdHg)$wl$bf*AC z1-Rnnz*LgVO4|B5HX#U@PXUn*;sq_sC5u*2fG7j7o&o~>%Wn3WWcg~#QmPptG|8+k2H7XW|=xVi9nUeg`1*I2IB*YJ(+JNL|VD24JQDXa_~} zqMBf8fF~Vbz5wvk*3xb81`yK5AZAEW$9)?Qt+BO>C3E@1Aktu4fz|6HW^Y;1@lk!lq%mkX z{~%3y0h-K!%;mq#+4%VQ5J7OCv&KMYjPLUG@9*#T_xE6cpCPBxaK_?)nX{kS?7!yn zfSI!2=Is9d{_pwx05oR#`T5`T`RC{7L9^Llzu!=FmQcCekkjew>+3LDf{>=XK(pDe zzt4c0vd`J#Fs;_V%-D~nykNlKAg9yc^7t^U)_~3BfX(J`#^Vv8&k>-{-}3p8(&?|? z?{JN&{r&x)v&FFA?=V_}aEz&7z~7M5=+D{X&+PS}+3awQs351(ptHqzpNxV4000qm zQchCIy&+X> z=*5Ul;OaQ@NK`Vzy8t_g2?_Jis)3C$i910Xw$PIU9&Uk!LpkskEkL9-LfkOWJAbaP zUroip18r(eg}^hN*BXg{sb1!Yfc6S#iGXvxN(6jb7x=sau0_D;#S-`?0_b=FJSG`H zPqbnfvWg$g}i**@5@#v5NT=$lzqSQdXDg|8f zIHlhJQN%Mfm~#2YP9b1YgB(!GAN!r?CIjA)sTANZfG||7{JhG5H)Vm3e?0>E>_vVi zq!;d4SOSQYxt#%m;F70Lx8o{r!Tt9&c8CI14(M}40nf9jzsNQAmkVA7gAM$Z|1+@m z0b{)*&IIp+jVE#-MjL9Dd6xv65#{P&<3u77*DDnbtf@m157r`vbG^_r?Ff8 d>Rr1A+%FMH_Q$8Zwr>Cc002ovPDHLkV1oT`waEYg literal 0 HcmV?d00001 diff --git a/version/204/paymentmethod/img/method/klarna@2x.png b/version/204/paymentmethod/img/method/klarna@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..e28a187b81e7c5a6256fea7382a643762746dd1e GIT binary patch literal 896 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 literal 0 HcmV?d00001 diff --git a/version/204/paymentmethod/img/method/paypal@2x.png b/version/204/paymentmethod/img/method/paypal@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..a816d7201f59ea7cef713f5e7895e66dcd6ee9a7 GIT binary patch literal 626 zcmV-&0*(ENP)zW{Q;0CK+oaK8X?zW{Q<0CB+pa=`#_!2of;na1S+alrro z|IFg@&*bxRu-m`e?~lRb-|hDbcETox$#AdRv()Q`yWm5X&|s$5P@dDD$>-eb_JFwG zpUUS$m(j@K@sPpeFpSLa_WMAU&p?#W{Qdsu^7&w=*MGR*^7#DO>Gd#+%P@?~P@U7S z((9ba=CIQ0sn6-_^!k0a-V=Mp)8_OXfyX(K&a%|&;_mkldc-e_%lZ5LgSp`#gUC6M z&erGk#LeN$0000GbW%=J0M8)rfN+qXfDoX6Z;yYFN6jxl0003wNklC4+MXiktqCYwRgSg6)KJbf z5Lj1?Y5+oU@|#dstX9C|0Ujt`J{M4b8Wr^cdi(ak0iFt>ORE}Nts8qh=FWCkI)}aEnE&{1?2hI?PIY68@ zbOdbw0PvXrf5i!Szy>sZ79ap>ye%)UHj^sMYbqagD6U zaJzaI>n$ypF23oVdS#o6|W|*DFT6j;X_Pjl^+{$7FxcM`F8{J!B6QqfZ6J=?T z0Z*i4z#}$g7~II(N7`*?T& O0000+D{~L?`zkmGy`PKgqj{m>0 z^Z&xI|35zdzp(26fxiDA9{<0v`v1;`{~L<_uT1&>;_Ck$4fn+3S%6jwlmz(&Gn{vr zARutRf5Q2Gh4~8e7rbanOaaP$^>lFzsfc?!?c};<10L727Z_ycPF(r9`v3o4QC^`f zNy*irThr_Lx8*f4F=sBE;Is9vL&{b+wWF_Q`cLpRlDMX^fZ@i14v}pdO3hrZ8V-u{ z6@GBmNPp@1=O;WPYJWl57EYgv)6tK(j<>!KX1Tkg-1yN7-6M=yr*jX!QWr1lo!e&; zepvX8JR>o1saCg`3ZOWgj;^L2z+zGho&3IENy|Lc5*g&izjA{*O9T;DjDIk7S9e6n)( p;e>?q6P^m(l+{vMe5&Mx9fO|m{vZE%WkG?%;OXk;vd$@?2>_eS)Oi2^ literal 0 HcmV?d00001 diff --git a/version/204/paymentmethod/tpl/bestellabschluss.tpl b/version/204/paymentmethod/tpl/bestellabschluss.tpl new file mode 100644 index 0000000..b26d8ef --- /dev/null +++ b/version/204/paymentmethod/tpl/bestellabschluss.tpl @@ -0,0 +1,26 @@ +{if isset($oMollieException)} +
+ {$oMollieException->getMessage()} +
+ +{/if} + +{if isset($redirect) && $redirect != ''} + + {if $checkoutMode == 'D'} + + {/if} +{/if} + diff --git a/version/204/paymentmethod/tpl/mollieComponents.tpl b/version/204/paymentmethod/tpl/mollieComponents.tpl new file mode 100644 index 0000000..8bcd452 --- /dev/null +++ b/version/204/paymentmethod/tpl/mollieComponents.tpl @@ -0,0 +1,147 @@ +

{$mollieLang.cctitle}

+ +
+ +
+ + {if $token !== false} + +
+
+ {$mollieLang.clearDescr} +
+
+ +
+
+ + {if $trustBadge} +
+ PCI-DSS SAQ-A compliant +
+ {/if} + + {else} + + +
+ +
+
+
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+ +
+
+ + +
+
+ + {if $trustBadge} +
+ PCI-DSS SAQ-A compliant +
+ {/if} + {if $components == 'S'} + + {/if} +
+ +{/if} + + + + + + \ No newline at end of file diff --git a/version/204/sql/204.sql b/version/204/sql/204.sql new file mode 100644 index 0000000..784d136 --- /dev/null +++ b/version/204/sql/204.sql @@ -0,0 +1,2 @@ +ALTER TABLE `xplugin_ws_mollie_shipments` + CHANGE `kLieferschien` `kLieferschein` INT(11) NOT NULL; \ No newline at end of file diff --git a/version/204/tpl/_alerts.tpl b/version/204/tpl/_alerts.tpl new file mode 100644 index 0000000..5279fa3 --- /dev/null +++ b/version/204/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} From b131df187e1762b491c428d846788aa957111646 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Tue, 8 Jun 2021 15:29:48 +0200 Subject: [PATCH 241/280] fix #140 --- info.xml | 66 +---- version/204/class/Mollie.php | 262 ------------------ .../paymentmethod/JTLMollieDirectDebit.php | 27 -- .../204/paymentmethod/JTLMollieINGHomePay.php | 28 -- 4 files changed, 13 insertions(+), 370 deletions(-) delete mode 100644 version/204/class/Mollie.php delete mode 100644 version/204/paymentmethod/JTLMollieDirectDebit.php delete mode 100644 version/204/paymentmethod/JTLMollieINGHomePay.php diff --git a/info.xml b/info.xml index e7bf955..df03e00 100644 --- a/info.xml +++ b/info.xml @@ -587,7 +587,7 @@ 1 mollie.com OTHER - 0 + 1 0 1 0 @@ -655,7 +655,7 @@ 1 mollie.com OTHER - 0 + 1 0 1 0 @@ -682,26 +682,6 @@ dueDays
- - Mollie DirectDebit - img/method/directdebit@2x.png - 7 - 1 - mollie.com - DIRECT_DEBIT - 0 - 0 - 1 - 0 - JTLMollieDirectDebit.php - JTLMollieDirectDebit - tpl/bestellabschluss.tpl - - SEPA Lastschrift - Mollie - Bezahlen Sie bequem mit SEPA Lastschrift. - - Mollie EPS img/method/eps@2x.png @@ -709,7 +689,7 @@ 1 mollie.com OTHER - 0 + 1 0 1 0 @@ -763,7 +743,7 @@ 1 mollie.com GIROPAY - 0 + 1 0 1 0 @@ -797,7 +777,7 @@ 1 mollie.com OTHER - 0 + 1 0 1 0 @@ -824,26 +804,6 @@ dueDays - - Mollie ING HomePay - img/method/inghomepay@2x.png - 11 - 1 - mollie.com - OTHER - 0 - 0 - 1 - 0 - JTLMollieINGHomePay.php - JTLMollieINGHomePay - tpl/bestellabschluss.tpl - - ING HomePay - Mollie - Bezahlen Sie bequem mit ING HomePay. - - Mollie KBC img/method/kbc@2x.png @@ -851,7 +811,7 @@ 1 mollie.com OTHER - 0 + 1 0 1 0 @@ -885,7 +845,7 @@ 1 mollie.com PAYPAL - 0 + 1 0 1 0 @@ -919,7 +879,7 @@ 1 mollie.com OTHER - 0 + 1 0 1 0 @@ -953,7 +913,7 @@ 1 mollie.com DIRECT_E_BANKING - 0 + 1 0 1 0 @@ -987,7 +947,7 @@ 1 mollie.com INVOICE - 0 + 1 0 1 0 @@ -1012,7 +972,7 @@ 1 mollie.com FINANCING - 0 + 1 0 1 0 @@ -1037,7 +997,7 @@ 1 mollie.com OTHER - 0 + 1 0 1 0 @@ -1071,7 +1031,7 @@ 1 mollie.com OTHER - 0 + 1 0 1 0 diff --git a/version/204/class/Mollie.php b/version/204/class/Mollie.php deleted file mode 100644 index 0381cdc..0000000 --- a/version/204/class/Mollie.php +++ /dev/null @@ -1,262 +0,0 @@ -kPlugin; - if ($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); - } - } - } - } - - 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[] = AbstractCheckout::getLocale($sS->cISO, $land); - } - } - return array_intersect(array_unique($result), $locales); - } - - 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/204/paymentmethod/JTLMollieDirectDebit.php b/version/204/paymentmethod/JTLMollieDirectDebit.php deleted file mode 100644 index 7318e8a..0000000 --- a/version/204/paymentmethod/JTLMollieDirectDebit.php +++ /dev/null @@ -1,27 +0,0 @@ - Date: Tue, 8 Jun 2021 16:37:52 +0200 Subject: [PATCH 242/280] cleanup, fix #136 --- info.xml | 7 + version/204/adminmenu/orders.php | 2 +- version/204/adminmenu/paymentmethods.php | 4 +- .../204/class/Checkout/AbstractCheckout.php | 254 ++++++++++++++++-- .../204/class/Checkout/PaymentCheckout.php | 29 +- version/204/class/Shipment.php | 2 +- version/204/paymentmethod/JTLMolliePayPal.php | 1 - .../paymentmethod/JTLMolliePaysafecard.php | 2 + 8 files changed, 273 insertions(+), 28 deletions(-) diff --git a/info.xml b/info.xml index df03e00..9686b15 100644 --- a/info.xml +++ b/info.xml @@ -89,6 +89,13 @@ + + Payment API Beschreibung + Beschreibung der Zahlung in Mollie. Folgende Variablen stehen zur Verfügung: + {orderNumber}, {storeName}, {customer.firstname}, {customer.lastname}, {customer.company} + + paymentDescTpl + Zahlungserinnerung Soll bei fehlgeschlagener Zahlung ein Zahlungslink verschickt werden? Angabe in Minuten diff --git a/version/204/adminmenu/orders.php b/version/204/adminmenu/orders.php index af6af9f..9033413 100644 --- a/version/204/adminmenu/orders.php +++ b/version/204/adminmenu/orders.php @@ -210,7 +210,7 @@ } } - Mollie::fixZahlungsarten(); + // Mollie::fixZahlungsarten(); $checkouts = []; $payments = Shop::DB()->executeQueryPrepared("SELECT * FROM xplugin_ws_mollie_payments WHERE kBestellung IS NOT NULL ORDER BY dCreatedAt DESC LIMIT 1000;", [], 2); diff --git a/version/204/adminmenu/paymentmethods.php b/version/204/adminmenu/paymentmethods.php index 18adb1e..1a6d47f 100644 --- a/version/204/adminmenu/paymentmethods.php +++ b/version/204/adminmenu/paymentmethods.php @@ -89,8 +89,8 @@ } Shop::Smarty()->assign('profile', $profile) - ->assign('currencies', Mollie::getCurrencies()) - ->assign('locales', Mollie::getLocales()) + ->assign('currencies', AbstractCheckout::getCurrencies()) + ->assign('locales', AbstractCheckout::getLocales()) ->assign('allMethods', $allMethods) ->assign('settings', $oPlugin->oPluginEinstellungAssoc_arr); Shop::Smarty()->display($oPlugin->cAdminmenuPfad . '/tpl/paymentmethods.tpl'); diff --git a/version/204/class/Checkout/AbstractCheckout.php b/version/204/class/Checkout/AbstractCheckout.php index 47287bb..7209be2 100644 --- a/version/204/class/Checkout/AbstractCheckout.php +++ b/version/204/class/Checkout/AbstractCheckout.php @@ -445,6 +445,240 @@ public static function cancel($checkout) throw new RuntimeException('AbstractCheckout::cancel: Invalid Checkout!'); } + 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[] = static::getLocale($sS->cISO, $land); + } + } + return array_intersect(array_unique($result), $locales); + } + + public static function getLocale($cISOSprache = null, $country = null) + { + + if ($cISOSprache === null) { + $cISOSprache = gibStandardsprache()->cISO; + } + if (array_key_exists($cISOSprache, self::$localeLangs)) { + $locale = self::$localeLangs[$cISOSprache]['lang']; + if ($country && is_array(self::$localeLangs[$cISOSprache]['country']) && in_array($country, self::$localeLangs[$cISOSprache]['country'], true)) { + $locale .= '_' . strtoupper($country); + } else { + $locale .= '_' . self::$localeLangs[$cISOSprache]['country'][0]; + } + return $locale; + } + + return self::Plugin()->oPluginEinstellungAssoc_arr['fallbackLocale']; + } + + 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; + } + public function loadRequest(&$options = []) { @@ -549,25 +783,6 @@ public function getCustomer($createOrUpdate = false, $oKunde = null) return $this->customer; } - public static function getLocale($cISOSprache = null, $country = null) - { - - if ($cISOSprache === null) { - $cISOSprache = gibStandardsprache()->cISO; - } - if (array_key_exists($cISOSprache, self::$localeLangs)) { - $locale = self::$localeLangs[$cISOSprache]['lang']; - if ($country && is_array(self::$localeLangs[$cISOSprache]['country']) && in_array($country, self::$localeLangs[$cISOSprache]['country'], true)) { - $locale .= '_' . strtoupper($country); - } else { - $locale .= '_' . self::$localeLangs[$cISOSprache]['country'][0]; - } - return $locale; - } - - return self::Plugin()->oPluginEinstellungAssoc_arr['fallbackLocale']; - } - /** * @return string */ @@ -937,4 +1152,5 @@ protected function setBestellung(Bestellung $oBestellung) */ abstract protected function setMollie($model); + } \ No newline at end of file diff --git a/version/204/class/Checkout/PaymentCheckout.php b/version/204/class/Checkout/PaymentCheckout.php index f11e22b..a75faea 100644 --- a/version/204/class/Checkout/PaymentCheckout.php +++ b/version/204/class/Checkout/PaymentCheckout.php @@ -7,13 +7,13 @@ use Exception; use Mollie\Api\Exceptions\ApiException; use Mollie\Api\Exceptions\IncompatiblePlatform; -use Mollie\Api\Resources\Order; use Mollie\Api\Resources\Payment; use Mollie\Api\Types\PaymentStatus; use RuntimeException; use Shop; use ws_mollie\Checkout\Payment\Address; use ws_mollie\Checkout\Payment\Amount; +use ws_mollie\Helper; /** * Class PaymentCheckout @@ -156,15 +156,36 @@ public function loadRequest(&$options = []) parent::loadRequest($options); - $this->description = 'Order ' . $this->getBestellung()->cBestellNr; - foreach ($options as $key => $value) { $this->$key = $value; } + + $this->description = $this->getDescription(); + return $this; } + public function getDescription() + { + $descTemplate = trim(Helper::getSetting('paymentDescTpl')) ?: "Order {orderNumber}"; + $oKunde = $this->getBestellung()->oKunde ?: $_SESSION['Kunde']; + return str_replace([ + '{orderNumber}', + '{storeName}', + '{customer.firstname}', + '{customer.lastname}', + '{customer.company}', + ], [ + $this->getBestellung()->cBestellNr, + Shop::getSettings([CONF_GLOBAL])['global']['global_shopname'], + $oKunde->cVorname, + $oKunde->cNachname, + $oKunde->cFirma + + ], $descTemplate); + } + /** * @return object|null */ @@ -207,7 +228,7 @@ protected function updateOrderNumber() { try { if ($this->getMollie()) { - $this->getMollie()->description = 'Order ' . $this->getBestellung()->cBestellNr; + $this->getMollie()->description = $this->getDescription(); $this->getMollie()->webhookUrl = Shop::getURL() . '/?mollie=1'; $this->getMollie()->update(); } diff --git a/version/204/class/Shipment.php b/version/204/class/Shipment.php index 0268423..ae533f7 100644 --- a/version/204/class/Shipment.php +++ b/version/204/class/Shipment.php @@ -240,7 +240,7 @@ public function updateModel() * @return $this * @throws Exception */ - public function loadRequest($options = []) + public function loadRequest(&$options = []) { /** @var Versand $oVersand */ $oVersand = $this->getLieferschein()->oVersand_arr[0]; diff --git a/version/204/paymentmethod/JTLMolliePayPal.php b/version/204/paymentmethod/JTLMolliePayPal.php index 5046b71..7df0b9d 100644 --- a/version/204/paymentmethod/JTLMolliePayPal.php +++ b/version/204/paymentmethod/JTLMolliePayPal.php @@ -31,7 +31,6 @@ public function getPaymentOptions(Bestellung $order, $apiType) } $paymentOptions['shippingAddress'] = Address::factory($order->Lieferadresse); } - $paymentOptions['description'] = 'Order ' . $order->cBestellNr; } diff --git a/version/204/paymentmethod/JTLMolliePaysafecard.php b/version/204/paymentmethod/JTLMolliePaysafecard.php index 272b799..b48e371 100644 --- a/version/204/paymentmethod/JTLMolliePaysafecard.php +++ b/version/204/paymentmethod/JTLMolliePaysafecard.php @@ -8,6 +8,8 @@ class JTLMolliePaysafecard extends JTLMollie const ALLOW_AUTO_STORNO = true; + const ALLOW_PAYMENT_BEFORE_ORDER = true; + public function getPaymentOptions(Bestellung $order, $apiType) { return $apiType === 'payment' ? ['customerReference' => $order->oKunde->kKunde] : []; From ec913db6448608a0d00b5a05f5d6b10885b8cb43 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Tue, 8 Jun 2021 16:49:17 +0200 Subject: [PATCH 243/280] fix #138 --- info.xml | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/info.xml b/info.xml index 9686b15..b4023cc 100644 --- a/info.xml +++ b/info.xml @@ -484,7 +484,7 @@ API - Welche API soll verwendet werden? + hier für mehr Informationen.]]> api @@ -519,9 +519,8 @@ Mollie Components - Wenn diese Einstellung aktiviert ist, werden die Kreditkarten ggf. bereits im Shop - abgefragt. - + hier für weitere Informationen]]> components @@ -540,7 +539,7 @@ API - Welche API soll verwendet werden? + hier für mehr Informationen.]]> api @@ -574,7 +573,7 @@ API - Welche API soll verwendet werden? + hier für mehr Informationen.]]> api @@ -608,7 +607,7 @@ API - Welche API soll verwendet werden? + hier für mehr Informationen.]]> api @@ -642,7 +641,7 @@ API - Welche API soll verwendet werden? + hier für mehr Informationen.]]> api @@ -676,7 +675,7 @@ API - Welche API soll verwendet werden? + hier für mehr Informationen.]]> api @@ -710,7 +709,7 @@ API - Welche API soll verwendet werden? + hier für mehr Informationen.]]> api @@ -764,7 +763,7 @@ API - Welche API soll verwendet werden? + hier für mehr Informationen.]]> api @@ -798,7 +797,7 @@ API - Welche API soll verwendet werden? + hier für mehr Informationen.]]> api @@ -832,7 +831,7 @@ API - Welche API soll verwendet werden? + hier für mehr Informationen.]]> api @@ -866,7 +865,7 @@ API - Welche API soll verwendet werden? + hier für mehr Informationen.]]> api @@ -900,7 +899,7 @@ API - Welche API soll verwendet werden? + hier für mehr Informationen.]]> api @@ -934,7 +933,7 @@ API - Welche API soll verwendet werden? + hier für mehr Informationen.]]> api @@ -1018,7 +1017,7 @@ API - Welche API soll verwendet werden? + hier für mehr Informationen.]]> api @@ -1052,7 +1051,7 @@ API - Welche API soll verwendet werden? + hier für mehr Informationen.]]> api From 7ad48fc383c58b9e801c83a7524887f4dc02d740 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Wed, 9 Jun 2021 14:03:04 +0200 Subject: [PATCH 244/280] fix backend info --- info.xml | 2 +- version/204/adminmenu/tpl/paymentmethods.tpl | 4 ++-- version/204/class/Checkout/OrderCheckout.php | 1 - 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/info.xml b/info.xml index b4023cc..1aa0180 100644 --- a/info.xml +++ b/info.xml @@ -41,7 +41,7 @@ 203.sql - 2021-06-08 + 2021-06-09 204.sql diff --git a/version/204/adminmenu/tpl/paymentmethods.tpl b/version/204/adminmenu/tpl/paymentmethods.tpl index 7aedaab..7821af5 100644 --- a/version/204/adminmenu/tpl/paymentmethods.tpl +++ b/version/204/adminmenu/tpl/paymentmethods.tpl @@ -97,9 +97,9 @@
Bestellabschluss: {if intval($method->shop->nWaehrendBestellung) === 1} - VOR Zahlung - {else} NACH Zahlung + {else} + VOR Zahlung {/if}
{/if} diff --git a/version/204/class/Checkout/OrderCheckout.php b/version/204/class/Checkout/OrderCheckout.php index f58764b..e6bdc8e 100644 --- a/version/204/class/Checkout/OrderCheckout.php +++ b/version/204/class/Checkout/OrderCheckout.php @@ -291,7 +291,6 @@ public function loadRequest(&$options = []) $max = $this->method && strpos($this->method, 'klarna') !== false ? 28 : 100; $date = new DateTime(sprintf("+%d DAYS", min($dueDays, $max)), new DateTimeZone('UTC')); $this->expiresAt = $date->format('Y-m-d'); - //date('Y-m-d', strtotime(sprintf("+%d DAYS", min($dueDays, $max)))); } catch (Exception $e) { $this->Log($e->getMessage(), LOGLEVEL_ERROR); } From 0a2b73338d44e65dc1bbeca50a220740369af8c7 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Thu, 10 Jun 2021 14:20:59 +0200 Subject: [PATCH 245/280] ApplePay: document ready --- composer.json | 8 +- composer.lock | 113 ++++++------------ version/204/class/Queue.php | 1 - version/204/class/Traits/RequestData.php | 3 + version/204/frontend/tpl/applepay.tpl | 24 ++-- .../paymentmethod/tpl/mollieComponents.tpl | 5 +- 6 files changed, 60 insertions(+), 94 deletions(-) diff --git a/composer.json b/composer.json index 96ac757..8e601b9 100644 --- a/composer.json +++ b/composer.json @@ -6,9 +6,9 @@ "ext-json": "*", "ext-curl": "*", "php": ">=5.6", - "mollie/mollie-api-php": "^v2.31.1" - } - , + "mollie/mollie-api-php": "^v2.31.1", + "guzzlehttp/guzzle": "^6.5.5" + }, "require-dev": { "roave/security-advisories": "dev-latest" }, @@ -20,6 +20,6 @@ } ], "config": { - "optimize-autoloader": true + "optimize-autoloader": true } } diff --git a/composer.lock b/composer.lock index ecbc2e2..ba1b3a2 100644 --- a/composer.lock +++ b/composer.lock @@ -4,20 +4,20 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "4ceee3c5cacb717215861c1bc668ac23", + "content-hash": "721bbf731782238720f88f8e8a38b737", "packages": [ { "name": "composer/ca-bundle", - "version": "1.2.9", + "version": "1.2.10", "source": { "type": "git", "url": "https://github.com/composer/ca-bundle.git", - "reference": "78a0e288fdcebf92aa2318a8d3656168da6ac1a5" + "reference": "9fdb22c2e97a614657716178093cd1da90a64aa8" }, "dist": { "type": "zip", - "url": "https://github.com/gitapi/repos/composer/ca-bundle/zipball/78a0e288fdcebf92aa2318a8d3656168da6ac1a5", - "reference": "78a0e288fdcebf92aa2318a8d3656168da6ac1a5", + "url": "https://github.com/gitapi/repos/composer/ca-bundle/zipball/9fdb22c2e97a614657716178093cd1da90a64aa8", + "reference": "9fdb22c2e97a614657716178093cd1da90a64aa8", "shasum": "" }, "require": { @@ -61,11 +61,6 @@ "ssl", "tls" ], - "support": { - "irc": "irc://irc.freenode.org/composer", - "issues": "https://github.com/composer/ca-bundle/issues", - "source": "https://github.com/composer/ca-bundle/tree/1.2.9" - }, "funding": [ { "url": "https://packagist.com", @@ -80,7 +75,7 @@ "type": "tidelift" } ], - "time": "2021-01-12T12:10:35+00:00" + "time": "2021-06-07T13:58:28+00:00" }, { "name": "guzzlehttp/guzzle", @@ -147,10 +142,6 @@ "rest", "web service" ], - "support": { - "issues": "https://github.com/guzzle/guzzle/issues", - "source": "https://github.com/guzzle/guzzle/tree/6.5" - }, "time": "2020-06-16T21:01:06+00:00" }, { @@ -202,10 +193,6 @@ "keywords": [ "promise" ], - "support": { - "issues": "https://github.com/guzzle/promises/issues", - "source": "https://github.com/guzzle/promises/tree/1.4.1" - }, "time": "2021-03-07T09:25:29+00:00" }, { @@ -277,24 +264,20 @@ "uri", "url" ], - "support": { - "issues": "https://github.com/guzzle/psr7/issues", - "source": "https://github.com/guzzle/psr7/tree/1.8.2" - }, "time": "2021-04-26T09:17:50+00:00" }, { "name": "mollie/mollie-api-php", - "version": "v2.31.1", + "version": "v2.32.2", "source": { "type": "git", "url": "https://github.com/mollie/mollie-api-php.git", - "reference": "c1a500d251255e29919c6250d5c741ae4fe4e178" + "reference": "48d3ce280a86e2aa18f56c94b2ae63e30468b773" }, "dist": { "type": "zip", - "url": "https://github.com/gitapi/repos/mollie/mollie-api-php/zipball/c1a500d251255e29919c6250d5c741ae4fe4e178", - "reference": "c1a500d251255e29919c6250d5c741ae4fe4e178", + "url": "https://github.com/gitapi/repos/mollie/mollie-api-php/zipball/48d3ce280a86e2aa18f56c94b2ae63e30468b773", + "reference": "48d3ce280a86e2aa18f56c94b2ae63e30468b773", "shasum": "" }, "require": { @@ -302,12 +285,12 @@ "ext-curl": "*", "ext-json": "*", "ext-openssl": "*", - "guzzlehttp/guzzle": "^6.3 || ^7.0", "php": ">=5.6" }, "require-dev": { "eloquent/liberator": "^2.0", - "friendsofphp/php-cs-fixer": "^v2.17", + "friendsofphp/php-cs-fixer": "^3.0", + "guzzlehttp/guzzle": "^6.3 || ^7.0", "phpunit/phpunit": "^5.7 || ^6.5 || ^7.1 || ^8.5" }, "suggest": { @@ -368,11 +351,7 @@ "sofortbanking", "subscriptions" ], - "support": { - "issues": "https://github.com/mollie/mollie-api-php/issues", - "source": "https://github.com/mollie/mollie-api-php/tree/v2.31.1" - }, - "time": "2021-04-26T11:38:41+00:00" + "time": "2021-06-08T06:03:46+00:00" }, { "name": "paragonie/random_compat", @@ -421,11 +400,6 @@ "pseudorandom", "random" ], - "support": { - "email": "info@paragonie.com", - "issues": "https://github.com/paragonie/random_compat/issues", - "source": "https://github.com/paragonie/random_compat" - }, "time": "2021-04-17T09:33:01+00:00" }, { @@ -476,9 +450,6 @@ "request", "response" ], - "support": { - "source": "https://github.com/php-fig/http-message/tree/master" - }, "time": "2016-08-06T14:39:51+00:00" }, { @@ -519,10 +490,6 @@ } ], "description": "A polyfill for getallheaders.", - "support": { - "issues": "https://github.com/ralouphie/getallheaders/issues", - "source": "https://github.com/ralouphie/getallheaders/tree/develop" - }, "time": "2019-03-08T08:55:37+00:00" }, { @@ -594,9 +561,6 @@ "portable", "shim" ], - "support": { - "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.19.0" - }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -678,9 +642,6 @@ "portable", "shim" ], - "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.19.0" - }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -758,9 +719,6 @@ "portable", "shim" ], - "support": { - "source": "https://github.com/symfony/polyfill-php70/tree/v1.19.0" - }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -834,9 +792,6 @@ "portable", "shim" ], - "support": { - "source": "https://github.com/symfony/polyfill-php72/tree/v1.19.0" - }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -861,18 +816,19 @@ "source": { "type": "git", "url": "https://github.com/Roave/SecurityAdvisories.git", - "reference": "42840dcc436945146d79a985240a99ddd3bc5dc7" + "reference": "ef267f15fbe759580779eef9f1aa2b29e637f279" }, "dist": { "type": "zip", - "url": "https://github.com/gitapi/repos/Roave/SecurityAdvisories/zipball/42840dcc436945146d79a985240a99ddd3bc5dc7", - "reference": "42840dcc436945146d79a985240a99ddd3bc5dc7", + "url": "https://github.com/gitapi/repos/Roave/SecurityAdvisories/zipball/ef267f15fbe759580779eef9f1aa2b29e637f279", + "reference": "ef267f15fbe759580779eef9f1aa2b29e637f279", "shasum": "" }, "conflict": { "3f/pygmentize": "<1.2", "adodb/adodb-php": "<5.20.12", "alterphp/easyadmin-extension-bundle": ">=1.2,<1.2.11|>=1.3,<1.3.1", + "amazing/media2click": ">=1,<1.3.3", "amphp/artax": "<1.0.6|>=2,<2.0.6", "amphp/http": "<1.0.1", "amphp/http-client": ">=4,<4.4", @@ -882,7 +838,7 @@ "bagisto/bagisto": "<0.1.5", "barrelstrength/sprout-base-email": "<1.2.7", "barrelstrength/sprout-forms": "<3.9", - "baserproject/basercms": ">=4,<=4.3.6|>=4.4,<4.4.1", + "baserproject/basercms": "<4.4.5", "bk2k/bootstrap-package": ">=7.1,<7.1.2|>=8,<8.0.8|>=9,<9.0.4|>=9.1,<9.1.3|>=10,<10.0.10|>=11,<11.0.3", "bolt/bolt": "<3.7.2", "bolt/core": "<4.1.13", @@ -892,7 +848,7 @@ "cakephp/cakephp": ">=1.3,<1.3.18|>=2,<2.4.99|>=2.5,<2.5.99|>=2.6,<2.6.12|>=2.7,<2.7.6|>=3,<3.5.18|>=3.6,<3.6.15|>=3.7,<3.7.7", "cart2quote/module-quotation": ">=4.1.6,<=4.4.5|>=5,<5.4.4", "cartalyst/sentry": "<=2.1.6", - "centreon/centreon": "<18.10.8|>=19,<19.4.5", + "centreon/centreon": "<20.10.7", "cesnet/simplesamlphp-module-proxystatistics": "<3.1", "codeigniter/framework": "<=3.0.6", "composer/composer": "<1.10.22|>=2-alpha.1,<2.0.13", @@ -903,6 +859,7 @@ "datadog/dd-trace": ">=0.30,<0.30.2", "david-garcia/phpwhois": "<=4.3.1", "derhansen/sf_event_mgt": "<4.3.1|>=5,<5.1.1", + "directmailteam/direct-mail": "<5.2.4", "doctrine/annotations": ">=1,<1.2.7", "doctrine/cache": ">=1,<1.3.2|>=1.4,<1.4.2", "doctrine/common": ">=2,<2.4.3|>=2.5,<2.5.1", @@ -936,7 +893,9 @@ "ezsystems/repository-forms": ">=2.3,<2.3.2.1", "ezyang/htmlpurifier": "<4.1.1", "facade/ignition": "<1.16.14|>=2,<2.4.2|>=2.5,<2.5.2", + "feehi/cms": "<=2.1.1", "firebase/php-jwt": "<2", + "flarum/core": ">=1,<=1.0.1", "flarum/sticky": ">=0.1-beta.14,<=0.1-beta.15", "flarum/tags": "<=0.1-beta.13", "fluidtypo3/vhs": "<5.1.1", @@ -949,7 +908,7 @@ "friendsofsymfony/user-bundle": ">=1.2,<1.3.5", "friendsoftypo3/mediace": ">=7.6.2,<7.6.5", "fuel/core": "<1.8.1", - "getgrav/grav": "<1.7.11", + "getgrav/grav": "<=1.7.10", "getkirby/cms": "<3.5.4", "getkirby/panel": "<2.5.14", "gos/web-socket-bundle": "<1.10.4|>=2,<2.6.1|>=3,<3.3", @@ -969,8 +928,10 @@ "jsmitty12/phpwhois": "<5.1", "kazist/phpwhois": "<=4.2.6", "kitodo/presentation": "<3.1.2", + "klaviyo/magento2-extension": ">=1,<3", "kreait/firebase-php": ">=3.2,<3.8.1", "la-haute-societe/tcpdf": "<6.2.22", + "laminas/laminas-http": "<2.14.2", "laravel/framework": "<6.20.26|>=7,<8.40", "laravel/socialite": ">=1,<1.0.99|>=2,<2.0.10", "league/commonmark": "<0.18.3", @@ -1014,6 +975,7 @@ "paypal/merchant-sdk-php": "<3.12", "pear/archive_tar": "<1.4.12", "personnummer/personnummer": "<3.0.2", + "phanan/koel": "<5.1.4", "phpfastcache/phpfastcache": ">=5,<5.0.13", "phpmailer/phpmailer": "<6.1.6|>=6.1.8,<6.4.1", "phpmussel/phpmussel": ">=1,<1.6", @@ -1050,7 +1012,7 @@ "shopware/core": "<=6.3.5.2", "shopware/platform": "<=6.3.5.2", "shopware/production": "<=6.3.5.2", - "shopware/shopware": "<5.6.9", + "shopware/shopware": "<=5.6.9", "silverstripe/admin": ">=1.0.3,<1.0.4|>=1.1,<1.1.1", "silverstripe/assets": ">=1,<1.4.7|>=1.5,<1.5.2", "silverstripe/cms": "<4.3.6|>=4.4,<4.4.4", @@ -1102,25 +1064,27 @@ "symfony/polyfill-php55": ">=1,<1.10", "symfony/proxy-manager-bridge": ">=2.7,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", "symfony/routing": ">=2,<2.0.19", - "symfony/security": ">=2,<2.7.51|>=2.8,<3.4.48|>=4,<4.4.23|>=5,<5.2.8", + "symfony/security": ">=2,<2.7.51|>=2.8,<3.4.49|>=4,<4.4.24|>=5,<5.2.8", "symfony/security-bundle": ">=2,<2.7.48|>=2.8,<2.8.41|>=3,<3.3.17|>=3.4,<3.4.11|>=4,<4.0.11", - "symfony/security-core": ">=2.4,<2.6.13|>=2.7,<2.7.9|>=2.7.30,<2.7.32|>=2.8,<3.4.48|>=4,<4.4.23|>=5,<5.2.8", + "symfony/security-core": ">=2.4,<2.6.13|>=2.7,<2.7.9|>=2.7.30,<2.7.32|>=2.8,<3.4.49|>=4,<4.4.24|>=5,<5.2.9", "symfony/security-csrf": ">=2.4,<2.7.48|>=2.8,<2.8.41|>=3,<3.3.17|>=3.4,<3.4.11|>=4,<4.0.11", "symfony/security-guard": ">=2.8,<3.4.48|>=4,<4.4.23|>=5,<5.2.8", "symfony/security-http": ">=2.3,<2.3.41|>=2.4,<2.7.51|>=2.8,<3.4.48|>=4,<4.4.23|>=5,<5.2.8", "symfony/serializer": ">=2,<2.0.11", - "symfony/symfony": ">=2,<3.4.48|>=4,<4.4.23|>=5,<5.2.8", + "symfony/symfony": ">=2,<3.4.49|>=4,<4.4.24|>=5,<5.2.9", "symfony/translation": ">=2,<2.0.17", "symfony/validator": ">=2,<2.0.24|>=2.1,<2.1.12|>=2.2,<2.2.5|>=2.3,<2.3.3", "symfony/var-exporter": ">=4.2,<4.2.12|>=4.3,<4.3.8", "symfony/web-profiler-bundle": ">=2,<2.3.19|>=2.4,<2.4.9|>=2.5,<2.5.4", "symfony/yaml": ">=2,<2.0.22|>=2.1,<2.1.7", + "t3/dce": ">=2.2,<2.6.2", "t3g/svg-sanitizer": "<1.0.3", "tecnickcom/tcpdf": "<6.2.22", "thelia/backoffice-default-template": ">=2.1,<2.1.2", "thelia/thelia": ">=2.1-beta.1,<2.1.3", "theonedemon/phpwhois": "<=4.2.5", "titon/framework": ">=0,<9.9.99", + "tribalsystems/zenario": "<8.8.53370", "truckersmp/phpwhois": "<=4.3.1", "twig/twig": "<1.38|>=2,<2.7", "typo3/cms": ">=6.2,<6.2.30|>=7,<7.6.32|>=8,<8.7.38|>=9,<9.5.25|>=10,<10.4.14|>=11,<11.1.1", @@ -1139,6 +1103,7 @@ "wallabag/tcpdf": "<6.2.22", "wikimedia/parsoid": "<0.12.2", "willdurand/js-translation-bundle": "<2.1.1", + "wp-cli/wp-cli": "<2.5", "yii2mod/yii2-cms": "<1.9.2", "yiisoft/yii": ">=1.1.14,<1.1.15", "yiisoft/yii2": "<2.0.38", @@ -1148,6 +1113,7 @@ "yiisoft/yii2-gii": "<2.0.4", "yiisoft/yii2-jui": "<2.0.4", "yiisoft/yii2-redis": "<2.0.8", + "yoast-seo-for-typo3/yoast_seo": "<7.2.1", "yourls/yourls": "<1.7.4", "zendesk/zendesk_api_client_php": "<2.2.11", "zendframework/zend-cache": ">=2.4,<2.4.8|>=2.5,<2.5.3", @@ -1167,7 +1133,7 @@ "zendframework/zend-validator": ">=2.3,<2.3.6", "zendframework/zend-view": ">=2,<2.2.7|>=2.3,<2.3.1", "zendframework/zend-xmlrpc": ">=2.1,<2.1.6|>=2.2,<2.2.6", - "zendframework/zendframework": "<2.5.1", + "zendframework/zendframework": "<=3", "zendframework/zendframework1": "<1.12.20", "zendframework/zendopenid": ">=2,<2.0.2", "zendframework/zendxml": ">=1,<1.0.1", @@ -1177,7 +1143,6 @@ "zfr/zfr-oauth2-server-module": "<0.1.2", "zoujingli/thinkadmin": "<6.0.22" }, - "default-branch": true, "type": "metapackage", "notification-url": "https://packagist.org/downloads/", "license": [ @@ -1196,10 +1161,6 @@ } ], "description": "Prevents installation of composer packages with known security vulnerabilities: no API, simply require it", - "support": { - "issues": "https://github.com/Roave/SecurityAdvisories/issues", - "source": "https://github.com/Roave/SecurityAdvisories/tree/latest" - }, "funding": [ { "url": "https://github.com/Ocramius", @@ -1210,7 +1171,7 @@ "type": "tidelift" } ], - "time": "2021-05-18T18:23:15+00:00" + "time": "2021-06-09T23:02:53+00:00" } ], "aliases": [], @@ -1226,5 +1187,5 @@ "php": ">=5.6" }, "platform-dev": [], - "plugin-api-version": "2.0.0" + "plugin-api-version": "1.1.0" } diff --git a/version/204/class/Queue.php b/version/204/class/Queue.php index 7340260..927c8c5 100644 --- a/version/204/class/Queue.php +++ b/version/204/class/Queue.php @@ -182,7 +182,6 @@ protected static function handleHook($hook, QueueModel $todo) if (is_string($shipment)) { $checkout->PaymentMethod()->Log("Shipping-Error: $shipment", $checkout->LogData()); $result .= "Shipping-Error: $shipment;\n"; - } else { $checkout->PaymentMethod()->Log("Order shipped: \n" . print_r($shipment, 1)); $result .= "Order shipped: $shipment->id;\n"; diff --git a/version/204/class/Traits/RequestData.php b/version/204/class/Traits/RequestData.php index 72eda6b..d5964c2 100644 --- a/version/204/class/Traits/RequestData.php +++ b/version/204/class/Traits/RequestData.php @@ -14,6 +14,9 @@ trait RequestData public function jsonSerialize() { + if (json_encode($this->requestData) === false) { + throw new \RuntimeException(sprintf("JSON Encode Error: %s\n%s", json_last_error_msg(), print_r($this->requestData, 1))); + } return $this->requestData; } diff --git a/version/204/frontend/tpl/applepay.tpl b/version/204/frontend/tpl/applepay.tpl index 1ef8a51..a7ec33b 100644 --- a/version/204/frontend/tpl/applepay.tpl +++ b/version/204/frontend/tpl/applepay.tpl @@ -1,15 +1,17 @@ - diff --git a/version/204/paymentmethod/tpl/mollieComponents.tpl b/version/204/paymentmethod/tpl/mollieComponents.tpl index 8bcd452..987abf1 100644 --- a/version/204/paymentmethod/tpl/mollieComponents.tpl +++ b/version/204/paymentmethod/tpl/mollieComponents.tpl @@ -1,6 +1,6 @@

{$mollieLang.cctitle}

-
+
@@ -86,8 +86,9 @@ - \ No newline at end of file diff --git a/version/205/adminmenu/tpl/info.tpl b/version/205/adminmenu/tpl/info.tpl new file mode 100644 index 0000000..2d41c95 --- /dev/null +++ b/version/205/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}
+
+
+
Changelog:
+
+ +
+
+ +
+
+ +
+
+
+ {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/205/adminmenu/tpl/mollie-account-erstellen.png b/version/205/adminmenu/tpl/mollie-account-erstellen.png new file mode 100644 index 0000000000000000000000000000000000000000..fc1819255ef725fa214cf2bf028cf3428794ecee GIT binary patch literal 38998 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 +

+ « + 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 isset($order->customerId)} + ID: + {$order->customerId} +
+ {/if} + {if isset($order->billingAddress, $order->billingAddress->organizationName)} + {$order->billingAddress->organizationName} + {elseif isset($order->billingAddress)} + {$order->billingAddress->title} {$order->billingAddress->givenName} {$order->billingAddress->familyName} + {/if} +
Mollie Checkout: + {if $order->getCheckoutURL()} + mollie.com/... + {else} + n/a + {/if} + + +
+{if $order->id|strpos:"ord_" !== false && $order->payments()->count > 0} +

Zahlungen

+ + + + + + + + + + + + + + {foreach from=$order->payments() item=payment} + + + + + + + + + + + {/foreach} +
IDStatusMethodeAmountSettlementRefundedRemainingDetails
{$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} +
+
+{/if} + +
+ {if ($order->status === 'authorized' || $order->status === 'shipping') && $oBestellung->cStatus|intval >= 3} + + Zahlung erfassen1 + + {/if} + {if !$order->amountRefunded || ($order->amount->value > $order->amountRefunded->value)} + Rückerstatten2 + + {/if} + {if $order->isCancelable} + Abbrechen3 + + {/if} +
+ +{if $order->id|strpos:"ord_" !== false} +

Positionen:

+ + + + + + + + + + + + + + + + + {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} + + + + + + + + + + + + + {/foreach} + + + + + + + + + + +
StatusSKUNameTypAnzahlMwStSteuerNettoBrutto 
+ {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'} + abgebrochen + {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*} +
{$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.
+
+{/if} + +{if isset($shipments) && $shipments|count} +

Shipmets

+ + + + + + + + + + + {foreach from=$shipments item=shipment} + + + + + + + {/foreach} + +
Lieferschein Nr.Mollie IDCarrierCode
{$shipment->getLieferschein()->getLieferscheinNr()}{$shipment->getShipment()->id} + {if isset($shipment->getShipment()->tracking)} + {$shipment->getShipment()->tracking->carrier} + {else} + - + {/if} + {if isset($shipment->getShipment()->tracking)} + {if isset($shipment->getShipment()->tracking->url)} + + {$shipment->getShipment()->tracking->code} + + {else} + {$shipment->getShipment()->tracking->code} + {/if} + {else} + - + {/if} +
+{/if} + +

Log

+ + {foreach from=$logs item=log} + + + + + + + {/foreach} +
+ {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}
+ + diff --git a/version/205/adminmenu/tpl/orders.tpl b/version/205/adminmenu/tpl/orders.tpl new file mode 100644 index 0000000..a499f32 --- /dev/null +++ b/version/205/adminmenu/tpl/orders.tpl @@ -0,0 +1,160 @@ +{ws_mollie\Helper::showAlerts('orders')} + +{if $hasAPIKey == false} + + Jetzt kostenlos Mollie Account eröffnen! + +{else} + + + + + + + + + + + + + + + {foreach from=$checkouts item=checkout} + + + + + + + + + + + + + + + {/foreach} + +
BestellNr.IDMollie StatusJTL StatusBetragMethodeErstellt 
+ {if $checkout->getModel()->bSynced == false && $checkout->getBestellung()->cAbgeholt === 'Y'} + * + {/if} + {$checkout->getModel()->cOrderNumber} + {if $checkout->getModel()->cMode == 'test'} + TEST + {/if} + {if $checkout->getModel()->bLockTimeout} + LOCK TIMEOUT + {/if} + {if $checkout->getModel()->dReminder && $checkout->getModel()->dReminder !== '0000-00-00 00:00:00'} + getModel()->dReminder|strtotime}}"> + {/if} + + {$checkout->getModel()->kID} + + {if $checkout->getModel()->cStatus == 'created' || $checkout->getModel()->cStatus == 'open'} + erstellt + {elseif $checkout->getModel()->cStatus == 'pending'} + austehend + {elseif $checkout->getModel()->cStatus == 'paid'} + bezahlt + {elseif $checkout->getModel()->cStatus == 'authorized'} + autorisiert + {elseif $checkout->getModel()->cStatus == 'shipping'} + versendet + {elseif $checkout->getModel()->cStatus == 'completed'} + abgeschlossen + {elseif $checkout->getModel()->cStatus == 'expired'} + abgelaufen + {elseif $checkout->getModel()->cStatus == 'canceled'} + abgebrochen + {else} + Unbekannt: {$checkout->getModel()->cStatus} + {/if} + {if $checkout->getModel()->fAmountRefunded && $checkout->getModel()->fAmountRefunded == $checkout->getModel()->fAmount} + (total refund) + {elseif $checkout->getModel()->fAmountRefunded && $checkout->getModel()->fAmountRefunded > 0} + (partly refund) + {/if} + + + {if $checkout->getBestellung()->cStatus|intval == 1} + OFFEN + {elseif $checkout->getBestellung()->cStatus|intval == 2} + IN BEARBEITUNG + {elseif $checkout->getBestellung()->cStatus|intval == 3} + BEZAHLT + {elseif $checkout->getBestellung()->cStatus|intval == 4} + VERSANDT + {elseif $checkout->getBestellung()->cStatus|intval == 5} + TEILVERSANDT + {elseif $checkout->getBestellung()->cStatus|intval == -1} + STORNO + {else} + n/a + {/if} + {$checkout->getModel()->fAmount|number_format:2:',':''} {$checkout->getModel()->cCurrency}{$checkout->getModel()->cMethod}{"d. M Y H:i"|date:{$checkout->getModel()->dCreatedAt|strtotime}} +
+ +
+ {if $checkout->getModel()->bSynced == false && $checkout->getBestellung()->cAbgeholt === 'Y'} + + {/if} + {if $checkout->remindable()} + + {/if} +
+
+
+ {if $payments|count > 900} +
Hier werden nur die letzten 1000 Ergebnisse angezeigt.
+ {/if} + + +
+
+

Export:

+
+ +
+ + + + + +
+
+ +{/if} + diff --git a/version/205/adminmenu/tpl/paymentmethods.tpl b/version/205/adminmenu/tpl/paymentmethods.tpl new file mode 100644 index 0000000..7821af5 --- /dev/null +++ b/version/205/adminmenu/tpl/paymentmethods.tpl @@ -0,0 +1,148 @@ +

Account Status

+ + + + + + + {if $profile->review} + + + {/if} + {if $profile->_links->checkoutPreviewUrl->href} + + {/if} + + +
Mode:{$profile->mode}Status:{$profile->status}Review:{$profile->review->status} + Checkout + Preview + + Mollie Dashboard +
+
+
+
+ + +
+ + + +
+
+ + +
+
+ + +
+
+ + + reset +
+
+
+
+{if $allMethods && $allMethods|count} + + + + + + + + + + + + {foreach from=$allMethods item=method} + + + + + + + + {/foreach} + +
BildName / IDInfoPreiseLimits
{$method->mollie->description|utf8_decode} + {if $method->mollie->status === 'activated'} + + {else} + + {/if} + {$method->mollie->description|utf8_decode}
+ {$method->mollie->id} +
+ {if $method->shop && $method->oClass} + {if intval($method->shop->nWaehrendBestellung) === 1 && !$method->allowPreOrder} +
Zahlung VOR Bestellabschluss nicht unterstützt!
+ {else} +
+ Bestellabschluss: + {if intval($method->shop->nWaehrendBestellung) === 1} + NACH Zahlung + {else} + VOR Zahlung + {/if} +
+ {/if} + + {if intval($settings.autoStorno) > 0} +
+ Unbez. Bestellung stornieren: + {if $method->allowAutoStorno} +
auto
+ {else} +
manual
+ {/if} +
+ {/if} +
+ Gültigkeit: + {$method->maxExpiryDays} Tage +
+ {else} + Derzeit nicht unterstützt. + {/if} +
+
    + {foreach from=$method->mollie->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->mollie->minimumAmount}{$method->mollie->minimumAmount->value} {$method->mollie->minimumAmount->currency}{else}n/a{/if} +
+ Max: {if $method->mollie->maximumAmount}{$method->mollie->maximumAmount->value} {$method->mollie->maximumAmount->currency}{else}n/a{/if} +
+{else} +
Es konnten keine Methoden abgerufen werden.
+{/if} \ No newline at end of file diff --git a/version/205/class/API.php b/version/205/class/API.php new file mode 100644 index 0000000..235b7cf --- /dev/null +++ b/version/205/class/API.php @@ -0,0 +1,78 @@ +test = $test === null ? self::getMode() : $test; + } + + /** + * @return bool + */ + public static function getMode() + { + require_once PFAD_ROOT . PFAD_ADMIN . PFAD_INCLUDES . 'benutzerverwaltung_inc.php'; + return self::Plugin()->oPluginEinstellungAssoc_arr["testAsAdmin"] === 'Y' && Shop::isAdmin() && self::Plugin()->oPluginEinstellungAssoc_arr['test_api_key']; + } + + /** + * @return MollieApiClient + * @throws ApiException + * @throws IncompatiblePlatform + */ + public function Client() + { + if (!$this->client) { + $this->client = new MollieApiClient(new Client([ + RequestOptions::VERIFY => CaBundle::getBundledCaBundlePath(), + RequestOptions::TIMEOUT => 60 + ])); + $this->client->setApiKey($this->isTest() ? self::Plugin()->oPluginEinstellungAssoc_arr['test_api_key'] : self::Plugin()->oPluginEinstellungAssoc_arr['api_key']) + ->addVersionString('JTL-Shop/' . JTL_VERSION . JTL_MINOR_VERSION) + ->addVersionString('ws_mollie/' . self::Plugin()->nVersion); + } + return $this->client; + } + + /** + * @return bool + */ + public function isTest() + { + return $this->test; + } + + +} \ No newline at end of file diff --git a/version/205/class/Checkout/AbstractCheckout.php b/version/205/class/Checkout/AbstractCheckout.php new file mode 100644 index 0000000..0a5d2be --- /dev/null +++ b/version/205/class/Checkout/AbstractCheckout.php @@ -0,0 +1,1164 @@ + ['lang' => 'de', 'country' => ['DE', 'AT', 'CH']], + 'fre' => ['lang' => 'fr', 'country' => ['BE', 'FR']], + 'dut' => ['lang' => 'nl', 'country' => ['BE', 'NL']], + 'spa' => ['lang' => 'es', 'country' => ['ES']], + 'ita' => ['lang' => 'it', 'country' => ['IT']], + 'pol' => ['lang' => 'pl', 'country' => ['PL']], + 'hun' => ['lang' => 'hu', 'country' => ['HU']], + 'por' => ['lang' => 'pt', 'country' => ['PT']], + 'nor' => ['lang' => 'nb', 'country' => ['NO']], + 'swe' => ['lang' => 'sv', 'country' => ['SE']], + 'fin' => ['lang' => 'fi', 'country' => ['FI']], + 'dan' => ['lang' => 'da', 'country' => ['DK']], + 'ice' => ['lang' => 'is', 'country' => ['IS']], + 'eng' => ['lang' => 'en', 'country' => ['GB', 'US']], + ]; + /** + * @var \Mollie\Api\Resources\Customer|null + */ + protected $customer; + /** + * @var string + */ + private $hash; + /** + * @var API + */ + private $api; + /** + * @var JTLMollie + */ + private $paymentMethod; + /** + * @var Bestellung + */ + private $oBestellung; + /** + * @var Payment + */ + private $model; + + /** + * AbstractCheckout constructor. + * @param Bestellung $oBestellung + * @param null $api + */ + public function __construct(Bestellung $oBestellung, $api = null) + { + $this->api = $api; + $this->oBestellung = $oBestellung; + } + + /** + * @param int $kBestellung + * @param bool $checkZA + * @return bool + */ + public static function isMollie($kBestellung, $checkZA = false) + { + if ($checkZA) { + $res = Shop::DB()->executeQueryPrepared('SELECT * FROM tzahlungsart WHERE cModulId LIKE :cModulId AND kZahlungsart = :kZahlungsart', [ + ':kZahlungsart' => $kBestellung, + ':cModulId' => 'kPlugin_' . self::Plugin()->kPlugin . '_%' + ], 1); + return (bool)$res; + } + + return ($res = Shop::DB()->executeQueryPrepared('SELECT kId FROM xplugin_ws_mollie_payments WHERE kBestellung = :kBestellung;', [ + ':kBestellung' => $kBestellung, + ], 1)) && $res->kId; + } + + public static function finalizeOrder($sessionHash, $id, $test = false) + { + try { + if ($paymentSession = Shop::DB()->select('tzahlungsession', 'cZahlungsID', $sessionHash)) { + if (session_id() !== $paymentSession->cSID) { + session_destroy(); + session_id($paymentSession->cSID); + $session = Session::getInstance(true, true); + } else { + $session = Session::getInstance(false); + } + + if ((!isset($paymentSession->nBezahlt) || !$paymentSession->nBezahlt) + && (!isset($paymentSession->kBestellung) || !$paymentSession->kBestellung) + && isset($_SESSION['Warenkorb']->PositionenArr) + && count($_SESSION['Warenkorb']->PositionenArr)) { + + $paymentSession->cNotifyID = $id; + $paymentSession->dNotify = 'now()'; + Shop::DB()->update('tzahlungsession', 'cZahlungsID', $sessionHash, $paymentSession); + + $api = new API($test); + if (strpos($id, 'tr_') === 0) { + $mollie = $api->Client()->payments->get($id); + } else { + $mollie = $api->Client()->orders->get($id); + } + + if (in_array($mollie->status, [OrderStatus::STATUS_PENDING, OrderStatus::STATUS_AUTHORIZED, OrderStatus::STATUS_PAID], true)) { + require_once PFAD_ROOT . PFAD_INCLUDES . 'bestellabschluss_inc.php'; + require_once PFAD_ROOT . PFAD_INCLUDES . 'mailTools.php'; + $order = finalisiereBestellung(); + $session->cleanUp(); + $paymentSession->nBezahlt = 1; + $paymentSession->dZeitBezahlt = 'now()'; + } else { + throw new Exception('Mollie Status invalid: ' . $mollie->status . '\n' . print_r([$sessionHash, $id], 1)); + } + + if ($order->kBestellung) { + + $paymentSession->kBestellung = $order->kBestellung; + Shop::DB()->update('tzahlungsession', 'cZahlungsID', $sessionHash, $paymentSession); + + try { + $checkout = self::fromID($id, false, $order); + } catch (Exception $e) { + if (strpos($id, 'tr_') === 0) { + $checkoutClass = PaymentCheckout::class; + } else { + $checkoutClass = OrderCheckout::class; + } + $checkout = new $checkoutClass($order, $api); + } + $checkout->setMollie($mollie); + $checkout->updateOrderNumber(); + $checkout->handleNotification($sessionHash); + } + } else { + Jtllog::writeLog(sprintf('PaymentSession bereits bezahlt: %s - ID: %s => Queue', $sessionHash, $id), JTLLOG_LEVEL_NOTICE); + Queue::saveToQueue($id, $id, 'webhook'); + } + } else { + Jtllog::writeLog(sprintf('PaymentSession nicht gefunden: %s - ID: %s => Queue', $sessionHash, $id), JTLLOG_LEVEL_ERROR); + Queue::saveToQueue($id, $id, 'webhook'); + } + } catch (Exception $e) { + Helper::logExc($e); + } + } + + /** + * @param string $id + * @param bool $bFill + * @param Bestellung|null $order + * @return OrderCheckout|PaymentCheckout + * @throws RuntimeException + */ + public static function fromID($id, $bFill = true, Bestellung $order = null) + { + if (($model = Payment::fromID($id))) { + return static::fromModel($model, $bFill, $order); + } + throw new RuntimeException(sprintf('Error loading Order: %s', $id)); + } + + /** + * @param Payment $model + * @param bool $bFill + * @param Bestellung|null $order + * @return OrderCheckout|PaymentCheckout + */ + public static function fromModel($model, $bFill = true, Bestellung $order = null) + { + if (!$model) { + throw new RuntimeException(sprintf('Error loading Order for Model: %s', print_r($model, 1))); + } + + $oBestellung = $order; + if (!$order) { + $oBestellung = new Bestellung($model->kBestellung, $bFill); + if (!$oBestellung->kBestellung) { + throw new RuntimeException(sprintf('Error loading Bestellung: %s', $model->kBestellung)); + } + } + + if (strpos($model->kID, 'tr_') !== false) { + $self = new PaymentCheckout($oBestellung); + } else { + $self = new OrderCheckout($oBestellung); + } + + $self->setModel($model); + return $self; + } + + /** + * @param null $hash + * @throws Exception + */ + public function handleNotification($hash = null) + { + if (!$this->getHash()) { + $this->getModel()->cHash = $hash; + } + + $this->updateModel()->saveModel(); + if (!$this->getBestellung()->dBezahltDatum || $this->getBestellung()->dBezahltDatum === '0000-00-00') { + if ($incoming = $this->getIncomingPayment()) { + $this->PaymentMethod()->addIncomingPayment($this->getBestellung(), $incoming); + + $this->PaymentMethod()->setOrderStatusToPaid($this->getBestellung()); + static::makeFetchable($this->getBestellung(), $this->getModel()); + $this->PaymentMethod()->deletePaymentHash($this->getHash()); + $this->Log(sprintf("Checkout::handleNotification: Bestellung '%s' als bezahlt markiert: %.2f %s", $this->getBestellung()->cBestellNr, (float)$incoming->fBetrag, $incoming->cISO)); + + $oZahlungsart = Shop::DB()->selectSingleRow('tzahlungsart', 'cModulId', $this->PaymentMethod()->moduleID); + if ($oZahlungsart && (int)$oZahlungsart->nMailSenden === 1) { + require_once PFAD_ROOT . 'includes/mailTools.php'; + $this->PaymentMethod()->sendConfirmationMail($this->getBestellung()); + } + if (!$this->completlyPaid()) { + $this->Log(sprintf("Checkout::handleNotification: Bestellung '%s': nicht komplett bezahlt: %.2f %s", $this->getBestellung()->cBestellNr, (float)$incoming->fBetrag, $incoming->cISO), LOGLEVEL_ERROR); + } + } + } + } + + /** + * @return string + */ + public function getHash() + { + if ($this->getModel()->cHash) { + return $this->getModel()->cHash; + } + if (!$this->hash) { + $this->hash = $this->PaymentMethod()->generateHash($this->oBestellung); + } + return $this->hash; + } + + /** + * @return Payment + */ + public function getModel() + { + if (!$this->model) { + $this->model = Payment::fromID($this->oBestellung->kBestellung, 'kBestellung'); + } + return $this->model; + } + + /** + * @param $model + * @return $this + */ + protected function setModel($model) + { + if (!$this->model) { + $this->model = $model; + } else { + throw new RuntimeException('Model already set.'); + } + return $this; + } + + /** + * @return JTLMollie + */ + public function PaymentMethod() + { + if (!$this->paymentMethod) { + include_once(PFAD_ROOT . PFAD_INCLUDES . 'modules/PaymentMethod.class.php'); + if ($this->getBestellung()->Zahlungsart && strpos($this->getBestellung()->Zahlungsart->cModulId, "kPlugin_{$this::Plugin()->kPlugin}_") !== false) { + try { + $this->paymentMethod = PaymentMethod::create($this->getBestellung()->Zahlungsart->cModulId); + } catch (Exception $e) { + $this->paymentMethod = PaymentMethod::create("kPlugin_{$this::Plugin()->kPlugin}_mollie"); + } + } else { + $this->paymentMethod = PaymentMethod::create("kPlugin_{$this::Plugin()->kPlugin}_mollie"); + } + } + return $this->paymentMethod; + } + + /** + * @return Bestellung + */ + public function getBestellung() + { + if (!$this->oBestellung && $this->getModel()->kBestellung) { + $this->oBestellung = new Bestellung($this->getModel()->kBestellung, true); + } + return $this->oBestellung; + } + + /** + * @return bool + */ + public function saveModel() + { + return $this->getModel()->save(); + } + + /** + * @return $this + */ + public function updateModel() + { + + if ($this->getMollie()) { + $this->getModel()->kID = $this->getMollie()->id; + $this->getModel()->cLocale = $this->getMollie()->locale; + $this->getModel()->fAmount = (float)$this->getMollie()->amount->value; + $this->getModel()->cMethod = $this->getMollie()->method; + $this->getModel()->cCurrency = $this->getMollie()->amount->currency; + $this->getModel()->cStatus = $this->getMollie()->status; + if ($this->getMollie()->amountRefunded) { + $this->getModel()->fAmountRefunded = $this->getMollie()->amountRefunded->value; + } + if ($this->getMollie()->amountCaptured) { + $this->getModel()->fAmountCaptured = $this->getMollie()->amountCaptured->value; + } + $this->getModel()->cMode = $this->getMollie()->mode ?: null; + $this->getModel()->cRedirectURL = $this->getMollie()->redirectUrl; + $this->getModel()->cWebhookURL = $this->getMollie()->webhookUrl; + $this->getModel()->cCheckoutURL = $this->getMollie()->getCheckoutUrl(); + } + + $this->getModel()->kBestellung = $this->getBestellung()->kBestellung; + $this->getModel()->cOrderNumber = $this->getBestellung()->cBestellNr; + $this->getModel()->cHash = trim($this->getHash(), '_'); + + $this->getModel()->bSynced = $this->getModel()->bSynced !== null ? $this->getModel()->bSynced : Helper::getSetting('onlyPaid') !== 'Y'; + return $this; + } + + /** + * @param false $force + * @return Order|\Mollie\Api\Resources\Payment|null + */ + abstract public function getMollie($force = false); + + /** + * @return stdClass + */ + abstract public function getIncomingPayment(); + + /** + * @param Bestellung $oBestellung + * @param Payment $model + * @return bool + */ + public static function makeFetchable(Bestellung $oBestellung, Payment $model) + { + // TODO: force ? + if ($oBestellung->cAbgeholt === 'Y' && !$model->bSynced) { + Shop::DB()->update('tbestellung', 'kBestellung', $oBestellung->kBestellung, (object)['cAbgeholt' => 'N']); + } + $model->bSynced = true; + try { + return $model->save(); + } catch (Exception $e) { + Jtllog::writeLog(sprintf("Fehler beim speichern des Models: %s / Bestellung: %s", $model->kID, $oBestellung->cBestellNr)); + } + return false; + } + + public function Log($msg, $level = LOGLEVEL_NOTICE) + { + try { + $data = ''; + if ($this->getBestellung()) { + $data .= '#' . $this->getBestellung()->kBestellung; + } + if ($this->getMollie()) { + $data .= '$' . $this->getMollie()->id; + } + ZahlungsLog::add($this->PaymentMethod()->moduleID, "[" . microtime(true) . " - " . $_SERVER['PHP_SELF'] . "] " . $msg, $data, $level); + } catch (Exception $e) { + Jtllog::writeLog('Mollie Log failed: ' . $e->getMessage() . '; Previous Log: ' . print_r([$msg, $level, $data], 1)); + } + return $this; + } + + /** + * @return bool + */ + public function completlyPaid() + { + + if ($row = Shop::DB()->executeQueryPrepared("SELECT SUM(fBetrag) as fBetragSumme FROM tzahlungseingang WHERE kBestellung = :kBestellung", [ + ':kBestellung' => $this->getBestellung()->kBestellung + ], 1)) { + return $row->fBetragSumme >= round($this->getBestellung()->fGesamtsumme * $this->getBestellung()->fWaehrungsFaktor, 2); + } + return false; + + } + + /** + * @param $kBestellung + * @return OrderCheckout|PaymentCheckout + * * @throws RuntimeException + */ + public static function fromBestellung($kBestellung) + { + if ($model = Payment::fromID($kBestellung, 'kBestellung')) { + return static::fromModel($model); + } + throw new RuntimeException(sprintf('Error loading Order for Bestellung: %s', $kBestellung)); + } + + public static function sendReminders() + { + $reminder = (int)self::Plugin()->oPluginEinstellungAssoc_arr['reminder']; + + if (!$reminder) { + return; + } + + $sql = "SELECT p.kID FROM xplugin_ws_mollie_payments p JOIN tbestellung b ON b.kBestellung = p.kBestellung " + . "WHERE (p.dReminder IS NULL OR p.dReminder = '0000-00-00 00:00:00') " + . "AND p.dCreatedAt < NOW() - INTERVAL :d MINUTE AND p.dCreatedAt > NOW() - INTERVAL 7 DAY " + . "AND p.cStatus IN ('created','open', 'expired', 'failed', 'canceled') AND NOT b.cStatus = '-1'"; + + $remindables = Shop::DB()->executeQueryPrepared($sql, [ + ':d' => $reminder + ], 2); + foreach ($remindables as $remindable) { + try { + self::sendReminder($remindable->kID); + } catch (Exception $e) { + Jtllog::writeLog("AbstractCheckout::sendReminders: " . $e->getMessage()); + } + } + } + + /** + * @param $kID + * @return bool + */ + public static function sendReminder($kID) + { + + $checkout = self::fromID($kID); + $return = true; + try { + $repayURL = Shop::getURL() . '/?m_pay=' . md5($checkout->getModel()->kID . '-' . $checkout->getBestellung()->kBestellung); + + $data = new stdClass(); + $data->tkunde = new Kunde($checkout->getBestellung()->oKunde->kKunde); + if ($data->tkunde->kKunde) { + + $data->Bestellung = $checkout->getBestellung(); + $data->PayURL = $repayURL; + $data->Amount = gibPreisStringLocalized($checkout->getModel()->fAmount, $checkout->getBestellung()->Waehrung); //Preise::getLocalizedPriceString($order->getAmount(), Currency::fromISO($order->getCurrency()), false); + + require_once PFAD_ROOT . PFAD_INCLUDES . 'mailTools.php'; + + $mail = new stdClass(); + $mail->toEmail = $data->tkunde->cMail; + $mail->toName = trim((isset($data->tKunde->cVorname) + ? $data->tKunde->cVorname + : '') . ' ' . ( + isset($data->tKunde->cNachname) + ? $data->tKunde->cNachname + : '' + )) ?: $mail->toEmail; + $data->mail = $mail; + if (!($sentMail = sendeMail('kPlugin_' . self::Plugin()->kPlugin . '_zahlungserinnerung', $data))) { + $checkout->Log(sprintf("Zahlungserinnerung konnte nicht versand werden: %s\n%s", isset($sentMail->cFehler) ?: print_r($sentMail, 1), print_r($data, 1)), LOGLEVEL_ERROR); + $return = false; + } else { + $checkout->Log(sprintf("Zahlungserinnerung für %s verschickt.", $checkout->getBestellung()->cBestellNr)); + } + } else { + $checkout->Log("Kunde '{$checkout->getBestellung()->oKunde->kKunde}' nicht gefunden.", LOGLEVEL_ERROR); + } + } catch (Exception $e) { + $checkout->Log(sprintf("AbstractCheckout::sendReminder: Zahlungserinnerung für %s fehlgeschlagen: %s", $checkout->getBestellung()->cBestellNr, $e->getMessage())); + $return = false; + } + $checkout->getModel()->dReminder = date('Y-m-d H:i:s'); + $checkout->getModel()->save(); + return $return; + } + + /** + * @param AbstractCheckout $checkout + * @return BaseResource|Refund + * @throws ApiException + */ + public static function refund(AbstractCheckout $checkout) + { + if ($checkout->getMollie()->resource === 'order') { + /** @var Order $order */ + $order = $checkout->getMollie(); + if (in_array($order->status, [OrderStatus::STATUS_CANCELED, OrderStatus::STATUS_EXPIRED, OrderStatus::STATUS_CREATED], true)) { + throw new RuntimeException('Bestellung kann derzeit nicht zurückerstattet werden.'); + } + $refund = $order->refundAll(); + $checkout->Log(sprintf('Bestellung wurde manuell zurückerstattet: %s', $refund->id)); + return $refund; + } + if ($checkout->getMollie()->resource === 'payment') { + /** @var \Mollie\Api\Resources\Payment $payment */ + $payment = $checkout->getMollie(); + if (in_array($payment->status, [PaymentStatus::STATUS_CANCELED, PaymentStatus::STATUS_EXPIRED, PaymentStatus::STATUS_OPEN], true)) { + throw new RuntimeException('Zahlung kann derzeit nicht zurückerstattet werden.'); + } + $refund = $checkout->API()->Client()->payments->refund($checkout->getMollie(), ['amount' => $checkout->getMollie()->amount]); + $checkout->Log(sprintf('Zahlung wurde manuell zurückerstattet: %s', $refund->id)); + return $refund; + } + throw new RuntimeException(sprintf('Unbekannte Resource: %s', $checkout->getMollie()->resource)); + } + + /** + * @return API + */ + public function API() + { + if (!$this->api) { + if ($this->getModel()->kID) { + $this->api = new API($this->getModel()->cMode === 'test'); + } else { + $this->api = new API(API::getMode()); + } + } + return $this->api; + } + + /** + * @param $checkout + * @return Order|\Mollie\Api\Resources\Payment + * @throws ApiException + */ + public static function cancel($checkout) + { + if ($checkout instanceof OrderCheckout) { + return OrderCheckout::cancel($checkout); + } + if ($checkout instanceof PaymentCheckout) { + return PaymentCheckout::cancel($checkout); + } + throw new RuntimeException('AbstractCheckout::cancel: Invalid Checkout!'); + } + + 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[] = static::getLocale($sS->cISO, $land); + } + } + return array_intersect(array_unique($result), $locales); + } + + public static function getLocale($cISOSprache = null, $country = null) + { + + if ($cISOSprache === null) { + $cISOSprache = gibStandardsprache()->cISO; + } + if (array_key_exists($cISOSprache, self::$localeLangs)) { + $locale = self::$localeLangs[$cISOSprache]['lang']; + if ($country && is_array(self::$localeLangs[$cISOSprache]['country']) && in_array($country, self::$localeLangs[$cISOSprache]['country'], true)) { + $locale .= '_' . strtoupper($country); + } else { + $locale .= '_' . self::$localeLangs[$cISOSprache]['country'][0]; + } + return $locale; + } + + return self::Plugin()->oPluginEinstellungAssoc_arr['fallbackLocale']; + } + + 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; + } + + public function loadRequest(&$options = []) + { + + $oKunde = !$this->getBestellung()->oKunde && $this->PaymentMethod()->duringCheckout ? $_SESSION['Kunde'] : $this->getBestellung()->oKunde; + if ($this->getBestellung()) { + if ($oKunde->nRegistriert + && ($customer = $this->getCustomer( + array_key_exists( + 'mollie_create_customer', + $_SESSION['cPost_arr'] ?: []) && $_SESSION['cPost_arr']['mollie_create_customer'] === 'Y', + $oKunde) + ) + && isset($customer)) { + $options['customerId'] = $customer->id; + } + $this->amount = Amount::factory($this->getBestellung()->fGesamtsummeKundenwaehrung, $this->getBestellung()->Waehrung->cISO, true); + $this->redirectUrl = $this->PaymentMethod()->duringCheckout ? Shop::getURL() . '/bestellabschluss.php?' . http_build_query(['hash' => $this->getHash()]) : $this->PaymentMethod()->getReturnURL($this->getBestellung()); + $this->metadata = [ + 'kBestellung' => $this->getBestellung()->kBestellung ?: $this->getBestellung()->cBestellNr, + 'kKunde' => $this->getBestellung()->kKunde, + 'kKundengruppe' => Session::getInstance()->CustomerGroup()->kKundengruppe, + 'cHash' => $this->getHash(), + ]; + } + + $this->locale = self::getLocale($_SESSION['cISOSprache'], Session::getInstance()->Customer()->cLand); + $this->webhookUrl = Shop::getURL(true) . '/?' . http_build_query([ + 'mollie' => 1, + 'hash' => $this->getHash(), + 'test' => $this->API()->isTest() ?: null, + ]); + + $pm = $this->PaymentMethod(); + $isPayAgain = strpos($_SERVER['PHP_SELF'], 'bestellab_again') !== false; + if ($pm::METHOD !== '' && (self::Plugin()->oPluginEinstellungAssoc_arr['resetMethod'] !== 'Y' || !$isPayAgain)) { + $this->method = $pm::METHOD; + } + + } + + /** + * @return \Mollie\Api\Resources\Customer|null + * @todo: Kunde wieder löschbar machen ?! + */ + public function getCustomer($createOrUpdate = false, $oKunde = null) + { + + if (!$oKunde) { + $oKunde = $this->getBestellung()->oKunde; + } + + if (!$this->customer) { + $customerModel = Customer::fromID($oKunde->kKunde, 'kKunde'); + if ($customerModel->customerId) { + try { + $this->customer = $this->API()->Client()->customers->get($customerModel->customerId); + } catch (ApiException $e) { + $this->Log(sprintf("Fehler beim laden des Mollie Customers %s (kKunde: %d): %s", $customerModel->customerId, $customerModel->kKunde, $e->getMessage()), LOGLEVEL_ERROR); + } + } + + if ($createOrUpdate) { + $customer = [ + 'name' => utf8_encode(trim($oKunde->cVorname . ' ' . $oKunde->cNachname)), + 'email' => utf8_encode($oKunde->cMail), + 'locale' => self::getLocale($_SESSION['cISOSprache'], $oKunde->cLand), + 'metadata' => (object)[ + 'kKunde' => $oKunde->kKunde, + 'kKundengruppe' => $oKunde->kKundengruppe, + 'cKundenNr' => utf8_encode($oKunde->cKundenNr), + ], + ]; + + if ($this->customer) { // UPDATE + + $this->customer->name = $customer['name']; + $this->customer->email = $customer['email']; + $this->customer->locale = $customer['locale']; + $this->customer->metadata = $customer['metadata']; + + try { + $this->customer->update(); + } catch (Exception $e) { + $this->Log(sprintf("Fehler beim aktualisieren des Mollie Customers %s: %s\n%s", $this->customer->id, $e->getMessage(), print_r($customer, 1)), LOGLEVEL_ERROR); + } + + + } else { // create + + try { + $this->customer = $this->API()->Client()->customers->create($customer); + $customerModel->kKunde = $oKunde->kKunde; + $customerModel->customerId = $this->customer->id; + $customerModel->save(); + $this->Log(sprintf("Customer '%s' für Kunde %s (%d) bei Mollie angelegt.", $this->customer->id, $this->customer->name, $this->getBestellung()->kKunde)); + } catch (Exception $e) { + $this->Log(sprintf("Fehler beim anlegen eines Mollie Customers: %s\n%s", $e->getMessage(), print_r($customer, 1)), LOGLEVEL_ERROR); + } + } + } + } + return $this->customer; + } + + /** + * Storno Order + */ + public function storno() + { + if (in_array((int)$this->getBestellung()->cStatus, [BESTELLUNG_STATUS_OFFEN, BESTELLUNG_STATUS_IN_BEARBEITUNG], true)) { + + $log = []; + + $conf = Shop::getSettings([CONF_GLOBAL, CONF_TRUSTEDSHOPS]); + $nArtikelAnzeigefilter = (int)$conf['global']['artikel_artikelanzeigefilter']; + + foreach ($this->getBestellung()->Positionen as $pos) { + if ($pos->kArtikel && $pos->Artikel && $pos->Artikel->cLagerBeachten === 'Y') { + $log[] = sprintf('Reset stock of "%s" by %d', $pos->Artikel->cArtNr, -1 * $pos->nAnzahl); + self::aktualisiereLagerbestand($pos->Artikel, -1 * $pos->nAnzahl, $pos->WarenkorbPosEigenschaftArr, $nArtikelAnzeigefilter); + } + } + $log[] = sprintf("Cancel order '%s'.", $this->getBestellung()->cBestellNr); + + if (Shop::DB()->executeQueryPrepared('UPDATE tbestellung SET cAbgeholt = \'Y\', cStatus = :cStatus WHERE kBestellung = :kBestellung', [':cStatus' => '-1', ':kBestellung' => $this->getBestellung()->kBestellung], 3)) { + $this->Log(implode('\n', $log)); + } + } + } + + protected static function aktualisiereLagerbestand($Artikel, $nAnzahl, $WarenkorbPosEigenschaftArr, $nArtikelAnzeigefilter = 1) + { + $artikelBestand = (float)$Artikel->fLagerbestand; + + if (isset($Artikel->cLagerBeachten) && $Artikel->cLagerBeachten === 'Y') { + if ($Artikel->cLagerVariation === 'Y' && + is_array($WarenkorbPosEigenschaftArr) && + count($WarenkorbPosEigenschaftArr) > 0 + ) { + foreach ($WarenkorbPosEigenschaftArr as $eWert) { + $EigenschaftWert = new EigenschaftWert($eWert->kEigenschaftWert); + if ($EigenschaftWert->fPackeinheit === .0) { + $EigenschaftWert->fPackeinheit = 1; + } + Shop::DB()->query( + "UPDATE teigenschaftwert + SET fLagerbestand = fLagerbestand - " . ($nAnzahl * $EigenschaftWert->fPackeinheit) . " + WHERE kEigenschaftWert = " . (int)$eWert->kEigenschaftWert, 4 + ); + } + } elseif ($Artikel->fPackeinheit > 0) { + // Stückliste + if ($Artikel->kStueckliste > 0) { + $artikelBestand = self::aktualisiereStuecklistenLagerbestand($Artikel, $nAnzahl); + } else { + Shop::DB()->query( + "UPDATE tartikel + SET fLagerbestand = IF (fLagerbestand >= " . ($nAnzahl * $Artikel->fPackeinheit) . ", + (fLagerbestand - " . ($nAnzahl * $Artikel->fPackeinheit) . "), fLagerbestand) + WHERE kArtikel = " . (int)$Artikel->kArtikel, 4 + ); + $tmpArtikel = Shop::DB()->select('tartikel', 'kArtikel', (int)$Artikel->kArtikel, null, null, null, null, false, 'fLagerbestand'); + if ($tmpArtikel !== null) { + $artikelBestand = (float)$tmpArtikel->fLagerbestand; + } + // Stücklisten Komponente + if (ArtikelHelper::isStuecklisteKomponente($Artikel->kArtikel)) { + self::aktualisiereKomponenteLagerbestand($Artikel->kArtikel, $artikelBestand, isset($Artikel->cLagerKleinerNull) && $Artikel->cLagerKleinerNull === 'Y'); + } + } + // Aktualisiere Merkmale in tartikelmerkmal vom Vaterartikel + if ($Artikel->kVaterArtikel > 0) { + Artikel::beachteVarikombiMerkmalLagerbestand($Artikel->kVaterArtikel, $nArtikelAnzeigefilter); + } + } + } + + return $artikelBestand; + } + + protected static function aktualisiereStuecklistenLagerbestand($oStueckListeArtikel, $nAnzahl) + { + $nAnzahl = (float)$nAnzahl; + $kStueckListe = (int)$oStueckListeArtikel->kStueckliste; + $bestandAlt = (float)$oStueckListeArtikel->fLagerbestand; + $bestandNeu = $bestandAlt; + $bestandUeberverkauf = $bestandAlt; + + if ($nAnzahl > 0) { + // Gibt es lagerrelevante Komponenten in der Stückliste? + $oKomponente_arr = Shop::DB()->query( + "SELECT tstueckliste.kArtikel, tstueckliste.fAnzahl + FROM tstueckliste + JOIN tartikel + ON tartikel.kArtikel = tstueckliste.kArtikel + WHERE tstueckliste.kStueckliste = $kStueckListe + AND tartikel.cLagerBeachten = 'Y'", 2 + ); + + if (is_array($oKomponente_arr) && count($oKomponente_arr) > 0) { + // wenn ja, dann wird für diese auch der Bestand aktualisiert + $options = Artikel::getDefaultOptions(); + + $options->nKeineSichtbarkeitBeachten = 1; + + foreach ($oKomponente_arr as $oKomponente) { + $tmpArtikel = new Artikel(); + $tmpArtikel->fuelleArtikel($oKomponente->kArtikel, $options); + + $komponenteBestand = floor(self::aktualisiereLagerbestand($tmpArtikel, $nAnzahl * $oKomponente->fAnzahl, null) / $oKomponente->fAnzahl); + + if ($komponenteBestand < $bestandNeu && $tmpArtikel->cLagerKleinerNull !== 'Y') { + // Neuer Bestand ist der Kleinste Komponententbestand aller Artikel ohne Überverkauf + $bestandNeu = $komponenteBestand; + } elseif ($komponenteBestand < $bestandUeberverkauf) { + // Für Komponenten mit Überverkauf wird der kleinste Bestand ermittelt. + $bestandUeberverkauf = $komponenteBestand; + } + } + } + + // Ist der alte gleich dem neuen Bestand? + if ($bestandAlt === $bestandNeu) { + // Es sind keine lagerrelevanten Komponenten vorhanden, die den Bestand der Stückliste herabsetzen. + if ($bestandUeberverkauf === $bestandNeu) { + // Es gibt auch keine Komponenten mit Überverkäufen, die den Bestand verringern, deshalb wird + // der Bestand des Stücklistenartikels anhand des Verkaufs verringert + $bestandNeu = $bestandNeu - $nAnzahl * $oStueckListeArtikel->fPackeinheit; + } else { + // Da keine lagerrelevanten Komponenten vorhanden sind, wird der kleinste Bestand der + // Komponentent mit Überverkauf verwendet. + $bestandNeu = $bestandUeberverkauf; + } + + Shop::DB()->update('tartikel', 'kArtikel', (int)$oStueckListeArtikel->kArtikel, (object)[ + 'fLagerbestand' => $bestandNeu, + ]); + } + // Kein Lagerbestands-Update für die Stückliste notwendig! Dies erfolgte bereits über die Komponentenabfrage und + // die dortige Lagerbestandsaktualisierung! + } + + return $bestandNeu; + } + + protected static function aktualisiereKomponenteLagerbestand($kKomponenteArtikel, $fLagerbestand, $bLagerKleinerNull) + { + $kKomponenteArtikel = (int)$kKomponenteArtikel; + $fLagerbestand = (float)$fLagerbestand; + + $oStueckliste_arr = Shop::DB()->query( + "SELECT tstueckliste.kStueckliste, tstueckliste.fAnzahl, + tartikel.kArtikel, tartikel.fLagerbestand, tartikel.cLagerKleinerNull + FROM tstueckliste + JOIN tartikel + ON tartikel.kStueckliste = tstueckliste.kStueckliste + WHERE tstueckliste.kArtikel = $kKomponenteArtikel + AND tartikel.cLagerBeachten = 'Y'", 2 + ); + + if (is_array($oStueckliste_arr) && count($oStueckliste_arr) > 0) { + foreach ($oStueckliste_arr as $oStueckliste) { + // Ist der aktuelle Bestand der Stückliste größer als dies mit dem Bestand der Komponente möglich wäre? + $maxAnzahl = floor($fLagerbestand / $oStueckliste->fAnzahl); + if ($maxAnzahl < (float)$oStueckliste->fLagerbestand && (!$bLagerKleinerNull || $oStueckliste->cLagerKleinerNull === 'Y')) { + // wenn ja, dann den Bestand der Stückliste entsprechend verringern, aber nur wenn die Komponente nicht + // überberkaufbar ist oder die gesamte Stückliste Überverkäufe zulässt + Shop::DB()->update('tartikel', 'kArtikel', (int)$oStueckliste->kArtikel, (object)[ + 'fLagerbestand' => $maxAnzahl, + ]); + } + } + } + } + + /** + * @return array|bool|int|object|null + */ + public function getLogs() + { + return 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' => '%#' . ($this->getBestellung()->kBestellung ?: '##') . '%', + ':cBestellNr' => '%§' . ($this->getBestellung()->cBestellNr ?: '§§') . '%', + ':MollieID' => '%$' . ($this->getMollie()->id ?: '$$') . '%', + ], 2); + } + + /** + * @return bool + */ + public function remindable() + { + return (int)$this->getBestellung()->cStatus !== BESTELLUNG_STATUS_STORNO && !in_array($this->getModel()->cStatus, [PaymentStatus::STATUS_PAID, PaymentStatus::STATUS_AUTHORIZED, PaymentStatus::STATUS_PENDING, OrderStatus::STATUS_COMPLETED, OrderStatus::STATUS_SHIPPING], true); + } + + /** + * @return string + */ + public function LogData() + { + + $data = ''; + if ($this->getBestellung()->kBestellung) { + $data .= '#' . $this->getBestellung()->kBestellung; + } + if ($this->getMollie()) { + $data .= '$' . $this->getMollie()->id; + } + + return $data; + } + + abstract public function cancelOrRefund($force = false); + + /** + * @param array $paymentOptions + * @return Payment|Order + */ + abstract public function create(array $paymentOptions = []); + + /** + * @return string + */ + public function getRepayURL() + { + return Shop::getURL(true) . '/?m_pay=' . md5($this->getModel()->kID . '-' . $this->getBestellung()->kBestellung); + } + + abstract protected function updateOrderNumber(); + + /** + * @param Bestellung $oBestellung + * @return $this + */ + protected function setBestellung(Bestellung $oBestellung) + { + $this->oBestellung = $oBestellung; + return $this; + } + + /** + * @param Order|\Mollie\Api\Resources\Payment $model + * @return self + */ + abstract protected function setMollie($model); + + +} \ No newline at end of file diff --git a/version/205/class/Checkout/AbstractResource.php b/version/205/class/Checkout/AbstractResource.php new file mode 100644 index 0000000..7ca9813 --- /dev/null +++ b/version/205/class/Checkout/AbstractResource.php @@ -0,0 +1,18 @@ +title = trim(($address->cAnrede === 'm' ? Shop::Lang()->get('mr') : Shop::Lang()->get('mrs')) . ' ' . $address->cTitel) ?: null; + $resource->givenName = $address->cVorname; + $resource->familyName = $address->cNachname; + $resource->email = $address->cMail ?: null; + + if ($organizationName = trim($address->cFirma)) { + $resource->organizationName = $organizationName; + } + + // Validity-Check + // TODO: Phone, with E.164 check + // TODO: Is Email-Format Check needed? + if (!$resource->givenName || !$resource->familyName || !$resource->email) { + throw ResourceValidityException::trigger(ResourceValidityException::ERROR_REQUIRED, ['givenName', 'familyName', 'email'], $resource); + } + return $resource; + } + +} \ No newline at end of file diff --git a/version/205/class/Checkout/Order/OrderLine.php b/version/205/class/Checkout/Order/OrderLine.php new file mode 100644 index 0000000..1c88bb1 --- /dev/null +++ b/version/205/class/Checkout/Order/OrderLine.php @@ -0,0 +1,230 @@ +totalAmount->value; + } + if (abs($sum - (float)$amount->value) > 0) { + $diff = (round((float)$amount->value - $sum, 2)); + if ($diff !== 0.0) { + $line = new self(); + $line->type = $diff > 0 ? OrderLineType::TYPE_SURCHARGE : OrderLineType::TYPE_DISCOUNT; + // TODO: Translation needed? + $line->name = 'Rundungsausgleich'; + $line->quantity = 1; + $line->unitPrice = Amount::factory($diff, $currency); + $line->totalAmount = Amount::factory($diff, $currency); + $line->vatRate = "0.00"; + $line->vatAmount = Amount::factory(0, $currency); + return $line; + } + } + return null; + } + + /** + * @param Bestellung $oBestellung + * @return OrderLine + */ + public static function getCredit(Bestellung $oBestellung) + { + $line = new self(); + $line->type = OrderLineType::TYPE_STORE_CREDIT; + $line->name = 'Guthaben'; + $line->quantity = 1; + // TODO: check currency of Guthaben + $line->unitPrice = Amount::factory($oBestellung->fGuthaben, $oBestellung->Waehrung->cISO); + $line->totalAmount = $line->unitPrice; + $line->vatRate = "0.00"; + $line->vatAmount = Amount::factory(0, $oBestellung->Waehrung->cISO); + + return $line; + } + + /** + * @param stdClass|WarenkorbPos $oPosition + * @param null $currency + * @return OrderLine + */ + public static function factory($oPosition, $currency = null) + { + if (!$oPosition) { + throw new RuntimeException('$oPosition invalid:', print_r($oPosition, 1)); + } + + $resource = new static(); + + $resource->fill($oPosition, $currency); + + // Validity Check + if (!$resource->name || !$resource->quantity || !$resource->unitPrice || !$resource->totalAmount + || !$resource->vatRate || !$resource->vatAmount) { + throw ResourceValidityException::trigger(ResourceValidityException::ERROR_REQUIRED, + ['name', 'quantity', 'unitPrice', 'totalAmount', 'vatRate', 'vatAmount'], $resource); + } + + return $resource; + + } + + /** + * @param WarenkorbPos|stdClass $oPosition + * @param null|stdClass $currency + * @return $this + * @todo Setting for Fraction handling needed? + */ + protected function fill($oPosition, $currency = null) + { + + if (!$currency) { + $currency = Amount::FallbackCurrency(); + } + + $isKupon = (int)$oPosition->nPosTyp === (int)C_WARENKORBPOS_TYP_KUPON; + $isFrac = fmod($oPosition->nAnzahl, 1) !== 0.0; + + // Kupon? set vatRate to 0 and adjust netto + $vatRate = $isKupon ? 0 : (float)$oPosition->fMwSt / 100; + $netto = $isKupon ? round($oPosition->fPreis * (1 + $vatRate), 4) : round($oPosition->fPreis, 4); + + // Fraction? transform, as it were 1, and set quantity to 1 + $netto = round(($isFrac ? $netto * (float)$oPosition->nAnzahl : $netto) * $currency->fFaktor, 4); + $this->quantity = $isFrac ? 1 : (int)$oPosition->nAnzahl; + + // Fraction? include quantity and unit in name + $this->name = $isFrac ? sprintf("%s (%.2f %s)", $oPosition->cName, (float)$oPosition->nAnzahl, $oPosition->cEinheit) : $oPosition->cName; + if (!$this->name) { + $this->name = '(null)'; + } + $this->mapType($oPosition->nPosTyp, $netto > 0); + + //$unitPriceNetto = round(($currency->fFaktor * $netto), 4); + + $this->unitPrice = Amount::factory(round($netto * (1 + $vatRate), 2), $currency->cISO, false); + $this->totalAmount = Amount::factory(round($this->quantity * $this->unitPrice->value, 2), $currency->cISO, false); + + $this->vatRate = number_format($vatRate * 100, 2); + $this->vatAmount = Amount::factory(round($this->totalAmount->value - ($this->totalAmount->value / (1 + $vatRate)), 2), $currency->cISO, false); + + $metadata = []; + + // Is Artikel ? + if (isset($oPosition->Artikel)) { + $this->sku = $oPosition->Artikel->cArtNr; + $metadata['kArtikel'] = $oPosition->kArtikel; + if ($oPosition->cUnique !== '') { + $metadata['cUnique'] = utf8_encode($oPosition->cUnique); + } + } + + if (isset($oPosition->WarenkorbPosEigenschaftArr) && is_array($oPosition->WarenkorbPosEigenschaftArr) && count($oPosition->WarenkorbPosEigenschaftArr)) { + $metadata['properties'] = []; + /** @var WarenkorbPosEigenschaft $warenkorbPosEigenschaft */ + foreach ($oPosition->WarenkorbPosEigenschaftArr as $warenkorbPosEigenschaft) { + $metadata['properties'][] = [ + 'kEigenschaft' => $warenkorbPosEigenschaft->kEigenschaft, + 'kEigenschaftWert' => $warenkorbPosEigenschaft->kEigenschaftWert, + 'name' => utf8_encode($warenkorbPosEigenschaft->cEigenschaftName), + 'value' => utf8_encode($warenkorbPosEigenschaft->cEigenschaftWertName), + ]; + if (strlen(json_encode($metadata)) > 1000) { + array_pop($metadata['properties']); + break; + } + } + + } + if (json_encode($metadata) !== false) { + $this->metadata = $metadata; + } + + return $this; + + + } + + /** + * @param $nPosTyp + * @param $positive + * @return OrderLine + */ + protected function mapType($nPosTyp, $positive) + { + switch ($nPosTyp) { + case C_WARENKORBPOS_TYP_ARTIKEL: + case C_WARENKORBPOS_TYP_GRATISGESCHENK: + // TODO: digital / Download Artikel? + $this->type = OrderLineType::TYPE_PHYSICAL; + return $this; + + case C_WARENKORBPOS_TYP_VERSANDPOS: + $this->type = OrderLineType::TYPE_SHIPPING_FEE; + return $this; + + case C_WARENKORBPOS_TYP_GUTSCHEIN: + case C_WARENKORBPOS_TYP_KUPON: + case C_WARENKORBPOS_TYP_NEUKUNDENKUPON: + $this->type = OrderLineType::TYPE_DISCOUNT; + return $this; + + case C_WARENKORBPOS_TYP_VERPACKUNG: + case C_WARENKORBPOS_TYP_VERSANDZUSCHLAG: + case C_WARENKORBPOS_TYP_ZAHLUNGSART: + case C_WARENKORBPOS_TYP_VERSAND_ARTIKELABHAENGIG: + case C_WARENKORBPOS_TYP_NACHNAHMEGEBUEHR: + $this->type = OrderLineType::TYPE_SURCHARGE; + return $this; + + default: + $this->type = $positive ? OrderLineType::TYPE_SURCHARGE : OrderLineType::TYPE_DISCOUNT; + return $this; + + } + } + +} \ No newline at end of file diff --git a/version/205/class/Checkout/OrderCheckout.php b/version/205/class/Checkout/OrderCheckout.php new file mode 100644 index 0000000..253e109 --- /dev/null +++ b/version/205/class/Checkout/OrderCheckout.php @@ -0,0 +1,371 @@ +getMollie()->status !== OrderStatus::STATUS_AUTHORIZED && $checkout->getMollie()->status !== OrderStatus::STATUS_SHIPPING) { + throw new RuntimeException('Nur autorisierte Zahlungen können erfasst werden!'); + } + $shipment = $checkout->API()->Client()->shipments->createFor($checkout->getMollie(), ['lines' => []]); + $checkout->Log(sprintf('Bestellung wurde manuell erfasst/versandt: %s', $shipment->id)); + return $shipment->id; + } + + /** + * @param false $force + * @return Order|null + */ + public function getMollie($force = false) + { + if ($force || (!$this->order && $this->getModel()->kID)) { + try { + $this->order = $this->API()->Client()->orders->get($this->getModel()->kID, ['embed' => 'payments,shipments,refunds']); + } catch (Exception $e) { + throw new RuntimeException(sprintf('Mollie-Order \'%s\' konnte nicht geladen werden: %s', $this->getModel()->kID, $e->getMessage())); + } + } + return $this->order; + } + + /** + * @param OrderCheckout $checkout + * @return Order + * @throws ApiException + */ + public static function cancel($checkout) + { + if (!$checkout->getMollie() || !$checkout->getMollie()->isCancelable) { + throw new RuntimeException('Bestellung kann nicht abgebrochen werden.'); + } + $order = $checkout->getMollie()->cancel(); + $checkout->Log('Bestellung wurde manuell abgebrochen.'); + return $order; + } + + /** + * @return array + * @throws Exception + */ + public function getShipments() + { + $shipments = []; + $lieferschien_arr = Shop::DB()->executeQueryPrepared("SELECT kLieferschein FROM tlieferschein WHERE kInetBestellung = :kBestellung", [ + ':kBestellung' => $this->getBestellung()->kBestellung + ], 2); + + foreach ($lieferschien_arr as $lieferschein) { + $shipments[] = new Shipment($lieferschein->kLieferschein, $this); + } + return $shipments; + } + + /** + * @return string + * @throws ApiException + */ + public function cancelOrRefund($force = false) + { + if (!$this->getMollie()) { + throw new RuntimeException('Mollie-Order konnte nicht geladen werden: ' . $this->getModel()->kID); + } + if ($force || (int)$this->getBestellung()->cStatus === BESTELLUNG_STATUS_STORNO) { + if ($this->getMollie()->isCancelable) { + $res = $this->getMollie()->cancel(); + $result = 'Order cancelled, Status: ' . $res->status; + } else { + $res = $this->getMollie()->refundAll(); + $result = "Order Refund initiiert, Status: " . $res->status; + } + $this->PaymentMethod()->Log("OrderCheckout::cancelOrRefund: " . $result, $this->LogData()); + return $result; + } + throw new RuntimeException('Bestellung ist derzeit nicht storniert, Status: ' . $this->getBestellung()->cStatus); + } + + /** + * @param array $paymentOptions + * @return Order + */ + public function create(array $paymentOptions = []) + { + if ($this->getModel()->kID) { + try { + $this->order = $this->API()->Client()->orders->get($this->getModel()->kID, ['embed' => 'payments']); + if (in_array($this->order->status, [OrderStatus::STATUS_COMPLETED, OrderStatus::STATUS_PAID, OrderStatus::STATUS_AUTHORIZED, OrderStatus::STATUS_PENDING], true)) { + $this->handleNotification(); + throw new RuntimeException(self::Plugin()->oPluginSprachvariableAssoc_arr['errAlreadyPaid']); + } + if ($this->order->status === OrderStatus::STATUS_CREATED) { + if ($this->order->payments()) { + /** @var Payment $payment */ + foreach ($this->order->payments() as $payment) { + if ($payment->status === PaymentStatus::STATUS_OPEN) { + $this->setPayment($payment); + break; + } + } + } + if (!$this->getPayment()) { + $this->setPayment($this->API()->Client()->orderPayments->createForId($this->getModel()->kID, $paymentOptions)); + } + $this->updateModel()->saveModel(); + return $this->getMollie(true); + } + } catch (RuntimeException $e) { + throw $e; + } catch (Exception $e) { + $this->Log(sprintf("OrderCheckout::create: Letzte Order '%s' konnte nicht geladen werden: %s, versuche neue zu erstellen.", $this->getModel()->kID, $e->getMessage()), LOGLEVEL_ERROR); + } + } + + try { + $req = $this->loadRequest($paymentOptions)->jsonSerialize(); + $this->order = $this->API()->Client()->orders->create($req); + $this->Log(sprintf("Order für '%s' wurde erfolgreich angelegt: %s", $this->getBestellung()->cBestellNr, $this->order->id)); + $this->updateModel()->saveModel(); + return $this->order; + } catch (Exception $e) { + $this->Log(sprintf("OrderCheckout::create: Neue Order '%s' konnte nicht erstellt werden: %s.", $this->getBestellung()->cBestellNr, $e->getMessage()), LOGLEVEL_ERROR); + throw new RuntimeException(sprintf("Order für '%s' konnte nicht angelegt werden: %s", $this->getBestellung()->cBestellNr, $e->getMessage())); + } + } + + /** + * @return Payment|null + */ + public function getPayment($search = false) + { + if (!$this->_payment && $search && $this->getMollie()) { + foreach ($this->getMollie()->payments() as $payment) { + if (in_array($payment->status, [ + PaymentStatus::STATUS_AUTHORIZED, + PaymentStatus::STATUS_PAID, + PaymentStatus::STATUS_PENDING, + ], true)) { + $this->_payment = $payment; + break; + } + } + } + return $this->_payment; + } + + /** + * @param $payment + * @return $this + */ + public function setPayment($payment) + { + $this->_payment = $payment; + return $this; + } + + /** + * @return $this|OrderCheckout + */ + public function updateModel() + { + parent::updateModel(); + + if (!$this->getPayment() && $this->getMollie() && $this->getMollie()->payments()) { + /** @var Payment $payment */ + foreach ($this->getMollie()->payments() as $payment) { + if (in_array($payment->status, [PaymentStatus::STATUS_OPEN, PaymentStatus::STATUS_PENDING, PaymentStatus::STATUS_AUTHORIZED, PaymentStatus::STATUS_PAID], true)) { + $this->setPayment($payment); + break; + } + } + } + if ($this->getPayment()) { + $this->getModel()->cTransactionId = $this->getPayment()->id; + } + if ($this->getMollie()) { + $this->getModel()->cCheckoutURL = $this->getMollie()->getCheckoutUrl(); + $this->getModel()->cWebhookURL = $this->getMollie()->webhookUrl; + $this->getModel()->cRedirectURL = $this->getMollie()->redirectUrl; + } + return $this; + } + + /** + * @param array $options + * @return $this|OrderCheckout + */ + public function loadRequest(&$options = []) + { + + parent::loadRequest($options); + + $this->orderNumber = $this->getBestellung()->cBestellNr; + + $this->billingAddress = Address::factory($this->getBestellung()->oRechnungsadresse); + if ($this->getBestellung()->Lieferadresse !== null) { + if (!$this->getBestellung()->Lieferadresse->cMail) { + $this->getBestellung()->Lieferadresse->cMail = $this->getBestellung()->oRechnungsadresse->cMail; + } + $this->shippingAddress = Address::factory($this->getBestellung()->Lieferadresse); + } + + if ( + !empty(Session::getInstance()->Customer()->dGeburtstag) + && Session::getInstance()->Customer()->dGeburtstag !== '0000-00-00' + && preg_match('/^\d{4}-\d{2}-\d{2}$/', trim(Session::getInstance()->Customer()->dGeburtstag)) + ) { + $this->consumerDateOfBirth = trim(Session::getInstance()->Customer()->dGeburtstag); + } + + $lines = []; + foreach ($this->getBestellung()->Positionen as $oPosition) { + $lines[] = OrderLine::factory($oPosition, $this->getBestellung()->Waehrung); + } + + if ($this->getBestellung()->GuthabenNutzen && $this->getBestellung()->fGuthaben > 0) { + $lines[] = OrderLine::getCredit($this->getBestellung()); + } + + if ($comp = OrderLine::getRoundingCompensation($lines, $this->amount, $this->getBestellung()->Waehrung->cISO)) { + $lines[] = $comp; + } + $this->lines = $lines; + + if ($dueDays = $this->PaymentMethod()->getExpiryDays()) { + try { + // #145 + //$max = $this->method && strpos($this->method, 'klarna') !== false ? 28 : 100; + $date = new DateTime(sprintf("+%d DAYS", $dueDays), new DateTimeZone('UTC')); + $this->expiresAt = $date->format('Y-m-d'); + } catch (Exception $e) { + $this->Log($e->getMessage(), LOGLEVEL_ERROR); + } + } + + $this->payment = $options; + + return $this; + } + + /** + * @return object|null + */ + public function getIncomingPayment() + { + if (!$this->getMollie(true)) { + return null; + } + + $cHinweis = sprintf("%s / %s", $this->getMollie()->id, $this->getPayment(true)->id); + if (Helper::getSetting('wawiPaymentID') === 'ord') { + $cHinweis = $this->getMollie()->id; + } else if (Helper::getSetting('wawiPaymentID') === 'tr') { + $cHinweis = $this->getPayment(true)->id; + } + + + /** @var Payment $payment */ + /** @noinspection NullPointerExceptionInspection */ + foreach ($this->getMollie()->payments() as $payment) { + if (in_array($payment->status, + [PaymentStatus::STATUS_AUTHORIZED, PaymentStatus::STATUS_PAID], true)) { + $this->setPayment($payment); + $data = (object)[ + 'fBetrag' => (float)$payment->amount->value, + 'cISO' => $payment->amount->currency, + 'cZahler' => $payment->details->paypalPayerId ?: $payment->customerId, + 'cHinweis' => $payment->details->paypalReference ?: $cHinweis, + ]; + if (isset($payment->details, $payment->details->paypalFee)) { + $data->fZahlungsgebuehr = $payment->details->paypalFee->value; + } + return $data; + } + } + return null; + } + + /** + * @return $this + */ + protected function updateOrderNumber() + { + try { + if ($this->getMollie()) { + $this->getMollie()->orderNumber = $this->getBestellung()->cBestellNr; + $this->getMollie()->webhookUrl = Shop::getURL() . '/?mollie=1'; + $this->getMollie()->update(); + } + } catch (Exception $e) { + $this->Log('OrderCheckout::updateOrderNumber:' . $e->getMessage(), LOGLEVEL_ERROR); + } + return $this; + } + + /** + * @param Order $model + * @return $this|AbstractCheckout + */ + protected function setMollie($model) + { + if ($model instanceof Order) { + $this->order = $model; + } + return $this; + } +} \ No newline at end of file diff --git a/version/205/class/Checkout/Payment/Address.php b/version/205/class/Checkout/Payment/Address.php new file mode 100644 index 0000000..ea460c1 --- /dev/null +++ b/version/205/class/Checkout/Payment/Address.php @@ -0,0 +1,54 @@ +streetAndNumber = $address->cStrasse . ' ' . $address->cHausnummer; + $resource->postalCode = $address->cPLZ; + $resource->city = $address->cOrt; + $resource->country = $address->cLand; + + if ( + isset($address->cAdressZusatz) + && trim($address->cAdressZusatz) !== '' + ) { + $resource->streetAdditional = trim($address->cAdressZusatz); + } + + // Validity-Check + // TODO: Check for valid Country Code? + // TODO: Check PostalCode requirement Country? + if (!$resource->streetAndNumber || !$resource->city || !$resource->country) { + throw ResourceValidityException::trigger(ResourceValidityException::ERROR_REQUIRED, ['streetAndNumber', 'city', 'country'], $resource); + } + + return $resource; + } + + +} \ No newline at end of file diff --git a/version/205/class/Checkout/Payment/Amount.php b/version/205/class/Checkout/Payment/Amount.php new file mode 100644 index 0000000..125829d --- /dev/null +++ b/version/205/class/Checkout/Payment/Amount.php @@ -0,0 +1,73 @@ + true [5 Rappen Rounding]) + * @return Amount + */ + public static function factory($value, $currency = null, $useRounding = false) + { + + if (!$currency) { + $currency = static::FallbackCurrency()->cISO; + } + + $resource = new static(); + + $resource->currency = $currency; + //$resource->value = number_format(round($useRounding ? $resource->round($value * (float)$currency->fFaktor) : $value * (float)$currency->fFaktor, 2), 2, '.', ''); + $resource->value = number_format(round($useRounding ? $resource->round($value) : $value, 2), 2, '.', ''); + + // Validity Check + // TODO: Check ISO Code? + // TODO: Check Value + if (!$resource->currency || !$resource->value) { + throw ResourceValidityException::trigger(ResourceValidityException::ERROR_REQUIRED, ['currency', 'value'], $resource); + } + return $resource; + } + + /** + * @return stdClass + */ + public static function FallbackCurrency() + { + return isset($_SESSION['Waehrung']) ? $_SESSION['Waehrung'] : Shop::DB()->select('twaehrung', 'cStandard', 'Y'); + } + + /** + * Check if 5 Rappen rounding is necessary + * + * @return float + */ + protected function round($value) + { + + $conf = Shop::getSettings([CONF_KAUFABWICKLUNG]); + if (isset($conf['kaufabwicklung']['bestellabschluss_runden5']) && (int)$conf['kaufabwicklung']['bestellabschluss_runden5'] === 1) { + $value = round($value * 20) / 20; + } + return $value; + } + + +} \ No newline at end of file diff --git a/version/205/class/Checkout/PaymentCheckout.php b/version/205/class/Checkout/PaymentCheckout.php new file mode 100644 index 0000000..a75faea --- /dev/null +++ b/version/205/class/Checkout/PaymentCheckout.php @@ -0,0 +1,241 @@ +getMollie()->isCancelable) { + throw new RuntimeException('Zahlung kann nicht abgebrochen werden.'); + } + $payment = $checkout->API()->Client()->payments->cancel($checkout->getMollie()->id); + $checkout->Log('Zahlung wurde manuell abgebrochen.'); + return $payment; + } + + /** + * @param false $force + * @return Payment|null + */ + public function getMollie($force = false) + { + if ($force || (!$this->getPayment() && $this->getModel()->kID)) { + try { + $this->setPayment($this->API()->Client()->payments->get($this->getModel()->kID, ['embed' => 'refunds'])); + } catch (Exception $e) { + throw new RuntimeException('Mollie-Payment konnte nicht geladen werden: ' . $e->getMessage()); + } + } + return $this->getPayment(); + } + + /** + * @return Payment|null + */ + public function getPayment() + { + return $this->_payment; + } + + /** + * @param $payment + * @return $this + */ + public function setPayment($payment) + { + $this->_payment = $payment; + return $this; + } + + /** + * @return string + * @throws ApiException + * @throws IncompatiblePlatform + */ + public function cancelOrRefund($force = false) + { + if (!$this->getMollie()) { + throw new RuntimeException('Mollie-Order konnte nicht geladen werden: ' . $this->getModel()->kID); + } + if ($force || (int)$this->getBestellung()->cStatus === BESTELLUNG_STATUS_STORNO) { + if ($this->getMollie()->isCancelable) { + $res = $this->API()->Client()->payments->cancel($this->getMollie()->id); + $result = 'Payment cancelled, Status: ' . $res->status; + } else { + $res = $this->API()->Client()->payments->refund($this->getMollie(), ['amount' => $this->getMollie()->amount]); + $result = "Payment Refund initiiert, Status: " . $res->status; + } + $this->PaymentMethod()->Log("PaymentCheckout::cancelOrRefund: " . $result, $this->LogData()); + return $result; + } + throw new RuntimeException('Bestellung ist derzeit nicht storniert, Status: ' . $this->getBestellung()->cStatus); + } + + /** + * @param array $paymentOptions + * @return Payment + */ + public function create(array $paymentOptions = []) + { + if ($this->getModel()->kID) { + try { + $this->setPayment($this->API()->Client()->payments->get($this->getModel()->kID)); + if ($this->getPayment()->status === PaymentStatus::STATUS_PAID) { + throw new RuntimeException(self::Plugin()->oPluginSprachvariableAssoc_arr['errAlreadyPaid']); + } + if ($this->getPayment()->status === PaymentStatus::STATUS_OPEN) { + $this->updateModel()->saveModel(); + return $this->getPayment(); + } + } catch (RuntimeException $e) { + //$this->Log(sprintf("PaymentCheckout::create: Letzte Transaktion '%s' konnte nicht geladen werden: %s", $this->getModel()->kID, $e->getMessage()), LOGLEVEL_ERROR); + throw $e; + } catch (Exception $e) { + $this->Log(sprintf("PaymentCheckout::create: Letzte Transaktion '%s' konnte nicht geladen werden: %s, versuche neue zu erstellen.", $this->getModel()->kID, $e->getMessage()), LOGLEVEL_ERROR); + } + } + + try { + $req = $this->loadRequest($paymentOptions)->jsonSerialize(); + $this->setPayment($this->API()->Client()->payments->create($req)); + $this->Log(sprintf("Payment für '%s' wurde erfolgreich angelegt: %s", $this->getBestellung()->cBestellNr, $this->getPayment()->id)); + $this->updateModel()->saveModel(); + return $this->getPayment(); + } catch (Exception $e) { + $this->Log(sprintf("PaymentCheckout::create: Neue Transaktion für '%s' konnte nicht erstellt werden: %s.", $this->getBestellung()->cBestellNr, $e->getMessage()), LOGLEVEL_ERROR); + throw new RuntimeException(sprintf('Mollie-Payment \'%s\' konnte nicht geladen werden: %s', $this->getBestellung()->cBestellNr, $e->getMessage())); + } + } + + /** + * @param array $options + * @return $this|PaymentCheckout + */ + public function loadRequest(&$options = []) + { + + parent::loadRequest($options); + + foreach ($options as $key => $value) { + $this->$key = $value; + } + + + $this->description = $this->getDescription(); + + return $this; + } + + public function getDescription() + { + $descTemplate = trim(Helper::getSetting('paymentDescTpl')) ?: "Order {orderNumber}"; + $oKunde = $this->getBestellung()->oKunde ?: $_SESSION['Kunde']; + return str_replace([ + '{orderNumber}', + '{storeName}', + '{customer.firstname}', + '{customer.lastname}', + '{customer.company}', + ], [ + $this->getBestellung()->cBestellNr, + Shop::getSettings([CONF_GLOBAL])['global']['global_shopname'], + $oKunde->cVorname, + $oKunde->cNachname, + $oKunde->cFirma + + ], $descTemplate); + } + + /** + * @return object|null + */ + public function getIncomingPayment() + { + if (!$this->getMollie()) { + return null; + } + + if (in_array($this->getMollie()->status, [PaymentStatus::STATUS_AUTHORIZED, PaymentStatus::STATUS_PAID], true)) { + $data = []; + $data['fBetrag'] = (float)$this->getMollie()->amount->value; + $data['cISO'] = $this->getMollie()->amount->currency; + $data['cZahler'] = $this->getMollie()->details->paypalPayerId ?: $this->getMollie()->customerId; + $data['cHinweis'] = $this->getMollie()->details->paypalReference ?: $this->getMollie()->id; + if (isset($this->getMollie()->details, $this->getMollie()->details->paypalFee)) { + $data['fZahlungsgebuehr'] = $this->getMollie()->details->paypalFee->value; + } + return (object)$data; + } + return null; + } + + /** + * @param Payment $model + * @return $this|AbstractCheckout + */ + protected function setMollie($model) + { + if ($model instanceof Payment) { + $this->setPayment($model); + } + return $this; + } + + /** + * @return $this + */ + protected function updateOrderNumber() + { + try { + if ($this->getMollie()) { + $this->getMollie()->description = $this->getDescription(); + $this->getMollie()->webhookUrl = Shop::getURL() . '/?mollie=1'; + $this->getMollie()->update(); + } + } catch (Exception $e) { + $this->Log('OrderCheckout::updateOrderNumber:' . $e->getMessage(), LOGLEVEL_ERROR); + } + return $this; + } + +} \ No newline at end of file diff --git a/version/205/class/ExclusiveLock.php b/version/205/class/ExclusiveLock.php new file mode 100644 index 0000000..f3d3d95 --- /dev/null +++ b/version/205/class/ExclusiveLock.php @@ -0,0 +1,64 @@ +key = $key; + $this->path = rtrim(realpath($path), '/') . '/'; + if (!is_dir($path) || !is_writable($path)) { + throw new RuntimeException("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", 'wb+'); + } + + + public function __destruct() + { + if ($this->own === true) { + $this->unlock(); + } + } + + /** @noinspection ForgottenDebugOutputInspection */ + 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; + } + 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 + } + + public function lock() + { + if (!flock($this->file, LOCK_EX | LOCK_NB)) { //failed + return false; + } + fwrite($this->file, "Locked - " . microtime(true) . "\n"); + fflush($this->file); + + $this->own = true; + return true; // success + } +} diff --git a/version/205/class/Helper.php b/version/205/class/Helper.php new file mode 100644 index 0000000..514f1c5 --- /dev/null +++ b/version/205/class/Helper.php @@ -0,0 +1,350 @@ +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) && !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; + } + 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()->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) 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/205/class/Hook/AbstractHook.php b/version/205/class/Hook/AbstractHook.php new file mode 100644 index 0000000..8dcbbda --- /dev/null +++ b/version/205/class/Hook/AbstractHook.php @@ -0,0 +1,13 @@ +kPlugin)) + && array_key_exists($key, $_SESSION) && !array_key_exists("Zahlungsart", $_SESSION)) { + unset($_SESSION[$key]); + } + + if (!array_key_exists('ws_mollie_applepay_available', $_SESSION)) { + Shop::Smarty()->assign('applePayCheckURL', json_encode(self::Plugin()->cFrontendPfadURLSSL . 'applepay.php')); + pq('body')->append(Shop::Smarty()->fetch(self::Plugin()->cFrontendPfad . 'tpl/applepay.tpl')); + } + + } + + /** + * @return bool + */ + public static function isAvailable() + { + if (array_key_exists('ws_mollie_applepay_available', $_SESSION)) { + return $_SESSION['ws_mollie_applepay_available']; + } + return false; + } + + /** + * @param $status bool + */ + public static function setAvailable($status) + { + $_SESSION['ws_mollie_applepay_available'] = $status; + } + +} \ No newline at end of file diff --git a/version/205/class/Hook/Checkbox.php b/version/205/class/Hook/Checkbox.php new file mode 100644 index 0000000..9ab5ca8 --- /dev/null +++ b/version/205/class/Hook/Checkbox.php @@ -0,0 +1,60 @@ +cModulId, 'kPlugin_' . self::Plugin()->kPlugin . '_') === false) { + return; + } + + if (array_key_exists('nAnzeigeOrt', $args_arr) && $args_arr['nAnzeigeOrt'] === CHECKBOX_ORT_BESTELLABSCHLUSS && Session::getInstance()->Customer()->nRegistriert) { + + $mCustomer = Customer::fromID(Session::getInstance()->Customer()->kKunde, 'kKunde'); + + if ($mCustomer->customerId) { + return; + } + + $checkbox = new \CheckBox(); + $checkbox->kLink = 0; + $checkbox->kCheckBox = -1; + $checkbox->kCheckBoxFunktion = 0; + $checkbox->cName = 'MOLLIE SAVE CUSTOMER'; + $checkbox->cKundengruppe = ';1;'; + $checkbox->cAnzeigeOrt = ';2;'; + $checkbox->nAktiv = 1; + $checkbox->nPflicht = 0; + $checkbox->nLogging = 0; + $checkbox->nSort = 999; + $checkbox->dErstellt = date('Y-m-d H:i:s'); + $checkbox->oCheckBoxSprache_arr = []; + + $langs = gibAlleSprachen(); + foreach ($langs as $lang) { + $checkbox->oCheckBoxSprache_arr[$lang->kSprache] = (object)[ + 'cText' => self::Plugin()->oPluginSprachvariableAssoc_arr['checkboxText'], + 'cBeschreibung' => self::Plugin()->oPluginSprachvariableAssoc_arr['checkboxDescr'], + 'kSprache' => $lang->kSprache, + 'kCheckbox' => -1 + ]; + } + + $checkbox->kKundengruppe_arr = [Session::getInstance()->Customer()->kKundengruppe]; + $checkbox->kAnzeigeOrt_arr = [CHECKBOX_ORT_BESTELLABSCHLUSS]; + $checkbox->cID = "mollie_create_customer"; + $checkbox->cLink = ''; + + $args_arr['oCheckBox_arr'][] = $checkbox; + + } + } +} \ No newline at end of file diff --git a/version/205/class/Hook/Queue.php b/version/205/class/Hook/Queue.php new file mode 100644 index 0000000..8e3bbcf --- /dev/null +++ b/version/205/class/Hook/Queue.php @@ -0,0 +1,137 @@ +nWaehrendBestellung === 0 + && $args_arr['oBestellung']->fGesamtsumme > 0 + && self::Plugin()->oPluginEinstellungAssoc_arr['onlyPaid'] === 'Y' + && AbstractCheckout::isMollie((int)$args_arr['oBestellung']->kZahlungsart, true)) { + + $args_arr['oBestellung']->cAbgeholt = 'Y'; + Jtllog::writeLog('Switch cAbgeholt for kBestellung: ' . print_r($args_arr['oBestellung']->kBestellung, 1), JTLLOG_LEVEL_NOTICE); + } + } + + /** + * @param array $args_arr + */ + public static function xmlBestellStatus(array $args_arr) + { + if (AbstractCheckout::isMollie((int)$args_arr['oBestellung']->kBestellung)) { + self::saveToQueue(HOOK_BESTELLUNGEN_XML_BESTELLSTATUS . ':' . (int)$args_arr['oBestellung']->kBestellung, [ + 'kBestellung' => $args_arr['oBestellung']->kBestellung, + 'status' => (int)$args_arr['status'] + ]); + } + } + + /** + * @param $hook + * @param $args_arr + * @param string $type + * @return bool + */ + public static function saveToQueue($hook, $args_arr, $type = 'hook') + { + $mQueue = new QueueModel(); + $mQueue->cType = $type . ':' . $hook; + $mQueue->cData = serialize($args_arr); + try { + return $mQueue->save(); + } catch (Exception $e) { + Jtllog::writeLog('mollie::saveToQueue: ' . $e->getMessage() . ' - ' . print_r($args_arr, 1)); + return false; + } + } + + /** + * @param array $args_arr + */ + public static function xmlBearbeiteStorno(array $args_arr) + { + if (AbstractCheckout::isMollie((int)$args_arr['oBestellung']->kBestellung)) { + self::saveToQueue(HOOK_BESTELLUNGEN_XML_BEARBEITESTORNO . ':' . $args_arr['oBestellung']->kBestellung, ['kBestellung' => $args_arr['oBestellung']->kBestellung]); + } + } + + /** + * + */ + public static function headPostGet() + { + if (array_key_exists('mollie', $_REQUEST) && (int)$_REQUEST['mollie'] === 1 && array_key_exists('id', $_REQUEST)) { + + if (array_key_exists('hash', $_REQUEST) && $hash = trim(StringHandler::htmlentities(StringHandler::filterXSS($_REQUEST['hash'])), '_')) { + + AbstractCheckout::finalizeOrder($hash, $_REQUEST['id'], array_key_exists('test', $_REQUEST)); + } else { + self::saveToQueue($_REQUEST['id'], $_REQUEST['id'], 'webhook'); + } + exit(); + } + if (array_key_exists('m_pay', $_REQUEST)) { + try { + $raw = Shop::DB()->executeQueryPrepared('SELECT kID FROM `xplugin_ws_mollie_payments` WHERE dReminder IS NOT NULL AND MD5(CONCAT(kID, "-", kBestellung)) = :md5', [ + ':md5' => $_REQUEST['m_pay'] + ], 1); + + if (!$raw) { + throw new RuntimeException(self::Plugin()->oPluginSprachvariableAssoc_arr['errOrderNotFound']); + } + + if (strpos($raw->cOrderId, 'tr_') === 0) { + $checkout = PaymentCheckout::fromID($raw->kID); + } else { + $checkout = OrderCheckout::fromID($raw->kID); + } + $checkout->getMollie(true); + $checkout->updateModel()->saveModel(); + + if (($checkout->getBestellung()->dBezahltDatum !== null && $checkout->getBestellung()->dBezahltDatum !== '0000-00-00') + || in_array($checkout->getModel()->cStatus, ['completed', 'paid', 'authorized', 'pending'])) { + throw new RuntimeException(self::Plugin()->oPluginSprachvariableAssoc_arr['errAlreadyPaid']); + } + + $options = []; + if (self::Plugin()->oPluginEinstellungAssoc_arr['resetMethod'] !== 'Y') { + $options['method'] = $checkout->getModel()->cMethod; + } + + $mollie = $checkout->create($options); // Order::repayOrder($orderModel->getOrderId(), $options, $api); + $url = $mollie->getCheckoutUrl(); + + header('Location: ' . $url); + exit(); + + } catch (RuntimeException $e) { + // TODO Workaround? + //$alertHelper = Shop::Container()->getAlertService(); + //$alertHelper->addAlert(Alert::TYPE_ERROR, $e->getMessage(), 'mollie_repay', ['dismissable' => true]); + } catch (Exception $e) { + Jtllog::writeLog('mollie:repay:error: ' . $e->getMessage() . "\n" . print_r($_REQUEST, 1)); + } + } + } + +} \ No newline at end of file diff --git a/version/205/class/Model/AbstractModel.php b/version/205/class/Model/AbstractModel.php new file mode 100644 index 0000000..e041d4e --- /dev/null +++ b/version/205/class/Model/AbstractModel.php @@ -0,0 +1,98 @@ +data = $data; + if (!$data) { + $this->new = true; + } + } + + /** + * @param $id + * @param string $col + * @param false $failIfNotExists + * @return static + */ + public static function fromID($id, $col = 'kID', $failIfNotExists = false) + { + if ($payment = Shop::DB()->executeQueryPrepared("SELECT * FROM " . static::TABLE . " WHERE `$col` = :id", + [':id' => $id], 1)) { + return new static($payment); + } + if ($failIfNotExists) { + throw new RuntimeException(sprintf('Model %s in %s nicht gefunden!', $id, static::TABLE)); + } + return new static(); + } + + /** + * @return mixed|stdClass|null + */ + public function jsonSerialize() + { + return $this->data; + } + + public function __get($name) + { + if (isset($this->data->$name)) { + return $this->data->$name; + } + return null; + } + + public function __set($name, $value) + { + if (!$this->data) { + $this->data = new stdClass(); + } + $this->data->$name = $value; + } + + public function __isset($name) + { + return isset($this->data->$name); + } + + /** + * @return bool + */ + public function save() + { + if (!$this->data) { + throw new RuntimeException('No Data to save!'); + } + + if ($this->new) { + Shop::DB()->insertRow(static::TABLE, $this->data); + $this->new = false; + return true; + } + Shop::DB()->updateRow(static::TABLE, static::PRIMARY, $this->data->{static::PRIMARY}, $this->data); + return true; + } + +} diff --git a/version/205/class/Model/Customer.php b/version/205/class/Model/Customer.php new file mode 100644 index 0000000..7be9e15 --- /dev/null +++ b/version/205/class/Model/Customer.php @@ -0,0 +1,19 @@ +dCreatedAt) { + $this->dCreatedAt = date('Y-m-d H:i:s'); + } + if($this->new){ + $this->dReminder = self::NULL; + } + return parent::save(); + } +} diff --git a/version/205/class/Model/Queue.php b/version/205/class/Model/Queue.php new file mode 100644 index 0000000..e17a491 --- /dev/null +++ b/version/205/class/Model/Queue.php @@ -0,0 +1,42 @@ +cResult = $result; + $this->dDone = $date ?: date('Y-m-d H:i:s'); + return $this->save(); + } + + public function save() + { + if (!$this->dCreated) { + $this->dCreated = date('Y-m-d H:i:s'); + } + $this->dModified = date('Y-m-d H:i:s'); + return parent::save(); + } + +} \ No newline at end of file diff --git a/version/205/class/Model/Shipment.php b/version/205/class/Model/Shipment.php new file mode 100644 index 0000000..bece7b4 --- /dev/null +++ b/version/205/class/Model/Shipment.php @@ -0,0 +1,28 @@ +executeQueryPrepared("SELECT p.kBestellung, b.cStatus FROM xplugin_ws_mollie_payments p " + . "JOIN tbestellung b ON b.kBestellung = p.kBestellung " + . "WHERE b.cAbgeholt = 'Y' AND NOT p.bSynced AND b.cStatus IN ('1', '2') AND p.dCreatedAt < NOW() - INTERVAL :d HOUR", + [':d' => $delay], 2); + + foreach ($open as $o) { + try { + + $checkout = AbstractCheckout::fromBestellung($o->kBestellung); + $pm = $checkout->PaymentMethod(); + if ($pm::ALLOW_AUTO_STORNO && $pm::METHOD === $checkout->getMollie()->method) { + if ($checkout->getBestellung()->cAbgeholt === 'Y' && (bool)$checkout->getModel()->bSynced === false) { + if (!in_array($checkout->getMollie()->status, [OrderStatus::STATUS_PAID, OrderStatus::STATUS_COMPLETED, OrderStatus::STATUS_AUTHORIZED], true)) { + $checkout->storno(); + } else { + $checkout->Log(sprintf('AutoStorno: Bestellung bezahlt? %s - Method: %s', $checkout->getMollie()->status, $checkout->getMollie()->method), LOGLEVEL_ERROR); + } + } else { + $checkout->Log('AutoStorno: bereits zur WAWI synchronisiert.', LOGLEVEL_ERROR); + } + } + + } catch (Exception $e) { + Helper::logExc($e); + } + } + return true; + } + + /** + * @param int $limit + */ + public static function run($limit = 10) + { + + foreach (self::getOpen($limit) as $todo) { + + if (!self::lock($todo)) { + Jtllog::writeLog(sprintf('%s already locked since %s', $todo->kId, $todo->bLock ?: 'just now')); + continue; + } + + if ((list($type, $id) = explode(':', $todo->cType))) { + try { + switch ($type) { + case 'webhook': + self::handleWebhook($id, $todo); + break; + + case 'hook': + self::handleHook((int)$id, $todo); + break; + } + + } catch (Exception $e) { + Jtllog::writeLog($e->getMessage() . " ($type, $id)"); + $todo->done("{$e->getMessage()}\n{$e->getFile()}:{$e->getLine()}\n{$e->getTraceAsString()}"); + } + } + + self::unlock($todo); + + } + } + + /** + * @param $limit + * @return Generator|QueueModel[] + * @noinspection PhpReturnDocTypeMismatchInspection + * @noinspection SqlResolve + */ + private static function getOpen($limit) + { + // TODO: DOKU! + if(!defined('MOLLIE_HOOK_DELAY')){ + define('MOLLIE_HOOK_DELAY', 3); + } + $open = Shop::DB()->executeQueryPrepared(sprintf("SELECT * FROM %s WHERE dDone IS NULL AND `bLock` IS NULL AND (cType LIKE 'webhook:%%' OR (cType LIKE 'hook:%%') AND dCreated < DATE_SUB(NOW(), INTERVAL ".(int)MOLLIE_HOOK_DELAY." MINUTE)) ORDER BY dCreated DESC LIMIT 0, :LIMIT;", QueueModel::TABLE), [ + ':LIMIT' => $limit + ], 2); + + foreach ($open as $_raw) { + yield new QueueModel($_raw); + } + } + + /** + * @param $todo + * @return bool + * @noinspection SqlResolve + */ + protected static function lock($todo) + { + return $todo->kId && Shop::DB()->executeQueryPrepared(sprintf('UPDATE %s SET `bLock` = NOW() WHERE `bLock` IS NULL AND kId = :kId', QueueModel::TABLE), [ + 'kId' => $todo->kId + ], 3) >= 1; + + } + + /** + * @param $id + * @param QueueModel $todo + * @return bool + * @throws Exception + */ + protected static function handleWebhook($id, QueueModel $todo) + { + $checkout = AbstractCheckout::fromID($id); + if ($checkout->getBestellung()->kBestellung && $checkout->PaymentMethod()) { + $checkout->handleNotification(); + return $todo->done('Status: ' . $checkout->getMollie()->status); + } + throw new RuntimeException("Bestellung oder Zahlungsart konnte nicht geladen werden: $id"); + } + + /** + * @param $hook + * @param QueueModel $todo + * @return bool + * @throws ApiException + * @throws IncompatiblePlatform + * @throws Exception + */ + protected static function handleHook($hook, QueueModel $todo) + { + $data = unserialize($todo->cData); + if (array_key_exists('kBestellung', $data)) { + switch ($hook) { + case HOOK_BESTELLUNGEN_XML_BESTELLSTATUS: + if ((int)$data['kBestellung']) { + $checkout = AbstractCheckout::fromBestellung($data['kBestellung']); + + $status = array_key_exists('status', $data) ? (int)$data['status'] : 0; + $result = ""; + if (!$status || $status < BESTELLUNG_STATUS_VERSANDT) { + return $todo->done("Bestellung noch nicht versendet: {$checkout->getBestellung()->cStatus}"); + } + + /** @var $method JTLMollie */ + if ((strpos($checkout->getModel()->kID, 'tr_') === false) + && $checkout->PaymentMethod() + && $checkout->getMollie()) { + /** @var OrderCheckout $checkout */ + $checkout->handleNotification(); + if ($checkout->getMollie()->status === OrderStatus::STATUS_COMPLETED) { + $result = 'Mollie Status already ' . $checkout->getMollie()->status; + } else if ($checkout->getMollie()->isCreated() || $checkout->getMollie()->isPaid() || $checkout->getMollie()->isAuthorized() || $checkout->getMollie()->isShipping() || $checkout->getMollie()->isPending()) { + try { + if ($shipments = Shipment::syncBestellung($checkout)) { + foreach ($shipments as $shipment) { + if (is_string($shipment)) { + $checkout->Log("Shipping-Error: $shipment"); + $result .= "Shipping-Error: $shipment;\n"; + } else { + $checkout->Log("Order shipped: {$shipment->id}"); + $result .= "Order shipped: $shipment->id;\n"; + } + } + } else { + $result = 'No Shipments ready!'; + } + } catch (RuntimeException $e) { + $result = $e->getMessage(); + } catch (Exception $e) { + $result = $e->getMessage() . "\n" . $e->getFile() . ":" . $e->getLine() . "\n" . $e->getTraceAsString(); + } + } else { + $result = sprintf('Unerwarteter Mollie Status "%s" für %s', $checkout->getMollie()->status, $checkout->getBestellung()->cBestellNr); + } + } else { + $result = 'Nothing to do.'; + } + $checkout->Log("Queue::handleHook: " . $result); + } else { + $result = "kBestellung missing"; + } + return $todo->done($result); + + case HOOK_BESTELLUNGEN_XML_BEARBEITESTORNO: + if (self::Plugin()->oPluginEinstellungAssoc_arr['autoRefund'] !== 'Y') { + throw new RuntimeException('Auto-Refund disabled'); + } + + $checkout = AbstractCheckout::fromBestellung((int)$data['kBestellung']); + return $todo->done($checkout->cancelOrRefund()); + } + } + return false; + } + + /** + * @param $todo + * @return bool + */ + protected static function unlock($todo) + { + return $todo->kId && Shop::DB()->executeQueryPrepared(sprintf('UPDATE %s SET `bLock` = NULL WHERE kId = :kId', QueueModel::TABLE), [ + 'kId' => $todo->kId + ], 3) >= 1; + } + +} \ No newline at end of file diff --git a/version/205/class/Shipment.php b/version/205/class/Shipment.php new file mode 100644 index 0000000..ae533f7 --- /dev/null +++ b/version/205/class/Shipment.php @@ -0,0 +1,316 @@ +kLieferschein = $kLieferschein; + if ($checkout) { + $this->checkout = $checkout; + } + + if (!$this->getLieferschein() || !$this->getLieferschein()->getLieferschein()) { + throw new RuntimeException('Lieferschein konnte nicht geladen werden'); + } + + if (!count($this->getLieferschein()->oVersand_arr)) { + throw new RuntimeException('Kein Versand gefunden!'); + } + + if (!$this->getCheckout()->getBestellung()->oKunde->nRegistriert) { + $this->isGuest = true; + } + } + + public function getLieferschein() + { + if (!$this->oLieferschein && $this->kLieferschein) { + $this->oLieferschein = new Lieferschein($this->kLieferschein); + } + return $this->oLieferschein; + } + + /** + * @return OrderCheckout + * @throws Exception + */ + public function getCheckout() + { + if (!$this->checkout) { + //TODO evtl. load by lieferschien + throw new Exception('Should not happen, but it did!'); + } + return $this->checkout; + } + + public static function syncBestellung(OrderCheckout $checkout) + { + $shipments = []; + if ($checkout->getBestellung()->kBestellung) { + + $oKunde = $checkout->getBestellung()->oKunde ?: new Kunde($checkout->getBestellung()->kKunde); + + $shippingActive = Helper::getSetting('shippingActive'); + if ($shippingActive === 'N') { + throw new RuntimeException('Shipping deaktiviert'); + } + + if ($shippingActive === 'K' && !$oKunde->nRegistriert && (int)$checkout->getBestellung()->cStatus !== BESTELLUNG_STATUS_VERSANDT) { + throw new RuntimeException('Shipping für Gast-Bestellungen und Teilversand deaktiviert'); + } + + /** @var Lieferschein $oLieferschein */ + foreach ($checkout->getBestellung()->oLieferschein_arr as $oLieferschein) { + try { + $shipment = new Shipment($oLieferschein->getLieferschein(), $checkout); + $mode = self::Plugin()->oPluginEinstellungAssoc_arr['shippingMode']; + switch ($mode) { + case 'A': + // ship directly + if (!$shipment->send() && !$shipment->getShipment()) { + throw new RuntimeException('Shipment konnte nicht gespeichert werden.'); + } + $shipments[] = $shipment->getShipment(); + break; + + case 'B': + // only ship if complete shipping + if ($oKunde->nRegistriert || (int)$checkout->getBestellung()->cStatus === BESTELLUNG_STATUS_VERSANDT) { + if (!$shipment->send() && !$shipment->getShipment()) { + throw new RuntimeException('Shipment konnte nicht gespeichert werden.'); + } + $shipments[] = $shipment->getShipment(); + break; + } + throw new RuntimeException('Gastbestellung noch nicht komplett versendet!'); + } + } catch (RuntimeException $e) { + $shipments[] = $e->getMessage(); + } catch (Exception $e) { + $shipments[] = $e->getMessage(); + $checkout->Log("mollie: Shipment::syncBestellung (BestellNr. {$checkout->getBestellung()->cBestellNr}, Lieferschein: {$oLieferschein->getLieferscheinNr()}) - " . $e->getMessage(), LOGLEVEL_ERROR); + } + } + } + return $shipments; + } + + /** + * @return bool + * @throws ApiException + * @throws IncompatiblePlatform + * @throws Exception + */ + public function send() + { + + if ($this->getShipment()) { + throw new RuntimeException('Lieferschien bereits an Mollie übertragen: ' . $this->getShipment()->id); + } + + if ($this->getCheckout()->getMollie(true)->status === OrderStatus::STATUS_COMPLETED) { + throw new RuntimeException('Bestellung bei Mollie bereits abgeschlossen!'); + } + + $api = $this->getCheckout()->API()->Client(); + $this->shipment = $api->shipments->createForId($this->checkout->getModel()->kID, $this->loadRequest()->jsonSerialize()); + + return $this->updateModel()->saveModel(); + + } + + /** + * @param false $force + * @return BaseResource|\Mollie\Api\Resources\Shipment + * @throws ApiException + * @throws IncompatiblePlatform + * @throws Exception + */ + public function getShipment($force = false) + { + if (($force || !$this->shipment) && $this->getModel() && $this->getModel()->cShipmentId) { + $this->shipment = $this->getCheckout()->API()->Client()->shipments->getForId($this->getModel()->cOrderId, $this->getModel()->cShipmentId); + } + return $this->shipment; + } + + /** + * @return ShipmentModel + * @throws Exception + */ + public function getModel() + { + if (!$this->model && $this->kLieferschein) { + $this->model = ShipmentModel::fromID($this->kLieferschein, 'kLieferschein'); + + if (!$this->model->dCreated) { + $this->model->dCreated = date('Y-m-d H:i:s'); + } + $this->updateModel(); + } + return $this->model; + } + + /** + * @return $this + * @throws Exception + */ + public function updateModel() + { + $this->getModel()->kLieferschein = $this->kLieferschein; + if ($this->getCheckout()) { + $this->getModel()->cOrderId = $this->getCheckout()->getModel()->kID; + $this->getModel()->kBestellung = $this->getCheckout()->getModel()->kBestellung; + } + if ($this->getShipment()) { + $this->getModel()->cShipmentId = $this->getShipment()->id; + $this->getModel()->cUrl = $this->getShipment()->getTrackingUrl() ?: ''; + } + if (isset($this->tracking)) { + $this->getModel()->cCarrier = $this->tracking['carrier'] ?: ''; + $this->getModel()->cCode = $this->tracking['code'] ?: ''; + } + return $this; + } + + /** + * @param array $options + * @return $this + * @throws Exception + */ + public function loadRequest(&$options = []) + { + /** @var Versand $oVersand */ + $oVersand = $this->getLieferschein()->oVersand_arr[0]; + if ($oVersand->getIdentCode() && $oVersand->getLogistik()) { + $tracking = [ + 'carrier' => utf8_encode($oVersand->getLogistik()), + 'code' => utf8_encode($oVersand->getIdentCode()), + ]; + if ($oVersand->getLogistikVarUrl()) { + $tracking['url'] = utf8_encode($oVersand->getLogistikURL()); + } + $this->tracking = $tracking; + } + + // TODO: Wenn alle Lieferschiene in der WAWI erstellt wurden, aber nicht im Shop, kommt status 4. + if ($this->isGuest || (int)$this->getCheckout()->getBestellung()->cStatus === BESTELLUNG_STATUS_VERSANDT) { + $this->lines = []; + } else { + $this->lines = $this->getOrderLines(); + } + return $this; + } + + /** + * @return array + * @throws Exception + */ + protected function getOrderLines() + { + $lines = []; + + if (!count($this->getLieferschein()->oLieferscheinPos_arr)) { + return $lines; + } + + // Bei Stücklisten, sonst gibt es mehrere OrderLines für die selbe ID + $shippedOrderLines = []; + + /** @var Lieferscheinpos $oLieferscheinPos */ + foreach ($this->getLieferschein()->oLieferscheinPos_arr as $oLieferscheinPos) { + + $wkpos = Shop::DB()->executeQueryPrepared('SELECT * FROM twarenkorbpos WHERE kBestellpos = :kBestellpos', [ + ':kBestellpos' => $oLieferscheinPos->getBestellPos() + ], 1); + + /** @var OrderLine $orderLine */ + foreach ($this->getCheckout()->getMollie()->lines as $orderLine) { + + if ($orderLine->sku === $wkpos->cArtNr && !in_array($orderLine->id, $shippedOrderLines, true)) { + + if ($quantity = min($oLieferscheinPos->getAnzahl(), $orderLine->shippableQuantity)) { + $lines[] = [ + 'id' => $orderLine->id, + 'quantity' => $quantity + ]; + } + $shippedOrderLines[] = $orderLine->id; + break; + } + } + } + return $lines; + } + + /** + * @return bool + * @throws Exception + */ + public function saveModel() + { + return $this->getModel()->save(); + } +} \ No newline at end of file diff --git a/version/205/class/Traits/Jsonable.php b/version/205/class/Traits/Jsonable.php new file mode 100644 index 0000000..afc0988 --- /dev/null +++ b/version/205/class/Traits/Jsonable.php @@ -0,0 +1,20 @@ +jsonSerialize(); + } + + public function jsonSerialize() + { + return array_filter(get_object_vars($this), static function ($value) { + return !($value === null || (is_string($value) && $value === '')); + }); + } +} \ No newline at end of file diff --git a/version/205/class/Traits/Plugin.php b/version/205/class/Traits/Plugin.php new file mode 100644 index 0000000..5b2c3a3 --- /dev/null +++ b/version/205/class/Traits/Plugin.php @@ -0,0 +1,25 @@ +requestData) === false) { + throw new \RuntimeException(sprintf("JSON Encode Error: %s\n%s", json_last_error_msg(), print_r($this->requestData, 1))); + } + return $this->requestData; + } + + public function __get($name) + { + if (!$this->requestData) { + $this->loadRequest(); + } + return is_string($this->requestData[$name]) ? utf8_decode($this->requestData[$name]) : $this->requestData[$name]; + } + + public function __set($name, $value) + { + if (!$this->requestData) { + $this->requestData = []; + } + + $this->requestData[$name] = is_string($value) ? utf8_encode($value) : $value; + + return $this; + } + + /** + * @param array $options + * @return $this + */ + public function loadRequest(&$options = []) + { + return $this; + } + + + public function __serialize() + { + return $this->requestData ?: []; + } + + public function __isset($name) + { + return $this->requestData[$name] !== null; + } + +} \ No newline at end of file diff --git a/version/205/frontend/.htaccess b/version/205/frontend/.htaccess new file mode 100644 index 0000000..df6c074 --- /dev/null +++ b/version/205/frontend/.htaccess @@ -0,0 +1,9 @@ + + + Require all granted + + + Order Allow,Deny + Allow from all + + diff --git a/version/205/frontend/131_globalinclude.php b/version/205/frontend/131_globalinclude.php new file mode 100644 index 0000000..2861d31 --- /dev/null +++ b/version/205/frontend/131_globalinclude.php @@ -0,0 +1,60 @@ +select('tzahlungsession', 'cZahlungsID', $sessionHash); + if ($paymentSession && $paymentSession->kBestellung) { + $oBestellung = new Bestellung($paymentSession->kBestellung); + + if (Shopsetting::getInstance()->getValue('kaufabwicklung', 'bestellabschluss_abschlussseite') === 'A') { + $oZahlungsID = Shop::DB()->query(" + SELECT cId + FROM tbestellid + WHERE kBestellung = " . (int)$paymentSession->kBestellung, 1 + ); + if (is_object($oZahlungsID)) { + header('Location: ' . Shop::getURL() . '/bestellabschluss.php?i=' . $oZahlungsID->cId); + exit(); + } + } + $bestellstatus = Shop::DB()->select('tbestellstatus', 'kBestellung', (int)$paymentSession->kBestellung); + header('Location: ' . Shop::getURL() . '/status.php?uid=' . $bestellstatus->cUID); + exit(); + } + } + + ifndef('MOLLIE_REMINDER_PROP', 10); + if (mt_rand(1, MOLLIE_REMINDER_PROP) % MOLLIE_REMINDER_PROP === 0) { + $lock = new \ws_mollie\ExclusiveLock('mollie_reminder', PFAD_ROOT . PFAD_COMPILEDIR); + if ($lock->lock()) { + // TODO: Doku! + + AbstractCheckout::sendReminders(); + Queue::storno((int)Helper::getSetting('autoStorno')); + + $lock->unlock(); + } + } + + +} catch (Exception $e) { + Helper::logExc($e); +} + + diff --git a/version/205/frontend/132_headPostGet.php b/version/205/frontend/132_headPostGet.php new file mode 100644 index 0000000..94afd33 --- /dev/null +++ b/version/205/frontend/132_headPostGet.php @@ -0,0 +1,17 @@ +append( + << + /* MOLLIE CHECKOUT STYLES*/ + #fieldset-payment .form-group > div:hover, #checkout-shipping-payment .form-group > div:hover { + background-color: #eee; + color: black; + } + $selector label { + $border + } + + $selector label::after { + clear: both; + content: ' '; + display: block; + } + + $selector label span small { + line-height: 48px; + } + + $selector label img { + float: right; + } + +HTML + ); + +} catch (Exception $e) { + Helper::logExc($e); +} diff --git a/version/205/frontend/180_checkbox.php b/version/205/frontend/180_checkbox.php new file mode 100644 index 0000000..95a070f --- /dev/null +++ b/version/205/frontend/180_checkbox.php @@ -0,0 +1,18 @@ +oPluginEinstellungAssoc_arr['useCustomerAPI'] === 'C') { + \ws_mollie\Hook\Checkbox::execute($args_arr); + } + +} catch (Exception $e) { + Helper::logExc($e); +} \ No newline at end of file diff --git a/version/205/frontend/181_sync.php b/version/205/frontend/181_sync.php new file mode 100644 index 0000000..22022a9 --- /dev/null +++ b/version/205/frontend/181_sync.php @@ -0,0 +1,14 @@ +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 Rmns)TMnX}%M${5 literal 0 HcmV?d00001 diff --git a/version/205/frontend/img/trust_fre.png b/version/205/frontend/img/trust_fre.png new file mode 100644 index 0000000000000000000000000000000000000000..ed1a2f6f03c56f6748aac8af0352de7fc0afd3a4 GIT binary patch literal 17319 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 Mu#8ZJpsxS_1AJc%;s5{u literal 0 HcmV?d00001 diff --git a/version/205/frontend/img/trust_ger.png b/version/205/frontend/img/trust_ger.png new file mode 100644 index 0000000000000000000000000000000000000000..e42821b06709e8f4371c66cfb5759d00df0e1afd GIT binary patch literal 15352 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 + diff --git a/version/205/paymentmethod/JTLMollie.php b/version/205/paymentmethod/JTLMollie.php new file mode 100644 index 0000000..27bfaea --- /dev/null +++ b/version/205/paymentmethod/JTLMollie.php @@ -0,0 +1,268 @@ +cModulId = "kPlugin_" . self::Plugin()->kPlugin . "_mollie" . $moduleID; + } + + /** + * @param Bestellung $order + * @return PaymentMethod + */ + public function setOrderStatusToPaid($order) + { + // If paid already, do nothing + if ((int)$order->cStatus >= BESTELLUNG_STATUS_BEZAHLT) { + return $this; + } + return parent::setOrderStatusToPaid($order); + } + + /** + * Prepares everything so that the Customer can start the Payment Process. + * Tells Template Engine. + * + * @param Bestellung $order + * @return void + */ + public function preparePaymentProcess($order) + { + + parent::preparePaymentProcess($order); + + try { + + if ($this->duringCheckout && !static::ALLOW_PAYMENT_BEFORE_ORDER) { + $this->Log(sprintf("Zahlung vor Bestellabschluss nicht unterstützt (%s)!", $order->cBestellNr), sprintf("#%s", $order->kBestellung), LOGLEVEL_ERROR); + return; + } + + $payable = (float)$order->fGesamtsumme > 0; + if (!$payable) { + $this->Log(sprintf("Bestellung '%s': Gesamtsumme %.2f, keine Zahlung notwendig!", $order->cBestellNr, $order->fGesamtsumme), sprintf("#%s", $order->kBestellung)); + return; + } + + $paymentOptions = []; + + $api = array_key_exists($this->moduleID . '_api', self::Plugin()->oPluginEinstellungAssoc_arr) ? self::Plugin()->oPluginEinstellungAssoc_arr[$this->moduleID . '_api'] : 'order'; + + $paymentOptions = array_merge($paymentOptions, $this->getPaymentOptions($order, $api)); + + if ($api === 'payment') { + $checkout = new PaymentCheckout($order); + $payment = $checkout->create($paymentOptions); + /** @noinspection NullPointerExceptionInspection */ + $url = $payment->getCheckoutUrl(); + } else { + $checkout = new OrderCheckout($order); + $mOrder = $checkout->create($paymentOptions); + /** @noinspection NullPointerExceptionInspection */ + $url = $mOrder->getCheckoutUrl(); + } + + ifndef('MOLLIE_REDIRECT_DELAY', 3); + $checkoutMode = self::Plugin()->oPluginEinstellungAssoc_arr['checkoutMode']; + Shop::Smarty()->assign('redirect', $url) + ->assign('checkoutMode', $checkoutMode); + if ($checkoutMode === 'Y' && !headers_sent()) { + header('Location: ' . $url); + } + } catch (Exception $e) { + $this->Log('mollie::preparePaymentProcess: ' . $e->getMessage() . ' - ' . print_r(['cBestellNr' => $order->cBestellNr], 1), '#' . $order->kBestellung, LOGLEVEL_ERROR); + Shop::Smarty()->assign('oMollieException', $e) + ->assign('tryAgain', Shop::getURL() . '/bestellab_again.php?kBestellung=' . $order->kBestellung); + } + } + + public function Log($msg, $data = null, $level = LOGLEVEL_NOTICE) + { + ZahlungsLog::add($this->moduleID, "[" . microtime(true) . " - " . $_SERVER['PHP_SELF'] . "] " . $msg, $data, $level); + return $this; + } + + public function getPaymentOptions(Bestellung $order, $apiType) + { + return []; + } + + /** + * @param Bestellung $order + * @param string $hash + * @param array $args + */ + public function handleNotification($order, $hash, $args) + { + parent::handleNotification($order, $hash, $args); + try { + $orderId = $args['id']; + $checkout = null; + if (strpos($orderId, 'tr_') === 0) { + $checkout = new PaymentCheckout($order); + } else { + $checkout = new OrderCheckout($order); + } + $checkout->handleNotification($hash); + + } catch (Exception $e) { + $checkout->Log(sprintf("mollie::handleNotification: Fehler bei Bestellung '%s': %s\n%s", $order->cBestellNr, $e->getMessage(), print_r($args, 1)), LOGLEVEL_ERROR); + } + } + + /** + * @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 (API::getMode()) { + $selectable = trim(self::Plugin()->oPluginEinstellungAssoc_arr['test_api_key']) !== ''; + } else { + $selectable = trim(self::Plugin()->oPluginEinstellungAssoc_arr['api_key']) !== ''; + if (!$selectable) { + Jtllog::writeLog("Live API Key missing!"); + } + } + if ($selectable) { + try { + $locale = AbstractCheckout::getLocale($_SESSION['cISOSprache'], Session::getInstance()->Customer()->cLand); + $amount = Session::getInstance()->Basket()->gibGesamtsummeWarenExt([ + C_WARENKORBPOS_TYP_ARTIKEL, + C_WARENKORBPOS_TYP_KUPON, + C_WARENKORBPOS_TYP_GUTSCHEIN, + C_WARENKORBPOS_TYP_NEUKUNDENKUPON, + ], true) * Session::getInstance()->Currency()->fFaktor; + if ($amount <= 0) { + $amount = 0.01; + } + $selectable = self::isMethodPossible( + static::METHOD, + $locale, + Session::getInstance()->Customer()->cLand, + Session::getInstance()->Currency()->cISO, + $amount + ); + } catch (Exception $e) { + Helper::logExc($e); + $selectable = false; + } + } + return $selectable && parent::isSelectable(); + } + + /** + * @param $method + * @param $locale + * @param $billingCountry + * @param $currency + * @param $amount + * @return bool + * @throws ApiException + */ + protected static function isMethodPossible($method, $locale, $billingCountry, $currency, $amount) + { + + $api = new API(API::getMode()); + + if (!array_key_exists('mollie_possibleMethods', $_SESSION)) { + $_SESSION['mollie_possibleMethods'] = []; + } + + $key = md5(serialize([$locale, $billingCountry, $currency, $amount])); + if (!array_key_exists($key, $_SESSION['mollie_possibleMethods'])) { + $active = $api->Client()->methods->allActive([ + 'locale' => $locale, + 'amount' => [ + 'currency' => $currency, + 'value' => number_format($amount, 2, ".", "") + ], + 'billingCountry' => $billingCountry, + 'resource' => 'orders', + 'includeWallets' => 'applepay', + ]); + foreach ($active as $a) { + $_SESSION['mollie_possibleMethods'][$key][] = (object)['id' => $a->id]; + } + } + + if ($method !== '') { + foreach ($_SESSION['mollie_possibleMethods'][$key] as $m) { + if ($m->id === $method) { + return true; + } + } + } else { + return true; + } + + return false; + + } + + /** + * @param array $args_arr + * @return bool + */ + public function isValidIntern($args_arr = []) + { + return $this->duringCheckout + ? static::ALLOW_PAYMENT_BEFORE_ORDER && parent::isValidIntern($args_arr) + : parent::isValidIntern($args_arr); + } + + /** + * @return int + */ + public function getExpiryDays() + { + return (int)min(abs((int)Helper::oPlugin()->oPluginEinstellungAssoc_arr[$this->cModulId . '_dueDays']), static::MAX_EXPIRY_DAYS) ?: static::MAX_EXPIRY_DAYS; + } + +} diff --git a/version/205/paymentmethod/JTLMollieApplePay.php b/version/205/paymentmethod/JTLMollieApplePay.php new file mode 100644 index 0000000..4b23bf4 --- /dev/null +++ b/version/205/paymentmethod/JTLMollieApplePay.php @@ -0,0 +1,15 @@ +oRechnungsadresse->cMail; + $paymentOptions['locale'] = AbstractCheckout::getLocale($_SESSION['cISOSprache'], $order->oRechnungsadresse->cLand); + } + + $dueDays = $this->getExpiryDays(); + if ($dueDays > 3) { + $paymentOptions['dueDate'] = date('Y-m-d', strtotime("+$dueDays DAYS")); + } + return $paymentOptions; + } +} diff --git a/version/205/paymentmethod/JTLMollieBelfius.php b/version/205/paymentmethod/JTLMollieBelfius.php new file mode 100644 index 0000000..00c8e7c --- /dev/null +++ b/version/205/paymentmethod/JTLMollieBelfius.php @@ -0,0 +1,13 @@ +clearToken(); + } + + protected function clearToken() + { + $this->unsetCache(self::CACHE_TOKEN) + ->unsetCache(self::CACHE_TOKEN_TIMESTAMP); + return true; + } + + public function handleAdditional($aPost_arr) + { + + $components = self::Plugin()->oPluginEinstellungAssoc_arr[$this->moduleID . '_components']; + $profileId = self::Plugin()->oPluginEinstellungAssoc_arr['profileId']; + + if ($components === 'N' || !$profileId || trim($profileId) === '') { + return parent::handleAdditional($aPost_arr); + } + + $cleared = false; + if (array_key_exists('clear', $aPost_arr) && (int)$aPost_arr['clear']) { + $cleared = $this->clearToken(); + } + + if ($components === 'S' && array_key_exists('skip', $aPost_arr) && (int)$aPost_arr['skip']) { + return parent::handleAdditional($aPost_arr); + } + + try { + $trustBadge = (bool)self::Plugin()->oPluginEinstellungAssoc_arr[$this->moduleID . '_loadTrust']; + $locale = AbstractCheckout::getLocale($_SESSION['cISOSprache'], Session::getInstance()->Customer() ? Session::getInstance()->Customer()->cLand : null); + $mode = API::getMode(); + $errorMessage = json_encode(self::Plugin()->oPluginSprachvariableAssoc_arr['mcErrorMessage']); + } catch (Exception $e) { + Jtllog::writeLog($e->getMessage() . "\n" . print_r(['e' => $e], 1)); + return parent::handleAdditional($aPost_arr); + } + + if (!$cleared && array_key_exists('cardToken', $aPost_arr) && ($token = trim($aPost_arr['cardToken']))) { + return $this->setToken($token) && parent::handleAdditional($aPost_arr); + } + + $token = false; + if (($ctTS = (int)$this->getCache(self::CACHE_TOKEN_TIMESTAMP)) && $ctTS > time()) { + $token = $this->getCache(self::CACHE_TOKEN); + } + + Shop::Smarty()->assign('profileId', $profileId) + ->assign('trustBadge', $trustBadge ? self::Plugin()->cFrontendPfadURLSSL . 'img/trust_' . $_SESSION['cISOSprache'] . '.png' : false) + ->assign('components', $components) + ->assign('locale', $locale ?: 'de_DE') + ->assign('token', $token ?: false) + ->assign('testMode', $mode ?: false) + ->assign('errorMessage', $errorMessage ?: null) + ->assign('mollieLang', self::Plugin()->oPluginSprachvariableAssoc_arr); + + return false; + } + + protected function setToken($token) + { + $this->addCache(self::CACHE_TOKEN, $token) + ->addCache(self::CACHE_TOKEN_TIMESTAMP, time() + 3600); + return true; + } + + public function getPaymentOptions(Bestellung $order, $apiType) + { + + $paymentOptions = []; + + if ($apiType === 'payment') { + if ($order->Lieferadresse !== null) { + if (!$order->Lieferadresse->cMail) { + $order->Lieferadresse->cMail = $order->oRechnungsadresse->cMail; + } + $paymentOptions['shippingAddress'] = Address::factory($order->Lieferadresse); + } + + $paymentOptions['billingAddress'] = Address::factory($order->oRechnungsadresse); + } + if ((int)$this->getCache(self::CACHE_TOKEN_TIMESTAMP) > time() && ($token = trim($this->getCache(self::CACHE_TOKEN)))) { + $paymentOptions['cardToken'] = $token; + } + return $paymentOptions; + } + +} diff --git a/version/205/paymentmethod/JTLMollieEPS.php b/version/205/paymentmethod/JTLMollieEPS.php new file mode 100644 index 0000000..df84b89 --- /dev/null +++ b/version/205/paymentmethod/JTLMollieEPS.php @@ -0,0 +1,12 @@ + substr($order->cBestellNr, 0, 13)]; + } +} diff --git a/version/205/paymentmethod/JTLMollieKlarnaPayLater.php b/version/205/paymentmethod/JTLMollieKlarnaPayLater.php new file mode 100644 index 0000000..0bfc8d1 --- /dev/null +++ b/version/205/paymentmethod/JTLMollieKlarnaPayLater.php @@ -0,0 +1,18 @@ +Lieferadresse !== null) { + if (!$order->Lieferadresse->cMail) { + $order->Lieferadresse->cMail = $order->oRechnungsadresse->cMail; + } + $paymentOptions['shippingAddress'] = Address::factory($order->Lieferadresse); + } + } + + + return $paymentOptions; + } + +} diff --git a/version/205/paymentmethod/JTLMolliePaysafecard.php b/version/205/paymentmethod/JTLMolliePaysafecard.php new file mode 100644 index 0000000..b48e371 --- /dev/null +++ b/version/205/paymentmethod/JTLMolliePaysafecard.php @@ -0,0 +1,17 @@ + $order->oKunde->kKunde] : []; + } +} diff --git a/version/205/paymentmethod/JTLMolliePrzelewy24.php b/version/205/paymentmethod/JTLMolliePrzelewy24.php new file mode 100644 index 0000000..355ecdf --- /dev/null +++ b/version/205/paymentmethod/JTLMolliePrzelewy24.php @@ -0,0 +1,18 @@ + $order->oRechnungsadresse->cMail] : []; + } + +} diff --git a/version/205/paymentmethod/JTLMollieSofort.php b/version/205/paymentmethod/JTLMollieSofort.php new file mode 100644 index 0000000..0a4d191 --- /dev/null +++ b/version/205/paymentmethod/JTLMollieSofort.php @@ -0,0 +1,13 @@ +OH(NI>=T42<+x9g>;*Gy9DrKtJl=F((p(~XhRMojR(!TROq)4##x zi;wfn&C+>%^UTiFKSt7JYSXp1>ZPgDP*&5InbUcF<%^K^*xKlsoYHP{(wCajZ*$Ra zbJNPo(OY2BWNFmE!S~qO{POeCTVT|{z|(GX;Bt54e}mdsUi8b(sL>`X0000JbW%=J z01%HLkU-Cn-_OsV&!6AlpP5D4UE1#Sax&aZg(%L>z8x33MOZZ8H?WJ;;n51dMe)(}9UH1j29 ze@0RGfq`^s0!X#X7!_srsUP@btltZoyHfrIVq@*+2f)Ge+&BuBcbdrjKu5}NuE;){Yi3#o7gOK=v6Y0{rAbqNgQSz}}0I~5?ej{GsP%?vN z=_l4!?VPOmM>R@!2oOAkd1t|Pb#@H>-d=$PnbBs7=u%Z>9N;0iml z2#guk2rk-V%mMEvxQCZ1@+-_*(mao=fPWKs%h@Mp0)~gcfgO7j{4M(n<{@x^Z^Hk! ze1;0X32xx)(NPC3aetZbtnBss>W2NT-v%Bch%He^5RXIyLDWRp5;o{lcPr>qmkRZj lpHDtfd;A2~X0zTP_aA;i{an>LN7rz#m}I!{TEUogY_hW!fX z1?mg>C*-erx%(so1LG!77srr_xVP7C<}EQ0XbW_HZ(Bb#ysRpA(wRN~nf+#OlTe%( zXkfncL^KKCCrg-Lh=kEnU|a;ZB9QaR>Td+?i96wEUURmd^*;_;}q*?JtCN zs9v0_oUIYrJ>{ItUF)Suj=nY*E;y-_bg}zQ;ZT|@FU4Qeut^B)WfWUjV9g-3v@K+f-ik;kV{MOr_6wK;GGik>mTp$V%-RtP)+CPEi`n!UgTe~DWM4fFWeR( literal 0 HcmV?d00001 diff --git a/version/205/paymentmethod/img/method/bancontact@2x.png b/version/205/paymentmethod/img/method/bancontact@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..a87af77d20330ab4ee197fd750d0bd39a5b10f90 GIT binary patch literal 582 zcmV-M0=fN(P)lk!lq%lq?@9+Qr z|M>X$=jZ1jWQqR%{`vX&|JVTk=U{-T&j0$~pTFAg&hoWPVjpU$|LlN(mQMfcfPbmZpr$+j>2Uw#P;ZV{AZe)(UZem0@6X@u|MkEB z;XwWU{r~1*Ky`MXzS=N!uW*i8kF?YfT$A7F^MIC5pQk%!Gip%)000nlQchC<&w%eB zkRX4bpb&7+Z;x=Vl85vF00AONL_t(|UhS6GZp0uI1+V+IBnNQY-qL&T?f<_j%Vs4k zWi4ZPi#+c$LIR;fk}z^m8)w(24LdL-qBSjmiImqQ6%1%eKSC_H5hBJOQ3wcbh=A9j z0E`>M;F1Gj9uRN{NX-L}@Ce`*0RKJE1nw{TTbXGF`gs|rT7l!dln0%_EVm0RbGyKB zqJ*zRaiSTxE%@_=;_x?lSs8dz{y6#LPln}z>8GT40dLB`KB#<1qlM(E;D0OsM*0?TeIhg`dn6;Q{6Fh2l%qOS4K%wo8-q7AUD{?yGF(55vm4C&H_FzBH+J=d4+57}kr Up-!czfB*mh07*qoM6N<$g3OCHTL1t6 literal 0 HcmV?d00001 diff --git a/version/205/paymentmethod/img/method/banktransfer@2x.png b/version/205/paymentmethod/img/method/banktransfer@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..c70206bef4893f23fcd59d436273108d2f2eebc7 GIT binary patch literal 801 zcmV++1K#|JP)lk!lq*=;-9+mkX z{{U2_ztrjP@9%)A(*D5?-|6)J(MtZwET6yKpugSt`1lZBsz86cAZf7q`T3Bv*Z%(g z-|F=K#U1|5JO0^dAZoDx_u=pL`RC{7_xJZ;l*j-3@c!I)@AdkSwAlXDS^mf@aG%W2 z;O`J$tN-Md>+9=KiNUYR<6xA=@AUcq@WXGP%>DiS|LnB>%sc+*q+gWBFm$#4l$oJ=bMJL) zN$}UM z^EEI7D0q#*=`w@Mb&#yX6$WP@x&}s<8JvJ@pvqecQO^sez9^Xbs$t>(|Nn0Y_`k@X z`u+Uv`wm6F?mz#2{?4!aFGTBV&I9cbE(!7rW)PTg{{H;_^9ubA3J&Kd+&@2If#l5V zkwEFKo-U3d6>)E`o#Z>Lz~g$+{n^fDUKQE@|Mgd!a9=T#&e{4(sr-HO1o4KQ>uv;= zWX2_)yrQzk;QY@iN0x35n7oK-g-2+63_H(@QU|u6Z>|Z!r6lZ1zes9a?+x$E9%YhzX@O1Ta JS?83{1OT9Jm%RW0 literal 0 HcmV?d00001 diff --git a/version/205/paymentmethod/img/method/creditcard@2x.png b/version/205/paymentmethod/img/method/creditcard@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..b08be792753326b65345c752a6f350182a9393d2 GIT binary patch literal 3125 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 P00000NkvXXu0mjf3Vis# literal 0 HcmV?d00001 diff --git a/version/205/paymentmethod/img/method/directdebit@2x.png b/version/205/paymentmethod/img/method/directdebit@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..514ff845b84d38cd8eb97b9e2c53e5c117967944 GIT binary patch literal 801 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 literal 0 HcmV?d00001 diff --git a/version/205/paymentmethod/img/method/giropay@2x.png b/version/205/paymentmethod/img/method/giropay@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..b787e1fee50c9bcca112f734ef4bcbd4ecfb6d6b GIT binary patch literal 602 zcmV-g0;T5Kx~EOrH!)pASu;4ojd8OQ8=; zpbt!;!_w#B>GK{}r)iJG@bvggdAR@o{+6-TrM%mCn#w$GvMpk*ho#Tb-RaC5+y)hho537JnGBqPA~G@Ik#rt1jWCNmt_X5yY-;OM4Sm|;L0fCz(H!a59C z!6FQJ1`O=K0(U?&WmHmQ%ovl1g=xY%=0>sX7T{!DDr3#1AfT>{>*NQdp;XxeDnn^6 z;Fg|~18)oh=#B%J574HG=ZK=b0(2)=ZWs@6u|Psp2S`Ms-aSCKNc4dZ3ml0Y1JpF0 zACT7(WFOdH$J={=+}Kh?t@=QTh`Y)S;{lL4q2$K&0aK;&(@GqDK&DI^R~^tLy#OA$ z1Nay30gQkc{Q&0jzz(SpmbnlhVhfzVhaBhB0($}wh1S_^$N7}lg}e4p3Ic|F4;Z~b zTY@72isxg1#8BrSfnxv^S{6kiGl4E$H2v|f@*S9m0aJJk172Vm21F3Hg)IO)g#GGT oVe}rh6KIQG--ZM8)e@S10aM=ZI#^TblmGw#07*qoM6N<$f@FIOx&QzG literal 0 HcmV?d00001 diff --git a/version/205/paymentmethod/img/method/ideal@2x.png b/version/205/paymentmethod/img/method/ideal@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..efc4315a96a6b2d9b160578a65fe52206783f2ca GIT binary patch literal 845 zcmV-T1G4;yP)lk!ZZ65OMGC?}UYf;o;!m;NZf-!qXsn`1tsvqob6RlsGvz=jZ45_xJw({`vX& z+CYuwfU@xL?-Nv%`QPmApT=fqW&i*F(b3WK zzuD%1v(zAZ>+9>Xv$F87&$F|$@bK^%8W`-K#nT^p^1s=^!okAA!Tj&_DJdxZ{r%~X zz3Gp=&=7F!pvK@}pYN~F>5#mWl#|_1mb0_6g@uIHFobn>b?J}1M@UB*8yIC~W#VwE zc6N2$P?z9fpjKB^=ker~0000HbW%=J0PlbhkiUP=Adhe$&v1`#zea&7rvLx}*GWV{ zRCr#^*2j+9Fc5%YO7?ntl9{1;aqqou@0;Fxd;j;y*jNN`HV2Bl>~|3_{4oLqkzy%V z*t96C%}2Z9&SQ)86vWClksDVqqe|=&Z3|YQQjA*4CE6Eai>Qp6VzP3=CKt6Gk}WnU zMr|=|2#YGH?I~G;2n`TD#K5)puk^^z67b+ZZd-naz)7$!d_QRdc|mw#b1~<{2k2)FEaYF&OT-`GX$RPM#Nt`QAi#wXJk>zhFTO>59`Wo^#}<>sMjOed(+{-3ru0A7D$0jI558$ z)N0PF!RsCe2|{A+{jU4@5&uc>v9T(>X>= zpc$wJPDAG6XudKWan^4w_bUdHVBPG<>jQiVOn&QMzg?RgEbW=`(e{u7#up5;D^8W3 z2%8R3n@hIHS^6WCiFSq9p;8&OR7*Sn%M-cP>{s2YOOzKYHtDf;#GS4DUiRI4c22NA XzpeJ7+7%dW00000NkvXXu0mjfybi$$ literal 0 HcmV?d00001 diff --git a/version/205/paymentmethod/img/method/inghomepay@2x.png b/version/205/paymentmethod/img/method/inghomepay@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..538f219588886db215757eafd5c5151241f18b5a GIT binary patch literal 1118 zcmV-k1flzhP)`_0RK|}|55<|Q2_r?0RL0~|5E_}r-1)w9RKX&|5E_}=Gy;L z0RR90|6UOPlVJbp-~WC<|J1+#zn}l9fd6P9|A|olb1?tk&;RxB|Mc(wo^bzkF#pQ0 z|Fn<)>fisgkpF2Q|G%LBsek{okpG@<|H-fazM%hUAODC@|H-ibs(=5~!2gtB|K894 zs(@(VAMyYI01|XkPE!C7&ySx#AdugXK#$)bkdUC?LT6GX000A7Nkl+_F4;G0`t->#NE zT;V&r`f!+EySiCj<6V7Pt?{mYTH&4jj{)gM0TN(F3?6st+kjw6 z>LApXPB>Unt8V~;Cik9f49AhQ!$i7^fuL#4vW=&{86JR|lTsG~BRymzfEs|JX9J1K z03Dw$1C&G3WKK=%kB`J1r1*<~s2`z=k6T78&3xGOL&RV&0xXfJ0Ql@xfEn*A1CX9E zQ!WBD5?VbTK7XTsCp`U6crw}TsH%60W z2hoh@0nLYSxRBab{+9<3C+^Mz9xYb&ZxhMVDb+cqriY2<9AG-<8gN)^Cix5?)@kAU z;?6$;-SN`NKvD-cR@w%n?9AWi0I~xRElDnK5^Rh@FtDVHX8@ZJfJl->N&_A{l2bso z2x`kJr-3lmJ%9)DK@>~Q{7brt3fNKr^rbrq+|{-iAekxBG;uoyGqur4Ei0S?0=Yll zF_SR>W}x;7ttLalDFCI-OXsp?(S;*|rkk|uOcTs~fUR;0m?79z>!T@dSC<#zVpen3 zDj@L*GoMZY$tw7C*m%o|vLvel!qz~FMPzph=x6{KTjppdC7aC#VVdHg)$wl$bf*AC z1-Rnnz*LgVO4|B5HX#U@PXUn*;sq_sC5u*2fG7j7o&o~>%Wn3WWcg~#QmPptG|8+k2H7XW|=xVi9nUeg`1*I2IB*YJ(+JNL|VD24JQDXa_~} zqMBf8fF~Vbz5wvk*3xb81`yK5AZAEW$9)?Qt+BO>C3E@1Aktu4fz|6HW^Y;1@lk!lq%mkX z{~%3y0h-K!%;mq#+4%VQ5J7OCv&KMYjPLUG@9*#T_xE6cpCPBxaK_?)nX{kS?7!yn zfSI!2=Is9d{_pwx05oR#`T5`T`RC{7L9^Llzu!=FmQcCekkjew>+3LDf{>=XK(pDe zzt4c0vd`J#Fs;_V%-D~nykNlKAg9yc^7t^U)_~3BfX(J`#^Vv8&k>-{-}3p8(&?|? z?{JN&{r&x)v&FFA?=V_}aEz&7z~7M5=+D{X&+PS}+3awQs351(ptHqzpNxV4000qm zQchCIy&+X> z=*5Ul;OaQ@NK`Vzy8t_g2?_Jis)3C$i910Xw$PIU9&Uk!LpkskEkL9-LfkOWJAbaP zUroip18r(eg}^hN*BXg{sb1!Yfc6S#iGXvxN(6jb7x=sau0_D;#S-`?0_b=FJSG`H zPqbnfvWg$g}i**@5@#v5NT=$lzqSQdXDg|8f zIHlhJQN%Mfm~#2YP9b1YgB(!GAN!r?CIjA)sTANZfG||7{JhG5H)Vm3e?0>E>_vVi zq!;d4SOSQYxt#%m;F70Lx8o{r!Tt9&c8CI14(M}40nf9jzsNQAmkVA7gAM$Z|1+@m z0b{)*&IIp+jVE#-MjL9Dd6xv65#{P&<3u77*DDnbtf@m157r`vbG^_r?Ff8 d>Rr1A+%FMH_Q$8Zwr>Cc002ovPDHLkV1oT`waEYg literal 0 HcmV?d00001 diff --git a/version/205/paymentmethod/img/method/klarna@2x.png b/version/205/paymentmethod/img/method/klarna@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..e28a187b81e7c5a6256fea7382a643762746dd1e GIT binary patch literal 896 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 literal 0 HcmV?d00001 diff --git a/version/205/paymentmethod/img/method/paypal@2x.png b/version/205/paymentmethod/img/method/paypal@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..a816d7201f59ea7cef713f5e7895e66dcd6ee9a7 GIT binary patch literal 626 zcmV-&0*(ENP)zW{Q;0CK+oaK8X?zW{Q<0CB+pa=`#_!2of;na1S+alrro z|IFg@&*bxRu-m`e?~lRb-|hDbcETox$#AdRv()Q`yWm5X&|s$5P@dDD$>-eb_JFwG zpUUS$m(j@K@sPpeFpSLa_WMAU&p?#W{Qdsu^7&w=*MGR*^7#DO>Gd#+%P@?~P@U7S z((9ba=CIQ0sn6-_^!k0a-V=Mp)8_OXfyX(K&a%|&;_mkldc-e_%lZ5LgSp`#gUC6M z&erGk#LeN$0000GbW%=J0M8)rfN+qXfDoX6Z;yYFN6jxl0003wNklC4+MXiktqCYwRgSg6)KJbf z5Lj1?Y5+oU@|#dstX9C|0Ujt`J{M4b8Wr^cdi(ak0iFt>ORE}Nts8qh=FWCkI)}aEnE&{1?2hI?PIY68@ zbOdbw0PvXrf5i!Szy>sZ79ap>ye%)UHj^sMYbqagD6U zaJzaI>n$ypF23oVdS#o6|W|*DFT6j;X_Pjl^+{$7FxcM`F8{J!B6QqfZ6J=?T z0Z*i4z#}$g7~II(N7`*?T& O0000+D{~L?`zkmGy`PKgqj{m>0 z^Z&xI|35zdzp(26fxiDA9{<0v`v1;`{~L<_uT1&>;_Ck$4fn+3S%6jwlmz(&Gn{vr zARutRf5Q2Gh4~8e7rbanOaaP$^>lFzsfc?!?c};<10L727Z_ycPF(r9`v3o4QC^`f zNy*irThr_Lx8*f4F=sBE;Is9vL&{b+wWF_Q`cLpRlDMX^fZ@i14v}pdO3hrZ8V-u{ z6@GBmNPp@1=O;WPYJWl57EYgv)6tK(j<>!KX1Tkg-1yN7-6M=yr*jX!QWr1lo!e&; zepvX8JR>o1saCg`3ZOWgj;^L2z+zGho&3IENy|Lc5*g&izjA{*O9T;DjDIk7S9e6n)( p;e>?q6P^m(l+{vMe5&Mx9fO|m{vZE%WkG?%;OXk;vd$@?2>_eS)Oi2^ literal 0 HcmV?d00001 diff --git a/version/205/paymentmethod/tpl/bestellabschluss.tpl b/version/205/paymentmethod/tpl/bestellabschluss.tpl new file mode 100644 index 0000000..b26d8ef --- /dev/null +++ b/version/205/paymentmethod/tpl/bestellabschluss.tpl @@ -0,0 +1,26 @@ +{if isset($oMollieException)} +
+ {$oMollieException->getMessage()} +
+ +{/if} + +{if isset($redirect) && $redirect != ''} + + {if $checkoutMode == 'D'} + + {/if} +{/if} + diff --git a/version/205/paymentmethod/tpl/mollieComponents.tpl b/version/205/paymentmethod/tpl/mollieComponents.tpl new file mode 100644 index 0000000..987abf1 --- /dev/null +++ b/version/205/paymentmethod/tpl/mollieComponents.tpl @@ -0,0 +1,148 @@ +

{$mollieLang.cctitle}

+ +
+ +
+ + {if $token !== false} + +
+
+ {$mollieLang.clearDescr} +
+
+ +
+
+ + {if $trustBadge} +
+ PCI-DSS SAQ-A compliant +
+ {/if} + + {else} + + +
+ +
+
+
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+ +
+
+ + +
+
+ + {if $trustBadge} +
+ PCI-DSS SAQ-A compliant +
+ {/if} + {if $components == 'S'} + + {/if} +
+ +{/if} + + + + + + \ No newline at end of file diff --git a/version/205/sql/204.sql b/version/205/sql/204.sql new file mode 100644 index 0000000..784d136 --- /dev/null +++ b/version/205/sql/204.sql @@ -0,0 +1,2 @@ +ALTER TABLE `xplugin_ws_mollie_shipments` + CHANGE `kLieferschien` `kLieferschein` INT(11) NOT NULL; \ No newline at end of file diff --git a/version/205/tpl/_alerts.tpl b/version/205/tpl/_alerts.tpl new file mode 100644 index 0000000..5279fa3 --- /dev/null +++ b/version/205/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} From 53bd3cfcb4233ce8c143f02769c8e0537143bd91 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Wed, 4 Aug 2021 14:02:03 +0200 Subject: [PATCH 255/280] fix #144 --- composer.json | 4 +- composer.lock | 707 +----------------- version/205/class/API.php | 7 +- .../205/class/Checkout/AbstractCheckout.php | 92 ++- version/205/class/Checkout/OrderCheckout.php | 6 + .../205/class/Checkout/PaymentCheckout.php | 20 +- 6 files changed, 104 insertions(+), 732 deletions(-) diff --git a/composer.json b/composer.json index 8e601b9..100ff6a 100644 --- a/composer.json +++ b/composer.json @@ -5,9 +5,9 @@ "require": { "ext-json": "*", "ext-curl": "*", + "ext-openssl": "*", "php": ">=5.6", - "mollie/mollie-api-php": "^v2.31.1", - "guzzlehttp/guzzle": "^6.5.5" + "mollie/mollie-api-php": "^v2.37.0" }, "require-dev": { "roave/security-advisories": "dev-latest" diff --git a/composer.lock b/composer.lock index ba1b3a2..65e50dd 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "721bbf731782238720f88f8e8a38b737", + "content-hash": "e2dcc50cc251dc1c3ab8989ced37cd2a", "packages": [ { "name": "composer/ca-bundle", @@ -77,207 +77,18 @@ ], "time": "2021-06-07T13:58:28+00:00" }, - { - "name": "guzzlehttp/guzzle", - "version": "6.5.5", - "source": { - "type": "git", - "url": "https://github.com/guzzle/guzzle.git", - "reference": "9d4290de1cfd701f38099ef7e183b64b4b7b0c5e" - }, - "dist": { - "type": "zip", - "url": "https://github.com/gitapi/repos/guzzle/guzzle/zipball/9d4290de1cfd701f38099ef7e183b64b4b7b0c5e", - "reference": "9d4290de1cfd701f38099ef7e183b64b4b7b0c5e", - "shasum": "" - }, - "require": { - "ext-json": "*", - "guzzlehttp/promises": "^1.0", - "guzzlehttp/psr7": "^1.6.1", - "php": ">=5.5", - "symfony/polyfill-intl-idn": "^1.17.0" - }, - "require-dev": { - "ext-curl": "*", - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0", - "psr/log": "^1.1" - }, - "suggest": { - "psr/log": "Required for using the Log middleware" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "6.5-dev" - } - }, - "autoload": { - "psr-4": { - "GuzzleHttp\\": "src/" - }, - "files": [ - "src/functions_include.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" - } - ], - "description": "Guzzle is a PHP HTTP client library", - "homepage": "http://guzzlephp.org/", - "keywords": [ - "client", - "curl", - "framework", - "http", - "http client", - "rest", - "web service" - ], - "time": "2020-06-16T21:01:06+00:00" - }, - { - "name": "guzzlehttp/promises", - "version": "1.4.1", - "source": { - "type": "git", - "url": "https://github.com/guzzle/promises.git", - "reference": "8e7d04f1f6450fef59366c399cfad4b9383aa30d" - }, - "dist": { - "type": "zip", - "url": "https://github.com/gitapi/repos/guzzle/promises/zipball/8e7d04f1f6450fef59366c399cfad4b9383aa30d", - "reference": "8e7d04f1f6450fef59366c399cfad4b9383aa30d", - "shasum": "" - }, - "require": { - "php": ">=5.5" - }, - "require-dev": { - "symfony/phpunit-bridge": "^4.4 || ^5.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.4-dev" - } - }, - "autoload": { - "psr-4": { - "GuzzleHttp\\Promise\\": "src/" - }, - "files": [ - "src/functions_include.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" - } - ], - "description": "Guzzle promises library", - "keywords": [ - "promise" - ], - "time": "2021-03-07T09:25:29+00:00" - }, - { - "name": "guzzlehttp/psr7", - "version": "1.8.2", - "source": { - "type": "git", - "url": "https://github.com/guzzle/psr7.git", - "reference": "dc960a912984efb74d0a90222870c72c87f10c91" - }, - "dist": { - "type": "zip", - "url": "https://github.com/gitapi/repos/guzzle/psr7/zipball/dc960a912984efb74d0a90222870c72c87f10c91", - "reference": "dc960a912984efb74d0a90222870c72c87f10c91", - "shasum": "" - }, - "require": { - "php": ">=5.4.0", - "psr/http-message": "~1.0", - "ralouphie/getallheaders": "^2.0.5 || ^3.0.0" - }, - "provide": { - "psr/http-message-implementation": "1.0" - }, - "require-dev": { - "ext-zlib": "*", - "phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.8 || ^9.3.10" - }, - "suggest": { - "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.7-dev" - } - }, - "autoload": { - "psr-4": { - "GuzzleHttp\\Psr7\\": "src/" - }, - "files": [ - "src/functions_include.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" - }, - { - "name": "Tobias Schultze", - "homepage": "https://github.com/Tobion" - } - ], - "description": "PSR-7 message implementation that also provides common utility methods", - "keywords": [ - "http", - "message", - "psr-7", - "request", - "response", - "stream", - "uri", - "url" - ], - "time": "2021-04-26T09:17:50+00:00" - }, { "name": "mollie/mollie-api-php", - "version": "v2.32.2", + "version": "v2.37.0", "source": { "type": "git", "url": "https://github.com/mollie/mollie-api-php.git", - "reference": "48d3ce280a86e2aa18f56c94b2ae63e30468b773" + "reference": "8e599a4f133341aa8623e0a61e2e77d65725c011" }, "dist": { "type": "zip", - "url": "https://github.com/gitapi/repos/mollie/mollie-api-php/zipball/48d3ce280a86e2aa18f56c94b2ae63e30468b773", - "reference": "48d3ce280a86e2aa18f56c94b2ae63e30468b773", + "url": "https://github.com/gitapi/repos/mollie/mollie-api-php/zipball/8e599a4f133341aa8623e0a61e2e77d65725c011", + "reference": "8e599a4f133341aa8623e0a61e2e77d65725c011", "shasum": "" }, "require": { @@ -351,462 +162,7 @@ "sofortbanking", "subscriptions" ], - "time": "2021-06-08T06:03:46+00:00" - }, - { - "name": "paragonie/random_compat", - "version": "v2.0.20", - "source": { - "type": "git", - "url": "https://github.com/paragonie/random_compat.git", - "reference": "0f1f60250fccffeaf5dda91eea1c018aed1adc2a" - }, - "dist": { - "type": "zip", - "url": "https://github.com/gitapi/repos/paragonie/random_compat/zipball/0f1f60250fccffeaf5dda91eea1c018aed1adc2a", - "reference": "0f1f60250fccffeaf5dda91eea1c018aed1adc2a", - "shasum": "" - }, - "require": { - "php": ">=5.2.0" - }, - "require-dev": { - "phpunit/phpunit": "4.*|5.*" - }, - "suggest": { - "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." - }, - "type": "library", - "autoload": { - "files": [ - "lib/random.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Paragon Initiative Enterprises", - "email": "security@paragonie.com", - "homepage": "https://paragonie.com" - } - ], - "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", - "keywords": [ - "csprng", - "polyfill", - "pseudorandom", - "random" - ], - "time": "2021-04-17T09:33:01+00:00" - }, - { - "name": "psr/http-message", - "version": "1.0.1", - "source": { - "type": "git", - "url": "https://github.com/php-fig/http-message.git", - "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" - }, - "dist": { - "type": "zip", - "url": "https://github.com/gitapi/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", - "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Http\\Message\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" - } - ], - "description": "Common interface for HTTP messages", - "homepage": "https://github.com/php-fig/http-message", - "keywords": [ - "http", - "http-message", - "psr", - "psr-7", - "request", - "response" - ], - "time": "2016-08-06T14:39:51+00:00" - }, - { - "name": "ralouphie/getallheaders", - "version": "3.0.3", - "source": { - "type": "git", - "url": "https://github.com/ralouphie/getallheaders.git", - "reference": "120b605dfeb996808c31b6477290a714d356e822" - }, - "dist": { - "type": "zip", - "url": "https://github.com/gitapi/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", - "reference": "120b605dfeb996808c31b6477290a714d356e822", - "shasum": "" - }, - "require": { - "php": ">=5.6" - }, - "require-dev": { - "php-coveralls/php-coveralls": "^2.1", - "phpunit/phpunit": "^5 || ^6.5" - }, - "type": "library", - "autoload": { - "files": [ - "src/getallheaders.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Ralph Khattar", - "email": "ralph.khattar@gmail.com" - } - ], - "description": "A polyfill for getallheaders.", - "time": "2019-03-08T08:55:37+00:00" - }, - { - "name": "symfony/polyfill-intl-idn", - "version": "v1.19.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-intl-idn.git", - "reference": "4ad5115c0f5d5172a9fe8147675ec6de266d8826" - }, - "dist": { - "type": "zip", - "url": "https://github.com/gitapi/repos/symfony/polyfill-intl-idn/zipball/4ad5115c0f5d5172a9fe8147675ec6de266d8826", - "reference": "4ad5115c0f5d5172a9fe8147675ec6de266d8826", - "shasum": "" - }, - "require": { - "php": ">=5.3.3", - "symfony/polyfill-intl-normalizer": "^1.10", - "symfony/polyfill-php70": "^1.10", - "symfony/polyfill-php72": "^1.10" - }, - "suggest": { - "ext-intl": "For best performance" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.19-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Intl\\Idn\\": "" - }, - "files": [ - "bootstrap.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Laurent Bassin", - "email": "laurent@bassin.info" - }, - { - "name": "Trevor Rowbotham", - "email": "trevor.rowbotham@pm.me" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "idn", - "intl", - "polyfill", - "portable", - "shim" - ], - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2020-10-21T09:57:48+00:00" - }, - { - "name": "symfony/polyfill-intl-normalizer", - "version": "v1.19.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "8db0ae7936b42feb370840cf24de1a144fb0ef27" - }, - "dist": { - "type": "zip", - "url": "https://github.com/gitapi/repos/symfony/polyfill-intl-normalizer/zipball/8db0ae7936b42feb370840cf24de1a144fb0ef27", - "reference": "8db0ae7936b42feb370840cf24de1a144fb0ef27", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "suggest": { - "ext-intl": "For best performance" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.19-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Intl\\Normalizer\\": "" - }, - "files": [ - "bootstrap.php" - ], - "classmap": [ - "Resources/stubs" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill for intl's Normalizer class and related functions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "intl", - "normalizer", - "polyfill", - "portable", - "shim" - ], - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2020-10-23T09:01:57+00:00" - }, - { - "name": "symfony/polyfill-php70", - "version": "v1.19.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php70.git", - "reference": "3fe414077251a81a1b15b1c709faf5c2fbae3d4e" - }, - "dist": { - "type": "zip", - "url": "https://github.com/gitapi/repos/symfony/polyfill-php70/zipball/3fe414077251a81a1b15b1c709faf5c2fbae3d4e", - "reference": "3fe414077251a81a1b15b1c709faf5c2fbae3d4e", - "shasum": "" - }, - "require": { - "paragonie/random_compat": "~1.0|~2.0|~9.99", - "php": ">=5.3.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.19-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Php70\\": "" - }, - "files": [ - "bootstrap.php" - ], - "classmap": [ - "Resources/stubs" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill backporting some PHP 7.0+ features to lower PHP versions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2020-10-23T09:01:57+00:00" - }, - { - "name": "symfony/polyfill-php72", - "version": "v1.19.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php72.git", - "reference": "beecef6b463b06954638f02378f52496cb84bacc" - }, - "dist": { - "type": "zip", - "url": "https://github.com/gitapi/repos/symfony/polyfill-php72/zipball/beecef6b463b06954638f02378f52496cb84bacc", - "reference": "beecef6b463b06954638f02378f52496cb84bacc", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.19-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Php72\\": "" - }, - "files": [ - "bootstrap.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2020-10-23T09:01:57+00:00" + "time": "2021-07-28T16:35:52+00:00" } ], "packages-dev": [ @@ -816,12 +172,12 @@ "source": { "type": "git", "url": "https://github.com/Roave/SecurityAdvisories.git", - "reference": "ef267f15fbe759580779eef9f1aa2b29e637f279" + "reference": "52a126190a36bc9236846f5d42e10bff9ff60d72" }, "dist": { "type": "zip", - "url": "https://github.com/gitapi/repos/Roave/SecurityAdvisories/zipball/ef267f15fbe759580779eef9f1aa2b29e637f279", - "reference": "ef267f15fbe759580779eef9f1aa2b29e637f279", + "url": "https://github.com/gitapi/repos/Roave/SecurityAdvisories/zipball/52a126190a36bc9236846f5d42e10bff9ff60d72", + "reference": "52a126190a36bc9236846f5d42e10bff9ff60d72", "shasum": "" }, "conflict": { @@ -854,8 +210,10 @@ "composer/composer": "<1.10.22|>=2-alpha.1,<2.0.13", "contao-components/mediaelement": ">=2.14.2,<2.21.1", "contao/core": ">=2,<3.5.39", - "contao/core-bundle": ">=4,<4.4.52|>=4.5,<4.9.6|= 4.10.0", + "contao/core-bundle": ">=4,<4.4.52|>=4.5,<4.9.16|>=4.10,<4.11.5|= 4.10.0", "contao/listing-bundle": ">=4,<4.4.8", + "craftcms/cms": "<3.6.7", + "croogo/croogo": "<3.0.7", "datadog/dd-trace": ">=0.30,<0.30.2", "david-garcia/phpwhois": "<=4.3.1", "derhansen/sf_event_mgt": "<4.3.1|>=5,<5.1.1", @@ -877,6 +235,7 @@ "endroid/qr-code-bundle": "<3.4.2", "enshrined/svg-sanitize": "<0.13.1", "erusev/parsedown": "<1.7.2", + "ether/logs": "<3.0.4", "ezsystems/demobundle": ">=5.4,<5.4.6.1", "ezsystems/ez-support-tools": ">=2.2,<2.2.3", "ezsystems/ezdemo-ls-extension": ">=5.4,<5.4.2.1", @@ -907,9 +266,10 @@ "friendsofsymfony/rest-bundle": ">=1.2,<1.2.2", "friendsofsymfony/user-bundle": ">=1.2,<1.3.5", "friendsoftypo3/mediace": ">=7.6.2,<7.6.5", + "froala/wysiwyg-editor": "<3.2.7", "fuel/core": "<1.8.1", "getgrav/grav": "<=1.7.10", - "getkirby/cms": "<3.5.4", + "getkirby/cms": "<=3.5.6", "getkirby/panel": "<2.5.14", "gos/web-socket-bundle": "<1.10.4|>=2,<2.6.1|>=3,<3.3", "gree/jose": "<=2.2", @@ -921,6 +281,7 @@ "illuminate/encryption": ">=4,<=4.0.11|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.40|>=5.6,<5.6.15", "illuminate/view": ">=7,<7.1.2", "impresscms/impresscms": "<=1.4.2", + "intelliants/subrion": "<=4.2.1", "ivankristianto/phpwhois": "<=4.3", "james-heinrich/getid3": "<1.9.9", "joomla/archive": "<1.1.10", @@ -935,9 +296,11 @@ "laravel/framework": "<6.20.26|>=7,<8.40", "laravel/socialite": ">=1,<1.0.99|>=2,<2.0.10", "league/commonmark": "<0.18.3", + "league/flysystem": "<1.1.4|>=2,<2.1.1", "lexik/jwt-authentication-bundle": "<2.10.7|>=2.11,<2.11.3", "librenms/librenms": "<21.1", "livewire/livewire": ">2.2.4,<2.2.6", + "localizationteam/l10nmgr": "<7.4|>=8,<8.7|>=9,<9.2", "magento/community-edition": ">=2,<2.2.10|>=2.3,<2.3.3", "magento/magento1ce": "<1.9.4.3", "magento/magento1ee": ">=1,<1.14.4.3", @@ -950,10 +313,13 @@ "moodle/moodle": "<3.5.17|>=3.7,<3.7.9|>=3.8,<3.8.8|>=3.9,<3.9.5|>=3.10,<3.10.2", "namshi/jose": "<2.2", "neos/flow": ">=1,<1.0.4|>=1.1,<1.1.1|>=2,<2.0.1|>=2.3,<2.3.16|>=3,<3.0.12|>=3.1,<3.1.10|>=3.2,<3.2.13|>=3.3,<3.3.13|>=4,<4.0.6", + "neos/form": ">=1.2,<4.3.3|>=5,<5.0.9|>=5.1,<5.1.3", "neos/neos": ">=1.1,<1.1.3|>=1.2,<1.2.13|>=2,<2.0.4|>=2.3,<2.9.99|>=3,<3.0.20|>=3.1,<3.1.18|>=3.2,<3.2.14|>=3.3,<3.3.23|>=4,<4.0.17|>=4.1,<4.1.16|>=4.2,<4.2.12|>=4.3,<4.3.3", "neos/swiftmailer": ">=4.1,<4.1.99|>=5.4,<5.4.5", "nette/application": ">=2,<2.0.19|>=2.1,<2.1.13|>=2.2,<2.2.10|>=2.3,<2.3.14|>=2.4,<2.4.16|>=3,<3.0.6", "nette/nette": ">=2,<2.0.19|>=2.1,<2.1.13", + "nilsteampassnet/teampass": "<=2.1.27.36", + "nukeviet/nukeviet": "<4.3.4", "nystudio107/craft-seomatic": "<3.3", "nzo/url-encryptor-bundle": ">=4,<4.3.2|>=5,<5.0.1", "october/backend": "<1.1.2", @@ -970,6 +336,7 @@ "oro/platform": ">=1.7,<1.7.4", "padraic/humbug_get_contents": "<1.1.2", "pagarme/pagarme-php": ">=0,<3", + "pagekit/pagekit": "<=1.0.18", "paragonie/random_compat": "<2", "passbolt/passbolt_api": "<2.11", "paypal/merchant-sdk-php": "<3.12", @@ -977,7 +344,7 @@ "personnummer/personnummer": "<3.0.2", "phanan/koel": "<5.1.4", "phpfastcache/phpfastcache": ">=5,<5.0.13", - "phpmailer/phpmailer": "<6.1.6|>=6.1.8,<6.4.1", + "phpmailer/phpmailer": "<6.5", "phpmussel/phpmussel": ">=1,<1.6", "phpmyadmin/phpmyadmin": "<4.9.6|>=5,<5.0.3", "phpoffice/phpexcel": "<1.8.2", @@ -986,7 +353,7 @@ "phpunit/phpunit": ">=4.8.19,<4.8.28|>=5.0.10,<5.6.3", "phpwhois/phpwhois": "<=4.2.5", "phpxmlrpc/extras": "<0.6.1", - "pimcore/pimcore": "<6.8.8", + "pimcore/pimcore": "<10.0.7", "pocketmine/pocketmine-mp": "<3.15.4", "pressbooks/pressbooks": "<5.18", "prestashop/autoupgrade": ">=4,<4.10.1", @@ -1009,8 +376,8 @@ "scheb/two-factor-bundle": ">=0,<3.26|>=4,<4.11", "sensiolabs/connect": "<4.2.3", "serluck/phpwhois": "<=4.2.6", - "shopware/core": "<=6.3.5.2", - "shopware/platform": "<=6.3.5.2", + "shopware/core": "<=6.4.1", + "shopware/platform": "<=6.4.1", "shopware/production": "<=6.3.5.2", "shopware/shopware": "<=5.6.9", "silverstripe/admin": ">=1.0.3,<1.0.4|>=1.1,<1.1.1", @@ -1018,8 +385,8 @@ "silverstripe/cms": "<4.3.6|>=4.4,<4.4.4", "silverstripe/comments": ">=1.3,<1.9.99|>=2,<2.9.99|>=3,<3.1.1", "silverstripe/forum": "<=0.6.1|>=0.7,<=0.7.3", - "silverstripe/framework": "<4.4.7|>=4.5,<4.5.4", - "silverstripe/graphql": ">=2,<2.0.5|>=3,<3.1.2|>=3.2,<3.2.4", + "silverstripe/framework": "<4.7.4", + "silverstripe/graphql": "<=3.5|>=4-alpha.1,<4-alpha.2", "silverstripe/registry": ">=2.1,<2.1.2|>=2.2,<2.2.1", "silverstripe/restfulserver": ">=1,<1.0.9|>=2,<2.0.4", "silverstripe/subsites": ">=2,<2.1.1", @@ -1038,14 +405,14 @@ "squizlabs/php_codesniffer": ">=1,<2.8.1|>=3,<3.0.1", "ssddanbrown/bookstack": "<0.29.2", "stormpath/sdk": ">=0,<9.9.99", - "studio-42/elfinder": "<2.1.49", - "sulu/sulu": "<1.6.34|>=2,<2.0.10|>=2.1,<2.1.1", + "studio-42/elfinder": "<2.1.59", + "sulu/sulu": "<1.6.41|>=2,<2.0.10|>=2.1,<2.1.1", "swiftmailer/swiftmailer": ">=4,<5.4.5", "sylius/admin-bundle": ">=1,<1.0.17|>=1.1,<1.1.9|>=1.2,<1.2.2", "sylius/grid": ">=1,<1.1.19|>=1.2,<1.2.18|>=1.3,<1.3.13|>=1.4,<1.4.5|>=1.5,<1.5.1", "sylius/grid-bundle": ">=1,<1.1.19|>=1.2,<1.2.18|>=1.3,<1.3.13|>=1.4,<1.4.5|>=1.5,<1.5.1", "sylius/resource-bundle": "<1.3.14|>=1.4,<1.4.7|>=1.5,<1.5.2|>=1.6,<1.6.4", - "sylius/sylius": "<1.6.9|>=1.7,<1.7.9|>=1.8,<1.8.3", + "sylius/sylius": "<1.6.9|>=1.7,<1.7.9|>=1.8,<1.8.3|>=1.9,<1.9.5", "symbiote/silverstripe-multivaluefield": ">=3,<3.0.99", "symbiote/silverstripe-queuedjobs": ">=3,<3.0.2|>=3.1,<3.1.4|>=4,<4.0.7|>=4.1,<4.1.2|>=4.2,<4.2.4|>=4.3,<4.3.3|>=4.4,<4.4.3|>=4.5,<4.5.1|>=4.6,<4.6.4", "symbiote/silverstripe-versionedfiles": "<=2.0.3", @@ -1069,9 +436,9 @@ "symfony/security-core": ">=2.4,<2.6.13|>=2.7,<2.7.9|>=2.7.30,<2.7.32|>=2.8,<3.4.49|>=4,<4.4.24|>=5,<5.2.9", "symfony/security-csrf": ">=2.4,<2.7.48|>=2.8,<2.8.41|>=3,<3.3.17|>=3.4,<3.4.11|>=4,<4.0.11", "symfony/security-guard": ">=2.8,<3.4.48|>=4,<4.4.23|>=5,<5.2.8", - "symfony/security-http": ">=2.3,<2.3.41|>=2.4,<2.7.51|>=2.8,<3.4.48|>=4,<4.4.23|>=5,<5.2.8", + "symfony/security-http": ">=2.3,<2.3.41|>=2.4,<2.7.51|>=2.8,<3.4.48|>=4,<4.4.23|>=5,<5.2.8|>=5.3,<5.3.2", "symfony/serializer": ">=2,<2.0.11", - "symfony/symfony": ">=2,<3.4.49|>=4,<4.4.24|>=5,<5.2.9", + "symfony/symfony": ">=2,<3.4.49|>=4,<4.4.24|>=5,<5.2.9|>=5.3,<5.3.2", "symfony/translation": ">=2,<2.0.17", "symfony/validator": ">=2,<2.0.24|>=2.1,<2.1.12|>=2.2,<2.2.5|>=2.3,<2.3.3", "symfony/var-exporter": ">=4.2,<4.2.12|>=4.3,<4.3.8", @@ -1087,9 +454,9 @@ "tribalsystems/zenario": "<8.8.53370", "truckersmp/phpwhois": "<=4.3.1", "twig/twig": "<1.38|>=2,<2.7", - "typo3/cms": ">=6.2,<6.2.30|>=7,<7.6.32|>=8,<8.7.38|>=9,<9.5.25|>=10,<10.4.14|>=11,<11.1.1", + "typo3/cms": ">=6.2,<6.2.30|>=7,<7.6.32|>=8,<8.7.38|>=9,<9.5.28|>=10,<10.4.18|>=11,<11.3.1", "typo3/cms-backend": ">=7,<=7.6.50|>=8,<=8.7.39|>=9,<=9.5.24|>=10,<=10.4.13|>=11,<=11.1", - "typo3/cms-core": ">=6.2,<=6.2.56|>=7,<=7.6.50|>=8,<=8.7.39|>=9,<9.5.25|>=10,<10.4.14|>=11,<11.1.1", + "typo3/cms-core": ">=6.2,<=6.2.56|>=7,<7.6.52|>=8,<8.7.41|>=9,<9.5.28|>=10,<10.4.18|>=11,<11.3.1", "typo3/cms-form": ">=8,<=8.7.39|>=9,<=9.5.24|>=10,<=10.4.13|>=11,<=11.1", "typo3/flow": ">=1,<1.0.4|>=1.1,<1.1.1|>=2,<2.0.1|>=2.3,<2.3.16|>=3,<3.0.12|>=3.1,<3.1.10|>=3.2,<3.2.13|>=3.3,<3.3.13|>=4,<4.0.6", "typo3/neos": ">=1.1,<1.1.3|>=1.2,<1.2.13|>=2,<2.0.4|>=2.3,<2.3.99|>=3,<3.0.20|>=3.1,<3.1.18|>=3.2,<3.2.14|>=3.3,<3.3.23|>=4,<4.0.17|>=4.1,<4.1.16|>=4.2,<4.2.12|>=4.3,<4.3.3", @@ -1104,6 +471,7 @@ "wikimedia/parsoid": "<0.12.2", "willdurand/js-translation-bundle": "<2.1.1", "wp-cli/wp-cli": "<2.5", + "yidashi/yii2cmf": "<=2", "yii2mod/yii2-cms": "<1.9.2", "yiisoft/yii": ">=1.1.14,<1.1.15", "yiisoft/yii2": "<2.0.38", @@ -1171,7 +539,7 @@ "type": "tidelift" } ], - "time": "2021-06-09T23:02:53+00:00" + "time": "2021-07-26T22:02:34+00:00" } ], "aliases": [], @@ -1184,6 +552,7 @@ "platform": { "ext-json": "*", "ext-curl": "*", + "ext-openssl": "*", "php": ">=5.6" }, "platform-dev": [], diff --git a/version/205/class/API.php b/version/205/class/API.php index 235b7cf..1790086 100644 --- a/version/205/class/API.php +++ b/version/205/class/API.php @@ -4,9 +4,6 @@ namespace ws_mollie; -use Composer\CaBundle\CaBundle; -use GuzzleHttp\Client; -use GuzzleHttp\RequestOptions; use Mollie\Api\Exceptions\ApiException; use Mollie\Api\Exceptions\IncompatiblePlatform; use Mollie\Api\MollieApiClient; @@ -55,10 +52,10 @@ public static function getMode() public function Client() { if (!$this->client) { - $this->client = new MollieApiClient(new Client([ + $this->client = new MollieApiClient(/*new Client([ RequestOptions::VERIFY => CaBundle::getBundledCaBundlePath(), RequestOptions::TIMEOUT => 60 - ])); + ])*/); $this->client->setApiKey($this->isTest() ? self::Plugin()->oPluginEinstellungAssoc_arr['test_api_key'] : self::Plugin()->oPluginEinstellungAssoc_arr['api_key']) ->addVersionString('JTL-Shop/' . JTL_VERSION . JTL_MINOR_VERSION) ->addVersionString('ws_mollie/' . self::Plugin()->nVersion); diff --git a/version/205/class/Checkout/AbstractCheckout.php b/version/205/class/Checkout/AbstractCheckout.php index 0a5d2be..5417a75 100644 --- a/version/205/class/Checkout/AbstractCheckout.php +++ b/version/205/class/Checkout/AbstractCheckout.php @@ -134,7 +134,7 @@ public static function finalizeOrder($sessionHash, $id, $test = false) if (strpos($id, 'tr_') === 0) { $mollie = $api->Client()->payments->get($id); } else { - $mollie = $api->Client()->orders->get($id); + $mollie = $api->Client()->orders->get($id, ['embed' => 'payments']); } if (in_array($mollie->status, [OrderStatus::STATUS_PENDING, OrderStatus::STATUS_AUTHORIZED, OrderStatus::STATUS_PAID], true)) { @@ -163,7 +163,7 @@ public static function finalizeOrder($sessionHash, $id, $test = false) } $checkout = new $checkoutClass($order, $api); } - $checkout->setMollie($mollie); + $checkout->setMollie($mollie)->updateModel()->saveModel(); $checkout->updateOrderNumber(); $checkout->handleNotification($sessionHash); } @@ -225,6 +225,39 @@ public static function fromModel($model, $bFill = true, Bestellung $order = null return $self; } + /** + * @return bool + */ + public function saveModel() + { + return $this->getModel()->save(); + } + + /** + * @return Payment + */ + public function getModel() + { + if (!$this->model) { + $this->model = Payment::fromID($this->oBestellung->kBestellung, 'kBestellung'); + } + return $this->model; + } + + /** + * @param $model + * @return $this + */ + protected function setModel($model) + { + if (!$this->model) { + $this->model = $model; + } else { + throw new RuntimeException('Model already set.'); + } + return $this; + } + /** * @param null $hash * @throws Exception @@ -271,31 +304,6 @@ public function getHash() return $this->hash; } - /** - * @return Payment - */ - public function getModel() - { - if (!$this->model) { - $this->model = Payment::fromID($this->oBestellung->kBestellung, 'kBestellung'); - } - return $this->model; - } - - /** - * @param $model - * @return $this - */ - protected function setModel($model) - { - if (!$this->model) { - $this->model = $model; - } else { - throw new RuntimeException('Model already set.'); - } - return $this; - } - /** * @return JTLMollie */ @@ -327,14 +335,6 @@ public function getBestellung() return $this->oBestellung; } - /** - * @return bool - */ - public function saveModel() - { - return $this->getModel()->save(); - } - /** * @return $this */ @@ -1142,6 +1142,26 @@ public function getRepayURL() return Shop::getURL(true) . '/?m_pay=' . md5($this->getModel()->kID . '-' . $this->getBestellung()->kBestellung); } + public function getDescription() + { + $descTemplate = trim(Helper::getSetting('paymentDescTpl')) ?: "Order {orderNumber}"; + $oKunde = $this->getBestellung()->oKunde ?: $_SESSION['Kunde']; + return str_replace([ + '{orderNumber}', + '{storeName}', + '{customer.firstname}', + '{customer.lastname}', + '{customer.company}', + ], [ + $this->getBestellung()->cBestellNr, + Shop::getSettings([CONF_GLOBAL])['global']['global_shopname'], + $oKunde->cVorname, + $oKunde->cNachname, + $oKunde->cFirma + + ], $descTemplate); + } + abstract protected function updateOrderNumber(); /** @@ -1159,6 +1179,4 @@ protected function setBestellung(Bestellung $oBestellung) * @return self */ abstract protected function setMollie($model); - - } \ No newline at end of file diff --git a/version/205/class/Checkout/OrderCheckout.php b/version/205/class/Checkout/OrderCheckout.php index 253e109..c6b961e 100644 --- a/version/205/class/Checkout/OrderCheckout.php +++ b/version/205/class/Checkout/OrderCheckout.php @@ -351,6 +351,12 @@ protected function updateOrderNumber() $this->getMollie()->webhookUrl = Shop::getURL() . '/?mollie=1'; $this->getMollie()->update(); } + if ($this->getModel()->cTransactionId) { + $this->API()->Client()->payments->update($this->getModel()->cTransactionId, [ + 'description' => $this->getDescription() + ]); + } + } catch (Exception $e) { $this->Log('OrderCheckout::updateOrderNumber:' . $e->getMessage(), LOGLEVEL_ERROR); } diff --git a/version/205/class/Checkout/PaymentCheckout.php b/version/205/class/Checkout/PaymentCheckout.php index a75faea..e5aa786 100644 --- a/version/205/class/Checkout/PaymentCheckout.php +++ b/version/205/class/Checkout/PaymentCheckout.php @@ -166,25 +166,7 @@ public function loadRequest(&$options = []) return $this; } - public function getDescription() - { - $descTemplate = trim(Helper::getSetting('paymentDescTpl')) ?: "Order {orderNumber}"; - $oKunde = $this->getBestellung()->oKunde ?: $_SESSION['Kunde']; - return str_replace([ - '{orderNumber}', - '{storeName}', - '{customer.firstname}', - '{customer.lastname}', - '{customer.company}', - ], [ - $this->getBestellung()->cBestellNr, - Shop::getSettings([CONF_GLOBAL])['global']['global_shopname'], - $oKunde->cVorname, - $oKunde->cNachname, - $oKunde->cFirma - - ], $descTemplate); - } + /** * @return object|null From 9524e6ae2cf3d0b66f2194eab270695cc6b16475 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Wed, 4 Aug 2021 14:19:03 +0200 Subject: [PATCH 256/280] fix #150 --- version/205/class/Queue.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/version/205/class/Queue.php b/version/205/class/Queue.php index 188bc1c..a789309 100644 --- a/version/205/class/Queue.php +++ b/version/205/class/Queue.php @@ -170,6 +170,11 @@ protected static function handleHook($hook, QueueModel $todo) if (!$status || $status < BESTELLUNG_STATUS_VERSANDT) { return $todo->done("Bestellung noch nicht versendet: {$checkout->getBestellung()->cStatus}"); } + if (!count($checkout->getBestellung()->oLieferschein_arr)){ + $todo->dCreated = date('Y-m-d H:i:s', strtotime('+3 MINUTES')); + $todo->cResult = 'Noch keine Lieferscheine, delay...'; + return $todo->save(); + } /** @var $method JTLMollie */ if ((strpos($checkout->getModel()->kID, 'tr_') === false) @@ -229,7 +234,7 @@ protected static function handleHook($hook, QueueModel $todo) */ protected static function unlock($todo) { - return $todo->kId && Shop::DB()->executeQueryPrepared(sprintf('UPDATE %s SET `bLock` = NULL WHERE kId = :kId', QueueModel::TABLE), [ + return $todo->kId && Shop::DB()->executeQueryPrepared(sprintf('UPDATE %s SET `bLock` = NULL WHERE kId = :kId OR bLock < DATE_SUB(NOW(), INTERVAL 15 MINUTE)', QueueModel::TABLE), [ 'kId' => $todo->kId ], 3) >= 1; } From e60c2ccb94733e642ec7d1dd24fc5be5bc89e620 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Wed, 4 Aug 2021 14:26:18 +0200 Subject: [PATCH 257/280] close #148, #142 --- info.xml | 1 + version/205/class/Checkout/AbstractCheckout.php | 6 ++++++ version/205/sql/204.sql | 2 -- version/205/sql/205.sql | 2 ++ 4 files changed, 9 insertions(+), 2 deletions(-) delete mode 100644 version/205/sql/204.sql create mode 100644 version/205/sql/205.sql diff --git a/info.xml b/info.xml index 8d9dfac..227c2f2 100644 --- a/info.xml +++ b/info.xml @@ -46,6 +46,7 @@ 2021-08-04 + 205.sql 75_bestellungInDb.php diff --git a/version/205/class/Checkout/AbstractCheckout.php b/version/205/class/Checkout/AbstractCheckout.php index 5417a75..8e0ef7b 100644 --- a/version/205/class/Checkout/AbstractCheckout.php +++ b/version/205/class/Checkout/AbstractCheckout.php @@ -478,6 +478,12 @@ public static function sendReminder($kID) $checkout = self::fromID($kID); $return = true; + + if (!$checkout->getBestellung()->kBestellung || (int)$checkout->getBestellung()->cStatus > BESTELLUNG_STATUS_IN_BEARBEITUNG || (int)$checkout->getBestellung()->cStatus < 0) { + return $return; + } + + try { $repayURL = Shop::getURL() . '/?m_pay=' . md5($checkout->getModel()->kID . '-' . $checkout->getBestellung()->kBestellung); diff --git a/version/205/sql/204.sql b/version/205/sql/204.sql deleted file mode 100644 index 784d136..0000000 --- a/version/205/sql/204.sql +++ /dev/null @@ -1,2 +0,0 @@ -ALTER TABLE `xplugin_ws_mollie_shipments` - CHANGE `kLieferschien` `kLieferschein` INT(11) NOT NULL; \ No newline at end of file diff --git a/version/205/sql/205.sql b/version/205/sql/205.sql new file mode 100644 index 0000000..cf9de22 --- /dev/null +++ b/version/205/sql/205.sql @@ -0,0 +1,2 @@ +ALTER TABLE `xplugin_ws_mollie_payments` + CHANGE `cHash` `cHash` VARCHAR(64) NULL DEFAULT NULL; \ No newline at end of file From b8b56c945ca75bd0cd12cdc22fa0c4e1959c47b2 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Tue, 10 Aug 2021 16:14:07 +0200 Subject: [PATCH 258/280] fix #153 --- info.xml | 2 +- .../205/paymentmethod/img/method/sofort@2x.png | Bin 453 -> 502 bytes 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/info.xml b/info.xml index 227c2f2..c5e96da 100644 --- a/info.xml +++ b/info.xml @@ -45,7 +45,7 @@ 204.sql - 2021-08-04 + 2021-08-10 205.sql diff --git a/version/205/paymentmethod/img/method/sofort@2x.png b/version/205/paymentmethod/img/method/sofort@2x.png index 9e3506f8b9373d01c7fd71c81a5379e82addfa62..f6cf131f7b3a149176c3632ed632a3b3f86c2c95 100644 GIT binary patch delta 476 zcmV<20VDp!1NH-uB!7)iOjJbx008r~#_zAs^tH(Jw#f9i$Mm+x^tHzHw#M_b!|$)h z^RvhAx5w|VzxB4q^tQ(JwaD_e#`Lzw0001qW^fM+4c4Eow}_S1pRVPryK7KadRt@U ztGX^CB_0X-t?BLmKQE>PBe{x1fE@On=HdqqA=xHol@*94&DRu2G6-2F{`otI zN!gG=!IEeT6@M$rp~BDtDsBi${z`Ba^b_^3e2f*?i9W=Z^F<-3Id=+yS~$3P=SXmMJSp1>p$1H*!JcSMVSgAe3-& z0mh#agL6&1ptf^~Lphnw(E@aHiP4+l1?{6Raf0X*i delta 427 zcmV;c0aX6>1H}W7B!6#EOjJbx0094i9{+$G|A8F;fFS>X5dVT6|AHO=fgb;Z9{++K z|9}|(f*t>WApe3M|A8L=f*$|>|NoIX|B5XCk~;sfa{uq+|L4{J;K%>ix&NV7|M>C$ z(5nByj{orE|In-dxq$z$a{sAh|LE2KxPaalUjzUE01$LiPJdGX&p?n65Z{lG&yOIV zAfKS^LzjQjTH?Nv|?j>Rkde-54LWC z0t0EGkW97RKxDN>CdKNRPmoPA7}hAD0N9|26t*ZLg9=3`Kp~$X_z8R)^o;&a6PQ}R zaCWo_OnA#%;(rRqh3``Y-MDu%;;1de0cy)_!RjX$c8#5mG*`nD+@=B=!&;%A48bx4 z=x2t1jsV^9tVb@~yWrX=IPnBi7ac+1=5%#D#e^2TUceIs?Lz*KaFEPW-Vp>|ztf*A z5(M>YIJ8&$1;6#5K%s~PN))k&6h-VnHbMpfx#X#v!z5r}&yeL1*&Qk*qsny1J^(Hg Vzxe(Q9RvUX002ovPDHLkV1f~~(^CKd From 7fdd838030160290a59e0405285837b4740cac5a Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Tue, 10 Aug 2021 16:26:15 +0200 Subject: [PATCH 259/280] php cs fix --- .gitignore | 1 + .php-cs-fixer.php | 91 + composer.json | 11 +- composer.lock | 2028 ++++++++++++++--- version/205/adminmenu/info.php | 23 +- version/205/adminmenu/orders.php | 56 +- version/205/adminmenu/paymentmethods.php | 50 +- version/205/class/API.php | 18 +- .../205/class/Checkout/AbstractCheckout.php | 574 ++--- .../205/class/Checkout/AbstractResource.php | 11 +- .../Exception/ResourceValidityException.php | 9 +- version/205/class/Checkout/Order/Address.php | 23 +- .../205/class/Checkout/Order/OrderLine.php | 101 +- version/205/class/Checkout/OrderCheckout.php | 100 +- .../205/class/Checkout/Payment/Address.php | 22 +- version/205/class/Checkout/Payment/Amount.php | 19 +- .../205/class/Checkout/PaymentCheckout.php | 61 +- version/205/class/ExclusiveLock.php | 21 +- version/205/class/Helper.php | 84 +- version/205/class/Hook/AbstractHook.php | 9 +- version/205/class/Hook/ApplePay.php | 17 +- version/205/class/Hook/Checkbox.php | 47 +- version/205/class/Hook/Queue.php | 22 +- version/205/class/Model/AbstractModel.php | 23 +- version/205/class/Model/Customer.php | 11 +- version/205/class/Model/Payment.php | 7 +- version/205/class/Model/Queue.php | 15 +- version/205/class/Model/Shipment.php | 10 +- version/205/class/Queue.php | 60 +- version/205/class/Shipment.php | 66 +- version/205/class/Traits/Jsonable.php | 8 +- version/205/class/Traits/Plugin.php | 8 +- version/205/class/Traits/RequestData.php | 14 +- version/205/frontend/131_globalinclude.php | 16 +- version/205/frontend/132_headPostGet.php | 8 +- version/205/frontend/140_smarty.php | 15 +- version/205/frontend/180_checkbox.php | 8 +- version/205/frontend/181_sync.php | 5 +- version/205/frontend/210_storno.php | 8 +- version/205/frontend/75_bestellungInDb.php | 8 +- version/205/frontend/applepay.php | 4 + version/205/paymentmethod/JTLMollie.php | 47 +- .../205/paymentmethod/JTLMollieApplePay.php | 4 + .../205/paymentmethod/JTLMollieBancontact.php | 5 +- .../paymentmethod/JTLMollieBanktransfer.php | 7 +- .../205/paymentmethod/JTLMollieBelfius.php | 5 +- .../205/paymentmethod/JTLMollieCreditCard.php | 23 +- version/205/paymentmethod/JTLMollieEPS.php | 4 + .../205/paymentmethod/JTLMollieGiftcard.php | 4 + .../205/paymentmethod/JTLMollieGiropay.php | 5 + version/205/paymentmethod/JTLMollieIDEAL.php | 6 +- version/205/paymentmethod/JTLMollieKBC.php | 5 + .../paymentmethod/JTLMollieKlarnaPayLater.php | 7 +- .../paymentmethod/JTLMollieKlarnaSliceIt.php | 7 +- version/205/paymentmethod/JTLMollieMyBank.php | 6 +- version/205/paymentmethod/JTLMolliePayPal.php | 7 +- .../paymentmethod/JTLMolliePaysafecard.php | 5 + .../205/paymentmethod/JTLMolliePrzelewy24.php | 6 +- version/205/paymentmethod/JTLMollieSofort.php | 6 +- 59 files changed, 2826 insertions(+), 1025 deletions(-) create mode 100644 .php-cs-fixer.php diff --git a/.gitignore b/.gitignore index bcc9342..6b9bfaf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ vendor/ *.log +*.cache diff --git a/.php-cs-fixer.php b/.php-cs-fixer.php new file mode 100644 index 0000000..e9318f1 --- /dev/null +++ b/.php-cs-fixer.php @@ -0,0 +1,91 @@ +in(__DIR__.'/version/205'); + +return (new Config()) + ->setRiskyAllowed(true) + ->setRules([ + '@PSR12' => true, + 'braces' => [ + 'allow_single_line_closure' => false + ], + 'cast_spaces' => [ + 'space' => 'none' + ], + 'fully_qualified_strict_types' => true, + 'single_quote' => true, + 'is_null' => true, + 'no_php4_constructor' => true, + 'lowercase_keywords' => true, + 'modernize_types_casting' => true, + 'native_function_casing' => true, + 'new_with_braces' => true, + 'single_blank_line_at_eof' => true, + 'blank_line_after_opening_tag' => false, + 'no_mixed_echo_print' => ['use' => 'echo'], + 'concat_space' => ['spacing' => 'one'], + 'no_multiline_whitespace_around_double_arrow' => true, + 'no_empty_statement' => true, + 'elseif' => true, + 'encoding' => true, + 'no_spaces_after_function_name' => true, + 'function_declaration' => ['closure_function_spacing' => 'one'], + 'include' => true, + 'indentation_type' => true, + 'no_alias_functions' => true, + 'blank_line_after_namespace' => true, + 'line_ending' => true, + 'multiline_whitespace_before_semicolons' => false, + 'single_import_per_statement' => true, + 'no_leading_namespace_whitespace' => true, + 'no_blank_lines_after_class_opening' => true, + 'no_blank_lines_after_phpdoc' => true, + 'object_operator_without_whitespace' => true, + 'no_spaces_inside_parenthesis' => true, + 'binary_operator_spaces' => [ + 'default' => 'align_single_space_minimal' + ], + 'phpdoc_align' => [ + 'tags' => ['param'] + ], + 'no_leading_import_slash' => true, + 'self_accessor' => true, + 'single_blank_line_before_namespace' => true, + 'single_line_after_imports' => true, + 'no_singleline_whitespace_before_semicolons' => true, + 'standardize_not_equals' => true, + 'ternary_operator_spaces' => true, + 'no_trailing_whitespace' => true, + 'trim_array_spaces' => true, + 'unary_operator_spaces' => true, + 'no_unused_imports' => true, + 'visibility_required' => true, + 'no_whitespace_in_blank_line' => true, + 'dir_constant' => true, + 'align_multiline_comment' => true, + 'array_syntax' => ['syntax' => 'short'], + 'blank_line_before_statement' => true, + 'combine_consecutive_unsets' => true, + 'header_comment' => [ + 'comment_type' => 'PHPDoc', + 'separate' => 'bottom', + 'header' => sprintf("@copyright %s WebStollen GmbH\n@link https://www.webstollen.de", date('Y')) + ], + 'list_syntax' => ['syntax' => 'short'], + 'phpdoc_trim_consecutive_blank_line_separation' => true, + 'no_null_property_initialization' => true, + 'echo_tag_syntax' => ['format' => 'short'], + 'no_useless_else' => true, + 'no_useless_return' => true, + 'ordered_class_elements' => false, + 'ordered_imports' => true, + 'phpdoc_add_missing_param_annotation' => true, + 'phpdoc_order' => true, + 'phpdoc_types_order' => true, + 'semicolon_after_instruction' => true, + 'single_line_comment_style' => true, + ]) + ->setFinder($finder); diff --git a/composer.json b/composer.json index 100ff6a..b56684f 100644 --- a/composer.json +++ b/composer.json @@ -1,7 +1,12 @@ { "name": "webstollen/ws_mollie", - "description": "mollie", + "description": "Mollie", "type": "project", + "scripts": { + "phpcbf": "phpcbf --standard=PSR12 --encoding=utf8 -p ./version/205", + "php-cs-fixer": "php-cs-fixer fix", + "fix": "phpcbf --standard=PSR12 --encoding=utf8 -p ./version/205 && php-cs-fixer fix" + }, "require": { "ext-json": "*", "ext-curl": "*", @@ -10,7 +15,9 @@ "mollie/mollie-api-php": "^v2.37.0" }, "require-dev": { - "roave/security-advisories": "dev-latest" + "roave/security-advisories": "dev-latest", + "squizlabs/php_codesniffer": "3.*", + "friendsofphp/php-cs-fixer": "2.*" }, "license": "Proprietary", "authors": [ diff --git a/composer.lock b/composer.lock index 65e50dd..0ee00dd 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "e2dcc50cc251dc1c3ab8989ced37cd2a", + "content-hash": "40fbb464e7cfb0adceba4c7e333a7639", "packages": [ { "name": "composer/ca-bundle", @@ -61,6 +61,11 @@ "ssl", "tls" ], + "support": { + "irc": "irc://irc.freenode.org/composer", + "issues": "https://github.com/composer/ca-bundle/issues", + "source": "https://github.com/composer/ca-bundle/tree/1.2.10" + }, "funding": [ { "url": "https://packagist.com", @@ -79,16 +84,16 @@ }, { "name": "mollie/mollie-api-php", - "version": "v2.37.0", + "version": "v2.37.1", "source": { "type": "git", "url": "https://github.com/mollie/mollie-api-php.git", - "reference": "8e599a4f133341aa8623e0a61e2e77d65725c011" + "reference": "260adf68db65edd82b6c11f8fa58622ff72b717c" }, "dist": { "type": "zip", - "url": "https://github.com/gitapi/repos/mollie/mollie-api-php/zipball/8e599a4f133341aa8623e0a61e2e77d65725c011", - "reference": "8e599a4f133341aa8623e0a61e2e77d65725c011", + "url": "https://github.com/gitapi/repos/mollie/mollie-api-php/zipball/260adf68db65edd82b6c11f8fa58622ff72b717c", + "reference": "260adf68db65edd82b6c11f8fa58622ff72b717c", "shasum": "" }, "require": { @@ -162,276 +167,831 @@ "sofortbanking", "subscriptions" ], - "time": "2021-07-28T16:35:52+00:00" + "support": { + "issues": "https://github.com/mollie/mollie-api-php/issues", + "source": "https://github.com/mollie/mollie-api-php/tree/v2.37.1" + }, + "time": "2021-08-09T09:30:47+00:00" } ], "packages-dev": [ { - "name": "roave/security-advisories", - "version": "dev-latest", + "name": "composer/semver", + "version": "3.2.5", "source": { "type": "git", - "url": "https://github.com/Roave/SecurityAdvisories.git", - "reference": "52a126190a36bc9236846f5d42e10bff9ff60d72" + "url": "https://github.com/composer/semver.git", + "reference": "31f3ea725711245195f62e54ffa402d8ef2fdba9" }, "dist": { "type": "zip", - "url": "https://github.com/gitapi/repos/Roave/SecurityAdvisories/zipball/52a126190a36bc9236846f5d42e10bff9ff60d72", - "reference": "52a126190a36bc9236846f5d42e10bff9ff60d72", + "url": "https://github.com/gitapi/repos/composer/semver/zipball/31f3ea725711245195f62e54ffa402d8ef2fdba9", + "reference": "31f3ea725711245195f62e54ffa402d8ef2fdba9", "shasum": "" }, - "conflict": { - "3f/pygmentize": "<1.2", - "adodb/adodb-php": "<5.20.12", - "alterphp/easyadmin-extension-bundle": ">=1.2,<1.2.11|>=1.3,<1.3.1", - "amazing/media2click": ">=1,<1.3.3", - "amphp/artax": "<1.0.6|>=2,<2.0.6", - "amphp/http": "<1.0.1", - "amphp/http-client": ">=4,<4.4", - "api-platform/core": ">=2.2,<2.2.10|>=2.3,<2.3.6", - "asymmetricrypt/asymmetricrypt": ">=0,<9.9.99", - "aws/aws-sdk-php": ">=3,<3.2.1", - "bagisto/bagisto": "<0.1.5", - "barrelstrength/sprout-base-email": "<1.2.7", - "barrelstrength/sprout-forms": "<3.9", - "baserproject/basercms": "<4.4.5", - "bk2k/bootstrap-package": ">=7.1,<7.1.2|>=8,<8.0.8|>=9,<9.0.4|>=9.1,<9.1.3|>=10,<10.0.10|>=11,<11.0.3", - "bolt/bolt": "<3.7.2", - "bolt/core": "<4.1.13", - "brightlocal/phpwhois": "<=4.2.5", - "buddypress/buddypress": "<5.1.2", - "bugsnag/bugsnag-laravel": ">=2,<2.0.2", - "cakephp/cakephp": ">=1.3,<1.3.18|>=2,<2.4.99|>=2.5,<2.5.99|>=2.6,<2.6.12|>=2.7,<2.7.6|>=3,<3.5.18|>=3.6,<3.6.15|>=3.7,<3.7.7", - "cart2quote/module-quotation": ">=4.1.6,<=4.4.5|>=5,<5.4.4", - "cartalyst/sentry": "<=2.1.6", - "centreon/centreon": "<20.10.7", - "cesnet/simplesamlphp-module-proxystatistics": "<3.1", - "codeigniter/framework": "<=3.0.6", - "composer/composer": "<1.10.22|>=2-alpha.1,<2.0.13", - "contao-components/mediaelement": ">=2.14.2,<2.21.1", - "contao/core": ">=2,<3.5.39", - "contao/core-bundle": ">=4,<4.4.52|>=4.5,<4.9.16|>=4.10,<4.11.5|= 4.10.0", - "contao/listing-bundle": ">=4,<4.4.8", - "craftcms/cms": "<3.6.7", - "croogo/croogo": "<3.0.7", - "datadog/dd-trace": ">=0.30,<0.30.2", - "david-garcia/phpwhois": "<=4.3.1", - "derhansen/sf_event_mgt": "<4.3.1|>=5,<5.1.1", - "directmailteam/direct-mail": "<5.2.4", - "doctrine/annotations": ">=1,<1.2.7", - "doctrine/cache": ">=1,<1.3.2|>=1.4,<1.4.2", - "doctrine/common": ">=2,<2.4.3|>=2.5,<2.5.1", - "doctrine/dbal": ">=2,<2.0.8|>=2.1,<2.1.2", - "doctrine/doctrine-bundle": "<1.5.2", - "doctrine/doctrine-module": "<=0.7.1", - "doctrine/mongodb-odm": ">=1,<1.0.2", - "doctrine/mongodb-odm-bundle": ">=2,<3.0.1", - "doctrine/orm": ">=2,<2.4.8|>=2.5,<2.5.1|>=2.8.3,<2.8.4", - "dolibarr/dolibarr": "<11.0.4", - "dompdf/dompdf": ">=0.6,<0.6.2", - "drupal/core": ">=7,<7.80|>=8,<8.9.14|>=9,<9.0.12|>=9.1,<9.1.7", - "drupal/drupal": ">=7,<7.80|>=8,<8.9.14|>=9,<9.0.12|>=9.1,<9.1.7", - "dweeves/magmi": "<=0.7.24", - "endroid/qr-code-bundle": "<3.4.2", - "enshrined/svg-sanitize": "<0.13.1", - "erusev/parsedown": "<1.7.2", - "ether/logs": "<3.0.4", - "ezsystems/demobundle": ">=5.4,<5.4.6.1", - "ezsystems/ez-support-tools": ">=2.2,<2.2.3", - "ezsystems/ezdemo-ls-extension": ">=5.4,<5.4.2.1", - "ezsystems/ezfind-ls": ">=5.3,<5.3.6.1|>=5.4,<5.4.11.1|>=2017.12,<2017.12.0.1", - "ezsystems/ezplatform": ">=1.7,<1.7.9.1|>=1.13,<1.13.5.1|>=2.5,<2.5.4", - "ezsystems/ezplatform-admin-ui": ">=1.3,<1.3.5|>=1.4,<1.4.6", - "ezsystems/ezplatform-admin-ui-assets": ">=4,<4.2.1|>=5,<5.0.1|>=5.1,<5.1.1", - "ezsystems/ezplatform-kernel": "<=1.2.5|>=1.3,<=1.3.1", - "ezsystems/ezplatform-rest": ">=1.2,<=1.2.2|>=1.3,<=1.3.1", - "ezsystems/ezplatform-user": ">=1,<1.0.1", - "ezsystems/ezpublish-kernel": "<=6.13.8.1|>=7,<=7.5.15.1", - "ezsystems/ezpublish-legacy": ">=5.3,<5.3.12.6|>=5.4,<5.4.14.2|>=2011,<2017.12.7.3|>=2018.6,<2018.6.1.4|>=2018.9,<2018.9.1.3|>=2019.3,<2019.3.5.1", - "ezsystems/platform-ui-assets-bundle": ">=4.2,<4.2.3", - "ezsystems/repository-forms": ">=2.3,<2.3.2.1", - "ezyang/htmlpurifier": "<4.1.1", - "facade/ignition": "<1.16.14|>=2,<2.4.2|>=2.5,<2.5.2", - "feehi/cms": "<=2.1.1", - "firebase/php-jwt": "<2", - "flarum/core": ">=1,<=1.0.1", - "flarum/sticky": ">=0.1-beta.14,<=0.1-beta.15", - "flarum/tags": "<=0.1-beta.13", - "fluidtypo3/vhs": "<5.1.1", - "fooman/tcpdf": "<6.2.22", - "forkcms/forkcms": "<5.8.3", - "fossar/tcpdf-parser": "<6.2.22", - "francoisjacquet/rosariosis": "<6.5.1", - "friendsofsymfony/oauth2-php": "<1.3", - "friendsofsymfony/rest-bundle": ">=1.2,<1.2.2", - "friendsofsymfony/user-bundle": ">=1.2,<1.3.5", - "friendsoftypo3/mediace": ">=7.6.2,<7.6.5", - "froala/wysiwyg-editor": "<3.2.7", - "fuel/core": "<1.8.1", - "getgrav/grav": "<=1.7.10", - "getkirby/cms": "<=3.5.6", - "getkirby/panel": "<2.5.14", - "gos/web-socket-bundle": "<1.10.4|>=2,<2.6.1|>=3,<3.3", - "gree/jose": "<=2.2", - "gregwar/rst": "<1.0.3", - "guzzlehttp/guzzle": ">=4-rc.2,<4.2.4|>=5,<5.3.1|>=6,<6.2.1", - "illuminate/auth": ">=4,<4.0.99|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.10", - "illuminate/cookie": ">=4,<=4.0.11|>=4.1,<=4.1.99999|>=4.2,<=4.2.99999|>=5,<=5.0.99999|>=5.1,<=5.1.99999|>=5.2,<=5.2.99999|>=5.3,<=5.3.99999|>=5.4,<=5.4.99999|>=5.5,<=5.5.49|>=5.6,<=5.6.99999|>=5.7,<=5.7.99999|>=5.8,<=5.8.99999|>=6,<6.18.31|>=7,<7.22.4", - "illuminate/database": "<6.20.26|>=7,<8.40", - "illuminate/encryption": ">=4,<=4.0.11|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.40|>=5.6,<5.6.15", - "illuminate/view": ">=7,<7.1.2", - "impresscms/impresscms": "<=1.4.2", - "intelliants/subrion": "<=4.2.1", - "ivankristianto/phpwhois": "<=4.3", - "james-heinrich/getid3": "<1.9.9", - "joomla/archive": "<1.1.10", - "joomla/session": "<1.3.1", - "jsmitty12/phpwhois": "<5.1", - "kazist/phpwhois": "<=4.2.6", - "kitodo/presentation": "<3.1.2", - "klaviyo/magento2-extension": ">=1,<3", - "kreait/firebase-php": ">=3.2,<3.8.1", - "la-haute-societe/tcpdf": "<6.2.22", - "laminas/laminas-http": "<2.14.2", - "laravel/framework": "<6.20.26|>=7,<8.40", - "laravel/socialite": ">=1,<1.0.99|>=2,<2.0.10", - "league/commonmark": "<0.18.3", - "league/flysystem": "<1.1.4|>=2,<2.1.1", - "lexik/jwt-authentication-bundle": "<2.10.7|>=2.11,<2.11.3", - "librenms/librenms": "<21.1", - "livewire/livewire": ">2.2.4,<2.2.6", - "localizationteam/l10nmgr": "<7.4|>=8,<8.7|>=9,<9.2", - "magento/community-edition": ">=2,<2.2.10|>=2.3,<2.3.3", - "magento/magento1ce": "<1.9.4.3", - "magento/magento1ee": ">=1,<1.14.4.3", - "magento/product-community-edition": ">=2,<2.2.10|>=2.3,<2.3.2-p.2", - "marcwillmann/turn": "<0.3.3", - "mautic/core": "<3.3.2|= 2.13.1", - "mediawiki/core": ">=1.27,<1.27.6|>=1.29,<1.29.3|>=1.30,<1.30.2|>=1.31,<1.31.9|>=1.32,<1.32.6|>=1.32.99,<1.33.3|>=1.33.99,<1.34.3|>=1.34.99,<1.35", - "mittwald/typo3_forum": "<1.2.1", - "monolog/monolog": ">=1.8,<1.12", - "moodle/moodle": "<3.5.17|>=3.7,<3.7.9|>=3.8,<3.8.8|>=3.9,<3.9.5|>=3.10,<3.10.2", - "namshi/jose": "<2.2", - "neos/flow": ">=1,<1.0.4|>=1.1,<1.1.1|>=2,<2.0.1|>=2.3,<2.3.16|>=3,<3.0.12|>=3.1,<3.1.10|>=3.2,<3.2.13|>=3.3,<3.3.13|>=4,<4.0.6", - "neos/form": ">=1.2,<4.3.3|>=5,<5.0.9|>=5.1,<5.1.3", - "neos/neos": ">=1.1,<1.1.3|>=1.2,<1.2.13|>=2,<2.0.4|>=2.3,<2.9.99|>=3,<3.0.20|>=3.1,<3.1.18|>=3.2,<3.2.14|>=3.3,<3.3.23|>=4,<4.0.17|>=4.1,<4.1.16|>=4.2,<4.2.12|>=4.3,<4.3.3", - "neos/swiftmailer": ">=4.1,<4.1.99|>=5.4,<5.4.5", - "nette/application": ">=2,<2.0.19|>=2.1,<2.1.13|>=2.2,<2.2.10|>=2.3,<2.3.14|>=2.4,<2.4.16|>=3,<3.0.6", - "nette/nette": ">=2,<2.0.19|>=2.1,<2.1.13", - "nilsteampassnet/teampass": "<=2.1.27.36", - "nukeviet/nukeviet": "<4.3.4", - "nystudio107/craft-seomatic": "<3.3", - "nzo/url-encryptor-bundle": ">=4,<4.3.2|>=5,<5.0.1", - "october/backend": "<1.1.2", - "october/cms": "= 1.1.1|= 1.0.471|= 1.0.469|>=1.0.319,<1.0.469", - "october/october": ">=1.0.319,<1.0.466", - "october/rain": "<1.0.472|>=1.1,<1.1.2", - "onelogin/php-saml": "<2.10.4", - "oneup/uploader-bundle": "<1.9.3|>=2,<2.1.5", - "opencart/opencart": "<=3.0.3.2", - "openid/php-openid": "<2.3", - "openmage/magento-lts": "<=19.4.12|>=20,<=20.0.8", - "orchid/platform": ">=9,<9.4.4", - "oro/crm": ">=1.7,<1.7.4", - "oro/platform": ">=1.7,<1.7.4", - "padraic/humbug_get_contents": "<1.1.2", - "pagarme/pagarme-php": ">=0,<3", - "pagekit/pagekit": "<=1.0.18", - "paragonie/random_compat": "<2", - "passbolt/passbolt_api": "<2.11", - "paypal/merchant-sdk-php": "<3.12", - "pear/archive_tar": "<1.4.12", - "personnummer/personnummer": "<3.0.2", - "phanan/koel": "<5.1.4", - "phpfastcache/phpfastcache": ">=5,<5.0.13", - "phpmailer/phpmailer": "<6.5", - "phpmussel/phpmussel": ">=1,<1.6", - "phpmyadmin/phpmyadmin": "<4.9.6|>=5,<5.0.3", - "phpoffice/phpexcel": "<1.8.2", - "phpoffice/phpspreadsheet": "<1.16", - "phpseclib/phpseclib": "<2.0.31|>=3,<3.0.7", - "phpunit/phpunit": ">=4.8.19,<4.8.28|>=5.0.10,<5.6.3", - "phpwhois/phpwhois": "<=4.2.5", - "phpxmlrpc/extras": "<0.6.1", - "pimcore/pimcore": "<10.0.7", - "pocketmine/pocketmine-mp": "<3.15.4", - "pressbooks/pressbooks": "<5.18", - "prestashop/autoupgrade": ">=4,<4.10.1", - "prestashop/contactform": ">1.0.1,<4.3", - "prestashop/gamification": "<2.3.2", - "prestashop/productcomments": ">=4,<4.2.1", - "prestashop/ps_emailsubscription": "<2.6.1", - "prestashop/ps_facetedsearch": "<3.4.1", - "privatebin/privatebin": "<1.2.2|>=1.3,<1.3.2", - "propel/propel": ">=2-alpha.1,<=2-alpha.7", - "propel/propel1": ">=1,<=1.7.1", - "pterodactyl/panel": "<0.7.19|>=1-rc.0,<=1-rc.6", - "pusher/pusher-php-server": "<2.2.1", - "pwweb/laravel-core": "<=0.3.6-beta", - "rainlab/debugbar-plugin": "<3.1", - "rmccue/requests": ">=1.6,<1.8", - "robrichards/xmlseclibs": "<3.0.4", - "sabberworm/php-css-parser": ">=1,<1.0.1|>=2,<2.0.1|>=3,<3.0.1|>=4,<4.0.1|>=5,<5.0.9|>=5.1,<5.1.3|>=5.2,<5.2.1|>=6,<6.0.2|>=7,<7.0.4|>=8,<8.0.1|>=8.1,<8.1.1|>=8.2,<8.2.1|>=8.3,<8.3.1", - "sabre/dav": ">=1.6,<1.6.99|>=1.7,<1.7.11|>=1.8,<1.8.9", - "scheb/two-factor-bundle": ">=0,<3.26|>=4,<4.11", - "sensiolabs/connect": "<4.2.3", - "serluck/phpwhois": "<=4.2.6", - "shopware/core": "<=6.4.1", - "shopware/platform": "<=6.4.1", - "shopware/production": "<=6.3.5.2", - "shopware/shopware": "<=5.6.9", - "silverstripe/admin": ">=1.0.3,<1.0.4|>=1.1,<1.1.1", - "silverstripe/assets": ">=1,<1.4.7|>=1.5,<1.5.2", - "silverstripe/cms": "<4.3.6|>=4.4,<4.4.4", - "silverstripe/comments": ">=1.3,<1.9.99|>=2,<2.9.99|>=3,<3.1.1", - "silverstripe/forum": "<=0.6.1|>=0.7,<=0.7.3", - "silverstripe/framework": "<4.7.4", - "silverstripe/graphql": "<=3.5|>=4-alpha.1,<4-alpha.2", - "silverstripe/registry": ">=2.1,<2.1.2|>=2.2,<2.2.1", - "silverstripe/restfulserver": ">=1,<1.0.9|>=2,<2.0.4", - "silverstripe/subsites": ">=2,<2.1.1", - "silverstripe/taxonomy": ">=1.3,<1.3.1|>=2,<2.0.1", - "silverstripe/userforms": "<3", - "simple-updates/phpwhois": "<=1", - "simplesamlphp/saml2": "<1.10.6|>=2,<2.3.8|>=3,<3.1.4", - "simplesamlphp/simplesamlphp": "<1.18.6", - "simplesamlphp/simplesamlphp-module-infocard": "<1.0.1", - "simplito/elliptic-php": "<1.0.6", - "slim/slim": "<2.6", - "smarty/smarty": "<3.1.39", - "socalnick/scn-social-auth": "<1.15.2", - "socialiteproviders/steam": "<1.1", - "spoonity/tcpdf": "<6.2.22", - "squizlabs/php_codesniffer": ">=1,<2.8.1|>=3,<3.0.1", - "ssddanbrown/bookstack": "<0.29.2", - "stormpath/sdk": ">=0,<9.9.99", - "studio-42/elfinder": "<2.1.59", - "sulu/sulu": "<1.6.41|>=2,<2.0.10|>=2.1,<2.1.1", - "swiftmailer/swiftmailer": ">=4,<5.4.5", - "sylius/admin-bundle": ">=1,<1.0.17|>=1.1,<1.1.9|>=1.2,<1.2.2", - "sylius/grid": ">=1,<1.1.19|>=1.2,<1.2.18|>=1.3,<1.3.13|>=1.4,<1.4.5|>=1.5,<1.5.1", - "sylius/grid-bundle": ">=1,<1.1.19|>=1.2,<1.2.18|>=1.3,<1.3.13|>=1.4,<1.4.5|>=1.5,<1.5.1", - "sylius/resource-bundle": "<1.3.14|>=1.4,<1.4.7|>=1.5,<1.5.2|>=1.6,<1.6.4", - "sylius/sylius": "<1.6.9|>=1.7,<1.7.9|>=1.8,<1.8.3|>=1.9,<1.9.5", - "symbiote/silverstripe-multivaluefield": ">=3,<3.0.99", - "symbiote/silverstripe-queuedjobs": ">=3,<3.0.2|>=3.1,<3.1.4|>=4,<4.0.7|>=4.1,<4.1.2|>=4.2,<4.2.4|>=4.3,<4.3.3|>=4.4,<4.4.3|>=4.5,<4.5.1|>=4.6,<4.6.4", - "symbiote/silverstripe-versionedfiles": "<=2.0.3", - "symfony/cache": ">=3.1,<3.4.35|>=4,<4.2.12|>=4.3,<4.3.8", - "symfony/dependency-injection": ">=2,<2.0.17|>=2.7,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", - "symfony/error-handler": ">=4.4,<4.4.4|>=5,<5.0.4", - "symfony/form": ">=2.3,<2.3.35|>=2.4,<2.6.12|>=2.7,<2.7.50|>=2.8,<2.8.49|>=3,<3.4.20|>=4,<4.0.15|>=4.1,<4.1.9|>=4.2,<4.2.1", - "symfony/framework-bundle": ">=2,<2.3.18|>=2.4,<2.4.8|>=2.5,<2.5.2|>=2.7,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", - "symfony/http-foundation": ">=2,<2.8.52|>=3,<3.4.35|>=4,<4.2.12|>=4.3,<4.3.8|>=4.4,<4.4.7|>=5,<5.0.7", - "symfony/http-kernel": ">=2,<2.8.52|>=3,<3.4.35|>=4,<4.2.12|>=4.3,<4.4.13|>=5,<5.1.5", - "symfony/intl": ">=2.7,<2.7.38|>=2.8,<2.8.31|>=3,<3.2.14|>=3.3,<3.3.13", - "symfony/maker-bundle": ">=1.27,<1.29.2|>=1.30,<1.31.1", - "symfony/mime": ">=4.3,<4.3.8", - "symfony/phpunit-bridge": ">=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", - "symfony/polyfill": ">=1,<1.10", - "symfony/polyfill-php55": ">=1,<1.10", - "symfony/proxy-manager-bridge": ">=2.7,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", - "symfony/routing": ">=2,<2.0.19", - "symfony/security": ">=2,<2.7.51|>=2.8,<3.4.49|>=4,<4.4.24|>=5,<5.2.8", + "require": { + "php": "^5.3.2 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^0.12.54", + "symfony/phpunit-bridge": "^4.2 || ^5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\Semver\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nils Adermann", + "email": "naderman@naderman.de", + "homepage": "http://www.naderman.de" + }, + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + }, + { + "name": "Rob Bast", + "email": "rob.bast@gmail.com", + "homepage": "http://robbast.nl" + } + ], + "description": "Semver library that offers utilities, version constraint parsing and validation.", + "keywords": [ + "semantic", + "semver", + "validation", + "versioning" + ], + "support": { + "irc": "irc://irc.freenode.org/composer", + "issues": "https://github.com/composer/semver/issues", + "source": "https://github.com/composer/semver/tree/3.2.5" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2021-05-24T12:41:47+00:00" + }, + { + "name": "composer/xdebug-handler", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/composer/xdebug-handler.git", + "reference": "84674dd3a7575ba617f5a76d7e9e29a7d3891339" + }, + "dist": { + "type": "zip", + "url": "https://github.com/gitapi/repos/composer/xdebug-handler/zipball/84674dd3a7575ba617f5a76d7e9e29a7d3891339", + "reference": "84674dd3a7575ba617f5a76d7e9e29a7d3891339", + "shasum": "" + }, + "require": { + "php": "^5.3.2 || ^7.0 || ^8.0", + "psr/log": "^1 || ^2 || ^3" + }, + "require-dev": { + "phpstan/phpstan": "^0.12.55", + "symfony/phpunit-bridge": "^4.2 || ^5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Composer\\XdebugHandler\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "John Stevenson", + "email": "john-stevenson@blueyonder.co.uk" + } + ], + "description": "Restarts a process without Xdebug.", + "keywords": [ + "Xdebug", + "performance" + ], + "support": { + "irc": "irc://irc.freenode.org/composer", + "issues": "https://github.com/composer/xdebug-handler/issues", + "source": "https://github.com/composer/xdebug-handler/tree/2.0.2" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2021-07-31T17:03:58+00:00" + }, + { + "name": "doctrine/annotations", + "version": "v1.4.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/annotations.git", + "reference": "54cacc9b81758b14e3ce750f205a393d52339e97" + }, + "dist": { + "type": "zip", + "url": "https://github.com/gitapi/repos/doctrine/annotations/zipball/54cacc9b81758b14e3ce750f205a393d52339e97", + "reference": "54cacc9b81758b14e3ce750f205a393d52339e97", + "shasum": "" + }, + "require": { + "doctrine/lexer": "1.*", + "php": "^5.6 || ^7.0" + }, + "require-dev": { + "doctrine/cache": "1.*", + "phpunit/phpunit": "^5.7" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Docblock Annotations Parser", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "annotations", + "docblock", + "parser" + ], + "support": { + "issues": "https://github.com/doctrine/annotations/issues", + "source": "https://github.com/doctrine/annotations/tree/v1.4.0" + }, + "time": "2017-02-24T16:22:25+00:00" + }, + { + "name": "doctrine/lexer", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/doctrine/lexer.git", + "reference": "1febd6c3ef84253d7c815bed85fc622ad207a9f8" + }, + "dist": { + "type": "zip", + "url": "https://github.com/gitapi/repos/doctrine/lexer/zipball/1febd6c3ef84253d7c815bed85fc622ad207a9f8", + "reference": "1febd6c3ef84253d7c815bed85fc622ad207a9f8", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "require-dev": { + "phpunit/phpunit": "^4.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Common\\Lexer\\": "lib/Doctrine/Common/Lexer" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.", + "homepage": "https://www.doctrine-project.org/projects/lexer.html", + "keywords": [ + "annotations", + "docblock", + "lexer", + "parser", + "php" + ], + "support": { + "issues": "https://github.com/doctrine/lexer/issues", + "source": "https://github.com/doctrine/lexer/tree/1.0.2" + }, + "time": "2019-06-08T11:03:04+00:00" + }, + { + "name": "friendsofphp/php-cs-fixer", + "version": "v2.19.1", + "source": { + "type": "git", + "url": "https://github.com/FriendsOfPHP/PHP-CS-Fixer.git", + "reference": "1fa4af92841f67362c053728989b262fba8eb1ec" + }, + "dist": { + "type": "zip", + "url": "https://github.com/gitapi/repos/FriendsOfPHP/PHP-CS-Fixer/zipball/1fa4af92841f67362c053728989b262fba8eb1ec", + "reference": "1fa4af92841f67362c053728989b262fba8eb1ec", + "shasum": "" + }, + "require": { + "composer/semver": "^1.4 || ^2.0 || ^3.0", + "composer/xdebug-handler": "^1.2 || ^2.0", + "doctrine/annotations": "^1.2", + "ext-json": "*", + "ext-tokenizer": "*", + "php": "^5.6 || ^7.0 || ^8.0", + "php-cs-fixer/diff": "^1.3", + "symfony/console": "^3.4.43 || ^4.1.6 || ^5.0", + "symfony/event-dispatcher": "^3.0 || ^4.0 || ^5.0", + "symfony/filesystem": "^3.0 || ^4.0 || ^5.0", + "symfony/finder": "^3.0 || ^4.0 || ^5.0", + "symfony/options-resolver": "^3.0 || ^4.0 || ^5.0", + "symfony/polyfill-php70": "^1.0", + "symfony/polyfill-php72": "^1.4", + "symfony/process": "^3.0 || ^4.0 || ^5.0", + "symfony/stopwatch": "^3.0 || ^4.0 || ^5.0" + }, + "require-dev": { + "justinrainbow/json-schema": "^5.0", + "keradus/cli-executor": "^1.4", + "mikey179/vfsstream": "^1.6", + "php-coveralls/php-coveralls": "^2.4.2", + "php-cs-fixer/accessible-object": "^1.0", + "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.2", + "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.2.1", + "phpspec/prophecy-phpunit": "^1.1 || ^2.0", + "phpunit/phpunit": "^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.13 || ^9.5", + "phpunitgoodpractices/polyfill": "^1.5", + "phpunitgoodpractices/traits": "^1.9.1", + "sanmai/phpunit-legacy-adapter": "^6.4 || ^8.2.1", + "symfony/phpunit-bridge": "^5.2.1", + "symfony/yaml": "^3.0 || ^4.0 || ^5.0" + }, + "suggest": { + "ext-dom": "For handling output formats in XML", + "ext-mbstring": "For handling non-UTF8 characters.", + "php-cs-fixer/phpunit-constraint-isidenticalstring": "For IsIdenticalString constraint.", + "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "For XmlMatchesXsd constraint.", + "symfony/polyfill-mbstring": "When enabling `ext-mbstring` is not possible." + }, + "bin": [ + "php-cs-fixer" + ], + "type": "application", + "extra": { + "branch-alias": { + "dev-master": "2.19-dev" + } + }, + "autoload": { + "psr-4": { + "PhpCsFixer\\": "src/" + }, + "classmap": [ + "tests/Test/AbstractFixerTestCase.php", + "tests/Test/AbstractIntegrationCaseFactory.php", + "tests/Test/AbstractIntegrationTestCase.php", + "tests/Test/Assert/AssertTokensTrait.php", + "tests/Test/IntegrationCase.php", + "tests/Test/IntegrationCaseFactory.php", + "tests/Test/IntegrationCaseFactoryInterface.php", + "tests/Test/InternalIntegrationCaseFactory.php", + "tests/Test/IsIdenticalConstraint.php", + "tests/Test/TokensWithObservedTransformers.php", + "tests/TestCase.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Dariusz Rumiński", + "email": "dariusz.ruminski@gmail.com" + } + ], + "description": "A tool to automatically fix PHP code style", + "support": { + "issues": "https://github.com/FriendsOfPHP/PHP-CS-Fixer/issues", + "source": "https://github.com/FriendsOfPHP/PHP-CS-Fixer/tree/v2.19.1" + }, + "funding": [ + { + "url": "https://github.com/keradus", + "type": "github" + } + ], + "time": "2021-08-02T17:52:09+00:00" + }, + { + "name": "paragonie/random_compat", + "version": "v2.0.20", + "source": { + "type": "git", + "url": "https://github.com/paragonie/random_compat.git", + "reference": "0f1f60250fccffeaf5dda91eea1c018aed1adc2a" + }, + "dist": { + "type": "zip", + "url": "https://github.com/gitapi/repos/paragonie/random_compat/zipball/0f1f60250fccffeaf5dda91eea1c018aed1adc2a", + "reference": "0f1f60250fccffeaf5dda91eea1c018aed1adc2a", + "shasum": "" + }, + "require": { + "php": ">=5.2.0" + }, + "require-dev": { + "phpunit/phpunit": "4.*|5.*" + }, + "suggest": { + "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." + }, + "type": "library", + "autoload": { + "files": [ + "lib/random.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com" + } + ], + "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", + "keywords": [ + "csprng", + "polyfill", + "pseudorandom", + "random" + ], + "support": { + "email": "info@paragonie.com", + "issues": "https://github.com/paragonie/random_compat/issues", + "source": "https://github.com/paragonie/random_compat" + }, + "time": "2021-04-17T09:33:01+00:00" + }, + { + "name": "php-cs-fixer/diff", + "version": "v1.3.1", + "source": { + "type": "git", + "url": "https://github.com/PHP-CS-Fixer/diff.git", + "reference": "dbd31aeb251639ac0b9e7e29405c1441907f5759" + }, + "dist": { + "type": "zip", + "url": "https://github.com/gitapi/repos/PHP-CS-Fixer/diff/zipball/dbd31aeb251639ac0b9e7e29405c1441907f5759", + "reference": "dbd31aeb251639ac0b9e7e29405c1441907f5759", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.7.23 || ^6.4.3 || ^7.0", + "symfony/process": "^3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + }, + { + "name": "SpacePossum" + } + ], + "description": "sebastian/diff v2 backport support for PHP5.6", + "homepage": "https://github.com/PHP-CS-Fixer", + "keywords": [ + "diff" + ], + "support": { + "issues": "https://github.com/PHP-CS-Fixer/diff/issues", + "source": "https://github.com/PHP-CS-Fixer/diff/tree/v1.3.1" + }, + "time": "2020-10-14T08:39:05+00:00" + }, + { + "name": "psr/log", + "version": "1.1.4", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11" + }, + "dist": { + "type": "zip", + "url": "https://github.com/gitapi/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "Psr/Log/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/1.1.4" + }, + "time": "2021-05-03T11:20:27+00:00" + }, + { + "name": "roave/security-advisories", + "version": "dev-latest", + "source": { + "type": "git", + "url": "https://github.com/Roave/SecurityAdvisories.git", + "reference": "8bbff2bbc495beeebbc3e1090cfba61184bf8ab1" + }, + "dist": { + "type": "zip", + "url": "https://github.com/gitapi/repos/Roave/SecurityAdvisories/zipball/8bbff2bbc495beeebbc3e1090cfba61184bf8ab1", + "reference": "8bbff2bbc495beeebbc3e1090cfba61184bf8ab1", + "shasum": "" + }, + "conflict": { + "3f/pygmentize": "<1.2", + "adodb/adodb-php": "<5.20.12", + "alterphp/easyadmin-extension-bundle": ">=1.2,<1.2.11|>=1.3,<1.3.1", + "amazing/media2click": ">=1,<1.3.3", + "amphp/artax": "<1.0.6|>=2,<2.0.6", + "amphp/http": "<1.0.1", + "amphp/http-client": ">=4,<4.4", + "api-platform/core": ">=2.2,<2.2.10|>=2.3,<2.3.6", + "asymmetricrypt/asymmetricrypt": ">=0,<9.9.99", + "aws/aws-sdk-php": ">=3,<3.2.1", + "bagisto/bagisto": "<0.1.5", + "barrelstrength/sprout-base-email": "<1.2.7", + "barrelstrength/sprout-forms": "<3.9", + "baserproject/basercms": "<4.4.5", + "bk2k/bootstrap-package": ">=7.1,<7.1.2|>=8,<8.0.8|>=9,<9.0.4|>=9.1,<9.1.3|>=10,<10.0.10|>=11,<11.0.3", + "bolt/bolt": "<3.7.2", + "bolt/core": "<4.1.13", + "brightlocal/phpwhois": "<=4.2.5", + "buddypress/buddypress": "<5.1.2", + "bugsnag/bugsnag-laravel": ">=2,<2.0.2", + "cakephp/cakephp": ">=1.3,<1.3.18|>=2,<2.4.99|>=2.5,<2.5.99|>=2.6,<2.6.12|>=2.7,<2.7.6|>=3,<3.5.18|>=3.6,<3.6.15|>=3.7,<3.7.7", + "cart2quote/module-quotation": ">=4.1.6,<=4.4.5|>=5,<5.4.4", + "cartalyst/sentry": "<=2.1.6", + "centreon/centreon": "<20.10.7", + "cesnet/simplesamlphp-module-proxystatistics": "<3.1", + "codeigniter/framework": "<=3.0.6", + "composer/composer": "<1.10.22|>=2-alpha.1,<2.0.13", + "contao-components/mediaelement": ">=2.14.2,<2.21.1", + "contao/core": ">=2,<3.5.39", + "contao/core-bundle": ">=4,<4.4.52|>=4.5,<4.9.16|>=4.10,<4.11.5|= 4.10.0", + "contao/listing-bundle": ">=4,<4.4.8", + "craftcms/cms": "<3.6.7", + "croogo/croogo": "<3.0.7", + "datadog/dd-trace": ">=0.30,<0.30.2", + "david-garcia/phpwhois": "<=4.3.1", + "derhansen/sf_event_mgt": "<4.3.1|>=5,<5.1.1", + "directmailteam/direct-mail": "<5.2.4", + "doctrine/annotations": ">=1,<1.2.7", + "doctrine/cache": ">=1,<1.3.2|>=1.4,<1.4.2", + "doctrine/common": ">=2,<2.4.3|>=2.5,<2.5.1", + "doctrine/dbal": ">=2,<2.0.8|>=2.1,<2.1.2", + "doctrine/doctrine-bundle": "<1.5.2", + "doctrine/doctrine-module": "<=0.7.1", + "doctrine/mongodb-odm": ">=1,<1.0.2", + "doctrine/mongodb-odm-bundle": ">=2,<3.0.1", + "doctrine/orm": ">=2,<2.4.8|>=2.5,<2.5.1|>=2.8.3,<2.8.4", + "dolibarr/dolibarr": "<11.0.4", + "dompdf/dompdf": ">=0.6,<0.6.2", + "drupal/core": ">=7,<7.80|>=8,<8.9.14|>=9,<9.0.12|>=9.1,<9.1.7", + "drupal/drupal": ">=7,<7.80|>=8,<8.9.14|>=9,<9.0.12|>=9.1,<9.1.7", + "dweeves/magmi": "<=0.7.24", + "endroid/qr-code-bundle": "<3.4.2", + "enshrined/svg-sanitize": "<0.13.1", + "erusev/parsedown": "<1.7.2", + "ether/logs": "<3.0.4", + "ezsystems/demobundle": ">=5.4,<5.4.6.1", + "ezsystems/ez-support-tools": ">=2.2,<2.2.3", + "ezsystems/ezdemo-ls-extension": ">=5.4,<5.4.2.1", + "ezsystems/ezfind-ls": ">=5.3,<5.3.6.1|>=5.4,<5.4.11.1|>=2017.12,<2017.12.0.1", + "ezsystems/ezplatform": ">=1.7,<1.7.9.1|>=1.13,<1.13.5.1|>=2.5,<2.5.4", + "ezsystems/ezplatform-admin-ui": ">=1.3,<1.3.5|>=1.4,<1.4.6", + "ezsystems/ezplatform-admin-ui-assets": ">=4,<4.2.1|>=5,<5.0.1|>=5.1,<5.1.1", + "ezsystems/ezplatform-kernel": "<=1.2.5|>=1.3,<=1.3.1", + "ezsystems/ezplatform-rest": ">=1.2,<=1.2.2|>=1.3,<=1.3.1", + "ezsystems/ezplatform-user": ">=1,<1.0.1", + "ezsystems/ezpublish-kernel": "<=6.13.8.1|>=7,<=7.5.15.1", + "ezsystems/ezpublish-legacy": ">=5.3,<5.3.12.6|>=5.4,<5.4.14.2|>=2011,<2017.12.7.3|>=2018.6,<2018.6.1.4|>=2018.9,<2018.9.1.3|>=2019.3,<2019.3.5.1", + "ezsystems/platform-ui-assets-bundle": ">=4.2,<4.2.3", + "ezsystems/repository-forms": ">=2.3,<2.3.2.1", + "ezyang/htmlpurifier": "<4.1.1", + "facade/ignition": "<1.16.14|>=2,<2.4.2|>=2.5,<2.5.2", + "feehi/cms": "<=2.1.1", + "firebase/php-jwt": "<2", + "flarum/core": ">=1,<=1.0.1", + "flarum/sticky": ">=0.1-beta.14,<=0.1-beta.15", + "flarum/tags": "<=0.1-beta.13", + "fluidtypo3/vhs": "<5.1.1", + "fooman/tcpdf": "<6.2.22", + "forkcms/forkcms": "<5.8.3", + "fossar/tcpdf-parser": "<6.2.22", + "francoisjacquet/rosariosis": "<6.5.1", + "friendsofsymfony/oauth2-php": "<1.3", + "friendsofsymfony/rest-bundle": ">=1.2,<1.2.2", + "friendsofsymfony/user-bundle": ">=1.2,<1.3.5", + "friendsoftypo3/mediace": ">=7.6.2,<7.6.5", + "froala/wysiwyg-editor": "<3.2.7", + "fuel/core": "<1.8.1", + "getgrav/grav": "<=1.7.10", + "getkirby/cms": "<=3.5.6", + "getkirby/panel": "<2.5.14", + "gos/web-socket-bundle": "<1.10.4|>=2,<2.6.1|>=3,<3.3", + "gree/jose": "<=2.2", + "gregwar/rst": "<1.0.3", + "grumpydictator/firefly-iii": "<5.5.13", + "guzzlehttp/guzzle": ">=4-rc.2,<4.2.4|>=5,<5.3.1|>=6,<6.2.1", + "illuminate/auth": ">=4,<4.0.99|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.10", + "illuminate/cookie": ">=4,<=4.0.11|>=4.1,<=4.1.99999|>=4.2,<=4.2.99999|>=5,<=5.0.99999|>=5.1,<=5.1.99999|>=5.2,<=5.2.99999|>=5.3,<=5.3.99999|>=5.4,<=5.4.99999|>=5.5,<=5.5.49|>=5.6,<=5.6.99999|>=5.7,<=5.7.99999|>=5.8,<=5.8.99999|>=6,<6.18.31|>=7,<7.22.4", + "illuminate/database": "<6.20.26|>=7,<8.40", + "illuminate/encryption": ">=4,<=4.0.11|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.40|>=5.6,<5.6.15", + "illuminate/view": ">=7,<7.1.2", + "impresscms/impresscms": "<=1.4.2", + "intelliants/subrion": "<=4.2.1", + "ivankristianto/phpwhois": "<=4.3", + "james-heinrich/getid3": "<1.9.9", + "joomla/archive": "<1.1.10", + "joomla/session": "<1.3.1", + "jsmitty12/phpwhois": "<5.1", + "kazist/phpwhois": "<=4.2.6", + "kitodo/presentation": "<3.1.2", + "klaviyo/magento2-extension": ">=1,<3", + "kreait/firebase-php": ">=3.2,<3.8.1", + "la-haute-societe/tcpdf": "<6.2.22", + "laminas/laminas-http": "<2.14.2", + "laravel/framework": "<6.20.26|>=7,<8.40", + "laravel/socialite": ">=1,<1.0.99|>=2,<2.0.10", + "lavalite/cms": "<=5.8", + "league/commonmark": "<0.18.3", + "league/flysystem": "<1.1.4|>=2,<2.1.1", + "lexik/jwt-authentication-bundle": "<2.10.7|>=2.11,<2.11.3", + "librenms/librenms": "<21.1", + "livewire/livewire": ">2.2.4,<2.2.6", + "localizationteam/l10nmgr": "<7.4|>=8,<8.7|>=9,<9.2", + "magento/community-edition": ">=2,<2.2.10|>=2.3,<2.3.3", + "magento/magento1ce": "<1.9.4.3", + "magento/magento1ee": ">=1,<1.14.4.3", + "magento/product-community-edition": ">=2,<2.2.10|>=2.3,<2.3.2-p.2", + "marcwillmann/turn": "<0.3.3", + "mautic/core": "<3.3.2|= 2.13.1", + "mediawiki/core": ">=1.27,<1.27.6|>=1.29,<1.29.3|>=1.30,<1.30.2|>=1.31,<1.31.9|>=1.32,<1.32.6|>=1.32.99,<1.33.3|>=1.33.99,<1.34.3|>=1.34.99,<1.35", + "mittwald/typo3_forum": "<1.2.1", + "monolog/monolog": ">=1.8,<1.12", + "moodle/moodle": "<3.5.17|>=3.7,<3.7.9|>=3.8,<3.8.8|>=3.9,<3.9.5|>=3.10,<3.10.2", + "namshi/jose": "<2.2", + "neos/flow": ">=1,<1.0.4|>=1.1,<1.1.1|>=2,<2.0.1|>=2.3,<2.3.16|>=3,<3.0.12|>=3.1,<3.1.10|>=3.2,<3.2.13|>=3.3,<3.3.13|>=4,<4.0.6", + "neos/form": ">=1.2,<4.3.3|>=5,<5.0.9|>=5.1,<5.1.3", + "neos/neos": ">=1.1,<1.1.3|>=1.2,<1.2.13|>=2,<2.0.4|>=2.3,<2.9.99|>=3,<3.0.20|>=3.1,<3.1.18|>=3.2,<3.2.14|>=3.3,<3.3.23|>=4,<4.0.17|>=4.1,<4.1.16|>=4.2,<4.2.12|>=4.3,<4.3.3", + "neos/swiftmailer": ">=4.1,<4.1.99|>=5.4,<5.4.5", + "nette/application": ">=2,<2.0.19|>=2.1,<2.1.13|>=2.2,<2.2.10|>=2.3,<2.3.14|>=2.4,<2.4.16|>=3,<3.0.6", + "nette/nette": ">=2,<2.0.19|>=2.1,<2.1.13", + "nilsteampassnet/teampass": "<=2.1.27.36", + "nukeviet/nukeviet": "<4.3.4", + "nystudio107/craft-seomatic": "<3.3", + "nzo/url-encryptor-bundle": ">=4,<4.3.2|>=5,<5.0.1", + "october/backend": "<1.1.2", + "october/cms": "= 1.1.1|= 1.0.471|= 1.0.469|>=1.0.319,<1.0.469", + "october/october": ">=1.0.319,<1.0.466", + "october/rain": "<1.0.472|>=1.1,<1.1.2", + "onelogin/php-saml": "<2.10.4", + "oneup/uploader-bundle": "<1.9.3|>=2,<2.1.5", + "opencart/opencart": "<=3.0.3.2", + "openid/php-openid": "<2.3", + "openmage/magento-lts": "<=19.4.12|>=20,<=20.0.8", + "orchid/platform": ">=9,<9.4.4", + "oro/crm": ">=1.7,<1.7.4", + "oro/platform": ">=1.7,<1.7.4", + "padraic/humbug_get_contents": "<1.1.2", + "pagarme/pagarme-php": ">=0,<3", + "pagekit/pagekit": "<=1.0.18", + "paragonie/random_compat": "<2", + "passbolt/passbolt_api": "<2.11", + "paypal/merchant-sdk-php": "<3.12", + "pear/archive_tar": "<1.4.14", + "personnummer/personnummer": "<3.0.2", + "phanan/koel": "<5.1.4", + "phpfastcache/phpfastcache": ">=5,<5.0.13", + "phpmailer/phpmailer": "<6.5", + "phpmussel/phpmussel": ">=1,<1.6", + "phpmyadmin/phpmyadmin": "<4.9.6|>=5,<5.0.3", + "phpoffice/phpexcel": "<1.8.2", + "phpoffice/phpspreadsheet": "<1.16", + "phpseclib/phpseclib": "<2.0.31|>=3,<3.0.7", + "phpunit/phpunit": ">=4.8.19,<4.8.28|>=5.0.10,<5.6.3", + "phpwhois/phpwhois": "<=4.2.5", + "phpxmlrpc/extras": "<0.6.1", + "pimcore/pimcore": "<10.0.7", + "pocketmine/pocketmine-mp": "<3.15.4", + "pressbooks/pressbooks": "<5.18", + "prestashop/autoupgrade": ">=4,<4.10.1", + "prestashop/contactform": ">1.0.1,<4.3", + "prestashop/gamification": "<2.3.2", + "prestashop/productcomments": ">=4,<4.2.1", + "prestashop/ps_emailsubscription": "<2.6.1", + "prestashop/ps_facetedsearch": "<3.4.1", + "privatebin/privatebin": "<1.2.2|>=1.3,<1.3.2", + "propel/propel": ">=2-alpha.1,<=2-alpha.7", + "propel/propel1": ">=1,<=1.7.1", + "pterodactyl/panel": "<0.7.19|>=1-rc.0,<=1-rc.6", + "pusher/pusher-php-server": "<2.2.1", + "pwweb/laravel-core": "<=0.3.6-beta", + "rainlab/debugbar-plugin": "<3.1", + "rmccue/requests": ">=1.6,<1.8", + "robrichards/xmlseclibs": "<3.0.4", + "sabberworm/php-css-parser": ">=1,<1.0.1|>=2,<2.0.1|>=3,<3.0.1|>=4,<4.0.1|>=5,<5.0.9|>=5.1,<5.1.3|>=5.2,<5.2.1|>=6,<6.0.2|>=7,<7.0.4|>=8,<8.0.1|>=8.1,<8.1.1|>=8.2,<8.2.1|>=8.3,<8.3.1", + "sabre/dav": ">=1.6,<1.6.99|>=1.7,<1.7.11|>=1.8,<1.8.9", + "scheb/two-factor-bundle": ">=0,<3.26|>=4,<4.11", + "sensiolabs/connect": "<4.2.3", + "serluck/phpwhois": "<=4.2.6", + "shopware/core": "<=6.4.1", + "shopware/platform": "<=6.4.1", + "shopware/production": "<=6.3.5.2", + "shopware/shopware": "<=5.6.9", + "silverstripe/admin": ">=1.0.3,<1.0.4|>=1.1,<1.1.1", + "silverstripe/assets": ">=1,<1.4.7|>=1.5,<1.5.2", + "silverstripe/cms": "<4.3.6|>=4.4,<4.4.4", + "silverstripe/comments": ">=1.3,<1.9.99|>=2,<2.9.99|>=3,<3.1.1", + "silverstripe/forum": "<=0.6.1|>=0.7,<=0.7.3", + "silverstripe/framework": "<4.7.4", + "silverstripe/graphql": "<=3.5|>=4-alpha.1,<4-alpha.2", + "silverstripe/registry": ">=2.1,<2.1.2|>=2.2,<2.2.1", + "silverstripe/restfulserver": ">=1,<1.0.9|>=2,<2.0.4", + "silverstripe/subsites": ">=2,<2.1.1", + "silverstripe/taxonomy": ">=1.3,<1.3.1|>=2,<2.0.1", + "silverstripe/userforms": "<3", + "simple-updates/phpwhois": "<=1", + "simplesamlphp/saml2": "<1.10.6|>=2,<2.3.8|>=3,<3.1.4", + "simplesamlphp/simplesamlphp": "<1.18.6", + "simplesamlphp/simplesamlphp-module-infocard": "<1.0.1", + "simplito/elliptic-php": "<1.0.6", + "slim/slim": "<2.6", + "smarty/smarty": "<3.1.39", + "socalnick/scn-social-auth": "<1.15.2", + "socialiteproviders/steam": "<1.1", + "spoonity/tcpdf": "<6.2.22", + "squizlabs/php_codesniffer": ">=1,<2.8.1|>=3,<3.0.1", + "ssddanbrown/bookstack": "<0.29.2", + "stormpath/sdk": ">=0,<9.9.99", + "studio-42/elfinder": "<2.1.59", + "sulu/sulu": "<1.6.41|>=2,<2.0.10|>=2.1,<2.1.1", + "swiftmailer/swiftmailer": ">=4,<5.4.5", + "sylius/admin-bundle": ">=1,<1.0.17|>=1.1,<1.1.9|>=1.2,<1.2.2", + "sylius/grid": ">=1,<1.1.19|>=1.2,<1.2.18|>=1.3,<1.3.13|>=1.4,<1.4.5|>=1.5,<1.5.1", + "sylius/grid-bundle": ">=1,<1.1.19|>=1.2,<1.2.18|>=1.3,<1.3.13|>=1.4,<1.4.5|>=1.5,<1.5.1", + "sylius/resource-bundle": "<1.3.14|>=1.4,<1.4.7|>=1.5,<1.5.2|>=1.6,<1.6.4", + "sylius/sylius": "<1.6.9|>=1.7,<1.7.9|>=1.8,<1.8.3|>=1.9,<1.9.5", + "symbiote/silverstripe-multivaluefield": ">=3,<3.0.99", + "symbiote/silverstripe-queuedjobs": ">=3,<3.0.2|>=3.1,<3.1.4|>=4,<4.0.7|>=4.1,<4.1.2|>=4.2,<4.2.4|>=4.3,<4.3.3|>=4.4,<4.4.3|>=4.5,<4.5.1|>=4.6,<4.6.4", + "symbiote/silverstripe-versionedfiles": "<=2.0.3", + "symfony/cache": ">=3.1,<3.4.35|>=4,<4.2.12|>=4.3,<4.3.8", + "symfony/dependency-injection": ">=2,<2.0.17|>=2.7,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", + "symfony/error-handler": ">=4.4,<4.4.4|>=5,<5.0.4", + "symfony/form": ">=2.3,<2.3.35|>=2.4,<2.6.12|>=2.7,<2.7.50|>=2.8,<2.8.49|>=3,<3.4.20|>=4,<4.0.15|>=4.1,<4.1.9|>=4.2,<4.2.1", + "symfony/framework-bundle": ">=2,<2.3.18|>=2.4,<2.4.8|>=2.5,<2.5.2|>=2.7,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", + "symfony/http-foundation": ">=2,<2.8.52|>=3,<3.4.35|>=4,<4.2.12|>=4.3,<4.3.8|>=4.4,<4.4.7|>=5,<5.0.7", + "symfony/http-kernel": ">=2,<2.8.52|>=3,<3.4.35|>=4,<4.2.12|>=4.3,<4.4.13|>=5,<5.1.5", + "symfony/intl": ">=2.7,<2.7.38|>=2.8,<2.8.31|>=3,<3.2.14|>=3.3,<3.3.13", + "symfony/maker-bundle": ">=1.27,<1.29.2|>=1.30,<1.31.1", + "symfony/mime": ">=4.3,<4.3.8", + "symfony/phpunit-bridge": ">=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", + "symfony/polyfill": ">=1,<1.10", + "symfony/polyfill-php55": ">=1,<1.10", + "symfony/proxy-manager-bridge": ">=2.7,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", + "symfony/routing": ">=2,<2.0.19", + "symfony/security": ">=2,<2.7.51|>=2.8,<3.4.49|>=4,<4.4.24|>=5,<5.2.8", "symfony/security-bundle": ">=2,<2.7.48|>=2.8,<2.8.41|>=3,<3.3.17|>=3.4,<3.4.11|>=4,<4.0.11", "symfony/security-core": ">=2.4,<2.6.13|>=2.7,<2.7.9|>=2.7.30,<2.7.32|>=2.8,<3.4.49|>=4,<4.4.24|>=5,<5.2.9", "symfony/security-csrf": ">=2.4,<2.7.48|>=2.8,<2.8.41|>=3,<3.3.17|>=3.4,<3.4.11|>=4,<4.0.11", @@ -451,6 +1011,7 @@ "thelia/thelia": ">=2.1-beta.1,<2.1.3", "theonedemon/phpwhois": "<=4.2.5", "titon/framework": ">=0,<9.9.99", + "topthink/think": "<=6.0.9", "tribalsystems/zenario": "<8.8.53370", "truckersmp/phpwhois": "<=4.3.1", "twig/twig": "<1.38|>=2,<2.7", @@ -511,35 +1072,950 @@ "zfr/zfr-oauth2-server-module": "<0.1.2", "zoujingli/thinkadmin": "<6.0.22" }, - "type": "metapackage", + "default-branch": true, + "type": "metapackage", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "role": "maintainer" + }, + { + "name": "Ilya Tribusean", + "email": "slash3b@gmail.com", + "role": "maintainer" + } + ], + "description": "Prevents installation of composer packages with known security vulnerabilities: no API, simply require it", + "support": { + "issues": "https://github.com/Roave/SecurityAdvisories/issues", + "source": "https://github.com/Roave/SecurityAdvisories/tree/latest" + }, + "funding": [ + { + "url": "https://github.com/Ocramius", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/roave/security-advisories", + "type": "tidelift" + } + ], + "time": "2021-08-09T21:02:34+00:00" + }, + { + "name": "squizlabs/php_codesniffer", + "version": "3.6.0", + "source": { + "type": "git", + "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", + "reference": "ffced0d2c8fa8e6cdc4d695a743271fab6c38625" + }, + "dist": { + "type": "zip", + "url": "https://github.com/gitapi/repos/squizlabs/PHP_CodeSniffer/zipball/ffced0d2c8fa8e6cdc4d695a743271fab6c38625", + "reference": "ffced0d2c8fa8e6cdc4d695a743271fab6c38625", + "shasum": "" + }, + "require": { + "ext-simplexml": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0" + }, + "bin": [ + "bin/phpcs", + "bin/phpcbf" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Greg Sherwood", + "role": "lead" + } + ], + "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", + "homepage": "https://github.com/squizlabs/PHP_CodeSniffer", + "keywords": [ + "phpcs", + "standards" + ], + "support": { + "issues": "https://github.com/squizlabs/PHP_CodeSniffer/issues", + "source": "https://github.com/squizlabs/PHP_CodeSniffer", + "wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki" + }, + "time": "2021-04-09T00:54:41+00:00" + }, + { + "name": "symfony/console", + "version": "v3.4.47", + "source": { + "type": "git", + "url": "https://github.com/symfony/console.git", + "reference": "a10b1da6fc93080c180bba7219b5ff5b7518fe81" + }, + "dist": { + "type": "zip", + "url": "https://github.com/gitapi/repos/symfony/console/zipball/a10b1da6fc93080c180bba7219b5ff5b7518fe81", + "reference": "a10b1da6fc93080c180bba7219b5ff5b7518fe81", + "shasum": "" + }, + "require": { + "php": "^5.5.9|>=7.0.8", + "symfony/debug": "~2.8|~3.0|~4.0", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "symfony/dependency-injection": "<3.4", + "symfony/process": "<3.3" + }, + "provide": { + "psr/log-implementation": "1.0" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/config": "~3.3|~4.0", + "symfony/dependency-injection": "~3.4|~4.0", + "symfony/event-dispatcher": "~2.8|~3.0|~4.0", + "symfony/lock": "~3.4|~4.0", + "symfony/process": "~3.3|~4.0" + }, + "suggest": { + "psr/log": "For using the console logger", + "symfony/event-dispatcher": "", + "symfony/lock": "", + "symfony/process": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Console\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Console Component", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/console/tree/v3.4.47" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-10-24T10:57:07+00:00" + }, + { + "name": "symfony/debug", + "version": "v3.4.47", + "source": { + "type": "git", + "url": "https://github.com/symfony/debug.git", + "reference": "ab42889de57fdfcfcc0759ab102e2fd4ea72dcae" + }, + "dist": { + "type": "zip", + "url": "https://github.com/gitapi/repos/symfony/debug/zipball/ab42889de57fdfcfcc0759ab102e2fd4ea72dcae", + "reference": "ab42889de57fdfcfcc0759ab102e2fd4ea72dcae", + "shasum": "" + }, + "require": { + "php": "^5.5.9|>=7.0.8", + "psr/log": "~1.0" + }, + "conflict": { + "symfony/http-kernel": ">=2.3,<2.3.24|~2.4.0|>=2.5,<2.5.9|>=2.6,<2.6.2" + }, + "require-dev": { + "symfony/http-kernel": "~2.8|~3.0|~4.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Debug\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Debug Component", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/debug/tree/v3.4.47" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-10-24T10:57:07+00:00" + }, + { + "name": "symfony/event-dispatcher", + "version": "v3.4.47", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "31fde73757b6bad247c54597beef974919ec6860" + }, + "dist": { + "type": "zip", + "url": "https://github.com/gitapi/repos/symfony/event-dispatcher/zipball/31fde73757b6bad247c54597beef974919ec6860", + "reference": "31fde73757b6bad247c54597beef974919ec6860", + "shasum": "" + }, + "require": { + "php": "^5.5.9|>=7.0.8" + }, + "conflict": { + "symfony/dependency-injection": "<3.3" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/config": "~2.8|~3.0|~4.0", + "symfony/debug": "~3.4|~4.4", + "symfony/dependency-injection": "~3.3|~4.0", + "symfony/expression-language": "~2.8|~3.0|~4.0", + "symfony/stopwatch": "~2.8|~3.0|~4.0" + }, + "suggest": { + "symfony/dependency-injection": "", + "symfony/http-kernel": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\EventDispatcher\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony EventDispatcher Component", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/event-dispatcher/tree/v3.4.47" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-10-24T10:57:07+00:00" + }, + { + "name": "symfony/filesystem", + "version": "v3.4.47", + "source": { + "type": "git", + "url": "https://github.com/symfony/filesystem.git", + "reference": "e58d7841cddfed6e846829040dca2cca0ebbbbb3" + }, + "dist": { + "type": "zip", + "url": "https://github.com/gitapi/repos/symfony/filesystem/zipball/e58d7841cddfed6e846829040dca2cca0ebbbbb3", + "reference": "e58d7841cddfed6e846829040dca2cca0ebbbbb3", + "shasum": "" + }, + "require": { + "php": "^5.5.9|>=7.0.8", + "symfony/polyfill-ctype": "~1.8" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Filesystem\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Filesystem Component", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/filesystem/tree/v3.4.47" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-10-24T10:57:07+00:00" + }, + { + "name": "symfony/finder", + "version": "v3.4.47", + "source": { + "type": "git", + "url": "https://github.com/symfony/finder.git", + "reference": "b6b6ad3db3edb1b4b1c1896b1975fb684994de6e" + }, + "dist": { + "type": "zip", + "url": "https://github.com/gitapi/repos/symfony/finder/zipball/b6b6ad3db3edb1b4b1c1896b1975fb684994de6e", + "reference": "b6b6ad3db3edb1b4b1c1896b1975fb684994de6e", + "shasum": "" + }, + "require": { + "php": "^5.5.9|>=7.0.8" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Finder\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Finder Component", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/finder/tree/v3.4.47" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-11-16T17:02:08+00:00" + }, + { + "name": "symfony/options-resolver", + "version": "v3.4.47", + "source": { + "type": "git", + "url": "https://github.com/symfony/options-resolver.git", + "reference": "c7efc97a47b2ebaabc19d5b6c6b50f5c37c92744" + }, + "dist": { + "type": "zip", + "url": "https://github.com/gitapi/repos/symfony/options-resolver/zipball/c7efc97a47b2ebaabc19d5b6c6b50f5c37c92744", + "reference": "c7efc97a47b2ebaabc19d5b6c6b50f5c37c92744", + "shasum": "" + }, + "require": { + "php": "^5.5.9|>=7.0.8" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\OptionsResolver\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony OptionsResolver Component", + "homepage": "https://symfony.com", + "keywords": [ + "config", + "configuration", + "options" + ], + "support": { + "source": "https://github.com/symfony/options-resolver/tree/v3.4.47" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-10-24T10:57:07+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.19.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "aed596913b70fae57be53d86faa2e9ef85a2297b" + }, + "dist": { + "type": "zip", + "url": "https://github.com/gitapi/repos/symfony/polyfill-ctype/zipball/aed596913b70fae57be53d86faa2e9ef85a2297b", + "reference": "aed596913b70fae57be53d86faa2e9ef85a2297b", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.19-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com", - "role": "maintainer" + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" }, { - "name": "Ilya Tribusean", - "email": "slash3b@gmail.com", - "role": "maintainer" + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "Prevents installation of composer packages with known security vulnerabilities: no API, simply require it", + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "support": { + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.19.0" + }, "funding": [ { - "url": "https://github.com/Ocramius", + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", "type": "github" }, { - "url": "https://tidelift.com/funding/github/packagist/roave/security-advisories", + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-10-23T09:01:57+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.19.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "b5f7b932ee6fa802fc792eabd77c4c88084517ce" + }, + "dist": { + "type": "zip", + "url": "https://github.com/gitapi/repos/symfony/polyfill-mbstring/zipball/b5f7b932ee6fa802fc792eabd77c4c88084517ce", + "reference": "b5f7b932ee6fa802fc792eabd77c4c88084517ce", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.19-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.19.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-10-23T09:01:57+00:00" + }, + { + "name": "symfony/polyfill-php70", + "version": "v1.19.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php70.git", + "reference": "3fe414077251a81a1b15b1c709faf5c2fbae3d4e" + }, + "dist": { + "type": "zip", + "url": "https://github.com/gitapi/repos/symfony/polyfill-php70/zipball/3fe414077251a81a1b15b1c709faf5c2fbae3d4e", + "reference": "3fe414077251a81a1b15b1c709faf5c2fbae3d4e", + "shasum": "" + }, + "require": { + "paragonie/random_compat": "~1.0|~2.0|~9.99", + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.19-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php70\\": "" + }, + "files": [ + "bootstrap.php" + ], + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php70/tree/v1.19.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-10-23T09:01:57+00:00" + }, + { + "name": "symfony/polyfill-php72", + "version": "v1.19.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php72.git", + "reference": "beecef6b463b06954638f02378f52496cb84bacc" + }, + "dist": { + "type": "zip", + "url": "https://github.com/gitapi/repos/symfony/polyfill-php72/zipball/beecef6b463b06954638f02378f52496cb84bacc", + "reference": "beecef6b463b06954638f02378f52496cb84bacc", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.19-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php72\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php72/tree/v1.19.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-10-23T09:01:57+00:00" + }, + { + "name": "symfony/process", + "version": "v3.4.47", + "source": { + "type": "git", + "url": "https://github.com/symfony/process.git", + "reference": "b8648cf1d5af12a44a51d07ef9bf980921f15fca" + }, + "dist": { + "type": "zip", + "url": "https://github.com/gitapi/repos/symfony/process/zipball/b8648cf1d5af12a44a51d07ef9bf980921f15fca", + "reference": "b8648cf1d5af12a44a51d07ef9bf980921f15fca", + "shasum": "" + }, + "require": { + "php": "^5.5.9|>=7.0.8" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Process\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Process Component", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/process/tree/v3.4.47" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-10-24T10:57:07+00:00" + }, + { + "name": "symfony/stopwatch", + "version": "v3.4.47", + "source": { + "type": "git", + "url": "https://github.com/symfony/stopwatch.git", + "reference": "298b81faad4ce60e94466226b2abbb8c9bca7462" + }, + "dist": { + "type": "zip", + "url": "https://github.com/gitapi/repos/symfony/stopwatch/zipball/298b81faad4ce60e94466226b2abbb8c9bca7462", + "reference": "298b81faad4ce60e94466226b2abbb8c9bca7462", + "shasum": "" + }, + "require": { + "php": "^5.5.9|>=7.0.8" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Stopwatch\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Stopwatch Component", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/stopwatch/tree/v3.4.47" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2021-07-26T22:02:34+00:00" + "time": "2020-10-24T10:57:07+00:00" } ], "aliases": [], @@ -556,5 +2032,5 @@ "php": ">=5.6" }, "platform-dev": [], - "plugin-api-version": "1.1.0" + "plugin-api-version": "2.1.0" } diff --git a/version/205/adminmenu/info.php b/version/205/adminmenu/info.php index 0430c6e..74477fa 100644 --- a/version/205/adminmenu/info.php +++ b/version/205/adminmenu/info.php @@ -1,23 +1,28 @@ assign('defaultTabbertab', Helper::getAdminmenu('Info') + Helper::getAdminmenu('Support')); 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)), + '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, ]); @@ -45,7 +50,6 @@ if ((int)Helper::oPlugin()->nVersion < (int)$latestRelease->version) { Shop::Smarty()->assign('update', $latestRelease); } - } catch (Exception $e) { } @@ -57,8 +61,7 @@ } catch (Exception $e) { } } - } catch (Exception $e) { echo "
Fehler: {$e->getMessage()}
"; Helper::logExc($e); -} \ No newline at end of file +} diff --git a/version/205/adminmenu/orders.php b/version/205/adminmenu/orders.php index 9033413..f000172 100644 --- a/version/205/adminmenu/orders.php +++ b/version/205/adminmenu/orders.php @@ -1,4 +1,8 @@ getBestellung(), $checkout->getModel())) { @@ -51,15 +57,14 @@ case 'export': try { - $export = []; $from = new DateTime($_REQUEST['from']); - $to = new DateTime($_REQUEST['to']); + $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'), + ':To' => $to->format('Y-m-d'), ], 2); @@ -87,22 +92,22 @@ foreach ($orders as $order) { - $order = new ws_mollie\Model\Payment($order); + $order = new ws_mollie\Model\Payment($order); $checkout = AbstractCheckout::fromModel($order); $tmp = [ - 'kBestellung' => $order->kBestellung, - 'cOrderId' => $order->kID, - 'cStatus' => $checkout->getMollie() ? $checkout->getMollie()->status : $order->cStatus, - 'cBestellNr' => $checkout->getBestellung() ? $checkout->getBestellung()->cBestellNr : $order->cOrderNumber, - 'nStatus' => $checkout->getBestellung() ? $checkout->getBestellung()->cStatus : 0, - 'cMode' => $order->cMode, + 'kBestellung' => $order->kBestellung, + 'cOrderId' => $order->kID, + 'cStatus' => $checkout->getMollie() ? $checkout->getMollie()->status : $order->cStatus, + 'cBestellNr' => $checkout->getBestellung() ? $checkout->getBestellung()->cBestellNr : $order->cOrderNumber, + 'nStatus' => $checkout->getBestellung() ? $checkout->getBestellung()->cStatus : 0, + 'cMode' => $order->cMode, 'cOriginalOrderNumber' => $checkout->getMollie() && isset($checkout->getMollie()->metadata->originalOrderNumber) ? $checkout->getMollie()->metadata->originalOrderNumber : '', - 'cCurrency' => $order->cCurrency, - 'fAmount' => $order->fAmount, - 'cMethod' => $order->cMethod, - 'cPaymentId' => $order->cTransactionId, - 'dCreated' => $order->dCreatedAt, + 'cCurrency' => $order->cCurrency, + 'fAmount' => $order->fAmount, + 'cMethod' => $order->cMethod, + 'cPaymentId' => $order->cTransactionId, + 'dCreated' => $order->dCreatedAt, ]; try { @@ -122,10 +127,10 @@ fclose($out); exit(); - } catch (Exception $e) { Helper::addAlert('Fehler:' . $e->getMessage(), 'danger', 'orders'); } + break; case 'refund': @@ -144,6 +149,7 @@ Helper::addAlert('Fehler: ' . $e->getMessage(), 'danger', 'orders'); goto order; } + break; case 'cancel': @@ -162,6 +168,7 @@ Helper::addAlert('Fehler: ' . $e->getMessage(), 'danger', 'orders'); goto order; } + break; case 'capture': @@ -180,12 +187,12 @@ Helper::addAlert('Fehler: ' . $e->getMessage(), 'danger', 'orders'); goto order; } + break; case 'order': - order: + order : try { - if (!array_key_exists('id', $_REQUEST)) { throw new InvalidArgumentException('Keine ID angeben!'); } @@ -202,10 +209,12 @@ ->assign('checkout', $checkout) ->assign('logs', $checkout->getLogs()); Shop::Smarty()->display($oPlugin->cAdminmenuPfad . '/tpl/order.tpl'); + return; } catch (Exception $e) { Helper::addAlert('Fehler: ' . $e->getMessage(), 'danger', 'orders'); } + break; } } @@ -213,9 +222,10 @@ // Mollie::fixZahlungsarten(); $checkouts = []; - $payments = Shop::DB()->executeQueryPrepared("SELECT * FROM xplugin_ws_mollie_payments WHERE kBestellung IS NOT NULL ORDER BY dCreatedAt DESC LIMIT 1000;", [], 2); + $payments = Shop::DB()->executeQueryPrepared('SELECT * FROM xplugin_ws_mollie_payments WHERE kBestellung IS NOT NULL ORDER BY dCreatedAt DESC LIMIT 1000;', [], 2); foreach ($payments as $i => $payment) { $payment = new Payment($payment); + try { $checkouts[$payment->kBestellung] = AbstractCheckout::fromModel($payment, false); } catch (Exception $e) { @@ -226,13 +236,13 @@ Shop::Smarty()->assign('payments', $payments) ->assign('checkouts', $checkouts) ->assign('admRoot', str_replace('http:', '', $oPlugin->cAdminmenuPfadURL)) - ->assign('hasAPIKey', trim(Helper::getSetting("api_key")) !== ''); + ->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/205/adminmenu/paymentmethods.php b/version/205/adminmenu/paymentmethods.php index 1a6d47f..5019e20 100644 --- a/version/205/adminmenu/paymentmethods.php +++ b/version/205/adminmenu/paymentmethods.php @@ -1,10 +1,13 @@ setApiKey(Helper::getSetting("api_key")); + $mollie->setApiKey(Helper::getSetting('api_key')); $profile = $mollie->profiles->get('me'); - $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}$/']]) ?: AbstractCheckout::getLocale(); + $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}$/']]) ?: AbstractCheckout::getLocale(); $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")); + Shop::Smarty()->assign('defaultTabbertab', Helper::getAdminmenu('Zahlungsarten')); } $params = [ 'include' => 'pricing,issuers', - 'locale' => $locale + 'locale' => $locale ]; if ($amount && $currency) { $params['amount'] = ['value' => number_format($amount, 2, '.', ''), 'currency' => $currency]; @@ -55,17 +59,16 @@ /** @var Method $method */ foreach ($_allMethods as $method) { - - $id = $method->id === 'creditcard' ? 'kreditkarte' : $method->id; + $id = $method->id === 'creditcard' ? 'kreditkarte' : $method->id; $key = "kPlugin_{$oPlugin->kPlugin}_mollie$id"; - $class = null; - $shop = null; + $class = null; + $shop = null; $oClass = null; if (array_key_exists($key, $oPlugin->oPluginZahlungsKlasseAssoc_arr) && !in_array($id, ['voucher', 'giftcard', 'directdebit'], true)) { $class = $oPlugin->oPluginZahlungsKlasseAssoc_arr[$key]; - include_once($oPlugin->cPluginPfad . 'paymentmethod/' . $class->cClassPfad); + include_once $oPlugin->cPluginPfad . 'paymentmethod/' . $class->cClassPfad; /** @var JTLMollie $oClass */ $oClass = new $class->cClassName($id); } @@ -73,19 +76,18 @@ $shop = $oPlugin->oPluginZahlungsmethodeAssoc_arr[$key]; } - $maxExpiryDays = $oClass ? $oClass->getExpiryDays() : null; + $maxExpiryDays = $oClass ? $oClass->getExpiryDays() : null; $allMethods[$method->id] = (object)[ - 'mollie' => $method, - 'class' => $class, - 'allowPreOrder' => $oClass ? $oClass::ALLOW_PAYMENT_BEFORE_ORDER : false, + 'mollie' => $method, + 'class' => $class, + 'allowPreOrder' => $oClass ? $oClass::ALLOW_PAYMENT_BEFORE_ORDER : false, 'allowAutoStorno' => $oClass ? $oClass::ALLOW_AUTO_STORNO : false, - 'oClass' => $oClass, - 'shop' => $shop, - 'maxExpiryDays' => $oClass ? $maxExpiryDays : null, - 'warning' => $oClass && ($maxExpiryDays * 24 * 60 * 60) > $sessionLife, - 'session' => round($sessionLife / 60 / 60, 2) . 'h' + 'oClass' => $oClass, + 'shop' => $shop, + 'maxExpiryDays' => $oClass ? $maxExpiryDays : null, + 'warning' => $oClass && ($maxExpiryDays * 24 * 60 * 60) > $sessionLife, + 'session' => round($sessionLife / 60 / 60, 2) . 'h' ]; - } Shop::Smarty()->assign('profile', $profile) diff --git a/version/205/class/API.php b/version/205/class/API.php index 1790086..a4a268e 100644 --- a/version/205/class/API.php +++ b/version/205/class/API.php @@ -1,9 +1,11 @@ test = $test === null ? self::getMode() : $test; } @@ -41,13 +41,14 @@ public function __construct($test = null) public static function getMode() { require_once PFAD_ROOT . PFAD_ADMIN . PFAD_INCLUDES . 'benutzerverwaltung_inc.php'; - return self::Plugin()->oPluginEinstellungAssoc_arr["testAsAdmin"] === 'Y' && Shop::isAdmin() && self::Plugin()->oPluginEinstellungAssoc_arr['test_api_key']; + + return self::Plugin()->oPluginEinstellungAssoc_arr['testAsAdmin'] === 'Y' && Shop::isAdmin() && self::Plugin()->oPluginEinstellungAssoc_arr['test_api_key']; } /** - * @return MollieApiClient * @throws ApiException * @throws IncompatiblePlatform + * @return MollieApiClient */ public function Client() { @@ -60,6 +61,7 @@ public function Client() ->addVersionString('JTL-Shop/' . JTL_VERSION . JTL_MINOR_VERSION) ->addVersionString('ws_mollie/' . self::Plugin()->nVersion); } + return $this->client; } @@ -70,6 +72,4 @@ public function isTest() { return $this->test; } - - -} \ No newline at end of file +} diff --git a/version/205/class/Checkout/AbstractCheckout.php b/version/205/class/Checkout/AbstractCheckout.php index 8e0ef7b..611475d 100644 --- a/version/205/class/Checkout/AbstractCheckout.php +++ b/version/205/class/Checkout/AbstractCheckout.php @@ -1,8 +1,11 @@ ['lang' => 'de', 'country' => ['DE', 'AT', 'CH']], @@ -54,7 +57,7 @@ abstract class AbstractCheckout 'eng' => ['lang' => 'en', 'country' => ['GB', 'US']], ]; /** - * @var \Mollie\Api\Resources\Customer|null + * @var null|\Mollie\Api\Resources\Customer */ protected $customer; /** @@ -81,16 +84,16 @@ abstract class AbstractCheckout /** * AbstractCheckout constructor. * @param Bestellung $oBestellung - * @param null $api + * @param null $api */ public function __construct(Bestellung $oBestellung, $api = null) { - $this->api = $api; + $this->api = $api; $this->oBestellung = $oBestellung; } /** - * @param int $kBestellung + * @param int $kBestellung * @param bool $checkZA * @return bool */ @@ -99,8 +102,9 @@ public static function isMollie($kBestellung, $checkZA = false) if ($checkZA) { $res = Shop::DB()->executeQueryPrepared('SELECT * FROM tzahlungsart WHERE cModulId LIKE :cModulId AND kZahlungsart = :kZahlungsart', [ ':kZahlungsart' => $kBestellung, - ':cModulId' => 'kPlugin_' . self::Plugin()->kPlugin . '_%' + ':cModulId' => 'kPlugin_' . self::Plugin()->kPlugin . '_%' ], 1); + return (bool)$res; } @@ -125,9 +129,8 @@ public static function finalizeOrder($sessionHash, $id, $test = false) && (!isset($paymentSession->kBestellung) || !$paymentSession->kBestellung) && isset($_SESSION['Warenkorb']->PositionenArr) && count($_SESSION['Warenkorb']->PositionenArr)) { - $paymentSession->cNotifyID = $id; - $paymentSession->dNotify = 'now()'; + $paymentSession->dNotify = 'now()'; Shop::DB()->update('tzahlungsession', 'cZahlungsID', $sessionHash, $paymentSession); $api = new API($test); @@ -142,14 +145,13 @@ public static function finalizeOrder($sessionHash, $id, $test = false) require_once PFAD_ROOT . PFAD_INCLUDES . 'mailTools.php'; $order = finalisiereBestellung(); $session->cleanUp(); - $paymentSession->nBezahlt = 1; + $paymentSession->nBezahlt = 1; $paymentSession->dZeitBezahlt = 'now()'; } else { throw new Exception('Mollie Status invalid: ' . $mollie->status . '\n' . print_r([$sessionHash, $id], 1)); } if ($order->kBestellung) { - $paymentSession->kBestellung = $order->kBestellung; Shop::DB()->update('tzahlungsession', 'cZahlungsID', $sessionHash, $paymentSession); @@ -181,24 +183,25 @@ public static function finalizeOrder($sessionHash, $id, $test = false) } /** - * @param string $id - * @param bool $bFill - * @param Bestellung|null $order - * @return OrderCheckout|PaymentCheckout + * @param string $id + * @param bool $bFill + * @param null|Bestellung $order * @throws RuntimeException + * @return OrderCheckout|PaymentCheckout */ public static function fromID($id, $bFill = true, Bestellung $order = null) { if (($model = Payment::fromID($id))) { return static::fromModel($model, $bFill, $order); } + throw new RuntimeException(sprintf('Error loading Order: %s', $id)); } /** - * @param Payment $model - * @param bool $bFill - * @param Bestellung|null $order + * @param Payment $model + * @param bool $bFill + * @param null|Bestellung $order * @return OrderCheckout|PaymentCheckout */ public static function fromModel($model, $bFill = true, Bestellung $order = null) @@ -222,6 +225,7 @@ public static function fromModel($model, $bFill = true, Bestellung $order = null } $self->setModel($model); + return $self; } @@ -241,6 +245,7 @@ public function getModel() if (!$this->model) { $this->model = Payment::fromID($this->oBestellung->kBestellung, 'kBestellung'); } + return $this->model; } @@ -255,6 +260,7 @@ protected function setModel($model) } else { throw new RuntimeException('Model already set.'); } + return $this; } @@ -301,6 +307,7 @@ public function getHash() if (!$this->hash) { $this->hash = $this->PaymentMethod()->generateHash($this->oBestellung); } + return $this->hash; } @@ -310,7 +317,7 @@ public function getHash() public function PaymentMethod() { if (!$this->paymentMethod) { - include_once(PFAD_ROOT . PFAD_INCLUDES . 'modules/PaymentMethod.class.php'); + include_once PFAD_ROOT . PFAD_INCLUDES . 'modules/PaymentMethod.class.php'; if ($this->getBestellung()->Zahlungsart && strpos($this->getBestellung()->Zahlungsart->cModulId, "kPlugin_{$this::Plugin()->kPlugin}_") !== false) { try { $this->paymentMethod = PaymentMethod::create($this->getBestellung()->Zahlungsart->cModulId); @@ -321,6 +328,7 @@ public function PaymentMethod() $this->paymentMethod = PaymentMethod::create("kPlugin_{$this::Plugin()->kPlugin}_mollie"); } } + return $this->paymentMethod; } @@ -332,6 +340,7 @@ public function getBestellung() if (!$this->oBestellung && $this->getModel()->kBestellung) { $this->oBestellung = new Bestellung($this->getModel()->kBestellung, true); } + return $this->oBestellung; } @@ -340,37 +349,37 @@ public function getBestellung() */ public function updateModel() { - if ($this->getMollie()) { - $this->getModel()->kID = $this->getMollie()->id; - $this->getModel()->cLocale = $this->getMollie()->locale; - $this->getModel()->fAmount = (float)$this->getMollie()->amount->value; - $this->getModel()->cMethod = $this->getMollie()->method; + $this->getModel()->kID = $this->getMollie()->id; + $this->getModel()->cLocale = $this->getMollie()->locale; + $this->getModel()->fAmount = (float)$this->getMollie()->amount->value; + $this->getModel()->cMethod = $this->getMollie()->method; $this->getModel()->cCurrency = $this->getMollie()->amount->currency; - $this->getModel()->cStatus = $this->getMollie()->status; + $this->getModel()->cStatus = $this->getMollie()->status; if ($this->getMollie()->amountRefunded) { $this->getModel()->fAmountRefunded = $this->getMollie()->amountRefunded->value; } if ($this->getMollie()->amountCaptured) { $this->getModel()->fAmountCaptured = $this->getMollie()->amountCaptured->value; } - $this->getModel()->cMode = $this->getMollie()->mode ?: null; + $this->getModel()->cMode = $this->getMollie()->mode ?: null; $this->getModel()->cRedirectURL = $this->getMollie()->redirectUrl; - $this->getModel()->cWebhookURL = $this->getMollie()->webhookUrl; + $this->getModel()->cWebhookURL = $this->getMollie()->webhookUrl; $this->getModel()->cCheckoutURL = $this->getMollie()->getCheckoutUrl(); } - $this->getModel()->kBestellung = $this->getBestellung()->kBestellung; + $this->getModel()->kBestellung = $this->getBestellung()->kBestellung; $this->getModel()->cOrderNumber = $this->getBestellung()->cBestellNr; - $this->getModel()->cHash = trim($this->getHash(), '_'); + $this->getModel()->cHash = trim($this->getHash(), '_'); $this->getModel()->bSynced = $this->getModel()->bSynced !== null ? $this->getModel()->bSynced : Helper::getSetting('onlyPaid') !== 'Y'; + return $this; } /** * @param false $force - * @return Order|\Mollie\Api\Resources\Payment|null + * @return null|\Mollie\Api\Resources\Payment|Order */ abstract public function getMollie($force = false); @@ -381,7 +390,7 @@ abstract public function getIncomingPayment(); /** * @param Bestellung $oBestellung - * @param Payment $model + * @param Payment $model * @return bool */ public static function makeFetchable(Bestellung $oBestellung, Payment $model) @@ -391,11 +400,13 @@ public static function makeFetchable(Bestellung $oBestellung, Payment $model) Shop::DB()->update('tbestellung', 'kBestellung', $oBestellung->kBestellung, (object)['cAbgeholt' => 'N']); } $model->bSynced = true; + try { return $model->save(); } catch (Exception $e) { - Jtllog::writeLog(sprintf("Fehler beim speichern des Models: %s / Bestellung: %s", $model->kID, $oBestellung->cBestellNr)); + Jtllog::writeLog(sprintf('Fehler beim speichern des Models: %s / Bestellung: %s', $model->kID, $oBestellung->cBestellNr)); } + return false; } @@ -409,10 +420,11 @@ public function Log($msg, $level = LOGLEVEL_NOTICE) if ($this->getMollie()) { $data .= '$' . $this->getMollie()->id; } - ZahlungsLog::add($this->PaymentMethod()->moduleID, "[" . microtime(true) . " - " . $_SERVER['PHP_SELF'] . "] " . $msg, $data, $level); + ZahlungsLog::add($this->PaymentMethod()->moduleID, '[' . microtime(true) . ' - ' . $_SERVER['PHP_SELF'] . '] ' . $msg, $data, $level); } catch (Exception $e) { Jtllog::writeLog('Mollie Log failed: ' . $e->getMessage() . '; Previous Log: ' . print_r([$msg, $level, $data], 1)); } + return $this; } @@ -421,26 +433,26 @@ public function Log($msg, $level = LOGLEVEL_NOTICE) */ public function completlyPaid() { - - if ($row = Shop::DB()->executeQueryPrepared("SELECT SUM(fBetrag) as fBetragSumme FROM tzahlungseingang WHERE kBestellung = :kBestellung", [ + if ($row = Shop::DB()->executeQueryPrepared('SELECT SUM(fBetrag) as fBetragSumme FROM tzahlungseingang WHERE kBestellung = :kBestellung', [ ':kBestellung' => $this->getBestellung()->kBestellung ], 1)) { return $row->fBetragSumme >= round($this->getBestellung()->fGesamtsumme * $this->getBestellung()->fWaehrungsFaktor, 2); } - return false; + return false; } /** * @param $kBestellung - * @return OrderCheckout|PaymentCheckout * * @throws RuntimeException + * @return OrderCheckout|PaymentCheckout */ public static function fromBestellung($kBestellung) { if ($model = Payment::fromID($kBestellung, 'kBestellung')) { return static::fromModel($model); } + throw new RuntimeException(sprintf('Error loading Order for Bestellung: %s', $kBestellung)); } @@ -452,9 +464,9 @@ public static function sendReminders() return; } - $sql = "SELECT p.kID FROM xplugin_ws_mollie_payments p JOIN tbestellung b ON b.kBestellung = p.kBestellung " + $sql = 'SELECT p.kID FROM xplugin_ws_mollie_payments p JOIN tbestellung b ON b.kBestellung = p.kBestellung ' . "WHERE (p.dReminder IS NULL OR p.dReminder = '0000-00-00 00:00:00') " - . "AND p.dCreatedAt < NOW() - INTERVAL :d MINUTE AND p.dCreatedAt > NOW() - INTERVAL 7 DAY " + . 'AND p.dCreatedAt < NOW() - INTERVAL :d MINUTE AND p.dCreatedAt > NOW() - INTERVAL 7 DAY ' . "AND p.cStatus IN ('created','open', 'expired', 'failed', 'canceled') AND NOT b.cStatus = '-1'"; $remindables = Shop::DB()->executeQueryPrepared($sql, [ @@ -464,7 +476,7 @@ public static function sendReminders() try { self::sendReminder($remindable->kID); } catch (Exception $e) { - Jtllog::writeLog("AbstractCheckout::sendReminders: " . $e->getMessage()); + Jtllog::writeLog('AbstractCheckout::sendReminders: ' . $e->getMessage()); } } } @@ -475,9 +487,8 @@ public static function sendReminders() */ public static function sendReminder($kID) { - $checkout = self::fromID($kID); - $return = true; + $return = true; if (!$checkout->getBestellung()->kBestellung || (int)$checkout->getBestellung()->cStatus > BESTELLUNG_STATUS_IN_BEARBEITUNG || (int)$checkout->getBestellung()->cStatus < 0) { return $return; @@ -487,50 +498,50 @@ public static function sendReminder($kID) try { $repayURL = Shop::getURL() . '/?m_pay=' . md5($checkout->getModel()->kID . '-' . $checkout->getBestellung()->kBestellung); - $data = new stdClass(); + $data = new stdClass(); $data->tkunde = new Kunde($checkout->getBestellung()->oKunde->kKunde); if ($data->tkunde->kKunde) { - $data->Bestellung = $checkout->getBestellung(); - $data->PayURL = $repayURL; - $data->Amount = gibPreisStringLocalized($checkout->getModel()->fAmount, $checkout->getBestellung()->Waehrung); //Preise::getLocalizedPriceString($order->getAmount(), Currency::fromISO($order->getCurrency()), false); + $data->PayURL = $repayURL; + $data->Amount = gibPreisStringLocalized($checkout->getModel()->fAmount, $checkout->getBestellung()->Waehrung); //Preise::getLocalizedPriceString($order->getAmount(), Currency::fromISO($order->getCurrency()), false); require_once PFAD_ROOT . PFAD_INCLUDES . 'mailTools.php'; - $mail = new stdClass(); + $mail = new stdClass(); $mail->toEmail = $data->tkunde->cMail; - $mail->toName = trim((isset($data->tKunde->cVorname) + $mail->toName = trim((isset($data->tKunde->cVorname) ? $data->tKunde->cVorname : '') . ' ' . ( - isset($data->tKunde->cNachname) + isset($data->tKunde->cNachname) ? $data->tKunde->cNachname : '' - )) ?: $mail->toEmail; + )) ?: $mail->toEmail; $data->mail = $mail; if (!($sentMail = sendeMail('kPlugin_' . self::Plugin()->kPlugin . '_zahlungserinnerung', $data))) { $checkout->Log(sprintf("Zahlungserinnerung konnte nicht versand werden: %s\n%s", isset($sentMail->cFehler) ?: print_r($sentMail, 1), print_r($data, 1)), LOGLEVEL_ERROR); $return = false; } else { - $checkout->Log(sprintf("Zahlungserinnerung für %s verschickt.", $checkout->getBestellung()->cBestellNr)); + $checkout->Log(sprintf('Zahlungserinnerung für %s verschickt.', $checkout->getBestellung()->cBestellNr)); } } else { $checkout->Log("Kunde '{$checkout->getBestellung()->oKunde->kKunde}' nicht gefunden.", LOGLEVEL_ERROR); } } catch (Exception $e) { - $checkout->Log(sprintf("AbstractCheckout::sendReminder: Zahlungserinnerung für %s fehlgeschlagen: %s", $checkout->getBestellung()->cBestellNr, $e->getMessage())); + $checkout->Log(sprintf('AbstractCheckout::sendReminder: Zahlungserinnerung für %s fehlgeschlagen: %s', $checkout->getBestellung()->cBestellNr, $e->getMessage())); $return = false; } $checkout->getModel()->dReminder = date('Y-m-d H:i:s'); $checkout->getModel()->save(); + return $return; } /** * @param AbstractCheckout $checkout - * @return BaseResource|Refund * @throws ApiException + * @return BaseResource|Refund */ - public static function refund(AbstractCheckout $checkout) + public static function refund(self $checkout) { if ($checkout->getMollie()->resource === 'order') { /** @var Order $order */ @@ -540,6 +551,7 @@ public static function refund(AbstractCheckout $checkout) } $refund = $order->refundAll(); $checkout->Log(sprintf('Bestellung wurde manuell zurückerstattet: %s', $refund->id)); + return $refund; } if ($checkout->getMollie()->resource === 'payment') { @@ -550,8 +562,10 @@ public static function refund(AbstractCheckout $checkout) } $refund = $checkout->API()->Client()->payments->refund($checkout->getMollie(), ['amount' => $checkout->getMollie()->amount]); $checkout->Log(sprintf('Zahlung wurde manuell zurückerstattet: %s', $refund->id)); + return $refund; } + throw new RuntimeException(sprintf('Unbekannte Resource: %s', $checkout->getMollie()->resource)); } @@ -567,13 +581,14 @@ public function API() $this->api = new API(API::getMode()); } } + return $this->api; } /** * @param $checkout - * @return Order|\Mollie\Api\Resources\Payment * @throws ApiException + * @return \Mollie\Api\Resources\Payment|Order */ public static function cancel($checkout) { @@ -583,6 +598,7 @@ public static function cancel($checkout) if ($checkout instanceof PaymentCheckout) { return PaymentCheckout::cancel($checkout); } + throw new RuntimeException('AbstractCheckout::cancel: Invalid Checkout!'); } @@ -611,26 +627,26 @@ public static function getLocales() 'lv_LV', 'lt_LT',]; - $laender = []; - $shopLaender = Shop::DB()->executeQuery("SELECT cLaender FROM tversandart", 2); + $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); + $result = []; + $shopSprachen = Shop::DB()->executeQuery('SELECT * FROM tsprache', 2); foreach ($shopSprachen as $sS) { foreach ($laender as $land) { $result[] = static::getLocale($sS->cISO, $land); } } + return array_intersect(array_unique($result), $locales); } public static function getLocale($cISOSprache = null, $country = null) { - if ($cISOSprache === null) { $cISOSprache = gibStandardsprache()->cISO; } @@ -641,6 +657,7 @@ public static function getLocale($cISOSprache = null, $country = null) } else { $locale .= '_' . self::$localeLangs[$cISOSprache]['country'][0]; } + return $locale; } @@ -650,164 +667,164 @@ public static function getLocale($cISOSprache = null, $country = null) 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); + '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 = []; @@ -822,51 +839,53 @@ public static function getCurrencies() public function loadRequest(&$options = []) { - $oKunde = !$this->getBestellung()->oKunde && $this->PaymentMethod()->duringCheckout ? $_SESSION['Kunde'] : $this->getBestellung()->oKunde; if ($this->getBestellung()) { if ($oKunde->nRegistriert - && ($customer = $this->getCustomer( + && ( + $customer = $this->getCustomer( array_key_exists( 'mollie_create_customer', - $_SESSION['cPost_arr'] ?: []) && $_SESSION['cPost_arr']['mollie_create_customer'] === 'Y', - $oKunde) + $_SESSION['cPost_arr'] ?: [] + ) && $_SESSION['cPost_arr']['mollie_create_customer'] === 'Y', + $oKunde + ) ) && isset($customer)) { $options['customerId'] = $customer->id; } - $this->amount = Amount::factory($this->getBestellung()->fGesamtsummeKundenwaehrung, $this->getBestellung()->Waehrung->cISO, true); + $this->amount = Amount::factory($this->getBestellung()->fGesamtsummeKundenwaehrung, $this->getBestellung()->Waehrung->cISO, true); $this->redirectUrl = $this->PaymentMethod()->duringCheckout ? Shop::getURL() . '/bestellabschluss.php?' . http_build_query(['hash' => $this->getHash()]) : $this->PaymentMethod()->getReturnURL($this->getBestellung()); - $this->metadata = [ - 'kBestellung' => $this->getBestellung()->kBestellung ?: $this->getBestellung()->cBestellNr, - 'kKunde' => $this->getBestellung()->kKunde, + $this->metadata = [ + 'kBestellung' => $this->getBestellung()->kBestellung ?: $this->getBestellung()->cBestellNr, + 'kKunde' => $this->getBestellung()->kKunde, 'kKundengruppe' => Session::getInstance()->CustomerGroup()->kKundengruppe, - 'cHash' => $this->getHash(), + 'cHash' => $this->getHash(), ]; } - $this->locale = self::getLocale($_SESSION['cISOSprache'], Session::getInstance()->Customer()->cLand); + $this->locale = self::getLocale($_SESSION['cISOSprache'], Session::getInstance()->Customer()->cLand); $this->webhookUrl = Shop::getURL(true) . '/?' . http_build_query([ 'mollie' => 1, - 'hash' => $this->getHash(), - 'test' => $this->API()->isTest() ?: null, + 'hash' => $this->getHash(), + 'test' => $this->API()->isTest() ?: null, ]); - $pm = $this->PaymentMethod(); + $pm = $this->PaymentMethod(); $isPayAgain = strpos($_SERVER['PHP_SELF'], 'bestellab_again') !== false; if ($pm::METHOD !== '' && (self::Plugin()->oPluginEinstellungAssoc_arr['resetMethod'] !== 'Y' || !$isPayAgain)) { $this->method = $pm::METHOD; } - } /** - * @return \Mollie\Api\Resources\Customer|null * @todo: Kunde wieder löschbar machen ?! + * @param mixed $createOrUpdate + * @param null|mixed $oKunde + * @return null|\Mollie\Api\Resources\Customer */ public function getCustomer($createOrUpdate = false, $oKunde = null) { - if (!$oKunde) { $oKunde = $this->getBestellung()->oKunde; } @@ -877,27 +896,27 @@ public function getCustomer($createOrUpdate = false, $oKunde = null) try { $this->customer = $this->API()->Client()->customers->get($customerModel->customerId); } catch (ApiException $e) { - $this->Log(sprintf("Fehler beim laden des Mollie Customers %s (kKunde: %d): %s", $customerModel->customerId, $customerModel->kKunde, $e->getMessage()), LOGLEVEL_ERROR); + $this->Log(sprintf('Fehler beim laden des Mollie Customers %s (kKunde: %d): %s', $customerModel->customerId, $customerModel->kKunde, $e->getMessage()), LOGLEVEL_ERROR); } } if ($createOrUpdate) { $customer = [ - 'name' => utf8_encode(trim($oKunde->cVorname . ' ' . $oKunde->cNachname)), - 'email' => utf8_encode($oKunde->cMail), - 'locale' => self::getLocale($_SESSION['cISOSprache'], $oKunde->cLand), + 'name' => utf8_encode(trim($oKunde->cVorname . ' ' . $oKunde->cNachname)), + 'email' => utf8_encode($oKunde->cMail), + 'locale' => self::getLocale($_SESSION['cISOSprache'], $oKunde->cLand), 'metadata' => (object)[ - 'kKunde' => $oKunde->kKunde, + 'kKunde' => $oKunde->kKunde, 'kKundengruppe' => $oKunde->kKundengruppe, - 'cKundenNr' => utf8_encode($oKunde->cKundenNr), + 'cKundenNr' => utf8_encode($oKunde->cKundenNr), ], ]; if ($this->customer) { // UPDATE - $this->customer->name = $customer['name']; - $this->customer->email = $customer['email']; - $this->customer->locale = $customer['locale']; + $this->customer->name = $customer['name']; + $this->customer->email = $customer['email']; + $this->customer->locale = $customer['locale']; $this->customer->metadata = $customer['metadata']; try { @@ -905,13 +924,11 @@ public function getCustomer($createOrUpdate = false, $oKunde = null) } catch (Exception $e) { $this->Log(sprintf("Fehler beim aktualisieren des Mollie Customers %s: %s\n%s", $this->customer->id, $e->getMessage(), print_r($customer, 1)), LOGLEVEL_ERROR); } - - } else { // create try { - $this->customer = $this->API()->Client()->customers->create($customer); - $customerModel->kKunde = $oKunde->kKunde; + $this->customer = $this->API()->Client()->customers->create($customer); + $customerModel->kKunde = $oKunde->kKunde; $customerModel->customerId = $this->customer->id; $customerModel->save(); $this->Log(sprintf("Customer '%s' für Kunde %s (%d) bei Mollie angelegt.", $this->customer->id, $this->customer->name, $this->getBestellung()->kKunde)); @@ -921,6 +938,7 @@ public function getCustomer($createOrUpdate = false, $oKunde = null) } } } + return $this->customer; } @@ -930,10 +948,9 @@ public function getCustomer($createOrUpdate = false, $oKunde = null) public function storno() { if (in_array((int)$this->getBestellung()->cStatus, [BESTELLUNG_STATUS_OFFEN, BESTELLUNG_STATUS_IN_BEARBEITUNG], true)) { - $log = []; - $conf = Shop::getSettings([CONF_GLOBAL, CONF_TRUSTEDSHOPS]); + $conf = Shop::getSettings([CONF_GLOBAL, CONF_TRUSTEDSHOPS]); $nArtikelAnzeigefilter = (int)$conf['global']['artikel_artikelanzeigefilter']; foreach ($this->getBestellung()->Positionen as $pos) { @@ -955,9 +972,7 @@ protected static function aktualisiereLagerbestand($Artikel, $nAnzahl, $Warenkor $artikelBestand = (float)$Artikel->fLagerbestand; if (isset($Artikel->cLagerBeachten) && $Artikel->cLagerBeachten === 'Y') { - if ($Artikel->cLagerVariation === 'Y' && - is_array($WarenkorbPosEigenschaftArr) && - count($WarenkorbPosEigenschaftArr) > 0 + if ($Artikel->cLagerVariation === 'Y' && is_array($WarenkorbPosEigenschaftArr) && count($WarenkorbPosEigenschaftArr) > 0 ) { foreach ($WarenkorbPosEigenschaftArr as $eWert) { $EigenschaftWert = new EigenschaftWert($eWert->kEigenschaftWert); @@ -965,9 +980,10 @@ protected static function aktualisiereLagerbestand($Artikel, $nAnzahl, $Warenkor $EigenschaftWert->fPackeinheit = 1; } Shop::DB()->query( - "UPDATE teigenschaftwert - SET fLagerbestand = fLagerbestand - " . ($nAnzahl * $EigenschaftWert->fPackeinheit) . " - WHERE kEigenschaftWert = " . (int)$eWert->kEigenschaftWert, 4 + 'UPDATE teigenschaftwert + SET fLagerbestand = fLagerbestand - ' . ($nAnzahl * $EigenschaftWert->fPackeinheit) . ' + WHERE kEigenschaftWert = ' . (int)$eWert->kEigenschaftWert, + 4 ); } } elseif ($Artikel->fPackeinheit > 0) { @@ -976,10 +992,11 @@ protected static function aktualisiereLagerbestand($Artikel, $nAnzahl, $Warenkor $artikelBestand = self::aktualisiereStuecklistenLagerbestand($Artikel, $nAnzahl); } else { Shop::DB()->query( - "UPDATE tartikel - SET fLagerbestand = IF (fLagerbestand >= " . ($nAnzahl * $Artikel->fPackeinheit) . ", - (fLagerbestand - " . ($nAnzahl * $Artikel->fPackeinheit) . "), fLagerbestand) - WHERE kArtikel = " . (int)$Artikel->kArtikel, 4 + 'UPDATE tartikel + SET fLagerbestand = IF (fLagerbestand >= ' . ($nAnzahl * $Artikel->fPackeinheit) . ', + (fLagerbestand - ' . ($nAnzahl * $Artikel->fPackeinheit) . '), fLagerbestand) + WHERE kArtikel = ' . (int)$Artikel->kArtikel, + 4 ); $tmpArtikel = Shop::DB()->select('tartikel', 'kArtikel', (int)$Artikel->kArtikel, null, null, null, null, false, 'fLagerbestand'); if ($tmpArtikel !== null) { @@ -1002,10 +1019,10 @@ protected static function aktualisiereLagerbestand($Artikel, $nAnzahl, $Warenkor protected static function aktualisiereStuecklistenLagerbestand($oStueckListeArtikel, $nAnzahl) { - $nAnzahl = (float)$nAnzahl; - $kStueckListe = (int)$oStueckListeArtikel->kStueckliste; - $bestandAlt = (float)$oStueckListeArtikel->fLagerbestand; - $bestandNeu = $bestandAlt; + $nAnzahl = (float)$nAnzahl; + $kStueckListe = (int)$oStueckListeArtikel->kStueckliste; + $bestandAlt = (float)$oStueckListeArtikel->fLagerbestand; + $bestandNeu = $bestandAlt; $bestandUeberverkauf = $bestandAlt; if ($nAnzahl > 0) { @@ -1016,7 +1033,8 @@ protected static function aktualisiereStuecklistenLagerbestand($oStueckListeArti JOIN tartikel ON tartikel.kArtikel = tstueckliste.kArtikel WHERE tstueckliste.kStueckliste = $kStueckListe - AND tartikel.cLagerBeachten = 'Y'", 2 + AND tartikel.cLagerBeachten = 'Y'", + 2 ); if (is_array($oKomponente_arr) && count($oKomponente_arr) > 0) { @@ -1068,7 +1086,7 @@ protected static function aktualisiereStuecklistenLagerbestand($oStueckListeArti protected static function aktualisiereKomponenteLagerbestand($kKomponenteArtikel, $fLagerbestand, $bLagerKleinerNull) { $kKomponenteArtikel = (int)$kKomponenteArtikel; - $fLagerbestand = (float)$fLagerbestand; + $fLagerbestand = (float)$fLagerbestand; $oStueckliste_arr = Shop::DB()->query( "SELECT tstueckliste.kStueckliste, tstueckliste.fAnzahl, @@ -1077,7 +1095,8 @@ protected static function aktualisiereKomponenteLagerbestand($kKomponenteArtikel JOIN tartikel ON tartikel.kStueckliste = tstueckliste.kStueckliste WHERE tstueckliste.kArtikel = $kKomponenteArtikel - AND tartikel.cLagerBeachten = 'Y'", 2 + AND tartikel.cLagerBeachten = 'Y'", + 2 ); if (is_array($oStueckliste_arr) && count($oStueckliste_arr) > 0) { @@ -1096,14 +1115,14 @@ protected static function aktualisiereKomponenteLagerbestand($kKomponenteArtikel } /** - * @return array|bool|int|object|null + * @return null|array|bool|int|object */ public function getLogs() { - return Shop::DB()->executeQueryPrepared("SELECT * FROM tzahlungslog WHERE cLogData LIKE :kBestellung OR cLogData LIKE :cBestellNr OR cLogData LIKE :MollieID ORDER BY dDatum DESC, cLog DESC", [ + return 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' => '%#' . ($this->getBestellung()->kBestellung ?: '##') . '%', - ':cBestellNr' => '%§' . ($this->getBestellung()->cBestellNr ?: '§§') . '%', - ':MollieID' => '%$' . ($this->getMollie()->id ?: '$$') . '%', + ':cBestellNr' => '%§' . ($this->getBestellung()->cBestellNr ?: '§§') . '%', + ':MollieID' => '%$' . ($this->getMollie()->id ?: '$$') . '%', ], 2); } @@ -1120,7 +1139,6 @@ public function remindable() */ public function LogData() { - $data = ''; if ($this->getBestellung()->kBestellung) { $data .= '#' . $this->getBestellung()->kBestellung; @@ -1136,7 +1154,7 @@ abstract public function cancelOrRefund($force = false); /** * @param array $paymentOptions - * @return Payment|Order + * @return Order|Payment */ abstract public function create(array $paymentOptions = []); @@ -1150,8 +1168,9 @@ public function getRepayURL() public function getDescription() { - $descTemplate = trim(Helper::getSetting('paymentDescTpl')) ?: "Order {orderNumber}"; - $oKunde = $this->getBestellung()->oKunde ?: $_SESSION['Kunde']; + $descTemplate = trim(Helper::getSetting('paymentDescTpl')) ?: 'Order {orderNumber}'; + $oKunde = $this->getBestellung()->oKunde ?: $_SESSION['Kunde']; + return str_replace([ '{orderNumber}', '{storeName}', @@ -1177,12 +1196,13 @@ abstract protected function updateOrderNumber(); protected function setBestellung(Bestellung $oBestellung) { $this->oBestellung = $oBestellung; + return $this; } /** - * @param Order|\Mollie\Api\Resources\Payment $model + * @param \Mollie\Api\Resources\Payment|Order $model * @return self */ abstract protected function setMollie($model); -} \ No newline at end of file +} diff --git a/version/205/class/Checkout/AbstractResource.php b/version/205/class/Checkout/AbstractResource.php index 7ca9813..c49adb7 100644 --- a/version/205/class/Checkout/AbstractResource.php +++ b/version/205/class/Checkout/AbstractResource.php @@ -1,9 +1,11 @@ title = trim(($address->cAnrede === 'm' ? Shop::Lang()->get('mr') : Shop::Lang()->get('mrs')) . ' ' . $address->cTitel) ?: null; - $resource->givenName = $address->cVorname; + $resource->title = trim(($address->cAnrede === 'm' ? Shop::Lang()->get('mr') : Shop::Lang()->get('mrs')) . ' ' . $address->cTitel) ?: null; + $resource->givenName = $address->cVorname; $resource->familyName = $address->cNachname; - $resource->email = $address->cMail ?: null; + $resource->email = $address->cMail ?: null; if ($organizationName = trim($address->cFirma)) { $resource->organizationName = $organizationName; @@ -38,7 +41,7 @@ public static function factory($address) if (!$resource->givenName || !$resource->familyName || !$resource->email) { throw ResourceValidityException::trigger(ResourceValidityException::ERROR_REQUIRED, ['givenName', 'familyName', 'email'], $resource); } + return $resource; } - -} \ No newline at end of file +} diff --git a/version/205/class/Checkout/Order/OrderLine.php b/version/205/class/Checkout/Order/OrderLine.php index 1c88bb1..8f1eedd 100644 --- a/version/205/class/Checkout/Order/OrderLine.php +++ b/version/205/class/Checkout/Order/OrderLine.php @@ -1,9 +1,11 @@ value) > 0) { $diff = (round((float)$amount->value - $sum, 2)); if ($diff !== 0.0) { - $line = new self(); + $line = new self(); $line->type = $diff > 0 ? OrderLineType::TYPE_SURCHARGE : OrderLineType::TYPE_DISCOUNT; // TODO: Translation needed? - $line->name = 'Rundungsausgleich'; - $line->quantity = 1; - $line->unitPrice = Amount::factory($diff, $currency); + $line->name = 'Rundungsausgleich'; + $line->quantity = 1; + $line->unitPrice = Amount::factory($diff, $currency); $line->totalAmount = Amount::factory($diff, $currency); - $line->vatRate = "0.00"; - $line->vatAmount = Amount::factory(0, $currency); + $line->vatRate = '0.00'; + $line->vatAmount = Amount::factory(0, $currency); + return $line; } } + return null; } @@ -73,22 +75,22 @@ public static function getRoundingCompensation(array $orderLines, Amount $amount */ public static function getCredit(Bestellung $oBestellung) { - $line = new self(); - $line->type = OrderLineType::TYPE_STORE_CREDIT; - $line->name = 'Guthaben'; + $line = new self(); + $line->type = OrderLineType::TYPE_STORE_CREDIT; + $line->name = 'Guthaben'; $line->quantity = 1; // TODO: check currency of Guthaben - $line->unitPrice = Amount::factory($oBestellung->fGuthaben, $oBestellung->Waehrung->cISO); + $line->unitPrice = Amount::factory($oBestellung->fGuthaben, $oBestellung->Waehrung->cISO); $line->totalAmount = $line->unitPrice; - $line->vatRate = "0.00"; - $line->vatAmount = Amount::factory(0, $oBestellung->Waehrung->cISO); + $line->vatRate = '0.00'; + $line->vatAmount = Amount::factory(0, $oBestellung->Waehrung->cISO); return $line; } /** * @param stdClass|WarenkorbPos $oPosition - * @param null $currency + * @param null $currency * @return OrderLine */ public static function factory($oPosition, $currency = null) @@ -104,40 +106,41 @@ public static function factory($oPosition, $currency = null) // Validity Check if (!$resource->name || !$resource->quantity || !$resource->unitPrice || !$resource->totalAmount || !$resource->vatRate || !$resource->vatAmount) { - throw ResourceValidityException::trigger(ResourceValidityException::ERROR_REQUIRED, - ['name', 'quantity', 'unitPrice', 'totalAmount', 'vatRate', 'vatAmount'], $resource); + throw ResourceValidityException::trigger( + ResourceValidityException::ERROR_REQUIRED, + ['name', 'quantity', 'unitPrice', 'totalAmount', 'vatRate', 'vatAmount'], + $resource + ); } return $resource; - } /** - * @param WarenkorbPos|stdClass $oPosition - * @param null|stdClass $currency + * @param stdClass|WarenkorbPos $oPosition + * @param null|stdClass $currency * @return $this * @todo Setting for Fraction handling needed? */ protected function fill($oPosition, $currency = null) { - if (!$currency) { $currency = Amount::FallbackCurrency(); } $isKupon = (int)$oPosition->nPosTyp === (int)C_WARENKORBPOS_TYP_KUPON; - $isFrac = fmod($oPosition->nAnzahl, 1) !== 0.0; + $isFrac = fmod($oPosition->nAnzahl, 1) !== 0.0; // Kupon? set vatRate to 0 and adjust netto $vatRate = $isKupon ? 0 : (float)$oPosition->fMwSt / 100; - $netto = $isKupon ? round($oPosition->fPreis * (1 + $vatRate), 4) : round($oPosition->fPreis, 4); + $netto = $isKupon ? round($oPosition->fPreis * (1 + $vatRate), 4) : round($oPosition->fPreis, 4); // Fraction? transform, as it were 1, and set quantity to 1 - $netto = round(($isFrac ? $netto * (float)$oPosition->nAnzahl : $netto) * $currency->fFaktor, 4); + $netto = round(($isFrac ? $netto * (float)$oPosition->nAnzahl : $netto) * $currency->fFaktor, 4); $this->quantity = $isFrac ? 1 : (int)$oPosition->nAnzahl; // Fraction? include quantity and unit in name - $this->name = $isFrac ? sprintf("%s (%.2f %s)", $oPosition->cName, (float)$oPosition->nAnzahl, $oPosition->cEinheit) : $oPosition->cName; + $this->name = $isFrac ? sprintf('%s (%.2f %s)', $oPosition->cName, (float)$oPosition->nAnzahl, $oPosition->cEinheit) : $oPosition->cName; if (!$this->name) { $this->name = '(null)'; } @@ -145,17 +148,17 @@ protected function fill($oPosition, $currency = null) //$unitPriceNetto = round(($currency->fFaktor * $netto), 4); - $this->unitPrice = Amount::factory(round($netto * (1 + $vatRate), 2), $currency->cISO, false); + $this->unitPrice = Amount::factory(round($netto * (1 + $vatRate), 2), $currency->cISO, false); $this->totalAmount = Amount::factory(round($this->quantity * $this->unitPrice->value, 2), $currency->cISO, false); - $this->vatRate = number_format($vatRate * 100, 2); + $this->vatRate = number_format($vatRate * 100, 2); $this->vatAmount = Amount::factory(round($this->totalAmount->value - ($this->totalAmount->value / (1 + $vatRate)), 2), $currency->cISO, false); $metadata = []; // Is Artikel ? if (isset($oPosition->Artikel)) { - $this->sku = $oPosition->Artikel->cArtNr; + $this->sku = $oPosition->Artikel->cArtNr; $metadata['kArtikel'] = $oPosition->kArtikel; if ($oPosition->cUnique !== '') { $metadata['cUnique'] = utf8_encode($oPosition->cUnique); @@ -167,25 +170,23 @@ protected function fill($oPosition, $currency = null) /** @var WarenkorbPosEigenschaft $warenkorbPosEigenschaft */ foreach ($oPosition->WarenkorbPosEigenschaftArr as $warenkorbPosEigenschaft) { $metadata['properties'][] = [ - 'kEigenschaft' => $warenkorbPosEigenschaft->kEigenschaft, + 'kEigenschaft' => $warenkorbPosEigenschaft->kEigenschaft, 'kEigenschaftWert' => $warenkorbPosEigenschaft->kEigenschaftWert, - 'name' => utf8_encode($warenkorbPosEigenschaft->cEigenschaftName), - 'value' => utf8_encode($warenkorbPosEigenschaft->cEigenschaftWertName), + 'name' => utf8_encode($warenkorbPosEigenschaft->cEigenschaftName), + 'value' => utf8_encode($warenkorbPosEigenschaft->cEigenschaftWertName), ]; if (strlen(json_encode($metadata)) > 1000) { array_pop($metadata['properties']); + break; } } - } if (json_encode($metadata) !== false) { $this->metadata = $metadata; } return $this; - - } /** @@ -200,16 +201,19 @@ protected function mapType($nPosTyp, $positive) case C_WARENKORBPOS_TYP_GRATISGESCHENK: // TODO: digital / Download Artikel? $this->type = OrderLineType::TYPE_PHYSICAL; + return $this; case C_WARENKORBPOS_TYP_VERSANDPOS: $this->type = OrderLineType::TYPE_SHIPPING_FEE; + return $this; case C_WARENKORBPOS_TYP_GUTSCHEIN: case C_WARENKORBPOS_TYP_KUPON: case C_WARENKORBPOS_TYP_NEUKUNDENKUPON: $this->type = OrderLineType::TYPE_DISCOUNT; + return $this; case C_WARENKORBPOS_TYP_VERPACKUNG: @@ -218,13 +222,14 @@ protected function mapType($nPosTyp, $positive) case C_WARENKORBPOS_TYP_VERSAND_ARTIKELABHAENGIG: case C_WARENKORBPOS_TYP_NACHNAHMEGEBUEHR: $this->type = OrderLineType::TYPE_SURCHARGE; + return $this; default: $this->type = $positive ? OrderLineType::TYPE_SURCHARGE : OrderLineType::TYPE_DISCOUNT; + return $this; } } - -} \ No newline at end of file +} diff --git a/version/205/class/Checkout/OrderCheckout.php b/version/205/class/Checkout/OrderCheckout.php index c6b961e..288d29f 100644 --- a/version/205/class/Checkout/OrderCheckout.php +++ b/version/205/class/Checkout/OrderCheckout.php @@ -1,9 +1,11 @@ getMollie()->status !== OrderStatus::STATUS_AUTHORIZED && $checkout->getMollie()->status !== OrderStatus::STATUS_SHIPPING) { throw new RuntimeException('Nur autorisierte Zahlungen können erfasst werden!'); } $shipment = $checkout->API()->Client()->shipments->createFor($checkout->getMollie(), ['lines' => []]); $checkout->Log(sprintf('Bestellung wurde manuell erfasst/versandt: %s', $shipment->id)); + return $shipment->id; } /** * @param false $force - * @return Order|null + * @return null|Order */ public function getMollie($force = false) { @@ -82,13 +84,14 @@ public function getMollie($force = false) throw new RuntimeException(sprintf('Mollie-Order \'%s\' konnte nicht geladen werden: %s', $this->getModel()->kID, $e->getMessage())); } } + return $this->order; } /** * @param OrderCheckout $checkout - * @return Order * @throws ApiException + * @return Order */ public static function cancel($checkout) { @@ -97,29 +100,32 @@ public static function cancel($checkout) } $order = $checkout->getMollie()->cancel(); $checkout->Log('Bestellung wurde manuell abgebrochen.'); + return $order; } /** - * @return array * @throws Exception + * @return array */ public function getShipments() { - $shipments = []; - $lieferschien_arr = Shop::DB()->executeQueryPrepared("SELECT kLieferschein FROM tlieferschein WHERE kInetBestellung = :kBestellung", [ + $shipments = []; + $lieferschien_arr = Shop::DB()->executeQueryPrepared('SELECT kLieferschein FROM tlieferschein WHERE kInetBestellung = :kBestellung', [ ':kBestellung' => $this->getBestellung()->kBestellung ], 2); foreach ($lieferschien_arr as $lieferschein) { $shipments[] = new Shipment($lieferschein->kLieferschein, $this); } + return $shipments; } /** - * @return string + * @param mixed $force * @throws ApiException + * @return string */ public function cancelOrRefund($force = false) { @@ -128,15 +134,17 @@ public function cancelOrRefund($force = false) } if ($force || (int)$this->getBestellung()->cStatus === BESTELLUNG_STATUS_STORNO) { if ($this->getMollie()->isCancelable) { - $res = $this->getMollie()->cancel(); + $res = $this->getMollie()->cancel(); $result = 'Order cancelled, Status: ' . $res->status; } else { - $res = $this->getMollie()->refundAll(); - $result = "Order Refund initiiert, Status: " . $res->status; + $res = $this->getMollie()->refundAll(); + $result = 'Order Refund initiiert, Status: ' . $res->status; } - $this->PaymentMethod()->Log("OrderCheckout::cancelOrRefund: " . $result, $this->LogData()); + $this->PaymentMethod()->Log('OrderCheckout::cancelOrRefund: ' . $result, $this->LogData()); + return $result; } + throw new RuntimeException('Bestellung ist derzeit nicht storniert, Status: ' . $this->getBestellung()->cStatus); } @@ -151,6 +159,7 @@ public function create(array $paymentOptions = []) $this->order = $this->API()->Client()->orders->get($this->getModel()->kID, ['embed' => 'payments']); if (in_array($this->order->status, [OrderStatus::STATUS_COMPLETED, OrderStatus::STATUS_PAID, OrderStatus::STATUS_AUTHORIZED, OrderStatus::STATUS_PENDING], true)) { $this->handleNotification(); + throw new RuntimeException(self::Plugin()->oPluginSprachvariableAssoc_arr['errAlreadyPaid']); } if ($this->order->status === OrderStatus::STATUS_CREATED) { @@ -159,6 +168,7 @@ public function create(array $paymentOptions = []) foreach ($this->order->payments() as $payment) { if ($payment->status === PaymentStatus::STATUS_OPEN) { $this->setPayment($payment); + break; } } @@ -167,6 +177,7 @@ public function create(array $paymentOptions = []) $this->setPayment($this->API()->Client()->orderPayments->createForId($this->getModel()->kID, $paymentOptions)); } $this->updateModel()->saveModel(); + return $this->getMollie(true); } } catch (RuntimeException $e) { @@ -177,19 +188,22 @@ public function create(array $paymentOptions = []) } try { - $req = $this->loadRequest($paymentOptions)->jsonSerialize(); + $req = $this->loadRequest($paymentOptions)->jsonSerialize(); $this->order = $this->API()->Client()->orders->create($req); $this->Log(sprintf("Order für '%s' wurde erfolgreich angelegt: %s", $this->getBestellung()->cBestellNr, $this->order->id)); $this->updateModel()->saveModel(); + return $this->order; } catch (Exception $e) { $this->Log(sprintf("OrderCheckout::create: Neue Order '%s' konnte nicht erstellt werden: %s.", $this->getBestellung()->cBestellNr, $e->getMessage()), LOGLEVEL_ERROR); + throw new RuntimeException(sprintf("Order für '%s' konnte nicht angelegt werden: %s", $this->getBestellung()->cBestellNr, $e->getMessage())); } } /** - * @return Payment|null + * @param mixed $search + * @return null|Payment */ public function getPayment($search = false) { @@ -201,10 +215,12 @@ public function getPayment($search = false) PaymentStatus::STATUS_PENDING, ], true)) { $this->_payment = $payment; + break; } } } + return $this->_payment; } @@ -215,6 +231,7 @@ public function getPayment($search = false) public function setPayment($payment) { $this->_payment = $payment; + return $this; } @@ -230,6 +247,7 @@ public function updateModel() foreach ($this->getMollie()->payments() as $payment) { if (in_array($payment->status, [PaymentStatus::STATUS_OPEN, PaymentStatus::STATUS_PENDING, PaymentStatus::STATUS_AUTHORIZED, PaymentStatus::STATUS_PAID], true)) { $this->setPayment($payment); + break; } } @@ -239,9 +257,10 @@ public function updateModel() } if ($this->getMollie()) { $this->getModel()->cCheckoutURL = $this->getMollie()->getCheckoutUrl(); - $this->getModel()->cWebhookURL = $this->getMollie()->webhookUrl; + $this->getModel()->cWebhookURL = $this->getMollie()->webhookUrl; $this->getModel()->cRedirectURL = $this->getMollie()->redirectUrl; } + return $this; } @@ -251,7 +270,6 @@ public function updateModel() */ public function loadRequest(&$options = []) { - parent::loadRequest($options); $this->orderNumber = $this->getBestellung()->cBestellNr; @@ -290,7 +308,7 @@ public function loadRequest(&$options = []) try { // #145 //$max = $this->method && strpos($this->method, 'klarna') !== false ? 28 : 100; - $date = new DateTime(sprintf("+%d DAYS", $dueDays), new DateTimeZone('UTC')); + $date = new DateTime(sprintf('+%d DAYS', $dueDays), new DateTimeZone('UTC')); $this->expiresAt = $date->format('Y-m-d'); } catch (Exception $e) { $this->Log($e->getMessage(), LOGLEVEL_ERROR); @@ -303,7 +321,7 @@ public function loadRequest(&$options = []) } /** - * @return object|null + * @return null|object */ public function getIncomingPayment() { @@ -311,10 +329,10 @@ public function getIncomingPayment() return null; } - $cHinweis = sprintf("%s / %s", $this->getMollie()->id, $this->getPayment(true)->id); + $cHinweis = sprintf('%s / %s', $this->getMollie()->id, $this->getPayment(true)->id); if (Helper::getSetting('wawiPaymentID') === 'ord') { $cHinweis = $this->getMollie()->id; - } else if (Helper::getSetting('wawiPaymentID') === 'tr') { + } elseif (Helper::getSetting('wawiPaymentID') === 'tr') { $cHinweis = $this->getPayment(true)->id; } @@ -322,21 +340,26 @@ public function getIncomingPayment() /** @var Payment $payment */ /** @noinspection NullPointerExceptionInspection */ foreach ($this->getMollie()->payments() as $payment) { - if (in_array($payment->status, - [PaymentStatus::STATUS_AUTHORIZED, PaymentStatus::STATUS_PAID], true)) { + if (in_array( + $payment->status, + [PaymentStatus::STATUS_AUTHORIZED, PaymentStatus::STATUS_PAID], + true + )) { $this->setPayment($payment); $data = (object)[ - 'fBetrag' => (float)$payment->amount->value, - 'cISO' => $payment->amount->currency, - 'cZahler' => $payment->details->paypalPayerId ?: $payment->customerId, + 'fBetrag' => (float)$payment->amount->value, + 'cISO' => $payment->amount->currency, + 'cZahler' => $payment->details->paypalPayerId ?: $payment->customerId, 'cHinweis' => $payment->details->paypalReference ?: $cHinweis, ]; if (isset($payment->details, $payment->details->paypalFee)) { $data->fZahlungsgebuehr = $payment->details->paypalFee->value; } + return $data; } } + return null; } @@ -348,7 +371,7 @@ protected function updateOrderNumber() try { if ($this->getMollie()) { $this->getMollie()->orderNumber = $this->getBestellung()->cBestellNr; - $this->getMollie()->webhookUrl = Shop::getURL() . '/?mollie=1'; + $this->getMollie()->webhookUrl = Shop::getURL() . '/?mollie=1'; $this->getMollie()->update(); } if ($this->getModel()->cTransactionId) { @@ -356,10 +379,10 @@ protected function updateOrderNumber() 'description' => $this->getDescription() ]); } - } catch (Exception $e) { $this->Log('OrderCheckout::updateOrderNumber:' . $e->getMessage(), LOGLEVEL_ERROR); } + return $this; } @@ -372,6 +395,7 @@ protected function setMollie($model) if ($model instanceof Order) { $this->order = $model; } + return $this; } -} \ No newline at end of file +} diff --git a/version/205/class/Checkout/Payment/Address.php b/version/205/class/Checkout/Payment/Address.php index ea460c1..c23e53e 100644 --- a/version/205/class/Checkout/Payment/Address.php +++ b/version/205/class/Checkout/Payment/Address.php @@ -1,11 +1,13 @@ streetAndNumber = $address->cStrasse . ' ' . $address->cHausnummer; - $resource->postalCode = $address->cPLZ; - $resource->city = $address->cOrt; - $resource->country = $address->cLand; + $resource->postalCode = $address->cPLZ; + $resource->city = $address->cOrt; + $resource->country = $address->cLand; if ( isset($address->cAdressZusatz) @@ -49,6 +49,4 @@ public static function factory($address) return $resource; } - - -} \ No newline at end of file +} diff --git a/version/205/class/Checkout/Payment/Amount.php b/version/205/class/Checkout/Payment/Amount.php index 125829d..ba86c72 100644 --- a/version/205/class/Checkout/Payment/Amount.php +++ b/version/205/class/Checkout/Payment/Amount.php @@ -1,5 +1,8 @@ true [5 Rappen Rounding]) + * @param false $useRounding (is it total SUM => true [5 Rappen Rounding]) * @return Amount */ public static function factory($value, $currency = null, $useRounding = false) { - if (!$currency) { $currency = static::FallbackCurrency()->cISO; } @@ -43,6 +44,7 @@ public static function factory($value, $currency = null, $useRounding = false) if (!$resource->currency || !$resource->value) { throw ResourceValidityException::trigger(ResourceValidityException::ERROR_REQUIRED, ['currency', 'value'], $resource); } + return $resource; } @@ -57,17 +59,16 @@ public static function FallbackCurrency() /** * Check if 5 Rappen rounding is necessary * + * @param mixed $value * @return float */ protected function round($value) { - $conf = Shop::getSettings([CONF_KAUFABWICKLUNG]); if (isset($conf['kaufabwicklung']['bestellabschluss_runden5']) && (int)$conf['kaufabwicklung']['bestellabschluss_runden5'] === 1) { $value = round($value * 20) / 20; } + return $value; } - - -} \ No newline at end of file +} diff --git a/version/205/class/Checkout/PaymentCheckout.php b/version/205/class/Checkout/PaymentCheckout.php index e5aa786..17c4d8f 100644 --- a/version/205/class/Checkout/PaymentCheckout.php +++ b/version/205/class/Checkout/PaymentCheckout.php @@ -1,9 +1,11 @@ API()->Client()->payments->cancel($checkout->getMollie()->id); $checkout->Log('Zahlung wurde manuell abgebrochen.'); + return $payment; } /** * @param false $force - * @return Payment|null + * @return null|Payment */ public function getMollie($force = false) { @@ -66,11 +67,12 @@ public function getMollie($force = false) throw new RuntimeException('Mollie-Payment konnte nicht geladen werden: ' . $e->getMessage()); } } + return $this->getPayment(); } /** - * @return Payment|null + * @return null|Payment */ public function getPayment() { @@ -84,13 +86,15 @@ public function getPayment() public function setPayment($payment) { $this->_payment = $payment; + return $this; } /** - * @return string + * @param mixed $force * @throws ApiException * @throws IncompatiblePlatform + * @return string */ public function cancelOrRefund($force = false) { @@ -99,15 +103,17 @@ public function cancelOrRefund($force = false) } if ($force || (int)$this->getBestellung()->cStatus === BESTELLUNG_STATUS_STORNO) { if ($this->getMollie()->isCancelable) { - $res = $this->API()->Client()->payments->cancel($this->getMollie()->id); + $res = $this->API()->Client()->payments->cancel($this->getMollie()->id); $result = 'Payment cancelled, Status: ' . $res->status; } else { - $res = $this->API()->Client()->payments->refund($this->getMollie(), ['amount' => $this->getMollie()->amount]); - $result = "Payment Refund initiiert, Status: " . $res->status; + $res = $this->API()->Client()->payments->refund($this->getMollie(), ['amount' => $this->getMollie()->amount]); + $result = 'Payment Refund initiiert, Status: ' . $res->status; } - $this->PaymentMethod()->Log("PaymentCheckout::cancelOrRefund: " . $result, $this->LogData()); + $this->PaymentMethod()->Log('PaymentCheckout::cancelOrRefund: ' . $result, $this->LogData()); + return $result; } + throw new RuntimeException('Bestellung ist derzeit nicht storniert, Status: ' . $this->getBestellung()->cStatus); } @@ -125,6 +131,7 @@ public function create(array $paymentOptions = []) } if ($this->getPayment()->status === PaymentStatus::STATUS_OPEN) { $this->updateModel()->saveModel(); + return $this->getPayment(); } } catch (RuntimeException $e) { @@ -140,9 +147,11 @@ public function create(array $paymentOptions = []) $this->setPayment($this->API()->Client()->payments->create($req)); $this->Log(sprintf("Payment für '%s' wurde erfolgreich angelegt: %s", $this->getBestellung()->cBestellNr, $this->getPayment()->id)); $this->updateModel()->saveModel(); + return $this->getPayment(); } catch (Exception $e) { $this->Log(sprintf("PaymentCheckout::create: Neue Transaktion für '%s' konnte nicht erstellt werden: %s.", $this->getBestellung()->cBestellNr, $e->getMessage()), LOGLEVEL_ERROR); + throw new RuntimeException(sprintf('Mollie-Payment \'%s\' konnte nicht geladen werden: %s', $this->getBestellung()->cBestellNr, $e->getMessage())); } } @@ -153,7 +162,6 @@ public function create(array $paymentOptions = []) */ public function loadRequest(&$options = []) { - parent::loadRequest($options); foreach ($options as $key => $value) { @@ -169,7 +177,7 @@ public function loadRequest(&$options = []) /** - * @return object|null + * @return null|object */ public function getIncomingPayment() { @@ -178,16 +186,18 @@ public function getIncomingPayment() } if (in_array($this->getMollie()->status, [PaymentStatus::STATUS_AUTHORIZED, PaymentStatus::STATUS_PAID], true)) { - $data = []; - $data['fBetrag'] = (float)$this->getMollie()->amount->value; - $data['cISO'] = $this->getMollie()->amount->currency; - $data['cZahler'] = $this->getMollie()->details->paypalPayerId ?: $this->getMollie()->customerId; + $data = []; + $data['fBetrag'] = (float)$this->getMollie()->amount->value; + $data['cISO'] = $this->getMollie()->amount->currency; + $data['cZahler'] = $this->getMollie()->details->paypalPayerId ?: $this->getMollie()->customerId; $data['cHinweis'] = $this->getMollie()->details->paypalReference ?: $this->getMollie()->id; if (isset($this->getMollie()->details, $this->getMollie()->details->paypalFee)) { $data['fZahlungsgebuehr'] = $this->getMollie()->details->paypalFee->value; } + return (object)$data; } + return null; } @@ -200,6 +210,7 @@ protected function setMollie($model) if ($model instanceof Payment) { $this->setPayment($model); } + return $this; } @@ -211,13 +222,13 @@ protected function updateOrderNumber() try { if ($this->getMollie()) { $this->getMollie()->description = $this->getDescription(); - $this->getMollie()->webhookUrl = Shop::getURL() . '/?mollie=1'; + $this->getMollie()->webhookUrl = Shop::getURL() . '/?mollie=1'; $this->getMollie()->update(); } } catch (Exception $e) { $this->Log('OrderCheckout::updateOrderNumber:' . $e->getMessage(), LOGLEVEL_ERROR); } + return $this; } - -} \ No newline at end of file +} diff --git a/version/205/class/ExclusiveLock.php b/version/205/class/ExclusiveLock.php index f3d3d95..d897e29 100644 --- a/version/205/class/ExclusiveLock.php +++ b/version/205/class/ExclusiveLock.php @@ -1,21 +1,23 @@ key = $key; + $this->key = $key; $this->path = rtrim(realpath($path), '/') . '/'; if (!is_dir($path) || !is_writable($path)) { throw new RuntimeException("Lock Path '$path' doesn't exist, or is not writable!"); @@ -39,14 +41,16 @@ public function unlock() if ($this->own === true) { if (!flock($this->file, LOCK_UN)) { //failed error_log("ExclusiveLock::lock FAILED to release lock [$key]"); + return false; } - fwrite($this->file, "Unlocked - " . microtime(true) . "\n"); + 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 } @@ -55,10 +59,11 @@ public function lock() if (!flock($this->file, LOCK_EX | LOCK_NB)) { //failed return false; } - fwrite($this->file, "Locked - " . microtime(true) . "\n"); + fwrite($this->file, 'Locked - ' . microtime(true) . "\n"); fflush($this->file); $this->own = true; + return true; // success } } diff --git a/version/205/class/Helper.php b/version/205/class/Helper.php index 514f1c5..327a937 100644 --- a/version/205/class/Helper.php +++ b/version/205/class/Helper.php @@ -1,5 +1,8 @@ short_url != '' ? $release->short_url : $release->full_url; - $filename = basename($release->full_url); - $tmpDir = PFAD_ROOT . PFAD_COMPILEDIR; + $release = self::getLatestRelease(true); + $url = $release->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 @@ -85,8 +86,8 @@ public static function selfupdate() 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 (!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!"); @@ -117,30 +118,29 @@ public static function selfupdate() // 3. UNZIP require_once PFAD_ROOT . PFAD_PCLZIP . 'pclzip.lib.php'; - $zip = new PclZip($tmpDir . $filename); + $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!"); + throw new Exception('Das Zip-Archiv ist leider ungültig!'); + } + $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 { - $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()); - } + throw new Exception('Entpacken fehlgeschlagen: ' . $zip->errorCode()); } } /** * @param bool $force - * @return mixed * @throws Exception + * @return mixed */ public static function getLatestRelease($force = false) { - $lastCheck = (int)self::getSetting(__NAMESPACE__ . '_upd'); + $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__); @@ -151,7 +151,7 @@ public static function getLatestRelease($force = false) @curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); @curl_setopt($curl, CURLOPT_HTTPHEADER, ['Content-Type: application/json']); - $data = curl_exec($curl); + $data = curl_exec($curl); $statusCode = (int)curl_getinfo($curl, CURLINFO_HTTP_CODE); @curl_close($curl); if ($statusCode !== 200) { @@ -163,8 +163,10 @@ public static function getLatestRelease($force = false) } self::setSetting(__NAMESPACE__ . '_upd', time()); file_put_contents(PFAD_ROOT . PFAD_COMPILEDIR . __NAMESPACE__ . '_upd', json_encode($json->data)); + return $json->data; } + return json_decode($lastRelease); } @@ -176,6 +178,7 @@ public static function getLatestRelease($force = false) public static function init() { ini_set('xdebug.default_enable', defined('WS_XDEBUG_ENABLED')); + return self::autoload(); } @@ -208,15 +211,17 @@ public static function addAlert($content, $type, $namespace) * {ws_mollie\Helper::showAlerts('namespace')} * * @param $namespace - * @return string * @throws SmartyException + * @return string */ 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 ''; } @@ -229,10 +234,10 @@ public static function showAlerts($namespace) */ public static function setSetting($name, $value) { - $setting = new stdClass; + $setting = new stdClass(); $setting->kPlugin = self::oPlugin()->kPlugin; - $setting->cName = $name; - $setting->cWert = $value; + $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); @@ -241,6 +246,7 @@ public static function setSetting($name, $value) } self::oPlugin()->oPluginEinstellungAssoc_arr[$name] = $value; self::oPlugin(true); // invalidate cache + return $return; } @@ -248,15 +254,16 @@ public static function setSetting($name, $value) * Get Plugin Object * * @param bool $force disable Cache - * @return Plugin|null + * @return null|Plugin */ public static function oPlugin($force = false) { if ($force === true) { self::$oPlugin = new Plugin(self::oPlugin()->kPlugin, true); - } else if (null === self::$oPlugin) { + } elseif (null === self::$oPlugin) { self::$oPlugin = Plugin::getPluginById(__NAMESPACE__); } + return self::$oPlugin; } @@ -271,6 +278,7 @@ public static function getSetting($name) if (array_key_exists($name, self::oPlugin()->oPluginEinstellungAssoc_arr ?: [])) { return self::oPlugin()->oPluginEinstellungAssoc_arr[$name]; } + return null; } @@ -282,8 +290,9 @@ public static function getSetting($name) */ public static function getDomain($url = URL_SHOP) { - $matches = array(); + $matches = []; @preg_match("/^((http(s)?):\/\/)?(www\.)?([a-zA-Z0-9-\.]+)(\/.*)?$/i", $url, $matches); + return strtolower(isset($matches[5]) ? $matches[5] : $url); } @@ -293,22 +302,24 @@ public static function getDomain($url = URL_SHOP) */ public static function getMasterMail($e = false) { - $settings = Shop::getSettings(array(CONF_EMAILS)); - $mail = trim($settings['emails']['email_master_absender']); + $settings = Shop::getSettings([CONF_EMAILS]); + $mail = trim($settings['emails']['email_master_absender']); if ($e === true && $mail != '') { - $mail = base64_encode($mail); - $eMail = ""; + $mail = base64_encode($mail); + $eMail = ''; foreach (str_split($mail) as $c) { $eMail .= chr(ord($c) ^ 0x00100110); } + return base64_encode($eMail); } + return $mail; } /** * @param Exception $exc - * @param bool $trace + * @param bool $trace * @return void */ public static function logExc(Exception $exc, $trace = true) @@ -338,12 +349,13 @@ public static function getAdminmenu($name) foreach (self::oPlugin()->oPluginAdminMenu_arr as $adminmenu) { if (strtolower($adminmenu->cName) == strtolower($name)) { $kPluginAdminMenu = $adminmenu->kPluginAdminMenu; + break; } } + return $kPluginAdminMenu; } - } } diff --git a/version/205/class/Hook/AbstractHook.php b/version/205/class/Hook/AbstractHook.php index 8dcbbda..1c8026b 100644 --- a/version/205/class/Hook/AbstractHook.php +++ b/version/205/class/Hook/AbstractHook.php @@ -1,13 +1,14 @@ kPlugin)) - && array_key_exists($key, $_SESSION) && !array_key_exists("Zahlungsart", $_SESSION)) { + if (($key = sprintf('kPlugin_%d_creditcard', self::Plugin()->kPlugin)) + && array_key_exists($key, $_SESSION) && !array_key_exists('Zahlungsart', $_SESSION)) { unset($_SESSION[$key]); } @@ -31,7 +31,6 @@ public static function execute($args_arr = []) Shop::Smarty()->assign('applePayCheckURL', json_encode(self::Plugin()->cFrontendPfadURLSSL . 'applepay.php')); pq('body')->append(Shop::Smarty()->fetch(self::Plugin()->cFrontendPfad . 'tpl/applepay.tpl')); } - } /** @@ -42,6 +41,7 @@ public static function isAvailable() if (array_key_exists('ws_mollie_applepay_available', $_SESSION)) { return $_SESSION['ws_mollie_applepay_available']; } + return false; } @@ -52,5 +52,4 @@ public static function setAvailable($status) { $_SESSION['ws_mollie_applepay_available'] = $status; } - -} \ No newline at end of file +} diff --git a/version/205/class/Hook/Checkbox.php b/version/205/class/Hook/Checkbox.php index 9ab5ca8..5da3728 100644 --- a/version/205/class/Hook/Checkbox.php +++ b/version/205/class/Hook/Checkbox.php @@ -1,9 +1,11 @@ cModulId, 'kPlugin_' . self::Plugin()->kPlugin . '_') === false) { return; } if (array_key_exists('nAnzeigeOrt', $args_arr) && $args_arr['nAnzeigeOrt'] === CHECKBOX_ORT_BESTELLABSCHLUSS && Session::getInstance()->Customer()->nRegistriert) { - $mCustomer = Customer::fromID(Session::getInstance()->Customer()->kKunde, 'kKunde'); if ($mCustomer->customerId) { return; } - $checkbox = new \CheckBox(); - $checkbox->kLink = 0; - $checkbox->kCheckBox = -1; - $checkbox->kCheckBoxFunktion = 0; - $checkbox->cName = 'MOLLIE SAVE CUSTOMER'; - $checkbox->cKundengruppe = ';1;'; - $checkbox->cAnzeigeOrt = ';2;'; - $checkbox->nAktiv = 1; - $checkbox->nPflicht = 0; - $checkbox->nLogging = 0; - $checkbox->nSort = 999; - $checkbox->dErstellt = date('Y-m-d H:i:s'); + $checkbox = new \CheckBox(); + $checkbox->kLink = 0; + $checkbox->kCheckBox = -1; + $checkbox->kCheckBoxFunktion = 0; + $checkbox->cName = 'MOLLIE SAVE CUSTOMER'; + $checkbox->cKundengruppe = ';1;'; + $checkbox->cAnzeigeOrt = ';2;'; + $checkbox->nAktiv = 1; + $checkbox->nPflicht = 0; + $checkbox->nLogging = 0; + $checkbox->nSort = 999; + $checkbox->dErstellt = date('Y-m-d H:i:s'); $checkbox->oCheckBoxSprache_arr = []; $langs = gibAlleSprachen(); foreach ($langs as $lang) { $checkbox->oCheckBoxSprache_arr[$lang->kSprache] = (object)[ - 'cText' => self::Plugin()->oPluginSprachvariableAssoc_arr['checkboxText'], + 'cText' => self::Plugin()->oPluginSprachvariableAssoc_arr['checkboxText'], 'cBeschreibung' => self::Plugin()->oPluginSprachvariableAssoc_arr['checkboxDescr'], - 'kSprache' => $lang->kSprache, - 'kCheckbox' => -1 + 'kSprache' => $lang->kSprache, + 'kCheckbox' => -1 ]; } $checkbox->kKundengruppe_arr = [Session::getInstance()->Customer()->kKundengruppe]; - $checkbox->kAnzeigeOrt_arr = [CHECKBOX_ORT_BESTELLABSCHLUSS]; - $checkbox->cID = "mollie_create_customer"; - $checkbox->cLink = ''; + $checkbox->kAnzeigeOrt_arr = [CHECKBOX_ORT_BESTELLABSCHLUSS]; + $checkbox->cID = 'mollie_create_customer'; + $checkbox->cLink = ''; $args_arr['oCheckBox_arr'][] = $checkbox; - } } -} \ No newline at end of file +} diff --git a/version/205/class/Hook/Queue.php b/version/205/class/Hook/Queue.php index 8e3bbcf..1cc3fb9 100644 --- a/version/205/class/Hook/Queue.php +++ b/version/205/class/Hook/Queue.php @@ -1,9 +1,11 @@ fGesamtsumme > 0 && self::Plugin()->oPluginEinstellungAssoc_arr['onlyPaid'] === 'Y' && AbstractCheckout::isMollie((int)$args_arr['oBestellung']->kZahlungsart, true)) { - $args_arr['oBestellung']->cAbgeholt = 'Y'; Jtllog::writeLog('Switch cAbgeholt for kBestellung: ' . print_r($args_arr['oBestellung']->kBestellung, 1), JTLLOG_LEVEL_NOTICE); } @@ -41,7 +41,7 @@ public static function xmlBestellStatus(array $args_arr) if (AbstractCheckout::isMollie((int)$args_arr['oBestellung']->kBestellung)) { self::saveToQueue(HOOK_BESTELLUNGEN_XML_BESTELLSTATUS . ':' . (int)$args_arr['oBestellung']->kBestellung, [ 'kBestellung' => $args_arr['oBestellung']->kBestellung, - 'status' => (int)$args_arr['status'] + 'status' => (int)$args_arr['status'] ]); } } @@ -54,13 +54,15 @@ public static function xmlBestellStatus(array $args_arr) */ public static function saveToQueue($hook, $args_arr, $type = 'hook') { - $mQueue = new QueueModel(); + $mQueue = new QueueModel(); $mQueue->cType = $type . ':' . $hook; $mQueue->cData = serialize($args_arr); + try { return $mQueue->save(); } catch (Exception $e) { Jtllog::writeLog('mollie::saveToQueue: ' . $e->getMessage() . ' - ' . print_r($args_arr, 1)); + return false; } } @@ -81,9 +83,7 @@ public static function xmlBearbeiteStorno(array $args_arr) public static function headPostGet() { if (array_key_exists('mollie', $_REQUEST) && (int)$_REQUEST['mollie'] === 1 && array_key_exists('id', $_REQUEST)) { - if (array_key_exists('hash', $_REQUEST) && $hash = trim(StringHandler::htmlentities(StringHandler::filterXSS($_REQUEST['hash'])), '_')) { - AbstractCheckout::finalizeOrder($hash, $_REQUEST['id'], array_key_exists('test', $_REQUEST)); } else { self::saveToQueue($_REQUEST['id'], $_REQUEST['id'], 'webhook'); @@ -119,11 +119,10 @@ public static function headPostGet() } $mollie = $checkout->create($options); // Order::repayOrder($orderModel->getOrderId(), $options, $api); - $url = $mollie->getCheckoutUrl(); + $url = $mollie->getCheckoutUrl(); header('Location: ' . $url); exit(); - } catch (RuntimeException $e) { // TODO Workaround? //$alertHelper = Shop::Container()->getAlertService(); @@ -133,5 +132,4 @@ public static function headPostGet() } } } - -} \ No newline at end of file +} diff --git a/version/205/class/Model/AbstractModel.php b/version/205/class/Model/AbstractModel.php index e041d4e..b0f1aaf 100644 --- a/version/205/class/Model/AbstractModel.php +++ b/version/205/class/Model/AbstractModel.php @@ -1,4 +1,8 @@ executeQueryPrepared("SELECT * FROM " . static::TABLE . " WHERE `$col` = :id", - [':id' => $id], 1)) { + if ($payment = Shop::DB()->executeQueryPrepared( + 'SELECT * FROM ' . static::TABLE . " WHERE `$col` = :id", + [':id' => $id], + 1 + )) { return new static($payment); } if ($failIfNotExists) { throw new RuntimeException(sprintf('Model %s in %s nicht gefunden!', $id, static::TABLE)); } + return new static(); } /** - * @return mixed|stdClass|null + * @return null|mixed|stdClass */ public function jsonSerialize() { @@ -61,6 +68,7 @@ public function __get($name) if (isset($this->data->$name)) { return $this->data->$name; } + return null; } @@ -89,10 +97,11 @@ public function save() if ($this->new) { Shop::DB()->insertRow(static::TABLE, $this->data); $this->new = false; + return true; } Shop::DB()->updateRow(static::TABLE, static::PRIMARY, $this->data->{static::PRIMARY}, $this->data); + return true; } - } diff --git a/version/205/class/Model/Customer.php b/version/205/class/Model/Customer.php index 7be9e15..4d61bc5 100644 --- a/version/205/class/Model/Customer.php +++ b/version/205/class/Model/Customer.php @@ -1,5 +1,8 @@ dCreatedAt) { $this->dCreatedAt = date('Y-m-d H:i:s'); } - if($this->new){ + if ($this->new) { $this->dReminder = self::NULL; } + return parent::save(); } } diff --git a/version/205/class/Model/Queue.php b/version/205/class/Model/Queue.php index e17a491..0977d57 100644 --- a/version/205/class/Model/Queue.php +++ b/version/205/class/Model/Queue.php @@ -1,5 +1,8 @@ cResult = $result; - $this->dDone = $date ?: date('Y-m-d H:i:s'); + $this->dDone = $date ?: date('Y-m-d H:i:s'); + return $this->save(); } @@ -36,7 +39,7 @@ public function save() $this->dCreated = date('Y-m-d H:i:s'); } $this->dModified = date('Y-m-d H:i:s'); + return parent::save(); } - -} \ No newline at end of file +} diff --git a/version/205/class/Model/Shipment.php b/version/205/class/Model/Shipment.php index bece7b4..bce1609 100644 --- a/version/205/class/Model/Shipment.php +++ b/version/205/class/Model/Shipment.php @@ -1,9 +1,11 @@ executeQueryPrepared("SELECT p.kBestellung, b.cStatus FROM xplugin_ws_mollie_payments p " - . "JOIN tbestellung b ON b.kBestellung = p.kBestellung " + $open = Shop::DB()->executeQueryPrepared( + 'SELECT p.kBestellung, b.cStatus FROM xplugin_ws_mollie_payments p ' + . 'JOIN tbestellung b ON b.kBestellung = p.kBestellung ' . "WHERE b.cAbgeholt = 'Y' AND NOT p.bSynced AND b.cStatus IN ('1', '2') AND p.dCreatedAt < NOW() - INTERVAL :d HOUR", - [':d' => $delay], 2); + [':d' => $delay], + 2 + ); foreach ($open as $o) { try { - $checkout = AbstractCheckout::fromBestellung($o->kBestellung); - $pm = $checkout->PaymentMethod(); + $pm = $checkout->PaymentMethod(); if ($pm::ALLOW_AUTO_STORNO && $pm::METHOD === $checkout->getMollie()->method) { if ($checkout->getBestellung()->cAbgeholt === 'Y' && (bool)$checkout->getModel()->bSynced === false) { if (!in_array($checkout->getMollie()->status, [OrderStatus::STATUS_PAID, OrderStatus::STATUS_COMPLETED, OrderStatus::STATUS_AUTHORIZED], true)) { @@ -54,11 +57,11 @@ public static function storno($delay) $checkout->Log('AutoStorno: bereits zur WAWI synchronisiert.', LOGLEVEL_ERROR); } } - } catch (Exception $e) { Helper::logExc($e); } } + return true; } @@ -67,11 +70,10 @@ public static function storno($delay) */ public static function run($limit = 10) { - foreach (self::getOpen($limit) as $todo) { - if (!self::lock($todo)) { Jtllog::writeLog(sprintf('%s already locked since %s', $todo->kId, $todo->bLock ?: 'just now')); + continue; } @@ -80,13 +82,14 @@ public static function run($limit = 10) switch ($type) { case 'webhook': self::handleWebhook($id, $todo); + break; case 'hook': self::handleHook((int)$id, $todo); + break; } - } catch (Exception $e) { Jtllog::writeLog($e->getMessage() . " ($type, $id)"); $todo->done("{$e->getMessage()}\n{$e->getFile()}:{$e->getLine()}\n{$e->getTraceAsString()}"); @@ -94,7 +97,6 @@ public static function run($limit = 10) } self::unlock($todo); - } } @@ -107,10 +109,10 @@ public static function run($limit = 10) private static function getOpen($limit) { // TODO: DOKU! - if(!defined('MOLLIE_HOOK_DELAY')){ + if (!defined('MOLLIE_HOOK_DELAY')) { define('MOLLIE_HOOK_DELAY', 3); } - $open = Shop::DB()->executeQueryPrepared(sprintf("SELECT * FROM %s WHERE dDone IS NULL AND `bLock` IS NULL AND (cType LIKE 'webhook:%%' OR (cType LIKE 'hook:%%') AND dCreated < DATE_SUB(NOW(), INTERVAL ".(int)MOLLIE_HOOK_DELAY." MINUTE)) ORDER BY dCreated DESC LIMIT 0, :LIMIT;", QueueModel::TABLE), [ + $open = Shop::DB()->executeQueryPrepared(sprintf("SELECT * FROM %s WHERE dDone IS NULL AND `bLock` IS NULL AND (cType LIKE 'webhook:%%' OR (cType LIKE 'hook:%%') AND dCreated < DATE_SUB(NOW(), INTERVAL " . (int)MOLLIE_HOOK_DELAY . ' MINUTE)) ORDER BY dCreated DESC LIMIT 0, :LIMIT;', QueueModel::TABLE), [ ':LIMIT' => $limit ], 2); @@ -129,32 +131,33 @@ protected static function lock($todo) return $todo->kId && Shop::DB()->executeQueryPrepared(sprintf('UPDATE %s SET `bLock` = NOW() WHERE `bLock` IS NULL AND kId = :kId', QueueModel::TABLE), [ 'kId' => $todo->kId ], 3) >= 1; - } /** * @param $id * @param QueueModel $todo - * @return bool * @throws Exception + * @return bool */ protected static function handleWebhook($id, QueueModel $todo) { $checkout = AbstractCheckout::fromID($id); if ($checkout->getBestellung()->kBestellung && $checkout->PaymentMethod()) { $checkout->handleNotification(); + return $todo->done('Status: ' . $checkout->getMollie()->status); } + throw new RuntimeException("Bestellung oder Zahlungsart konnte nicht geladen werden: $id"); } /** * @param $hook * @param QueueModel $todo - * @return bool * @throws ApiException * @throws IncompatiblePlatform * @throws Exception + * @return bool */ protected static function handleHook($hook, QueueModel $todo) { @@ -166,13 +169,14 @@ protected static function handleHook($hook, QueueModel $todo) $checkout = AbstractCheckout::fromBestellung($data['kBestellung']); $status = array_key_exists('status', $data) ? (int)$data['status'] : 0; - $result = ""; + $result = ''; if (!$status || $status < BESTELLUNG_STATUS_VERSANDT) { return $todo->done("Bestellung noch nicht versendet: {$checkout->getBestellung()->cStatus}"); } - if (!count($checkout->getBestellung()->oLieferschein_arr)){ + if (!count($checkout->getBestellung()->oLieferschein_arr)) { $todo->dCreated = date('Y-m-d H:i:s', strtotime('+3 MINUTES')); - $todo->cResult = 'Noch keine Lieferscheine, delay...'; + $todo->cResult = 'Noch keine Lieferscheine, delay...'; + return $todo->save(); } @@ -184,7 +188,7 @@ protected static function handleHook($hook, QueueModel $todo) $checkout->handleNotification(); if ($checkout->getMollie()->status === OrderStatus::STATUS_COMPLETED) { $result = 'Mollie Status already ' . $checkout->getMollie()->status; - } else if ($checkout->getMollie()->isCreated() || $checkout->getMollie()->isPaid() || $checkout->getMollie()->isAuthorized() || $checkout->getMollie()->isShipping() || $checkout->getMollie()->isPending()) { + } elseif ($checkout->getMollie()->isCreated() || $checkout->getMollie()->isPaid() || $checkout->getMollie()->isAuthorized() || $checkout->getMollie()->isShipping() || $checkout->getMollie()->isPending()) { try { if ($shipments = Shipment::syncBestellung($checkout)) { foreach ($shipments as $shipment) { @@ -202,7 +206,7 @@ protected static function handleHook($hook, QueueModel $todo) } catch (RuntimeException $e) { $result = $e->getMessage(); } catch (Exception $e) { - $result = $e->getMessage() . "\n" . $e->getFile() . ":" . $e->getLine() . "\n" . $e->getTraceAsString(); + $result = $e->getMessage() . "\n" . $e->getFile() . ':' . $e->getLine() . "\n" . $e->getTraceAsString(); } } else { $result = sprintf('Unerwarteter Mollie Status "%s" für %s', $checkout->getMollie()->status, $checkout->getBestellung()->cBestellNr); @@ -210,10 +214,11 @@ protected static function handleHook($hook, QueueModel $todo) } else { $result = 'Nothing to do.'; } - $checkout->Log("Queue::handleHook: " . $result); + $checkout->Log('Queue::handleHook: ' . $result); } else { - $result = "kBestellung missing"; + $result = 'kBestellung missing'; } + return $todo->done($result); case HOOK_BESTELLUNGEN_XML_BEARBEITESTORNO: @@ -222,9 +227,11 @@ protected static function handleHook($hook, QueueModel $todo) } $checkout = AbstractCheckout::fromBestellung((int)$data['kBestellung']); + return $todo->done($checkout->cancelOrRefund()); } } + return false; } @@ -238,5 +245,4 @@ protected static function unlock($todo) 'kId' => $todo->kId ], 3) >= 1; } - -} \ No newline at end of file +} diff --git a/version/205/class/Shipment.php b/version/205/class/Shipment.php index ae533f7..c807e7f 100644 --- a/version/205/class/Shipment.php +++ b/version/205/class/Shipment.php @@ -1,5 +1,8 @@ oLieferschein && $this->kLieferschein) { $this->oLieferschein = new Lieferschein($this->kLieferschein); } + return $this->oLieferschein; } /** - * @return OrderCheckout * @throws Exception + * @return OrderCheckout */ public function getCheckout() { @@ -102,6 +105,7 @@ public function getCheckout() //TODO evtl. load by lieferschien throw new Exception('Should not happen, but it did!'); } + return $this->checkout; } @@ -109,7 +113,6 @@ public static function syncBestellung(OrderCheckout $checkout) { $shipments = []; if ($checkout->getBestellung()->kBestellung) { - $oKunde = $checkout->getBestellung()->oKunde ?: new Kunde($checkout->getBestellung()->kKunde); $shippingActive = Helper::getSetting('shippingActive'); @@ -124,8 +127,8 @@ public static function syncBestellung(OrderCheckout $checkout) /** @var Lieferschein $oLieferschein */ foreach ($checkout->getBestellung()->oLieferschein_arr as $oLieferschein) { try { - $shipment = new Shipment($oLieferschein->getLieferschein(), $checkout); - $mode = self::Plugin()->oPluginEinstellungAssoc_arr['shippingMode']; + $shipment = new self($oLieferschein->getLieferschein(), $checkout); + $mode = self::Plugin()->oPluginEinstellungAssoc_arr['shippingMode']; switch ($mode) { case 'A': // ship directly @@ -133,6 +136,7 @@ public static function syncBestellung(OrderCheckout $checkout) throw new RuntimeException('Shipment konnte nicht gespeichert werden.'); } $shipments[] = $shipment->getShipment(); + break; case 'B': @@ -142,8 +146,10 @@ public static function syncBestellung(OrderCheckout $checkout) throw new RuntimeException('Shipment konnte nicht gespeichert werden.'); } $shipments[] = $shipment->getShipment(); + break; } + throw new RuntimeException('Gastbestellung noch nicht komplett versendet!'); } } catch (RuntimeException $e) { @@ -154,18 +160,18 @@ public static function syncBestellung(OrderCheckout $checkout) } } } + return $shipments; } /** - * @return bool * @throws ApiException * @throws IncompatiblePlatform * @throws Exception + * @return bool */ public function send() { - if ($this->getShipment()) { throw new RuntimeException('Lieferschien bereits an Mollie übertragen: ' . $this->getShipment()->id); } @@ -174,31 +180,31 @@ public function send() throw new RuntimeException('Bestellung bei Mollie bereits abgeschlossen!'); } - $api = $this->getCheckout()->API()->Client(); + $api = $this->getCheckout()->API()->Client(); $this->shipment = $api->shipments->createForId($this->checkout->getModel()->kID, $this->loadRequest()->jsonSerialize()); return $this->updateModel()->saveModel(); - } /** * @param false $force - * @return BaseResource|\Mollie\Api\Resources\Shipment * @throws ApiException * @throws IncompatiblePlatform * @throws Exception + * @return BaseResource|\Mollie\Api\Resources\Shipment */ public function getShipment($force = false) { if (($force || !$this->shipment) && $this->getModel() && $this->getModel()->cShipmentId) { $this->shipment = $this->getCheckout()->API()->Client()->shipments->getForId($this->getModel()->cOrderId, $this->getModel()->cShipmentId); } + return $this->shipment; } /** - * @return ShipmentModel * @throws Exception + * @return ShipmentModel */ public function getModel() { @@ -210,35 +216,37 @@ public function getModel() } $this->updateModel(); } + return $this->model; } /** - * @return $this * @throws Exception + * @return $this */ public function updateModel() { $this->getModel()->kLieferschein = $this->kLieferschein; if ($this->getCheckout()) { - $this->getModel()->cOrderId = $this->getCheckout()->getModel()->kID; + $this->getModel()->cOrderId = $this->getCheckout()->getModel()->kID; $this->getModel()->kBestellung = $this->getCheckout()->getModel()->kBestellung; } if ($this->getShipment()) { $this->getModel()->cShipmentId = $this->getShipment()->id; - $this->getModel()->cUrl = $this->getShipment()->getTrackingUrl() ?: ''; + $this->getModel()->cUrl = $this->getShipment()->getTrackingUrl() ?: ''; } if (isset($this->tracking)) { $this->getModel()->cCarrier = $this->tracking['carrier'] ?: ''; - $this->getModel()->cCode = $this->tracking['code'] ?: ''; + $this->getModel()->cCode = $this->tracking['code'] ?: ''; } + return $this; } /** * @param array $options - * @return $this * @throws Exception + * @return $this */ public function loadRequest(&$options = []) { @@ -247,7 +255,7 @@ public function loadRequest(&$options = []) if ($oVersand->getIdentCode() && $oVersand->getLogistik()) { $tracking = [ 'carrier' => utf8_encode($oVersand->getLogistik()), - 'code' => utf8_encode($oVersand->getIdentCode()), + 'code' => utf8_encode($oVersand->getIdentCode()), ]; if ($oVersand->getLogistikVarUrl()) { $tracking['url'] = utf8_encode($oVersand->getLogistikURL()); @@ -261,12 +269,13 @@ public function loadRequest(&$options = []) } else { $this->lines = $this->getOrderLines(); } + return $this; } /** - * @return array * @throws Exception + * @return array */ protected function getOrderLines() { @@ -281,36 +290,35 @@ protected function getOrderLines() /** @var Lieferscheinpos $oLieferscheinPos */ foreach ($this->getLieferschein()->oLieferscheinPos_arr as $oLieferscheinPos) { - $wkpos = Shop::DB()->executeQueryPrepared('SELECT * FROM twarenkorbpos WHERE kBestellpos = :kBestellpos', [ ':kBestellpos' => $oLieferscheinPos->getBestellPos() ], 1); /** @var OrderLine $orderLine */ foreach ($this->getCheckout()->getMollie()->lines as $orderLine) { - if ($orderLine->sku === $wkpos->cArtNr && !in_array($orderLine->id, $shippedOrderLines, true)) { - if ($quantity = min($oLieferscheinPos->getAnzahl(), $orderLine->shippableQuantity)) { $lines[] = [ - 'id' => $orderLine->id, + 'id' => $orderLine->id, 'quantity' => $quantity ]; } $shippedOrderLines[] = $orderLine->id; + break; } } } + return $lines; } /** - * @return bool * @throws Exception + * @return bool */ public function saveModel() { return $this->getModel()->save(); } -} \ No newline at end of file +} diff --git a/version/205/class/Traits/Jsonable.php b/version/205/class/Traits/Jsonable.php index afc0988..5e20a1b 100644 --- a/version/205/class/Traits/Jsonable.php +++ b/version/205/class/Traits/Jsonable.php @@ -1,9 +1,11 @@ requestData) === false) { throw new \RuntimeException(sprintf("JSON Encode Error: %s\n%s", json_last_error_msg(), print_r($this->requestData, 1))); } + return $this->requestData; } @@ -25,6 +27,7 @@ public function __get($name) if (!$this->requestData) { $this->loadRequest(); } + return is_string($this->requestData[$name]) ? utf8_decode($this->requestData[$name]) : $this->requestData[$name]; } @@ -58,5 +61,4 @@ public function __isset($name) { return $this->requestData[$name] !== null; } - -} \ No newline at end of file +} diff --git a/version/205/frontend/131_globalinclude.php b/version/205/frontend/131_globalinclude.php index 2861d31..88f8c12 100644 --- a/version/205/frontend/131_globalinclude.php +++ b/version/205/frontend/131_globalinclude.php @@ -1,4 +1,8 @@ select('tzahlungsession', 'cZahlungsID', $sessionHash); if ($paymentSession && $paymentSession->kBestellung) { $oBestellung = new Bestellung($paymentSession->kBestellung); if (Shopsetting::getInstance()->getValue('kaufabwicklung', 'bestellabschluss_abschlussseite') === 'A') { - $oZahlungsID = Shop::DB()->query(" + $oZahlungsID = Shop::DB()->query( + ' SELECT cId FROM tbestellid - WHERE kBestellung = " . (int)$paymentSession->kBestellung, 1 + WHERE kBestellung = ' . (int)$paymentSession->kBestellung, + 1 ); if (is_object($oZahlungsID)) { header('Location: ' . Shop::getURL() . '/bestellabschluss.php?i=' . $oZahlungsID->cId); @@ -51,10 +57,6 @@ $lock->unlock(); } } - - } catch (Exception $e) { Helper::logExc($e); } - - diff --git a/version/205/frontend/132_headPostGet.php b/version/205/frontend/132_headPostGet.php index 94afd33..d6f72ba 100644 --- a/version/205/frontend/132_headPostGet.php +++ b/version/205/frontend/132_headPostGet.php @@ -1,9 +1,12 @@ HTML ); - } catch (Exception $e) { Helper::logExc($e); } diff --git a/version/205/frontend/180_checkbox.php b/version/205/frontend/180_checkbox.php index 95a070f..97d8a0e 100644 --- a/version/205/frontend/180_checkbox.php +++ b/version/205/frontend/180_checkbox.php @@ -1,8 +1,11 @@ oPluginEinstellungAssoc_arr['useCustomerAPI'] === 'C') { \ws_mollie\Hook\Checkbox::execute($args_arr); } - } catch (Exception $e) { Helper::logExc($e); -} \ No newline at end of file +} diff --git a/version/205/frontend/181_sync.php b/version/205/frontend/181_sync.php index 22022a9..6d41838 100644 --- a/version/205/frontend/181_sync.php +++ b/version/205/frontend/181_sync.php @@ -1,4 +1,8 @@ cModulId = "kPlugin_" . self::Plugin()->kPlugin . "_mollie" . $moduleID; + $this->cModulId = 'kPlugin_' . self::Plugin()->kPlugin . '_mollie' . $moduleID; } /** @@ -51,6 +54,7 @@ public function setOrderStatusToPaid($order) if ((int)$order->cStatus >= BESTELLUNG_STATUS_BEZAHLT) { return $this; } + return parent::setOrderStatusToPaid($order); } @@ -63,19 +67,19 @@ public function setOrderStatusToPaid($order) */ public function preparePaymentProcess($order) { - parent::preparePaymentProcess($order); try { - if ($this->duringCheckout && !static::ALLOW_PAYMENT_BEFORE_ORDER) { - $this->Log(sprintf("Zahlung vor Bestellabschluss nicht unterstützt (%s)!", $order->cBestellNr), sprintf("#%s", $order->kBestellung), LOGLEVEL_ERROR); + $this->Log(sprintf('Zahlung vor Bestellabschluss nicht unterstützt (%s)!', $order->cBestellNr), sprintf('#%s', $order->kBestellung), LOGLEVEL_ERROR); + return; } $payable = (float)$order->fGesamtsumme > 0; if (!$payable) { - $this->Log(sprintf("Bestellung '%s': Gesamtsumme %.2f, keine Zahlung notwendig!", $order->cBestellNr, $order->fGesamtsumme), sprintf("#%s", $order->kBestellung)); + $this->Log(sprintf("Bestellung '%s': Gesamtsumme %.2f, keine Zahlung notwendig!", $order->cBestellNr, $order->fGesamtsumme), sprintf('#%s', $order->kBestellung)); + return; } @@ -87,12 +91,12 @@ public function preparePaymentProcess($order) if ($api === 'payment') { $checkout = new PaymentCheckout($order); - $payment = $checkout->create($paymentOptions); + $payment = $checkout->create($paymentOptions); /** @noinspection NullPointerExceptionInspection */ $url = $payment->getCheckoutUrl(); } else { $checkout = new OrderCheckout($order); - $mOrder = $checkout->create($paymentOptions); + $mOrder = $checkout->create($paymentOptions); /** @noinspection NullPointerExceptionInspection */ $url = $mOrder->getCheckoutUrl(); } @@ -113,7 +117,8 @@ public function preparePaymentProcess($order) public function Log($msg, $data = null, $level = LOGLEVEL_NOTICE) { - ZahlungsLog::add($this->moduleID, "[" . microtime(true) . " - " . $_SERVER['PHP_SELF'] . "] " . $msg, $data, $level); + ZahlungsLog::add($this->moduleID, '[' . microtime(true) . ' - ' . $_SERVER['PHP_SELF'] . '] ' . $msg, $data, $level); + return $this; } @@ -124,14 +129,15 @@ public function getPaymentOptions(Bestellung $order, $apiType) /** * @param Bestellung $order - * @param string $hash - * @param array $args + * @param string $hash + * @param array $args */ public function handleNotification($order, $hash, $args) { parent::handleNotification($order, $hash, $args); + try { - $orderId = $args['id']; + $orderId = $args['id']; $checkout = null; if (strpos($orderId, 'tr_') === 0) { $checkout = new PaymentCheckout($order); @@ -139,7 +145,6 @@ public function handleNotification($order, $hash, $args) $checkout = new OrderCheckout($order); } $checkout->handleNotification($hash); - } catch (Exception $e) { $checkout->Log(sprintf("mollie::handleNotification: Fehler bei Bestellung '%s': %s\n%s", $order->cBestellNr, $e->getMessage(), print_r($args, 1)), LOGLEVEL_ERROR); } @@ -158,16 +163,14 @@ public function canPayAgain() * * @return bool */ - public function isSelectable() { - if (API::getMode()) { $selectable = trim(self::Plugin()->oPluginEinstellungAssoc_arr['test_api_key']) !== ''; } else { $selectable = trim(self::Plugin()->oPluginEinstellungAssoc_arr['api_key']) !== ''; if (!$selectable) { - Jtllog::writeLog("Live API Key missing!"); + Jtllog::writeLog('Live API Key missing!'); } } if ($selectable) { @@ -194,6 +197,7 @@ public function isSelectable() $selectable = false; } } + return $selectable && parent::isSelectable(); } @@ -203,12 +207,11 @@ public function isSelectable() * @param $billingCountry * @param $currency * @param $amount - * @return bool * @throws ApiException + * @return bool */ protected static function isMethodPossible($method, $locale, $billingCountry, $currency, $amount) { - $api = new API(API::getMode()); if (!array_key_exists('mollie_possibleMethods', $_SESSION)) { @@ -221,10 +224,10 @@ protected static function isMethodPossible($method, $locale, $billingCountry, $c 'locale' => $locale, 'amount' => [ 'currency' => $currency, - 'value' => number_format($amount, 2, ".", "") + 'value' => number_format($amount, 2, '.', '') ], 'billingCountry' => $billingCountry, - 'resource' => 'orders', + 'resource' => 'orders', 'includeWallets' => 'applepay', ]); foreach ($active as $a) { @@ -243,7 +246,6 @@ protected static function isMethodPossible($method, $locale, $billingCountry, $c } return false; - } /** @@ -264,5 +266,4 @@ public function getExpiryDays() { return (int)min(abs((int)Helper::oPlugin()->oPluginEinstellungAssoc_arr[$this->cModulId . '_dueDays']), static::MAX_EXPIRY_DAYS) ?: static::MAX_EXPIRY_DAYS; } - } diff --git a/version/205/paymentmethod/JTLMollieApplePay.php b/version/205/paymentmethod/JTLMollieApplePay.php index 4b23bf4..47f5ba0 100644 --- a/version/205/paymentmethod/JTLMollieApplePay.php +++ b/version/205/paymentmethod/JTLMollieApplePay.php @@ -1,4 +1,8 @@ oRechnungsadresse->cMail; - $paymentOptions['locale'] = AbstractCheckout::getLocale($_SESSION['cISOSprache'], $order->oRechnungsadresse->cLand); + $paymentOptions['locale'] = AbstractCheckout::getLocale($_SESSION['cISOSprache'], $order->oRechnungsadresse->cLand); } $dueDays = $this->getExpiryDays(); if ($dueDays > 3) { $paymentOptions['dueDate'] = date('Y-m-d', strtotime("+$dueDays DAYS")); } + return $paymentOptions; } } diff --git a/version/205/paymentmethod/JTLMollieBelfius.php b/version/205/paymentmethod/JTLMollieBelfius.php index 00c8e7c..01f737d 100644 --- a/version/205/paymentmethod/JTLMollieBelfius.php +++ b/version/205/paymentmethod/JTLMollieBelfius.php @@ -1,10 +1,13 @@ unsetCache(self::CACHE_TOKEN) ->unsetCache(self::CACHE_TOKEN_TIMESTAMP); + return true; } public function handleAdditional($aPost_arr) { - $components = self::Plugin()->oPluginEinstellungAssoc_arr[$this->moduleID . '_components']; - $profileId = self::Plugin()->oPluginEinstellungAssoc_arr['profileId']; + $profileId = self::Plugin()->oPluginEinstellungAssoc_arr['profileId']; if ($components === 'N' || !$profileId || trim($profileId) === '') { return parent::handleAdditional($aPost_arr); @@ -49,12 +53,13 @@ public function handleAdditional($aPost_arr) } try { - $trustBadge = (bool)self::Plugin()->oPluginEinstellungAssoc_arr[$this->moduleID . '_loadTrust']; - $locale = AbstractCheckout::getLocale($_SESSION['cISOSprache'], Session::getInstance()->Customer() ? Session::getInstance()->Customer()->cLand : null); - $mode = API::getMode(); + $trustBadge = (bool)self::Plugin()->oPluginEinstellungAssoc_arr[$this->moduleID . '_loadTrust']; + $locale = AbstractCheckout::getLocale($_SESSION['cISOSprache'], Session::getInstance()->Customer() ? Session::getInstance()->Customer()->cLand : null); + $mode = API::getMode(); $errorMessage = json_encode(self::Plugin()->oPluginSprachvariableAssoc_arr['mcErrorMessage']); } catch (Exception $e) { Jtllog::writeLog($e->getMessage() . "\n" . print_r(['e' => $e], 1)); + return parent::handleAdditional($aPost_arr); } @@ -83,12 +88,12 @@ protected function setToken($token) { $this->addCache(self::CACHE_TOKEN, $token) ->addCache(self::CACHE_TOKEN_TIMESTAMP, time() + 3600); + return true; } public function getPaymentOptions(Bestellung $order, $apiType) { - $paymentOptions = []; if ($apiType === 'payment') { @@ -104,7 +109,7 @@ public function getPaymentOptions(Bestellung $order, $apiType) if ((int)$this->getCache(self::CACHE_TOKEN_TIMESTAMP) > time() && ($token = trim($this->getCache(self::CACHE_TOKEN)))) { $paymentOptions['cardToken'] = $token; } + return $paymentOptions; } - } diff --git a/version/205/paymentmethod/JTLMollieEPS.php b/version/205/paymentmethod/JTLMollieEPS.php index df84b89..96f3470 100644 --- a/version/205/paymentmethod/JTLMollieEPS.php +++ b/version/205/paymentmethod/JTLMollieEPS.php @@ -1,4 +1,8 @@ $order->oRechnungsadresse->cMail] : []; } - } diff --git a/version/205/paymentmethod/JTLMollieSofort.php b/version/205/paymentmethod/JTLMollieSofort.php index 0a4d191..38fffa9 100644 --- a/version/205/paymentmethod/JTLMollieSofort.php +++ b/version/205/paymentmethod/JTLMollieSofort.php @@ -1,10 +1,14 @@ Date: Tue, 10 Aug 2021 16:36:35 +0200 Subject: [PATCH 260/280] fix #152 --- version/205/frontend/131_globalinclude.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version/205/frontend/131_globalinclude.php b/version/205/frontend/131_globalinclude.php index 88f8c12..dfe4fa4 100644 --- a/version/205/frontend/131_globalinclude.php +++ b/version/205/frontend/131_globalinclude.php @@ -26,7 +26,7 @@ if ($paymentSession && $paymentSession->kBestellung) { $oBestellung = new Bestellung($paymentSession->kBestellung); - if (Shopsetting::getInstance()->getValue('kaufabwicklung', 'bestellabschluss_abschlussseite') === 'A') { + if (Shop::getConfig([CONF_KAUFABWICKLUNG])['kaufabwicklung']['bestellabschluss_abschlussseite'] === 'A') { $oZahlungsID = Shop::DB()->query( ' SELECT cId From 740d4476e2955c3e335642e5f0957c44308f47c7 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Tue, 10 Aug 2021 16:41:35 +0200 Subject: [PATCH 261/280] fix #141 --- version/205/class/Checkout/AbstractCheckout.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version/205/class/Checkout/AbstractCheckout.php b/version/205/class/Checkout/AbstractCheckout.php index 611475d..9405e41 100644 --- a/version/205/class/Checkout/AbstractCheckout.php +++ b/version/205/class/Checkout/AbstractCheckout.php @@ -174,7 +174,7 @@ public static function finalizeOrder($sessionHash, $id, $test = false) Queue::saveToQueue($id, $id, 'webhook'); } } else { - Jtllog::writeLog(sprintf('PaymentSession nicht gefunden: %s - ID: %s => Queue', $sessionHash, $id), JTLLOG_LEVEL_ERROR); + Jtllog::writeLog(sprintf('PaymentSession nicht gefunden: %s - ID: %s => Queue', $sessionHash, $id), JTLLOG_LEVEL_NOTICE); Queue::saveToQueue($id, $id, 'webhook'); } } catch (Exception $e) { From 9f01383edbfeb81a3e38ecf32a59db474fd0a4f5 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Tue, 10 Aug 2021 17:07:55 +0200 Subject: [PATCH 262/280] fix #154 --- version/205/frontend/tpl/applepay.tpl | 28 +++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/version/205/frontend/tpl/applepay.tpl b/version/205/frontend/tpl/applepay.tpl index a7ec33b..cfd359b 100644 --- a/version/205/frontend/tpl/applepay.tpl +++ b/version/205/frontend/tpl/applepay.tpl @@ -1,17 +1,21 @@ From 37471df82c601a7559bd129d7ba83634586c6ff3 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Wed, 11 Aug 2021 10:31:49 +0200 Subject: [PATCH 263/280] CS Fix --- .php-cs-fixer.php | 2 +- composer.json | 4 +- version/100/adminmenu/info.php | 15 +- version/100/adminmenu/orders.php | 56 +- version/100/adminmenu/paymentmethods.php | 12 +- version/100/class/Helper.php | 72 ++- version/100/class/Model/AbstractModel.php | 4 + version/100/class/Model/Payment.php | 54 +- version/100/class/Mollie.php | 74 ++- version/100/frontend/131_globalinclude.php | 14 +- version/100/frontend/140_smarty.php | 16 +- version/100/frontend/144_notify.php | 9 +- version/100/frontend/181_sync.php | 13 +- version/100/paymentmethod/JTLMollie.php | 279 +++++---- .../100/paymentmethod/JTLMollieBancontact.php | 4 + .../paymentmethod/JTLMollieBanktransfer.php | 5 + .../100/paymentmethod/JTLMollieBelfius.php | 4 + .../100/paymentmethod/JTLMollieBitcoin.php | 4 + .../100/paymentmethod/JTLMollieCreditCard.php | 4 + .../paymentmethod/JTLMollieDirectDebit.php | 4 + version/100/paymentmethod/JTLMollieEPS.php | 4 + .../100/paymentmethod/JTLMollieGiftcard.php | 4 + .../100/paymentmethod/JTLMollieGiropay.php | 5 + version/100/paymentmethod/JTLMollieIDEAL.php | 5 + .../100/paymentmethod/JTLMollieINGHomePay.php | 5 + version/100/paymentmethod/JTLMollieKBC.php | 5 + .../paymentmethod/JTLMollieKlarnaPayLater.php | 5 + .../paymentmethod/JTLMollieKlarnaSliceIt.php | 5 + version/100/paymentmethod/JTLMolliePayPal.php | 5 + .../paymentmethod/JTLMolliePaysafecard.php | 5 + version/100/paymentmethod/JTLMollieSofort.php | 5 + version/107/adminmenu/info.php | 23 +- version/107/adminmenu/orders.php | 92 +-- version/107/adminmenu/paymentmethods.php | 22 +- version/107/class/ExclusiveLock.php | 48 +- version/107/class/Helper.php | 83 +-- version/107/class/Model/AbstractModel.php | 4 + version/107/class/Model/Payment.php | 56 +- version/107/class/Mollie.php | 450 ++++++------- version/107/frontend/131_globalinclude.php | 38 +- version/107/frontend/140_smarty.php | 27 +- version/107/frontend/144_notify.php | 15 +- version/107/frontend/181_sync.php | 49 +- version/107/paymentmethod/JTLMollie.php | 331 +++++----- .../107/paymentmethod/JTLMollieApplePay.php | 4 + .../107/paymentmethod/JTLMollieBancontact.php | 4 + .../paymentmethod/JTLMollieBanktransfer.php | 5 + .../107/paymentmethod/JTLMollieBelfius.php | 4 + .../107/paymentmethod/JTLMollieCreditCard.php | 9 +- .../paymentmethod/JTLMollieDirectDebit.php | 4 + version/107/paymentmethod/JTLMollieEPS.php | 4 + .../107/paymentmethod/JTLMollieGiftcard.php | 4 + .../107/paymentmethod/JTLMollieGiropay.php | 5 + version/107/paymentmethod/JTLMollieIDEAL.php | 5 + .../107/paymentmethod/JTLMollieINGHomePay.php | 5 + version/107/paymentmethod/JTLMollieKBC.php | 5 + .../paymentmethod/JTLMollieKlarnaPayLater.php | 5 + .../paymentmethod/JTLMollieKlarnaSliceIt.php | 5 + version/107/paymentmethod/JTLMollieMyBank.php | 5 + version/107/paymentmethod/JTLMolliePayPal.php | 5 + .../paymentmethod/JTLMolliePaysafecard.php | 5 + .../107/paymentmethod/JTLMolliePrzelewy24.php | 5 + version/107/paymentmethod/JTLMollieSofort.php | 5 + version/109/adminmenu/info.php | 23 +- version/109/adminmenu/orders.php | 94 +-- version/109/adminmenu/paymentmethods.php | 22 +- version/109/class/ExclusiveLock.php | 48 +- version/109/class/Helper.php | 87 +-- version/109/class/Model/AbstractModel.php | 4 + version/109/class/Model/Payment.php | 56 +- version/109/class/Mollie.php | 450 ++++++------- version/109/frontend/131_globalinclude.php | 38 +- version/109/frontend/140_smarty.php | 23 +- version/109/frontend/144_notify.php | 16 +- version/109/frontend/181_sync.php | 49 +- version/109/paymentmethod/JTLMollie.php | 320 +++++----- .../109/paymentmethod/JTLMollieApplePay.php | 4 + .../109/paymentmethod/JTLMollieBancontact.php | 4 + .../paymentmethod/JTLMollieBanktransfer.php | 5 + .../109/paymentmethod/JTLMollieBelfius.php | 4 + .../109/paymentmethod/JTLMollieCreditCard.php | 19 +- .../paymentmethod/JTLMollieDirectDebit.php | 4 + version/109/paymentmethod/JTLMollieEPS.php | 4 + .../109/paymentmethod/JTLMollieGiftcard.php | 4 + .../109/paymentmethod/JTLMollieGiropay.php | 5 + version/109/paymentmethod/JTLMollieIDEAL.php | 5 + .../109/paymentmethod/JTLMollieINGHomePay.php | 5 + version/109/paymentmethod/JTLMollieKBC.php | 5 + .../paymentmethod/JTLMollieKlarnaPayLater.php | 5 + .../paymentmethod/JTLMollieKlarnaSliceIt.php | 5 + version/109/paymentmethod/JTLMollieMyBank.php | 5 + version/109/paymentmethod/JTLMolliePayPal.php | 5 + .../paymentmethod/JTLMolliePaysafecard.php | 5 + .../109/paymentmethod/JTLMolliePrzelewy24.php | 5 + version/109/paymentmethod/JTLMollieSofort.php | 5 + version/110/adminmenu/info.php | 23 +- version/110/adminmenu/orders.php | 88 +-- version/110/adminmenu/paymentmethods.php | 45 +- version/110/class/ExclusiveLock.php | 48 +- version/110/class/Helper.php | 87 +-- version/110/class/Model/AbstractModel.php | 4 + version/110/class/Model/Payment.php | 56 +- version/110/class/Mollie.php | 450 ++++++------- version/110/frontend/131_globalinclude.php | 38 +- version/110/frontend/140_smarty.php | 23 +- version/110/frontend/144_notify.php | 16 +- version/110/frontend/181_sync.php | 49 +- version/110/paymentmethod/JTLMollie.php | 338 +++++----- .../110/paymentmethod/JTLMollieApplePay.php | 4 + .../110/paymentmethod/JTLMollieBancontact.php | 4 + .../paymentmethod/JTLMollieBanktransfer.php | 5 + .../110/paymentmethod/JTLMollieBelfius.php | 4 + .../110/paymentmethod/JTLMollieCreditCard.php | 18 +- .../paymentmethod/JTLMollieDirectDebit.php | 4 + version/110/paymentmethod/JTLMollieEPS.php | 4 + .../110/paymentmethod/JTLMollieGiftcard.php | 4 + .../110/paymentmethod/JTLMollieGiropay.php | 5 + version/110/paymentmethod/JTLMollieIDEAL.php | 5 + .../110/paymentmethod/JTLMollieINGHomePay.php | 5 + version/110/paymentmethod/JTLMollieKBC.php | 5 + .../paymentmethod/JTLMollieKlarnaPayLater.php | 5 + .../paymentmethod/JTLMollieKlarnaSliceIt.php | 5 + version/110/paymentmethod/JTLMollieMyBank.php | 5 + version/110/paymentmethod/JTLMolliePayPal.php | 5 + .../paymentmethod/JTLMolliePaysafecard.php | 5 + .../110/paymentmethod/JTLMolliePrzelewy24.php | 5 + version/110/paymentmethod/JTLMollieSofort.php | 5 + version/111/adminmenu/info.php | 23 +- version/111/adminmenu/orders.php | 88 +-- version/111/adminmenu/paymentmethods.php | 45 +- version/111/class/ExclusiveLock.php | 25 +- version/111/class/Helper.php | 87 +-- version/111/class/Model/AbstractModel.php | 4 + version/111/class/Model/Payment.php | 56 +- version/111/class/Mollie.php | 451 ++++++------- version/111/frontend/131_globalinclude.php | 38 +- version/111/frontend/140_smarty.php | 23 +- version/111/frontend/144_notify.php | 16 +- version/111/frontend/181_sync.php | 49 +- version/111/paymentmethod/JTLMollie.php | 338 +++++----- .../111/paymentmethod/JTLMollieApplePay.php | 4 + .../111/paymentmethod/JTLMollieBancontact.php | 4 + .../paymentmethod/JTLMollieBanktransfer.php | 5 + .../111/paymentmethod/JTLMollieBelfius.php | 4 + .../111/paymentmethod/JTLMollieCreditCard.php | 18 +- .../paymentmethod/JTLMollieDirectDebit.php | 4 + version/111/paymentmethod/JTLMollieEPS.php | 4 + .../111/paymentmethod/JTLMollieGiftcard.php | 4 + .../111/paymentmethod/JTLMollieGiropay.php | 5 + version/111/paymentmethod/JTLMollieIDEAL.php | 5 + .../111/paymentmethod/JTLMollieINGHomePay.php | 5 + version/111/paymentmethod/JTLMollieKBC.php | 5 + .../paymentmethod/JTLMollieKlarnaPayLater.php | 5 + .../paymentmethod/JTLMollieKlarnaSliceIt.php | 5 + version/111/paymentmethod/JTLMollieMyBank.php | 5 + version/111/paymentmethod/JTLMolliePayPal.php | 5 + .../paymentmethod/JTLMolliePaysafecard.php | 5 + .../111/paymentmethod/JTLMolliePrzelewy24.php | 5 + version/111/paymentmethod/JTLMollieSofort.php | 5 + version/200/adminmenu/info.php | 23 +- version/200/adminmenu/orders.php | 62 +- version/200/adminmenu/paymentmethods.php | 45 +- version/200/class/API.php | 20 +- .../200/class/Checkout/AbstractCheckout.php | 162 ++--- .../200/class/Checkout/AbstractResource.php | 11 +- .../Exception/ResourceValidityException.php | 9 +- version/200/class/Checkout/Order/Address.php | 23 +- .../200/class/Checkout/Order/OrderLine.php | 107 ++-- version/200/class/Checkout/OrderCheckout.php | 129 ++-- .../200/class/Checkout/Payment/Address.php | 22 +- version/200/class/Checkout/Payment/Amount.php | 19 +- .../200/class/Checkout/PaymentCheckout.php | 83 ++- version/200/class/ExclusiveLock.php | 22 +- version/200/class/Helper.php | 87 +-- version/200/class/Hook/AbstractHook.php | 9 +- version/200/class/Hook/ApplePay.php | 19 +- version/200/class/Hook/Checkbox.php | 47 +- version/200/class/Hook/Queue.php | 32 +- version/200/class/Model/AbstractModel.php | 23 +- version/200/class/Model/Customer.php | 11 +- version/200/class/Model/Payment.php | 7 +- version/200/class/Model/Queue.php | 13 +- version/200/class/Model/Shipment.php | 10 +- version/200/class/Mollie.php | 342 +++++----- version/200/class/Queue.php | 41 +- version/200/class/Shipment.php | 66 +- version/200/class/Traits/Jsonable.php | 8 +- version/200/class/Traits/Plugin.php | 8 +- version/200/class/Traits/RequestData.php | 13 +- version/200/frontend/131_globalinclude.php | 7 +- version/200/frontend/132_headPostGet.php | 8 +- version/200/frontend/140_smarty.php | 15 +- version/200/frontend/180_checkbox.php | 8 +- version/200/frontend/181_sync.php | 5 +- version/200/frontend/210_storno.php | 8 +- version/200/frontend/75_bestellungInDb.php | 8 +- version/200/frontend/applepay.php | 4 + version/200/paymentmethod/JTLMollie.php | 51 +- .../200/paymentmethod/JTLMollieApplePay.php | 5 + .../200/paymentmethod/JTLMollieBancontact.php | 4 + .../paymentmethod/JTLMollieBanktransfer.php | 7 +- .../200/paymentmethod/JTLMollieBelfius.php | 4 + .../200/paymentmethod/JTLMollieCreditCard.php | 21 +- .../paymentmethod/JTLMollieDirectDebit.php | 4 + version/200/paymentmethod/JTLMollieEPS.php | 4 + .../200/paymentmethod/JTLMollieGiftcard.php | 4 + .../200/paymentmethod/JTLMollieGiropay.php | 5 + version/200/paymentmethod/JTLMollieIDEAL.php | 5 + .../200/paymentmethod/JTLMollieINGHomePay.php | 6 +- version/200/paymentmethod/JTLMollieKBC.php | 5 + .../paymentmethod/JTLMollieKlarnaPayLater.php | 5 + .../paymentmethod/JTLMollieKlarnaSliceIt.php | 5 + version/200/paymentmethod/JTLMollieMyBank.php | 5 + version/200/paymentmethod/JTLMolliePayPal.php | 6 +- .../paymentmethod/JTLMolliePaysafecard.php | 5 + .../200/paymentmethod/JTLMolliePrzelewy24.php | 6 +- version/200/paymentmethod/JTLMollieSofort.php | 5 + version/201/adminmenu/info.php | 23 +- version/201/adminmenu/orders.php | 61 +- version/201/adminmenu/paymentmethods.php | 45 +- version/201/class/API.php | 20 +- .../201/class/Checkout/AbstractCheckout.php | 160 ++--- .../201/class/Checkout/AbstractResource.php | 11 +- .../Exception/ResourceValidityException.php | 9 +- version/201/class/Checkout/Order/Address.php | 23 +- .../201/class/Checkout/Order/OrderLine.php | 107 ++-- version/201/class/Checkout/OrderCheckout.php | 129 ++-- .../201/class/Checkout/Payment/Address.php | 22 +- version/201/class/Checkout/Payment/Amount.php | 19 +- .../201/class/Checkout/PaymentCheckout.php | 83 ++- version/201/class/ExclusiveLock.php | 22 +- version/201/class/Helper.php | 87 +-- version/201/class/Hook/AbstractHook.php | 9 +- version/201/class/Hook/ApplePay.php | 19 +- version/201/class/Hook/Checkbox.php | 47 +- version/201/class/Hook/Queue.php | 32 +- version/201/class/Model/AbstractModel.php | 23 +- version/201/class/Model/Customer.php | 11 +- version/201/class/Model/Payment.php | 7 +- version/201/class/Model/Queue.php | 13 +- version/201/class/Model/Shipment.php | 10 +- version/201/class/Mollie.php | 342 +++++----- version/201/class/Queue.php | 41 +- version/201/class/Shipment.php | 66 +- version/201/class/Traits/Jsonable.php | 8 +- version/201/class/Traits/Plugin.php | 8 +- version/201/class/Traits/RequestData.php | 13 +- version/201/frontend/131_globalinclude.php | 7 +- version/201/frontend/132_headPostGet.php | 8 +- version/201/frontend/140_smarty.php | 15 +- version/201/frontend/180_checkbox.php | 8 +- version/201/frontend/181_sync.php | 5 +- version/201/frontend/210_storno.php | 8 +- version/201/frontend/75_bestellungInDb.php | 8 +- version/201/frontend/applepay.php | 4 + version/201/paymentmethod/JTLMollie.php | 55 +- .../201/paymentmethod/JTLMollieApplePay.php | 4 + .../201/paymentmethod/JTLMollieBancontact.php | 4 + .../paymentmethod/JTLMollieBanktransfer.php | 7 +- .../201/paymentmethod/JTLMollieBelfius.php | 4 + .../201/paymentmethod/JTLMollieCreditCard.php | 21 +- .../paymentmethod/JTLMollieDirectDebit.php | 4 + version/201/paymentmethod/JTLMollieEPS.php | 4 + .../201/paymentmethod/JTLMollieGiftcard.php | 4 + .../201/paymentmethod/JTLMollieGiropay.php | 5 + version/201/paymentmethod/JTLMollieIDEAL.php | 5 + .../201/paymentmethod/JTLMollieINGHomePay.php | 6 +- version/201/paymentmethod/JTLMollieKBC.php | 5 + .../paymentmethod/JTLMollieKlarnaPayLater.php | 5 + .../paymentmethod/JTLMollieKlarnaSliceIt.php | 5 + version/201/paymentmethod/JTLMollieMyBank.php | 5 + version/201/paymentmethod/JTLMolliePayPal.php | 6 +- .../paymentmethod/JTLMolliePaysafecard.php | 5 + .../201/paymentmethod/JTLMolliePrzelewy24.php | 6 +- version/201/paymentmethod/JTLMollieSofort.php | 5 + version/202/adminmenu/info.php | 23 +- version/202/adminmenu/orders.php | 60 +- version/202/adminmenu/paymentmethods.php | 45 +- version/202/class/API.php | 20 +- .../202/class/Checkout/AbstractCheckout.php | 161 ++--- .../202/class/Checkout/AbstractResource.php | 11 +- .../Exception/ResourceValidityException.php | 9 +- version/202/class/Checkout/Order/Address.php | 23 +- .../202/class/Checkout/Order/OrderLine.php | 107 ++-- version/202/class/Checkout/OrderCheckout.php | 129 ++-- .../202/class/Checkout/Payment/Address.php | 22 +- version/202/class/Checkout/Payment/Amount.php | 19 +- .../202/class/Checkout/PaymentCheckout.php | 83 ++- version/202/class/ExclusiveLock.php | 22 +- version/202/class/Helper.php | 87 +-- version/202/class/Hook/AbstractHook.php | 9 +- version/202/class/Hook/ApplePay.php | 19 +- version/202/class/Hook/Checkbox.php | 47 +- version/202/class/Hook/Queue.php | 32 +- version/202/class/Model/AbstractModel.php | 23 +- version/202/class/Model/Customer.php | 11 +- version/202/class/Model/Payment.php | 7 +- version/202/class/Model/Queue.php | 13 +- version/202/class/Model/Shipment.php | 10 +- version/202/class/Mollie.php | 342 +++++----- version/202/class/Queue.php | 41 +- version/202/class/Shipment.php | 66 +- version/202/class/Traits/Jsonable.php | 8 +- version/202/class/Traits/Plugin.php | 8 +- version/202/class/Traits/RequestData.php | 13 +- version/202/frontend/131_globalinclude.php | 7 +- version/202/frontend/132_headPostGet.php | 8 +- version/202/frontend/140_smarty.php | 15 +- version/202/frontend/180_checkbox.php | 8 +- version/202/frontend/181_sync.php | 5 +- version/202/frontend/210_storno.php | 8 +- version/202/frontend/75_bestellungInDb.php | 8 +- version/202/frontend/applepay.php | 4 + version/202/paymentmethod/JTLMollie.php | 55 +- .../202/paymentmethod/JTLMollieApplePay.php | 4 + .../202/paymentmethod/JTLMollieBancontact.php | 4 + .../paymentmethod/JTLMollieBanktransfer.php | 7 +- .../202/paymentmethod/JTLMollieBelfius.php | 4 + .../202/paymentmethod/JTLMollieCreditCard.php | 21 +- .../paymentmethod/JTLMollieDirectDebit.php | 4 + version/202/paymentmethod/JTLMollieEPS.php | 4 + .../202/paymentmethod/JTLMollieGiftcard.php | 4 + .../202/paymentmethod/JTLMollieGiropay.php | 5 + version/202/paymentmethod/JTLMollieIDEAL.php | 5 + .../202/paymentmethod/JTLMollieINGHomePay.php | 6 +- version/202/paymentmethod/JTLMollieKBC.php | 5 + .../paymentmethod/JTLMollieKlarnaPayLater.php | 5 + .../paymentmethod/JTLMollieKlarnaSliceIt.php | 5 + version/202/paymentmethod/JTLMollieMyBank.php | 5 + version/202/paymentmethod/JTLMolliePayPal.php | 6 +- .../paymentmethod/JTLMolliePaysafecard.php | 5 + .../202/paymentmethod/JTLMolliePrzelewy24.php | 6 +- version/202/paymentmethod/JTLMollieSofort.php | 5 + version/203/adminmenu/info.php | 23 +- version/203/adminmenu/orders.php | 60 +- version/203/adminmenu/paymentmethods.php | 49 +- version/203/class/API.php | 20 +- .../203/class/Checkout/AbstractCheckout.php | 264 ++++---- .../203/class/Checkout/AbstractResource.php | 11 +- .../Exception/ResourceValidityException.php | 9 +- version/203/class/Checkout/Order/Address.php | 23 +- .../203/class/Checkout/Order/OrderLine.php | 111 ++-- version/203/class/Checkout/OrderCheckout.php | 109 ++-- .../203/class/Checkout/Payment/Address.php | 22 +- version/203/class/Checkout/Payment/Amount.php | 19 +- .../203/class/Checkout/PaymentCheckout.php | 61 +- version/203/class/ExclusiveLock.php | 21 +- version/203/class/Helper.php | 84 +-- version/203/class/Hook/AbstractHook.php | 9 +- version/203/class/Hook/ApplePay.php | 19 +- version/203/class/Hook/Checkbox.php | 47 +- version/203/class/Hook/Queue.php | 34 +- version/203/class/Model/AbstractModel.php | 25 +- version/203/class/Model/Customer.php | 11 +- version/203/class/Model/Payment.php | 7 +- version/203/class/Model/Queue.php | 15 +- version/203/class/Model/Shipment.php | 10 +- version/203/class/Mollie.php | 341 +++++----- version/203/class/Queue.php | 60 +- version/203/class/Shipment.php | 66 +- version/203/class/Traits/Jsonable.php | 8 +- version/203/class/Traits/Plugin.php | 8 +- version/203/class/Traits/RequestData.php | 13 +- version/203/frontend/131_globalinclude.php | 15 +- version/203/frontend/132_headPostGet.php | 8 +- version/203/frontend/140_smarty.php | 15 +- version/203/frontend/180_checkbox.php | 8 +- version/203/frontend/181_sync.php | 5 +- version/203/frontend/210_storno.php | 8 +- version/203/frontend/75_bestellungInDb.php | 8 +- version/203/frontend/applepay.php | 4 + version/203/paymentmethod/JTLMollie.php | 47 +- .../203/paymentmethod/JTLMollieApplePay.php | 4 + .../203/paymentmethod/JTLMollieBancontact.php | 5 +- .../paymentmethod/JTLMollieBanktransfer.php | 7 +- .../203/paymentmethod/JTLMollieBelfius.php | 5 +- .../203/paymentmethod/JTLMollieCreditCard.php | 23 +- .../paymentmethod/JTLMollieDirectDebit.php | 4 + version/203/paymentmethod/JTLMollieEPS.php | 4 + .../203/paymentmethod/JTLMollieGiftcard.php | 4 + .../203/paymentmethod/JTLMollieGiropay.php | 5 + version/203/paymentmethod/JTLMollieIDEAL.php | 6 +- .../203/paymentmethod/JTLMollieINGHomePay.php | 6 +- version/203/paymentmethod/JTLMollieKBC.php | 5 + .../paymentmethod/JTLMollieKlarnaPayLater.php | 5 + .../paymentmethod/JTLMollieKlarnaSliceIt.php | 5 + version/203/paymentmethod/JTLMollieMyBank.php | 6 +- version/203/paymentmethod/JTLMolliePayPal.php | 7 +- .../paymentmethod/JTLMolliePaysafecard.php | 5 + .../203/paymentmethod/JTLMolliePrzelewy24.php | 6 +- version/203/paymentmethod/JTLMollieSofort.php | 6 +- version/204/adminmenu/info.php | 23 +- version/204/adminmenu/orders.php | 60 +- version/204/adminmenu/paymentmethods.php | 50 +- version/204/class/API.php | 20 +- .../204/class/Checkout/AbstractCheckout.php | 590 +++++++++--------- .../204/class/Checkout/AbstractResource.php | 11 +- .../Exception/ResourceValidityException.php | 9 +- version/204/class/Checkout/Order/Address.php | 23 +- .../204/class/Checkout/Order/OrderLine.php | 108 ++-- version/204/class/Checkout/OrderCheckout.php | 107 ++-- .../204/class/Checkout/Payment/Address.php | 22 +- version/204/class/Checkout/Payment/Amount.php | 19 +- .../204/class/Checkout/PaymentCheckout.php | 65 +- version/204/class/ExclusiveLock.php | 21 +- version/204/class/Helper.php | 84 +-- version/204/class/Hook/AbstractHook.php | 9 +- version/204/class/Hook/ApplePay.php | 19 +- version/204/class/Hook/Checkbox.php | 47 +- version/204/class/Hook/Queue.php | 34 +- version/204/class/Model/AbstractModel.php | 25 +- version/204/class/Model/Customer.php | 11 +- version/204/class/Model/Payment.php | 7 +- version/204/class/Model/Queue.php | 15 +- version/204/class/Model/Shipment.php | 10 +- version/204/class/Queue.php | 61 +- version/204/class/Shipment.php | 66 +- version/204/class/Traits/Jsonable.php | 8 +- version/204/class/Traits/Plugin.php | 8 +- version/204/class/Traits/RequestData.php | 14 +- version/204/frontend/131_globalinclude.php | 15 +- version/204/frontend/132_headPostGet.php | 8 +- version/204/frontend/140_smarty.php | 15 +- version/204/frontend/180_checkbox.php | 8 +- version/204/frontend/181_sync.php | 5 +- version/204/frontend/210_storno.php | 8 +- version/204/frontend/75_bestellungInDb.php | 8 +- version/204/frontend/applepay.php | 4 + version/204/paymentmethod/JTLMollie.php | 47 +- .../204/paymentmethod/JTLMollieApplePay.php | 4 + .../204/paymentmethod/JTLMollieBancontact.php | 5 +- .../paymentmethod/JTLMollieBanktransfer.php | 7 +- .../204/paymentmethod/JTLMollieBelfius.php | 5 +- .../204/paymentmethod/JTLMollieCreditCard.php | 23 +- version/204/paymentmethod/JTLMollieEPS.php | 4 + .../204/paymentmethod/JTLMollieGiftcard.php | 4 + .../204/paymentmethod/JTLMollieGiropay.php | 5 + version/204/paymentmethod/JTLMollieIDEAL.php | 6 +- version/204/paymentmethod/JTLMollieKBC.php | 5 + .../paymentmethod/JTLMollieKlarnaPayLater.php | 7 +- .../paymentmethod/JTLMollieKlarnaSliceIt.php | 7 +- version/204/paymentmethod/JTLMollieMyBank.php | 6 +- version/204/paymentmethod/JTLMolliePayPal.php | 7 +- .../paymentmethod/JTLMolliePaysafecard.php | 5 + .../204/paymentmethod/JTLMolliePrzelewy24.php | 6 +- version/204/paymentmethod/JTLMollieSofort.php | 6 +- version/205/adminmenu/info.php | 1 + version/205/adminmenu/orders.php | 5 +- version/205/adminmenu/paymentmethods.php | 1 + version/205/class/API.php | 4 +- .../205/class/Checkout/AbstractCheckout.php | 36 +- .../205/class/Checkout/AbstractResource.php | 1 + .../Exception/ResourceValidityException.php | 1 + version/205/class/Checkout/Order/Address.php | 1 + .../205/class/Checkout/Order/OrderLine.php | 8 +- version/205/class/Checkout/OrderCheckout.php | 19 +- .../205/class/Checkout/Payment/Address.php | 1 + version/205/class/Checkout/Payment/Amount.php | 1 + .../205/class/Checkout/PaymentCheckout.php | 1 + version/205/class/ExclusiveLock.php | 1 + version/205/class/Helper.php | 1 + version/205/class/Hook/AbstractHook.php | 1 + version/205/class/Hook/ApplePay.php | 7 +- version/205/class/Hook/Checkbox.php | 1 + version/205/class/Hook/Queue.php | 13 +- version/205/class/Model/AbstractModel.php | 13 +- version/205/class/Model/Customer.php | 1 + version/205/class/Model/Payment.php | 1 + version/205/class/Model/Queue.php | 1 + version/205/class/Model/Shipment.php | 1 + version/205/class/Queue.php | 7 +- version/205/class/Shipment.php | 1 + version/205/class/Traits/Jsonable.php | 1 + version/205/class/Traits/Plugin.php | 1 + version/205/class/Traits/RequestData.php | 1 + version/205/frontend/131_globalinclude.php | 1 + version/205/frontend/132_headPostGet.php | 1 + version/205/frontend/140_smarty.php | 1 + version/205/frontend/180_checkbox.php | 1 + version/205/frontend/181_sync.php | 1 + version/205/frontend/210_storno.php | 1 + version/205/frontend/75_bestellungInDb.php | 1 + version/205/frontend/applepay.php | 1 + version/205/paymentmethod/JTLMollie.php | 1 + .../205/paymentmethod/JTLMollieApplePay.php | 1 + .../205/paymentmethod/JTLMollieBancontact.php | 1 + .../paymentmethod/JTLMollieBanktransfer.php | 1 + .../205/paymentmethod/JTLMollieBelfius.php | 1 + .../205/paymentmethod/JTLMollieCreditCard.php | 1 + version/205/paymentmethod/JTLMollieEPS.php | 1 + .../205/paymentmethod/JTLMollieGiftcard.php | 1 + .../205/paymentmethod/JTLMollieGiropay.php | 1 + version/205/paymentmethod/JTLMollieIDEAL.php | 1 + version/205/paymentmethod/JTLMollieKBC.php | 1 + .../paymentmethod/JTLMollieKlarnaPayLater.php | 1 + .../paymentmethod/JTLMollieKlarnaSliceIt.php | 1 + version/205/paymentmethod/JTLMollieMyBank.php | 1 + version/205/paymentmethod/JTLMolliePayPal.php | 1 + .../paymentmethod/JTLMolliePaysafecard.php | 1 + .../205/paymentmethod/JTLMolliePrzelewy24.php | 1 + version/205/paymentmethod/JTLMollieSofort.php | 1 + 501 files changed, 8546 insertions(+), 6355 deletions(-) diff --git a/.php-cs-fixer.php b/.php-cs-fixer.php index e9318f1..8f63f08 100644 --- a/.php-cs-fixer.php +++ b/.php-cs-fixer.php @@ -3,7 +3,7 @@ use PhpCsFixer\Config; $finder = PhpCsFixer\Finder::create() - ->in(__DIR__.'/version/205'); + ->in(__DIR__.'/version'); return (new Config()) ->setRiskyAllowed(true) diff --git a/composer.json b/composer.json index b56684f..91b7605 100644 --- a/composer.json +++ b/composer.json @@ -3,9 +3,9 @@ "description": "Mollie", "type": "project", "scripts": { - "phpcbf": "phpcbf --standard=PSR12 --encoding=utf8 -p ./version/205", + "phpcbf": "phpcbf --standard=PSR12 --encoding=utf8 -p ./version", "php-cs-fixer": "php-cs-fixer fix", - "fix": "phpcbf --standard=PSR12 --encoding=utf8 -p ./version/205 && php-cs-fixer fix" + "fix": "phpcbf --standard=PSR12 --encoding=utf8 -p ./version; php-cs-fixer fix" }, "require": { "ext-json": "*", diff --git a/version/100/adminmenu/info.php b/version/100/adminmenu/info.php index 4cfb99b..cbffae6 100644 --- a/version/100/adminmenu/info.php +++ b/version/100/adminmenu/info.php @@ -1,21 +1,26 @@ 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, - 'd' => Helper::getDomain(), + 'p' => Helper::oPlugin()->cPluginID, + 'v' => Helper::oPlugin()->nVersion, + 's' => defined('APPLICATION_VERSION') ? APPLICATION_VERSION : JTL_VERSION, + 'd' => Helper::getDomain(), 'php' => PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION . '.' . PHP_RELEASE_VERSION, ]); diff --git a/version/100/adminmenu/orders.php b/version/100/adminmenu/orders.php index 891f42a..a920236 100644 --- a/version/100/adminmenu/orders.php +++ b/version/100/adminmenu/orders.php @@ -1,4 +1,8 @@ 'danger', 'text' => 'Keine ID angeben!']; + break; } $payment = Payment::getPaymentMollie($_REQUEST['id']); if (!$payment) { $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; + break; } $order = JTLMollie::API()->orders->get($_REQUEST['id']); if ($order->status == OrderStatus::STATUS_CANCELED) { $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung bereits storniert']; + 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); + Mollie::JTLMollie()->doLog('Order refunded:
' . print_r($refund, 1) . '
', '$' . $payment->kID . '#' . $payment->kBestellung . '§' . $payment->cOrderNumber, LOGLEVEL_NOTICE); goto order; + break; case 'cancel': if (!array_key_exists('id', $_REQUEST)) { $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; + break; } $payment = Payment::getPaymentMollie($_REQUEST['id']); if (!$payment) { $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; + break; } $order = JTLMollie::API()->orders->get($_REQUEST['id']); if ($order->status == OrderStatus::STATUS_CANCELED) { $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung bereits storniert']; + 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); + Mollie::JTLMollie()->doLog('Order canceled:
' . print_r($cancel, 1) . '
', '$' . $payment->kID . '#' . $payment->kBestellung . '§' . $payment->cOrderNumber, LOGLEVEL_NOTICE); goto order; + break; case 'capture': if (!array_key_exists('id', $_REQUEST)) { $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; + break; } $payment = Payment::getPaymentMollie($_REQUEST['id']); if (!$payment) { $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; + break; } $order = JTLMollie::API()->orders->get($_REQUEST['id']); if ($order->status !== OrderStatus::STATUS_AUTHORIZED && $order->status !== OrderStatus::STATUS_SHIPPING) { $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Nur autorisierte Zahlungen können erfasst werden!']; + break; } $oBestellung = new Bestellung($payment->kBestellung, true); if (!$oBestellung->kBestellung) { $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung konnte nicht geladen werden!']; + break; } - $logData = '#' . $payment->kBestellung . '$' . $payment->kID . "§" . $oBestellung->cBestellNr; + $logData = '#' . $payment->kBestellung . '$' . $payment->kID . '§' . $oBestellung->cBestellNr; $options = ['lines' => []]; if ($oBestellung->cTracking) { - $tracking = new stdClass(); - $tracking->carrier = $oBestellung->cVersandartName; - $tracking->url = $oBestellung->cTrackingURL; - $tracking->code = $oBestellung->cTracking; + $tracking = new stdClass(); + $tracking->carrier = $oBestellung->cVersandartName; + $tracking->url = $oBestellung->cTrackingURL; + $tracking->code = $oBestellung->cTracking; $options['tracking'] = $tracking; } // CAPTURE ALL - $shipment = JTLMollie::API()->shipments->createFor($order, $options); + $shipment = JTLMollie::API()->shipments->createFor($order, $options); $ordersMsgs[] = (object)['type' => 'success', 'text' => 'Zahlung wurde erfolgreich erfasst!']; Mollie::JTLMollie()->doLog('Shipment created
' . print_r(['options' => $options, 'shipment' => $shipment], 1) . '
', $logData); goto order; case 'order': - order: + order : if (!array_key_exists('id', $_REQUEST)) { $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; + break; } - $order = JTLMollie::API()->orders->get($_REQUEST['id']); + $order = JTLMollie::API()->orders->get($_REQUEST['id']); $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", [ + Shop::DB()->executeQueryPrepared('UPDATE xplugin_ws_mollie_payments SET cOrderNumber = :cBestellNr WHERE kID = :kID', [ ':cBestellNr' => $oBestellung->cBestellNr, - ':kID' => $payment->kID, + ':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", [ + $logs = Shop::DB()->executeQueryPrepared('SELECT * FROM tzahlungslog WHERE cLogData LIKE :kBestellung OR cLogData LIKE :cBestellNr OR cLogData LIKE :MollieID ORDER BY dDatum DESC', [ ':kBestellung' => '%#' . ($payment->kBestellung ?: '##') . '%', - ':cBestellNr' => '%§' . ($payment->cOrderNumber ?: '§§') . '%', - ':MollieID' => '%$' . ($payment->kID ?: '$$') . '%', + ':cBestellNr' => '%§' . ($payment->cOrderNumber ?: '§§') . '%', + ':MollieID' => '%$' . ($payment->kID ?: '$$') . '%', ], 2); Shop::Smarty()->assign('payment', $payment) @@ -129,6 +148,7 @@ ->assign('logs', $logs) ->assign('ordersMsgs', $ordersMsgs); Shop::Smarty()->display($oPlugin->cAdminmenuPfad . '/tpl/order.tpl'); + return; } } @@ -142,13 +162,13 @@ Shop::Smarty()->assign('payments', $payments) ->assign('ordersMsgs', $ordersMsgs) ->assign('admRoot', str_replace('http:', '', $oPlugin->cAdminmenuPfadURL)) - ->assign('hasAPIKey', trim(Helper::getSetting("api_key")) !== ''); + ->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/100/adminmenu/paymentmethods.php b/version/100/adminmenu/paymentmethods.php index ae01887..02dcebf 100644 --- a/version/100/adminmenu/paymentmethods.php +++ b/version/100/adminmenu/paymentmethods.php @@ -1,12 +1,18 @@ setApiKey(Helper::getSetting("api_key")); + $mollie->setApiKey(Helper::getSetting('api_key')); $profile = $mollie->profiles->get('me'); $methods = $mollie->methods->allAvailable([ - 'locale' => 'de_DE', + 'locale' => 'de_DE', 'include' => 'pricing', ]); diff --git a/version/100/class/Helper.php b/version/100/class/Helper.php index cdfcd6a..a01893b 100644 --- a/version/100/class/Helper.php +++ b/version/100/class/Helper.php @@ -1,5 +1,8 @@ short_url != '' ? $release->short_url : $release->full_url; - $filename = basename($release->full_url); - $tmpDir = PFAD_ROOT . PFAD_COMPILEDIR; + $release = self::getLatestRelease(true); + $url = $release->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 @@ -83,8 +85,8 @@ public static function selfupdate() 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 (!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!"); @@ -117,30 +119,29 @@ public static function selfupdate() // 3. UNZIP require_once PFAD_ROOT . PFAD_PCLZIP . 'pclzip.lib.php'; - $zip = new PclZip($tmpDir . $filename); + $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!"); + throw new Exception('Das Zip-Archiv ist leider ung�ltig!'); + } + $unzipPath = PFAD_ROOT . PFAD_PLUGIN; + $res = $zip->extract(PCLZIP_OPT_PATH, $unzipPath); + if ($res !== 0) { + header('Location: ' . Shop::getURL() . DIRECTORY_SEPARATOR . PFAD_ADMIN . 'pluginverwaltung.php', true); } else { - $unzipPath = PFAD_ROOT . PFAD_PLUGIN; - $res = $zip->extract(PCLZIP_OPT_PATH, $unzipPath); - if ($res !== 0) { - header('Location: ' . Shop::getURL() . DIRECTORY_SEPARATOR . PFAD_ADMIN . 'pluginverwaltung.php', true); - } else { - throw new Exception('Entpacken fehlgeschlagen: ' . $zip->errorCode()); - } + throw new Exception('Entpacken fehlgeschlagen: ' . $zip->errorCode()); } } /** * @param bool $force - * @return mixed * @throws Exception + * @return mixed */ public static function getLatestRelease($force = false) { - $lastCheck = (int)self::getSetting(__NAMESPACE__ . '_upd'); + $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__); @@ -151,7 +152,7 @@ public static function getLatestRelease($force = false) @curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); @curl_setopt($curl, CURLOPT_HTTPHEADER, ['Content-Type: application/json']); - $data = curl_exec($curl); + $data = curl_exec($curl); $statusCode = (int)curl_getinfo($curl, CURLINFO_HTTP_CODE); @curl_close($curl); if ($statusCode !== 200) { @@ -163,10 +164,11 @@ public static function getLatestRelease($force = false) } 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); } + + return json_decode($lastRelease); } /** @@ -177,6 +179,7 @@ public static function getLatestRelease($force = false) public static function init() { ini_set('xdebug.default_enable', defined('WS_XDEBUG_ENABLED')); + return self::autoload(); } @@ -189,10 +192,10 @@ public static function init() */ public static function setSetting($name, $value) { - $setting = new stdClass; + $setting = new stdClass(); $setting->kPlugin = self::oPlugin()->kPlugin; - $setting->cName = $name; - $setting->cWert = $value; + $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); @@ -201,6 +204,7 @@ public static function setSetting($name, $value) } self::oPlugin()->oPluginEinstellungAssoc_arr[$name] = $value; self::oPlugin(true); // invalidate cache + return $return; } @@ -208,7 +212,7 @@ public static function setSetting($name, $value) * Get Plugin Object * * @param bool $force disable Cache - * @return Plugin|null + * @return null|Plugin */ public static function oPlugin($force = false) { @@ -217,6 +221,7 @@ public static function oPlugin($force = false) } elseif (null === self::$oPlugin) { self::$oPlugin = Plugin::getPluginById(__NAMESPACE__); } + return self::$oPlugin; } @@ -231,6 +236,7 @@ public static function getSetting($name) if (array_key_exists($name, self::oPlugin()->oPluginEinstellungAssoc_arr)) { return self::oPlugin()->oPluginEinstellungAssoc_arr[$name]; } + return null; } @@ -242,8 +248,9 @@ public static function getSetting($name) */ public static function getDomain($url = URL_SHOP) { - $matches = array(); + $matches = []; @preg_match("/^((http(s)?):\/\/)?(www\.)?([a-zA-Z0-9-\.]+)(\/.*)?$/i", $url, $matches); + return strtolower(isset($matches[5]) ? $matches[5] : $url); } @@ -252,13 +259,14 @@ public static function getDomain($url = URL_SHOP) */ private static function _masterMail() { - $settings = Shop::getSettings(array(CONF_EMAILS)); + $settings = Shop::getSettings([CONF_EMAILS]); + return $settings['emails']['email_master_absender']; } /** * @param Exception $exc - * @param bool $trace + * @param bool $trace * @return void */ public static function logExc(Exception $exc, $trace = true) @@ -288,9 +296,11 @@ public static function getAdminmenu($name) foreach (self::oPlugin()->oPluginAdminMenu_arr as $adminmenu) { if (strtolower($adminmenu->cName) == strtolower($name)) { $kPluginAdminMenu = $adminmenu->kPluginAdminMenu; + break; } } + return $kPluginAdminMenu; } } diff --git a/version/100/class/Model/AbstractModel.php b/version/100/class/Model/AbstractModel.php index 5638700..d8e07cf 100644 --- a/version/100/class/Model/AbstractModel.php +++ b/version/100/class/Model/AbstractModel.php @@ -1,4 +1,8 @@ $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, + ':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, + ':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, + ':dCreatedAt' => $oMolliePayment->createdAt ? date('Y-m-d H:i:s', strtotime($oMolliePayment->createdAt)) : null, ]; + 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) ' @@ -54,6 +59,7 @@ public static function getPayment($kBestellung) if ($payment && $payment->kBestellung) { $payment->oBestellung = new Bestellung($payment->kBestellung, false); } + return $payment; } @@ -63,6 +69,7 @@ public static function getPaymentMollie($kID) if ($payment && $payment->kBestellung) { $payment->oBestellung = new Bestellung($payment->kBestellung, false); } + return $payment; } @@ -72,6 +79,7 @@ public static function getPaymentHash($cHash) if ($payment && $payment->kBestellung) { $payment->oBestellung = new Bestellung($payment->kBestellung, false); } + return $payment; } } diff --git a/version/100/class/Mollie.php b/version/100/class/Mollie.php index 6ad4b88..aab5c85 100644 --- a/version/100/class/Mollie.php +++ b/version/100/class/Mollie.php @@ -1,9 +1,7 @@ getValue(CONF_KAUFABWICKLUNG, 'bestellabschluss_abschlussseite'); - $bestellid = Shop::DB()->select("tbestellid ", 'kBestellung', (int)$kBestellung); - $url = Shop::getURL() . '/bestellabschluss.php?i=' . $bestellid->cId; + $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; + $url = Shop::getURL() . '/status.php?uid=' . $bestellstatus->cUID; } if ($redirect) { header('Location: ' . $url); exit(); } + return $url; } @@ -54,8 +53,8 @@ public static function getOrderCompletedRedirect($kBestellung, $redirect = true) * @param Order $order * @param $kBestellung * @param bool $newStatus - * @return array * @throws Exception + * @return array */ public static function getShipmentOptions(Order $order, $kBestellung, $newStatus = false) { @@ -72,28 +71,29 @@ public static function getShipmentOptions(Order $order, $kBestellung, $newStatus // Tracking Data if ($oBestellung->cTracking) { - $tracking = new stdClass(); - $tracking->carrier = $oBestellung->cVersandartName; - $tracking->url = $oBestellung->cTrackingURL; - $tracking->code = $oBestellung->cTracking; + $tracking = new stdClass(); + $tracking->carrier = $oBestellung->cVersandartName; + $tracking->url = $oBestellung->cTrackingURL; + $tracking->code = $oBestellung->cTracking; $options['tracking'] = $tracking; } switch ((int)$newStatus) { case BESTELLUNG_STATUS_VERSANDT: $options['lines'] = []; + break; case BESTELLUNG_STATUS_TEILVERSANDT: $lines = []; foreach ($order->lines as $i => $line) { - if (($quantity = Mollie::getBestellPosSent($line->sku, $oBestellung)) !== false && ($quantity - $line->quantityShipped) > 0) { - $x = $quantity - $line->quantityShipped; + if (($quantity = self::getBestellPosSent($line->sku, $oBestellung)) !== false && ($quantity - $line->quantityShipped) > 0) { + $x = $quantity - $line->quantityShipped; $lines[] = (object)[ - 'id' => $line->id, + 'id' => $line->id, 'quantity' => $x, - 'amount' => (object)[ + 'amount' => (object)[ 'currency' => $line->totalAmount->currency, - 'value' => number_format($x * $line->unitPrice->value, 2), + 'value' => number_format($x * $line->unitPrice->value, 2), ], ]; } @@ -101,9 +101,11 @@ public static function getShipmentOptions(Order $order, $kBestellung, $newStatus if (count($lines)) { $options['lines'] = $lines; } + break; case BESTELLUNG_STATUS_STORNO: $options = null; + break; } @@ -114,8 +116,8 @@ public static function getShipmentOptions(Order $order, $kBestellung, $newStatus * Returns amount of sent items for SKU * @param $sku * @param Bestellung $oBestellung - * @return float|int * @throws Exception + * @return float|int */ public static function getBestellPosSent($sku, Bestellung $oBestellung) { @@ -135,28 +137,30 @@ public static function getBestellPosSent($sku, Bestellung $oBestellung) } } } + return $sent; } } + return false; } /** * @param Order $order - * @param null $kBestellung - * @return bool + * @param null $kBestellung * @throws Exception + * @return bool */ public static function handleOrder(Order $order, $kBestellung) { - $logData = '$' . $order->id . '#' . $kBestellung . "§" . $order->orderNumber; + $logData = '$' . $order->id . '#' . $kBestellung . '§' . $order->orderNumber; $oBestellung = new Bestellung($kBestellung); if ($oBestellung->kBestellung) { $order->orderNumber = $oBestellung->cBestellNr; Payment::updateFromPayment($order, $kBestellung); - $oIncomingPayment = Shop::DB()->executeQueryPrepared("SELECT * FROM tzahlungseingang WHERE cHinweis = :cHinweis AND kBestellung = :kBestellung", [':cHinweis' => $order->id, ':kBestellung' => $oBestellung->kBestellung], 1); + $oIncomingPayment = Shop::DB()->executeQueryPrepared('SELECT * FROM tzahlungseingang WHERE cHinweis = :cHinweis AND kBestellung = :kBestellung', [':cHinweis' => $order->id, ':kBestellung' => $oBestellung->kBestellung], 1); if (!$oIncomingPayment) { $oIncomingPayment = new stdClass(); } @@ -165,43 +169,49 @@ public static function handleOrder(Order $order, $kBestellung) switch ($order->status) { case OrderStatus::STATUS_PAID: case OrderStatus::STATUS_COMPLETED: - $oIncomingPayment->fBetrag = $order->amount->value; - $oIncomingPayment->cISO = $order->amount->curreny; + $oIncomingPayment->fBetrag = $order->amount->value; + $oIncomingPayment->cISO = $order->amount->curreny; $oIncomingPayment->cHinweis = $order->id; - Mollie::JTLMollie()->addIncomingPayment($oBestellung, $oIncomingPayment); - Mollie::JTLMollie()->setOrderStatusToPaid($oBestellung); - Mollie::JTLMollie()->doLog('PaymentStatus: ' . $order->status . ' => Zahlungseingang (' . $order->amount->value . ')', $logData, LOGLEVEL_DEBUG); + self::JTLMollie()->addIncomingPayment($oBestellung, $oIncomingPayment); + self::JTLMollie()->setOrderStatusToPaid($oBestellung); + self::JTLMollie()->doLog('PaymentStatus: ' . $order->status . ' => Zahlungseingang (' . $order->amount->value . ')', $logData, LOGLEVEL_DEBUG); + break; case OrderStatus::STATUS_SHIPPING: case OrderStatus::STATUS_AUTHORIZED: case OrderStatus::STATUS_PENDING: - Mollie::JTLMollie()->setOrderStatusToPaid($oBestellung); - Mollie::JTLMollie()->doLog('PaymentStatus: ' . $order->status . ' => Bestellung bezahlt', $logData, LOGLEVEL_NOTICE); + self::JTLMollie()->setOrderStatusToPaid($oBestellung); + self::JTLMollie()->doLog('PaymentStatus: ' . $order->status . ' => Bestellung bezahlt', $logData, LOGLEVEL_NOTICE); + break; case OrderStatus::STATUS_CANCELED: case OrderStatus::STATUS_EXPIRED: - Mollie::JTLMollie()->doLog('PaymentStatus: ' . $order->status, $logData, LOGLEVEL_ERROR); + self::JTLMollie()->doLog('PaymentStatus: ' . $order->status, $logData, LOGLEVEL_ERROR); + break; } + return true; } + return false; } /** - * @return JTLMollie * @throws Exception + * @return JTLMollie */ 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!"); + throw new Exception('Mollie Zahlungsart nicht in DB gefunden!'); } require_once __DIR__ . '/../paymentmethod/JTLMollie.php'; self::$_jtlmollie = new JTLMollie($pza->cModulId); } + return self::$_jtlmollie; } } diff --git a/version/100/frontend/131_globalinclude.php b/version/100/frontend/131_globalinclude.php index 45d4c6f..3cbb607 100644 --- a/version/100/frontend/131_globalinclude.php +++ b/version/100/frontend/131_globalinclude.php @@ -1,4 +1,8 @@ executeQueryPrepared("SELECT * FROM " . \ws_mollie\Model\Payment::TABLE . " WHERE cHash = :cHash", [':cHash' => $_REQUEST['mollie']], 1); + $payment = Shop::DB()->executeQueryPrepared('SELECT * FROM ' . \ws_mollie\Model\Payment::TABLE . ' WHERE cHash = :cHash', [':cHash' => $_REQUEST['mollie']], 1); // Bestellung finalized, redirect to status/completion page if ((int)$payment->kBestellung) { - $logData = '$' . $payment->kID . '#' . $payment->kBestellung . "§" . $payment->cOrderNumber; + $logData = '$' . $payment->kID . '#' . $payment->kBestellung . '§' . $payment->cOrderNumber; Mollie::JTLMollie()->doLog('Bestellung finalized => redirect abschluss/status', $logData); $order = JTLMollie::API()->orders->get($payment->kID, ['embed' => 'payments']); Mollie::handleOrder($order, $payment->kBestellung); Mollie::getOrderCompletedRedirect($payment->kBestellung, true); } elseif ($payment) { // payment, but no order => finalize it require_once __DIR__ . '/../paymentmethod/JTLMollie.php'; - $order = JTLMollie::API()->orders->get($payment->kID, ['embed' => 'payments']); - $logData = '$' . $order->id . '#' . $payment->kBestellung . "§" . $payment->cOrderNumber; + $order = JTLMollie::API()->orders->get($payment->kID, ['embed' => 'payments']); + $logData = '$' . $order->id . '#' . $payment->kBestellung . '§' . $payment->cOrderNumber; // GET NEWEST PAYMENT: /** @var Payment $_payment */ @@ -35,6 +40,7 @@ foreach ($order->payments() as $p) { if (!$_payment) { $_payment = $p; + continue; } if (strtotime($p->createdAt) > strtotime($_payment->createdAt)) { diff --git a/version/100/frontend/140_smarty.php b/version/100/frontend/140_smarty.php index 56a6400..9e229f3 100644 --- a/version/100/frontend/140_smarty.php +++ b/version/100/frontend/140_smarty.php @@ -1,4 +1,8 @@ - Update Payment, stop skript - * - ELSE weiter mit der notify.php + * @copyright 2021 WebStollen GmbH + * @link https://www.webstollen.de */ use ws_mollie\Helper; @@ -12,13 +10,14 @@ if (array_key_exists('hash', $_REQUEST)) { require_once __DIR__ . '/../class/Helper.php'; + try { Helper::init(); $payment = Payment::getPaymentHash($_REQUEST['hash']); // If Bestellung already exists, treat as Notification if ($payment && $payment->kBestellung) { require_once __DIR__ . '/../paymentmethod/JTLMollie.php'; - $order = JTLMollie::API()->orders->get($payment->kID); + $order = JTLMollie::API()->orders->get($payment->kID); $logData = '#' . $payment->kBestellung . '$' . $payment->kID; Mollie::JTLMollie()->doLog('Received Notification
' . print_r([$order, $payment], 1) . '
', $logData); Mollie::handleOrder($order, $payment->kBestellung); diff --git a/version/100/frontend/181_sync.php b/version/100/frontend/181_sync.php index 5fb008e..11d0f3a 100644 --- a/version/100/frontend/181_sync.php +++ b/version/100/frontend/181_sync.php @@ -1,4 +1,8 @@ kBestellung && $payment = Payment::getPayment($oBestellung->kBestellung)) { - $logData = '#' . $payment->kBestellung . '$' . $payment->kID . "§" . $oBestellung->cBestellNr; - Mollie::JTLMollie()->doLog("WAWI Abgleich: HOOK_BESTELLUNGEN_XML_BESTELLSTATUS", $logData); + $logData = '#' . $payment->kBestellung . '$' . $payment->kID . '§' . $oBestellung->cBestellNr; + Mollie::JTLMollie()->doLog('WAWI Abgleich: HOOK_BESTELLUNGEN_XML_BESTELLSTATUS', $logData); + try { - $order = JTLMollie::API()->orders->get($payment->kID); + $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()) { - Mollie::JTLMollie()->doLog("Create Shippment:
" . print_r($args_arr, 1) . '
', $logData, LOGLEVEL_DEBUG); + Mollie::JTLMollie()->doLog('Create Shippment:
' . print_r($args_arr, 1) . '
', $logData, LOGLEVEL_DEBUG); $options = Mollie::getShipmentOptions($order, $oBestellung->kBestellung, $status); if ($options && array_key_exists('lines', $options) && is_array($options['lines'])) { require_once __DIR__ . '/../paymentmethod/JTLMollie.php'; diff --git a/version/100/paymentmethod/JTLMollie.php b/version/100/paymentmethod/JTLMollie.php index dd85c3e..295bfcd 100644 --- a/version/100/paymentmethod/JTLMollie.php +++ b/version/100/paymentmethod/JTLMollie.php @@ -1,4 +1,8 @@ (int)$order->kBestellung, + 'kBestellung' => (int)$order->kBestellung, 'cZahlungsanbieter' => empty($order->cZahlungsartName) ? $this->name : $order->cZahlungsartName, - 'fBetrag' => 0, - 'fZahlungsgebuehr' => 0, - 'cISO' => $_SESSION['Waehrung']->cISO, - 'cEmpfaenger' => '', - 'cZahler' => '', - 'dZeit' => 'now()', - 'cHinweis' => '', - 'cAbgeholt' => 'N' + 'fBetrag' => 0, + 'fZahlungsgebuehr' => 0, + 'cISO' => $_SESSION['Waehrung']->cISO, + 'cEmpfaenger' => '', + 'cZahler' => '', + 'dZeit' => 'now()', + 'cHinweis' => '', + 'cAbgeholt' => 'N' ], (array)$payment); if (isset($model->kZahlungseingang) && $model->kZahlungseingang > 0) { Shop::DB()->update('tzahlungseingang', 'kZahlungseingang', $model->kZahlungseingang, $model); @@ -110,7 +114,8 @@ public function setOrderStatusToPaid($order) */ public function preparePaymentProcess($order) { - $logData = '#' . $order->kBestellung . "" . $order->cBestellNr; + $logData = '#' . $order->kBestellung . '' . $order->cBestellNr; + try { $payment = Payment::getPayment($order->kBestellung); if ($payment && in_array($payment->cStatus, [OrderStatus::STATUS_CREATED]) && $payment->cCheckoutURL) { @@ -122,15 +127,15 @@ public function preparePaymentProcess($order) exit(); } } catch (Exception $e) { - $this->doLog("Get Payment Error: " . $e->getMessage() . ". Create new ORDER...", $logData); + $this->doLog('Get Payment Error: ' . $e->getMessage() . '. Create new ORDER...', $logData); } try { - $hash = $this->generateHash($order); - $oMolliePayment = self::API()->orders->create($this->getOrderData($order, $hash)); + $hash = $this->generateHash($order); + $oMolliePayment = self::API()->orders->create($this->getOrderData($order, $hash)); $_SESSION['oMolliePayment'] = $oMolliePayment; $logData .= '$' . $oMolliePayment->id; - $this->doLog('Mollie Create Payment Redirect: ' . $oMolliePayment->getCheckoutUrl() . "
" . print_r($oMolliePayment, 1) . "
", $logData, LOGLEVEL_DEBUG); + $this->doLog('Mollie Create Payment Redirect: ' . $oMolliePayment->getCheckoutUrl() . '
' . print_r($oMolliePayment, 1) . '
', $logData, LOGLEVEL_DEBUG); Payment::updateFromPayment($oMolliePayment, $order->kBestellung, md5($hash)); Shop::Smarty()->assign('oMolliePayment', $oMolliePayment); if (!$this->duringCheckout) { @@ -140,26 +145,27 @@ public function preparePaymentProcess($order) exit(); } catch (ApiException $e) { Shop::Smarty()->assign('oMollieException', $e); - $this->doLog("Create Payment Error: " . $e->getMessage() . '
' . print_r($e->getTrace(), 1) . '
', $logData); + $this->doLog('Create Payment Error: ' . $e->getMessage() . '
' . print_r($e->getTrace(), 1) . '
', $logData); } } /** * @param string $msg - * @param null $data - * @param int $level + * @param null $data + * @param int $level * @return $this */ public function doLog($msg, $data = null, $level = LOGLEVEL_NOTICE) { ZahlungsLog::add($this->moduleID, $msg, $data, $level); + return $this; } /** - * @return MollieApiClient * @throws ApiException * @throws IncompatiblePlatform + * @return MollieApiClient */ public static function API() { @@ -167,6 +173,7 @@ public static function API() self::$_mollie = new MollieApiClient(); self::$_mollie->setApiKey(Helper::getSetting('api_key')); } + return self::$_mollie; } @@ -178,61 +185,61 @@ public static function API() protected function getOrderData(Bestellung $order, $hash) { $locale = self::getLocale($_SESSION['cISOSprache'], $_SESSION['Kunde']->cLand); - $data = [ + $data = [ 'locale' => $locale ?: 'de_DE', 'amount' => (object)[ 'currency' => $order->Waehrung->cISO, - 'value' => number_format($order->fGesamtsummeKundenwaehrung, 2, '.', ''), + 'value' => number_format($order->fGesamtsummeKundenwaehrung, 2, '.', ''), ], - 'orderNumber' => $order->cBestellNr, - 'lines' => [], - 'billingAddress' => new stdClass(), + 'orderNumber' => $order->cBestellNr, + 'lines' => [], + 'billingAddress' => new stdClass(), 'shippingAddress' => new stdClass(), - 'redirectUrl' => (int)$this->duringCheckout ? Shop::getURL() . '/bestellabschluss.php?mollie=' . md5($hash) : $this->getReturnURL($order), - 'webhookUrl' => $this->getNotificationURL($hash) . '&hash=' . md5($hash), + 'redirectUrl' => (int)$this->duringCheckout ? Shop::getURL() . '/bestellabschluss.php?mollie=' . md5($hash) : $this->getReturnURL($order), + 'webhookUrl' => $this->getNotificationURL($hash) . '&hash=' . md5($hash), ]; if (static::MOLLIE_METHOD !== '') { $data['method'] = static::MOLLIE_METHOD; } $data['billingAddress']->organizationName = utf8_encode($order->oRechnungsadresse->cFirma); - $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 = $order->oRechnungsadresse->cMail; - $data['billingAddress']->streetAndNumber = utf8_encode($order->oRechnungsadresse->cStrasse . ' ' . $order->oRechnungsadresse->cHausnummer); - $data['billingAddress']->postalCode = $order->oRechnungsadresse->cPLZ; - $data['billingAddress']->city = utf8_encode($order->oRechnungsadresse->cOrt); - $data['billingAddress']->country = $order->oRechnungsadresse->cLand; + $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 = $order->oRechnungsadresse->cMail; + $data['billingAddress']->streetAndNumber = utf8_encode($order->oRechnungsadresse->cStrasse . ' ' . $order->oRechnungsadresse->cHausnummer); + $data['billingAddress']->postalCode = $order->oRechnungsadresse->cPLZ; + $data['billingAddress']->city = utf8_encode($order->oRechnungsadresse->cOrt); + $data['billingAddress']->country = $order->oRechnungsadresse->cLand; //if ((int)$order->kLieferadresse) { $data['shippingAddress']->organizationName = utf8_encode($order->Lieferadresse->cFirma); - $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 = $order->oRechnungsadresse->cMail; - $data['shippingAddress']->streetAndNumber = utf8_encode($order->Lieferadresse->cStrasse . ' ' . $order->Lieferadresse->cHausnummer); - $data['shippingAddress']->postalCode = $order->Lieferadresse->cPLZ; - $data['shippingAddress']->city = utf8_encode($order->Lieferadresse->cOrt); - $data['shippingAddress']->country = $order->Lieferadresse->cLand; + $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 = $order->oRechnungsadresse->cMail; + $data['shippingAddress']->streetAndNumber = utf8_encode($order->Lieferadresse->cStrasse . ' ' . $order->Lieferadresse->cHausnummer); + $data['shippingAddress']->postalCode = $order->Lieferadresse->cPLZ; + $data['shippingAddress']->city = utf8_encode($order->Lieferadresse->cOrt); + $data['shippingAddress']->country = $order->Lieferadresse->cLand; //} /** @var WarenkorbPos $oPosition */ foreach ($order->Positionen as $oPosition) { - $line = new stdClass(); - $line->name = utf8_encode($oPosition->cName); - $line->quantity = $oPosition->nAnzahl; + $line = new stdClass(); + $line->name = utf8_encode($oPosition->cName); + $line->quantity = $oPosition->nAnzahl; $line->unitPrice = (object)[ - 'value' => number_format($order->Waehrung->fFaktor * ($oPosition->fPreis * ((float)$oPosition->fMwSt / 100 + 1)), 2, '.', ''), + 'value' => number_format($order->Waehrung->fFaktor * ($oPosition->fPreis * ((float)$oPosition->fMwSt / 100 + 1)), 2, '.', ''), 'currency' => $order->Waehrung->cISO, ]; $line->totalAmount = (object)[ - 'value' => number_format($oPosition->nAnzahl * (float)$line->unitPrice->value, 2, '.', ''), + 'value' => number_format($oPosition->nAnzahl * (float)$line->unitPrice->value, 2, '.', ''), 'currency' => $order->Waehrung->cISO, ]; - $line->vatRate = $oPosition->fMwSt; + $line->vatRate = $oPosition->fMwSt; $line->vatAmount = (object)[ - 'value' => number_format($line->totalAmount->value - ($line->totalAmount->value / (1 + (float)$oPosition->fMwSt / 100)), 2, '.', ''), + 'value' => number_format($line->totalAmount->value - ($line->totalAmount->value / (1 + (float)$oPosition->fMwSt / 100)), 2, '.', ''), 'currency' => $order->Waehrung->cISO, ]; @@ -240,10 +247,12 @@ protected function getOrderData(Bestellung $order, $hash) case (int)C_WARENKORBPOS_TYP_GRATISGESCHENK: case (int)C_WARENKORBPOS_TYP_ARTIKEL: $line->type = OrderLineType::TYPE_PHYSICAL; - $line->sku = $oPosition->cArtNr; + $line->sku = $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: @@ -251,11 +260,13 @@ protected function getOrderData(Bestellung $order, $hash) 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)) { @@ -264,25 +275,25 @@ protected function getOrderData(Bestellung $order, $hash) } if ((int)$order->GuthabenNutzen === 1 && $order->fGuthaben < 0) { - $line = new stdClass(); - $line->type = OrderLineType::TYPE_STORE_CREDIT; - $line->name = 'Guthaben'; - $line->quantity = 1; + $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, '.', ''), + 'value' => number_format($order->Waehrung->fFaktor * $order->fGuthaben, 2, '.', ''), 'currency' => $order->Waehrung->cISO, ]; $line->unitPrice = (object)[ - 'value' => number_format($order->Waehrung->fFaktor * $order->fGuthaben, 2, '.', ''), + '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, '.', ''), + 'value' => number_format($order->Waehrung->fFaktor * $order->fGuthaben, 2, '.', ''), 'currency' => $order->Waehrung->cISO, ]; - $line->vatRate = "0.00"; + $line->vatRate = '0.00'; $line->vatAmount = (object)[ - 'value' => number_format(0, 2, '.', ''), + 'value' => number_format(0, 2, '.', ''), 'currency' => $order->Waehrung->cISO, ]; $data['lines'][] = $line; @@ -296,25 +307,25 @@ protected function getOrderData(Bestellung $order, $hash) 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 = 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, '.', ''), + 'value' => number_format($diff, 2, '.', ''), 'currency' => $order->Waehrung->cISO, ]; $line->unitPrice = (object)[ - 'value' => number_format($diff, 2, '.', ''), + 'value' => number_format($diff, 2, '.', ''), 'currency' => $order->Waehrung->cISO, ]; $line->totalAmount = (object)[ - 'value' => number_format($diff, 2, '.', ''), + 'value' => number_format($diff, 2, '.', ''), 'currency' => $order->Waehrung->cISO, ]; - $line->vatRate = "0.00"; + $line->vatRate = '0.00'; $line->vatAmount = (object)[ - 'value' => number_format(0, 2, '.', ''), + 'value' => number_format(0, 2, '.', ''), 'currency' => $order->Waehrung->cISO, ]; $data['lines'][] = $line; @@ -327,60 +338,63 @@ protected function getOrderData(Bestellung $order, $hash) public static function getLocale($cISOSprache, $country = null) { switch ($cISOSprache) { - case "ger": - if ($country === "AT") { - return "de_AT"; + case 'ger': + if ($country === 'AT') { + return 'de_AT'; } - if ($country === "CH") { - return "de_CH"; + if ($country === 'CH') { + return 'de_CH'; } - return "de_DE"; - case "eng": - return "en_US"; - case "fre": - if ($country === "BE") { - return "fr_BE"; + + return 'de_DE'; + case 'eng': + return 'en_US'; + case 'fre': + if ($country === 'BE') { + return 'fr_BE'; } - return "fr_FR"; - case "dut": - if ($country === "BE") { - return "nl_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"; + + 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"; + return 'en_US'; } } /** * @param Bestellung $order - * @param string $hash - * @param array $args + * @param string $hash + * @param array $args */ public function handleNotification($order, $hash, $args) { Helper::autoload(); - $logData = '#' . $order->kBestellung . "" . $order->cBestellNr; + $logData = '#' . $order->kBestellung . '' . $order->cBestellNr; $this->doLog('Received Notification
' . print_r([$hash, $args], 1) . '
', $logData, LOGLEVEL_NOTICE); try { @@ -393,24 +407,27 @@ public function handleNotification($order, $hash, $args) /** * @param Bestellung $order - * @param string $hash - * @param array $args + * @param string $hash + * @param array $args * * @return true, if $order should be finalized */ public function finalizeOrder($order, $hash, $args) { - $logData = '#' . $order->kBestellung . "" . $order->cBestellNr; + $logData = '#' . $order->kBestellung . '' . $order->cBestellNr; + try { Helper::autoload(); $oMolliePayment = self::API()->orders->get($args['id'], ['embed' => 'payments']); $logData .= '$' . $oMolliePayment->id; $this->doLog('Received Notification Finalize Order
' . print_r([$hash, $args, $oMolliePayment], 1) . '
', $logData, LOGLEVEL_DEBUG); Payment::updateFromPayment($oMolliePayment, $order->kBestellung); + return in_array($oMolliePayment->status, [OrderStatus::STATUS_PAID, OrderStatus::STATUS_AUTHORIZED, OrderStatus::STATUS_PENDING, OrderStatus::STATUS_COMPLETED]); } catch (Exception $e) { $this->doLog($e->getMessage(), $logData); } + return false; } @@ -433,19 +450,23 @@ public function isSelectable() if (static::MOLLIE_METHOD !== '') { try { /** @var Warenkorb $wk */ - $wk = $_SESSION['Warenkorb']; + $wk = $_SESSION['Warenkorb']; $method = self::PossiblePaymentMethods(static::MOLLIE_METHOD, $locale, $_SESSION['Kunde']->cLand, $_SESSION['Waehrung']->cISO, $wk->gibGesamtsummeWaren() * $_SESSION['Waehrung']->fFaktor); if ($method !== null) { $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; } } + return true; } @@ -455,9 +476,9 @@ public function isSelectable() * @param $billingCountry * @param $currency * @param $amount - * @return mixed|null * @throws ApiException * @throws IncompatiblePlatform + * @return null|mixed */ protected static function PossiblePaymentMethods($method, $locale, $billingCountry, $currency, $amount) { @@ -471,8 +492,10 @@ protected static function PossiblePaymentMethods($method, $locale, $billingCount return $m; } } + return null; } + return self::$_possiblePaymentMethods[$key]; } @@ -487,33 +510,34 @@ protected function updatePaymentMethod($cISOSprache, $method) } $size = ws_mollie\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); + 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' => '', + ':kZahlungsart' => (int)$za->kZahlungsart, + ':cISOSprache' => $cISOSprache, + ':cName' => utf8_decode($method->description), + ':cGebuehrname' => '', + ':cHinweisText' => '', ':cHinweisTextShop' => utf8_decode($method->description), - 'cName1' => $method->description, + 'cName1' => $method->description, ], 3); } } /** * - * @param object $customer + * @param object $customer * @param Warenkorb $cart * @return bool - true, if $customer with $cart may use Payment Method */ public function isValid($customer, $cart) { - if (Helper::init() && Helper::getSetting("api_key")) { + if (Helper::init() && Helper::getSetting('api_key')) { return true; } - $this->doLog("isValdid failed: init failed or no API Key given. Try clear the Cache."); + $this->doLog('isValdid failed: init failed or no API Key given. Try clear the Cache.'); + return false; } @@ -523,10 +547,11 @@ public function isValid($customer, $cart) */ public function isValidIntern($args_arr = []) { - if (Helper::init() && Helper::getSetting("api_key")) { + if (Helper::init() && Helper::getSetting('api_key')) { return true; } - $this->doLog("isValdid failed: init failed or no API Key given. Try clear the Cache."); + $this->doLog('isValdid failed: init failed or no API Key given. Try clear the Cache.'); + return false; } } diff --git a/version/100/paymentmethod/JTLMollieBancontact.php b/version/100/paymentmethod/JTLMollieBancontact.php index 0e5eeed..764f588 100644 --- a/version/100/paymentmethod/JTLMollieBancontact.php +++ b/version/100/paymentmethod/JTLMollieBancontact.php @@ -1,4 +1,8 @@ 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)), + '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, ]); @@ -45,7 +50,6 @@ if ((int)Helper::oPlugin()->nVersion < (int)$latestRelease->version) { Shop::Smarty()->assign('update', $latestRelease); } - } catch (\Exception $e) { } @@ -57,8 +61,7 @@ } catch (Exception $e) { } } - } catch (Exception $e) { echo "
Fehler: {$e->getMessage()}
"; Helper::logExc($e); -} \ No newline at end of file +} diff --git a/version/107/adminmenu/orders.php b/version/107/adminmenu/orders.php index 9a584d7..bf3f642 100644 --- a/version/107/adminmenu/orders.php +++ b/version/107/adminmenu/orders.php @@ -1,4 +1,8 @@ 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'), + ':To' => $to->format('Y-m-d'), ], 2); @@ -62,23 +64,23 @@ $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, + '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, + '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; + $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) { @@ -94,116 +96,129 @@ fclose($out); exit(); - } catch (Exception $e) { $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Fehler:' . $e->getMessage()]; } + break; case 'refund': if (!array_key_exists('id', $_REQUEST)) { $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; + break; } $payment = Payment::getPaymentMollie($_REQUEST['id']); if (!$payment) { $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; + break; } $order = JTLMollie::API()->orders->get($_REQUEST['id']); if ($order->status == OrderStatus::STATUS_CANCELED) { $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung bereits storniert']; + 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); + Mollie::JTLMollie()->doLog('Order refunded:
' . print_r($refund, 1) . '
', '$' . $payment->kID . '#' . $payment->kBestellung . '§' . $payment->cOrderNumber, LOGLEVEL_NOTICE); goto order; + break; case 'cancel': if (!array_key_exists('id', $_REQUEST)) { $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; + break; } $payment = Payment::getPaymentMollie($_REQUEST['id']); if (!$payment) { $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; + break; } $order = JTLMollie::API()->orders->get($_REQUEST['id']); if ($order->status == OrderStatus::STATUS_CANCELED) { $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung bereits storniert']; + 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); + Mollie::JTLMollie()->doLog('Order canceled:
' . print_r($cancel, 1) . '
', '$' . $payment->kID . '#' . $payment->kBestellung . '§' . $payment->cOrderNumber, LOGLEVEL_NOTICE); goto order; + break; case 'capture': if (!array_key_exists('id', $_REQUEST)) { $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; + break; } $payment = Payment::getPaymentMollie($_REQUEST['id']); if (!$payment) { $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Order nicht gefunden!']; + break; } $order = JTLMollie::API()->orders->get($_REQUEST['id']); if ($order->status !== OrderStatus::STATUS_AUTHORIZED && $order->status !== OrderStatus::STATUS_SHIPPING) { $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Nur autorisierte Zahlungen können erfasst werden!']; + break; } $oBestellung = new Bestellung($payment->kBestellung, true); if (!$oBestellung->kBestellung) { $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Bestellung konnte nicht geladen werden!']; + break; } - $logData = '#' . $payment->kBestellung . '$' . $payment->kID . "§" . $oBestellung->cBestellNr; + $logData = '#' . $payment->kBestellung . '$' . $payment->kID . '§' . $oBestellung->cBestellNr; $options = ['lines' => []]; if ($oBestellung->cTracking) { - $tracking = new stdClass(); - $tracking->carrier = $oBestellung->cVersandartName; - $tracking->url = $oBestellung->cTrackingURL; - $tracking->code = $oBestellung->cTracking; + $tracking = new stdClass(); + $tracking->carrier = $oBestellung->cVersandartName; + $tracking->url = $oBestellung->cTrackingURL; + $tracking->code = $oBestellung->cTracking; $options['tracking'] = $tracking; } // CAPTURE ALL - $shipment = JTLMollie::API()->shipments->createFor($order, $options); + $shipment = JTLMollie::API()->shipments->createFor($order, $options); $ordersMsgs[] = (object)['type' => 'success', 'text' => 'Zahlung wurde erfolgreich erfasst!']; Mollie::JTLMollie()->doLog('Shipment created
' . print_r(['options' => $options, 'shipment' => $shipment], 1) . '
', $logData); goto order; case 'order': - order: + order : if (!array_key_exists('id', $_REQUEST)) { $ordersMsgs[] = (object)['type' => 'danger', 'text' => 'Keine ID angeben!']; + break; } - $order = JTLMollie::API()->orders->get($_REQUEST['id'], ['embed' => 'payments,refunds']); + $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", [ + Shop::DB()->executeQueryPrepared('UPDATE xplugin_ws_mollie_payments SET cOrderNumber = :cBestellNr WHERE kID = :kID', [ ':cBestellNr' => $oBestellung->cBestellNr, - ':kID' => $payment->kID, + ':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", [ + $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 ?: '$$') . '%', + ':cBestellNr' => '%§' . ($payment->cOrderNumber ?: '§§') . '%', + ':MollieID' => '%$' . ($payment->kID ?: '$$') . '%', ], 2); Shop::Smarty()->assign('payment', $payment) @@ -212,6 +227,7 @@ ->assign('logs', $logs) ->assign('ordersMsgs', $ordersMsgs); Shop::Smarty()->display($oPlugin->cAdminmenuPfad . '/tpl/order.tpl'); + return; } } @@ -228,13 +244,13 @@ Shop::Smarty()->assign('payments', $payments) ->assign('ordersMsgs', $ordersMsgs) ->assign('admRoot', str_replace('http:', '', $oPlugin->cAdminmenuPfadURL)) - ->assign('hasAPIKey', trim(Helper::getSetting("api_key")) !== ''); + ->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/107/adminmenu/paymentmethods.php b/version/107/adminmenu/paymentmethods.php index 1782978..a548a9f 100644 --- a/version/107/adminmenu/paymentmethods.php +++ b/version/107/adminmenu/paymentmethods.php @@ -1,13 +1,19 @@ setApiKey(Helper::getSetting("api_key")); + $mollie->setApiKey(Helper::getSetting('api_key')); $profile = $mollie->profiles->get('me'); /* $methods = $mollie->methods->all([ @@ -23,14 +29,14 @@ '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; + $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")); + Shop::Smarty()->assign('defaultTabbertab', Helper::getAdminmenu('Zahlungsarten')); } $params = ['include' => 'pricing,issuers']; @@ -39,7 +45,7 @@ $params['locale'] = $locale; if ($active) { $params['includeWallets'] = 'applepay'; - $params['resource'] = 'orders'; + $params['resource'] = 'orders'; } } diff --git a/version/107/class/ExclusiveLock.php b/version/107/class/ExclusiveLock.php index 834e00f..2349413 100644 --- a/version/107/class/ExclusiveLock.php +++ b/version/107/class/ExclusiveLock.php @@ -1,23 +1,25 @@ key = $key; - $this->path = rtrim(realpath($path), '/'). '/' ; - if(!is_dir($path) || !is_writable($path)){ + $this->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 @@ -27,26 +29,28 @@ public function __construct( $key, $path = "" ) public function __destruct() { - if( $this->own === true ) - $this->unlock( ); + if ($this->own === true) { + $this->unlock(); + } } public function lock() { - if( !flock($this->file, LOCK_EX | LOCK_NB)) - { //failed + 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 ); + fwrite($this->file, 'Locked - ' . microtime(true) . "\n"); + fflush($this->file); $this->own = true; + return true; // success } @@ -54,23 +58,21 @@ public function lock() public function unlock() { $key = $this->key; - if( $this->own === true ) - { - if( !flock($this->file, LOCK_UN) ) - { //failed + 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 ); + fwrite($this->file, 'Unlocked - ' . microtime(true) . "\n"); + fflush($this->file); $this->own = false; - } - else - { + } else { error_log("ExclusiveLock::unlock called on [$key] but its not acquired by caller"); } + return true; // success } } diff --git a/version/107/class/Helper.php b/version/107/class/Helper.php index 8f4772c..50a398b 100644 --- a/version/107/class/Helper.php +++ b/version/107/class/Helper.php @@ -1,5 +1,8 @@ short_url != '' ? $release->short_url : $release->full_url; - $filename = basename($release->full_url); - $tmpDir = PFAD_ROOT . PFAD_COMPILEDIR; + $release = self::getLatestRelease(true); + $url = $release->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 @@ -84,8 +85,8 @@ public static function selfupdate() 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 (!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!"); @@ -118,30 +119,29 @@ public static function selfupdate() // 3. UNZIP require_once PFAD_ROOT . PFAD_PCLZIP . 'pclzip.lib.php'; - $zip = new PclZip($tmpDir . $filename); + $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!"); + throw new Exception('Das Zip-Archiv ist leider ungültig!'); + } + $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 { - $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()); - } + throw new Exception('Entpacken fehlgeschlagen: ' . $zip->errorCode()); } } /** * @param bool $force - * @return mixed * @throws Exception + * @return mixed */ public static function getLatestRelease($force = false) { - $lastCheck = (int)self::getSetting(__NAMESPACE__ . '_upd'); + $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__); @@ -152,7 +152,7 @@ public static function getLatestRelease($force = false) @curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); @curl_setopt($curl, CURLOPT_HTTPHEADER, ['Content-Type: application/json']); - $data = curl_exec($curl); + $data = curl_exec($curl); $statusCode = (int)curl_getinfo($curl, CURLINFO_HTTP_CODE); @curl_close($curl); if ($statusCode !== 200) { @@ -164,10 +164,11 @@ public static function getLatestRelease($force = false) } 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); } + + return json_decode($lastRelease); } /** @@ -178,6 +179,7 @@ public static function getLatestRelease($force = false) public static function init() { ini_set('xdebug.default_enable', defined('WS_XDEBUG_ENABLED')); + return self::autoload(); } @@ -190,10 +192,10 @@ public static function init() */ public static function setSetting($name, $value) { - $setting = new stdClass; + $setting = new stdClass(); $setting->kPlugin = self::oPlugin()->kPlugin; - $setting->cName = $name; - $setting->cWert = $value; + $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); @@ -202,6 +204,7 @@ public static function setSetting($name, $value) } self::oPlugin()->oPluginEinstellungAssoc_arr[$name] = $value; self::oPlugin(true); // invalidate cache + return $return; } @@ -209,15 +212,16 @@ public static function setSetting($name, $value) * Get Plugin Object * * @param bool $force disable Cache - * @return Plugin|null + * @return null|Plugin */ public static function oPlugin($force = false) { if ($force === true) { self::$oPlugin = new Plugin(self::oPlugin(false)->kPlugin, true); - } else if (null === self::$oPlugin) { + } elseif (null === self::$oPlugin) { self::$oPlugin = Plugin::getPluginById(__NAMESPACE__); } + return self::$oPlugin; } @@ -232,6 +236,7 @@ public static function getSetting($name) if (array_key_exists($name, self::oPlugin()->oPluginEinstellungAssoc_arr ?: [])) { return self::oPlugin()->oPluginEinstellungAssoc_arr[$name]; } + return null; } @@ -243,8 +248,9 @@ public static function getSetting($name) */ public static function getDomain($url = URL_SHOP) { - $matches = array(); + $matches = []; @preg_match("/^((http(s)?):\/\/)?(www\.)?([a-zA-Z0-9-\.]+)(\/.*)?$/i", $url, $matches); + return strtolower(isset($matches[5]) ? $matches[5] : $url); } @@ -254,22 +260,24 @@ public static function getDomain($url = URL_SHOP) */ public static function getMasterMail($e = false) { - $settings = Shop::getSettings(array(CONF_EMAILS)); - $mail = trim($settings['emails']['email_master_absender']); + $settings = Shop::getSettings([CONF_EMAILS]); + $mail = trim($settings['emails']['email_master_absender']); if ($e === true && $mail != '') { - $mail = base64_encode($mail); - $eMail = ""; + $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 + * @param bool $trace * @return void */ public static function logExc(Exception $exc, $trace = true) @@ -299,12 +307,13 @@ public static function getAdminmenu($name) foreach (self::oPlugin()->oPluginAdminMenu_arr as $adminmenu) { if (strtolower($adminmenu->cName) == strtolower($name)) { $kPluginAdminMenu = $adminmenu->kPluginAdminMenu; + break; } } + return $kPluginAdminMenu; } - } } diff --git a/version/107/class/Model/AbstractModel.php b/version/107/class/Model/AbstractModel.php index 5638700..d8e07cf 100644 --- a/version/107/class/Model/AbstractModel.php +++ b/version/107/class/Model/AbstractModel.php @@ -1,4 +1,8 @@ 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, + $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, + ':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, + ':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) ' @@ -57,6 +62,7 @@ public static function getPayment($kBestellung) if ($payment && $payment->kBestellung) { $payment->oBestellung = new Bestellung($payment->kBestellung, false); } + return $payment; } @@ -66,6 +72,7 @@ public static function getPaymentMollie($kID) if ($payment && $payment->kBestellung) { $payment->oBestellung = new Bestellung($payment->kBestellung, false); } + return $payment; } @@ -79,6 +86,7 @@ public static function getPaymentHash($cHash) if ($payment && $payment->kBestellung) { $payment->oBestellung = new Bestellung($payment->kBestellung, false); } + return $payment; } } diff --git a/version/107/class/Mollie.php b/version/107/class/Mollie.php index 6d0fd4c..7ac60d5 100644 --- a/version/107/class/Mollie.php +++ b/version/107/class/Mollie.php @@ -1,9 +1,7 @@ getValue(CONF_KAUFABWICKLUNG, 'bestellabschluss_abschlussseite'); - $bestellid = Shop::DB()->select("tbestellid ", 'kBestellung', (int)$kBestellung); - $url = Shop::getURL() . '/bestellabschluss.php?i=' . $bestellid->cId; + $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; + $url = Shop::getURL() . '/status.php?uid=' . $bestellstatus->cUID; } if ($redirect) { @@ -51,6 +49,7 @@ public static function getOrderCompletedRedirect($kBestellung, $redirect = true) echo "redirect ..."; exit(); } + return $url; } @@ -58,8 +57,8 @@ public static function getOrderCompletedRedirect($kBestellung, $redirect = true) * @param Order $order * @param $kBestellung * @param bool $newStatus - * @return array * @throws Exception + * @return array */ public static function getShipmentOptions(Order $order, $kBestellung, $newStatus = false) { @@ -75,10 +74,10 @@ public static function getShipmentOptions(Order $order, $kBestellung, $newStatus // Tracking Data if ($oBestellung->cTracking) { - $tracking = new stdClass(); - $tracking->carrier = $oBestellung->cVersandartName; - $tracking->url = $oBestellung->cTrackingURL; - $tracking->code = $oBestellung->cTracking; + $tracking = new stdClass(); + $tracking->carrier = $oBestellung->cVersandartName; + $tracking->url = $oBestellung->cTrackingURL; + $tracking->code = $oBestellung->cTracking; $options['tracking'] = $tracking; } @@ -86,35 +85,39 @@ public static function getShipmentOptions(Order $order, $kBestellung, $newStatus switch ((int)$newStatus) { case BESTELLUNG_STATUS_VERSANDT: - Mollie::JTLMollie()->doLog('181_sync: Bestellung versandt', $logData, LOGLEVEL_DEBUG); + self::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) { + if ($line->totalAmount->value > 0.0) { + if (($quantity = self::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), - ], + '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); + self::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); + self::JTLMollie()->doLog('181_sync: Bestellung storniert', $logData, LOGLEVEL_DEBUG); $options = null; + break; case BESTELLUNG_STATUS_BEZAHLT: case BESTELLUNG_STATUS_IN_BEARBEITUNG: @@ -122,26 +125,27 @@ public static function getShipmentOptions(Order $order, $kBestellung, $newStatus // NOTHING TO DO! break; default: - Mollie::JTLMollie()->doLog('181_sync: Bestellungstatus unbekannt: ' . $newStatus . '/' . $oBestellung->cStatus, $logData, LOGLEVEL_DEBUG); + self::JTLMollie()->doLog('181_sync: Bestellungstatus unbekannt: ' . $newStatus . '/' . $oBestellung->cStatus, $logData, LOGLEVEL_DEBUG); } return $options; } /** - * @return JTLMollie * @throws Exception + * @return JTLMollie */ 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!"); + throw new Exception('Mollie Zahlungsart nicht in DB gefunden!'); } require_once __DIR__ . '/../paymentmethod/JTLMollie.php'; self::$_jtlmollie = new JTLMollie($pza->cModulId); } + return self::$_jtlmollie; } @@ -149,8 +153,8 @@ public static function JTLMollie() * Returns amount of sent items for SKU * @param $sku * @param Bestellung $oBestellung - * @return float|int * @throws Exception + * @return float|int */ public static function getBestellPosSent($sku, Bestellung $oBestellung) { @@ -170,9 +174,11 @@ public static function getBestellPosSent($sku, Bestellung $oBestellung) } } } + return $sent; } } + return false; } @@ -181,17 +187,17 @@ public static function getBestellPosSent($sku, Bestellung $oBestellung) */ public static function fixZahlungsarten() { - $kPlugin = Helper::oPlugin()->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", [ + $kPlugin = Helper::oPlugin()->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), + ':cModulId' => preg_replace('/^kPlugin_\d+_/', 'kPlugin_' . $kPlugin . '_', $conflicted->cModulId), ':kZahlungsart' => $conflicted->kZahlungsart, ], 3); } @@ -200,34 +206,33 @@ public static function fixZahlungsarten() /** * @param Order $order - * @param null $kBestellung - * @return bool + * @param null $kBestellung * @throws Exception + * @return bool */ public static function handleOrder(Order $order, $kBestellung) { - $logData = '$' . $order->id . '#' . $kBestellung . "§" . $order->orderNumber; + $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, + ':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, + ':orderId1' => $oBestellung->cBestellNr, + ':orderId2' => $oBestellung->cBestellNr, ], 3); - if(isset($order->metadata->originalOrderNumber)){ + 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, + ':orderId1' => $order->metadata->originalOrderNumber, + ':orderId2' => $order->metadata->originalOrderNumber, ], 3); } @@ -243,15 +248,15 @@ public static function handleOrder(Order $order, $kBestellung) 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, + ':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])); + 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); @@ -267,7 +272,7 @@ public static function handleOrder(Order $order, $kBestellung) $order->orderNumber = $oBestellung->cBestellNr; Payment::updateFromPayment($order, $kBestellung); - $oIncomingPayment = Shop::DB()->executeQueryPrepared("SELECT * FROM tzahlungseingang WHERE kBestellung = :kBestellung", [':kBestellung' => $oBestellung->kBestellung], 1); + $oIncomingPayment = Shop::DB()->executeQueryPrepared('SELECT * FROM tzahlungseingang WHERE kBestellung = :kBestellung', [':kBestellung' => $oBestellung->kBestellung], 1); if (!$oIncomingPayment) { $oIncomingPayment = new stdClass(); } @@ -277,7 +282,6 @@ public static function handleOrder(Order $order, $kBestellung) case OrderStatus::STATUS_PAID: case OrderStatus::STATUS_COMPLETED: case OrderStatus::STATUS_AUTHORIZED: - $cHinweis = $order->id; if ($mPayment) { $cHinweis .= ' / ' . $mPayment->id; @@ -288,31 +292,36 @@ public static function handleOrder(Order $order, $kBestellung) $cHinweis = $mPayment->id; } - $oIncomingPayment->fBetrag = $order->amount->value; - $oIncomingPayment->cISO = $order->amount->currency; + $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); + self::JTLMollie()->addIncomingPayment($oBestellung, $oIncomingPayment); + self::JTLMollie()->setOrderStatusToPaid($oBestellung); + self::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); + self::JTLMollie()->setOrderStatusToPaid($oBestellung); + self::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); + self::JTLMollie()->doLog('Mollie::handleOrder/PaymentStatus: ' . $order->status, $logData, LOGLEVEL_ERROR); + break; } + return true; } + return false; } /** * @param Order $order - * @return \Mollie\Api\Resources\Payment|null + * @return null|\Mollie\Api\Resources\Payment */ public static function getLastPayment(Order $order) { @@ -322,6 +331,7 @@ public static function getLastPayment(Order $order) foreach ($order->payments() as $p) { if (!$payment) { $payment = $p; + continue; } if (strtotime($p->createdAt) > strtotime($payment->createdAt)) { @@ -329,6 +339,7 @@ public static function getLastPayment(Order $order) } } } + return $payment; } @@ -356,184 +367,185 @@ public static function getLocales() 'lv_LV', 'lt_LT',]; - $laender = []; - $shopLaender = Shop::DB()->executeQuery("SELECT cLaender FROM tversandart", 2); + $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); + $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); + '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 = []; diff --git a/version/107/frontend/131_globalinclude.php b/version/107/frontend/131_globalinclude.php index 916a7f9..773fb9d 100644 --- a/version/107/frontend/131_globalinclude.php +++ b/version/107/frontend/131_globalinclude.php @@ -1,4 +1,8 @@ cNotifyID; if (!(int)$oZahlungSession->kBestellung && $oZahlungSession->cNotifyID) { @@ -28,9 +30,8 @@ // 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; + $lock = new \ws_mollie\ExclusiveLock('mollie_' . $mOrder->id, PFAD_ROOT . PFAD_COMPILEDIR); + $logged = false; $maxWait = 300; while (!$lock->lock() && $maxWait > 0) { if (!$logged) { @@ -42,7 +43,7 @@ } if ($logged) { - Mollie::JTLMollie()->doLog("Hook 131: Order unlocked (after " . round(microtime(true) - $logged, 2) . "s - maxWait left: {$maxWait})", $logData, LOGLEVEL_DEBUG); + 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); } @@ -50,22 +51,21 @@ $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); + 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); + 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); + Mollie::JTLMollie()->doLog('Hook 131: Already in PaymentSession
' . print_r([session_id(), $oZahlungSession], 1) . '
', $logData, LOGLEVEL_DEBUG); $session = Session::getInstance(false, false); } @@ -76,26 +76,25 @@ $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); + 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->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"); + $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); } + 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); @@ -109,6 +108,7 @@ } 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); } } @@ -116,5 +116,3 @@ } catch (Exception $e) { Helper::logExc($e); } - - diff --git a/version/107/frontend/140_smarty.php b/version/107/frontend/140_smarty.php index 0213117..629f0d7 100644 --- a/version/107/frontend/140_smarty.php +++ b/version/107/frontend/140_smarty.php @@ -1,4 +1,8 @@ -oPluginSprachvariableAssoc_arr['error_' . $status]; + $text = Helper::oPlugin()->oPluginSprachvariableAssoc_arr['error_' . $status]; pq('#fieldset-payment')->prepend('
' . $text . '
'); } - - $applePayId = "kPlugin_".Helper::oPlugin()->kPlugin."_mollieapplepay"; -pq('body')->append(<<kPlugin . '_mollieapplepay'; + pq('body')->append( + << // HTML -); + ); switch (Helper::getSetting('load_styles')) { case 'Y': $selector = '#fieldset-payment [id*="_mollie"]'; - $border = ""; + $border = ''; + break; case 'A': $selector = '#fieldset-payment'; - $border = "border-bottom: 1px solid #ccc;"; + $border = 'border-bottom: 1px solid #ccc;'; + break; case 'N': default: return; } - $lh = "30px"; + $lh = '30px'; if (Helper::getSetting('paymentmethod_sync') === 'size2x') { - $lh = "40px"; + $lh = '40px'; } pq('head')->append( diff --git a/version/107/frontend/144_notify.php b/version/107/frontend/144_notify.php index 65e24e3..7c95703 100644 --- a/version/107/frontend/144_notify.php +++ b/version/107/frontend/144_notify.php @@ -1,17 +1,13 @@ Update Payment, stop skript - * - ELSE weiter mit der notify.php + * @copyright 2021 WebStollen GmbH + * @link https://www.webstollen.de */ - use ws_mollie\Helper; use ws_mollie\Mollie; try { - require_once __DIR__ . '/../class/Helper.php'; Helper::init(); @@ -35,23 +31,22 @@ 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); + 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); } + 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/107/frontend/181_sync.php b/version/107/frontend/181_sync.php index 86c610c..3a5bd60 100644 --- a/version/107/frontend/181_sync.php +++ b/version/107/frontend/181_sync.php @@ -1,4 +1,8 @@ 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); - } + $status = (int)$args_arr['status']; + /** @var Bestellung $oBestellung */ + $oBestellung = $args_arr['oBestellung']; + // Order got paid with mollie: + if ($oBestellung->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) { + Mollie::JTLMollie()->doLog('Fehler: ' . $e->getMessage() . '
' . print_r($e->getTrace(), 1) . '
', $logData, LOGLEVEL_ERROR); } + } //} } catch (Exception $e) { diff --git a/version/107/paymentmethod/JTLMollie.php b/version/107/paymentmethod/JTLMollie.php index 7ff428f..b90f367 100644 --- a/version/107/paymentmethod/JTLMollie.php +++ b/version/107/paymentmethod/JTLMollie.php @@ -1,4 +1,8 @@ (int)$order->kBestellung, + 'kBestellung' => (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' + '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; @@ -102,13 +106,14 @@ public function addIncomingPayment($order, $payment) /** * @param string $msg - * @param null $data - * @param int $level + * @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); + ZahlungsLog::add($this->moduleID, '[' . microtime(true) . ' - ' . $_SERVER['PHP_SELF'] . '] ' . $msg, $data, $level); + return $this; } @@ -134,7 +139,7 @@ public function setOrderStatusToPaid($order) */ public function preparePaymentProcess($order) { - $logData = '#' . $order->kBestellung . "§" . $order->cBestellNr; + $logData = '#' . $order->kBestellung . '§' . $order->cBestellNr; $payable = (float)$order->fGesamtsumme > 0; @@ -143,10 +148,9 @@ public function preparePaymentProcess($order) } try { - if ($order->kBestellung) { if ($payable) { - $payment = Payment::getPayment($order->kBestellung); + $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) { @@ -163,13 +167,11 @@ public function preparePaymentProcess($order) } } } catch (Exception $e) { - $this->doLog("Get Payment Error: " . $e->getMessage() . ". Create new ORDER...", $logData, LOGLEVEL_ERROR); + $this->doLog('Get Payment Error: ' . $e->getMessage() . '. Create new ORDER...', $logData, LOGLEVEL_ERROR); } try { - - if (!$payable) { $bestellung = finalisiereBestellung(); if ($bestellung && (int)$bestellung->kBestellung > 0) { @@ -183,7 +185,7 @@ public function preparePaymentProcess($order) if (!array_key_exists('oMolliePayment', $_SESSION) || !($_SESSION['oMolliePayment'] instanceof \Mollie\Api\Resources\Order)) { $hash = $this->generateHash($order); //$_SESSION['cMollieHash'] = $hash; - $orderData = $this->getOrderData($order, $hash); + $orderData = $this->getOrderData($order, $hash); $oMolliePayment = self::API()->orders->create($orderData); $this->updateHash($hash, $oMolliePayment->id); $_SESSION['oMolliePayment'] = $oMolliePayment; @@ -191,7 +193,7 @@ public function preparePaymentProcess($order) $oMolliePayment = $_SESSION['oMolliePayment']; } $logData .= '$' . $oMolliePayment->id; - $this->doLog('Mollie Create Payment Redirect: ' . $oMolliePayment->getCheckoutUrl() . "
" . print_r($oMolliePayment, 1) . "
", $logData, LOGLEVEL_DEBUG); + $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) { @@ -202,7 +204,7 @@ public function preparePaymentProcess($order) echo "redirect to payment ..."; exit(); } catch (ApiException $e) { - $this->doLog("Create Payment Error: " . $e->getMessage() . '
' . print_r($orderData, 1) . '
', $logData, LOGLEVEL_ERROR); + $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(); @@ -217,9 +219,10 @@ public function updateMollieCustomer($oKunde) if (!$oKunde->kKunde || (int)$oKunde->nRegistriert <= 0) { return; } + try { $customerId = Shop::DB()->select('xplugin_ws_mollie_kunde', 'kKunde', (int)$oKunde->kKunde); - $api = JTLMollie::API(); + $api = self::API(); /** @var Customer $customer */ $customer = new stdClass(); if ($customerId && isset($customerId->customerId)) { @@ -230,13 +233,13 @@ public function updateMollieCustomer($oKunde) } } - $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->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' => $oKunde->kKunde, + 'kKunde' => $oKunde->kKunde, 'kKundengruppe' => $oKunde->kKundengruppe, - 'cKundenNr' => $oKunde->cKundenNr, + 'cKundenNr' => $oKunde->cKundenNr, ]; if ($customer instanceof Customer) { @@ -244,21 +247,20 @@ public function updateMollieCustomer($oKunde) } else { if ($customer = $api->customers->create((array)$customer)) { Shop::DB()->insert('xplugin_ws_mollie_kunde', (object)[ - 'kKunde' => $oKunde->kKunde, + 'kKunde' => $oKunde->kKunde, 'customerId' => $customer->id, ]); } } - } catch (Exception $e) { Helper::logExc($e); } } /** - * @return MollieApiClient * @throws ApiException * @throws IncompatiblePlatform + * @return MollieApiClient */ public static function API() { @@ -266,55 +268,59 @@ public static function API() if (self::$_mollie === null) { self::$_mollie = new MollieApiClient(); 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); + self::$_mollie->addVersionString('JTL-Shop/' . JTL_VERSION . '.' . JTL_MINOR_VERSION); + self::$_mollie->addVersionString('ws_mollie/' . Helper::oPlugin()->nVersion); } + return self::$_mollie; } public static function getLocale($cISOSprache, $country = null) { switch ($cISOSprache) { - case "ger": - if ($country === "AT") { - return "de_AT"; + case 'ger': + if ($country === 'AT') { + return 'de_AT'; } - if ($country === "CH") { - return "de_CH"; + if ($country === 'CH') { + return 'de_CH'; } - return "de_DE"; - case "fre": - if ($country === "BE") { - return "fr_BE"; + + return 'de_DE'; + case 'fre': + if ($country === 'BE') { + return 'fr_BE'; } - return "fr_FR"; - case "dut": - if ($country === "BE") { - return "nl_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"; + + 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"; + return 'en_US'; } } @@ -337,12 +343,12 @@ protected function getOrderData(Bestellung $order, $hash) // runden auf 5 Rappen berücksichtigt 'value' => number_format($this->optionaleRundung($order->fGesamtsumme * $_currencyFactor), 2, '.', ''), ], - 'orderNumber' => utf8_encode($order->cBestellNr), - 'lines' => [], + '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, '_')), + '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 !== '') { @@ -350,7 +356,7 @@ protected function getOrderData(Bestellung $order, $hash) } if (static::MOLLIE_METHOD === \Mollie\Api\Types\PaymentMethod::CREDITCARD && array_key_exists('mollieCardToken', $_SESSION)) { - $data['payment'] = new stdClass(); + $data['payment'] = new stdClass(); $data['payment']->cardToken = trim($_SESSION['mollieCardToken']); } @@ -364,14 +370,14 @@ protected function getOrderData(Bestellung $order, $hash) 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']->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; + $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) && preg_match('/^\d{4}-\d{2}-\d{2}/$', trim($_SESSION['Kunde']->dGeburtstag))) { @@ -387,14 +393,14 @@ protected function getOrderData(Bestellung $order, $hash) 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']->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; + $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)); @@ -403,42 +409,43 @@ protected function getOrderData(Bestellung $order, $hash) /** @var WarenkorbPos $oPosition */ foreach ($order->Positionen as $oPosition) { - - $line = new stdClass(); + $line = new stdClass(); $line->name = utf8_encode($oPosition->cName); - $_netto = round($oPosition->fPreis, 2); + $_netto = round($oPosition->fPreis, 2); $_vatRate = (float)$oPosition->fMwSt / 100; - $_amount = (float)$oPosition->nAnzahl; + $_amount = (float)$oPosition->nAnzahl; - if (Helper::getSetting("supportQ") === 'Y') { + 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) { + 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); + $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); + $unitPrice = round($unitPriceNetto * (1 + $_vatRate), 2); + $totalAmount = round($_amount * $unitPrice, 2); + $vatAmount = round($totalAmount - ($totalAmount / (1 + $_vatRate)), 2); - $line->quantity = (int)$_amount; + $line->quantity = (int)$_amount; $line->unitPrice = (object)[ - 'value' => number_format($unitPrice, 2, '.', ''), + 'value' => number_format($unitPrice, 2, '.', ''), 'currency' => $order->Waehrung->cISO, ]; $line->totalAmount = (object)[ - 'value' => number_format($totalAmount, 2, '.', ''), + 'value' => number_format($totalAmount, 2, '.', ''), 'currency' => $order->Waehrung->cISO, ]; $line->vatRate = "{$oPosition->fMwSt}"; $line->vatAmount = (object)[ - 'value' => number_format($vatAmount, 2, '.', ''), + 'value' => number_format($vatAmount, 2, '.', ''), 'currency' => $order->Waehrung->cISO, ]; @@ -446,10 +453,12 @@ protected function getOrderData(Bestellung $order, $hash) case (int)C_WARENKORBPOS_TYP_GRATISGESCHENK: case (int)C_WARENKORBPOS_TYP_ARTIKEL: $line->type = OrderLineType::TYPE_PHYSICAL; - $line->sku = utf8_encode($oPosition->cArtNr); + $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: @@ -457,11 +466,13 @@ protected function getOrderData(Bestellung $order, $hash) 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)) { @@ -470,25 +481,25 @@ protected function getOrderData(Bestellung $order, $hash) } if ((int)$order->GuthabenNutzen === 1 && $order->fGuthaben < 0) { - $line = new stdClass(); - $line->type = OrderLineType::TYPE_STORE_CREDIT; - $line->name = 'Guthaben'; - $line->quantity = 1; + $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, '.', ''), + 'value' => number_format($order->Waehrung->fFaktor * $order->fGuthaben, 2, '.', ''), 'currency' => $order->Waehrung->cISO, ]; $line->unitPrice = (object)[ - 'value' => number_format($order->Waehrung->fFaktor * $order->fGuthaben, 2, '.', ''), + '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, '.', ''), + 'value' => number_format($order->Waehrung->fFaktor * $order->fGuthaben, 2, '.', ''), 'currency' => $order->Waehrung->cISO, ]; - $line->vatRate = "0.00"; + $line->vatRate = '0.00'; $line->vatAmount = (object)[ - 'value' => number_format(0, 2, '.', ''), + 'value' => number_format(0, 2, '.', ''), 'currency' => $order->Waehrung->cISO, ]; $data['lines'][] = $line; @@ -502,30 +513,31 @@ protected function getOrderData(Bestellung $order, $hash) 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 = 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, '.', ''), + 'value' => number_format($diff, 2, '.', ''), 'currency' => $order->Waehrung->cISO, ]; $line->unitPrice = (object)[ - 'value' => number_format($diff, 2, '.', ''), + 'value' => number_format($diff, 2, '.', ''), 'currency' => $order->Waehrung->cISO, ]; $line->totalAmount = (object)[ - 'value' => number_format($diff, 2, '.', ''), + 'value' => number_format($diff, 2, '.', ''), 'currency' => $order->Waehrung->cISO, ]; - $line->vatRate = "0.00"; + $line->vatRate = '0.00'; $line->vatAmount = (object)[ - 'value' => number_format(0, 2, '.', ''), + 'value' => number_format(0, 2, '.', ''), 'currency' => $order->Waehrung->cISO, ]; $data['lines'][] = $line; } } + return $data; } @@ -553,33 +565,32 @@ 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(); + $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 + * @param string $hash + * @param array $args */ public function handleNotification($order, $hash, $args) { - - $logData = '#' . $order->kBestellung . "§" . $order->cBestellNr; + $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); } @@ -587,19 +598,19 @@ public function handleNotification($order, $hash, $args) /** * @param Bestellung $order - * @param string $hash - * @param array $args + * @param string $hash + * @param array $args * * @return 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']; + $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); @@ -614,14 +625,15 @@ public function finalizeOrder($order, $hash, $args) } } } catch (Exception $e) { - $this->doLog('JTLMollie::finalizeOrder: ' . $e->getMessage(), "#" . $hash); + $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 Shop::DB()->executeQueryPrepared('SELECT * FROM tzahlungsession WHERE MD5(cZahlungsID) = :cZahlungsID', [':cZahlungsID' => trim($hash, '_')], 1); } /** @@ -641,11 +653,13 @@ public function isSelectable() { /** @var Warenkorb $wk */ $wk = $_SESSION['Warenkorb']; - if (Helper::getSetting("supportQ") !== 'Y') { + 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) { + if ( + (int)$oPosition->nPosTyp === (int)C_WARENKORBPOS_TYP_ARTIKEL && $oPosition->Artikel && $oPosition->Artikel->cTeilbar === 'Y' + && fmod($oPosition->nAnzahl, 1) !== 0.0 + ) { return false; } } @@ -656,24 +670,28 @@ public function isSelectable() try { $method = self::PossiblePaymentMethods(static::MOLLIE_METHOD, $locale, $_SESSION['Kunde']->cLand, $_SESSION['Waehrung']->cISO, $wk->gibGesamtsummeWaren(true) * $_SESSION['Waehrung']->fFaktor); 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."); + $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 { - $this->doLog("Global mollie PaymentMethod cannot be used for payments directly."); + $this->doLog('Global mollie PaymentMethod cannot be used for payments directly.'); } + return false; } @@ -683,9 +701,9 @@ public function isSelectable() * @param $billingCountry * @param $currency * @param $amount - * @return mixed|null * @throws ApiException * @throws IncompatiblePlatform + * @return null|mixed */ protected static function PossiblePaymentMethods($method, $locale, $billingCountry, $currency, $amount) { @@ -700,8 +718,10 @@ protected static function PossiblePaymentMethods($method, $locale, $billingCount return $m; } } + return null; } + return self::$_possiblePaymentMethods[$key]; } @@ -716,17 +736,17 @@ protected function updatePaymentMethod($cISOSprache, $method) } $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); + 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' => '', + ':kZahlungsart' => (int)$za->kZahlungsart, + ':cISOSprache' => $cISOSprache, + ':cName' => utf8_decode($method->description), + ':cGebuehrname' => '', + ':cHinweisText' => '', ':cHinweisTextShop' => utf8_decode($method->description), - 'cName1' => $method->description, + 'cName1' => $method->description, ], 3); } } @@ -737,10 +757,11 @@ protected function updatePaymentMethod($cISOSprache, $method) */ public function isValidIntern($args_arr = []) { - if (Helper::getSetting("api_key")) { + if (Helper::getSetting('api_key')) { return true; } - $this->doLog("isValdid failed: init failed or no API Key given. Try clear the Cache."); + $this->doLog('isValdid failed: init failed or no API Key given. Try clear the Cache.'); + return false; } } diff --git a/version/107/paymentmethod/JTLMollieApplePay.php b/version/107/paymentmethod/JTLMollieApplePay.php index ecf20a8..5cd26a9 100644 --- a/version/107/paymentmethod/JTLMollieApplePay.php +++ b/version/107/paymentmethod/JTLMollieApplePay.php @@ -1,4 +1,8 @@ assign('profileId',$profileId) + Shop::Smarty()->assign('profileId', $profileId) ->assign('locale', self::getLocale($_SESSION['cISOSprache'], $_SESSION['Kunde']->cLand)) ->assign('testmode', strpos(Helper::getSetting('api_key'), 'test_') === 0) ->assign('mollieLang', Helper::oPlugin()->oPluginSprachvariableAssoc_arr) @@ -31,6 +36,4 @@ public function handleAdditional($aPost_arr) return false; } - - } diff --git a/version/107/paymentmethod/JTLMollieDirectDebit.php b/version/107/paymentmethod/JTLMollieDirectDebit.php index ce0441d..1e897f6 100644 --- a/version/107/paymentmethod/JTLMollieDirectDebit.php +++ b/version/107/paymentmethod/JTLMollieDirectDebit.php @@ -1,4 +1,8 @@ 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)), + '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, ]); @@ -45,7 +50,6 @@ if ((int)Helper::oPlugin()->nVersion < (int)$latestRelease->version) { Shop::Smarty()->assign('update', $latestRelease); } - } catch (\Exception $e) { } @@ -57,8 +61,7 @@ } 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 index ff35df5..be8ab0b 100644 --- a/version/109/adminmenu/orders.php +++ b/version/109/adminmenu/orders.php @@ -1,4 +1,8 @@ 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'); + 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']); + $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'), + ':To' => $to->format('Y-m-d'), ], 2); @@ -71,23 +75,23 @@ $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, + '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, + '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; + $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) { @@ -103,82 +107,92 @@ 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); + 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); + 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; + $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); + $tracking = new stdClass(); + $tracking->carrier = utf8_encode($oBestellung->cVersandartName); + $tracking->url = utf8_encode($oBestellung->cTrackingURL); + $tracking->code = utf8_encode($oBestellung->cTracking); $options['tracking'] = $tracking; } @@ -189,28 +203,29 @@ goto order; case 'order': - 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']); + $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", [ + Shop::DB()->executeQueryPrepared('UPDATE xplugin_ws_mollie_payments SET cOrderNumber = :cBestellNr WHERE kID = :kID', [ ':cBestellNr' => $oBestellung->cBestellNr, - ':kID' => $payment->kID, + ':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", [ + $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 ?: '$$') . '%', + ':cBestellNr' => '%§' . ($payment->cOrderNumber ?: '§§') . '%', + ':MollieID' => '%$' . ($payment->kID ?: '$$') . '%', ], 2); Shop::Smarty()->assign('payment', $payment) @@ -218,6 +233,7 @@ ->assign('order', $order) ->assign('logs', $logs); Shop::Smarty()->display($oPlugin->cAdminmenuPfad . '/tpl/order.tpl'); + return; } } @@ -233,13 +249,13 @@ Shop::Smarty()->assign('payments', $payments) ->assign('admRoot', str_replace('http:', '', $oPlugin->cAdminmenuPfadURL)) - ->assign('hasAPIKey', trim(Helper::getSetting("api_key")) !== ''); + ->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 index 1782978..a548a9f 100644 --- a/version/109/adminmenu/paymentmethods.php +++ b/version/109/adminmenu/paymentmethods.php @@ -1,13 +1,19 @@ setApiKey(Helper::getSetting("api_key")); + $mollie->setApiKey(Helper::getSetting('api_key')); $profile = $mollie->profiles->get('me'); /* $methods = $mollie->methods->all([ @@ -23,14 +29,14 @@ '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; + $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")); + Shop::Smarty()->assign('defaultTabbertab', Helper::getAdminmenu('Zahlungsarten')); } $params = ['include' => 'pricing,issuers']; @@ -39,7 +45,7 @@ $params['locale'] = $locale; if ($active) { $params['includeWallets'] = 'applepay'; - $params['resource'] = 'orders'; + $params['resource'] = 'orders'; } } diff --git a/version/109/class/ExclusiveLock.php b/version/109/class/ExclusiveLock.php index 834e00f..2349413 100644 --- a/version/109/class/ExclusiveLock.php +++ b/version/109/class/ExclusiveLock.php @@ -1,23 +1,25 @@ key = $key; - $this->path = rtrim(realpath($path), '/'). '/' ; - if(!is_dir($path) || !is_writable($path)){ + $this->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 @@ -27,26 +29,28 @@ public function __construct( $key, $path = "" ) public function __destruct() { - if( $this->own === true ) - $this->unlock( ); + if ($this->own === true) { + $this->unlock(); + } } public function lock() { - if( !flock($this->file, LOCK_EX | LOCK_NB)) - { //failed + 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 ); + fwrite($this->file, 'Locked - ' . microtime(true) . "\n"); + fflush($this->file); $this->own = true; + return true; // success } @@ -54,23 +58,21 @@ public function lock() public function unlock() { $key = $this->key; - if( $this->own === true ) - { - if( !flock($this->file, LOCK_UN) ) - { //failed + 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 ); + fwrite($this->file, 'Unlocked - ' . microtime(true) . "\n"); + fflush($this->file); $this->own = false; - } - else - { + } 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 index 5f2a8be..dffa4eb 100644 --- a/version/109/class/Helper.php +++ b/version/109/class/Helper.php @@ -1,5 +1,8 @@ short_url != '' ? $release->short_url : $release->full_url; - $filename = basename($release->full_url); - $tmpDir = PFAD_ROOT . PFAD_COMPILEDIR; + $release = self::getLatestRelease(true); + $url = $release->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 @@ -84,8 +85,8 @@ public static function selfupdate() 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 (!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!"); @@ -118,30 +119,29 @@ public static function selfupdate() // 3. UNZIP require_once PFAD_ROOT . PFAD_PCLZIP . 'pclzip.lib.php'; - $zip = new PclZip($tmpDir . $filename); + $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!"); + throw new Exception('Das Zip-Archiv ist leider ungültig!'); + } + $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 { - $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()); - } + throw new Exception('Entpacken fehlgeschlagen: ' . $zip->errorCode()); } } /** * @param bool $force - * @return mixed * @throws Exception + * @return mixed */ public static function getLatestRelease($force = false) { - $lastCheck = (int)self::getSetting(__NAMESPACE__ . '_upd'); + $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__); @@ -152,7 +152,7 @@ public static function getLatestRelease($force = false) @curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); @curl_setopt($curl, CURLOPT_HTTPHEADER, ['Content-Type: application/json']); - $data = curl_exec($curl); + $data = curl_exec($curl); $statusCode = (int)curl_getinfo($curl, CURLINFO_HTTP_CODE); @curl_close($curl); if ($statusCode !== 200) { @@ -164,10 +164,11 @@ public static function getLatestRelease($force = false) } 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); } + + return json_decode($lastRelease); } /** @@ -178,6 +179,7 @@ public static function getLatestRelease($force = false) public static function init() { ini_set('xdebug.default_enable', defined('WS_XDEBUG_ENABLED')); + return self::autoload(); } @@ -210,15 +212,17 @@ public static function addAlert($content, $type, $namespace) * {ws_mollie\Helper::showAlerts('namespace')} * * @param $namespace - * @return string * @throws \SmartyException + * @return string */ 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 ''; } @@ -231,10 +235,10 @@ public static function showAlerts($namespace) */ public static function setSetting($name, $value) { - $setting = new stdClass; + $setting = new stdClass(); $setting->kPlugin = self::oPlugin()->kPlugin; - $setting->cName = $name; - $setting->cWert = $value; + $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); @@ -243,6 +247,7 @@ public static function setSetting($name, $value) } self::oPlugin()->oPluginEinstellungAssoc_arr[$name] = $value; self::oPlugin(true); // invalidate cache + return $return; } @@ -250,15 +255,16 @@ public static function setSetting($name, $value) * Get Plugin Object * * @param bool $force disable Cache - * @return Plugin|null + * @return null|Plugin */ public static function oPlugin($force = false) { if ($force === true) { self::$oPlugin = new Plugin(self::oPlugin(false)->kPlugin, true); - } else if (null === self::$oPlugin) { + } elseif (null === self::$oPlugin) { self::$oPlugin = Plugin::getPluginById(__NAMESPACE__); } + return self::$oPlugin; } @@ -273,6 +279,7 @@ public static function getSetting($name) if (array_key_exists($name, self::oPlugin()->oPluginEinstellungAssoc_arr ?: [])) { return self::oPlugin()->oPluginEinstellungAssoc_arr[$name]; } + return null; } @@ -284,8 +291,9 @@ public static function getSetting($name) */ public static function getDomain($url = URL_SHOP) { - $matches = array(); + $matches = []; @preg_match("/^((http(s)?):\/\/)?(www\.)?([a-zA-Z0-9-\.]+)(\/.*)?$/i", $url, $matches); + return strtolower(isset($matches[5]) ? $matches[5] : $url); } @@ -295,22 +303,24 @@ public static function getDomain($url = URL_SHOP) */ public static function getMasterMail($e = false) { - $settings = Shop::getSettings(array(CONF_EMAILS)); - $mail = trim($settings['emails']['email_master_absender']); + $settings = Shop::getSettings([CONF_EMAILS]); + $mail = trim($settings['emails']['email_master_absender']); if ($e === true && $mail != '') { - $mail = base64_encode($mail); - $eMail = ""; + $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 + * @param bool $trace * @return void */ public static function logExc(Exception $exc, $trace = true) @@ -340,12 +350,13 @@ public static function getAdminmenu($name) 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 index 5638700..d8e07cf 100644 --- a/version/109/class/Model/AbstractModel.php +++ b/version/109/class/Model/AbstractModel.php @@ -1,4 +1,8 @@ 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, + $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, + ':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, + ':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) ' @@ -57,6 +62,7 @@ public static function getPayment($kBestellung) if ($payment && $payment->kBestellung) { $payment->oBestellung = new Bestellung($payment->kBestellung, false); } + return $payment; } @@ -66,6 +72,7 @@ public static function getPaymentMollie($kID) if ($payment && $payment->kBestellung) { $payment->oBestellung = new Bestellung($payment->kBestellung, false); } + return $payment; } @@ -79,6 +86,7 @@ public static function getPaymentHash($cHash) 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 index 1f87dbe..205d4d4 100644 --- a/version/109/class/Mollie.php +++ b/version/109/class/Mollie.php @@ -1,9 +1,7 @@ getValue(CONF_KAUFABWICKLUNG, 'bestellabschluss_abschlussseite'); - $bestellid = Shop::DB()->select("tbestellid ", 'kBestellung', (int)$kBestellung); - $url = Shop::getURL() . '/bestellabschluss.php?i=' . $bestellid->cId; + $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; + $url = Shop::getURL() . '/status.php?uid=' . $bestellstatus->cUID; } if ($redirect) { @@ -52,6 +50,7 @@ public static function getOrderCompletedRedirect($kBestellung, $redirect = true) echo "redirect ..."; exit(); } + return $url; } @@ -59,8 +58,8 @@ public static function getOrderCompletedRedirect($kBestellung, $redirect = true) * @param Order $order * @param $kBestellung * @param bool $newStatus - * @return array * @throws Exception + * @return array */ public static function getShipmentOptions(Order $order, $kBestellung, $newStatus = false) { @@ -76,10 +75,10 @@ public static function getShipmentOptions(Order $order, $kBestellung, $newStatus // Tracking Data if ($oBestellung->cTracking) { - $tracking = new stdClass(); - $tracking->carrier = $oBestellung->cVersandartName; - $tracking->url = $oBestellung->cTrackingURL; - $tracking->code = $oBestellung->cTracking; + $tracking = new stdClass(); + $tracking->carrier = $oBestellung->cVersandartName; + $tracking->url = $oBestellung->cTrackingURL; + $tracking->code = $oBestellung->cTracking; $options['tracking'] = $tracking; } @@ -87,35 +86,39 @@ public static function getShipmentOptions(Order $order, $kBestellung, $newStatus switch ((int)$newStatus) { case BESTELLUNG_STATUS_VERSANDT: - Mollie::JTLMollie()->doLog('181_sync: Bestellung versandt', $logData, LOGLEVEL_DEBUG); + self::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) { + if ($line->totalAmount->value > 0.0) { + if (($quantity = self::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), - ], + '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); + self::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); + self::JTLMollie()->doLog('181_sync: Bestellung storniert', $logData, LOGLEVEL_DEBUG); $options = null; + break; case BESTELLUNG_STATUS_BEZAHLT: case BESTELLUNG_STATUS_IN_BEARBEITUNG: @@ -123,26 +126,27 @@ public static function getShipmentOptions(Order $order, $kBestellung, $newStatus // NOTHING TO DO! break; default: - Mollie::JTLMollie()->doLog('181_sync: Bestellungstatus unbekannt: ' . $newStatus . '/' . $oBestellung->cStatus, $logData, LOGLEVEL_DEBUG); + self::JTLMollie()->doLog('181_sync: Bestellungstatus unbekannt: ' . $newStatus . '/' . $oBestellung->cStatus, $logData, LOGLEVEL_DEBUG); } return $options; } /** - * @return JTLMollie * @throws Exception + * @return JTLMollie */ 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!"); + throw new Exception('Mollie Zahlungsart nicht in DB gefunden!'); } require_once __DIR__ . '/../paymentmethod/JTLMollie.php'; self::$_jtlmollie = new JTLMollie($pza->cModulId); } + return self::$_jtlmollie; } @@ -150,8 +154,8 @@ public static function JTLMollie() * Returns amount of sent items for SKU * @param $sku * @param Bestellung $oBestellung - * @return float|int * @throws Exception + * @return float|int */ public static function getBestellPosSent($sku, Bestellung $oBestellung) { @@ -171,9 +175,11 @@ public static function getBestellPosSent($sku, Bestellung $oBestellung) } } } + return $sent; } } + return false; } @@ -184,16 +190,16 @@ 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 = '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), + ':cModulId' => preg_replace('/^kPlugin_\d+_/', 'kPlugin_' . $kPlugin . '_', $conflicted->cModulId), ':kZahlungsart' => $conflicted->kZahlungsart, ], 3); } @@ -203,34 +209,33 @@ public static function fixZahlungsarten() /** * @param Order $order - * @param null $kBestellung - * @return bool + * @param null $kBestellung * @throws Exception + * @return bool */ public static function handleOrder(Order $order, $kBestellung) { - $logData = '$' . $order->id . '#' . $kBestellung . "§" . $order->orderNumber; + $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, + ':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, + ':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, + ':orderId1' => $order->metadata->originalOrderNumber, + ':orderId2' => $order->metadata->originalOrderNumber, ], 3); } @@ -246,15 +251,15 @@ public static function handleOrder(Order $order, $kBestellung) 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, + ':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])); + 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); @@ -270,7 +275,7 @@ public static function handleOrder(Order $order, $kBestellung) $order->orderNumber = $oBestellung->cBestellNr; Payment::updateFromPayment($order, $kBestellung); - $oIncomingPayment = Shop::DB()->executeQueryPrepared("SELECT * FROM tzahlungseingang WHERE kBestellung = :kBestellung", [':kBestellung' => $oBestellung->kBestellung], 1); + $oIncomingPayment = Shop::DB()->executeQueryPrepared('SELECT * FROM tzahlungseingang WHERE kBestellung = :kBestellung', [':kBestellung' => $oBestellung->kBestellung], 1); if (!$oIncomingPayment) { $oIncomingPayment = new stdClass(); } @@ -280,7 +285,6 @@ public static function handleOrder(Order $order, $kBestellung) case OrderStatus::STATUS_PAID: case OrderStatus::STATUS_COMPLETED: case OrderStatus::STATUS_AUTHORIZED: - $cHinweis = $order->id; if ($mPayment) { $cHinweis .= ' / ' . $mPayment->id; @@ -291,36 +295,41 @@ public static function handleOrder(Order $order, $kBestellung) $cHinweis = $mPayment->id; } - if($mPayment->method === PaymentMethod::PAYPAL && isset($mPayment->details->paypalReference)){ - $cHinweis = $mPayment->details->paypalReference; + 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->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); + self::JTLMollie()->addIncomingPayment($oBestellung, $oIncomingPayment); + self::JTLMollie()->setOrderStatusToPaid($oBestellung); + self::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); + self::JTLMollie()->setOrderStatusToPaid($oBestellung); + self::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); + self::JTLMollie()->doLog('Mollie::handleOrder/PaymentStatus: ' . $order->status, $logData, LOGLEVEL_ERROR); + break; } + return true; } + return false; } /** * @param Order $order - * @return \Mollie\Api\Resources\Payment|null + * @return null|\Mollie\Api\Resources\Payment */ public static function getLastPayment(Order $order) { @@ -330,6 +339,7 @@ public static function getLastPayment(Order $order) foreach ($order->payments() as $p) { if (!$payment) { $payment = $p; + continue; } if (strtotime($p->createdAt) > strtotime($payment->createdAt)) { @@ -337,6 +347,7 @@ public static function getLastPayment(Order $order) } } } + return $payment; } @@ -364,184 +375,185 @@ public static function getLocales() 'lv_LV', 'lt_LT',]; - $laender = []; - $shopLaender = Shop::DB()->executeQuery("SELECT cLaender FROM tversandart", 2); + $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); + $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); + '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 = []; diff --git a/version/109/frontend/131_globalinclude.php b/version/109/frontend/131_globalinclude.php index 5778e21..fe8dc67 100644 --- a/version/109/frontend/131_globalinclude.php +++ b/version/109/frontend/131_globalinclude.php @@ -1,4 +1,8 @@ cNotifyID; if (!(int)$oZahlungSession->kBestellung && $oZahlungSession->cNotifyID) { @@ -28,9 +30,8 @@ // 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; + $lock = new \ws_mollie\ExclusiveLock('mollie_' . $mOrder->id, PFAD_ROOT . PFAD_COMPILEDIR); + $logged = false; $maxWait = 120; while (!$lock->lock() && $maxWait > 0) { if (!$logged) { @@ -42,7 +43,7 @@ } if ($logged) { - Mollie::JTLMollie()->doLog("Hook 131: Order unlocked (after " . round(microtime(true) - $logged, 2) . "s - maxWait left: {$maxWait})", $logData, LOGLEVEL_DEBUG); + 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); } @@ -50,22 +51,21 @@ $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); + 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); + 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); + Mollie::JTLMollie()->doLog('Hook 131: Already in PaymentSession
' . print_r([session_id(), $oZahlungSession], 1) . '
', $logData, LOGLEVEL_DEBUG); $session = Session::getInstance(false, false); } @@ -76,26 +76,25 @@ $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); + 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->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"); + $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); } + 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); @@ -109,6 +108,7 @@ } 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); } } @@ -116,5 +116,3 @@ } catch (Exception $e) { Helper::logExc($e); } - - diff --git a/version/109/frontend/140_smarty.php b/version/109/frontend/140_smarty.php index ac119c6..e8cc80e 100644 --- a/version/109/frontend/140_smarty.php +++ b/version/109/frontend/140_smarty.php @@ -1,4 +1,8 @@ -oPluginSprachvariableAssoc_arr['error_' . $status]; + $text = Helper::oPlugin()->oPluginSprachvariableAssoc_arr['error_' . $status]; pq('#fieldset-payment')->prepend('
' . $text . '
'); } - $applePayId = "kPlugin_" . Helper::oPlugin()->kPlugin . "_mollieapplepay"; + $applePayId = 'kPlugin_' . Helper::oPlugin()->kPlugin . '_mollieapplepay'; if (pq('#' . $applePayId)) { $selector = 'body'; if (array_key_exists('isAjax', $_REQUEST)) { $selector = '#checkout'; } - pq($selector)->append(<<append( + << // + \ No newline at end of file diff --git a/version/206/adminmenu/tpl/info.tpl b/version/206/adminmenu/tpl/info.tpl new file mode 100644 index 0000000..2d41c95 --- /dev/null +++ b/version/206/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}
+
+
+
Changelog:
+
+ +
+
+ +
+
+ +
+
+
+ {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/206/adminmenu/tpl/mollie-account-erstellen.png b/version/206/adminmenu/tpl/mollie-account-erstellen.png new file mode 100644 index 0000000000000000000000000000000000000000..fc1819255ef725fa214cf2bf028cf3428794ecee GIT binary patch literal 38998 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 +

+ « + 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 isset($order->customerId)} + ID: + {$order->customerId} +
+ {/if} + {if isset($order->billingAddress, $order->billingAddress->organizationName)} + {$order->billingAddress->organizationName} + {elseif isset($order->billingAddress)} + {$order->billingAddress->title} {$order->billingAddress->givenName} {$order->billingAddress->familyName} + {/if} +
Mollie Checkout: + {if $order->getCheckoutURL()} + mollie.com/... + {else} + n/a + {/if} + + +
+{if $order->id|strpos:"ord_" !== false && $order->payments()->count > 0} +

Zahlungen

+ + + + + + + + + + + + + + {foreach from=$order->payments() item=payment} + + + + + + + + + + + {/foreach} +
IDStatusMethodeAmountSettlementRefundedRemainingDetails
{$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} +
+
+{/if} + +
+ {if ($order->status === 'authorized' || $order->status === 'shipping') && $oBestellung->cStatus|intval >= 3} + + Zahlung erfassen1 + + {/if} + {if !$order->amountRefunded || ($order->amount->value > $order->amountRefunded->value)} + Rückerstatten2 + + {/if} + {if $order->isCancelable} + Abbrechen3 + + {/if} +
+ +{if $order->id|strpos:"ord_" !== false} +

Positionen:

+ + + + + + + + + + + + + + + + + {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} + + + + + + + + + + + + + {/foreach} + + + + + + + + + + +
StatusSKUNameTypAnzahlMwStSteuerNettoBrutto 
+ {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'} + abgebrochen + {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*} +
{$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.
+
+{/if} + +{if isset($shipments) && $shipments|count} +

Shipmets

+ + + + + + + + + + + {foreach from=$shipments item=shipment} + + + + + + + {/foreach} + +
Lieferschein Nr.Mollie IDCarrierCode
{$shipment->getLieferschein()->getLieferscheinNr()}{$shipment->getShipment()->id} + {if isset($shipment->getShipment()->tracking)} + {$shipment->getShipment()->tracking->carrier} + {else} + - + {/if} + {if isset($shipment->getShipment()->tracking)} + {if isset($shipment->getShipment()->tracking->url)} + + {$shipment->getShipment()->tracking->code} + + {else} + {$shipment->getShipment()->tracking->code} + {/if} + {else} + - + {/if} +
+{/if} + +

Log

+ + {foreach from=$logs item=log} + + + + + + + {/foreach} +
+ {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}
+ + diff --git a/version/206/adminmenu/tpl/orders.tpl b/version/206/adminmenu/tpl/orders.tpl new file mode 100644 index 0000000..a499f32 --- /dev/null +++ b/version/206/adminmenu/tpl/orders.tpl @@ -0,0 +1,160 @@ +{ws_mollie\Helper::showAlerts('orders')} + +{if $hasAPIKey == false} + + Jetzt kostenlos Mollie Account eröffnen! + +{else} + + + + + + + + + + + + + + + {foreach from=$checkouts item=checkout} + + + + + + + + + + + + + + + {/foreach} + +
BestellNr.IDMollie StatusJTL StatusBetragMethodeErstellt 
+ {if $checkout->getModel()->bSynced == false && $checkout->getBestellung()->cAbgeholt === 'Y'} + * + {/if} + {$checkout->getModel()->cOrderNumber} + {if $checkout->getModel()->cMode == 'test'} + TEST + {/if} + {if $checkout->getModel()->bLockTimeout} + LOCK TIMEOUT + {/if} + {if $checkout->getModel()->dReminder && $checkout->getModel()->dReminder !== '0000-00-00 00:00:00'} + getModel()->dReminder|strtotime}}"> + {/if} + + {$checkout->getModel()->kID} + + {if $checkout->getModel()->cStatus == 'created' || $checkout->getModel()->cStatus == 'open'} + erstellt + {elseif $checkout->getModel()->cStatus == 'pending'} + austehend + {elseif $checkout->getModel()->cStatus == 'paid'} + bezahlt + {elseif $checkout->getModel()->cStatus == 'authorized'} + autorisiert + {elseif $checkout->getModel()->cStatus == 'shipping'} + versendet + {elseif $checkout->getModel()->cStatus == 'completed'} + abgeschlossen + {elseif $checkout->getModel()->cStatus == 'expired'} + abgelaufen + {elseif $checkout->getModel()->cStatus == 'canceled'} + abgebrochen + {else} + Unbekannt: {$checkout->getModel()->cStatus} + {/if} + {if $checkout->getModel()->fAmountRefunded && $checkout->getModel()->fAmountRefunded == $checkout->getModel()->fAmount} + (total refund) + {elseif $checkout->getModel()->fAmountRefunded && $checkout->getModel()->fAmountRefunded > 0} + (partly refund) + {/if} + + + {if $checkout->getBestellung()->cStatus|intval == 1} + OFFEN + {elseif $checkout->getBestellung()->cStatus|intval == 2} + IN BEARBEITUNG + {elseif $checkout->getBestellung()->cStatus|intval == 3} + BEZAHLT + {elseif $checkout->getBestellung()->cStatus|intval == 4} + VERSANDT + {elseif $checkout->getBestellung()->cStatus|intval == 5} + TEILVERSANDT + {elseif $checkout->getBestellung()->cStatus|intval == -1} + STORNO + {else} + n/a + {/if} + {$checkout->getModel()->fAmount|number_format:2:',':''} {$checkout->getModel()->cCurrency}{$checkout->getModel()->cMethod}{"d. M Y H:i"|date:{$checkout->getModel()->dCreatedAt|strtotime}} +
+ +
+ {if $checkout->getModel()->bSynced == false && $checkout->getBestellung()->cAbgeholt === 'Y'} + + {/if} + {if $checkout->remindable()} + + {/if} +
+
+
+ {if $payments|count > 900} +
Hier werden nur die letzten 1000 Ergebnisse angezeigt.
+ {/if} + + +
+
+

Export:

+
+ +
+ + + + + +
+
+ +{/if} + diff --git a/version/206/adminmenu/tpl/paymentmethods.tpl b/version/206/adminmenu/tpl/paymentmethods.tpl new file mode 100644 index 0000000..7821af5 --- /dev/null +++ b/version/206/adminmenu/tpl/paymentmethods.tpl @@ -0,0 +1,148 @@ +

Account Status

+ + + + + + + {if $profile->review} + + + {/if} + {if $profile->_links->checkoutPreviewUrl->href} + + {/if} + + +
Mode:{$profile->mode}Status:{$profile->status}Review:{$profile->review->status} + Checkout + Preview + + Mollie Dashboard +
+
+
+
+ + +
+ + + +
+
+ + +
+
+ + +
+
+ + + reset +
+
+
+
+{if $allMethods && $allMethods|count} + + + + + + + + + + + + {foreach from=$allMethods item=method} + + + + + + + + {/foreach} + +
BildName / IDInfoPreiseLimits
{$method->mollie->description|utf8_decode} + {if $method->mollie->status === 'activated'} + + {else} + + {/if} + {$method->mollie->description|utf8_decode}
+ {$method->mollie->id} +
+ {if $method->shop && $method->oClass} + {if intval($method->shop->nWaehrendBestellung) === 1 && !$method->allowPreOrder} +
Zahlung VOR Bestellabschluss nicht unterstützt!
+ {else} +
+ Bestellabschluss: + {if intval($method->shop->nWaehrendBestellung) === 1} + NACH Zahlung + {else} + VOR Zahlung + {/if} +
+ {/if} + + {if intval($settings.autoStorno) > 0} +
+ Unbez. Bestellung stornieren: + {if $method->allowAutoStorno} +
auto
+ {else} +
manual
+ {/if} +
+ {/if} +
+ Gültigkeit: + {$method->maxExpiryDays} Tage +
+ {else} + Derzeit nicht unterstützt. + {/if} +
+
    + {foreach from=$method->mollie->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->mollie->minimumAmount}{$method->mollie->minimumAmount->value} {$method->mollie->minimumAmount->currency}{else}n/a{/if} +
+ Max: {if $method->mollie->maximumAmount}{$method->mollie->maximumAmount->value} {$method->mollie->maximumAmount->currency}{else}n/a{/if} +
+{else} +
Es konnten keine Methoden abgerufen werden.
+{/if} \ No newline at end of file diff --git a/version/206/class/API.php b/version/206/class/API.php new file mode 100644 index 0000000..927fe6c --- /dev/null +++ b/version/206/class/API.php @@ -0,0 +1,76 @@ +test = $test === null ? self::getMode() : $test; + } + + /** + * @return bool + */ + public static function getMode() + { + require_once PFAD_ROOT . PFAD_ADMIN . PFAD_INCLUDES . 'benutzerverwaltung_inc.php'; + + return self::Plugin()->oPluginEinstellungAssoc_arr['testAsAdmin'] === 'Y' && Shop::isAdmin() && self::Plugin()->oPluginEinstellungAssoc_arr['test_api_key']; + } + + /** + * @throws ApiException + * @throws IncompatiblePlatform + * @return MollieApiClient + */ + public function Client() + { + if (!$this->client) { + $this->client = new MollieApiClient(/*new Client([ + RequestOptions::VERIFY => CaBundle::getBundledCaBundlePath(), + RequestOptions::TIMEOUT => 60 + ])*/ + ); + $this->client->setApiKey($this->isTest() ? self::Plugin()->oPluginEinstellungAssoc_arr['test_api_key'] : self::Plugin()->oPluginEinstellungAssoc_arr['api_key']) + ->addVersionString('JTL-Shop/' . JTL_VERSION . JTL_MINOR_VERSION) + ->addVersionString('ws_mollie/' . self::Plugin()->nVersion); + } + + return $this->client; + } + + /** + * @return bool + */ + public function isTest() + { + return $this->test; + } +} diff --git a/version/206/class/Checkout/AbstractCheckout.php b/version/206/class/Checkout/AbstractCheckout.php new file mode 100644 index 0000000..df8951f --- /dev/null +++ b/version/206/class/Checkout/AbstractCheckout.php @@ -0,0 +1,1213 @@ + ['lang' => 'de', 'country' => ['DE', 'AT', 'CH']], + 'fre' => ['lang' => 'fr', 'country' => ['BE', 'FR']], + 'dut' => ['lang' => 'nl', 'country' => ['BE', 'NL']], + 'spa' => ['lang' => 'es', 'country' => ['ES']], + 'ita' => ['lang' => 'it', 'country' => ['IT']], + 'pol' => ['lang' => 'pl', 'country' => ['PL']], + 'hun' => ['lang' => 'hu', 'country' => ['HU']], + 'por' => ['lang' => 'pt', 'country' => ['PT']], + 'nor' => ['lang' => 'nb', 'country' => ['NO']], + 'swe' => ['lang' => 'sv', 'country' => ['SE']], + 'fin' => ['lang' => 'fi', 'country' => ['FI']], + 'dan' => ['lang' => 'da', 'country' => ['DK']], + 'ice' => ['lang' => 'is', 'country' => ['IS']], + 'eng' => ['lang' => 'en', 'country' => ['GB', 'US']], + ]; + /** + * @var null|\Mollie\Api\Resources\Customer + */ + protected $customer; + /** + * @var string + */ + private $hash; + /** + * @var API + */ + private $api; + /** + * @var JTLMollie + */ + private $paymentMethod; + /** + * @var Bestellung + */ + private $oBestellung; + /** + * @var Payment + */ + private $model; + + /** + * AbstractCheckout constructor. + * @param Bestellung $oBestellung + * @param null $api + */ + public function __construct(Bestellung $oBestellung, $api = null) + { + $this->api = $api; + $this->oBestellung = $oBestellung; + } + + /** + * @param int $kBestellung + * @param bool $checkZA + * @return bool + */ + public static function isMollie($kBestellung, $checkZA = false) + { + if ($checkZA) { + $res = Shop::DB()->executeQueryPrepared('SELECT * FROM tzahlungsart WHERE cModulId LIKE :cModulId AND kZahlungsart = :kZahlungsart', [ + ':kZahlungsart' => $kBestellung, + ':cModulId' => 'kPlugin_' . self::Plugin()->kPlugin . '_%' + ], 1); + + return (bool)$res; + } + + return ($res = Shop::DB()->executeQueryPrepared('SELECT kId FROM xplugin_ws_mollie_payments WHERE kBestellung = :kBestellung;', [ + ':kBestellung' => $kBestellung, + ], 1)) && $res->kId; + } + + public static function finalizeOrder($sessionHash, $id, $test = false) + { + try { + if ($paymentSession = Shop::DB()->select('tzahlungsession', 'cZahlungsID', $sessionHash)) { + if (session_id() !== $paymentSession->cSID) { + session_destroy(); + session_id($paymentSession->cSID); + $session = Session::getInstance(true, true); + } else { + $session = Session::getInstance(false); + } + + if ( + (!isset($paymentSession->nBezahlt) || !$paymentSession->nBezahlt) + && (!isset($paymentSession->kBestellung) || !$paymentSession->kBestellung) + && isset($_SESSION['Warenkorb']->PositionenArr) + && count($_SESSION['Warenkorb']->PositionenArr) + ) { + $paymentSession->cNotifyID = $id; + $paymentSession->dNotify = 'now()'; + Shop::DB()->update('tzahlungsession', 'cZahlungsID', $sessionHash, $paymentSession); + + $api = new API($test); + if (strpos($id, 'tr_') === 0) { + $mollie = $api->Client()->payments->get($id); + } else { + $mollie = $api->Client()->orders->get($id, ['embed' => 'payments']); + } + + if (in_array($mollie->status, [OrderStatus::STATUS_PENDING, OrderStatus::STATUS_AUTHORIZED, OrderStatus::STATUS_PAID], true)) { + require_once PFAD_ROOT . PFAD_INCLUDES . 'bestellabschluss_inc.php'; + require_once PFAD_ROOT . PFAD_INCLUDES . 'mailTools.php'; + $order = finalisiereBestellung(); + $session->cleanUp(); + $paymentSession->nBezahlt = 1; + $paymentSession->dZeitBezahlt = 'now()'; + } else { + throw new Exception('Mollie Status invalid: ' . $mollie->status . '\n' . print_r([$sessionHash, $id], 1)); + } + + if ($order->kBestellung) { + $paymentSession->kBestellung = $order->kBestellung; + Shop::DB()->update('tzahlungsession', 'cZahlungsID', $sessionHash, $paymentSession); + + try { + $checkout = self::fromID($id, false, $order); + } catch (Exception $e) { + if (strpos($id, 'tr_') === 0) { + $checkoutClass = PaymentCheckout::class; + } else { + $checkoutClass = OrderCheckout::class; + } + $checkout = new $checkoutClass($order, $api); + } + $checkout->setMollie($mollie)->updateModel()->saveModel(); + $checkout->updateOrderNumber(); + $checkout->handleNotification($sessionHash); + } + } else { + Jtllog::writeLog(sprintf('PaymentSession bereits bezahlt: %s - ID: %s => Queue', $sessionHash, $id), JTLLOG_LEVEL_NOTICE); + Queue::saveToQueue($id, $id, 'webhook'); + } + } else { + Jtllog::writeLog(sprintf('PaymentSession nicht gefunden: %s - ID: %s => Queue', $sessionHash, $id), JTLLOG_LEVEL_NOTICE); + Queue::saveToQueue($id, $id, 'webhook'); + } + } catch (Exception $e) { + Helper::logExc($e); + } + } + + /** + * @param string $id + * @param bool $bFill + * @param null|Bestellung $order + * @throws RuntimeException + * @return OrderCheckout|PaymentCheckout + */ + public static function fromID($id, $bFill = true, Bestellung $order = null) + { + if (($model = Payment::fromID($id))) { + return static::fromModel($model, $bFill, $order); + } + + throw new RuntimeException(sprintf('Error loading Order: %s', $id)); + } + + /** + * @param Payment $model + * @param bool $bFill + * @param null|Bestellung $order + * @return OrderCheckout|PaymentCheckout + */ + public static function fromModel($model, $bFill = true, Bestellung $order = null) + { + if (!$model) { + throw new RuntimeException(sprintf('Error loading Order for Model: %s', print_r($model, 1))); + } + + $oBestellung = $order; + if (!$order) { + $oBestellung = new Bestellung($model->kBestellung, $bFill); + if (!$oBestellung->kBestellung) { + throw new RuntimeException(sprintf('Error loading Bestellung: %s', $model->kBestellung)); + } + } + + if (strpos($model->kID, 'tr_') !== false) { + $self = new PaymentCheckout($oBestellung); + } else { + $self = new OrderCheckout($oBestellung); + } + + $self->setModel($model); + + return $self; + } + + /** + * @return bool + */ + public function saveModel() + { + return $this->getModel()->save(); + } + + /** + * @return Payment + */ + public function getModel() + { + if (!$this->model) { + $this->model = Payment::fromID($this->oBestellung->kBestellung, 'kBestellung'); + } + + return $this->model; + } + + /** + * @param $model + * @return $this + */ + protected function setModel($model) + { + if (!$this->model) { + $this->model = $model; + } else { + throw new RuntimeException('Model already set.'); + } + + return $this; + } + + /** + * @param null $hash + * @throws Exception + */ + public function handleNotification($hash = null) + { + if (!$this->getHash()) { + $this->getModel()->cHash = $hash; + } + + $this->updateModel()->saveModel(); + if (!$this->getBestellung()->dBezahltDatum || $this->getBestellung()->dBezahltDatum === '0000-00-00') { + if ($incoming = $this->getIncomingPayment()) { + $this->PaymentMethod()->addIncomingPayment($this->getBestellung(), $incoming); + + $this->PaymentMethod()->setOrderStatusToPaid($this->getBestellung()); + static::makeFetchable($this->getBestellung(), $this->getModel()); + $this->PaymentMethod()->deletePaymentHash($this->getHash()); + $this->Log(sprintf("Checkout::handleNotification: Bestellung '%s' als bezahlt markiert: %.2f %s", $this->getBestellung()->cBestellNr, (float)$incoming->fBetrag, $incoming->cISO)); + + $oZahlungsart = Shop::DB()->selectSingleRow('tzahlungsart', 'cModulId', $this->PaymentMethod()->moduleID); + if ($oZahlungsart && (int)$oZahlungsart->nMailSenden === 1) { + require_once PFAD_ROOT . 'includes/mailTools.php'; + $this->PaymentMethod()->sendConfirmationMail($this->getBestellung()); + } + if (!$this->completlyPaid()) { + $this->Log(sprintf("Checkout::handleNotification: Bestellung '%s': nicht komplett bezahlt: %.2f %s", $this->getBestellung()->cBestellNr, (float)$incoming->fBetrag, $incoming->cISO), LOGLEVEL_ERROR); + } + } + } + } + + /** + * @return string + */ + public function getHash() + { + if ($this->getModel()->cHash) { + return $this->getModel()->cHash; + } + if (!$this->hash) { + $this->hash = $this->PaymentMethod()->generateHash($this->oBestellung); + } + + return $this->hash; + } + + /** + * @return JTLMollie + */ + public function PaymentMethod() + { + if (!$this->paymentMethod) { + include_once PFAD_ROOT . PFAD_INCLUDES . 'modules/PaymentMethod.class.php'; + if ($this->getBestellung()->Zahlungsart && strpos($this->getBestellung()->Zahlungsart->cModulId, "kPlugin_{$this::Plugin()->kPlugin}_") !== false) { + try { + $this->paymentMethod = PaymentMethod::create($this->getBestellung()->Zahlungsart->cModulId); + } catch (Exception $e) { + $this->paymentMethod = PaymentMethod::create("kPlugin_{$this::Plugin()->kPlugin}_mollie"); + } + } else { + $this->paymentMethod = PaymentMethod::create("kPlugin_{$this::Plugin()->kPlugin}_mollie"); + } + } + + return $this->paymentMethod; + } + + /** + * @return Bestellung + */ + public function getBestellung() + { + if (!$this->oBestellung && $this->getModel()->kBestellung) { + $this->oBestellung = new Bestellung($this->getModel()->kBestellung, true); + } + + return $this->oBestellung; + } + + /** + * @return $this + */ + public function updateModel() + { + if ($this->getMollie()) { + $this->getModel()->kID = $this->getMollie()->id; + $this->getModel()->cLocale = $this->getMollie()->locale; + $this->getModel()->fAmount = (float)$this->getMollie()->amount->value; + $this->getModel()->cMethod = $this->getMollie()->method; + $this->getModel()->cCurrency = $this->getMollie()->amount->currency; + $this->getModel()->cStatus = $this->getMollie()->status; + if ($this->getMollie()->amountRefunded) { + $this->getModel()->fAmountRefunded = $this->getMollie()->amountRefunded->value; + } + if ($this->getMollie()->amountCaptured) { + $this->getModel()->fAmountCaptured = $this->getMollie()->amountCaptured->value; + } + $this->getModel()->cMode = $this->getMollie()->mode ?: null; + $this->getModel()->cRedirectURL = $this->getMollie()->redirectUrl; + $this->getModel()->cWebhookURL = $this->getMollie()->webhookUrl; + $this->getModel()->cCheckoutURL = $this->getMollie()->getCheckoutUrl(); + } + + $this->getModel()->kBestellung = $this->getBestellung()->kBestellung; + $this->getModel()->cOrderNumber = $this->getBestellung()->cBestellNr; + $this->getModel()->cHash = trim($this->getHash(), '_'); + + $this->getModel()->bSynced = $this->getModel()->bSynced !== null ? $this->getModel()->bSynced : Helper::getSetting('onlyPaid') !== 'Y'; + + return $this; + } + + /** + * @param false $force + * @return null|\Mollie\Api\Resources\Payment|Order + */ + abstract public function getMollie($force = false); + + /** + * @return stdClass + */ + abstract public function getIncomingPayment(); + + /** + * @param Bestellung $oBestellung + * @param Payment $model + * @return bool + */ + public static function makeFetchable(Bestellung $oBestellung, Payment $model) + { + // TODO: force ? + if ($oBestellung->cAbgeholt === 'Y' && !$model->bSynced) { + Shop::DB()->update('tbestellung', 'kBestellung', $oBestellung->kBestellung, (object)['cAbgeholt' => 'N']); + } + $model->bSynced = true; + + try { + return $model->save(); + } catch (Exception $e) { + Jtllog::writeLog(sprintf('Fehler beim speichern des Models: %s / Bestellung: %s', $model->kID, $oBestellung->cBestellNr)); + } + + return false; + } + + public function Log($msg, $level = LOGLEVEL_NOTICE) + { + try { + $data = ''; + if ($this->getBestellung()) { + $data .= '#' . $this->getBestellung()->kBestellung; + } + if ($this->getMollie()) { + $data .= '$' . $this->getMollie()->id; + } + ZahlungsLog::add($this->PaymentMethod()->moduleID, '[' . microtime(true) . ' - ' . $_SERVER['PHP_SELF'] . '] ' . $msg, $data, $level); + } catch (Exception $e) { + Jtllog::writeLog('Mollie Log failed: ' . $e->getMessage() . '; Previous Log: ' . print_r([$msg, $level, $data], 1)); + } + + return $this; + } + + /** + * @return bool + */ + public function completlyPaid() + { + if ( + $row = Shop::DB()->executeQueryPrepared('SELECT SUM(fBetrag) as fBetragSumme FROM tzahlungseingang WHERE kBestellung = :kBestellung', [ + ':kBestellung' => $this->getBestellung()->kBestellung + ], 1) + ) { + return $row->fBetragSumme >= round($this->getBestellung()->fGesamtsumme * $this->getBestellung()->fWaehrungsFaktor, 2); + } + + return false; + } + + /** + * @param $kBestellung + * * @throws RuntimeException + * @return OrderCheckout|PaymentCheckout + */ + public static function fromBestellung($kBestellung) + { + if ($model = Payment::fromID($kBestellung, 'kBestellung')) { + return static::fromModel($model); + } + + throw new RuntimeException(sprintf('Error loading Order for Bestellung: %s', $kBestellung)); + } + + public static function sendReminders() + { + $reminder = (int)self::Plugin()->oPluginEinstellungAssoc_arr['reminder']; + + if (!$reminder) { + return; + } + + $sql = 'SELECT p.kID FROM xplugin_ws_mollie_payments p JOIN tbestellung b ON b.kBestellung = p.kBestellung ' + . "WHERE (p.dReminder IS NULL OR p.dReminder = '0000-00-00 00:00:00') " + . 'AND p.dCreatedAt < NOW() - INTERVAL :d MINUTE AND p.dCreatedAt > NOW() - INTERVAL 7 DAY ' + . "AND p.cStatus IN ('created','open', 'expired', 'failed', 'canceled') AND NOT b.cStatus = '-1'"; + + $remindables = Shop::DB()->executeQueryPrepared($sql, [ + ':d' => $reminder + ], 2); + foreach ($remindables as $remindable) { + try { + self::sendReminder($remindable->kID); + } catch (Exception $e) { + Jtllog::writeLog('AbstractCheckout::sendReminders: ' . $e->getMessage()); + } + } + } + + /** + * @param $kID + * @return bool + */ + public static function sendReminder($kID) + { + $checkout = self::fromID($kID); + $return = true; + + if (!$checkout->getBestellung()->kBestellung || (int)$checkout->getBestellung()->cStatus > BESTELLUNG_STATUS_IN_BEARBEITUNG || (int)$checkout->getBestellung()->cStatus < 0) { + return $return; + } + + + try { + $repayURL = Shop::getURL() . '/?m_pay=' . md5($checkout->getModel()->kID . '-' . $checkout->getBestellung()->kBestellung); + + $data = new stdClass(); + $data->tkunde = new Kunde($checkout->getBestellung()->oKunde->kKunde); + if ($data->tkunde->kKunde) { + $data->Bestellung = $checkout->getBestellung(); + $data->PayURL = $repayURL; + $data->Amount = gibPreisStringLocalized($checkout->getModel()->fAmount, $checkout->getBestellung()->Waehrung); //Preise::getLocalizedPriceString($order->getAmount(), Currency::fromISO($order->getCurrency()), false); + + require_once PFAD_ROOT . PFAD_INCLUDES . 'mailTools.php'; + + $mail = new stdClass(); + $mail->toEmail = $data->tkunde->cMail; + $mail->toName = trim((isset($data->tKunde->cVorname) + ? $data->tKunde->cVorname + : '') . ' ' . ( + isset($data->tKunde->cNachname) + ? $data->tKunde->cNachname + : '' + )) ?: $mail->toEmail; + $data->mail = $mail; + if (!($sentMail = sendeMail('kPlugin_' . self::Plugin()->kPlugin . '_zahlungserinnerung', $data))) { + $checkout->Log(sprintf("Zahlungserinnerung konnte nicht versand werden: %s\n%s", isset($sentMail->cFehler) ?: print_r($sentMail, 1), print_r($data, 1)), LOGLEVEL_ERROR); + $return = false; + } else { + $checkout->Log(sprintf('Zahlungserinnerung für %s verschickt.', $checkout->getBestellung()->cBestellNr)); + } + } else { + $checkout->Log("Kunde '{$checkout->getBestellung()->oKunde->kKunde}' nicht gefunden.", LOGLEVEL_ERROR); + } + } catch (Exception $e) { + $checkout->Log(sprintf('AbstractCheckout::sendReminder: Zahlungserinnerung für %s fehlgeschlagen: %s', $checkout->getBestellung()->cBestellNr, $e->getMessage())); + $return = false; + } + $checkout->getModel()->dReminder = date('Y-m-d H:i:s'); + $checkout->getModel()->save(); + + return $return; + } + + /** + * @param AbstractCheckout $checkout + * @throws ApiException + * @return BaseResource|Refund + */ + public static function refund(self $checkout) + { + if ($checkout->getMollie()->resource === 'order') { + /** @var Order $order */ + $order = $checkout->getMollie(); + if (in_array($order->status, [OrderStatus::STATUS_CANCELED, OrderStatus::STATUS_EXPIRED, OrderStatus::STATUS_CREATED], true)) { + throw new RuntimeException('Bestellung kann derzeit nicht zurückerstattet werden.'); + } + $refund = $order->refundAll(); + $checkout->Log(sprintf('Bestellung wurde manuell zurückerstattet: %s', $refund->id)); + + return $refund; + } + if ($checkout->getMollie()->resource === 'payment') { + /** @var \Mollie\Api\Resources\Payment $payment */ + $payment = $checkout->getMollie(); + if (in_array($payment->status, [PaymentStatus::STATUS_CANCELED, PaymentStatus::STATUS_EXPIRED, PaymentStatus::STATUS_OPEN], true)) { + throw new RuntimeException('Zahlung kann derzeit nicht zurückerstattet werden.'); + } + $refund = $checkout->API()->Client()->payments->refund($checkout->getMollie(), ['amount' => $checkout->getMollie()->amount]); + $checkout->Log(sprintf('Zahlung wurde manuell zurückerstattet: %s', $refund->id)); + + return $refund; + } + + throw new RuntimeException(sprintf('Unbekannte Resource: %s', $checkout->getMollie()->resource)); + } + + /** + * @return API + */ + public function API() + { + if (!$this->api) { + if ($this->getModel()->kID) { + $this->api = new API($this->getModel()->cMode === 'test'); + } else { + $this->api = new API(API::getMode()); + } + } + + return $this->api; + } + + /** + * @param $checkout + * @throws ApiException + * @return \Mollie\Api\Resources\Payment|Order + */ + public static function cancel($checkout) + { + if ($checkout instanceof OrderCheckout) { + return OrderCheckout::cancel($checkout); + } + if ($checkout instanceof PaymentCheckout) { + return PaymentCheckout::cancel($checkout); + } + + throw new RuntimeException('AbstractCheckout::cancel: Invalid Checkout!'); + } + + 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[] = static::getLocale($sS->cISO, $land); + } + } + + return array_intersect(array_unique($result), $locales); + } + + public static function getLocale($cISOSprache = null, $country = null) + { + if ($cISOSprache === null) { + $cISOSprache = gibStandardsprache()->cISO; + } + if (array_key_exists($cISOSprache, self::$localeLangs)) { + $locale = self::$localeLangs[$cISOSprache]['lang']; + if ($country && is_array(self::$localeLangs[$cISOSprache]['country']) && in_array($country, self::$localeLangs[$cISOSprache]['country'], true)) { + $locale .= '_' . strtoupper($country); + } else { + $locale .= '_' . self::$localeLangs[$cISOSprache]['country'][0]; + } + + return $locale; + } + + return self::Plugin()->oPluginEinstellungAssoc_arr['fallbackLocale']; + } + + 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; + } + + public function loadRequest(&$options = []) + { + $oKunde = !$this->getBestellung()->oKunde && $this->PaymentMethod()->duringCheckout ? $_SESSION['Kunde'] : $this->getBestellung()->oKunde; + if ($this->getBestellung()) { + if ( + $oKunde->nRegistriert + && ( + $customer = $this->getCustomer( + array_key_exists( + 'mollie_create_customer', + $_SESSION['cPost_arr'] ?: [] + ) && $_SESSION['cPost_arr']['mollie_create_customer'] === 'Y', + $oKunde + ) + ) + && isset($customer) + ) { + $options['customerId'] = $customer->id; + } + $this->amount = Amount::factory($this->getBestellung()->fGesamtsummeKundenwaehrung, $this->getBestellung()->Waehrung->cISO, true); + $this->redirectUrl = $this->PaymentMethod()->duringCheckout ? Shop::getURL() . '/bestellabschluss.php?' . http_build_query(['hash' => $this->getHash()]) : $this->PaymentMethod()->getReturnURL($this->getBestellung()); + $this->metadata = [ + 'kBestellung' => $this->getBestellung()->kBestellung ?: $this->getBestellung()->cBestellNr, + 'kKunde' => $this->getBestellung()->kKunde, + 'kKundengruppe' => Session::getInstance()->CustomerGroup()->kKundengruppe, + 'cHash' => $this->getHash(), + ]; + } + + $this->locale = self::getLocale($_SESSION['cISOSprache'], Session::getInstance()->Customer()->cLand); + $this->webhookUrl = Shop::getURL(true) . '/?' . http_build_query([ + 'mollie' => 1, + 'hash' => $this->getHash(), + 'test' => $this->API()->isTest() ?: null, + ]); + + $pm = $this->PaymentMethod(); + $isPayAgain = strpos($_SERVER['PHP_SELF'], 'bestellab_again') !== false; + if ($pm::METHOD !== '' && (self::Plugin()->oPluginEinstellungAssoc_arr['resetMethod'] !== 'Y' || !$isPayAgain)) { + $this->method = $pm::METHOD; + } + } + + /** + * @todo: Kunde wieder löschbar machen ?! + * @param mixed $createOrUpdate + * @param null|mixed $oKunde + * @return null|\Mollie\Api\Resources\Customer + */ + public function getCustomer($createOrUpdate = false, $oKunde = null) + { + if (!$oKunde) { + $oKunde = $this->getBestellung()->oKunde; + } + + if (!$this->customer) { + $customerModel = Customer::fromID($oKunde->kKunde, 'kKunde'); + if ($customerModel->customerId) { + try { + $this->customer = $this->API()->Client()->customers->get($customerModel->customerId); + } catch (ApiException $e) { + $this->Log(sprintf('Fehler beim laden des Mollie Customers %s (kKunde: %d): %s', $customerModel->customerId, $customerModel->kKunde, $e->getMessage()), LOGLEVEL_ERROR); + } + } + + if ($createOrUpdate) { + $customer = [ + 'name' => utf8_encode(trim($oKunde->cVorname . ' ' . $oKunde->cNachname)), + 'email' => utf8_encode($oKunde->cMail), + 'locale' => self::getLocale($_SESSION['cISOSprache'], $oKunde->cLand), + 'metadata' => (object)[ + 'kKunde' => $oKunde->kKunde, + 'kKundengruppe' => $oKunde->kKundengruppe, + 'cKundenNr' => utf8_encode($oKunde->cKundenNr), + ], + ]; + + if ($this->customer) { // UPDATE + $this->customer->name = $customer['name']; + $this->customer->email = $customer['email']; + $this->customer->locale = $customer['locale']; + $this->customer->metadata = $customer['metadata']; + + try { + $this->customer->update(); + } catch (Exception $e) { + $this->Log(sprintf("Fehler beim aktualisieren des Mollie Customers %s: %s\n%s", $this->customer->id, $e->getMessage(), print_r($customer, 1)), LOGLEVEL_ERROR); + } + } else { // create + try { + $this->customer = $this->API()->Client()->customers->create($customer); + $customerModel->kKunde = $oKunde->kKunde; + $customerModel->customerId = $this->customer->id; + $customerModel->save(); + $this->Log(sprintf("Customer '%s' für Kunde %s (%d) bei Mollie angelegt.", $this->customer->id, $this->customer->name, $this->getBestellung()->kKunde)); + } catch (Exception $e) { + $this->Log(sprintf("Fehler beim anlegen eines Mollie Customers: %s\n%s", $e->getMessage(), print_r($customer, 1)), LOGLEVEL_ERROR); + } + } + } + } + + return $this->customer; + } + + /** + * Storno Order + */ + public function storno() + { + if (in_array((int)$this->getBestellung()->cStatus, [BESTELLUNG_STATUS_OFFEN, BESTELLUNG_STATUS_IN_BEARBEITUNG], true)) { + $log = []; + + $conf = Shop::getSettings([CONF_GLOBAL, CONF_TRUSTEDSHOPS]); + $nArtikelAnzeigefilter = (int)$conf['global']['artikel_artikelanzeigefilter']; + + foreach ($this->getBestellung()->Positionen as $pos) { + if ($pos->kArtikel && $pos->Artikel && $pos->Artikel->cLagerBeachten === 'Y') { + $log[] = sprintf('Reset stock of "%s" by %d', $pos->Artikel->cArtNr, -1 * $pos->nAnzahl); + self::aktualisiereLagerbestand($pos->Artikel, -1 * $pos->nAnzahl, $pos->WarenkorbPosEigenschaftArr, $nArtikelAnzeigefilter); + } + } + $log[] = sprintf("Cancel order '%s'.", $this->getBestellung()->cBestellNr); + + if (Shop::DB()->executeQueryPrepared('UPDATE tbestellung SET cAbgeholt = \'Y\', cStatus = :cStatus WHERE kBestellung = :kBestellung', [':cStatus' => '-1', ':kBestellung' => $this->getBestellung()->kBestellung], 3)) { + $this->Log(implode('\n', $log)); + } + } + } + + protected static function aktualisiereLagerbestand($Artikel, $nAnzahl, $WarenkorbPosEigenschaftArr, $nArtikelAnzeigefilter = 1) + { + $artikelBestand = (float)$Artikel->fLagerbestand; + + if (isset($Artikel->cLagerBeachten) && $Artikel->cLagerBeachten === 'Y') { + if ( + $Artikel->cLagerVariation === 'Y' && is_array($WarenkorbPosEigenschaftArr) && count($WarenkorbPosEigenschaftArr) > 0 + ) { + foreach ($WarenkorbPosEigenschaftArr as $eWert) { + $EigenschaftWert = new EigenschaftWert($eWert->kEigenschaftWert); + if ($EigenschaftWert->fPackeinheit === .0) { + $EigenschaftWert->fPackeinheit = 1; + } + Shop::DB()->query( + 'UPDATE teigenschaftwert + SET fLagerbestand = fLagerbestand - ' . ($nAnzahl * $EigenschaftWert->fPackeinheit) . ' + WHERE kEigenschaftWert = ' . (int)$eWert->kEigenschaftWert, + 4 + ); + } + } elseif ($Artikel->fPackeinheit > 0) { + // Stückliste + if ($Artikel->kStueckliste > 0) { + $artikelBestand = self::aktualisiereStuecklistenLagerbestand($Artikel, $nAnzahl); + } else { + Shop::DB()->query( + 'UPDATE tartikel + SET fLagerbestand = IF (fLagerbestand >= ' . ($nAnzahl * $Artikel->fPackeinheit) . ', + (fLagerbestand - ' . ($nAnzahl * $Artikel->fPackeinheit) . '), fLagerbestand) + WHERE kArtikel = ' . (int)$Artikel->kArtikel, + 4 + ); + $tmpArtikel = Shop::DB()->select('tartikel', 'kArtikel', (int)$Artikel->kArtikel, null, null, null, null, false, 'fLagerbestand'); + if ($tmpArtikel !== null) { + $artikelBestand = (float)$tmpArtikel->fLagerbestand; + } + // Stücklisten Komponente + if (ArtikelHelper::isStuecklisteKomponente($Artikel->kArtikel)) { + self::aktualisiereKomponenteLagerbestand($Artikel->kArtikel, $artikelBestand, isset($Artikel->cLagerKleinerNull) && $Artikel->cLagerKleinerNull === 'Y'); + } + } + // Aktualisiere Merkmale in tartikelmerkmal vom Vaterartikel + if ($Artikel->kVaterArtikel > 0) { + Artikel::beachteVarikombiMerkmalLagerbestand($Artikel->kVaterArtikel, $nArtikelAnzeigefilter); + } + } + } + + return $artikelBestand; + } + + protected static function aktualisiereStuecklistenLagerbestand($oStueckListeArtikel, $nAnzahl) + { + $nAnzahl = (float)$nAnzahl; + $kStueckListe = (int)$oStueckListeArtikel->kStueckliste; + $bestandAlt = (float)$oStueckListeArtikel->fLagerbestand; + $bestandNeu = $bestandAlt; + $bestandUeberverkauf = $bestandAlt; + + if ($nAnzahl > 0) { + // Gibt es lagerrelevante Komponenten in der Stückliste? + $oKomponente_arr = Shop::DB()->query( + "SELECT tstueckliste.kArtikel, tstueckliste.fAnzahl + FROM tstueckliste + JOIN tartikel + ON tartikel.kArtikel = tstueckliste.kArtikel + WHERE tstueckliste.kStueckliste = $kStueckListe + AND tartikel.cLagerBeachten = 'Y'", + 2 + ); + + if (is_array($oKomponente_arr) && count($oKomponente_arr) > 0) { + // wenn ja, dann wird für diese auch der Bestand aktualisiert + $options = Artikel::getDefaultOptions(); + + $options->nKeineSichtbarkeitBeachten = 1; + + foreach ($oKomponente_arr as $oKomponente) { + $tmpArtikel = new Artikel(); + $tmpArtikel->fuelleArtikel($oKomponente->kArtikel, $options); + + $komponenteBestand = floor(self::aktualisiereLagerbestand($tmpArtikel, $nAnzahl * $oKomponente->fAnzahl, null) / $oKomponente->fAnzahl); + + if ($komponenteBestand < $bestandNeu && $tmpArtikel->cLagerKleinerNull !== 'Y') { + // Neuer Bestand ist der Kleinste Komponententbestand aller Artikel ohne Überverkauf + $bestandNeu = $komponenteBestand; + } elseif ($komponenteBestand < $bestandUeberverkauf) { + // Für Komponenten mit Überverkauf wird der kleinste Bestand ermittelt. + $bestandUeberverkauf = $komponenteBestand; + } + } + } + + // Ist der alte gleich dem neuen Bestand? + if ($bestandAlt === $bestandNeu) { + // Es sind keine lagerrelevanten Komponenten vorhanden, die den Bestand der Stückliste herabsetzen. + if ($bestandUeberverkauf === $bestandNeu) { + // Es gibt auch keine Komponenten mit Überverkäufen, die den Bestand verringern, deshalb wird + // der Bestand des Stücklistenartikels anhand des Verkaufs verringert + $bestandNeu = $bestandNeu - $nAnzahl * $oStueckListeArtikel->fPackeinheit; + } else { + // Da keine lagerrelevanten Komponenten vorhanden sind, wird der kleinste Bestand der + // Komponentent mit Überverkauf verwendet. + $bestandNeu = $bestandUeberverkauf; + } + + Shop::DB()->update('tartikel', 'kArtikel', (int)$oStueckListeArtikel->kArtikel, (object)[ + 'fLagerbestand' => $bestandNeu, + ]); + } + // Kein Lagerbestands-Update für die Stückliste notwendig! Dies erfolgte bereits über die Komponentenabfrage und + // die dortige Lagerbestandsaktualisierung! + } + + return $bestandNeu; + } + + protected static function aktualisiereKomponenteLagerbestand($kKomponenteArtikel, $fLagerbestand, $bLagerKleinerNull) + { + $kKomponenteArtikel = (int)$kKomponenteArtikel; + $fLagerbestand = (float)$fLagerbestand; + + $oStueckliste_arr = Shop::DB()->query( + "SELECT tstueckliste.kStueckliste, tstueckliste.fAnzahl, + tartikel.kArtikel, tartikel.fLagerbestand, tartikel.cLagerKleinerNull + FROM tstueckliste + JOIN tartikel + ON tartikel.kStueckliste = tstueckliste.kStueckliste + WHERE tstueckliste.kArtikel = $kKomponenteArtikel + AND tartikel.cLagerBeachten = 'Y'", + 2 + ); + + if (is_array($oStueckliste_arr) && count($oStueckliste_arr) > 0) { + foreach ($oStueckliste_arr as $oStueckliste) { + // Ist der aktuelle Bestand der Stückliste größer als dies mit dem Bestand der Komponente möglich wäre? + $maxAnzahl = floor($fLagerbestand / $oStueckliste->fAnzahl); + if ($maxAnzahl < (float)$oStueckliste->fLagerbestand && (!$bLagerKleinerNull || $oStueckliste->cLagerKleinerNull === 'Y')) { + // wenn ja, dann den Bestand der Stückliste entsprechend verringern, aber nur wenn die Komponente nicht + // überberkaufbar ist oder die gesamte Stückliste Überverkäufe zulässt + Shop::DB()->update('tartikel', 'kArtikel', (int)$oStueckliste->kArtikel, (object)[ + 'fLagerbestand' => $maxAnzahl, + ]); + } + } + } + } + + /** + * @return null|array|bool|int|object + */ + public function getLogs() + { + return 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' => '%#' . ($this->getBestellung()->kBestellung ?: '##') . '%', + ':cBestellNr' => '%§' . ($this->getBestellung()->cBestellNr ?: '§§') . '%', + ':MollieID' => '%$' . ($this->getMollie()->id ?: '$$') . '%', + ], 2); + } + + /** + * @return bool + */ + public function remindable() + { + return (int)$this->getBestellung()->cStatus !== BESTELLUNG_STATUS_STORNO && !in_array($this->getModel()->cStatus, [PaymentStatus::STATUS_PAID, PaymentStatus::STATUS_AUTHORIZED, PaymentStatus::STATUS_PENDING, OrderStatus::STATUS_COMPLETED, OrderStatus::STATUS_SHIPPING], true); + } + + /** + * @return string + */ + public function LogData() + { + $data = ''; + if ($this->getBestellung()->kBestellung) { + $data .= '#' . $this->getBestellung()->kBestellung; + } + if ($this->getMollie()) { + $data .= '$' . $this->getMollie()->id; + } + + return $data; + } + + abstract public function cancelOrRefund($force = false); + + /** + * @param array $paymentOptions + * @return Order|Payment + */ + abstract public function create(array $paymentOptions = []); + + /** + * @return string + */ + public function getRepayURL() + { + return Shop::getURL(true) . '/?m_pay=' . md5($this->getModel()->kID . '-' . $this->getBestellung()->kBestellung); + } + + public function getDescription() + { + $descTemplate = trim(Helper::getSetting('paymentDescTpl')) ?: 'Order {orderNumber}'; + $oKunde = $this->getBestellung()->oKunde ?: $_SESSION['Kunde']; + + return str_replace([ + '{orderNumber}', + '{storeName}', + '{customer.firstname}', + '{customer.lastname}', + '{customer.company}', + ], [ + $this->getBestellung()->cBestellNr, + Shop::getSettings([CONF_GLOBAL])['global']['global_shopname'], + $oKunde->cVorname, + $oKunde->cNachname, + $oKunde->cFirma + + ], $descTemplate); + } + + abstract protected function updateOrderNumber(); + + /** + * @param Bestellung $oBestellung + * @return $this + */ + protected function setBestellung(Bestellung $oBestellung) + { + $this->oBestellung = $oBestellung; + + return $this; + } + + /** + * @param \Mollie\Api\Resources\Payment|Order $model + * @return self + */ + abstract protected function setMollie($model); +} diff --git a/version/206/class/Checkout/AbstractResource.php b/version/206/class/Checkout/AbstractResource.php new file mode 100644 index 0000000..8d1b2b2 --- /dev/null +++ b/version/206/class/Checkout/AbstractResource.php @@ -0,0 +1,17 @@ +title = substr(trim(($address->cAnrede === 'm' ? Shop::Lang()->get('mr') : Shop::Lang()->get('mrs')) . ' ' . $address->cTitel) ?: null, 0, 20); + $resource->givenName = $address->cVorname; + $resource->familyName = $address->cNachname; + $resource->email = $address->cMail ?: null; + + if ($organizationName = trim($address->cFirma)) { + $resource->organizationName = $organizationName; + } + + // Validity-Check + // TODO: Phone, with E.164 check + // TODO: Is Email-Format Check needed? + if (!$resource->givenName || !$resource->familyName || !$resource->email) { + throw ResourceValidityException::trigger(ResourceValidityException::ERROR_REQUIRED, ['givenName', 'familyName', 'email'], $resource); + } + + return $resource; + } +} diff --git a/version/206/class/Checkout/Order/OrderLine.php b/version/206/class/Checkout/Order/OrderLine.php new file mode 100644 index 0000000..a76bfbb --- /dev/null +++ b/version/206/class/Checkout/Order/OrderLine.php @@ -0,0 +1,236 @@ +totalAmount->value; + } + if (abs($sum - (float)$amount->value) > 0) { + $diff = (round((float)$amount->value - $sum, 2)); + if ($diff !== 0.0) { + $line = new self(); + $line->type = $diff > 0 ? OrderLineType::TYPE_SURCHARGE : OrderLineType::TYPE_DISCOUNT; + // TODO: Translation needed? + $line->name = 'Rundungsausgleich'; + $line->quantity = 1; + $line->unitPrice = Amount::factory($diff, $currency); + $line->totalAmount = Amount::factory($diff, $currency); + $line->vatRate = '0.00'; + $line->vatAmount = Amount::factory(0, $currency); + + return $line; + } + } + + return null; + } + + /** + * @param Bestellung $oBestellung + * @return OrderLine + */ + public static function getCredit(Bestellung $oBestellung) + { + $line = new self(); + $line->type = OrderLineType::TYPE_STORE_CREDIT; + $line->name = 'Guthaben'; + $line->quantity = 1; + // TODO: check currency of Guthaben + $line->unitPrice = Amount::factory($oBestellung->fGuthaben, $oBestellung->Waehrung->cISO); + $line->totalAmount = $line->unitPrice; + $line->vatRate = '0.00'; + $line->vatAmount = Amount::factory(0, $oBestellung->Waehrung->cISO); + + return $line; + } + + /** + * @param stdClass|WarenkorbPos $oPosition + * @param null $currency + * @return OrderLine + */ + public static function factory($oPosition, $currency = null) + { + if (!$oPosition) { + throw new RuntimeException('$oPosition invalid:', print_r($oPosition, 1)); + } + + $resource = new static(); + + $resource->fill($oPosition, $currency); + + // Validity Check + if ( + !$resource->name || !$resource->quantity || !$resource->unitPrice || !$resource->totalAmount + || !$resource->vatRate || !$resource->vatAmount + ) { + throw ResourceValidityException::trigger( + ResourceValidityException::ERROR_REQUIRED, + ['name', 'quantity', 'unitPrice', 'totalAmount', 'vatRate', 'vatAmount'], + $resource + ); + } + + return $resource; + } + + /** + * @param stdClass|WarenkorbPos $oPosition + * @param null|stdClass $currency + * @return $this + * @todo Setting for Fraction handling needed? + */ + protected function fill($oPosition, $currency = null) + { + if (!$currency) { + $currency = Amount::FallbackCurrency(); + } + + $isKupon = (int)$oPosition->nPosTyp === (int)C_WARENKORBPOS_TYP_KUPON; + $isFrac = fmod($oPosition->nAnzahl, 1) !== 0.0; + + // Kupon? set vatRate to 0 and adjust netto + $vatRate = $isKupon ? 0 : (float)$oPosition->fMwSt / 100; + $netto = $isKupon ? round($oPosition->fPreis * (1 + $vatRate), 4) : round($oPosition->fPreis, 4); + + // Fraction? transform, as it were 1, and set quantity to 1 + $netto = round(($isFrac ? $netto * (float)$oPosition->nAnzahl : $netto) * $currency->fFaktor, 4); + $this->quantity = $isFrac ? 1 : (int)$oPosition->nAnzahl; + + // Fraction? include quantity and unit in name + $this->name = $isFrac ? sprintf('%s (%.2f %s)', $oPosition->cName, (float)$oPosition->nAnzahl, $oPosition->cEinheit) : $oPosition->cName; + if (!$this->name) { + $this->name = '(null)'; + } + $this->mapType($oPosition->nPosTyp, $netto > 0); + + //$unitPriceNetto = round(($currency->fFaktor * $netto), 4); + + $this->unitPrice = Amount::factory(round($netto * (1 + $vatRate), 2), $currency->cISO, false); + $this->totalAmount = Amount::factory(round($this->quantity * $this->unitPrice->value, 2), $currency->cISO, false); + + $this->vatRate = number_format($vatRate * 100, 2); + $this->vatAmount = Amount::factory(round($this->totalAmount->value - ($this->totalAmount->value / (1 + $vatRate)), 2), $currency->cISO, false); + + $metadata = []; + + // Is Artikel ? + if (isset($oPosition->Artikel)) { + $this->sku = $oPosition->Artikel->cArtNr; + $metadata['kArtikel'] = $oPosition->kArtikel; + if ($oPosition->cUnique !== '') { + $metadata['cUnique'] = utf8_encode($oPosition->cUnique); + } + } + + if (isset($oPosition->WarenkorbPosEigenschaftArr) && is_array($oPosition->WarenkorbPosEigenschaftArr) && count($oPosition->WarenkorbPosEigenschaftArr)) { + $metadata['properties'] = []; + /** @var WarenkorbPosEigenschaft $warenkorbPosEigenschaft */ + foreach ($oPosition->WarenkorbPosEigenschaftArr as $warenkorbPosEigenschaft) { + $metadata['properties'][] = [ + 'kEigenschaft' => $warenkorbPosEigenschaft->kEigenschaft, + 'kEigenschaftWert' => $warenkorbPosEigenschaft->kEigenschaftWert, + 'name' => utf8_encode($warenkorbPosEigenschaft->cEigenschaftName), + 'value' => utf8_encode($warenkorbPosEigenschaft->cEigenschaftWertName), + ]; + if (strlen(json_encode($metadata)) > 1000) { + array_pop($metadata['properties']); + + break; + } + } + } + if (json_encode($metadata) !== false) { + $this->metadata = $metadata; + } + + return $this; + } + + /** + * @param $nPosTyp + * @param $positive + * @return OrderLine + */ + protected function mapType($nPosTyp, $positive) + { + switch ($nPosTyp) { + case C_WARENKORBPOS_TYP_ARTIKEL: + case C_WARENKORBPOS_TYP_GRATISGESCHENK: + // TODO: digital / Download Artikel? + $this->type = OrderLineType::TYPE_PHYSICAL; + + return $this; + + case C_WARENKORBPOS_TYP_VERSANDPOS: + $this->type = OrderLineType::TYPE_SHIPPING_FEE; + + return $this; + + case C_WARENKORBPOS_TYP_GUTSCHEIN: + case C_WARENKORBPOS_TYP_KUPON: + case C_WARENKORBPOS_TYP_NEUKUNDENKUPON: + $this->type = OrderLineType::TYPE_DISCOUNT; + + return $this; + + case C_WARENKORBPOS_TYP_VERPACKUNG: + case C_WARENKORBPOS_TYP_VERSANDZUSCHLAG: + case C_WARENKORBPOS_TYP_ZAHLUNGSART: + case C_WARENKORBPOS_TYP_VERSAND_ARTIKELABHAENGIG: + case C_WARENKORBPOS_TYP_NACHNAHMEGEBUEHR: + $this->type = OrderLineType::TYPE_SURCHARGE; + + return $this; + + default: + $this->type = $positive ? OrderLineType::TYPE_SURCHARGE : OrderLineType::TYPE_DISCOUNT; + + return $this; + } + } +} diff --git a/version/206/class/Checkout/OrderCheckout.php b/version/206/class/Checkout/OrderCheckout.php new file mode 100644 index 0000000..041a002 --- /dev/null +++ b/version/206/class/Checkout/OrderCheckout.php @@ -0,0 +1,405 @@ +getMollie()->status !== OrderStatus::STATUS_AUTHORIZED && $checkout->getMollie()->status !== OrderStatus::STATUS_SHIPPING) { + throw new RuntimeException('Nur autorisierte Zahlungen können erfasst werden!'); + } + $shipment = $checkout->API()->Client()->shipments->createFor($checkout->getMollie(), ['lines' => []]); + $checkout->Log(sprintf('Bestellung wurde manuell erfasst/versandt: %s', $shipment->id)); + + return $shipment->id; + } + + /** + * @param false $force + * @return null|Order + */ + public function getMollie($force = false) + { + if ($force || (!$this->order && $this->getModel()->kID)) { + try { + $this->order = $this->API()->Client()->orders->get($this->getModel()->kID, ['embed' => 'payments,shipments,refunds']); + } catch (Exception $e) { + throw new RuntimeException(sprintf('Mollie-Order \'%s\' konnte nicht geladen werden: %s', $this->getModel()->kID, $e->getMessage())); + } + } + + return $this->order; + } + + /** + * @param OrderCheckout $checkout + * @throws ApiException + * @return Order + */ + public static function cancel($checkout) + { + if (!$checkout->getMollie() || !$checkout->getMollie()->isCancelable) { + throw new RuntimeException('Bestellung kann nicht abgebrochen werden.'); + } + $order = $checkout->getMollie()->cancel(); + $checkout->Log('Bestellung wurde manuell abgebrochen.'); + + return $order; + } + + /** + * @throws Exception + * @return array + */ + public function getShipments() + { + $shipments = []; + $lieferschien_arr = Shop::DB()->executeQueryPrepared('SELECT kLieferschein FROM tlieferschein WHERE kInetBestellung = :kBestellung', [ + ':kBestellung' => $this->getBestellung()->kBestellung + ], 2); + + foreach ($lieferschien_arr as $lieferschein) { + $shipments[] = new Shipment($lieferschein->kLieferschein, $this); + } + + return $shipments; + } + + /** + * @param mixed $force + * @throws ApiException + * @return string + */ + public function cancelOrRefund($force = false) + { + if (!$this->getMollie()) { + throw new RuntimeException('Mollie-Order konnte nicht geladen werden: ' . $this->getModel()->kID); + } + if ($force || (int)$this->getBestellung()->cStatus === BESTELLUNG_STATUS_STORNO) { + if ($this->getMollie()->isCancelable) { + $res = $this->getMollie()->cancel(); + $result = 'Order cancelled, Status: ' . $res->status; + } else { + $res = $this->getMollie()->refundAll(); + $result = 'Order Refund initiiert, Status: ' . $res->status; + } + $this->PaymentMethod()->Log('OrderCheckout::cancelOrRefund: ' . $result, $this->LogData()); + + return $result; + } + + throw new RuntimeException('Bestellung ist derzeit nicht storniert, Status: ' . $this->getBestellung()->cStatus); + } + + /** + * @param array $paymentOptions + * @return Order + */ + public function create(array $paymentOptions = []) + { + if ($this->getModel()->kID) { + try { + $this->order = $this->API()->Client()->orders->get($this->getModel()->kID, ['embed' => 'payments']); + if (in_array($this->order->status, [OrderStatus::STATUS_COMPLETED, OrderStatus::STATUS_PAID, OrderStatus::STATUS_AUTHORIZED, OrderStatus::STATUS_PENDING], true)) { + $this->handleNotification(); + + throw new RuntimeException(self::Plugin()->oPluginSprachvariableAssoc_arr['errAlreadyPaid']); + } + if ($this->order->status === OrderStatus::STATUS_CREATED) { + if ($this->order->payments()) { + /** @var Payment $payment */ + foreach ($this->order->payments() as $payment) { + if ($payment->status === PaymentStatus::STATUS_OPEN) { + $this->setPayment($payment); + + break; + } + } + } + if (!$this->getPayment()) { + $this->setPayment($this->API()->Client()->orderPayments->createForId($this->getModel()->kID, $paymentOptions)); + } + $this->updateModel()->saveModel(); + + return $this->getMollie(true); + } + } catch (RuntimeException $e) { + throw $e; + } catch (Exception $e) { + $this->Log(sprintf("OrderCheckout::create: Letzte Order '%s' konnte nicht geladen werden: %s, versuche neue zu erstellen.", $this->getModel()->kID, $e->getMessage()), LOGLEVEL_ERROR); + } + } + + try { + $req = $this->loadRequest($paymentOptions)->jsonSerialize(); + $this->order = $this->API()->Client()->orders->create($req); + $this->Log(sprintf("Order für '%s' wurde erfolgreich angelegt: %s", $this->getBestellung()->cBestellNr, $this->order->id)); + $this->updateModel()->saveModel(); + + return $this->order; + } catch (Exception $e) { + $this->Log(sprintf("OrderCheckout::create: Neue Order '%s' konnte nicht erstellt werden: %s.", $this->getBestellung()->cBestellNr, $e->getMessage()), LOGLEVEL_ERROR); + + throw new RuntimeException(sprintf("Order für '%s' konnte nicht angelegt werden: %s", $this->getBestellung()->cBestellNr, $e->getMessage())); + } + } + + /** + * @param mixed $search + * @return null|Payment + */ + public function getPayment($search = false) + { + if (!$this->_payment && $search && $this->getMollie()) { + foreach ($this->getMollie()->payments() as $payment) { + if ( + in_array($payment->status, [ + PaymentStatus::STATUS_AUTHORIZED, + PaymentStatus::STATUS_PAID, + PaymentStatus::STATUS_PENDING, + ], true) + ) { + $this->_payment = $payment; + + break; + } + } + } + + return $this->_payment; + } + + /** + * @param $payment + * @return $this + */ + public function setPayment($payment) + { + $this->_payment = $payment; + + return $this; + } + + /** + * @return $this|OrderCheckout + */ + public function updateModel() + { + parent::updateModel(); + + if (!$this->getPayment() && $this->getMollie() && $this->getMollie()->payments()) { + /** @var Payment $payment */ + foreach ($this->getMollie()->payments() as $payment) { + if (in_array($payment->status, [PaymentStatus::STATUS_OPEN, PaymentStatus::STATUS_PENDING, PaymentStatus::STATUS_AUTHORIZED, PaymentStatus::STATUS_PAID], true)) { + $this->setPayment($payment); + + break; + } + } + } + if ($this->getPayment()) { + $this->getModel()->cTransactionId = $this->getPayment()->id; + } + if ($this->getMollie()) { + $this->getModel()->cCheckoutURL = $this->getMollie()->getCheckoutUrl(); + $this->getModel()->cWebhookURL = $this->getMollie()->webhookUrl; + $this->getModel()->cRedirectURL = $this->getMollie()->redirectUrl; + } + + return $this; + } + + /** + * @param array $options + * @return $this|OrderCheckout + */ + public function loadRequest(&$options = []) + { + parent::loadRequest($options); + + $this->orderNumber = $this->getBestellung()->cBestellNr; + + $this->billingAddress = Address::factory($this->getBestellung()->oRechnungsadresse); + if ($this->getBestellung()->Lieferadresse !== null) { + if (!$this->getBestellung()->Lieferadresse->cMail) { + $this->getBestellung()->Lieferadresse->cMail = $this->getBestellung()->oRechnungsadresse->cMail; + } + $this->shippingAddress = Address::factory($this->getBestellung()->Lieferadresse); + } + + if ( + !empty(Session::getInstance()->Customer()->dGeburtstag) + && Session::getInstance()->Customer()->dGeburtstag !== '0000-00-00' + && preg_match('/^\d{4}-\d{2}-\d{2}$/', trim(Session::getInstance()->Customer()->dGeburtstag)) + ) { + $this->consumerDateOfBirth = trim(Session::getInstance()->Customer()->dGeburtstag); + } + + $lines = []; + foreach ($this->getBestellung()->Positionen as $oPosition) { + $lines[] = OrderLine::factory($oPosition, $this->getBestellung()->Waehrung); + } + + if ($this->getBestellung()->GuthabenNutzen && $this->getBestellung()->fGuthaben > 0) { + $lines[] = OrderLine::getCredit($this->getBestellung()); + } + + if ($comp = OrderLine::getRoundingCompensation($lines, $this->amount, $this->getBestellung()->Waehrung->cISO)) { + $lines[] = $comp; + } + $this->lines = $lines; + + if ($dueDays = $this->PaymentMethod()->getExpiryDays()) { + try { + // #145 + //$max = $this->method && strpos($this->method, 'klarna') !== false ? 28 : 100; + $date = new DateTime(sprintf('+%d DAYS', $dueDays), new DateTimeZone('UTC')); + $this->expiresAt = $date->format('Y-m-d'); + } catch (Exception $e) { + $this->Log($e->getMessage(), LOGLEVEL_ERROR); + } + } + + $this->payment = $options; + + return $this; + } + + /** + * @return null|object + */ + public function getIncomingPayment() + { + if (!$this->getMollie(true)) { + return null; + } + + $cHinweis = sprintf('%s / %s', $this->getMollie()->id, $this->getPayment(true)->id); + if (Helper::getSetting('wawiPaymentID') === 'ord') { + $cHinweis = $this->getMollie()->id; + } elseif (Helper::getSetting('wawiPaymentID') === 'tr') { + $cHinweis = $this->getPayment(true)->id; + } + + + /** @var Payment $payment */ + /** @noinspection NullPointerExceptionInspection */ + foreach ($this->getMollie()->payments() as $payment) { + if ( + in_array( + $payment->status, + [PaymentStatus::STATUS_AUTHORIZED, PaymentStatus::STATUS_PAID], + true + ) + ) { + $this->setPayment($payment); + $data = (object)[ + 'fBetrag' => (float)$payment->amount->value, + 'cISO' => $payment->amount->currency, + 'cZahler' => $payment->details->paypalPayerId ?: $payment->customerId, + 'cHinweis' => $payment->details->paypalReference ?: $cHinweis, + ]; + if (isset($payment->details, $payment->details->paypalFee)) { + $data->fZahlungsgebuehr = $payment->details->paypalFee->value; + } + + return $data; + } + } + + return null; + } + + /** + * @return $this + */ + protected function updateOrderNumber() + { + try { + if ($this->getMollie()) { + $this->getMollie()->orderNumber = $this->getBestellung()->cBestellNr; + $this->getMollie()->webhookUrl = Shop::getURL() . '/?mollie=1'; + $this->getMollie()->update(); + } + if ($this->getModel()->cTransactionId) { + $this->API()->Client()->payments->update($this->getModel()->cTransactionId, [ + 'description' => $this->getDescription() + ]); + } + } catch (Exception $e) { + $this->Log('OrderCheckout::updateOrderNumber:' . $e->getMessage(), LOGLEVEL_ERROR); + } + + return $this; + } + + /** + * @param Order $model + * @return $this|AbstractCheckout + */ + protected function setMollie($model) + { + if ($model instanceof Order) { + $this->order = $model; + } + + return $this; + } +} diff --git a/version/206/class/Checkout/Payment/Address.php b/version/206/class/Checkout/Payment/Address.php new file mode 100644 index 0000000..731b55e --- /dev/null +++ b/version/206/class/Checkout/Payment/Address.php @@ -0,0 +1,52 @@ +streetAndNumber = $address->cStrasse . ' ' . $address->cHausnummer; + $resource->postalCode = $address->cPLZ; + $resource->city = $address->cOrt; + $resource->country = $address->cLand; + + if ( + isset($address->cAdressZusatz) + && trim($address->cAdressZusatz) !== '' + ) { + $resource->streetAdditional = trim($address->cAdressZusatz); + } + + // Validity-Check + // TODO: Check for valid Country Code? + // TODO: Check PostalCode requirement Country? + if (!$resource->streetAndNumber || !$resource->city || !$resource->country) { + throw ResourceValidityException::trigger(ResourceValidityException::ERROR_REQUIRED, ['streetAndNumber', 'city', 'country'], $resource); + } + + return $resource; + } +} diff --git a/version/206/class/Checkout/Payment/Amount.php b/version/206/class/Checkout/Payment/Amount.php new file mode 100644 index 0000000..54ffa5b --- /dev/null +++ b/version/206/class/Checkout/Payment/Amount.php @@ -0,0 +1,74 @@ + true [5 Rappen Rounding]) + * @return Amount + */ + public static function factory($value, $currency = null, $useRounding = false) + { + if (!$currency) { + $currency = static::FallbackCurrency()->cISO; + } + + $resource = new static(); + + $resource->currency = $currency; + //$resource->value = number_format(round($useRounding ? $resource->round($value * (float)$currency->fFaktor) : $value * (float)$currency->fFaktor, 2), 2, '.', ''); + $resource->value = number_format(round($useRounding ? $resource->round($value) : $value, 2), 2, '.', ''); + + // Validity Check + // TODO: Check ISO Code? + // TODO: Check Value + if (!$resource->currency || !$resource->value) { + throw ResourceValidityException::trigger(ResourceValidityException::ERROR_REQUIRED, ['currency', 'value'], $resource); + } + + return $resource; + } + + /** + * @return stdClass + */ + public static function FallbackCurrency() + { + return isset($_SESSION['Waehrung']) ? $_SESSION['Waehrung'] : Shop::DB()->select('twaehrung', 'cStandard', 'Y'); + } + + /** + * Check if 5 Rappen rounding is necessary + * + * @param mixed $value + * @return float + */ + protected function round($value) + { + $conf = Shop::getSettings([CONF_KAUFABWICKLUNG]); + if (isset($conf['kaufabwicklung']['bestellabschluss_runden5']) && (int)$conf['kaufabwicklung']['bestellabschluss_runden5'] === 1) { + $value = round($value * 20) / 20; + } + + return $value; + } +} diff --git a/version/206/class/Checkout/PaymentCheckout.php b/version/206/class/Checkout/PaymentCheckout.php new file mode 100644 index 0000000..d482a58 --- /dev/null +++ b/version/206/class/Checkout/PaymentCheckout.php @@ -0,0 +1,234 @@ +getMollie()->isCancelable) { + throw new RuntimeException('Zahlung kann nicht abgebrochen werden.'); + } + $payment = $checkout->API()->Client()->payments->cancel($checkout->getMollie()->id); + $checkout->Log('Zahlung wurde manuell abgebrochen.'); + + return $payment; + } + + /** + * @param false $force + * @return null|Payment + */ + public function getMollie($force = false) + { + if ($force || (!$this->getPayment() && $this->getModel()->kID)) { + try { + $this->setPayment($this->API()->Client()->payments->get($this->getModel()->kID, ['embed' => 'refunds'])); + } catch (Exception $e) { + throw new RuntimeException('Mollie-Payment konnte nicht geladen werden: ' . $e->getMessage()); + } + } + + return $this->getPayment(); + } + + /** + * @return null|Payment + */ + public function getPayment() + { + return $this->_payment; + } + + /** + * @param $payment + * @return $this + */ + public function setPayment($payment) + { + $this->_payment = $payment; + + return $this; + } + + /** + * @param mixed $force + * @throws ApiException + * @throws IncompatiblePlatform + * @return string + */ + public function cancelOrRefund($force = false) + { + if (!$this->getMollie()) { + throw new RuntimeException('Mollie-Order konnte nicht geladen werden: ' . $this->getModel()->kID); + } + if ($force || (int)$this->getBestellung()->cStatus === BESTELLUNG_STATUS_STORNO) { + if ($this->getMollie()->isCancelable) { + $res = $this->API()->Client()->payments->cancel($this->getMollie()->id); + $result = 'Payment cancelled, Status: ' . $res->status; + } else { + $res = $this->API()->Client()->payments->refund($this->getMollie(), ['amount' => $this->getMollie()->amount]); + $result = 'Payment Refund initiiert, Status: ' . $res->status; + } + $this->PaymentMethod()->Log('PaymentCheckout::cancelOrRefund: ' . $result, $this->LogData()); + + return $result; + } + + throw new RuntimeException('Bestellung ist derzeit nicht storniert, Status: ' . $this->getBestellung()->cStatus); + } + + /** + * @param array $paymentOptions + * @return Payment + */ + public function create(array $paymentOptions = []) + { + if ($this->getModel()->kID) { + try { + $this->setPayment($this->API()->Client()->payments->get($this->getModel()->kID)); + if ($this->getPayment()->status === PaymentStatus::STATUS_PAID) { + throw new RuntimeException(self::Plugin()->oPluginSprachvariableAssoc_arr['errAlreadyPaid']); + } + if ($this->getPayment()->status === PaymentStatus::STATUS_OPEN) { + $this->updateModel()->saveModel(); + + return $this->getPayment(); + } + } catch (RuntimeException $e) { + //$this->Log(sprintf("PaymentCheckout::create: Letzte Transaktion '%s' konnte nicht geladen werden: %s", $this->getModel()->kID, $e->getMessage()), LOGLEVEL_ERROR); + throw $e; + } catch (Exception $e) { + $this->Log(sprintf("PaymentCheckout::create: Letzte Transaktion '%s' konnte nicht geladen werden: %s, versuche neue zu erstellen.", $this->getModel()->kID, $e->getMessage()), LOGLEVEL_ERROR); + } + } + + try { + $req = $this->loadRequest($paymentOptions)->jsonSerialize(); + $this->setPayment($this->API()->Client()->payments->create($req)); + $this->Log(sprintf("Payment für '%s' wurde erfolgreich angelegt: %s", $this->getBestellung()->cBestellNr, $this->getPayment()->id)); + $this->updateModel()->saveModel(); + + return $this->getPayment(); + } catch (Exception $e) { + $this->Log(sprintf("PaymentCheckout::create: Neue Transaktion für '%s' konnte nicht erstellt werden: %s.", $this->getBestellung()->cBestellNr, $e->getMessage()), LOGLEVEL_ERROR); + + throw new RuntimeException(sprintf('Mollie-Payment \'%s\' konnte nicht geladen werden: %s', $this->getBestellung()->cBestellNr, $e->getMessage())); + } + } + + /** + * @param array $options + * @return $this|PaymentCheckout + */ + public function loadRequest(&$options = []) + { + parent::loadRequest($options); + + foreach ($options as $key => $value) { + $this->$key = $value; + } + + + $this->description = $this->getDescription(); + + return $this; + } + + + + /** + * @return null|object + */ + public function getIncomingPayment() + { + if (!$this->getMollie()) { + return null; + } + + if (in_array($this->getMollie()->status, [PaymentStatus::STATUS_AUTHORIZED, PaymentStatus::STATUS_PAID], true)) { + $data = []; + $data['fBetrag'] = (float)$this->getMollie()->amount->value; + $data['cISO'] = $this->getMollie()->amount->currency; + $data['cZahler'] = $this->getMollie()->details->paypalPayerId ?: $this->getMollie()->customerId; + $data['cHinweis'] = $this->getMollie()->details->paypalReference ?: $this->getMollie()->id; + if (isset($this->getMollie()->details, $this->getMollie()->details->paypalFee)) { + $data['fZahlungsgebuehr'] = $this->getMollie()->details->paypalFee->value; + } + + return (object)$data; + } + + return null; + } + + /** + * @param Payment $model + * @return $this|AbstractCheckout + */ + protected function setMollie($model) + { + if ($model instanceof Payment) { + $this->setPayment($model); + } + + return $this; + } + + /** + * @return $this + */ + protected function updateOrderNumber() + { + try { + if ($this->getMollie()) { + $this->getMollie()->description = $this->getDescription(); + $this->getMollie()->webhookUrl = Shop::getURL() . '/?mollie=1'; + $this->getMollie()->update(); + } + } catch (Exception $e) { + $this->Log('OrderCheckout::updateOrderNumber:' . $e->getMessage(), LOGLEVEL_ERROR); + } + + return $this; + } +} diff --git a/version/206/class/ExclusiveLock.php b/version/206/class/ExclusiveLock.php new file mode 100644 index 0000000..16d525e --- /dev/null +++ b/version/206/class/ExclusiveLock.php @@ -0,0 +1,69 @@ +key = $key; + $this->path = rtrim(realpath($path), '/') . '/'; + if (!is_dir($path) || !is_writable($path)) { + throw new RuntimeException("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", 'wb+'); + } + + + public function __destruct() + { + if ($this->own === true) { + $this->unlock(); + } + } + + /** @noinspection ForgottenDebugOutputInspection */ + 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; + } + 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 + } + + public function lock() + { + if (!flock($this->file, LOCK_EX | LOCK_NB)) { //failed + return false; + } + fwrite($this->file, 'Locked - ' . microtime(true) . "\n"); + fflush($this->file); + + $this->own = true; + + return true; // success + } +} diff --git a/version/206/class/Helper.php b/version/206/class/Helper.php new file mode 100644 index 0000000..0df574e --- /dev/null +++ b/version/206/class/Helper.php @@ -0,0 +1,362 @@ +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) && !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!'); + } + $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 + * @throws Exception + * @return mixed + */ + 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; + } + + 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 + * @throws SmartyException + * @return string + */ + 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 null|Plugin + */ + public static function oPlugin($force = false) + { + if ($force === true) { + self::$oPlugin = new Plugin(self::oPlugin()->kPlugin, true); + } elseif (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 = []; + @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([CONF_EMAILS]); + $mail = trim($settings['emails']['email_master_absender']); + if ($e === true && $mail != '') { + $mail = base64_encode($mail); + $eMail = ''; + foreach (str_split($mail) 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/206/class/Hook/AbstractHook.php b/version/206/class/Hook/AbstractHook.php new file mode 100644 index 0000000..1d9e6b6 --- /dev/null +++ b/version/206/class/Hook/AbstractHook.php @@ -0,0 +1,14 @@ +kPlugin)) + && array_key_exists($key, $_SESSION) && !array_key_exists('Zahlungsart', $_SESSION) + ) { + unset($_SESSION[$key]); + } + + if (!array_key_exists('ws_mollie_applepay_available', $_SESSION)) { + Shop::Smarty()->assign('applePayCheckURL', json_encode(self::Plugin()->cFrontendPfadURLSSL . 'applepay.php')); + pq('body')->append(Shop::Smarty()->fetch(self::Plugin()->cFrontendPfad . 'tpl/applepay.tpl')); + } + } + + /** + * @return bool + */ + public static function isAvailable() + { + if (array_key_exists('ws_mollie_applepay_available', $_SESSION)) { + return $_SESSION['ws_mollie_applepay_available']; + } + + return false; + } + + /** + * @param $status bool + */ + public static function setAvailable($status) + { + $_SESSION['ws_mollie_applepay_available'] = $status; + } +} diff --git a/version/206/class/Hook/Checkbox.php b/version/206/class/Hook/Checkbox.php new file mode 100644 index 0000000..d6d1b5d --- /dev/null +++ b/version/206/class/Hook/Checkbox.php @@ -0,0 +1,59 @@ +cModulId, 'kPlugin_' . self::Plugin()->kPlugin . '_') === false) { + return; + } + + if (array_key_exists('nAnzeigeOrt', $args_arr) && $args_arr['nAnzeigeOrt'] === CHECKBOX_ORT_BESTELLABSCHLUSS && Session::getInstance()->Customer()->nRegistriert) { + $mCustomer = Customer::fromID(Session::getInstance()->Customer()->kKunde, 'kKunde'); + + if ($mCustomer->customerId) { + return; + } + + $checkbox = new \CheckBox(); + $checkbox->kLink = 0; + $checkbox->kCheckBox = -1; + $checkbox->kCheckBoxFunktion = 0; + $checkbox->cName = 'MOLLIE SAVE CUSTOMER'; + $checkbox->cKundengruppe = ';1;'; + $checkbox->cAnzeigeOrt = ';2;'; + $checkbox->nAktiv = 1; + $checkbox->nPflicht = 0; + $checkbox->nLogging = 0; + $checkbox->nSort = 999; + $checkbox->dErstellt = date('Y-m-d H:i:s'); + $checkbox->oCheckBoxSprache_arr = []; + + $langs = gibAlleSprachen(); + foreach ($langs as $lang) { + $checkbox->oCheckBoxSprache_arr[$lang->kSprache] = (object)[ + 'cText' => self::Plugin()->oPluginSprachvariableAssoc_arr['checkboxText'], + 'cBeschreibung' => self::Plugin()->oPluginSprachvariableAssoc_arr['checkboxDescr'], + 'kSprache' => $lang->kSprache, + 'kCheckbox' => -1 + ]; + } + + $checkbox->kKundengruppe_arr = [Session::getInstance()->Customer()->kKundengruppe]; + $checkbox->kAnzeigeOrt_arr = [CHECKBOX_ORT_BESTELLABSCHLUSS]; + $checkbox->cID = 'mollie_create_customer'; + $checkbox->cLink = ''; + + $args_arr['oCheckBox_arr'][] = $checkbox; + } + } +} diff --git a/version/206/class/Hook/Queue.php b/version/206/class/Hook/Queue.php new file mode 100644 index 0000000..849ee52 --- /dev/null +++ b/version/206/class/Hook/Queue.php @@ -0,0 +1,139 @@ +nWaehrendBestellung === 0 + && $args_arr['oBestellung']->fGesamtsumme > 0 + && self::Plugin()->oPluginEinstellungAssoc_arr['onlyPaid'] === 'Y' + && AbstractCheckout::isMollie((int)$args_arr['oBestellung']->kZahlungsart, true) + ) { + $args_arr['oBestellung']->cAbgeholt = 'Y'; + Jtllog::writeLog('Switch cAbgeholt for kBestellung: ' . print_r($args_arr['oBestellung']->kBestellung, 1), JTLLOG_LEVEL_NOTICE); + } + } + + /** + * @param array $args_arr + */ + public static function xmlBestellStatus(array $args_arr) + { + if (AbstractCheckout::isMollie((int)$args_arr['oBestellung']->kBestellung)) { + self::saveToQueue(HOOK_BESTELLUNGEN_XML_BESTELLSTATUS . ':' . (int)$args_arr['oBestellung']->kBestellung, [ + 'kBestellung' => $args_arr['oBestellung']->kBestellung, + 'status' => (int)$args_arr['status'] + ]); + } + } + + /** + * @param $hook + * @param $args_arr + * @param string $type + * @return bool + */ + public static function saveToQueue($hook, $args_arr, $type = 'hook') + { + $mQueue = new QueueModel(); + $mQueue->cType = $type . ':' . $hook; + $mQueue->cData = serialize($args_arr); + + try { + return $mQueue->save(); + } catch (Exception $e) { + Jtllog::writeLog('mollie::saveToQueue: ' . $e->getMessage() . ' - ' . print_r($args_arr, 1)); + + return false; + } + } + + /** + * @param array $args_arr + */ + public static function xmlBearbeiteStorno(array $args_arr) + { + if (AbstractCheckout::isMollie((int)$args_arr['oBestellung']->kBestellung)) { + self::saveToQueue(HOOK_BESTELLUNGEN_XML_BEARBEITESTORNO . ':' . $args_arr['oBestellung']->kBestellung, ['kBestellung' => $args_arr['oBestellung']->kBestellung]); + } + } + + /** + * + */ + public static function headPostGet() + { + if (array_key_exists('mollie', $_REQUEST) && (int)$_REQUEST['mollie'] === 1 && array_key_exists('id', $_REQUEST)) { + if (array_key_exists('hash', $_REQUEST) && $hash = trim(StringHandler::htmlentities(StringHandler::filterXSS($_REQUEST['hash'])), '_')) { + AbstractCheckout::finalizeOrder($hash, $_REQUEST['id'], array_key_exists('test', $_REQUEST)); + } else { + self::saveToQueue($_REQUEST['id'], $_REQUEST['id'], 'webhook'); + } + exit(); + } + if (array_key_exists('m_pay', $_REQUEST)) { + try { + $raw = Shop::DB()->executeQueryPrepared('SELECT kID FROM `xplugin_ws_mollie_payments` WHERE dReminder IS NOT NULL AND MD5(CONCAT(kID, "-", kBestellung)) = :md5', [ + ':md5' => $_REQUEST['m_pay'] + ], 1); + + if (!$raw) { + throw new RuntimeException(self::Plugin()->oPluginSprachvariableAssoc_arr['errOrderNotFound']); + } + + if (strpos($raw->cOrderId, 'tr_') === 0) { + $checkout = PaymentCheckout::fromID($raw->kID); + } else { + $checkout = OrderCheckout::fromID($raw->kID); + } + $checkout->getMollie(true); + $checkout->updateModel()->saveModel(); + + if ( + ($checkout->getBestellung()->dBezahltDatum !== null && $checkout->getBestellung()->dBezahltDatum !== '0000-00-00') + || in_array($checkout->getModel()->cStatus, ['completed', 'paid', 'authorized', 'pending']) + ) { + throw new RuntimeException(self::Plugin()->oPluginSprachvariableAssoc_arr['errAlreadyPaid']); + } + + $options = []; + if (self::Plugin()->oPluginEinstellungAssoc_arr['resetMethod'] !== 'Y') { + $options['method'] = $checkout->getModel()->cMethod; + } + + $mollie = $checkout->create($options); // Order::repayOrder($orderModel->getOrderId(), $options, $api); + $url = $mollie->getCheckoutUrl(); + + header('Location: ' . $url); + exit(); + } catch (RuntimeException $e) { + // TODO Workaround? + //$alertHelper = Shop::Container()->getAlertService(); + //$alertHelper->addAlert(Alert::TYPE_ERROR, $e->getMessage(), 'mollie_repay', ['dismissable' => true]); + } catch (Exception $e) { + Jtllog::writeLog('mollie:repay:error: ' . $e->getMessage() . "\n" . print_r($_REQUEST, 1)); + } + } + } +} diff --git a/version/206/class/Model/AbstractModel.php b/version/206/class/Model/AbstractModel.php new file mode 100644 index 0000000..a91071c --- /dev/null +++ b/version/206/class/Model/AbstractModel.php @@ -0,0 +1,109 @@ +data = $data; + if (!$data) { + $this->new = true; + } + } + + /** + * @param $id + * @param string $col + * @param false $failIfNotExists + * @return static + */ + public static function fromID($id, $col = 'kID', $failIfNotExists = false) + { + if ( + $payment = Shop::DB()->executeQueryPrepared( + 'SELECT * FROM ' . static::TABLE . " WHERE `$col` = :id", + [':id' => $id], + 1 + ) + ) { + return new static($payment); + } + if ($failIfNotExists) { + throw new RuntimeException(sprintf('Model %s in %s nicht gefunden!', $id, static::TABLE)); + } + + return new static(); + } + + /** + * @return null|mixed|stdClass + */ + public function jsonSerialize() + { + return $this->data; + } + + public function __get($name) + { + if (isset($this->data->$name)) { + return $this->data->$name; + } + + return null; + } + + public function __set($name, $value) + { + if (!$this->data) { + $this->data = new stdClass(); + } + $this->data->$name = $value; + } + + public function __isset($name) + { + return isset($this->data->$name); + } + + /** + * @return bool + */ + public function save() + { + if (!$this->data) { + throw new RuntimeException('No Data to save!'); + } + + if ($this->new) { + Shop::DB()->insertRow(static::TABLE, $this->data); + $this->new = false; + + return true; + } + Shop::DB()->updateRow(static::TABLE, static::PRIMARY, $this->data->{static::PRIMARY}, $this->data); + + return true; + } +} diff --git a/version/206/class/Model/Customer.php b/version/206/class/Model/Customer.php new file mode 100644 index 0000000..9f7f1a5 --- /dev/null +++ b/version/206/class/Model/Customer.php @@ -0,0 +1,20 @@ +dCreatedAt) { + $this->dCreatedAt = date('Y-m-d H:i:s'); + } + if ($this->new) { + $this->dReminder = self::NULL; + } + + return parent::save(); + } +} diff --git a/version/206/class/Model/Queue.php b/version/206/class/Model/Queue.php new file mode 100644 index 0000000..c1a611c --- /dev/null +++ b/version/206/class/Model/Queue.php @@ -0,0 +1,45 @@ +cResult = $result; + $this->dDone = $date ?: date('Y-m-d H:i:s'); + + return $this->save(); + } + + public function save() + { + if (!$this->dCreated) { + $this->dCreated = date('Y-m-d H:i:s'); + } + $this->dModified = date('Y-m-d H:i:s'); + + return parent::save(); + } +} diff --git a/version/206/class/Model/Shipment.php b/version/206/class/Model/Shipment.php new file mode 100644 index 0000000..9f4db59 --- /dev/null +++ b/version/206/class/Model/Shipment.php @@ -0,0 +1,28 @@ +executeQueryPrepared( + 'SELECT p.kBestellung, b.cStatus FROM xplugin_ws_mollie_payments p ' + . 'JOIN tbestellung b ON b.kBestellung = p.kBestellung ' + . "WHERE b.cAbgeholt = 'Y' AND NOT p.bSynced AND b.cStatus IN ('1', '2') AND p.dCreatedAt < NOW() - INTERVAL :d HOUR", + [':d' => $delay], + 2 + ); + + foreach ($open as $o) { + try { + $checkout = AbstractCheckout::fromBestellung($o->kBestellung); + $pm = $checkout->PaymentMethod(); + if ($pm::ALLOW_AUTO_STORNO && $pm::METHOD === $checkout->getMollie()->method) { + if ($checkout->getBestellung()->cAbgeholt === 'Y' && (bool)$checkout->getModel()->bSynced === false) { + if (!in_array($checkout->getMollie()->status, [OrderStatus::STATUS_PAID, OrderStatus::STATUS_COMPLETED, OrderStatus::STATUS_AUTHORIZED], true)) { + $checkout->storno(); + } else { + $checkout->Log(sprintf('AutoStorno: Bestellung bezahlt? %s - Method: %s', $checkout->getMollie()->status, $checkout->getMollie()->method), LOGLEVEL_ERROR); + } + } else { + $checkout->Log('AutoStorno: bereits zur WAWI synchronisiert.', LOGLEVEL_ERROR); + } + } + } catch (Exception $e) { + Helper::logExc($e); + } + } + + return true; + } + + /** + * @param int $limit + */ + public static function run($limit = 10) + { + foreach (self::getOpen($limit) as $todo) { + if (!self::lock($todo)) { + Jtllog::writeLog(sprintf('%s already locked since %s', $todo->kId, $todo->bLock ?: 'just now')); + + continue; + } + + if (([$type, $id] = explode(':', $todo->cType))) { + try { + switch ($type) { + case 'webhook': + self::handleWebhook($id, $todo); + + break; + + case 'hook': + self::handleHook((int)$id, $todo); + + break; + } + } catch (Exception $e) { + Jtllog::writeLog($e->getMessage() . " ($type, $id)"); + $todo->done("{$e->getMessage()}\n{$e->getFile()}:{$e->getLine()}\n{$e->getTraceAsString()}"); + } + } + + self::unlock($todo); + } + } + + /** + * @param $limit + * @return Generator|QueueModel[] + * @noinspection PhpReturnDocTypeMismatchInspection + * @noinspection SqlResolve + */ + private static function getOpen($limit) + { + if (!defined('MOLLIE_HOOK_DELAY')) { + define('MOLLIE_HOOK_DELAY', 3); + } + $open = Shop::DB()->executeQueryPrepared(sprintf("SELECT * FROM %s WHERE (dDone IS NULL OR dDone = '0000-00-00 00:00:00') AND `bLock` IS NULL AND (cType LIKE 'webhook:%%' OR (cType LIKE 'hook:%%') AND dCreated < DATE_SUB(NOW(), INTERVAL " . (int)MOLLIE_HOOK_DELAY . ' MINUTE)) ORDER BY dCreated DESC LIMIT 0, :LIMIT;', QueueModel::TABLE), [ + ':LIMIT' => $limit + ], 2); + + foreach ($open as $_raw) { + yield new QueueModel($_raw); + } + } + + /** + * @param $todo + * @return bool + * @noinspection SqlResolve + */ + protected static function lock($todo) + { + return $todo->kId && Shop::DB()->executeQueryPrepared(sprintf('UPDATE %s SET `bLock` = NOW() WHERE `bLock` IS NULL AND kId = :kId', QueueModel::TABLE), [ + 'kId' => $todo->kId + ], 3) >= 1; + } + + /** + * @param $id + * @param QueueModel $todo + * @throws Exception + * @return bool + */ + protected static function handleWebhook($id, QueueModel $todo) + { + $checkout = AbstractCheckout::fromID($id); + if ($checkout->getBestellung()->kBestellung && $checkout->PaymentMethod()) { + $checkout->handleNotification(); + + return $todo->done('Status: ' . $checkout->getMollie()->status); + } + + throw new RuntimeException("Bestellung oder Zahlungsart konnte nicht geladen werden: $id"); + } + + /** + * @param $hook + * @param QueueModel $todo + * @throws ApiException + * @throws IncompatiblePlatform + * @throws Exception + * @return bool + */ + protected static function handleHook($hook, QueueModel $todo) + { + $data = unserialize($todo->cData); + if (array_key_exists('kBestellung', $data)) { + switch ($hook) { + case HOOK_BESTELLUNGEN_XML_BESTELLSTATUS: + if ((int)$data['kBestellung']) { + // TODO: #158 What happens when API requests fail? + $checkout = AbstractCheckout::fromBestellung($data['kBestellung']); + + $status = array_key_exists('status', $data) ? (int)$data['status'] : 0; + $result = ''; + if (!$status || $status < BESTELLUNG_STATUS_VERSANDT) { + return $todo->done("Bestellung noch nicht versendet: {$checkout->getBestellung()->cStatus}"); + } + if (!count($checkout->getBestellung()->oLieferschein_arr)) { + $todo->dCreated = date('Y-m-d H:i:s', strtotime('+3 MINUTES')); + $todo->cResult = 'Noch keine Lieferscheine, delay...'; + + return $todo->save(); + } + + /** @var $method JTLMollie */ + if ( + (strpos($checkout->getModel()->kID, 'tr_') === false) + && $checkout->PaymentMethod() + && $checkout->getMollie() + ) { + /** @var OrderCheckout $checkout */ + $checkout->handleNotification(); + if ($checkout->getMollie()->status === OrderStatus::STATUS_COMPLETED) { + $result = 'Mollie Status already ' . $checkout->getMollie()->status; + } elseif ($checkout->getMollie()->isCreated() || $checkout->getMollie()->isPaid() || $checkout->getMollie()->isAuthorized() || $checkout->getMollie()->isShipping() || $checkout->getMollie()->isPending()) { + try { + if ($shipments = Shipment::syncBestellung($checkout)) { + foreach ($shipments as $shipment) { + if (is_string($shipment)) { + $checkout->Log("Shipping-Error: $shipment"); + $result .= "Shipping-Error: $shipment;\n"; + } else { + $checkout->Log("Order shipped: {$shipment->id}"); + $result .= "Order shipped: $shipment->id;\n"; + } + } + } else { + $result = 'No Shipments ready!'; + } + } catch (RuntimeException $e) { + $result = $e->getMessage(); + } catch (Exception $e) { + $result = $e->getMessage() . "\n" . $e->getFile() . ':' . $e->getLine() . "\n" . $e->getTraceAsString(); + } + } else { + $result = sprintf('Unerwarteter Mollie Status "%s" für %s', $checkout->getMollie()->status, $checkout->getBestellung()->cBestellNr); + } + } else { + $result = 'Nothing to do.'; + } + $checkout->Log('Queue::handleHook: ' . $result); + } else { + $result = 'kBestellung missing'; + } + + return $todo->done($result); + + case HOOK_BESTELLUNGEN_XML_BEARBEITESTORNO: + if (self::Plugin()->oPluginEinstellungAssoc_arr['autoRefund'] !== 'Y') { + throw new RuntimeException('Auto-Refund disabled'); + } + + $checkout = AbstractCheckout::fromBestellung((int)$data['kBestellung']); + + return $todo->done($checkout->cancelOrRefund()); + } + } + + return false; + } + + /** + * @param $todo + * @return bool + */ + protected static function unlock($todo) + { + return $todo->kId && Shop::DB()->executeQueryPrepared(sprintf('UPDATE %s SET `bLock` = NULL WHERE kId = :kId OR bLock < DATE_SUB(NOW(), INTERVAL 15 MINUTE)', QueueModel::TABLE), [ + 'kId' => $todo->kId + ], 3) >= 1; + } +} diff --git a/version/206/class/Shipment.php b/version/206/class/Shipment.php new file mode 100644 index 0000000..d206079 --- /dev/null +++ b/version/206/class/Shipment.php @@ -0,0 +1,324 @@ +kLieferschein = $kLieferschein; + if ($checkout) { + $this->checkout = $checkout; + } + + if (!$this->getLieferschein() || !$this->getLieferschein()->getLieferschein()) { + throw new RuntimeException('Lieferschein konnte nicht geladen werden'); + } + + if (!count($this->getLieferschein()->oVersand_arr)) { + throw new RuntimeException('Kein Versand gefunden!'); + } + + if (!$this->getCheckout()->getBestellung()->oKunde->nRegistriert) { + $this->isGuest = true; + } + } + + public function getLieferschein() + { + if (!$this->oLieferschein && $this->kLieferschein) { + $this->oLieferschein = new Lieferschein($this->kLieferschein); + } + + return $this->oLieferschein; + } + + /** + * @throws Exception + * @return OrderCheckout + */ + public function getCheckout() + { + if (!$this->checkout) { + //TODO evtl. load by lieferschien + throw new Exception('Should not happen, but it did!'); + } + + return $this->checkout; + } + + public static function syncBestellung(OrderCheckout $checkout) + { + $shipments = []; + if ($checkout->getBestellung()->kBestellung) { + $oKunde = $checkout->getBestellung()->oKunde ?: new Kunde($checkout->getBestellung()->kKunde); + + $shippingActive = Helper::getSetting('shippingActive'); + if ($shippingActive === 'N') { + throw new RuntimeException('Shipping deaktiviert'); + } + + if ($shippingActive === 'K' && !$oKunde->nRegistriert && (int)$checkout->getBestellung()->cStatus !== BESTELLUNG_STATUS_VERSANDT) { + throw new RuntimeException('Shipping für Gast-Bestellungen und Teilversand deaktiviert'); + } + + /** @var Lieferschein $oLieferschein */ + foreach ($checkout->getBestellung()->oLieferschein_arr as $oLieferschein) { + try { + $shipment = new self($oLieferschein->getLieferschein(), $checkout); + $mode = self::Plugin()->oPluginEinstellungAssoc_arr['shippingMode']; + switch ($mode) { + case 'A': + // ship directly + if (!$shipment->send() && !$shipment->getShipment()) { + throw new RuntimeException('Shipment konnte nicht gespeichert werden.'); + } + $shipments[] = $shipment->getShipment(); + + break; + + case 'B': + // only ship if complete shipping + if ($oKunde->nRegistriert || (int)$checkout->getBestellung()->cStatus === BESTELLUNG_STATUS_VERSANDT) { + if (!$shipment->send() && !$shipment->getShipment()) { + throw new RuntimeException('Shipment konnte nicht gespeichert werden.'); + } + $shipments[] = $shipment->getShipment(); + + break; + } + + throw new RuntimeException('Gastbestellung noch nicht komplett versendet!'); + } + } catch (RuntimeException $e) { + $shipments[] = $e->getMessage(); + } catch (Exception $e) { + $shipments[] = $e->getMessage(); + $checkout->Log("mollie: Shipment::syncBestellung (BestellNr. {$checkout->getBestellung()->cBestellNr}, Lieferschein: {$oLieferschein->getLieferscheinNr()}) - " . $e->getMessage(), LOGLEVEL_ERROR); + } + } + } + + return $shipments; + } + + /** + * @throws ApiException + * @throws IncompatiblePlatform + * @throws Exception + * @return bool + */ + public function send() + { + if ($this->getShipment()) { + throw new RuntimeException('Lieferschien bereits an Mollie übertragen: ' . $this->getShipment()->id); + } + + if ($this->getCheckout()->getMollie(true)->status === OrderStatus::STATUS_COMPLETED) { + throw new RuntimeException('Bestellung bei Mollie bereits abgeschlossen!'); + } + + $api = $this->getCheckout()->API()->Client(); + $this->shipment = $api->shipments->createForId($this->checkout->getModel()->kID, $this->loadRequest()->jsonSerialize()); + + return $this->updateModel()->saveModel(); + } + + /** + * @param false $force + * @throws ApiException + * @throws IncompatiblePlatform + * @throws Exception + * @return BaseResource|\Mollie\Api\Resources\Shipment + */ + public function getShipment($force = false) + { + if (($force || !$this->shipment) && $this->getModel() && $this->getModel()->cShipmentId) { + $this->shipment = $this->getCheckout()->API()->Client()->shipments->getForId($this->getModel()->cOrderId, $this->getModel()->cShipmentId); + } + + return $this->shipment; + } + + /** + * @throws Exception + * @return ShipmentModel + */ + public function getModel() + { + if (!$this->model && $this->kLieferschein) { + $this->model = ShipmentModel::fromID($this->kLieferschein, 'kLieferschein'); + + if (!$this->model->dCreated) { + $this->model->dCreated = date('Y-m-d H:i:s'); + } + $this->updateModel(); + } + + return $this->model; + } + + /** + * @throws Exception + * @return $this + */ + public function updateModel() + { + $this->getModel()->kLieferschein = $this->kLieferschein; + if ($this->getCheckout()) { + $this->getModel()->cOrderId = $this->getCheckout()->getModel()->kID; + $this->getModel()->kBestellung = $this->getCheckout()->getModel()->kBestellung; + } + if ($this->getShipment()) { + $this->getModel()->cShipmentId = $this->getShipment()->id; + $this->getModel()->cUrl = $this->getShipment()->getTrackingUrl() ?: ''; + } + if (isset($this->tracking)) { + $this->getModel()->cCarrier = $this->tracking['carrier'] ?: ''; + $this->getModel()->cCode = $this->tracking['code'] ?: ''; + } + + return $this; + } + + /** + * @param array $options + * @throws Exception + * @return $this + */ + public function loadRequest(&$options = []) + { + /** @var Versand $oVersand */ + $oVersand = $this->getLieferschein()->oVersand_arr[0]; + if ($oVersand->getIdentCode() && $oVersand->getLogistik()) { + $tracking = [ + 'carrier' => utf8_encode($oVersand->getLogistik()), + 'code' => utf8_encode($oVersand->getIdentCode()), + ]; + if ($oVersand->getLogistikVarUrl()) { + $tracking['url'] = utf8_encode($oVersand->getLogistikURL()); + } + $this->tracking = $tracking; + } + + // TODO: Wenn alle Lieferschiene in der WAWI erstellt wurden, aber nicht im Shop, kommt status 4. + if ($this->isGuest || (int)$this->getCheckout()->getBestellung()->cStatus === BESTELLUNG_STATUS_VERSANDT) { + $this->lines = []; + } else { + $this->lines = $this->getOrderLines(); + } + + return $this; + } + + /** + * @throws Exception + * @return array + */ + protected function getOrderLines() + { + $lines = []; + + if (!count($this->getLieferschein()->oLieferscheinPos_arr)) { + return $lines; + } + + // Bei Stücklisten, sonst gibt es mehrere OrderLines für die selbe ID + $shippedOrderLines = []; + + /** @var Lieferscheinpos $oLieferscheinPos */ + foreach ($this->getLieferschein()->oLieferscheinPos_arr as $oLieferscheinPos) { + $wkpos = Shop::DB()->executeQueryPrepared('SELECT * FROM twarenkorbpos WHERE kBestellpos = :kBestellpos', [ + ':kBestellpos' => $oLieferscheinPos->getBestellPos() + ], 1); + + /** @var OrderLine $orderLine */ + foreach ($this->getCheckout()->getMollie()->lines as $orderLine) { + if ($orderLine->sku === $wkpos->cArtNr && !in_array($orderLine->id, $shippedOrderLines, true)) { + if ($quantity = min($oLieferscheinPos->getAnzahl(), $orderLine->shippableQuantity)) { + $lines[] = [ + 'id' => $orderLine->id, + 'quantity' => $quantity + ]; + } + $shippedOrderLines[] = $orderLine->id; + + break; + } + } + } + + return $lines; + } + + /** + * @throws Exception + * @return bool + */ + public function saveModel() + { + return $this->getModel()->save(); + } +} diff --git a/version/206/class/Traits/Jsonable.php b/version/206/class/Traits/Jsonable.php new file mode 100644 index 0000000..cc825fd --- /dev/null +++ b/version/206/class/Traits/Jsonable.php @@ -0,0 +1,22 @@ +jsonSerialize(); + } + + public function jsonSerialize() + { + return array_filter(get_object_vars($this), static function ($value) { + return !($value === null || (is_string($value) && $value === '')); + }); + } +} diff --git a/version/206/class/Traits/Plugin.php b/version/206/class/Traits/Plugin.php new file mode 100644 index 0000000..3359392 --- /dev/null +++ b/version/206/class/Traits/Plugin.php @@ -0,0 +1,29 @@ +requestData) === false) { + throw new \RuntimeException(sprintf("JSON Encode Error: %s\n%s", json_last_error_msg(), print_r($this->requestData, 1))); + } + + return $this->requestData; + } + + public function __get($name) + { + if (!$this->requestData) { + $this->loadRequest(); + } + + return is_string($this->requestData[$name]) ? utf8_decode($this->requestData[$name]) : $this->requestData[$name]; + } + + public function __set($name, $value) + { + if (!$this->requestData) { + $this->requestData = []; + } + + $this->requestData[$name] = is_string($value) ? utf8_encode($value) : $value; + + return $this; + } + + /** + * @param array $options + * @return $this + */ + public function loadRequest(&$options = []) + { + return $this; + } + + + public function __serialize() + { + return $this->requestData ?: []; + } + + public function __isset($name) + { + return $this->requestData[$name] !== null; + } +} diff --git a/version/206/frontend/.htaccess b/version/206/frontend/.htaccess new file mode 100644 index 0000000..df6c074 --- /dev/null +++ b/version/206/frontend/.htaccess @@ -0,0 +1,9 @@ + + + Require all granted + + + Order Allow,Deny + Allow from all + + diff --git a/version/206/frontend/131_globalinclude.php b/version/206/frontend/131_globalinclude.php new file mode 100644 index 0000000..ffed0c3 --- /dev/null +++ b/version/206/frontend/131_globalinclude.php @@ -0,0 +1,60 @@ +select('tzahlungsession', 'cZahlungsID', $sessionHash); + if ($paymentSession && $paymentSession->kBestellung) { + $oBestellung = new Bestellung($paymentSession->kBestellung); + + if (Shop::getConfig([CONF_KAUFABWICKLUNG])['kaufabwicklung']['bestellabschluss_abschlussseite'] === 'A') { + $oZahlungsID = Shop::DB()->query( + ' + SELECT cId + FROM tbestellid + WHERE kBestellung = ' . (int)$paymentSession->kBestellung, + 1 + ); + if (is_object($oZahlungsID)) { + header('Location: ' . Shop::getURL() . '/bestellabschluss.php?i=' . $oZahlungsID->cId); + exit(); + } + } + $bestellstatus = Shop::DB()->select('tbestellstatus', 'kBestellung', (int)$paymentSession->kBestellung); + header('Location: ' . Shop::getURL() . '/status.php?uid=' . $bestellstatus->cUID); + exit(); + } + } + + ifndef('MOLLIE_REMINDER_PROP', 10); + if (mt_rand(1, MOLLIE_REMINDER_PROP) % MOLLIE_REMINDER_PROP === 0) { + $lock = new \ws_mollie\ExclusiveLock('mollie_reminder', PFAD_ROOT . PFAD_COMPILEDIR); + if ($lock->lock()) { + AbstractCheckout::sendReminders(); + Queue::storno((int)Helper::getSetting('autoStorno')); + + $lock->unlock(); + } + } +} catch (Exception $e) { + Helper::logExc($e); +} diff --git a/version/206/frontend/132_headPostGet.php b/version/206/frontend/132_headPostGet.php new file mode 100644 index 0000000..b27fb2f --- /dev/null +++ b/version/206/frontend/132_headPostGet.php @@ -0,0 +1,19 @@ +append( + << + /* MOLLIE CHECKOUT STYLES*/ + #fieldset-payment .form-group > div:hover, #checkout-shipping-payment .form-group > div:hover { + background-color: #eee; + color: black; + } + $selector label { + $border + } + + $selector label::after { + clear: both; + content: ' '; + display: block; + } + + $selector label span small { + line-height: 48px; + } + + $selector label img { + float: right; + } + +HTML + ); +} catch (Exception $e) { + Helper::logExc($e); +} diff --git a/version/206/frontend/180_checkbox.php b/version/206/frontend/180_checkbox.php new file mode 100644 index 0000000..d91ac2f --- /dev/null +++ b/version/206/frontend/180_checkbox.php @@ -0,0 +1,20 @@ +oPluginEinstellungAssoc_arr['useCustomerAPI'] === 'C') { + \ws_mollie\Hook\Checkbox::execute($args_arr); + } +} catch (Exception $e) { + Helper::logExc($e); +} diff --git a/version/206/frontend/181_sync.php b/version/206/frontend/181_sync.php new file mode 100644 index 0000000..eb6e912 --- /dev/null +++ b/version/206/frontend/181_sync.php @@ -0,0 +1,17 @@ +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 Rmns)TMnX}%M${5 literal 0 HcmV?d00001 diff --git a/version/206/frontend/img/trust_fre.png b/version/206/frontend/img/trust_fre.png new file mode 100644 index 0000000000000000000000000000000000000000..ed1a2f6f03c56f6748aac8af0352de7fc0afd3a4 GIT binary patch literal 17319 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 Mu#8ZJpsxS_1AJc%;s5{u literal 0 HcmV?d00001 diff --git a/version/206/frontend/img/trust_ger.png b/version/206/frontend/img/trust_ger.png new file mode 100644 index 0000000000000000000000000000000000000000..e42821b06709e8f4371c66cfb5759d00df0e1afd GIT binary patch literal 15352 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 + diff --git a/version/206/paymentmethod/JTLMollie.php b/version/206/paymentmethod/JTLMollie.php new file mode 100644 index 0000000..5d0e626 --- /dev/null +++ b/version/206/paymentmethod/JTLMollie.php @@ -0,0 +1,305 @@ +cModulId = 'kPlugin_' . self::Plugin()->kPlugin . '_mollie' . $moduleID; + } + + /** + * @param Bestellung $order + * @return PaymentMethod + */ + public function setOrderStatusToPaid($order) + { + // If paid already, do nothing + if ((int)$order->cStatus >= BESTELLUNG_STATUS_BEZAHLT) { + return $this; + } + + return parent::setOrderStatusToPaid($order); + } + + + /** + * @param $kBestellung + * @param bool $redirect + * @return bool|string + */ + public static function getOrderCompletedRedirect($kBestellung, $redirect = true) + { + $mode = Shopsetting::getInstance()->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; + } + + + /** + * Prepares everything so that the Customer can start the Payment Process. + * Tells Template Engine. + * + * @param Bestellung $order + * @return void + */ + public function preparePaymentProcess($order) + { + parent::preparePaymentProcess($order); + + try { + if ($this->duringCheckout && !static::ALLOW_PAYMENT_BEFORE_ORDER) { + $this->Log(sprintf('Zahlung vor Bestellabschluss nicht unterstützt (%s)!', $order->cBestellNr), sprintf('#%s', $order->kBestellung), LOGLEVEL_ERROR); + + return; + } + + $payable = (float)$order->fGesamtsumme > 0; + if (!$payable) { + $this->Log(sprintf("Bestellung '%s': Gesamtsumme %.2f, keine Zahlung notwendig!", $order->cBestellNr, $order->fGesamtsumme), sprintf('#%s', $order->kBestellung)); + require_once PFAD_ROOT . PFAD_INCLUDES . 'bestellabschluss_inc.php'; + require_once PFAD_ROOT . PFAD_INCLUDES . 'mailTools.php'; + $finalized = finalisiereBestellung(); + Session::getInstance()->cleanUp(); + self::getOrderCompletedRedirect($finalized->kBestellung); + + return; + } + + $paymentOptions = []; + + $api = array_key_exists($this->moduleID . '_api', self::Plugin()->oPluginEinstellungAssoc_arr) ? self::Plugin()->oPluginEinstellungAssoc_arr[$this->moduleID . '_api'] : 'order'; + + $paymentOptions = array_merge($paymentOptions, $this->getPaymentOptions($order, $api)); + + if ($api === 'payment') { + $checkout = new PaymentCheckout($order); + $payment = $checkout->create($paymentOptions); + /** @noinspection NullPointerExceptionInspection */ + $url = $payment->getCheckoutUrl(); + } else { + $checkout = new OrderCheckout($order); + $mOrder = $checkout->create($paymentOptions); + /** @noinspection NullPointerExceptionInspection */ + $url = $mOrder->getCheckoutUrl(); + } + + ifndef('MOLLIE_REDIRECT_DELAY', 3); + $checkoutMode = self::Plugin()->oPluginEinstellungAssoc_arr['checkoutMode']; + Shop::Smarty()->assign('redirect', $url) + ->assign('checkoutMode', $checkoutMode); + if ($checkoutMode === 'Y' && !headers_sent()) { + header('Location: ' . $url); + } + } catch (Exception $e) { + $this->Log('mollie::preparePaymentProcess: ' . $e->getMessage() . ' - ' . print_r(['cBestellNr' => $order->cBestellNr], 1), '#' . $order->kBestellung, LOGLEVEL_ERROR); + Shop::Smarty()->assign('oMollieException', $e) + ->assign('tryAgain', Shop::getURL() . '/bestellab_again.php?kBestellung=' . $order->kBestellung); + } + } + + public function Log($msg, $data = null, $level = LOGLEVEL_NOTICE) + { + ZahlungsLog::add($this->moduleID, '[' . microtime(true) . ' - ' . $_SERVER['PHP_SELF'] . '] ' . $msg, $data, $level); + + return $this; + } + + public function getPaymentOptions(Bestellung $order, $apiType) + { + return []; + } + + /** + * @param Bestellung $order + * @param string $hash + * @param array $args + */ + public function handleNotification($order, $hash, $args) + { + parent::handleNotification($order, $hash, $args); + + try { + $orderId = $args['id']; + $checkout = null; + if (strpos($orderId, 'tr_') === 0) { + $checkout = new PaymentCheckout($order); + } else { + $checkout = new OrderCheckout($order); + } + $checkout->handleNotification($hash); + } catch (Exception $e) { + $checkout->Log(sprintf("mollie::handleNotification: Fehler bei Bestellung '%s': %s\n%s", $order->cBestellNr, $e->getMessage(), print_r($args, 1)), LOGLEVEL_ERROR); + } + } + + /** + * @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 (API::getMode()) { + $selectable = trim(self::Plugin()->oPluginEinstellungAssoc_arr['test_api_key']) !== ''; + } else { + $selectable = trim(self::Plugin()->oPluginEinstellungAssoc_arr['api_key']) !== ''; + if (!$selectable) { + Jtllog::writeLog('Live API Key missing!'); + } + } + if ($selectable) { + try { + $locale = AbstractCheckout::getLocale($_SESSION['cISOSprache'], Session::getInstance()->Customer()->cLand); + $amount = Session::getInstance()->Basket()->gibGesamtsummeWarenExt([ + C_WARENKORBPOS_TYP_ARTIKEL, + C_WARENKORBPOS_TYP_KUPON, + C_WARENKORBPOS_TYP_GUTSCHEIN, + C_WARENKORBPOS_TYP_NEUKUNDENKUPON, + ], true) * Session::getInstance()->Currency()->fFaktor; + if ($amount <= 0) { + $amount = 0.01; + } + $selectable = self::isMethodPossible( + static::METHOD, + $locale, + Session::getInstance()->Customer()->cLand, + Session::getInstance()->Currency()->cISO, + $amount + ); + } catch (Exception $e) { + Helper::logExc($e); + $selectable = false; + } + } + + return $selectable && parent::isSelectable(); + } + + /** + * @param $method + * @param $locale + * @param $billingCountry + * @param $currency + * @param $amount + * @throws ApiException + * @return bool + */ + protected static function isMethodPossible($method, $locale, $billingCountry, $currency, $amount) + { + $api = new API(API::getMode()); + + if (!array_key_exists('mollie_possibleMethods', $_SESSION)) { + $_SESSION['mollie_possibleMethods'] = []; + } + + $key = md5(serialize([$locale, $billingCountry, $currency, $amount])); + if (!array_key_exists($key, $_SESSION['mollie_possibleMethods'])) { + $active = $api->Client()->methods->allActive([ + 'locale' => $locale, + 'amount' => [ + 'currency' => $currency, + 'value' => number_format($amount, 2, '.', '') + ], + 'billingCountry' => $billingCountry, + 'resource' => 'orders', + 'includeWallets' => 'applepay', + ]); + foreach ($active as $a) { + $_SESSION['mollie_possibleMethods'][$key][] = (object)['id' => $a->id]; + } + } + + if ($method !== '') { + foreach ($_SESSION['mollie_possibleMethods'][$key] as $m) { + if ($m->id === $method) { + return true; + } + } + } else { + return true; + } + + return false; + } + + /** + * @param array $args_arr + * @return bool + */ + public function isValidIntern($args_arr = []) + { + return $this->duringCheckout + ? static::ALLOW_PAYMENT_BEFORE_ORDER && parent::isValidIntern($args_arr) + : parent::isValidIntern($args_arr); + } + + /** + * @return int + */ + public function getExpiryDays() + { + return (int)min(abs((int)Helper::oPlugin()->oPluginEinstellungAssoc_arr[$this->cModulId . '_dueDays']), static::MAX_EXPIRY_DAYS) ?: static::MAX_EXPIRY_DAYS; + } +} diff --git a/version/206/paymentmethod/JTLMollieApplePay.php b/version/206/paymentmethod/JTLMollieApplePay.php new file mode 100644 index 0000000..7c10dcf --- /dev/null +++ b/version/206/paymentmethod/JTLMollieApplePay.php @@ -0,0 +1,19 @@ +oRechnungsadresse->cMail; + $paymentOptions['locale'] = AbstractCheckout::getLocale($_SESSION['cISOSprache'], $order->oRechnungsadresse->cLand); + } + + $dueDays = $this->getExpiryDays(); + if ($dueDays > 3) { + $paymentOptions['dueDate'] = date('Y-m-d', strtotime("+$dueDays DAYS")); + } + + return $paymentOptions; + } +} diff --git a/version/206/paymentmethod/JTLMollieBelfius.php b/version/206/paymentmethod/JTLMollieBelfius.php new file mode 100644 index 0000000..1c0b500 --- /dev/null +++ b/version/206/paymentmethod/JTLMollieBelfius.php @@ -0,0 +1,16 @@ +clearToken(); + } + + protected function clearToken() + { + $this->unsetCache(self::CACHE_TOKEN) + ->unsetCache(self::CACHE_TOKEN_TIMESTAMP); + + return true; + } + + public function handleAdditional($aPost_arr) + { + $components = self::Plugin()->oPluginEinstellungAssoc_arr[$this->moduleID . '_components']; + $profileId = self::Plugin()->oPluginEinstellungAssoc_arr['profileId']; + + if ($components === 'N' || !$profileId || trim($profileId) === '') { + return parent::handleAdditional($aPost_arr); + } + + $cleared = false; + if (array_key_exists('clear', $aPost_arr) && (int)$aPost_arr['clear']) { + $cleared = $this->clearToken(); + } + + if ($components === 'S' && array_key_exists('skip', $aPost_arr) && (int)$aPost_arr['skip']) { + return parent::handleAdditional($aPost_arr); + } + + try { + $trustBadge = (bool)self::Plugin()->oPluginEinstellungAssoc_arr[$this->moduleID . '_loadTrust']; + $locale = AbstractCheckout::getLocale($_SESSION['cISOSprache'], Session::getInstance()->Customer() ? Session::getInstance()->Customer()->cLand : null); + $mode = API::getMode(); + $errorMessage = json_encode(self::Plugin()->oPluginSprachvariableAssoc_arr['mcErrorMessage']); + } catch (Exception $e) { + Jtllog::writeLog($e->getMessage() . "\n" . print_r(['e' => $e], 1)); + + return parent::handleAdditional($aPost_arr); + } + + if (!$cleared && array_key_exists('cardToken', $aPost_arr) && ($token = trim($aPost_arr['cardToken']))) { + return $this->setToken($token) && parent::handleAdditional($aPost_arr); + } + + $token = false; + if (($ctTS = (int)$this->getCache(self::CACHE_TOKEN_TIMESTAMP)) && $ctTS > time()) { + $token = $this->getCache(self::CACHE_TOKEN); + } + + Shop::Smarty()->assign('profileId', $profileId) + ->assign('trustBadge', $trustBadge ? self::Plugin()->cFrontendPfadURLSSL . 'img/trust_' . $_SESSION['cISOSprache'] . '.png' : false) + ->assign('components', $components) + ->assign('locale', $locale ?: 'de_DE') + ->assign('token', $token ?: false) + ->assign('testMode', $mode ?: false) + ->assign('errorMessage', $errorMessage ?: null) + ->assign('mollieLang', self::Plugin()->oPluginSprachvariableAssoc_arr); + + return false; + } + + protected function setToken($token) + { + $this->addCache(self::CACHE_TOKEN, $token) + ->addCache(self::CACHE_TOKEN_TIMESTAMP, time() + 3600); + + return true; + } + + public function getPaymentOptions(Bestellung $order, $apiType) + { + $paymentOptions = []; + + if ($apiType === 'payment') { + if ($order->Lieferadresse !== null) { + if (!$order->Lieferadresse->cMail) { + $order->Lieferadresse->cMail = $order->oRechnungsadresse->cMail; + } + $paymentOptions['shippingAddress'] = Address::factory($order->Lieferadresse); + } + + $paymentOptions['billingAddress'] = Address::factory($order->oRechnungsadresse); + } + if ((int)$this->getCache(self::CACHE_TOKEN_TIMESTAMP) > time() && ($token = trim($this->getCache(self::CACHE_TOKEN)))) { + $paymentOptions['cardToken'] = $token; + } + + return $paymentOptions; + } +} diff --git a/version/206/paymentmethod/JTLMollieEPS.php b/version/206/paymentmethod/JTLMollieEPS.php new file mode 100644 index 0000000..bbac66c --- /dev/null +++ b/version/206/paymentmethod/JTLMollieEPS.php @@ -0,0 +1,16 @@ + substr($order->cBestellNr, 0, 13)]; + } +} diff --git a/version/206/paymentmethod/JTLMollieKlarnaPayLater.php b/version/206/paymentmethod/JTLMollieKlarnaPayLater.php new file mode 100644 index 0000000..e8928b1 --- /dev/null +++ b/version/206/paymentmethod/JTLMollieKlarnaPayLater.php @@ -0,0 +1,23 @@ +Lieferadresse !== null) { + if (!$order->Lieferadresse->cMail) { + $order->Lieferadresse->cMail = $order->oRechnungsadresse->cMail; + } + $paymentOptions['shippingAddress'] = Address::factory($order->Lieferadresse); + } + } + + + return $paymentOptions; + } +} diff --git a/version/206/paymentmethod/JTLMolliePaysafecard.php b/version/206/paymentmethod/JTLMolliePaysafecard.php new file mode 100644 index 0000000..ebfa5c2 --- /dev/null +++ b/version/206/paymentmethod/JTLMolliePaysafecard.php @@ -0,0 +1,22 @@ + $order->oKunde->kKunde] : []; + } +} diff --git a/version/206/paymentmethod/JTLMolliePrzelewy24.php b/version/206/paymentmethod/JTLMolliePrzelewy24.php new file mode 100644 index 0000000..b05c76b --- /dev/null +++ b/version/206/paymentmethod/JTLMolliePrzelewy24.php @@ -0,0 +1,22 @@ + $order->oRechnungsadresse->cMail] : []; + } +} diff --git a/version/206/paymentmethod/JTLMollieSofort.php b/version/206/paymentmethod/JTLMollieSofort.php new file mode 100644 index 0000000..66c5b5c --- /dev/null +++ b/version/206/paymentmethod/JTLMollieSofort.php @@ -0,0 +1,17 @@ +OH(NI>=T42<+x9g>;*Gy9DrKtJl=F((p(~XhRMojR(!TROq)4##x zi;wfn&C+>%^UTiFKSt7JYSXp1>ZPgDP*&5InbUcF<%^K^*xKlsoYHP{(wCajZ*$Ra zbJNPo(OY2BWNFmE!S~qO{POeCTVT|{z|(GX;Bt54e}mdsUi8b(sL>`X0000JbW%=J z01%HLkU-Cn-_OsV&!6AlpP5D4UE1#Sax&aZg(%L>z8x33MOZZ8H?WJ;;n51dMe)(}9UH1j29 ze@0RGfq`^s0!X#X7!_srsUP@btltZoyHfrIVq@*+2f)Ge+&BuBcbdrjKu5}NuE;){Yi3#o7gOK=v6Y0{rAbqNgQSz}}0I~5?ej{GsP%?vN z=_l4!?VPOmM>R@!2oOAkd1t|Pb#@H>-d=$PnbBs7=u%Z>9N;0iml z2#guk2rk-V%mMEvxQCZ1@+-_*(mao=fPWKs%h@Mp0)~gcfgO7j{4M(n<{@x^Z^Hk! ze1;0X32xx)(NPC3aetZbtnBss>W2NT-v%Bch%He^5RXIyLDWRp5;o{lcPr>qmkRZj lpHDtfd;A2~X0zTP_aA;i{an>LN7rz#m}I!{TEUogY_hW!fX z1?mg>C*-erx%(so1LG!77srr_xVP7C<}EQ0XbW_HZ(Bb#ysRpA(wRN~nf+#OlTe%( zXkfncL^KKCCrg-Lh=kEnU|a;ZB9QaR>Td+?i96wEUURmd^*;_;}q*?JtCN zs9v0_oUIYrJ>{ItUF)Suj=nY*E;y-_bg}zQ;ZT|@FU4Qeut^B)WfWUjV9g-3v@K+f-ik;kV{MOr_6wK;GGik>mTp$V%-RtP)+CPEi`n!UgTe~DWM4fFWeR( literal 0 HcmV?d00001 diff --git a/version/206/paymentmethod/img/method/bancontact@2x.png b/version/206/paymentmethod/img/method/bancontact@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..a87af77d20330ab4ee197fd750d0bd39a5b10f90 GIT binary patch literal 582 zcmV-M0=fN(P)lk!lq%lq?@9+Qr z|M>X$=jZ1jWQqR%{`vX&|JVTk=U{-T&j0$~pTFAg&hoWPVjpU$|LlN(mQMfcfPbmZpr$+j>2Uw#P;ZV{AZe)(UZem0@6X@u|MkEB z;XwWU{r~1*Ky`MXzS=N!uW*i8kF?YfT$A7F^MIC5pQk%!Gip%)000nlQchC<&w%eB zkRX4bpb&7+Z;x=Vl85vF00AONL_t(|UhS6GZp0uI1+V+IBnNQY-qL&T?f<_j%Vs4k zWi4ZPi#+c$LIR;fk}z^m8)w(24LdL-qBSjmiImqQ6%1%eKSC_H5hBJOQ3wcbh=A9j z0E`>M;F1Gj9uRN{NX-L}@Ce`*0RKJE1nw{TTbXGF`gs|rT7l!dln0%_EVm0RbGyKB zqJ*zRaiSTxE%@_=;_x?lSs8dz{y6#LPln}z>8GT40dLB`KB#<1qlM(E;D0OsM*0?TeIhg`dn6;Q{6Fh2l%qOS4K%wo8-q7AUD{?yGF(55vm4C&H_FzBH+J=d4+57}kr Up-!czfB*mh07*qoM6N<$g3OCHTL1t6 literal 0 HcmV?d00001 diff --git a/version/206/paymentmethod/img/method/banktransfer@2x.png b/version/206/paymentmethod/img/method/banktransfer@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..c70206bef4893f23fcd59d436273108d2f2eebc7 GIT binary patch literal 801 zcmV++1K#|JP)lk!lq*=;-9+mkX z{{U2_ztrjP@9%)A(*D5?-|6)J(MtZwET6yKpugSt`1lZBsz86cAZf7q`T3Bv*Z%(g z-|F=K#U1|5JO0^dAZoDx_u=pL`RC{7_xJZ;l*j-3@c!I)@AdkSwAlXDS^mf@aG%W2 z;O`J$tN-Md>+9=KiNUYR<6xA=@AUcq@WXGP%>DiS|LnB>%sc+*q+gWBFm$#4l$oJ=bMJL) zN$}UM z^EEI7D0q#*=`w@Mb&#yX6$WP@x&}s<8JvJ@pvqecQO^sez9^Xbs$t>(|Nn0Y_`k@X z`u+Uv`wm6F?mz#2{?4!aFGTBV&I9cbE(!7rW)PTg{{H;_^9ubA3J&Kd+&@2If#l5V zkwEFKo-U3d6>)E`o#Z>Lz~g$+{n^fDUKQE@|Mgd!a9=T#&e{4(sr-HO1o4KQ>uv;= zWX2_)yrQzk;QY@iN0x35n7oK-g-2+63_H(@QU|u6Z>|Z!r6lZ1zes9a?+x$E9%YhzX@O1Ta JS?83{1OT9Jm%RW0 literal 0 HcmV?d00001 diff --git a/version/206/paymentmethod/img/method/creditcard@2x.png b/version/206/paymentmethod/img/method/creditcard@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..b08be792753326b65345c752a6f350182a9393d2 GIT binary patch literal 3125 zcmV-549fF~P)U)tpG8C;JKuOy`KwEz465f^0GVo$<); zd;mfKu>I#Bzt#-T%#)}DDWufmGZ9EFFLceya6K~<;5f&W8C05XrA8uP@_rJ=rq=;@ zR)u+-o=|-(zgqT?=2YJRez*!K^ymC+OYTy@(LM4UzC$eC%do?e#azZHv3718cbK)5 zIOgtOt(MkKc`bm;i6pea!~*cciaJ4IKqD(#?9k=89GB-avX3$(%gT~nEfAw0pAc3h z0!+qjRD-n>uXo^hl9In#iopx|WH($CAi1fDlakPPtOXR;(U<{s!f z3}v_DtNz;YZ)4mN+85)x2tYq)9FS(rUocS&kj&|=VTlEfMCx)ajX~CS!xRI~^#lZq z8CY!?aKiO4qY&Wc)WOB4d5}+iL zkUew@xT6X;n3-@m52^GuOT>C~0aBkrWtK!zC;&hV&Mypx;=>XLMA6v_0Gf+w3DR4D zqT(=NA`BAPltKAD4T7Ol0buo(*VBhp2}y@2AzSH2KTZtUF`)E!=h}S0Xzkw4_ex{R zLhEYvNTalj6zrPob}*RlVWB^drNsd{?l~{Jqo`p>@XUk<+-(gvJ@zClFD8}(R@T-i z2K?b~W4!tk|HLQ0vRMSpYqN5Uu7V82yjZHPflkFm%h`hr&BGFifsA0vRyOqJI?c}< zx^rE0s*3Ixa}0LeX&1X27);7xC&h;N`dcr;skfSob=jQrtO!p*wsvb=@Yr7*abRI( z7HdcWQv~dEIxwm4IiDv=)&e}A%r(mPnxB5Zm*+qZL?DA!PrHc0Jh5CXp#0^dSA2r*c}?G7_~{RR4@Ccz7(e-uKLNP8hGMPS^gtDKO;wfMAnAQW8w3m4 z8*0y^-~3cnY6T}t>atdzpws42A->avhk2bzP?Y^~%zzI)KaXzdXLgkDSyA_vyMXRN zpmKj&Pmxk$+?iQAI=bDeQM%VyyoZ#G!A^ry(TWK*jNI`&nLcQ|@IWXWulm?w1Oz^b zxv-(}IqU!c`n}gog?@M^9-6nNq4GIT)<3R4cYREDNGI-?sY@+4vt${4iFqJK@_xbxNU0rJR^c@iI2K=*viT0 zI^9HXY=ED==n5?NGf^~wgVuzx`1!-e2-m&&=Rr%B%uFE%DC}>r6 zFn3TrMKR(bgjtIGYD6pL17U_5E$zZ@8ujJI0XO)0^Rw8LZaX21`!wPC{5i#)TOf11Bk;K5T@84jWHUH z7~kdARxU9E__fs)Q~^9FG7itFA_G8Nhu$sLC%6o}WCHAjb1w0P!2p&LH&fqaHB=wqI|{b$|?_2`4Q((p-wQgtIDZIrX{ty8~?JYnDgMQ=hOY-Nj(r7IVxlqHoi#=9{JSg2le0fs+%Ko z%x{ zq4SxFSjs3ZQpzR`R-KobaqnDcA6SknT4I4hXtvjA~)$vS1+&bsJI zj{#9CeBHrdCV@{Qyv>OI`j_TVz7Y^G$<`1Yqp1-1>_ahJ>3by zcrs<_%8ASnX0&X6;QQhbIt950hc=*q%>2X zQd&})X(>zga1N4L6gi2OP+HCcIL;OS-qIVGFCVf||Zn_w$A9o8XgbK!{vB2cJ;~xzRrqi0K zP^r(gSr$ubcL)f{zGJ7Kcj4;{_6&*qR7~hQvj`%(v3Y+mi0H4%*Wd|HsqcO`9`I2a z+}j^wb90-)G~N+lvm9JQEl(M9{Cc0Ae)h$8vdX^rh#zih==FNxTVWjy zQdE$F^T4Bw(4#T_{?C6#EKthNPSK1@X7Uf7d9O5`oMFeGe+=`}&DUA7XSj0>#6$>s zq!S1Z17BQj3}Pcyf=coZ-<>pPGx^F4w6(p9?VTO{k5tm0eRa#w$5?g3kX{eqnRcrS zZ-@Tw_A2JaUk3bgDo9E(2x^wlw0B_rYPMgC<=My*r8ODA>hf>@_-B4VOM+|_VE8-( zl-X$C8Sl--zslO`>351bt5{z}cXT}r&(PDMCDPT1C}oT}DGCkGG^fjyss-RP@Yo#y zYvWivcUtma>l;zxQVw+i?bBtmOs^jgd)JqLmd*gMt`BRf1EkNp+2;U!1#I{aVUxz$GxXq9 P00000NkvXXu0mjf3Vis# literal 0 HcmV?d00001 diff --git a/version/206/paymentmethod/img/method/directdebit@2x.png b/version/206/paymentmethod/img/method/directdebit@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..514ff845b84d38cd8eb97b9e2c53e5c117967944 GIT binary patch literal 801 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 literal 0 HcmV?d00001 diff --git a/version/206/paymentmethod/img/method/giropay@2x.png b/version/206/paymentmethod/img/method/giropay@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..b787e1fee50c9bcca112f734ef4bcbd4ecfb6d6b GIT binary patch literal 602 zcmV-g0;T5Kx~EOrH!)pASu;4ojd8OQ8=; zpbt!;!_w#B>GK{}r)iJG@bvggdAR@o{+6-TrM%mCn#w$GvMpk*ho#Tb-RaC5+y)hho537JnGBqPA~G@Ik#rt1jWCNmt_X5yY-;OM4Sm|;L0fCz(H!a59C z!6FQJ1`O=K0(U?&WmHmQ%ovl1g=xY%=0>sX7T{!DDr3#1AfT>{>*NQdp;XxeDnn^6 z;Fg|~18)oh=#B%J574HG=ZK=b0(2)=ZWs@6u|Psp2S`Ms-aSCKNc4dZ3ml0Y1JpF0 zACT7(WFOdH$J={=+}Kh?t@=QTh`Y)S;{lL4q2$K&0aK;&(@GqDK&DI^R~^tLy#OA$ z1Nay30gQkc{Q&0jzz(SpmbnlhVhfzVhaBhB0($}wh1S_^$N7}lg}e4p3Ic|F4;Z~b zTY@72isxg1#8BrSfnxv^S{6kiGl4E$H2v|f@*S9m0aJJk172Vm21F3Hg)IO)g#GGT oVe}rh6KIQG--ZM8)e@S10aM=ZI#^TblmGw#07*qoM6N<$f@FIOx&QzG literal 0 HcmV?d00001 diff --git a/version/206/paymentmethod/img/method/ideal@2x.png b/version/206/paymentmethod/img/method/ideal@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..efc4315a96a6b2d9b160578a65fe52206783f2ca GIT binary patch literal 845 zcmV-T1G4;yP)lk!ZZ65OMGC?}UYf;o;!m;NZf-!qXsn`1tsvqob6RlsGvz=jZ45_xJw({`vX& z+CYuwfU@xL?-Nv%`QPmApT=fqW&i*F(b3WK zzuD%1v(zAZ>+9>Xv$F87&$F|$@bK^%8W`-K#nT^p^1s=^!okAA!Tj&_DJdxZ{r%~X zz3Gp=&=7F!pvK@}pYN~F>5#mWl#|_1mb0_6g@uIHFobn>b?J}1M@UB*8yIC~W#VwE zc6N2$P?z9fpjKB^=ker~0000HbW%=J0PlbhkiUP=Adhe$&v1`#zea&7rvLx}*GWV{ zRCr#^*2j+9Fc5%YO7?ntl9{1;aqqou@0;Fxd;j;y*jNN`HV2Bl>~|3_{4oLqkzy%V z*t96C%}2Z9&SQ)86vWClksDVqqe|=&Z3|YQQjA*4CE6Eai>Qp6VzP3=CKt6Gk}WnU zMr|=|2#YGH?I~G;2n`TD#K5)puk^^z67b+ZZd-naz)7$!d_QRdc|mw#b1~<{2k2)FEaYF&OT-`GX$RPM#Nt`QAi#wXJk>zhFTO>59`Wo^#}<>sMjOed(+{-3ru0A7D$0jI558$ z)N0PF!RsCe2|{A+{jU4@5&uc>v9T(>X>= zpc$wJPDAG6XudKWan^4w_bUdHVBPG<>jQiVOn&QMzg?RgEbW=`(e{u7#up5;D^8W3 z2%8R3n@hIHS^6WCiFSq9p;8&OR7*Sn%M-cP>{s2YOOzKYHtDf;#GS4DUiRI4c22NA XzpeJ7+7%dW00000NkvXXu0mjfybi$$ literal 0 HcmV?d00001 diff --git a/version/206/paymentmethod/img/method/inghomepay@2x.png b/version/206/paymentmethod/img/method/inghomepay@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..538f219588886db215757eafd5c5151241f18b5a GIT binary patch literal 1118 zcmV-k1flzhP)`_0RK|}|55<|Q2_r?0RL0~|5E_}r-1)w9RKX&|5E_}=Gy;L z0RR90|6UOPlVJbp-~WC<|J1+#zn}l9fd6P9|A|olb1?tk&;RxB|Mc(wo^bzkF#pQ0 z|Fn<)>fisgkpF2Q|G%LBsek{okpG@<|H-fazM%hUAODC@|H-ibs(=5~!2gtB|K894 zs(@(VAMyYI01|XkPE!C7&ySx#AdugXK#$)bkdUC?LT6GX000A7Nkl+_F4;G0`t->#NE zT;V&r`f!+EySiCj<6V7Pt?{mYTH&4jj{)gM0TN(F3?6st+kjw6 z>LApXPB>Unt8V~;Cik9f49AhQ!$i7^fuL#4vW=&{86JR|lTsG~BRymzfEs|JX9J1K z03Dw$1C&G3WKK=%kB`J1r1*<~s2`z=k6T78&3xGOL&RV&0xXfJ0Ql@xfEn*A1CX9E zQ!WBD5?VbTK7XTsCp`U6crw}TsH%60W z2hoh@0nLYSxRBab{+9<3C+^Mz9xYb&ZxhMVDb+cqriY2<9AG-<8gN)^Cix5?)@kAU z;?6$;-SN`NKvD-cR@w%n?9AWi0I~xRElDnK5^Rh@FtDVHX8@ZJfJl->N&_A{l2bso z2x`kJr-3lmJ%9)DK@>~Q{7brt3fNKr^rbrq+|{-iAekxBG;uoyGqur4Ei0S?0=Yll zF_SR>W}x;7ttLalDFCI-OXsp?(S;*|rkk|uOcTs~fUR;0m?79z>!T@dSC<#zVpen3 zDj@L*GoMZY$tw7C*m%o|vLvel!qz~FMPzph=x6{KTjppdC7aC#VVdHg)$wl$bf*AC z1-Rnnz*LgVO4|B5HX#U@PXUn*;sq_sC5u*2fG7j7o&o~>%Wn3WWcg~#QmPptG|8+k2H7XW|=xVi9nUeg`1*I2IB*YJ(+JNL|VD24JQDXa_~} zqMBf8fF~Vbz5wvk*3xb81`yK5AZAEW$9)?Qt+BO>C3E@1Aktu4fz|6HW^Y;1@lk!lq%mkX z{~%3y0h-K!%;mq#+4%VQ5J7OCv&KMYjPLUG@9*#T_xE6cpCPBxaK_?)nX{kS?7!yn zfSI!2=Is9d{_pwx05oR#`T5`T`RC{7L9^Llzu!=FmQcCekkjew>+3LDf{>=XK(pDe zzt4c0vd`J#Fs;_V%-D~nykNlKAg9yc^7t^U)_~3BfX(J`#^Vv8&k>-{-}3p8(&?|? z?{JN&{r&x)v&FFA?=V_}aEz&7z~7M5=+D{X&+PS}+3awQs351(ptHqzpNxV4000qm zQchCIy&+X> z=*5Ul;OaQ@NK`Vzy8t_g2?_Jis)3C$i910Xw$PIU9&Uk!LpkskEkL9-LfkOWJAbaP zUroip18r(eg}^hN*BXg{sb1!Yfc6S#iGXvxN(6jb7x=sau0_D;#S-`?0_b=FJSG`H zPqbnfvWg$g}i**@5@#v5NT=$lzqSQdXDg|8f zIHlhJQN%Mfm~#2YP9b1YgB(!GAN!r?CIjA)sTANZfG||7{JhG5H)Vm3e?0>E>_vVi zq!;d4SOSQYxt#%m;F70Lx8o{r!Tt9&c8CI14(M}40nf9jzsNQAmkVA7gAM$Z|1+@m z0b{)*&IIp+jVE#-MjL9Dd6xv65#{P&<3u77*DDnbtf@m157r`vbG^_r?Ff8 d>Rr1A+%FMH_Q$8Zwr>Cc002ovPDHLkV1oT`waEYg literal 0 HcmV?d00001 diff --git a/version/206/paymentmethod/img/method/klarna@2x.png b/version/206/paymentmethod/img/method/klarna@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..e28a187b81e7c5a6256fea7382a643762746dd1e GIT binary patch literal 896 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 literal 0 HcmV?d00001 diff --git a/version/206/paymentmethod/img/method/paypal@2x.png b/version/206/paymentmethod/img/method/paypal@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..a816d7201f59ea7cef713f5e7895e66dcd6ee9a7 GIT binary patch literal 626 zcmV-&0*(ENP)zW{Q;0CK+oaK8X?zW{Q<0CB+pa=`#_!2of;na1S+alrro z|IFg@&*bxRu-m`e?~lRb-|hDbcETox$#AdRv()Q`yWm5X&|s$5P@dDD$>-eb_JFwG zpUUS$m(j@K@sPpeFpSLa_WMAU&p?#W{Qdsu^7&w=*MGR*^7#DO>Gd#+%P@?~P@U7S z((9ba=CIQ0sn6-_^!k0a-V=Mp)8_OXfyX(K&a%|&;_mkldc-e_%lZ5LgSp`#gUC6M z&erGk#LeN$0000GbW%=J0M8)rfN+qXfDoX6Z;yYFN6jxl0003wNklC4+MXiktqCYwRgSg6)KJbf z5Lj1?Y5+oU@|#dstX9C|0Ujt`J{M4b8Wr^cdi(ak0iFt>ORE}Nts8qh=FWCkI)}aEnE&{1?2hI?PIY68@ zbOdbw0PvXrf5i!Szy>sZ79ap>ye%)UHj^sMYbqagD6U zaJzaI>n$ypF23oVdS#o6|W|*DFT6j;X_Pjl^+{$7FxcM`F8{J!B6QqfZ6J=?T z0Z*i4z#}$g7~II(N7`*?T& O0000Mm~wpOtGdRMp-ebF zJuNaG78zVbOD!TMdRt_ueTc`Cq7MrUiDqwHL`pp^G2!3~t^fc45_D2dQvi?<&ySzq z&yPSLKp+s`&(ENlBcfvf009O`L_t(|UhS60Zp1JQL@BrJDI>X-t?BLmKQE>PBe{x1 zfE@On=HdqqA=xHol@*94&DRu2G6-2F{`otIN!gG=!IEeT6)Vc2!q5ULZU{>LN^lkQ z6ZNlrj1}04KE#&uMIop;cM5^ytf}zD`79SS9QTk5o_qtj!1)0xvEX2t7f1!iGHgI7 z7&;pYNCh93DJw_?;Rw7pazW)+@E{i;lyGtZ#-9>{b4|RUwsVO?IhoGU0(5hU(VOB0 z?V~Sog7riT<`S21tDgk|d|Kv}cTm1bUaD=+I8@G^{_l6;Dkz}hmJC$nw1J8>=|(U_ sv|A{Db!jJ_!6X#e-V3HE%!Veu0ZmugH{Fk>9RL6T07*qoM6N<$f);_{SO5S3 literal 0 HcmV?d00001 diff --git a/version/206/paymentmethod/tpl/bestellabschluss.tpl b/version/206/paymentmethod/tpl/bestellabschluss.tpl new file mode 100644 index 0000000..b26d8ef --- /dev/null +++ b/version/206/paymentmethod/tpl/bestellabschluss.tpl @@ -0,0 +1,26 @@ +{if isset($oMollieException)} +
+ {$oMollieException->getMessage()} +
+ +{/if} + +{if isset($redirect) && $redirect != ''} + + {if $checkoutMode == 'D'} + + {/if} +{/if} + diff --git a/version/206/paymentmethod/tpl/mollieComponents.tpl b/version/206/paymentmethod/tpl/mollieComponents.tpl new file mode 100644 index 0000000..987abf1 --- /dev/null +++ b/version/206/paymentmethod/tpl/mollieComponents.tpl @@ -0,0 +1,148 @@ +

{$mollieLang.cctitle}

+ +
+ +
+ + {if $token !== false} + +
+
+ {$mollieLang.clearDescr} +
+
+ +
+
+ + {if $trustBadge} +
+ PCI-DSS SAQ-A compliant +
+ {/if} + + {else} + + +
+ +
+
+
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+ +
+
+ + +
+
+ + {if $trustBadge} +
+ PCI-DSS SAQ-A compliant +
+ {/if} + {if $components == 'S'} + + {/if} +
+ +{/if} + + + + + + \ No newline at end of file diff --git a/version/206/tpl/_alerts.tpl b/version/206/tpl/_alerts.tpl new file mode 100644 index 0000000..5279fa3 --- /dev/null +++ b/version/206/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} From 1ba7f0f9725632c53d0bb2a1359bfe599f21a254 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Tue, 11 Jan 2022 09:53:20 +0100 Subject: [PATCH 274/280] composer fix --- version/100/adminmenu/info.php | 1 + version/100/adminmenu/orders.php | 1 + version/100/adminmenu/paymentmethods.php | 1 + version/100/class/Helper.php | 1 + version/100/class/Model/AbstractModel.php | 1 + version/100/class/Model/Payment.php | 1 + version/100/class/Mollie.php | 1 + version/100/frontend/131_globalinclude.php | 1 + version/100/frontend/140_smarty.php | 1 + version/100/frontend/144_notify.php | 1 + version/100/frontend/181_sync.php | 1 + version/100/paymentmethod/JTLMollie.php | 1 + version/100/paymentmethod/JTLMollieBancontact.php | 1 + version/100/paymentmethod/JTLMollieBanktransfer.php | 1 + version/100/paymentmethod/JTLMollieBelfius.php | 1 + version/100/paymentmethod/JTLMollieBitcoin.php | 1 + version/100/paymentmethod/JTLMollieCreditCard.php | 1 + version/100/paymentmethod/JTLMollieDirectDebit.php | 1 + version/100/paymentmethod/JTLMollieEPS.php | 1 + version/100/paymentmethod/JTLMollieGiftcard.php | 1 + version/100/paymentmethod/JTLMollieGiropay.php | 1 + version/100/paymentmethod/JTLMollieIDEAL.php | 1 + version/100/paymentmethod/JTLMollieINGHomePay.php | 1 + version/100/paymentmethod/JTLMollieKBC.php | 1 + version/100/paymentmethod/JTLMollieKlarnaPayLater.php | 1 + version/100/paymentmethod/JTLMollieKlarnaSliceIt.php | 1 + version/100/paymentmethod/JTLMolliePayPal.php | 1 + version/100/paymentmethod/JTLMolliePaysafecard.php | 1 + version/100/paymentmethod/JTLMollieSofort.php | 1 + version/107/adminmenu/info.php | 1 + version/107/adminmenu/orders.php | 1 + version/107/adminmenu/paymentmethods.php | 1 + version/107/class/ExclusiveLock.php | 1 + version/107/class/Helper.php | 1 + version/107/class/Model/AbstractModel.php | 1 + version/107/class/Model/Payment.php | 1 + version/107/class/Mollie.php | 1 + version/107/frontend/131_globalinclude.php | 1 + version/107/frontend/140_smarty.php | 1 + version/107/frontend/144_notify.php | 1 + version/107/frontend/181_sync.php | 1 + version/107/paymentmethod/JTLMollie.php | 1 + version/107/paymentmethod/JTLMollieApplePay.php | 1 + version/107/paymentmethod/JTLMollieBancontact.php | 1 + version/107/paymentmethod/JTLMollieBanktransfer.php | 1 + version/107/paymentmethod/JTLMollieBelfius.php | 1 + version/107/paymentmethod/JTLMollieCreditCard.php | 1 + version/107/paymentmethod/JTLMollieDirectDebit.php | 1 + version/107/paymentmethod/JTLMollieEPS.php | 1 + version/107/paymentmethod/JTLMollieGiftcard.php | 1 + version/107/paymentmethod/JTLMollieGiropay.php | 1 + version/107/paymentmethod/JTLMollieIDEAL.php | 1 + version/107/paymentmethod/JTLMollieINGHomePay.php | 1 + version/107/paymentmethod/JTLMollieKBC.php | 1 + version/107/paymentmethod/JTLMollieKlarnaPayLater.php | 1 + version/107/paymentmethod/JTLMollieKlarnaSliceIt.php | 1 + version/107/paymentmethod/JTLMollieMyBank.php | 1 + version/107/paymentmethod/JTLMolliePayPal.php | 1 + version/107/paymentmethod/JTLMolliePaysafecard.php | 1 + version/107/paymentmethod/JTLMolliePrzelewy24.php | 1 + version/107/paymentmethod/JTLMollieSofort.php | 1 + version/109/adminmenu/info.php | 1 + version/109/adminmenu/orders.php | 1 + version/109/adminmenu/paymentmethods.php | 1 + version/109/class/ExclusiveLock.php | 1 + version/109/class/Helper.php | 1 + version/109/class/Model/AbstractModel.php | 1 + version/109/class/Model/Payment.php | 1 + version/109/class/Mollie.php | 1 + version/109/frontend/131_globalinclude.php | 1 + version/109/frontend/140_smarty.php | 1 + version/109/frontend/144_notify.php | 1 + version/109/frontend/181_sync.php | 1 + version/109/paymentmethod/JTLMollie.php | 1 + version/109/paymentmethod/JTLMollieApplePay.php | 1 + version/109/paymentmethod/JTLMollieBancontact.php | 1 + version/109/paymentmethod/JTLMollieBanktransfer.php | 1 + version/109/paymentmethod/JTLMollieBelfius.php | 1 + version/109/paymentmethod/JTLMollieCreditCard.php | 1 + version/109/paymentmethod/JTLMollieDirectDebit.php | 1 + version/109/paymentmethod/JTLMollieEPS.php | 1 + version/109/paymentmethod/JTLMollieGiftcard.php | 1 + version/109/paymentmethod/JTLMollieGiropay.php | 1 + version/109/paymentmethod/JTLMollieIDEAL.php | 1 + version/109/paymentmethod/JTLMollieINGHomePay.php | 1 + version/109/paymentmethod/JTLMollieKBC.php | 1 + version/109/paymentmethod/JTLMollieKlarnaPayLater.php | 1 + version/109/paymentmethod/JTLMollieKlarnaSliceIt.php | 1 + version/109/paymentmethod/JTLMollieMyBank.php | 1 + version/109/paymentmethod/JTLMolliePayPal.php | 1 + version/109/paymentmethod/JTLMolliePaysafecard.php | 1 + version/109/paymentmethod/JTLMolliePrzelewy24.php | 1 + version/109/paymentmethod/JTLMollieSofort.php | 1 + version/110/adminmenu/info.php | 1 + version/110/adminmenu/orders.php | 1 + version/110/adminmenu/paymentmethods.php | 1 + version/110/class/ExclusiveLock.php | 1 + version/110/class/Helper.php | 1 + version/110/class/Model/AbstractModel.php | 1 + version/110/class/Model/Payment.php | 1 + version/110/class/Mollie.php | 1 + version/110/frontend/131_globalinclude.php | 1 + version/110/frontend/140_smarty.php | 1 + version/110/frontend/144_notify.php | 1 + version/110/frontend/181_sync.php | 1 + version/110/paymentmethod/JTLMollie.php | 1 + version/110/paymentmethod/JTLMollieApplePay.php | 1 + version/110/paymentmethod/JTLMollieBancontact.php | 1 + version/110/paymentmethod/JTLMollieBanktransfer.php | 1 + version/110/paymentmethod/JTLMollieBelfius.php | 1 + version/110/paymentmethod/JTLMollieCreditCard.php | 1 + version/110/paymentmethod/JTLMollieDirectDebit.php | 1 + version/110/paymentmethod/JTLMollieEPS.php | 1 + version/110/paymentmethod/JTLMollieGiftcard.php | 1 + version/110/paymentmethod/JTLMollieGiropay.php | 1 + version/110/paymentmethod/JTLMollieIDEAL.php | 1 + version/110/paymentmethod/JTLMollieINGHomePay.php | 1 + version/110/paymentmethod/JTLMollieKBC.php | 1 + version/110/paymentmethod/JTLMollieKlarnaPayLater.php | 1 + version/110/paymentmethod/JTLMollieKlarnaSliceIt.php | 1 + version/110/paymentmethod/JTLMollieMyBank.php | 1 + version/110/paymentmethod/JTLMolliePayPal.php | 1 + version/110/paymentmethod/JTLMolliePaysafecard.php | 1 + version/110/paymentmethod/JTLMolliePrzelewy24.php | 1 + version/110/paymentmethod/JTLMollieSofort.php | 1 + version/111/adminmenu/info.php | 1 + version/111/adminmenu/orders.php | 1 + version/111/adminmenu/paymentmethods.php | 1 + version/111/class/ExclusiveLock.php | 1 + version/111/class/Helper.php | 1 + version/111/class/Model/AbstractModel.php | 1 + version/111/class/Model/Payment.php | 1 + version/111/class/Mollie.php | 1 + version/111/frontend/131_globalinclude.php | 1 + version/111/frontend/140_smarty.php | 1 + version/111/frontend/144_notify.php | 1 + version/111/frontend/181_sync.php | 1 + version/111/paymentmethod/JTLMollie.php | 1 + version/111/paymentmethod/JTLMollieApplePay.php | 1 + version/111/paymentmethod/JTLMollieBancontact.php | 1 + version/111/paymentmethod/JTLMollieBanktransfer.php | 1 + version/111/paymentmethod/JTLMollieBelfius.php | 1 + version/111/paymentmethod/JTLMollieCreditCard.php | 1 + version/111/paymentmethod/JTLMollieDirectDebit.php | 1 + version/111/paymentmethod/JTLMollieEPS.php | 1 + version/111/paymentmethod/JTLMollieGiftcard.php | 1 + version/111/paymentmethod/JTLMollieGiropay.php | 1 + version/111/paymentmethod/JTLMollieIDEAL.php | 1 + version/111/paymentmethod/JTLMollieINGHomePay.php | 1 + version/111/paymentmethod/JTLMollieKBC.php | 1 + version/111/paymentmethod/JTLMollieKlarnaPayLater.php | 1 + version/111/paymentmethod/JTLMollieKlarnaSliceIt.php | 1 + version/111/paymentmethod/JTLMollieMyBank.php | 1 + version/111/paymentmethod/JTLMolliePayPal.php | 1 + version/111/paymentmethod/JTLMolliePaysafecard.php | 1 + version/111/paymentmethod/JTLMolliePrzelewy24.php | 1 + version/111/paymentmethod/JTLMollieSofort.php | 1 + version/200/adminmenu/info.php | 1 + version/200/adminmenu/orders.php | 1 + version/200/adminmenu/paymentmethods.php | 1 + version/200/class/API.php | 1 + version/200/class/Checkout/AbstractCheckout.php | 1 + version/200/class/Checkout/AbstractResource.php | 1 + .../200/class/Checkout/Exception/ResourceValidityException.php | 1 + version/200/class/Checkout/Order/Address.php | 1 + version/200/class/Checkout/Order/OrderLine.php | 1 + version/200/class/Checkout/OrderCheckout.php | 1 + version/200/class/Checkout/Payment/Address.php | 1 + version/200/class/Checkout/Payment/Amount.php | 1 + version/200/class/Checkout/PaymentCheckout.php | 1 + version/200/class/ExclusiveLock.php | 1 + version/200/class/Helper.php | 1 + version/200/class/Hook/AbstractHook.php | 1 + version/200/class/Hook/ApplePay.php | 1 + version/200/class/Hook/Checkbox.php | 1 + version/200/class/Hook/Queue.php | 1 + version/200/class/Model/AbstractModel.php | 1 + version/200/class/Model/Customer.php | 1 + version/200/class/Model/Payment.php | 1 + version/200/class/Model/Queue.php | 1 + version/200/class/Model/Shipment.php | 1 + version/200/class/Mollie.php | 1 + version/200/class/Queue.php | 1 + version/200/class/Shipment.php | 1 + version/200/class/Traits/Jsonable.php | 1 + version/200/class/Traits/Plugin.php | 1 + version/200/class/Traits/RequestData.php | 1 + version/200/frontend/131_globalinclude.php | 1 + version/200/frontend/132_headPostGet.php | 1 + version/200/frontend/140_smarty.php | 1 + version/200/frontend/180_checkbox.php | 1 + version/200/frontend/181_sync.php | 1 + version/200/frontend/210_storno.php | 1 + version/200/frontend/75_bestellungInDb.php | 1 + version/200/frontend/applepay.php | 1 + version/200/paymentmethod/JTLMollie.php | 1 + version/200/paymentmethod/JTLMollieApplePay.php | 1 + version/200/paymentmethod/JTLMollieBancontact.php | 1 + version/200/paymentmethod/JTLMollieBanktransfer.php | 1 + version/200/paymentmethod/JTLMollieBelfius.php | 1 + version/200/paymentmethod/JTLMollieCreditCard.php | 1 + version/200/paymentmethod/JTLMollieDirectDebit.php | 1 + version/200/paymentmethod/JTLMollieEPS.php | 1 + version/200/paymentmethod/JTLMollieGiftcard.php | 1 + version/200/paymentmethod/JTLMollieGiropay.php | 1 + version/200/paymentmethod/JTLMollieIDEAL.php | 1 + version/200/paymentmethod/JTLMollieINGHomePay.php | 1 + version/200/paymentmethod/JTLMollieKBC.php | 1 + version/200/paymentmethod/JTLMollieKlarnaPayLater.php | 1 + version/200/paymentmethod/JTLMollieKlarnaSliceIt.php | 1 + version/200/paymentmethod/JTLMollieMyBank.php | 1 + version/200/paymentmethod/JTLMolliePayPal.php | 1 + version/200/paymentmethod/JTLMolliePaysafecard.php | 1 + version/200/paymentmethod/JTLMolliePrzelewy24.php | 1 + version/200/paymentmethod/JTLMollieSofort.php | 1 + version/201/adminmenu/info.php | 1 + version/201/adminmenu/orders.php | 1 + version/201/adminmenu/paymentmethods.php | 1 + version/201/class/API.php | 1 + version/201/class/Checkout/AbstractCheckout.php | 1 + version/201/class/Checkout/AbstractResource.php | 1 + .../201/class/Checkout/Exception/ResourceValidityException.php | 1 + version/201/class/Checkout/Order/Address.php | 1 + version/201/class/Checkout/Order/OrderLine.php | 1 + version/201/class/Checkout/OrderCheckout.php | 1 + version/201/class/Checkout/Payment/Address.php | 1 + version/201/class/Checkout/Payment/Amount.php | 1 + version/201/class/Checkout/PaymentCheckout.php | 1 + version/201/class/ExclusiveLock.php | 1 + version/201/class/Helper.php | 1 + version/201/class/Hook/AbstractHook.php | 1 + version/201/class/Hook/ApplePay.php | 1 + version/201/class/Hook/Checkbox.php | 1 + version/201/class/Hook/Queue.php | 1 + version/201/class/Model/AbstractModel.php | 1 + version/201/class/Model/Customer.php | 1 + version/201/class/Model/Payment.php | 1 + version/201/class/Model/Queue.php | 1 + version/201/class/Model/Shipment.php | 1 + version/201/class/Mollie.php | 1 + version/201/class/Queue.php | 1 + version/201/class/Shipment.php | 1 + version/201/class/Traits/Jsonable.php | 1 + version/201/class/Traits/Plugin.php | 1 + version/201/class/Traits/RequestData.php | 1 + version/201/frontend/131_globalinclude.php | 1 + version/201/frontend/132_headPostGet.php | 1 + version/201/frontend/140_smarty.php | 1 + version/201/frontend/180_checkbox.php | 1 + version/201/frontend/181_sync.php | 1 + version/201/frontend/210_storno.php | 1 + version/201/frontend/75_bestellungInDb.php | 1 + version/201/frontend/applepay.php | 1 + version/201/paymentmethod/JTLMollie.php | 1 + version/201/paymentmethod/JTLMollieApplePay.php | 1 + version/201/paymentmethod/JTLMollieBancontact.php | 1 + version/201/paymentmethod/JTLMollieBanktransfer.php | 1 + version/201/paymentmethod/JTLMollieBelfius.php | 1 + version/201/paymentmethod/JTLMollieCreditCard.php | 1 + version/201/paymentmethod/JTLMollieDirectDebit.php | 1 + version/201/paymentmethod/JTLMollieEPS.php | 1 + version/201/paymentmethod/JTLMollieGiftcard.php | 1 + version/201/paymentmethod/JTLMollieGiropay.php | 1 + version/201/paymentmethod/JTLMollieIDEAL.php | 1 + version/201/paymentmethod/JTLMollieINGHomePay.php | 1 + version/201/paymentmethod/JTLMollieKBC.php | 1 + version/201/paymentmethod/JTLMollieKlarnaPayLater.php | 1 + version/201/paymentmethod/JTLMollieKlarnaSliceIt.php | 1 + version/201/paymentmethod/JTLMollieMyBank.php | 1 + version/201/paymentmethod/JTLMolliePayPal.php | 1 + version/201/paymentmethod/JTLMolliePaysafecard.php | 1 + version/201/paymentmethod/JTLMolliePrzelewy24.php | 1 + version/201/paymentmethod/JTLMollieSofort.php | 1 + version/202/adminmenu/info.php | 1 + version/202/adminmenu/orders.php | 1 + version/202/adminmenu/paymentmethods.php | 1 + version/202/class/API.php | 1 + version/202/class/Checkout/AbstractCheckout.php | 1 + version/202/class/Checkout/AbstractResource.php | 1 + .../202/class/Checkout/Exception/ResourceValidityException.php | 1 + version/202/class/Checkout/Order/Address.php | 1 + version/202/class/Checkout/Order/OrderLine.php | 1 + version/202/class/Checkout/OrderCheckout.php | 1 + version/202/class/Checkout/Payment/Address.php | 1 + version/202/class/Checkout/Payment/Amount.php | 1 + version/202/class/Checkout/PaymentCheckout.php | 1 + version/202/class/ExclusiveLock.php | 1 + version/202/class/Helper.php | 1 + version/202/class/Hook/AbstractHook.php | 1 + version/202/class/Hook/ApplePay.php | 1 + version/202/class/Hook/Checkbox.php | 1 + version/202/class/Hook/Queue.php | 1 + version/202/class/Model/AbstractModel.php | 1 + version/202/class/Model/Customer.php | 1 + version/202/class/Model/Payment.php | 1 + version/202/class/Model/Queue.php | 1 + version/202/class/Model/Shipment.php | 1 + version/202/class/Mollie.php | 1 + version/202/class/Queue.php | 1 + version/202/class/Shipment.php | 1 + version/202/class/Traits/Jsonable.php | 1 + version/202/class/Traits/Plugin.php | 1 + version/202/class/Traits/RequestData.php | 1 + version/202/frontend/131_globalinclude.php | 1 + version/202/frontend/132_headPostGet.php | 1 + version/202/frontend/140_smarty.php | 1 + version/202/frontend/180_checkbox.php | 1 + version/202/frontend/181_sync.php | 1 + version/202/frontend/210_storno.php | 1 + version/202/frontend/75_bestellungInDb.php | 1 + version/202/frontend/applepay.php | 1 + version/202/paymentmethod/JTLMollie.php | 1 + version/202/paymentmethod/JTLMollieApplePay.php | 1 + version/202/paymentmethod/JTLMollieBancontact.php | 1 + version/202/paymentmethod/JTLMollieBanktransfer.php | 1 + version/202/paymentmethod/JTLMollieBelfius.php | 1 + version/202/paymentmethod/JTLMollieCreditCard.php | 1 + version/202/paymentmethod/JTLMollieDirectDebit.php | 1 + version/202/paymentmethod/JTLMollieEPS.php | 1 + version/202/paymentmethod/JTLMollieGiftcard.php | 1 + version/202/paymentmethod/JTLMollieGiropay.php | 1 + version/202/paymentmethod/JTLMollieIDEAL.php | 1 + version/202/paymentmethod/JTLMollieINGHomePay.php | 1 + version/202/paymentmethod/JTLMollieKBC.php | 1 + version/202/paymentmethod/JTLMollieKlarnaPayLater.php | 1 + version/202/paymentmethod/JTLMollieKlarnaSliceIt.php | 1 + version/202/paymentmethod/JTLMollieMyBank.php | 1 + version/202/paymentmethod/JTLMolliePayPal.php | 1 + version/202/paymentmethod/JTLMolliePaysafecard.php | 1 + version/202/paymentmethod/JTLMolliePrzelewy24.php | 1 + version/202/paymentmethod/JTLMollieSofort.php | 1 + version/203/adminmenu/info.php | 1 + version/203/adminmenu/orders.php | 1 + version/203/adminmenu/paymentmethods.php | 1 + version/203/class/API.php | 1 + version/203/class/Checkout/AbstractCheckout.php | 1 + version/203/class/Checkout/AbstractResource.php | 1 + .../203/class/Checkout/Exception/ResourceValidityException.php | 1 + version/203/class/Checkout/Order/Address.php | 1 + version/203/class/Checkout/Order/OrderLine.php | 1 + version/203/class/Checkout/OrderCheckout.php | 1 + version/203/class/Checkout/Payment/Address.php | 1 + version/203/class/Checkout/Payment/Amount.php | 1 + version/203/class/Checkout/PaymentCheckout.php | 1 + version/203/class/ExclusiveLock.php | 1 + version/203/class/Helper.php | 1 + version/203/class/Hook/AbstractHook.php | 1 + version/203/class/Hook/ApplePay.php | 1 + version/203/class/Hook/Checkbox.php | 1 + version/203/class/Hook/Queue.php | 1 + version/203/class/Model/AbstractModel.php | 1 + version/203/class/Model/Customer.php | 1 + version/203/class/Model/Payment.php | 1 + version/203/class/Model/Queue.php | 1 + version/203/class/Model/Shipment.php | 1 + version/203/class/Mollie.php | 1 + version/203/class/Queue.php | 1 + version/203/class/Shipment.php | 1 + version/203/class/Traits/Jsonable.php | 1 + version/203/class/Traits/Plugin.php | 1 + version/203/class/Traits/RequestData.php | 1 + version/203/frontend/131_globalinclude.php | 1 + version/203/frontend/132_headPostGet.php | 1 + version/203/frontend/140_smarty.php | 1 + version/203/frontend/180_checkbox.php | 1 + version/203/frontend/181_sync.php | 1 + version/203/frontend/210_storno.php | 1 + version/203/frontend/75_bestellungInDb.php | 1 + version/203/frontend/applepay.php | 1 + version/203/paymentmethod/JTLMollie.php | 1 + version/203/paymentmethod/JTLMollieApplePay.php | 1 + version/203/paymentmethod/JTLMollieBancontact.php | 1 + version/203/paymentmethod/JTLMollieBanktransfer.php | 1 + version/203/paymentmethod/JTLMollieBelfius.php | 1 + version/203/paymentmethod/JTLMollieCreditCard.php | 1 + version/203/paymentmethod/JTLMollieDirectDebit.php | 1 + version/203/paymentmethod/JTLMollieEPS.php | 1 + version/203/paymentmethod/JTLMollieGiftcard.php | 1 + version/203/paymentmethod/JTLMollieGiropay.php | 1 + version/203/paymentmethod/JTLMollieIDEAL.php | 1 + version/203/paymentmethod/JTLMollieINGHomePay.php | 1 + version/203/paymentmethod/JTLMollieKBC.php | 1 + version/203/paymentmethod/JTLMollieKlarnaPayLater.php | 1 + version/203/paymentmethod/JTLMollieKlarnaSliceIt.php | 1 + version/203/paymentmethod/JTLMollieMyBank.php | 1 + version/203/paymentmethod/JTLMolliePayPal.php | 1 + version/203/paymentmethod/JTLMolliePaysafecard.php | 1 + version/203/paymentmethod/JTLMolliePrzelewy24.php | 1 + version/203/paymentmethod/JTLMollieSofort.php | 1 + version/204/adminmenu/info.php | 1 + version/204/adminmenu/orders.php | 1 + version/204/adminmenu/paymentmethods.php | 1 + version/204/class/API.php | 1 + version/204/class/Checkout/AbstractCheckout.php | 1 + version/204/class/Checkout/AbstractResource.php | 1 + .../204/class/Checkout/Exception/ResourceValidityException.php | 1 + version/204/class/Checkout/Order/Address.php | 1 + version/204/class/Checkout/Order/OrderLine.php | 1 + version/204/class/Checkout/OrderCheckout.php | 1 + version/204/class/Checkout/Payment/Address.php | 1 + version/204/class/Checkout/Payment/Amount.php | 1 + version/204/class/Checkout/PaymentCheckout.php | 1 + version/204/class/ExclusiveLock.php | 1 + version/204/class/Helper.php | 1 + version/204/class/Hook/AbstractHook.php | 1 + version/204/class/Hook/ApplePay.php | 1 + version/204/class/Hook/Checkbox.php | 1 + version/204/class/Hook/Queue.php | 1 + version/204/class/Model/AbstractModel.php | 1 + version/204/class/Model/Customer.php | 1 + version/204/class/Model/Payment.php | 1 + version/204/class/Model/Queue.php | 1 + version/204/class/Model/Shipment.php | 1 + version/204/class/Queue.php | 1 + version/204/class/Shipment.php | 1 + version/204/class/Traits/Jsonable.php | 1 + version/204/class/Traits/Plugin.php | 1 + version/204/class/Traits/RequestData.php | 1 + version/204/frontend/131_globalinclude.php | 1 + version/204/frontend/132_headPostGet.php | 1 + version/204/frontend/140_smarty.php | 1 + version/204/frontend/180_checkbox.php | 1 + version/204/frontend/181_sync.php | 1 + version/204/frontend/210_storno.php | 1 + version/204/frontend/75_bestellungInDb.php | 1 + version/204/frontend/applepay.php | 1 + version/204/paymentmethod/JTLMollie.php | 1 + version/204/paymentmethod/JTLMollieApplePay.php | 1 + version/204/paymentmethod/JTLMollieBancontact.php | 1 + version/204/paymentmethod/JTLMollieBanktransfer.php | 1 + version/204/paymentmethod/JTLMollieBelfius.php | 1 + version/204/paymentmethod/JTLMollieCreditCard.php | 1 + version/204/paymentmethod/JTLMollieEPS.php | 1 + version/204/paymentmethod/JTLMollieGiftcard.php | 1 + version/204/paymentmethod/JTLMollieGiropay.php | 1 + version/204/paymentmethod/JTLMollieIDEAL.php | 1 + version/204/paymentmethod/JTLMollieKBC.php | 1 + version/204/paymentmethod/JTLMollieKlarnaPayLater.php | 1 + version/204/paymentmethod/JTLMollieKlarnaSliceIt.php | 1 + version/204/paymentmethod/JTLMollieMyBank.php | 1 + version/204/paymentmethod/JTLMolliePayPal.php | 1 + version/204/paymentmethod/JTLMolliePaysafecard.php | 1 + version/204/paymentmethod/JTLMolliePrzelewy24.php | 1 + version/204/paymentmethod/JTLMollieSofort.php | 1 + version/205/adminmenu/info.php | 1 + version/205/adminmenu/orders.php | 1 + version/205/adminmenu/paymentmethods.php | 1 + version/205/class/API.php | 1 + version/205/class/Checkout/AbstractCheckout.php | 1 + version/205/class/Checkout/AbstractResource.php | 1 + .../205/class/Checkout/Exception/ResourceValidityException.php | 1 + version/205/class/Checkout/Order/Address.php | 1 + version/205/class/Checkout/Order/OrderLine.php | 1 + version/205/class/Checkout/OrderCheckout.php | 1 + version/205/class/Checkout/Payment/Address.php | 1 + version/205/class/Checkout/Payment/Amount.php | 1 + version/205/class/Checkout/PaymentCheckout.php | 1 + version/205/class/ExclusiveLock.php | 1 + version/205/class/Helper.php | 1 + version/205/class/Hook/AbstractHook.php | 1 + version/205/class/Hook/ApplePay.php | 1 + version/205/class/Hook/Checkbox.php | 1 + version/205/class/Hook/Queue.php | 1 + version/205/class/Model/AbstractModel.php | 1 + version/205/class/Model/Customer.php | 1 + version/205/class/Model/Payment.php | 1 + version/205/class/Model/Queue.php | 1 + version/205/class/Model/Shipment.php | 1 + version/205/class/Queue.php | 1 + version/205/class/Shipment.php | 1 + version/205/class/Traits/Jsonable.php | 1 + version/205/class/Traits/Plugin.php | 1 + version/205/class/Traits/RequestData.php | 1 + version/205/frontend/131_globalinclude.php | 1 + version/205/frontend/132_headPostGet.php | 1 + version/205/frontend/140_smarty.php | 1 + version/205/frontend/180_checkbox.php | 1 + version/205/frontend/181_sync.php | 1 + version/205/frontend/210_storno.php | 1 + version/205/frontend/75_bestellungInDb.php | 1 + version/205/frontend/applepay.php | 1 + version/205/paymentmethod/JTLMollie.php | 1 + version/205/paymentmethod/JTLMollieApplePay.php | 1 + version/205/paymentmethod/JTLMollieBancontact.php | 1 + version/205/paymentmethod/JTLMollieBanktransfer.php | 1 + version/205/paymentmethod/JTLMollieBelfius.php | 1 + version/205/paymentmethod/JTLMollieCreditCard.php | 1 + version/205/paymentmethod/JTLMollieEPS.php | 1 + version/205/paymentmethod/JTLMollieGiftcard.php | 1 + version/205/paymentmethod/JTLMollieGiropay.php | 1 + version/205/paymentmethod/JTLMollieIDEAL.php | 1 + version/205/paymentmethod/JTLMollieKBC.php | 1 + version/205/paymentmethod/JTLMollieKlarnaPayLater.php | 1 + version/205/paymentmethod/JTLMollieKlarnaSliceIt.php | 1 + version/205/paymentmethod/JTLMollieMyBank.php | 1 + version/205/paymentmethod/JTLMolliePayPal.php | 1 + version/205/paymentmethod/JTLMolliePaysafecard.php | 1 + version/205/paymentmethod/JTLMolliePrzelewy24.php | 1 + version/205/paymentmethod/JTLMollieSofort.php | 1 + version/206/adminmenu/info.php | 1 + version/206/adminmenu/orders.php | 1 + version/206/adminmenu/paymentmethods.php | 1 + version/206/class/API.php | 1 + version/206/class/Checkout/AbstractCheckout.php | 1 + version/206/class/Checkout/AbstractResource.php | 1 + .../206/class/Checkout/Exception/ResourceValidityException.php | 1 + version/206/class/Checkout/Order/Address.php | 1 + version/206/class/Checkout/Order/OrderLine.php | 1 + version/206/class/Checkout/OrderCheckout.php | 1 + version/206/class/Checkout/Payment/Address.php | 1 + version/206/class/Checkout/Payment/Amount.php | 1 + version/206/class/Checkout/PaymentCheckout.php | 1 + version/206/class/ExclusiveLock.php | 1 + version/206/class/Helper.php | 1 + version/206/class/Hook/AbstractHook.php | 1 + version/206/class/Hook/ApplePay.php | 1 + version/206/class/Hook/Checkbox.php | 1 + version/206/class/Hook/Queue.php | 1 + version/206/class/Model/AbstractModel.php | 1 + version/206/class/Model/Customer.php | 1 + version/206/class/Model/Payment.php | 1 + version/206/class/Model/Queue.php | 1 + version/206/class/Model/Shipment.php | 1 + version/206/class/Queue.php | 1 + version/206/class/Shipment.php | 1 + version/206/class/Traits/Jsonable.php | 1 + version/206/class/Traits/Plugin.php | 1 + version/206/class/Traits/RequestData.php | 1 + version/206/frontend/131_globalinclude.php | 1 + version/206/frontend/132_headPostGet.php | 1 + version/206/frontend/140_smarty.php | 1 + version/206/frontend/180_checkbox.php | 1 + version/206/frontend/181_sync.php | 1 + version/206/frontend/210_storno.php | 1 + version/206/frontend/75_bestellungInDb.php | 1 + version/206/frontend/applepay.php | 1 + version/206/paymentmethod/JTLMollie.php | 1 + version/206/paymentmethod/JTLMollieApplePay.php | 1 + version/206/paymentmethod/JTLMollieBancontact.php | 1 + version/206/paymentmethod/JTLMollieBanktransfer.php | 1 + version/206/paymentmethod/JTLMollieBelfius.php | 1 + version/206/paymentmethod/JTLMollieCreditCard.php | 1 + version/206/paymentmethod/JTLMollieEPS.php | 1 + version/206/paymentmethod/JTLMollieGiftcard.php | 1 + version/206/paymentmethod/JTLMollieGiropay.php | 1 + version/206/paymentmethod/JTLMollieIDEAL.php | 1 + version/206/paymentmethod/JTLMollieKBC.php | 1 + version/206/paymentmethod/JTLMollieKlarnaPayLater.php | 1 + version/206/paymentmethod/JTLMollieKlarnaSliceIt.php | 1 + version/206/paymentmethod/JTLMollieMyBank.php | 1 + version/206/paymentmethod/JTLMolliePayPal.php | 1 + version/206/paymentmethod/JTLMolliePaysafecard.php | 1 + version/206/paymentmethod/JTLMolliePrzelewy24.php | 1 + version/206/paymentmethod/JTLMollieSofort.php | 1 + 554 files changed, 554 insertions(+) diff --git a/version/100/adminmenu/info.php b/version/100/adminmenu/info.php index bd4a321..f6e4e4a 100644 --- a/version/100/adminmenu/info.php +++ b/version/100/adminmenu/info.php @@ -1,4 +1,5 @@ Date: Tue, 11 Jan 2022 09:55:32 +0100 Subject: [PATCH 275/280] fix #154 --- composer.json | 2 +- info.xml | 7 +++++++ version/206/class/Hook/ApplePay.php | 10 ++++++++-- version/206/frontend/js/applePay.js | 22 ++++++++++++++++++++++ version/206/frontend/tpl/applepay.tpl | 2 -- 5 files changed, 38 insertions(+), 5 deletions(-) create mode 100644 version/206/frontend/js/applePay.js diff --git a/composer.json b/composer.json index 91b7605..ce26ce2 100644 --- a/composer.json +++ b/composer.json @@ -5,7 +5,7 @@ "scripts": { "phpcbf": "phpcbf --standard=PSR12 --encoding=utf8 -p ./version", "php-cs-fixer": "php-cs-fixer fix", - "fix": "phpcbf --standard=PSR12 --encoding=utf8 -p ./version; php-cs-fixer fix" + "fix": "php-cs-fixer fix; phpcbf --standard=PSR12 --encoding=utf8 -p ./version" }, "require": { "ext-json": "*", diff --git a/info.xml b/info.xml index 853d918..ab9cadf 100644 --- a/info.xml +++ b/info.xml @@ -60,6 +60,13 @@ 181_sync.php 210_storno.php
+ + + applePay.js + 5 + body + + Bestellungen diff --git a/version/206/class/Hook/ApplePay.php b/version/206/class/Hook/ApplePay.php index cfd7124..7820d91 100644 --- a/version/206/class/Hook/ApplePay.php +++ b/version/206/class/Hook/ApplePay.php @@ -31,8 +31,14 @@ public static function execute($args_arr = []) } if (!array_key_exists('ws_mollie_applepay_available', $_SESSION)) { - Shop::Smarty()->assign('applePayCheckURL', json_encode(self::Plugin()->cFrontendPfadURLSSL . 'applepay.php')); - pq('body')->append(Shop::Smarty()->fetch(self::Plugin()->cFrontendPfad . 'tpl/applepay.tpl')); + // TODO DOKU + if (defined('MOLLIE_APPLEPAY_TPL') && MOLLIE_APPLEPAY_TPL) { + Shop::Smarty()->assign('applePayCheckURL', json_encode(self::Plugin()->cFrontendPfadURLSSL . 'applepay.php')); + pq('body')->append(Shop::Smarty()->fetch(self::Plugin()->cFrontendPfad . 'tpl/applepay.tpl')); + } else { + $checkUrl = self::Plugin()->cFrontendPfadURLSSL . 'applepay.php'; + pq('head')->append(""); + } } } diff --git a/version/206/frontend/js/applePay.js b/version/206/frontend/js/applePay.js new file mode 100644 index 0000000..89701f8 --- /dev/null +++ b/version/206/frontend/js/applePay.js @@ -0,0 +1,22 @@ +// diff --git a/version/206/frontend/tpl/applepay.tpl b/version/206/frontend/tpl/applepay.tpl index cfd359b..57c2e75 100644 --- a/version/206/frontend/tpl/applepay.tpl +++ b/version/206/frontend/tpl/applepay.tpl @@ -14,8 +14,6 @@ } setApplePayStatus(window.ApplePaySession && window.ApplePaySession.canMakePayments() ? 1 : 0); }); - } else if (window.console) { - console.warn('jQuery not loaded as yet, ApplePay not available!'); } // --> From f18cb5c44181a38de780b8cc6922507e0d60f1a1 Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Tue, 11 Jan 2022 09:59:57 +0100 Subject: [PATCH 276/280] set create date --- info.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/info.xml b/info.xml index ab9cadf..3243f1f 100644 --- a/info.xml +++ b/info.xml @@ -49,7 +49,7 @@ 205.sql - 2022-01-10 + 2022-01-11 75_bestellungInDb.php From b83d11cd91ddf65df9e35504adb93c2ac7c2a46b Mon Sep 17 00:00:00 2001 From: Christian Proske Date: Wed, 19 Jan 2022 10:13:16 +0100 Subject: [PATCH 277/280] fix PHP 7 compatibility --- version/206/class/Queue.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version/206/class/Queue.php b/version/206/class/Queue.php index 116becd..7d6d766 100644 --- a/version/206/class/Queue.php +++ b/version/206/class/Queue.php @@ -78,7 +78,7 @@ public static function run($limit = 10) continue; } - if (([$type, $id] = explode(':', $todo->cType))) { + if ((list($type, $id) = explode(':', $todo->cType))) { try { switch ($type) { case 'webhook': From 05636bc85934c985fbd4188e6834e5769c7ca3ff Mon Sep 17 00:00:00 2001 From: Florian Klamer Date: Fri, 10 Jun 2022 10:44:11 +0200 Subject: [PATCH 278/280] init 207 --- version/207/adminmenu/info.php | 0 version/207/adminmenu/orders.php | 0 version/207/adminmenu/paymentmethods.php | 0 version/207/adminmenu/tpl/_addon.tpl | 0 version/207/adminmenu/tpl/info.tpl | 0 version/207/adminmenu/tpl/mollie-account-erstellen.png | 0 version/207/adminmenu/tpl/order.tpl | 0 version/207/adminmenu/tpl/orders.tpl | 0 version/207/adminmenu/tpl/paymentmethods.tpl | 0 version/207/class/Checkout/AbstractCheckout.php | 0 version/207/class/Checkout/AbstractResource.php | 0 version/207/class/Checkout/PaymentCheckout.php | 0 version/207/class/ExclusiveLock.php | 0 version/207/class/Helper.php | 0 version/207/class/Queue.php | 0 version/207/class/Shipment.php | 0 version/207/frontend/.htaccess | 0 version/207/frontend/131_globalinclude.php | 0 version/207/frontend/132_headPostGet.php | 0 version/207/frontend/140_smarty.php | 0 version/207/frontend/180_checkbox.php | 0 version/207/frontend/181_sync.php | 0 version/207/frontend/210_storno.php | 0 version/207/frontend/75_bestellungInDb.php | 0 version/207/frontend/applepay.php | 0 version/207/frontend/img/trust_eng.png | 0 version/207/frontend/img/trust_fre.png | 0 version/207/frontend/img/trust_ger.png | 0 version/207/frontend/js/applePay.js | 0 version/207/frontend/tpl/applepay.tpl | 0 version/207/paymentmethod/JTLMollie.php | 0 version/207/paymentmethod/JTLMollieApplePay.php | 0 version/207/paymentmethod/JTLMollieBanktransfer.php | 0 version/207/paymentmethod/JTLMollieBelfius.php | 0 version/207/paymentmethod/JTLMollieCreditCard.php | 0 version/207/paymentmethod/JTLMollieEPS.php | 0 version/207/paymentmethod/JTLMollieGiftcard.php | 0 version/207/paymentmethod/JTLMollieGiropay.php | 0 version/207/paymentmethod/JTLMollieIDEAL.php | 0 version/207/paymentmethod/JTLMollieKBC.php | 0 version/207/paymentmethod/JTLMollieKlarnaPayLater.php | 0 version/207/paymentmethod/JTLMollieKlarnaSliceIt.php | 0 version/207/paymentmethod/JTLMollieMyBank.php | 0 version/207/paymentmethod/JTLMolliePayPal.php | 0 version/207/paymentmethod/JTLMolliePaysafecard.php | 0 version/207/paymentmethod/JTLMolliePrzelewy24.php | 0 version/207/paymentmethod/JTLMollieSofort.php | 0 version/207/paymentmethod/img/method/Przelewy24@2x.png | 0 version/207/paymentmethod/img/method/applepay@2x.png | 0 version/207/paymentmethod/img/method/bancontact@2x.png | 0 version/207/paymentmethod/img/method/banktransfer@2x.png | 0 version/207/paymentmethod/img/method/belfius@2x.png | 0 version/207/paymentmethod/img/method/creditcard@2x.png | 0 version/207/paymentmethod/img/method/directdebit@2x.png | 0 version/207/paymentmethod/img/method/eps@2x.png | 0 version/207/paymentmethod/img/method/giftcard@2x.png | 0 version/207/paymentmethod/img/method/giropay@2x.png | 0 version/207/paymentmethod/img/method/ideal@2x.png | 0 version/207/paymentmethod/img/method/inghomepay@2x.png | 0 version/207/paymentmethod/img/method/kbc@2x.png | 0 version/207/paymentmethod/img/method/klarna@2x.png | 0 version/207/paymentmethod/img/method/mollie@2x.png | 0 version/207/paymentmethod/img/method/mybank@2x.png | 0 version/207/paymentmethod/img/method/paypal@2x.png | 0 version/207/paymentmethod/img/method/paysafecard@2x.png | 0 version/207/paymentmethod/img/method/sofort@2x.png | 0 version/207/paymentmethod/tpl/bestellabschluss.tpl | 0 version/207/paymentmethod/tpl/mollieComponents.tpl | 0 68 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 version/207/adminmenu/info.php create mode 100644 version/207/adminmenu/orders.php create mode 100644 version/207/adminmenu/paymentmethods.php create mode 100644 version/207/adminmenu/tpl/_addon.tpl create mode 100644 version/207/adminmenu/tpl/info.tpl create mode 100644 version/207/adminmenu/tpl/mollie-account-erstellen.png create mode 100644 version/207/adminmenu/tpl/order.tpl create mode 100644 version/207/adminmenu/tpl/orders.tpl create mode 100644 version/207/adminmenu/tpl/paymentmethods.tpl create mode 100644 version/207/class/Checkout/AbstractCheckout.php create mode 100644 version/207/class/Checkout/AbstractResource.php create mode 100644 version/207/class/Checkout/PaymentCheckout.php create mode 100644 version/207/class/ExclusiveLock.php create mode 100644 version/207/class/Helper.php create mode 100644 version/207/class/Queue.php create mode 100644 version/207/class/Shipment.php create mode 100644 version/207/frontend/.htaccess create mode 100644 version/207/frontend/131_globalinclude.php create mode 100644 version/207/frontend/132_headPostGet.php create mode 100644 version/207/frontend/140_smarty.php create mode 100644 version/207/frontend/180_checkbox.php create mode 100644 version/207/frontend/181_sync.php create mode 100644 version/207/frontend/210_storno.php create mode 100644 version/207/frontend/75_bestellungInDb.php create mode 100644 version/207/frontend/applepay.php create mode 100644 version/207/frontend/img/trust_eng.png create mode 100644 version/207/frontend/img/trust_fre.png create mode 100644 version/207/frontend/img/trust_ger.png create mode 100644 version/207/frontend/js/applePay.js create mode 100644 version/207/frontend/tpl/applepay.tpl create mode 100644 version/207/paymentmethod/JTLMollie.php create mode 100644 version/207/paymentmethod/JTLMollieApplePay.php create mode 100644 version/207/paymentmethod/JTLMollieBanktransfer.php create mode 100644 version/207/paymentmethod/JTLMollieBelfius.php create mode 100644 version/207/paymentmethod/JTLMollieCreditCard.php create mode 100644 version/207/paymentmethod/JTLMollieEPS.php create mode 100644 version/207/paymentmethod/JTLMollieGiftcard.php create mode 100644 version/207/paymentmethod/JTLMollieGiropay.php create mode 100644 version/207/paymentmethod/JTLMollieIDEAL.php create mode 100644 version/207/paymentmethod/JTLMollieKBC.php create mode 100644 version/207/paymentmethod/JTLMollieKlarnaPayLater.php create mode 100644 version/207/paymentmethod/JTLMollieKlarnaSliceIt.php create mode 100644 version/207/paymentmethod/JTLMollieMyBank.php create mode 100644 version/207/paymentmethod/JTLMolliePayPal.php create mode 100644 version/207/paymentmethod/JTLMolliePaysafecard.php create mode 100644 version/207/paymentmethod/JTLMolliePrzelewy24.php create mode 100644 version/207/paymentmethod/JTLMollieSofort.php create mode 100644 version/207/paymentmethod/img/method/Przelewy24@2x.png create mode 100644 version/207/paymentmethod/img/method/applepay@2x.png create mode 100644 version/207/paymentmethod/img/method/bancontact@2x.png create mode 100644 version/207/paymentmethod/img/method/banktransfer@2x.png create mode 100644 version/207/paymentmethod/img/method/belfius@2x.png create mode 100644 version/207/paymentmethod/img/method/creditcard@2x.png create mode 100644 version/207/paymentmethod/img/method/directdebit@2x.png create mode 100644 version/207/paymentmethod/img/method/eps@2x.png create mode 100644 version/207/paymentmethod/img/method/giftcard@2x.png create mode 100644 version/207/paymentmethod/img/method/giropay@2x.png create mode 100644 version/207/paymentmethod/img/method/ideal@2x.png create mode 100644 version/207/paymentmethod/img/method/inghomepay@2x.png create mode 100644 version/207/paymentmethod/img/method/kbc@2x.png create mode 100644 version/207/paymentmethod/img/method/klarna@2x.png create mode 100644 version/207/paymentmethod/img/method/mollie@2x.png create mode 100644 version/207/paymentmethod/img/method/mybank@2x.png create mode 100644 version/207/paymentmethod/img/method/paypal@2x.png create mode 100644 version/207/paymentmethod/img/method/paysafecard@2x.png create mode 100644 version/207/paymentmethod/img/method/sofort@2x.png create mode 100644 version/207/paymentmethod/tpl/bestellabschluss.tpl create mode 100644 version/207/paymentmethod/tpl/mollieComponents.tpl diff --git a/version/207/adminmenu/info.php b/version/207/adminmenu/info.php new file mode 100644 index 0000000..e69de29 diff --git a/version/207/adminmenu/orders.php b/version/207/adminmenu/orders.php new file mode 100644 index 0000000..e69de29 diff --git a/version/207/adminmenu/paymentmethods.php b/version/207/adminmenu/paymentmethods.php new file mode 100644 index 0000000..e69de29 diff --git a/version/207/adminmenu/tpl/_addon.tpl b/version/207/adminmenu/tpl/_addon.tpl new file mode 100644 index 0000000..e69de29 diff --git a/version/207/adminmenu/tpl/info.tpl b/version/207/adminmenu/tpl/info.tpl new file mode 100644 index 0000000..e69de29 diff --git a/version/207/adminmenu/tpl/mollie-account-erstellen.png b/version/207/adminmenu/tpl/mollie-account-erstellen.png new file mode 100644 index 0000000..e69de29 diff --git a/version/207/adminmenu/tpl/order.tpl b/version/207/adminmenu/tpl/order.tpl new file mode 100644 index 0000000..e69de29 diff --git a/version/207/adminmenu/tpl/orders.tpl b/version/207/adminmenu/tpl/orders.tpl new file mode 100644 index 0000000..e69de29 diff --git a/version/207/adminmenu/tpl/paymentmethods.tpl b/version/207/adminmenu/tpl/paymentmethods.tpl new file mode 100644 index 0000000..e69de29 diff --git a/version/207/class/Checkout/AbstractCheckout.php b/version/207/class/Checkout/AbstractCheckout.php new file mode 100644 index 0000000..e69de29 diff --git a/version/207/class/Checkout/AbstractResource.php b/version/207/class/Checkout/AbstractResource.php new file mode 100644 index 0000000..e69de29 diff --git a/version/207/class/Checkout/PaymentCheckout.php b/version/207/class/Checkout/PaymentCheckout.php new file mode 100644 index 0000000..e69de29 diff --git a/version/207/class/ExclusiveLock.php b/version/207/class/ExclusiveLock.php new file mode 100644 index 0000000..e69de29 diff --git a/version/207/class/Helper.php b/version/207/class/Helper.php new file mode 100644 index 0000000..e69de29 diff --git a/version/207/class/Queue.php b/version/207/class/Queue.php new file mode 100644 index 0000000..e69de29 diff --git a/version/207/class/Shipment.php b/version/207/class/Shipment.php new file mode 100644 index 0000000..e69de29 diff --git a/version/207/frontend/.htaccess b/version/207/frontend/.htaccess new file mode 100644 index 0000000..e69de29 diff --git a/version/207/frontend/131_globalinclude.php b/version/207/frontend/131_globalinclude.php new file mode 100644 index 0000000..e69de29 diff --git a/version/207/frontend/132_headPostGet.php b/version/207/frontend/132_headPostGet.php new file mode 100644 index 0000000..e69de29 diff --git a/version/207/frontend/140_smarty.php b/version/207/frontend/140_smarty.php new file mode 100644 index 0000000..e69de29 diff --git a/version/207/frontend/180_checkbox.php b/version/207/frontend/180_checkbox.php new file mode 100644 index 0000000..e69de29 diff --git a/version/207/frontend/181_sync.php b/version/207/frontend/181_sync.php new file mode 100644 index 0000000..e69de29 diff --git a/version/207/frontend/210_storno.php b/version/207/frontend/210_storno.php new file mode 100644 index 0000000..e69de29 diff --git a/version/207/frontend/75_bestellungInDb.php b/version/207/frontend/75_bestellungInDb.php new file mode 100644 index 0000000..e69de29 diff --git a/version/207/frontend/applepay.php b/version/207/frontend/applepay.php new file mode 100644 index 0000000..e69de29 diff --git a/version/207/frontend/img/trust_eng.png b/version/207/frontend/img/trust_eng.png new file mode 100644 index 0000000..e69de29 diff --git a/version/207/frontend/img/trust_fre.png b/version/207/frontend/img/trust_fre.png new file mode 100644 index 0000000..e69de29 diff --git a/version/207/frontend/img/trust_ger.png b/version/207/frontend/img/trust_ger.png new file mode 100644 index 0000000..e69de29 diff --git a/version/207/frontend/js/applePay.js b/version/207/frontend/js/applePay.js new file mode 100644 index 0000000..e69de29 diff --git a/version/207/frontend/tpl/applepay.tpl b/version/207/frontend/tpl/applepay.tpl new file mode 100644 index 0000000..e69de29 diff --git a/version/207/paymentmethod/JTLMollie.php b/version/207/paymentmethod/JTLMollie.php new file mode 100644 index 0000000..e69de29 diff --git a/version/207/paymentmethod/JTLMollieApplePay.php b/version/207/paymentmethod/JTLMollieApplePay.php new file mode 100644 index 0000000..e69de29 diff --git a/version/207/paymentmethod/JTLMollieBanktransfer.php b/version/207/paymentmethod/JTLMollieBanktransfer.php new file mode 100644 index 0000000..e69de29 diff --git a/version/207/paymentmethod/JTLMollieBelfius.php b/version/207/paymentmethod/JTLMollieBelfius.php new file mode 100644 index 0000000..e69de29 diff --git a/version/207/paymentmethod/JTLMollieCreditCard.php b/version/207/paymentmethod/JTLMollieCreditCard.php new file mode 100644 index 0000000..e69de29 diff --git a/version/207/paymentmethod/JTLMollieEPS.php b/version/207/paymentmethod/JTLMollieEPS.php new file mode 100644 index 0000000..e69de29 diff --git a/version/207/paymentmethod/JTLMollieGiftcard.php b/version/207/paymentmethod/JTLMollieGiftcard.php new file mode 100644 index 0000000..e69de29 diff --git a/version/207/paymentmethod/JTLMollieGiropay.php b/version/207/paymentmethod/JTLMollieGiropay.php new file mode 100644 index 0000000..e69de29 diff --git a/version/207/paymentmethod/JTLMollieIDEAL.php b/version/207/paymentmethod/JTLMollieIDEAL.php new file mode 100644 index 0000000..e69de29 diff --git a/version/207/paymentmethod/JTLMollieKBC.php b/version/207/paymentmethod/JTLMollieKBC.php new file mode 100644 index 0000000..e69de29 diff --git a/version/207/paymentmethod/JTLMollieKlarnaPayLater.php b/version/207/paymentmethod/JTLMollieKlarnaPayLater.php new file mode 100644 index 0000000..e69de29 diff --git a/version/207/paymentmethod/JTLMollieKlarnaSliceIt.php b/version/207/paymentmethod/JTLMollieKlarnaSliceIt.php new file mode 100644 index 0000000..e69de29 diff --git a/version/207/paymentmethod/JTLMollieMyBank.php b/version/207/paymentmethod/JTLMollieMyBank.php new file mode 100644 index 0000000..e69de29 diff --git a/version/207/paymentmethod/JTLMolliePayPal.php b/version/207/paymentmethod/JTLMolliePayPal.php new file mode 100644 index 0000000..e69de29 diff --git a/version/207/paymentmethod/JTLMolliePaysafecard.php b/version/207/paymentmethod/JTLMolliePaysafecard.php new file mode 100644 index 0000000..e69de29 diff --git a/version/207/paymentmethod/JTLMolliePrzelewy24.php b/version/207/paymentmethod/JTLMolliePrzelewy24.php new file mode 100644 index 0000000..e69de29 diff --git a/version/207/paymentmethod/JTLMollieSofort.php b/version/207/paymentmethod/JTLMollieSofort.php new file mode 100644 index 0000000..e69de29 diff --git a/version/207/paymentmethod/img/method/Przelewy24@2x.png b/version/207/paymentmethod/img/method/Przelewy24@2x.png new file mode 100644 index 0000000..e69de29 diff --git a/version/207/paymentmethod/img/method/applepay@2x.png b/version/207/paymentmethod/img/method/applepay@2x.png new file mode 100644 index 0000000..e69de29 diff --git a/version/207/paymentmethod/img/method/bancontact@2x.png b/version/207/paymentmethod/img/method/bancontact@2x.png new file mode 100644 index 0000000..e69de29 diff --git a/version/207/paymentmethod/img/method/banktransfer@2x.png b/version/207/paymentmethod/img/method/banktransfer@2x.png new file mode 100644 index 0000000..e69de29 diff --git a/version/207/paymentmethod/img/method/belfius@2x.png b/version/207/paymentmethod/img/method/belfius@2x.png new file mode 100644 index 0000000..e69de29 diff --git a/version/207/paymentmethod/img/method/creditcard@2x.png b/version/207/paymentmethod/img/method/creditcard@2x.png new file mode 100644 index 0000000..e69de29 diff --git a/version/207/paymentmethod/img/method/directdebit@2x.png b/version/207/paymentmethod/img/method/directdebit@2x.png new file mode 100644 index 0000000..e69de29 diff --git a/version/207/paymentmethod/img/method/eps@2x.png b/version/207/paymentmethod/img/method/eps@2x.png new file mode 100644 index 0000000..e69de29 diff --git a/version/207/paymentmethod/img/method/giftcard@2x.png b/version/207/paymentmethod/img/method/giftcard@2x.png new file mode 100644 index 0000000..e69de29 diff --git a/version/207/paymentmethod/img/method/giropay@2x.png b/version/207/paymentmethod/img/method/giropay@2x.png new file mode 100644 index 0000000..e69de29 diff --git a/version/207/paymentmethod/img/method/ideal@2x.png b/version/207/paymentmethod/img/method/ideal@2x.png new file mode 100644 index 0000000..e69de29 diff --git a/version/207/paymentmethod/img/method/inghomepay@2x.png b/version/207/paymentmethod/img/method/inghomepay@2x.png new file mode 100644 index 0000000..e69de29 diff --git a/version/207/paymentmethod/img/method/kbc@2x.png b/version/207/paymentmethod/img/method/kbc@2x.png new file mode 100644 index 0000000..e69de29 diff --git a/version/207/paymentmethod/img/method/klarna@2x.png b/version/207/paymentmethod/img/method/klarna@2x.png new file mode 100644 index 0000000..e69de29 diff --git a/version/207/paymentmethod/img/method/mollie@2x.png b/version/207/paymentmethod/img/method/mollie@2x.png new file mode 100644 index 0000000..e69de29 diff --git a/version/207/paymentmethod/img/method/mybank@2x.png b/version/207/paymentmethod/img/method/mybank@2x.png new file mode 100644 index 0000000..e69de29 diff --git a/version/207/paymentmethod/img/method/paypal@2x.png b/version/207/paymentmethod/img/method/paypal@2x.png new file mode 100644 index 0000000..e69de29 diff --git a/version/207/paymentmethod/img/method/paysafecard@2x.png b/version/207/paymentmethod/img/method/paysafecard@2x.png new file mode 100644 index 0000000..e69de29 diff --git a/version/207/paymentmethod/img/method/sofort@2x.png b/version/207/paymentmethod/img/method/sofort@2x.png new file mode 100644 index 0000000..e69de29 diff --git a/version/207/paymentmethod/tpl/bestellabschluss.tpl b/version/207/paymentmethod/tpl/bestellabschluss.tpl new file mode 100644 index 0000000..e69de29 diff --git a/version/207/paymentmethod/tpl/mollieComponents.tpl b/version/207/paymentmethod/tpl/mollieComponents.tpl new file mode 100644 index 0000000..e69de29 From 8144be484140739977d01160caefbabeeb67562d Mon Sep 17 00:00:00 2001 From: Florian Klamer Date: Fri, 10 Jun 2022 10:45:22 +0200 Subject: [PATCH 279/280] init 207 --- info.xml | 3 + version/207/adminmenu/info.php | 68 + version/207/adminmenu/orders.php | 245 ++++ version/207/adminmenu/paymentmethods.php | 103 ++ version/207/adminmenu/tpl/_addon.tpl | 6 + version/207/adminmenu/tpl/info.tpl | 114 ++ .../tpl/mollie-account-erstellen.png | Bin 0 -> 38998 bytes version/207/adminmenu/tpl/order.tpl | 344 +++++ version/207/adminmenu/tpl/orders.tpl | 160 +++ version/207/adminmenu/tpl/paymentmethods.tpl | 148 ++ version/207/class/API.php | 77 ++ .../207/class/Checkout/AbstractCheckout.php | 1214 +++++++++++++++++ .../207/class/Checkout/AbstractResource.php | 18 + .../Exception/ResourceValidityException.php | 27 + version/207/class/Checkout/Order/Address.php | 48 + .../207/class/Checkout/Order/OrderLine.php | 237 ++++ version/207/class/Checkout/OrderCheckout.php | 406 ++++++ .../207/class/Checkout/Payment/Address.php | 53 + version/207/class/Checkout/Payment/Amount.php | 75 + .../207/class/Checkout/PaymentCheckout.php | 235 ++++ version/207/class/ExclusiveLock.php | 70 + version/207/class/Helper.php | 363 +++++ version/207/class/Hook/AbstractHook.php | 15 + version/207/class/Hook/ApplePay.php | 64 + version/207/class/Hook/Checkbox.php | 60 + version/207/class/Hook/Queue.php | 140 ++ version/207/class/Model/AbstractModel.php | 110 ++ version/207/class/Model/Customer.php | 21 + version/207/class/Model/Payment.php | 53 + version/207/class/Model/Queue.php | 46 + version/207/class/Model/Shipment.php | 29 + version/207/class/Queue.php | 251 ++++ version/207/class/Shipment.php | 325 +++++ version/207/class/Traits/Jsonable.php | 23 + version/207/class/Traits/Plugin.php | 30 + version/207/class/Traits/RequestData.php | 65 + version/207/frontend/.htaccess | 9 + version/207/frontend/131_globalinclude.php | 61 + version/207/frontend/132_headPostGet.php | 20 + version/207/frontend/140_smarty.php | 64 + version/207/frontend/180_checkbox.php | 21 + version/207/frontend/181_sync.php | 18 + version/207/frontend/210_storno.php | 20 + version/207/frontend/75_bestellungInDb.php | 20 + version/207/frontend/applepay.php | 23 + version/207/frontend/img/trust_eng.png | Bin 0 -> 15299 bytes version/207/frontend/img/trust_fre.png | Bin 0 -> 17319 bytes version/207/frontend/img/trust_ger.png | Bin 0 -> 15352 bytes version/207/frontend/js/applePay.js | 22 + version/207/frontend/tpl/applepay.tpl | 19 + version/207/paymentmethod/JTLMollie.php | 306 +++++ .../207/paymentmethod/JTLMollieApplePay.php | 20 + .../207/paymentmethod/JTLMollieBancontact.php | 17 + .../paymentmethod/JTLMollieBanktransfer.php | 34 + .../207/paymentmethod/JTLMollieBelfius.php | 17 + .../207/paymentmethod/JTLMollieCreditCard.php | 116 ++ version/207/paymentmethod/JTLMollieEPS.php | 17 + .../207/paymentmethod/JTLMollieGiftcard.php | 32 + .../207/paymentmethod/JTLMollieGiropay.php | 18 + version/207/paymentmethod/JTLMollieIDEAL.php | 18 + version/207/paymentmethod/JTLMollieKBC.php | 23 + .../paymentmethod/JTLMollieKlarnaPayLater.php | 24 + .../paymentmethod/JTLMollieKlarnaSliceIt.php | 24 + version/207/paymentmethod/JTLMollieMyBank.php | 18 + version/207/paymentmethod/JTLMolliePayPal.php | 42 + .../paymentmethod/JTLMolliePaysafecard.php | 23 + .../207/paymentmethod/JTLMolliePrzelewy24.php | 23 + version/207/paymentmethod/JTLMollieSofort.php | 18 + .../img/method/Przelewy24@2x.png | Bin 0 -> 859 bytes .../paymentmethod/img/method/applepay@2x.png | Bin 0 -> 656 bytes .../img/method/bancontact@2x.png | Bin 0 -> 582 bytes .../img/method/banktransfer@2x.png | Bin 0 -> 801 bytes .../paymentmethod/img/method/belfius@2x.png | Bin 0 -> 377 bytes .../img/method/creditcard@2x.png | Bin 0 -> 3125 bytes .../img/method/directdebit@2x.png | Bin 0 -> 801 bytes .../207/paymentmethod/img/method/eps@2x.png | Bin 0 -> 536 bytes .../paymentmethod/img/method/giftcard@2x.png | Bin 0 -> 2218 bytes .../paymentmethod/img/method/giropay@2x.png | Bin 0 -> 602 bytes .../207/paymentmethod/img/method/ideal@2x.png | Bin 0 -> 845 bytes .../img/method/inghomepay@2x.png | Bin 0 -> 1118 bytes .../207/paymentmethod/img/method/kbc@2x.png | Bin 0 -> 799 bytes .../paymentmethod/img/method/klarna@2x.png | Bin 0 -> 896 bytes .../paymentmethod/img/method/mollie@2x.png | Bin 0 -> 5366 bytes .../paymentmethod/img/method/mybank@2x.png | Bin 0 -> 2111 bytes .../paymentmethod/img/method/paypal@2x.png | Bin 0 -> 626 bytes .../img/method/paysafecard@2x.png | Bin 0 -> 420 bytes .../paymentmethod/img/method/sofort@2x.png | Bin 0 -> 502 bytes .../paymentmethod/tpl/bestellabschluss.tpl | 26 + .../paymentmethod/tpl/mollieComponents.tpl | 148 ++ version/207/tpl/_alerts.tpl | 10 + 90 files changed, 6517 insertions(+) create mode 100644 version/207/class/API.php create mode 100644 version/207/class/Checkout/Exception/ResourceValidityException.php create mode 100644 version/207/class/Checkout/Order/Address.php create mode 100644 version/207/class/Checkout/Order/OrderLine.php create mode 100644 version/207/class/Checkout/OrderCheckout.php create mode 100644 version/207/class/Checkout/Payment/Address.php create mode 100644 version/207/class/Checkout/Payment/Amount.php create mode 100644 version/207/class/Hook/AbstractHook.php create mode 100644 version/207/class/Hook/ApplePay.php create mode 100644 version/207/class/Hook/Checkbox.php create mode 100644 version/207/class/Hook/Queue.php create mode 100644 version/207/class/Model/AbstractModel.php create mode 100644 version/207/class/Model/Customer.php create mode 100644 version/207/class/Model/Payment.php create mode 100644 version/207/class/Model/Queue.php create mode 100644 version/207/class/Model/Shipment.php create mode 100644 version/207/class/Traits/Jsonable.php create mode 100644 version/207/class/Traits/Plugin.php create mode 100644 version/207/class/Traits/RequestData.php create mode 100644 version/207/paymentmethod/JTLMollieBancontact.php create mode 100644 version/207/tpl/_alerts.tpl diff --git a/info.xml b/info.xml index 3243f1f..59ca7b3 100644 --- a/info.xml +++ b/info.xml @@ -51,6 +51,9 @@ 2022-01-11 + + 2022-06-10 + 75_bestellungInDb.php 131_globalinclude.php diff --git a/version/207/adminmenu/info.php b/version/207/adminmenu/info.php index e69de29..4ef2525 100644 --- a/version/207/adminmenu/info.php +++ b/version/207/adminmenu/info.php @@ -0,0 +1,68 @@ +assign('defaultTabbertab', Helper::getAdminmenu('Info') + Helper::getAdminmenu('Support')); + 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 "
" . + "
" . + " " . + " Lizenz Informationen" . + ' ' . + '
' . + "
" . + " " . + " Update Informationen" . + ' ' . + '
' . + "
" . + " " . + " Plugin informationen" . + ' ' . + '
' . + '
'; + + 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); +} diff --git a/version/207/adminmenu/orders.php b/version/207/adminmenu/orders.php index e69de29..68197ed 100644 --- a/version/207/adminmenu/orders.php +++ b/version/207/adminmenu/orders.php @@ -0,0 +1,245 @@ +getModel()->kID)) { + Helper::addAlert('Zahlungserinnerung wurde verschickt.', 'success', 'orders'); + } else { + Helper::addAlert('Es ist ein Fehler aufgetreten, prüfe den Log.', 'danger', 'orders'); + } + } else { + Helper::addAlert('Bestellung konnte nicht geladen werden.', 'danger', 'orders'); + } + + + break; + + case 'fetchable': + if (array_key_exists('kBestellung', $_REQUEST) && ($checkout = AbstractCheckout::fromBestellung((int)$_REQUEST['kBestellung']))) { + if (AbstractCheckout::makeFetchable($checkout->getBestellung(), $checkout->getModel())) { + Helper::addAlert('Bestellung kann jetzt von der WAWI abgeholt werden.', 'success', 'orders'); + } else { + Helper::addAlert('Es ist ein Fehler aufgetreten, prüfe den Log.', 'danger', 'orders'); + } + } else { + Helper::addAlert('Bestellung konnte nicht geladen werden.', 'danger', 'orders'); + } + + break; + + 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); + + + 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', 'wb'); + + + fputcsv($out, [ + 'kBestellung', + 'OrderID', + 'Status (mollie)', + 'BestellNr', + 'Status (JTL)', + 'Mode', + 'OriginalOrderNumber', + 'Currency', + 'Amount', + 'Method', + 'PaymentID', + 'Created' + ]); + + + foreach ($orders as $order) { + $order = new ws_mollie\Model\Payment($order); + $checkout = AbstractCheckout::fromModel($order); + + $tmp = [ + 'kBestellung' => $order->kBestellung, + 'cOrderId' => $order->kID, + 'cStatus' => $checkout->getMollie() ? $checkout->getMollie()->status : $order->cStatus, + 'cBestellNr' => $checkout->getBestellung() ? $checkout->getBestellung()->cBestellNr : $order->cOrderNumber, + 'nStatus' => $checkout->getBestellung() ? $checkout->getBestellung()->cStatus : 0, + 'cMode' => $order->cMode, + 'cOriginalOrderNumber' => $checkout->getMollie() && isset($checkout->getMollie()->metadata->originalOrderNumber) ? $checkout->getMollie()->metadata->originalOrderNumber : '', + 'cCurrency' => $order->cCurrency, + 'fAmount' => $order->fAmount, + 'cMethod' => $order->cMethod, + 'cPaymentId' => $order->cTransactionId, + 'dCreated' => $order->dCreatedAt, + ]; + + try { + if ($checkout->getMollie() && $checkout->getMollie()->resource === 'order') { + foreach ($checkout->getMollie()->payments() as $payment) { + if ($payment->status === 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': + try { + if (!array_key_exists('id', $_REQUEST)) { + throw new InvalidArgumentException('Keine ID angegeben!', 'danger', 'orders'); + } + $checkout = AbstractCheckout::fromID($_REQUEST['id']); + if ($refund = $checkout::refund($checkout)) { + Helper::addAlert(sprintf('Bestellung wurde zurückerstattet (%s).', $refund->id), 'success', 'orders'); + } + goto order; + } catch (InvalidArgumentException $e) { + Helper::addAlert('Fehler: ' . $e->getMessage(), 'danger', 'orders'); + } catch (Exception $e) { + Helper::addAlert('Fehler: ' . $e->getMessage(), 'danger', 'orders'); + goto order; + } + + break; + + case 'cancel': + try { + if (!array_key_exists('id', $_REQUEST)) { + throw new InvalidArgumentException('Keine ID angeben!'); + } + $checkout = AbstractCheckout::fromID($_REQUEST['id']); + if ($checkout::cancel($checkout)) { + Helper::addAlert('Bestellung wurde abgebrochen.', 'success', 'orders'); + } + goto order; + } catch (InvalidArgumentException $e) { + Helper::addAlert('Fehler: ' . $e->getMessage(), 'danger', 'orders'); + } catch (Exception $e) { + Helper::addAlert('Fehler: ' . $e->getMessage(), 'danger', 'orders'); + goto order; + } + + break; + + case 'capture': + try { + if (!array_key_exists('id', $_REQUEST)) { + throw new InvalidArgumentException('Keine ID angeben!'); + } + $checkout = AbstractCheckout::fromID($_REQUEST['id']); + if ($shipmentId = OrderCheckout::capture($checkout)) { + Helper::addAlert(sprintf('Zahlung erfolgreich erfasst/versandt (%s).', $shipmentId), 'success', 'orders'); + } + goto order; + } catch (InvalidArgumentException $e) { + Helper::addAlert('Fehler: ' . $e->getMessage(), 'danger', 'orders'); + } catch (Exception $e) { + Helper::addAlert('Fehler: ' . $e->getMessage(), 'danger', 'orders'); + goto order; + } + + break; + + case 'order': + order : + try { + if (!array_key_exists('id', $_REQUEST)) { + throw new InvalidArgumentException('Keine ID angeben!'); + } + + $checkout = AbstractCheckout::fromID($_REQUEST['id']); + + if ($checkout instanceof OrderCheckout) { + Shop::Smarty()->assign('shipments', $checkout->getShipments()); + } + + Shop::Smarty()->assign('payment', $checkout->getModel()) + ->assign('oBestellung', $checkout->getBestellung()) + ->assign('order', $checkout->getMollie()) + ->assign('checkout', $checkout) + ->assign('logs', $checkout->getLogs()); + Shop::Smarty()->display($oPlugin->cAdminmenuPfad . '/tpl/order.tpl'); + + return; + } catch (Exception $e) { + Helper::addAlert('Fehler: ' . $e->getMessage(), 'danger', 'orders'); + } + + break; + } + } + + // Mollie::fixZahlungsarten(); + + $checkouts = []; + $payments = Shop::DB()->executeQueryPrepared('SELECT * FROM xplugin_ws_mollie_payments WHERE kBestellung IS NOT NULL ORDER BY dCreatedAt DESC LIMIT 1000;', [], 2); + foreach ($payments as $i => $payment) { + $payment = new Payment($payment); + + try { + $checkouts[$payment->kBestellung] = AbstractCheckout::fromModel($payment, false); + } catch (Exception $e) { + //Helper::addAlert($e->getMessage(), 'danger', 'orders'); + } + } + + Shop::Smarty()->assign('payments', $payments) + ->assign('checkouts', $checkouts) + ->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/207/adminmenu/paymentmethods.php b/version/207/adminmenu/paymentmethods.php index e69de29..49c2851 100644 --- a/version/207/adminmenu/paymentmethods.php +++ b/version/207/adminmenu/paymentmethods.php @@ -0,0 +1,103 @@ +setApiKey(Helper::getSetting('api_key')); + + $profile = $mollie->profiles->get('me'); + + $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}$/']]) ?: AbstractCheckout::getLocale(); + $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', + 'locale' => $locale + ]; + if ($amount && $currency) { + $params['amount'] = ['value' => number_format($amount, 2, '.', ''), 'currency' => $currency]; + if ($active) { + $params['includeWallets'] = 'applepay'; + //$params['resource'] = 'orders'; + } + } + + $allMethods = []; + if ($active) { + $_allMethods = $mollie->methods->allActive($params); + } else { + $_allMethods = $mollie->methods->allAvailable($params); + } + + $sessionLife = (int)ini_get('session.gc_maxlifetime'); + + /** @var Method $method */ + foreach ($_allMethods as $method) { + $id = $method->id === 'creditcard' ? 'kreditkarte' : $method->id; + $key = "kPlugin_{$oPlugin->kPlugin}_mollie$id"; + + $class = null; + $shop = null; + $oClass = null; + + if (array_key_exists($key, $oPlugin->oPluginZahlungsKlasseAssoc_arr) && !in_array($id, ['voucher', 'giftcard', 'directdebit'], true)) { + $class = $oPlugin->oPluginZahlungsKlasseAssoc_arr[$key]; + include_once $oPlugin->cPluginPfad . 'paymentmethod/' . $class->cClassPfad; + /** @var JTLMollie $oClass */ + $oClass = new $class->cClassName($id); + } + if (array_key_exists($key, $oPlugin->oPluginZahlungsmethodeAssoc_arr)) { + $shop = $oPlugin->oPluginZahlungsmethodeAssoc_arr[$key]; + } + + $maxExpiryDays = $oClass ? $oClass->getExpiryDays() : null; + $allMethods[$method->id] = (object)[ + 'mollie' => $method, + 'class' => $class, + 'allowPreOrder' => $oClass ? $oClass::ALLOW_PAYMENT_BEFORE_ORDER : false, + 'allowAutoStorno' => $oClass ? $oClass::ALLOW_AUTO_STORNO : false, + 'oClass' => $oClass, + 'shop' => $shop, + 'maxExpiryDays' => $oClass ? $maxExpiryDays : null, + 'warning' => $oClass && ($maxExpiryDays * 24 * 60 * 60) > $sessionLife, + 'session' => round($sessionLife / 60 / 60, 2) . 'h' + ]; + } + + Shop::Smarty()->assign('profile', $profile) + ->assign('currencies', AbstractCheckout::getCurrencies()) + ->assign('locales', AbstractCheckout::getLocales()) + ->assign('allMethods', $allMethods) + ->assign('settings', $oPlugin->oPluginEinstellungAssoc_arr); + Shop::Smarty()->display($oPlugin->cAdminmenuPfad . '/tpl/paymentmethods.tpl'); +} catch (Exception $e) { + echo "
{$e->getMessage()}
"; + Helper::logExc($e); +} diff --git a/version/207/adminmenu/tpl/_addon.tpl b/version/207/adminmenu/tpl/_addon.tpl index e69de29..6539757 100644 --- a/version/207/adminmenu/tpl/_addon.tpl +++ b/version/207/adminmenu/tpl/_addon.tpl @@ -0,0 +1,6 @@ + \ No newline at end of file diff --git a/version/207/adminmenu/tpl/info.tpl b/version/207/adminmenu/tpl/info.tpl index e69de29..2d41c95 100644 --- a/version/207/adminmenu/tpl/info.tpl +++ b/version/207/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}
+
+
+
Changelog:
+
+ +
+
+ +
+
+ +
+
+
+ {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/207/adminmenu/tpl/mollie-account-erstellen.png b/version/207/adminmenu/tpl/mollie-account-erstellen.png index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..fc1819255ef725fa214cf2bf028cf3428794ecee 100644 GIT binary patch literal 38998 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 +

+ « + 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 isset($order->customerId)} + ID: + {$order->customerId} +
+ {/if} + {if isset($order->billingAddress, $order->billingAddress->organizationName)} + {$order->billingAddress->organizationName} + {elseif isset($order->billingAddress)} + {$order->billingAddress->title} {$order->billingAddress->givenName} {$order->billingAddress->familyName} + {/if} +
Mollie Checkout: + {if $order->getCheckoutURL()} + mollie.com/... + {else} + n/a + {/if} + + +
+{if $order->id|strpos:"ord_" !== false && $order->payments()->count > 0} +

Zahlungen

+ + + + + + + + + + + + + + {foreach from=$order->payments() item=payment} + + + + + + + + + + + {/foreach} +
IDStatusMethodeAmountSettlementRefundedRemainingDetails
{$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} +
+
+{/if} + +
+ {if ($order->status === 'authorized' || $order->status === 'shipping') && $oBestellung->cStatus|intval >= 3} + + Zahlung erfassen1 + + {/if} + {if !$order->amountRefunded || ($order->amount->value > $order->amountRefunded->value)} + Rückerstatten2 + + {/if} + {if $order->isCancelable} + Abbrechen3 + + {/if} +
+ +{if $order->id|strpos:"ord_" !== false} +

Positionen:

+ + + + + + + + + + + + + + + + + {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} + + + + + + + + + + + + + {/foreach} + + + + + + + + + + +
StatusSKUNameTypAnzahlMwStSteuerNettoBrutto 
+ {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'} + abgebrochen + {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*} +
{$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.
+
+{/if} + +{if isset($shipments) && $shipments|count} +

Shipmets

+ + + + + + + + + + + {foreach from=$shipments item=shipment} + + + + + + + {/foreach} + +
Lieferschein Nr.Mollie IDCarrierCode
{$shipment->getLieferschein()->getLieferscheinNr()}{$shipment->getShipment()->id} + {if isset($shipment->getShipment()->tracking)} + {$shipment->getShipment()->tracking->carrier} + {else} + - + {/if} + {if isset($shipment->getShipment()->tracking)} + {if isset($shipment->getShipment()->tracking->url)} + + {$shipment->getShipment()->tracking->code} + + {else} + {$shipment->getShipment()->tracking->code} + {/if} + {else} + - + {/if} +
+{/if} + +

Log

+ + {foreach from=$logs item=log} + + + + + + + {/foreach} +
+ {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}
+ + diff --git a/version/207/adminmenu/tpl/orders.tpl b/version/207/adminmenu/tpl/orders.tpl index e69de29..a499f32 100644 --- a/version/207/adminmenu/tpl/orders.tpl +++ b/version/207/adminmenu/tpl/orders.tpl @@ -0,0 +1,160 @@ +{ws_mollie\Helper::showAlerts('orders')} + +{if $hasAPIKey == false} + + Jetzt kostenlos Mollie Account eröffnen! + +{else} + + + + + + + + + + + + + + + {foreach from=$checkouts item=checkout} + + + + + + + + + + + + + + + {/foreach} + +
BestellNr.IDMollie StatusJTL StatusBetragMethodeErstellt 
+ {if $checkout->getModel()->bSynced == false && $checkout->getBestellung()->cAbgeholt === 'Y'} + * + {/if} + {$checkout->getModel()->cOrderNumber} + {if $checkout->getModel()->cMode == 'test'} + TEST + {/if} + {if $checkout->getModel()->bLockTimeout} + LOCK TIMEOUT + {/if} + {if $checkout->getModel()->dReminder && $checkout->getModel()->dReminder !== '0000-00-00 00:00:00'} + getModel()->dReminder|strtotime}}"> + {/if} + + {$checkout->getModel()->kID} + + {if $checkout->getModel()->cStatus == 'created' || $checkout->getModel()->cStatus == 'open'} + erstellt + {elseif $checkout->getModel()->cStatus == 'pending'} + austehend + {elseif $checkout->getModel()->cStatus == 'paid'} + bezahlt + {elseif $checkout->getModel()->cStatus == 'authorized'} + autorisiert + {elseif $checkout->getModel()->cStatus == 'shipping'} + versendet + {elseif $checkout->getModel()->cStatus == 'completed'} + abgeschlossen + {elseif $checkout->getModel()->cStatus == 'expired'} + abgelaufen + {elseif $checkout->getModel()->cStatus == 'canceled'} + abgebrochen + {else} + Unbekannt: {$checkout->getModel()->cStatus} + {/if} + {if $checkout->getModel()->fAmountRefunded && $checkout->getModel()->fAmountRefunded == $checkout->getModel()->fAmount} + (total refund) + {elseif $checkout->getModel()->fAmountRefunded && $checkout->getModel()->fAmountRefunded > 0} + (partly refund) + {/if} + + + {if $checkout->getBestellung()->cStatus|intval == 1} + OFFEN + {elseif $checkout->getBestellung()->cStatus|intval == 2} + IN BEARBEITUNG + {elseif $checkout->getBestellung()->cStatus|intval == 3} + BEZAHLT + {elseif $checkout->getBestellung()->cStatus|intval == 4} + VERSANDT + {elseif $checkout->getBestellung()->cStatus|intval == 5} + TEILVERSANDT + {elseif $checkout->getBestellung()->cStatus|intval == -1} + STORNO + {else} + n/a + {/if} + {$checkout->getModel()->fAmount|number_format:2:',':''} {$checkout->getModel()->cCurrency}{$checkout->getModel()->cMethod}{"d. M Y H:i"|date:{$checkout->getModel()->dCreatedAt|strtotime}} +
+ +
+ {if $checkout->getModel()->bSynced == false && $checkout->getBestellung()->cAbgeholt === 'Y'} + + {/if} + {if $checkout->remindable()} + + {/if} +
+
+
+ {if $payments|count > 900} +
Hier werden nur die letzten 1000 Ergebnisse angezeigt.
+ {/if} + + +
+
+

Export:

+
+ +
+ + + + + +
+
+ +{/if} + diff --git a/version/207/adminmenu/tpl/paymentmethods.tpl b/version/207/adminmenu/tpl/paymentmethods.tpl index e69de29..7821af5 100644 --- a/version/207/adminmenu/tpl/paymentmethods.tpl +++ b/version/207/adminmenu/tpl/paymentmethods.tpl @@ -0,0 +1,148 @@ +

Account Status

+ + + + + + + {if $profile->review} + + + {/if} + {if $profile->_links->checkoutPreviewUrl->href} + + {/if} + + +
Mode:{$profile->mode}Status:{$profile->status}Review:{$profile->review->status} + Checkout + Preview + + Mollie Dashboard +
+
+
+
+ + +
+ + + +
+
+ + +
+
+ + +
+
+ + + reset +
+
+
+
+{if $allMethods && $allMethods|count} + + + + + + + + + + + + {foreach from=$allMethods item=method} + + + + + + + + {/foreach} + +
BildName / IDInfoPreiseLimits
{$method->mollie->description|utf8_decode} + {if $method->mollie->status === 'activated'} + + {else} + + {/if} + {$method->mollie->description|utf8_decode}
+ {$method->mollie->id} +
+ {if $method->shop && $method->oClass} + {if intval($method->shop->nWaehrendBestellung) === 1 && !$method->allowPreOrder} +
Zahlung VOR Bestellabschluss nicht unterstützt!
+ {else} +
+ Bestellabschluss: + {if intval($method->shop->nWaehrendBestellung) === 1} + NACH Zahlung + {else} + VOR Zahlung + {/if} +
+ {/if} + + {if intval($settings.autoStorno) > 0} +
+ Unbez. Bestellung stornieren: + {if $method->allowAutoStorno} +
auto
+ {else} +
manual
+ {/if} +
+ {/if} +
+ Gültigkeit: + {$method->maxExpiryDays} Tage +
+ {else} + Derzeit nicht unterstützt. + {/if} +
+
    + {foreach from=$method->mollie->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->mollie->minimumAmount}{$method->mollie->minimumAmount->value} {$method->mollie->minimumAmount->currency}{else}n/a{/if} +
+ Max: {if $method->mollie->maximumAmount}{$method->mollie->maximumAmount->value} {$method->mollie->maximumAmount->currency}{else}n/a{/if} +
+{else} +
Es konnten keine Methoden abgerufen werden.
+{/if} \ No newline at end of file diff --git a/version/207/class/API.php b/version/207/class/API.php new file mode 100644 index 0000000..3532455 --- /dev/null +++ b/version/207/class/API.php @@ -0,0 +1,77 @@ +test = $test === null ? self::getMode() : $test; + } + + /** + * @return bool + */ + public static function getMode() + { + require_once PFAD_ROOT . PFAD_ADMIN . PFAD_INCLUDES . 'benutzerverwaltung_inc.php'; + + return self::Plugin()->oPluginEinstellungAssoc_arr['testAsAdmin'] === 'Y' && Shop::isAdmin() && self::Plugin()->oPluginEinstellungAssoc_arr['test_api_key']; + } + + /** + * @throws ApiException + * @throws IncompatiblePlatform + * @return MollieApiClient + */ + public function Client() + { + if (!$this->client) { + $this->client = new MollieApiClient(/*new Client([ + RequestOptions::VERIFY => CaBundle::getBundledCaBundlePath(), + RequestOptions::TIMEOUT => 60 + ])*/ + ); + $this->client->setApiKey($this->isTest() ? self::Plugin()->oPluginEinstellungAssoc_arr['test_api_key'] : self::Plugin()->oPluginEinstellungAssoc_arr['api_key']) + ->addVersionString('JTL-Shop/' . JTL_VERSION . JTL_MINOR_VERSION) + ->addVersionString('ws_mollie/' . self::Plugin()->nVersion); + } + + return $this->client; + } + + /** + * @return bool + */ + public function isTest() + { + return $this->test; + } +} diff --git a/version/207/class/Checkout/AbstractCheckout.php b/version/207/class/Checkout/AbstractCheckout.php index e69de29..8a31700 100644 --- a/version/207/class/Checkout/AbstractCheckout.php +++ b/version/207/class/Checkout/AbstractCheckout.php @@ -0,0 +1,1214 @@ + ['lang' => 'de', 'country' => ['DE', 'AT', 'CH']], + 'fre' => ['lang' => 'fr', 'country' => ['BE', 'FR']], + 'dut' => ['lang' => 'nl', 'country' => ['BE', 'NL']], + 'spa' => ['lang' => 'es', 'country' => ['ES']], + 'ita' => ['lang' => 'it', 'country' => ['IT']], + 'pol' => ['lang' => 'pl', 'country' => ['PL']], + 'hun' => ['lang' => 'hu', 'country' => ['HU']], + 'por' => ['lang' => 'pt', 'country' => ['PT']], + 'nor' => ['lang' => 'nb', 'country' => ['NO']], + 'swe' => ['lang' => 'sv', 'country' => ['SE']], + 'fin' => ['lang' => 'fi', 'country' => ['FI']], + 'dan' => ['lang' => 'da', 'country' => ['DK']], + 'ice' => ['lang' => 'is', 'country' => ['IS']], + 'eng' => ['lang' => 'en', 'country' => ['GB', 'US']], + ]; + /** + * @var null|\Mollie\Api\Resources\Customer + */ + protected $customer; + /** + * @var string + */ + private $hash; + /** + * @var API + */ + private $api; + /** + * @var JTLMollie + */ + private $paymentMethod; + /** + * @var Bestellung + */ + private $oBestellung; + /** + * @var Payment + */ + private $model; + + /** + * AbstractCheckout constructor. + * @param Bestellung $oBestellung + * @param null $api + */ + public function __construct(Bestellung $oBestellung, $api = null) + { + $this->api = $api; + $this->oBestellung = $oBestellung; + } + + /** + * @param int $kBestellung + * @param bool $checkZA + * @return bool + */ + public static function isMollie($kBestellung, $checkZA = false) + { + if ($checkZA) { + $res = Shop::DB()->executeQueryPrepared('SELECT * FROM tzahlungsart WHERE cModulId LIKE :cModulId AND kZahlungsart = :kZahlungsart', [ + ':kZahlungsart' => $kBestellung, + ':cModulId' => 'kPlugin_' . self::Plugin()->kPlugin . '_%' + ], 1); + + return (bool)$res; + } + + return ($res = Shop::DB()->executeQueryPrepared('SELECT kId FROM xplugin_ws_mollie_payments WHERE kBestellung = :kBestellung;', [ + ':kBestellung' => $kBestellung, + ], 1)) && $res->kId; + } + + public static function finalizeOrder($sessionHash, $id, $test = false) + { + try { + if ($paymentSession = Shop::DB()->select('tzahlungsession', 'cZahlungsID', $sessionHash)) { + if (session_id() !== $paymentSession->cSID) { + session_destroy(); + session_id($paymentSession->cSID); + $session = Session::getInstance(true, true); + } else { + $session = Session::getInstance(false); + } + + if ( + (!isset($paymentSession->nBezahlt) || !$paymentSession->nBezahlt) + && (!isset($paymentSession->kBestellung) || !$paymentSession->kBestellung) + && isset($_SESSION['Warenkorb']->PositionenArr) + && count($_SESSION['Warenkorb']->PositionenArr) + ) { + $paymentSession->cNotifyID = $id; + $paymentSession->dNotify = 'now()'; + Shop::DB()->update('tzahlungsession', 'cZahlungsID', $sessionHash, $paymentSession); + + $api = new API($test); + if (strpos($id, 'tr_') === 0) { + $mollie = $api->Client()->payments->get($id); + } else { + $mollie = $api->Client()->orders->get($id, ['embed' => 'payments']); + } + + if (in_array($mollie->status, [OrderStatus::STATUS_PENDING, OrderStatus::STATUS_AUTHORIZED, OrderStatus::STATUS_PAID], true)) { + require_once PFAD_ROOT . PFAD_INCLUDES . 'bestellabschluss_inc.php'; + require_once PFAD_ROOT . PFAD_INCLUDES . 'mailTools.php'; + $order = finalisiereBestellung(); + $session->cleanUp(); + $paymentSession->nBezahlt = 1; + $paymentSession->dZeitBezahlt = 'now()'; + } else { + throw new Exception('Mollie Status invalid: ' . $mollie->status . '\n' . print_r([$sessionHash, $id], 1)); + } + + if ($order->kBestellung) { + $paymentSession->kBestellung = $order->kBestellung; + Shop::DB()->update('tzahlungsession', 'cZahlungsID', $sessionHash, $paymentSession); + + try { + $checkout = self::fromID($id, false, $order); + } catch (Exception $e) { + if (strpos($id, 'tr_') === 0) { + $checkoutClass = PaymentCheckout::class; + } else { + $checkoutClass = OrderCheckout::class; + } + $checkout = new $checkoutClass($order, $api); + } + $checkout->setMollie($mollie)->updateModel()->saveModel(); + $checkout->updateOrderNumber(); + $checkout->handleNotification($sessionHash); + } + } else { + Jtllog::writeLog(sprintf('PaymentSession bereits bezahlt: %s - ID: %s => Queue', $sessionHash, $id), JTLLOG_LEVEL_NOTICE); + Queue::saveToQueue($id, $id, 'webhook'); + } + } else { + Jtllog::writeLog(sprintf('PaymentSession nicht gefunden: %s - ID: %s => Queue', $sessionHash, $id), JTLLOG_LEVEL_NOTICE); + Queue::saveToQueue($id, $id, 'webhook'); + } + } catch (Exception $e) { + Helper::logExc($e); + } + } + + /** + * @param string $id + * @param bool $bFill + * @param null|Bestellung $order + * @throws RuntimeException + * @return OrderCheckout|PaymentCheckout + */ + public static function fromID($id, $bFill = true, Bestellung $order = null) + { + if (($model = Payment::fromID($id))) { + return static::fromModel($model, $bFill, $order); + } + + throw new RuntimeException(sprintf('Error loading Order: %s', $id)); + } + + /** + * @param Payment $model + * @param bool $bFill + * @param null|Bestellung $order + * @return OrderCheckout|PaymentCheckout + */ + public static function fromModel($model, $bFill = true, Bestellung $order = null) + { + if (!$model) { + throw new RuntimeException(sprintf('Error loading Order for Model: %s', print_r($model, 1))); + } + + $oBestellung = $order; + if (!$order) { + $oBestellung = new Bestellung($model->kBestellung, $bFill); + if (!$oBestellung->kBestellung) { + throw new RuntimeException(sprintf('Error loading Bestellung: %s', $model->kBestellung)); + } + } + + if (strpos($model->kID, 'tr_') !== false) { + $self = new PaymentCheckout($oBestellung); + } else { + $self = new OrderCheckout($oBestellung); + } + + $self->setModel($model); + + return $self; + } + + /** + * @return bool + */ + public function saveModel() + { + return $this->getModel()->save(); + } + + /** + * @return Payment + */ + public function getModel() + { + if (!$this->model) { + $this->model = Payment::fromID($this->oBestellung->kBestellung, 'kBestellung'); + } + + return $this->model; + } + + /** + * @param $model + * @return $this + */ + protected function setModel($model) + { + if (!$this->model) { + $this->model = $model; + } else { + throw new RuntimeException('Model already set.'); + } + + return $this; + } + + /** + * @param null $hash + * @throws Exception + */ + public function handleNotification($hash = null) + { + if (!$this->getHash()) { + $this->getModel()->cHash = $hash; + } + + $this->updateModel()->saveModel(); + if (!$this->getBestellung()->dBezahltDatum || $this->getBestellung()->dBezahltDatum === '0000-00-00') { + if ($incoming = $this->getIncomingPayment()) { + $this->PaymentMethod()->addIncomingPayment($this->getBestellung(), $incoming); + + $this->PaymentMethod()->setOrderStatusToPaid($this->getBestellung()); + static::makeFetchable($this->getBestellung(), $this->getModel()); + $this->PaymentMethod()->deletePaymentHash($this->getHash()); + $this->Log(sprintf("Checkout::handleNotification: Bestellung '%s' als bezahlt markiert: %.2f %s", $this->getBestellung()->cBestellNr, (float)$incoming->fBetrag, $incoming->cISO)); + + $oZahlungsart = Shop::DB()->selectSingleRow('tzahlungsart', 'cModulId', $this->PaymentMethod()->moduleID); + if ($oZahlungsart && (int)$oZahlungsart->nMailSenden === 1) { + require_once PFAD_ROOT . 'includes/mailTools.php'; + $this->PaymentMethod()->sendConfirmationMail($this->getBestellung()); + } + if (!$this->completlyPaid()) { + $this->Log(sprintf("Checkout::handleNotification: Bestellung '%s': nicht komplett bezahlt: %.2f %s", $this->getBestellung()->cBestellNr, (float)$incoming->fBetrag, $incoming->cISO), LOGLEVEL_ERROR); + } + } + } + } + + /** + * @return string + */ + public function getHash() + { + if ($this->getModel()->cHash) { + return $this->getModel()->cHash; + } + if (!$this->hash) { + $this->hash = $this->PaymentMethod()->generateHash($this->oBestellung); + } + + return $this->hash; + } + + /** + * @return JTLMollie + */ + public function PaymentMethod() + { + if (!$this->paymentMethod) { + include_once PFAD_ROOT . PFAD_INCLUDES . 'modules/PaymentMethod.class.php'; + if ($this->getBestellung()->Zahlungsart && strpos($this->getBestellung()->Zahlungsart->cModulId, "kPlugin_{$this::Plugin()->kPlugin}_") !== false) { + try { + $this->paymentMethod = PaymentMethod::create($this->getBestellung()->Zahlungsart->cModulId); + } catch (Exception $e) { + $this->paymentMethod = PaymentMethod::create("kPlugin_{$this::Plugin()->kPlugin}_mollie"); + } + } else { + $this->paymentMethod = PaymentMethod::create("kPlugin_{$this::Plugin()->kPlugin}_mollie"); + } + } + + return $this->paymentMethod; + } + + /** + * @return Bestellung + */ + public function getBestellung() + { + if (!$this->oBestellung && $this->getModel()->kBestellung) { + $this->oBestellung = new Bestellung($this->getModel()->kBestellung, true); + } + + return $this->oBestellung; + } + + /** + * @return $this + */ + public function updateModel() + { + if ($this->getMollie()) { + $this->getModel()->kID = $this->getMollie()->id; + $this->getModel()->cLocale = $this->getMollie()->locale; + $this->getModel()->fAmount = (float)$this->getMollie()->amount->value; + $this->getModel()->cMethod = $this->getMollie()->method; + $this->getModel()->cCurrency = $this->getMollie()->amount->currency; + $this->getModel()->cStatus = $this->getMollie()->status; + if ($this->getMollie()->amountRefunded) { + $this->getModel()->fAmountRefunded = $this->getMollie()->amountRefunded->value; + } + if ($this->getMollie()->amountCaptured) { + $this->getModel()->fAmountCaptured = $this->getMollie()->amountCaptured->value; + } + $this->getModel()->cMode = $this->getMollie()->mode ?: null; + $this->getModel()->cRedirectURL = $this->getMollie()->redirectUrl; + $this->getModel()->cWebhookURL = $this->getMollie()->webhookUrl; + $this->getModel()->cCheckoutURL = $this->getMollie()->getCheckoutUrl(); + } + + $this->getModel()->kBestellung = $this->getBestellung()->kBestellung; + $this->getModel()->cOrderNumber = $this->getBestellung()->cBestellNr; + $this->getModel()->cHash = trim($this->getHash(), '_'); + + $this->getModel()->bSynced = $this->getModel()->bSynced !== null ? $this->getModel()->bSynced : Helper::getSetting('onlyPaid') !== 'Y'; + + return $this; + } + + /** + * @param false $force + * @return null|\Mollie\Api\Resources\Payment|Order + */ + abstract public function getMollie($force = false); + + /** + * @return stdClass + */ + abstract public function getIncomingPayment(); + + /** + * @param Bestellung $oBestellung + * @param Payment $model + * @return bool + */ + public static function makeFetchable(Bestellung $oBestellung, Payment $model) + { + // TODO: force ? + if ($oBestellung->cAbgeholt === 'Y' && !$model->bSynced) { + Shop::DB()->update('tbestellung', 'kBestellung', $oBestellung->kBestellung, (object)['cAbgeholt' => 'N']); + } + $model->bSynced = true; + + try { + return $model->save(); + } catch (Exception $e) { + Jtllog::writeLog(sprintf('Fehler beim speichern des Models: %s / Bestellung: %s', $model->kID, $oBestellung->cBestellNr)); + } + + return false; + } + + public function Log($msg, $level = LOGLEVEL_NOTICE) + { + try { + $data = ''; + if ($this->getBestellung()) { + $data .= '#' . $this->getBestellung()->kBestellung; + } + if ($this->getMollie()) { + $data .= '$' . $this->getMollie()->id; + } + ZahlungsLog::add($this->PaymentMethod()->moduleID, '[' . microtime(true) . ' - ' . $_SERVER['PHP_SELF'] . '] ' . $msg, $data, $level); + } catch (Exception $e) { + Jtllog::writeLog('Mollie Log failed: ' . $e->getMessage() . '; Previous Log: ' . print_r([$msg, $level, $data], 1)); + } + + return $this; + } + + /** + * @return bool + */ + public function completlyPaid() + { + if ( + $row = Shop::DB()->executeQueryPrepared('SELECT SUM(fBetrag) as fBetragSumme FROM tzahlungseingang WHERE kBestellung = :kBestellung', [ + ':kBestellung' => $this->getBestellung()->kBestellung + ], 1) + ) { + return $row->fBetragSumme >= round($this->getBestellung()->fGesamtsumme * $this->getBestellung()->fWaehrungsFaktor, 2); + } + + return false; + } + + /** + * @param $kBestellung + * * @throws RuntimeException + * @return OrderCheckout|PaymentCheckout + */ + public static function fromBestellung($kBestellung) + { + if ($model = Payment::fromID($kBestellung, 'kBestellung')) { + return static::fromModel($model); + } + + throw new RuntimeException(sprintf('Error loading Order for Bestellung: %s', $kBestellung)); + } + + public static function sendReminders() + { + $reminder = (int)self::Plugin()->oPluginEinstellungAssoc_arr['reminder']; + + if (!$reminder) { + return; + } + + $sql = 'SELECT p.kID FROM xplugin_ws_mollie_payments p JOIN tbestellung b ON b.kBestellung = p.kBestellung ' + . "WHERE (p.dReminder IS NULL OR p.dReminder = '0000-00-00 00:00:00') " + . 'AND p.dCreatedAt < NOW() - INTERVAL :d MINUTE AND p.dCreatedAt > NOW() - INTERVAL 7 DAY ' + . "AND p.cStatus IN ('created','open', 'expired', 'failed', 'canceled') AND NOT b.cStatus = '-1'"; + + $remindables = Shop::DB()->executeQueryPrepared($sql, [ + ':d' => $reminder + ], 2); + foreach ($remindables as $remindable) { + try { + self::sendReminder($remindable->kID); + } catch (Exception $e) { + Jtllog::writeLog('AbstractCheckout::sendReminders: ' . $e->getMessage()); + } + } + } + + /** + * @param $kID + * @return bool + */ + public static function sendReminder($kID) + { + $checkout = self::fromID($kID); + $return = true; + + if (!$checkout->getBestellung()->kBestellung || (int)$checkout->getBestellung()->cStatus > BESTELLUNG_STATUS_IN_BEARBEITUNG || (int)$checkout->getBestellung()->cStatus < 0) { + return $return; + } + + + try { + $repayURL = Shop::getURL() . '/?m_pay=' . md5($checkout->getModel()->kID . '-' . $checkout->getBestellung()->kBestellung); + + $data = new stdClass(); + $data->tkunde = new Kunde($checkout->getBestellung()->oKunde->kKunde); + if ($data->tkunde->kKunde) { + $data->Bestellung = $checkout->getBestellung(); + $data->PayURL = $repayURL; + $data->Amount = gibPreisStringLocalized($checkout->getModel()->fAmount, $checkout->getBestellung()->Waehrung); //Preise::getLocalizedPriceString($order->getAmount(), Currency::fromISO($order->getCurrency()), false); + + require_once PFAD_ROOT . PFAD_INCLUDES . 'mailTools.php'; + + $mail = new stdClass(); + $mail->toEmail = $data->tkunde->cMail; + $mail->toName = trim((isset($data->tKunde->cVorname) + ? $data->tKunde->cVorname + : '') . ' ' . ( + isset($data->tKunde->cNachname) + ? $data->tKunde->cNachname + : '' + )) ?: $mail->toEmail; + $data->mail = $mail; + if (!($sentMail = sendeMail('kPlugin_' . self::Plugin()->kPlugin . '_zahlungserinnerung', $data))) { + $checkout->Log(sprintf("Zahlungserinnerung konnte nicht versand werden: %s\n%s", isset($sentMail->cFehler) ?: print_r($sentMail, 1), print_r($data, 1)), LOGLEVEL_ERROR); + $return = false; + } else { + $checkout->Log(sprintf('Zahlungserinnerung für %s verschickt.', $checkout->getBestellung()->cBestellNr)); + } + } else { + $checkout->Log("Kunde '{$checkout->getBestellung()->oKunde->kKunde}' nicht gefunden.", LOGLEVEL_ERROR); + } + } catch (Exception $e) { + $checkout->Log(sprintf('AbstractCheckout::sendReminder: Zahlungserinnerung für %s fehlgeschlagen: %s', $checkout->getBestellung()->cBestellNr, $e->getMessage())); + $return = false; + } + $checkout->getModel()->dReminder = date('Y-m-d H:i:s'); + $checkout->getModel()->save(); + + return $return; + } + + /** + * @param AbstractCheckout $checkout + * @throws ApiException + * @return BaseResource|Refund + */ + public static function refund(self $checkout) + { + if ($checkout->getMollie()->resource === 'order') { + /** @var Order $order */ + $order = $checkout->getMollie(); + if (in_array($order->status, [OrderStatus::STATUS_CANCELED, OrderStatus::STATUS_EXPIRED, OrderStatus::STATUS_CREATED], true)) { + throw new RuntimeException('Bestellung kann derzeit nicht zurückerstattet werden.'); + } + $refund = $order->refundAll(); + $checkout->Log(sprintf('Bestellung wurde manuell zurückerstattet: %s', $refund->id)); + + return $refund; + } + if ($checkout->getMollie()->resource === 'payment') { + /** @var \Mollie\Api\Resources\Payment $payment */ + $payment = $checkout->getMollie(); + if (in_array($payment->status, [PaymentStatus::STATUS_CANCELED, PaymentStatus::STATUS_EXPIRED, PaymentStatus::STATUS_OPEN], true)) { + throw new RuntimeException('Zahlung kann derzeit nicht zurückerstattet werden.'); + } + $refund = $checkout->API()->Client()->payments->refund($checkout->getMollie(), ['amount' => $checkout->getMollie()->amount]); + $checkout->Log(sprintf('Zahlung wurde manuell zurückerstattet: %s', $refund->id)); + + return $refund; + } + + throw new RuntimeException(sprintf('Unbekannte Resource: %s', $checkout->getMollie()->resource)); + } + + /** + * @return API + */ + public function API() + { + if (!$this->api) { + if ($this->getModel()->kID) { + $this->api = new API($this->getModel()->cMode === 'test'); + } else { + $this->api = new API(API::getMode()); + } + } + + return $this->api; + } + + /** + * @param $checkout + * @throws ApiException + * @return \Mollie\Api\Resources\Payment|Order + */ + public static function cancel($checkout) + { + if ($checkout instanceof OrderCheckout) { + return OrderCheckout::cancel($checkout); + } + if ($checkout instanceof PaymentCheckout) { + return PaymentCheckout::cancel($checkout); + } + + throw new RuntimeException('AbstractCheckout::cancel: Invalid Checkout!'); + } + + 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[] = static::getLocale($sS->cISO, $land); + } + } + + return array_intersect(array_unique($result), $locales); + } + + public static function getLocale($cISOSprache = null, $country = null) + { + if ($cISOSprache === null) { + $cISOSprache = gibStandardsprache()->cISO; + } + if (array_key_exists($cISOSprache, self::$localeLangs)) { + $locale = self::$localeLangs[$cISOSprache]['lang']; + if ($country && is_array(self::$localeLangs[$cISOSprache]['country']) && in_array($country, self::$localeLangs[$cISOSprache]['country'], true)) { + $locale .= '_' . strtoupper($country); + } else { + $locale .= '_' . self::$localeLangs[$cISOSprache]['country'][0]; + } + + return $locale; + } + + return self::Plugin()->oPluginEinstellungAssoc_arr['fallbackLocale']; + } + + 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; + } + + public function loadRequest(&$options = []) + { + $oKunde = !$this->getBestellung()->oKunde && $this->PaymentMethod()->duringCheckout ? $_SESSION['Kunde'] : $this->getBestellung()->oKunde; + if ($this->getBestellung()) { + if ( + $oKunde->nRegistriert + && ( + $customer = $this->getCustomer( + array_key_exists( + 'mollie_create_customer', + $_SESSION['cPost_arr'] ?: [] + ) && $_SESSION['cPost_arr']['mollie_create_customer'] === 'Y', + $oKunde + ) + ) + && isset($customer) + ) { + $options['customerId'] = $customer->id; + } + $this->amount = Amount::factory($this->getBestellung()->fGesamtsummeKundenwaehrung, $this->getBestellung()->Waehrung->cISO, true); + $this->redirectUrl = $this->PaymentMethod()->duringCheckout ? Shop::getURL() . '/bestellabschluss.php?' . http_build_query(['hash' => $this->getHash()]) : $this->PaymentMethod()->getReturnURL($this->getBestellung()); + $this->metadata = [ + 'kBestellung' => $this->getBestellung()->kBestellung ?: $this->getBestellung()->cBestellNr, + 'kKunde' => $this->getBestellung()->kKunde, + 'kKundengruppe' => Session::getInstance()->CustomerGroup()->kKundengruppe, + 'cHash' => $this->getHash(), + ]; + } + + $this->locale = self::getLocale($_SESSION['cISOSprache'], Session::getInstance()->Customer()->cLand); + $this->webhookUrl = Shop::getURL(true) . '/?' . http_build_query([ + 'mollie' => 1, + 'hash' => $this->getHash(), + 'test' => $this->API()->isTest() ?: null, + ]); + + $pm = $this->PaymentMethod(); + $isPayAgain = strpos($_SERVER['PHP_SELF'], 'bestellab_again') !== false; + if ($pm::METHOD !== '' && (self::Plugin()->oPluginEinstellungAssoc_arr['resetMethod'] !== 'Y' || !$isPayAgain)) { + $this->method = $pm::METHOD; + } + } + + /** + * @todo: Kunde wieder löschbar machen ?! + * @param mixed $createOrUpdate + * @param null|mixed $oKunde + * @return null|\Mollie\Api\Resources\Customer + */ + public function getCustomer($createOrUpdate = false, $oKunde = null) + { + if (!$oKunde) { + $oKunde = $this->getBestellung()->oKunde; + } + + if (!$this->customer) { + $customerModel = Customer::fromID($oKunde->kKunde, 'kKunde'); + if ($customerModel->customerId) { + try { + $this->customer = $this->API()->Client()->customers->get($customerModel->customerId); + } catch (ApiException $e) { + $this->Log(sprintf('Fehler beim laden des Mollie Customers %s (kKunde: %d): %s', $customerModel->customerId, $customerModel->kKunde, $e->getMessage()), LOGLEVEL_ERROR); + } + } + + if ($createOrUpdate) { + $customer = [ + 'name' => utf8_encode(trim($oKunde->cVorname . ' ' . $oKunde->cNachname)), + 'email' => utf8_encode($oKunde->cMail), + 'locale' => self::getLocale($_SESSION['cISOSprache'], $oKunde->cLand), + 'metadata' => (object)[ + 'kKunde' => $oKunde->kKunde, + 'kKundengruppe' => $oKunde->kKundengruppe, + 'cKundenNr' => utf8_encode($oKunde->cKundenNr), + ], + ]; + + if ($this->customer) { // UPDATE + $this->customer->name = $customer['name']; + $this->customer->email = $customer['email']; + $this->customer->locale = $customer['locale']; + $this->customer->metadata = $customer['metadata']; + + try { + $this->customer->update(); + } catch (Exception $e) { + $this->Log(sprintf("Fehler beim aktualisieren des Mollie Customers %s: %s\n%s", $this->customer->id, $e->getMessage(), print_r($customer, 1)), LOGLEVEL_ERROR); + } + } else { // create + try { + $this->customer = $this->API()->Client()->customers->create($customer); + $customerModel->kKunde = $oKunde->kKunde; + $customerModel->customerId = $this->customer->id; + $customerModel->save(); + $this->Log(sprintf("Customer '%s' für Kunde %s (%d) bei Mollie angelegt.", $this->customer->id, $this->customer->name, $this->getBestellung()->kKunde)); + } catch (Exception $e) { + $this->Log(sprintf("Fehler beim anlegen eines Mollie Customers: %s\n%s", $e->getMessage(), print_r($customer, 1)), LOGLEVEL_ERROR); + } + } + } + } + + return $this->customer; + } + + /** + * Storno Order + */ + public function storno() + { + if (in_array((int)$this->getBestellung()->cStatus, [BESTELLUNG_STATUS_OFFEN, BESTELLUNG_STATUS_IN_BEARBEITUNG], true)) { + $log = []; + + $conf = Shop::getSettings([CONF_GLOBAL, CONF_TRUSTEDSHOPS]); + $nArtikelAnzeigefilter = (int)$conf['global']['artikel_artikelanzeigefilter']; + + foreach ($this->getBestellung()->Positionen as $pos) { + if ($pos->kArtikel && $pos->Artikel && $pos->Artikel->cLagerBeachten === 'Y') { + $log[] = sprintf('Reset stock of "%s" by %d', $pos->Artikel->cArtNr, -1 * $pos->nAnzahl); + self::aktualisiereLagerbestand($pos->Artikel, -1 * $pos->nAnzahl, $pos->WarenkorbPosEigenschaftArr, $nArtikelAnzeigefilter); + } + } + $log[] = sprintf("Cancel order '%s'.", $this->getBestellung()->cBestellNr); + + if (Shop::DB()->executeQueryPrepared('UPDATE tbestellung SET cAbgeholt = \'Y\', cStatus = :cStatus WHERE kBestellung = :kBestellung', [':cStatus' => '-1', ':kBestellung' => $this->getBestellung()->kBestellung], 3)) { + $this->Log(implode('\n', $log)); + } + } + } + + protected static function aktualisiereLagerbestand($Artikel, $nAnzahl, $WarenkorbPosEigenschaftArr, $nArtikelAnzeigefilter = 1) + { + $artikelBestand = (float)$Artikel->fLagerbestand; + + if (isset($Artikel->cLagerBeachten) && $Artikel->cLagerBeachten === 'Y') { + if ( + $Artikel->cLagerVariation === 'Y' && is_array($WarenkorbPosEigenschaftArr) && count($WarenkorbPosEigenschaftArr) > 0 + ) { + foreach ($WarenkorbPosEigenschaftArr as $eWert) { + $EigenschaftWert = new EigenschaftWert($eWert->kEigenschaftWert); + if ($EigenschaftWert->fPackeinheit === .0) { + $EigenschaftWert->fPackeinheit = 1; + } + Shop::DB()->query( + 'UPDATE teigenschaftwert + SET fLagerbestand = fLagerbestand - ' . ($nAnzahl * $EigenschaftWert->fPackeinheit) . ' + WHERE kEigenschaftWert = ' . (int)$eWert->kEigenschaftWert, + 4 + ); + } + } elseif ($Artikel->fPackeinheit > 0) { + // Stückliste + if ($Artikel->kStueckliste > 0) { + $artikelBestand = self::aktualisiereStuecklistenLagerbestand($Artikel, $nAnzahl); + } else { + Shop::DB()->query( + 'UPDATE tartikel + SET fLagerbestand = IF (fLagerbestand >= ' . ($nAnzahl * $Artikel->fPackeinheit) . ', + (fLagerbestand - ' . ($nAnzahl * $Artikel->fPackeinheit) . '), fLagerbestand) + WHERE kArtikel = ' . (int)$Artikel->kArtikel, + 4 + ); + $tmpArtikel = Shop::DB()->select('tartikel', 'kArtikel', (int)$Artikel->kArtikel, null, null, null, null, false, 'fLagerbestand'); + if ($tmpArtikel !== null) { + $artikelBestand = (float)$tmpArtikel->fLagerbestand; + } + // Stücklisten Komponente + if (ArtikelHelper::isStuecklisteKomponente($Artikel->kArtikel)) { + self::aktualisiereKomponenteLagerbestand($Artikel->kArtikel, $artikelBestand, isset($Artikel->cLagerKleinerNull) && $Artikel->cLagerKleinerNull === 'Y'); + } + } + // Aktualisiere Merkmale in tartikelmerkmal vom Vaterartikel + if ($Artikel->kVaterArtikel > 0) { + Artikel::beachteVarikombiMerkmalLagerbestand($Artikel->kVaterArtikel, $nArtikelAnzeigefilter); + } + } + } + + return $artikelBestand; + } + + protected static function aktualisiereStuecklistenLagerbestand($oStueckListeArtikel, $nAnzahl) + { + $nAnzahl = (float)$nAnzahl; + $kStueckListe = (int)$oStueckListeArtikel->kStueckliste; + $bestandAlt = (float)$oStueckListeArtikel->fLagerbestand; + $bestandNeu = $bestandAlt; + $bestandUeberverkauf = $bestandAlt; + + if ($nAnzahl > 0) { + // Gibt es lagerrelevante Komponenten in der Stückliste? + $oKomponente_arr = Shop::DB()->query( + "SELECT tstueckliste.kArtikel, tstueckliste.fAnzahl + FROM tstueckliste + JOIN tartikel + ON tartikel.kArtikel = tstueckliste.kArtikel + WHERE tstueckliste.kStueckliste = $kStueckListe + AND tartikel.cLagerBeachten = 'Y'", + 2 + ); + + if (is_array($oKomponente_arr) && count($oKomponente_arr) > 0) { + // wenn ja, dann wird für diese auch der Bestand aktualisiert + $options = Artikel::getDefaultOptions(); + + $options->nKeineSichtbarkeitBeachten = 1; + + foreach ($oKomponente_arr as $oKomponente) { + $tmpArtikel = new Artikel(); + $tmpArtikel->fuelleArtikel($oKomponente->kArtikel, $options); + + $komponenteBestand = floor(self::aktualisiereLagerbestand($tmpArtikel, $nAnzahl * $oKomponente->fAnzahl, null) / $oKomponente->fAnzahl); + + if ($komponenteBestand < $bestandNeu && $tmpArtikel->cLagerKleinerNull !== 'Y') { + // Neuer Bestand ist der Kleinste Komponententbestand aller Artikel ohne Überverkauf + $bestandNeu = $komponenteBestand; + } elseif ($komponenteBestand < $bestandUeberverkauf) { + // Für Komponenten mit Überverkauf wird der kleinste Bestand ermittelt. + $bestandUeberverkauf = $komponenteBestand; + } + } + } + + // Ist der alte gleich dem neuen Bestand? + if ($bestandAlt === $bestandNeu) { + // Es sind keine lagerrelevanten Komponenten vorhanden, die den Bestand der Stückliste herabsetzen. + if ($bestandUeberverkauf === $bestandNeu) { + // Es gibt auch keine Komponenten mit Überverkäufen, die den Bestand verringern, deshalb wird + // der Bestand des Stücklistenartikels anhand des Verkaufs verringert + $bestandNeu = $bestandNeu - $nAnzahl * $oStueckListeArtikel->fPackeinheit; + } else { + // Da keine lagerrelevanten Komponenten vorhanden sind, wird der kleinste Bestand der + // Komponentent mit Überverkauf verwendet. + $bestandNeu = $bestandUeberverkauf; + } + + Shop::DB()->update('tartikel', 'kArtikel', (int)$oStueckListeArtikel->kArtikel, (object)[ + 'fLagerbestand' => $bestandNeu, + ]); + } + // Kein Lagerbestands-Update für die Stückliste notwendig! Dies erfolgte bereits über die Komponentenabfrage und + // die dortige Lagerbestandsaktualisierung! + } + + return $bestandNeu; + } + + protected static function aktualisiereKomponenteLagerbestand($kKomponenteArtikel, $fLagerbestand, $bLagerKleinerNull) + { + $kKomponenteArtikel = (int)$kKomponenteArtikel; + $fLagerbestand = (float)$fLagerbestand; + + $oStueckliste_arr = Shop::DB()->query( + "SELECT tstueckliste.kStueckliste, tstueckliste.fAnzahl, + tartikel.kArtikel, tartikel.fLagerbestand, tartikel.cLagerKleinerNull + FROM tstueckliste + JOIN tartikel + ON tartikel.kStueckliste = tstueckliste.kStueckliste + WHERE tstueckliste.kArtikel = $kKomponenteArtikel + AND tartikel.cLagerBeachten = 'Y'", + 2 + ); + + if (is_array($oStueckliste_arr) && count($oStueckliste_arr) > 0) { + foreach ($oStueckliste_arr as $oStueckliste) { + // Ist der aktuelle Bestand der Stückliste größer als dies mit dem Bestand der Komponente möglich wäre? + $maxAnzahl = floor($fLagerbestand / $oStueckliste->fAnzahl); + if ($maxAnzahl < (float)$oStueckliste->fLagerbestand && (!$bLagerKleinerNull || $oStueckliste->cLagerKleinerNull === 'Y')) { + // wenn ja, dann den Bestand der Stückliste entsprechend verringern, aber nur wenn die Komponente nicht + // überberkaufbar ist oder die gesamte Stückliste Überverkäufe zulässt + Shop::DB()->update('tartikel', 'kArtikel', (int)$oStueckliste->kArtikel, (object)[ + 'fLagerbestand' => $maxAnzahl, + ]); + } + } + } + } + + /** + * @return null|array|bool|int|object + */ + public function getLogs() + { + return 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' => '%#' . ($this->getBestellung()->kBestellung ?: '##') . '%', + ':cBestellNr' => '%§' . ($this->getBestellung()->cBestellNr ?: '§§') . '%', + ':MollieID' => '%$' . ($this->getMollie()->id ?: '$$') . '%', + ], 2); + } + + /** + * @return bool + */ + public function remindable() + { + return (int)$this->getBestellung()->cStatus !== BESTELLUNG_STATUS_STORNO && !in_array($this->getModel()->cStatus, [PaymentStatus::STATUS_PAID, PaymentStatus::STATUS_AUTHORIZED, PaymentStatus::STATUS_PENDING, OrderStatus::STATUS_COMPLETED, OrderStatus::STATUS_SHIPPING], true); + } + + /** + * @return string + */ + public function LogData() + { + $data = ''; + if ($this->getBestellung()->kBestellung) { + $data .= '#' . $this->getBestellung()->kBestellung; + } + if ($this->getMollie()) { + $data .= '$' . $this->getMollie()->id; + } + + return $data; + } + + abstract public function cancelOrRefund($force = false); + + /** + * @param array $paymentOptions + * @return Order|Payment + */ + abstract public function create(array $paymentOptions = []); + + /** + * @return string + */ + public function getRepayURL() + { + return Shop::getURL(true) . '/?m_pay=' . md5($this->getModel()->kID . '-' . $this->getBestellung()->kBestellung); + } + + public function getDescription() + { + $descTemplate = trim(Helper::getSetting('paymentDescTpl')) ?: 'Order {orderNumber}'; + $oKunde = $this->getBestellung()->oKunde ?: $_SESSION['Kunde']; + + return str_replace([ + '{orderNumber}', + '{storeName}', + '{customer.firstname}', + '{customer.lastname}', + '{customer.company}', + ], [ + $this->getBestellung()->cBestellNr, + Shop::getSettings([CONF_GLOBAL])['global']['global_shopname'], + $oKunde->cVorname, + $oKunde->cNachname, + $oKunde->cFirma + + ], $descTemplate); + } + + abstract protected function updateOrderNumber(); + + /** + * @param Bestellung $oBestellung + * @return $this + */ + protected function setBestellung(Bestellung $oBestellung) + { + $this->oBestellung = $oBestellung; + + return $this; + } + + /** + * @param \Mollie\Api\Resources\Payment|Order $model + * @return self + */ + abstract protected function setMollie($model); +} diff --git a/version/207/class/Checkout/AbstractResource.php b/version/207/class/Checkout/AbstractResource.php index e69de29..7c4439e 100644 --- a/version/207/class/Checkout/AbstractResource.php +++ b/version/207/class/Checkout/AbstractResource.php @@ -0,0 +1,18 @@ +title = substr(trim(($address->cAnrede === 'm' ? Shop::Lang()->get('mr') : Shop::Lang()->get('mrs')) . ' ' . $address->cTitel) ?: null, 0, 20); + $resource->givenName = $address->cVorname; + $resource->familyName = $address->cNachname; + $resource->email = $address->cMail ?: null; + + if ($organizationName = trim($address->cFirma)) { + $resource->organizationName = $organizationName; + } + + // Validity-Check + // TODO: Phone, with E.164 check + // TODO: Is Email-Format Check needed? + if (!$resource->givenName || !$resource->familyName || !$resource->email) { + throw ResourceValidityException::trigger(ResourceValidityException::ERROR_REQUIRED, ['givenName', 'familyName', 'email'], $resource); + } + + return $resource; + } +} diff --git a/version/207/class/Checkout/Order/OrderLine.php b/version/207/class/Checkout/Order/OrderLine.php new file mode 100644 index 0000000..757edf7 --- /dev/null +++ b/version/207/class/Checkout/Order/OrderLine.php @@ -0,0 +1,237 @@ +totalAmount->value; + } + if (abs($sum - (float)$amount->value) > 0) { + $diff = (round((float)$amount->value - $sum, 2)); + if ($diff !== 0.0) { + $line = new self(); + $line->type = $diff > 0 ? OrderLineType::TYPE_SURCHARGE : OrderLineType::TYPE_DISCOUNT; + // TODO: Translation needed? + $line->name = 'Rundungsausgleich'; + $line->quantity = 1; + $line->unitPrice = Amount::factory($diff, $currency); + $line->totalAmount = Amount::factory($diff, $currency); + $line->vatRate = '0.00'; + $line->vatAmount = Amount::factory(0, $currency); + + return $line; + } + } + + return null; + } + + /** + * @param Bestellung $oBestellung + * @return OrderLine + */ + public static function getCredit(Bestellung $oBestellung) + { + $line = new self(); + $line->type = OrderLineType::TYPE_STORE_CREDIT; + $line->name = 'Guthaben'; + $line->quantity = 1; + // TODO: check currency of Guthaben + $line->unitPrice = Amount::factory($oBestellung->fGuthaben, $oBestellung->Waehrung->cISO); + $line->totalAmount = $line->unitPrice; + $line->vatRate = '0.00'; + $line->vatAmount = Amount::factory(0, $oBestellung->Waehrung->cISO); + + return $line; + } + + /** + * @param stdClass|WarenkorbPos $oPosition + * @param null $currency + * @return OrderLine + */ + public static function factory($oPosition, $currency = null) + { + if (!$oPosition) { + throw new RuntimeException('$oPosition invalid:', print_r($oPosition, 1)); + } + + $resource = new static(); + + $resource->fill($oPosition, $currency); + + // Validity Check + if ( + !$resource->name || !$resource->quantity || !$resource->unitPrice || !$resource->totalAmount + || !$resource->vatRate || !$resource->vatAmount + ) { + throw ResourceValidityException::trigger( + ResourceValidityException::ERROR_REQUIRED, + ['name', 'quantity', 'unitPrice', 'totalAmount', 'vatRate', 'vatAmount'], + $resource + ); + } + + return $resource; + } + + /** + * @param stdClass|WarenkorbPos $oPosition + * @param null|stdClass $currency + * @return $this + * @todo Setting for Fraction handling needed? + */ + protected function fill($oPosition, $currency = null) + { + if (!$currency) { + $currency = Amount::FallbackCurrency(); + } + + $isKupon = (int)$oPosition->nPosTyp === (int)C_WARENKORBPOS_TYP_KUPON; + $isFrac = fmod($oPosition->nAnzahl, 1) !== 0.0; + + // Kupon? set vatRate to 0 and adjust netto + $vatRate = $isKupon ? 0 : (float)$oPosition->fMwSt / 100; + $netto = $isKupon ? round($oPosition->fPreis * (1 + $vatRate), 4) : round($oPosition->fPreis, 4); + + // Fraction? transform, as it were 1, and set quantity to 1 + $netto = round(($isFrac ? $netto * (float)$oPosition->nAnzahl : $netto) * $currency->fFaktor, 4); + $this->quantity = $isFrac ? 1 : (int)$oPosition->nAnzahl; + + // Fraction? include quantity and unit in name + $this->name = $isFrac ? sprintf('%s (%.2f %s)', $oPosition->cName, (float)$oPosition->nAnzahl, $oPosition->cEinheit) : $oPosition->cName; + if (!$this->name) { + $this->name = '(null)'; + } + $this->mapType($oPosition->nPosTyp, $netto > 0); + + //$unitPriceNetto = round(($currency->fFaktor * $netto), 4); + + $this->unitPrice = Amount::factory(round($netto * (1 + $vatRate), 2), $currency->cISO, false); + $this->totalAmount = Amount::factory(round($this->quantity * $this->unitPrice->value, 2), $currency->cISO, false); + + $this->vatRate = number_format($vatRate * 100, 2); + $this->vatAmount = Amount::factory(round($this->totalAmount->value - ($this->totalAmount->value / (1 + $vatRate)), 2), $currency->cISO, false); + + $metadata = []; + + // Is Artikel ? + if (isset($oPosition->Artikel)) { + $this->sku = $oPosition->Artikel->cArtNr; + $metadata['kArtikel'] = $oPosition->kArtikel; + if ($oPosition->cUnique !== '') { + $metadata['cUnique'] = utf8_encode($oPosition->cUnique); + } + } + + if (isset($oPosition->WarenkorbPosEigenschaftArr) && is_array($oPosition->WarenkorbPosEigenschaftArr) && count($oPosition->WarenkorbPosEigenschaftArr)) { + $metadata['properties'] = []; + /** @var WarenkorbPosEigenschaft $warenkorbPosEigenschaft */ + foreach ($oPosition->WarenkorbPosEigenschaftArr as $warenkorbPosEigenschaft) { + $metadata['properties'][] = [ + 'kEigenschaft' => $warenkorbPosEigenschaft->kEigenschaft, + 'kEigenschaftWert' => $warenkorbPosEigenschaft->kEigenschaftWert, + 'name' => utf8_encode($warenkorbPosEigenschaft->cEigenschaftName), + 'value' => utf8_encode($warenkorbPosEigenschaft->cEigenschaftWertName), + ]; + if (strlen(json_encode($metadata)) > 1000) { + array_pop($metadata['properties']); + + break; + } + } + } + if (json_encode($metadata) !== false) { + $this->metadata = $metadata; + } + + return $this; + } + + /** + * @param $nPosTyp + * @param $positive + * @return OrderLine + */ + protected function mapType($nPosTyp, $positive) + { + switch ($nPosTyp) { + case C_WARENKORBPOS_TYP_ARTIKEL: + case C_WARENKORBPOS_TYP_GRATISGESCHENK: + // TODO: digital / Download Artikel? + $this->type = OrderLineType::TYPE_PHYSICAL; + + return $this; + + case C_WARENKORBPOS_TYP_VERSANDPOS: + $this->type = OrderLineType::TYPE_SHIPPING_FEE; + + return $this; + + case C_WARENKORBPOS_TYP_GUTSCHEIN: + case C_WARENKORBPOS_TYP_KUPON: + case C_WARENKORBPOS_TYP_NEUKUNDENKUPON: + $this->type = OrderLineType::TYPE_DISCOUNT; + + return $this; + + case C_WARENKORBPOS_TYP_VERPACKUNG: + case C_WARENKORBPOS_TYP_VERSANDZUSCHLAG: + case C_WARENKORBPOS_TYP_ZAHLUNGSART: + case C_WARENKORBPOS_TYP_VERSAND_ARTIKELABHAENGIG: + case C_WARENKORBPOS_TYP_NACHNAHMEGEBUEHR: + $this->type = OrderLineType::TYPE_SURCHARGE; + + return $this; + + default: + $this->type = $positive ? OrderLineType::TYPE_SURCHARGE : OrderLineType::TYPE_DISCOUNT; + + return $this; + } + } +} diff --git a/version/207/class/Checkout/OrderCheckout.php b/version/207/class/Checkout/OrderCheckout.php new file mode 100644 index 0000000..1d61b6d --- /dev/null +++ b/version/207/class/Checkout/OrderCheckout.php @@ -0,0 +1,406 @@ +getMollie()->status !== OrderStatus::STATUS_AUTHORIZED && $checkout->getMollie()->status !== OrderStatus::STATUS_SHIPPING) { + throw new RuntimeException('Nur autorisierte Zahlungen können erfasst werden!'); + } + $shipment = $checkout->API()->Client()->shipments->createFor($checkout->getMollie(), ['lines' => []]); + $checkout->Log(sprintf('Bestellung wurde manuell erfasst/versandt: %s', $shipment->id)); + + return $shipment->id; + } + + /** + * @param false $force + * @return null|Order + */ + public function getMollie($force = false) + { + if ($force || (!$this->order && $this->getModel()->kID)) { + try { + $this->order = $this->API()->Client()->orders->get($this->getModel()->kID, ['embed' => 'payments,shipments,refunds']); + } catch (Exception $e) { + throw new RuntimeException(sprintf('Mollie-Order \'%s\' konnte nicht geladen werden: %s', $this->getModel()->kID, $e->getMessage())); + } + } + + return $this->order; + } + + /** + * @param OrderCheckout $checkout + * @throws ApiException + * @return Order + */ + public static function cancel($checkout) + { + if (!$checkout->getMollie() || !$checkout->getMollie()->isCancelable) { + throw new RuntimeException('Bestellung kann nicht abgebrochen werden.'); + } + $order = $checkout->getMollie()->cancel(); + $checkout->Log('Bestellung wurde manuell abgebrochen.'); + + return $order; + } + + /** + * @throws Exception + * @return array + */ + public function getShipments() + { + $shipments = []; + $lieferschien_arr = Shop::DB()->executeQueryPrepared('SELECT kLieferschein FROM tlieferschein WHERE kInetBestellung = :kBestellung', [ + ':kBestellung' => $this->getBestellung()->kBestellung + ], 2); + + foreach ($lieferschien_arr as $lieferschein) { + $shipments[] = new Shipment($lieferschein->kLieferschein, $this); + } + + return $shipments; + } + + /** + * @param mixed $force + * @throws ApiException + * @return string + */ + public function cancelOrRefund($force = false) + { + if (!$this->getMollie()) { + throw new RuntimeException('Mollie-Order konnte nicht geladen werden: ' . $this->getModel()->kID); + } + if ($force || (int)$this->getBestellung()->cStatus === BESTELLUNG_STATUS_STORNO) { + if ($this->getMollie()->isCancelable) { + $res = $this->getMollie()->cancel(); + $result = 'Order cancelled, Status: ' . $res->status; + } else { + $res = $this->getMollie()->refundAll(); + $result = 'Order Refund initiiert, Status: ' . $res->status; + } + $this->PaymentMethod()->Log('OrderCheckout::cancelOrRefund: ' . $result, $this->LogData()); + + return $result; + } + + throw new RuntimeException('Bestellung ist derzeit nicht storniert, Status: ' . $this->getBestellung()->cStatus); + } + + /** + * @param array $paymentOptions + * @return Order + */ + public function create(array $paymentOptions = []) + { + if ($this->getModel()->kID) { + try { + $this->order = $this->API()->Client()->orders->get($this->getModel()->kID, ['embed' => 'payments']); + if (in_array($this->order->status, [OrderStatus::STATUS_COMPLETED, OrderStatus::STATUS_PAID, OrderStatus::STATUS_AUTHORIZED, OrderStatus::STATUS_PENDING], true)) { + $this->handleNotification(); + + throw new RuntimeException(self::Plugin()->oPluginSprachvariableAssoc_arr['errAlreadyPaid']); + } + if ($this->order->status === OrderStatus::STATUS_CREATED) { + if ($this->order->payments()) { + /** @var Payment $payment */ + foreach ($this->order->payments() as $payment) { + if ($payment->status === PaymentStatus::STATUS_OPEN) { + $this->setPayment($payment); + + break; + } + } + } + if (!$this->getPayment()) { + $this->setPayment($this->API()->Client()->orderPayments->createForId($this->getModel()->kID, $paymentOptions)); + } + $this->updateModel()->saveModel(); + + return $this->getMollie(true); + } + } catch (RuntimeException $e) { + throw $e; + } catch (Exception $e) { + $this->Log(sprintf("OrderCheckout::create: Letzte Order '%s' konnte nicht geladen werden: %s, versuche neue zu erstellen.", $this->getModel()->kID, $e->getMessage()), LOGLEVEL_ERROR); + } + } + + try { + $req = $this->loadRequest($paymentOptions)->jsonSerialize(); + $this->order = $this->API()->Client()->orders->create($req); + $this->Log(sprintf("Order für '%s' wurde erfolgreich angelegt: %s", $this->getBestellung()->cBestellNr, $this->order->id)); + $this->updateModel()->saveModel(); + + return $this->order; + } catch (Exception $e) { + $this->Log(sprintf("OrderCheckout::create: Neue Order '%s' konnte nicht erstellt werden: %s.", $this->getBestellung()->cBestellNr, $e->getMessage()), LOGLEVEL_ERROR); + + throw new RuntimeException(sprintf("Order für '%s' konnte nicht angelegt werden: %s", $this->getBestellung()->cBestellNr, $e->getMessage())); + } + } + + /** + * @param mixed $search + * @return null|Payment + */ + public function getPayment($search = false) + { + if (!$this->_payment && $search && $this->getMollie()) { + foreach ($this->getMollie()->payments() as $payment) { + if ( + in_array($payment->status, [ + PaymentStatus::STATUS_AUTHORIZED, + PaymentStatus::STATUS_PAID, + PaymentStatus::STATUS_PENDING, + ], true) + ) { + $this->_payment = $payment; + + break; + } + } + } + + return $this->_payment; + } + + /** + * @param $payment + * @return $this + */ + public function setPayment($payment) + { + $this->_payment = $payment; + + return $this; + } + + /** + * @return $this|OrderCheckout + */ + public function updateModel() + { + parent::updateModel(); + + if (!$this->getPayment() && $this->getMollie() && $this->getMollie()->payments()) { + /** @var Payment $payment */ + foreach ($this->getMollie()->payments() as $payment) { + if (in_array($payment->status, [PaymentStatus::STATUS_OPEN, PaymentStatus::STATUS_PENDING, PaymentStatus::STATUS_AUTHORIZED, PaymentStatus::STATUS_PAID], true)) { + $this->setPayment($payment); + + break; + } + } + } + if ($this->getPayment()) { + $this->getModel()->cTransactionId = $this->getPayment()->id; + } + if ($this->getMollie()) { + $this->getModel()->cCheckoutURL = $this->getMollie()->getCheckoutUrl(); + $this->getModel()->cWebhookURL = $this->getMollie()->webhookUrl; + $this->getModel()->cRedirectURL = $this->getMollie()->redirectUrl; + } + + return $this; + } + + /** + * @param array $options + * @return $this|OrderCheckout + */ + public function loadRequest(&$options = []) + { + parent::loadRequest($options); + + $this->orderNumber = $this->getBestellung()->cBestellNr; + + $this->billingAddress = Address::factory($this->getBestellung()->oRechnungsadresse); + if ($this->getBestellung()->Lieferadresse !== null) { + if (!$this->getBestellung()->Lieferadresse->cMail) { + $this->getBestellung()->Lieferadresse->cMail = $this->getBestellung()->oRechnungsadresse->cMail; + } + $this->shippingAddress = Address::factory($this->getBestellung()->Lieferadresse); + } + + if ( + !empty(Session::getInstance()->Customer()->dGeburtstag) + && Session::getInstance()->Customer()->dGeburtstag !== '0000-00-00' + && preg_match('/^\d{4}-\d{2}-\d{2}$/', trim(Session::getInstance()->Customer()->dGeburtstag)) + ) { + $this->consumerDateOfBirth = trim(Session::getInstance()->Customer()->dGeburtstag); + } + + $lines = []; + foreach ($this->getBestellung()->Positionen as $oPosition) { + $lines[] = OrderLine::factory($oPosition, $this->getBestellung()->Waehrung); + } + + if ($this->getBestellung()->GuthabenNutzen && $this->getBestellung()->fGuthaben > 0) { + $lines[] = OrderLine::getCredit($this->getBestellung()); + } + + if ($comp = OrderLine::getRoundingCompensation($lines, $this->amount, $this->getBestellung()->Waehrung->cISO)) { + $lines[] = $comp; + } + $this->lines = $lines; + + if ($dueDays = $this->PaymentMethod()->getExpiryDays()) { + try { + // #145 + //$max = $this->method && strpos($this->method, 'klarna') !== false ? 28 : 100; + $date = new DateTime(sprintf('+%d DAYS', $dueDays), new DateTimeZone('UTC')); + $this->expiresAt = $date->format('Y-m-d'); + } catch (Exception $e) { + $this->Log($e->getMessage(), LOGLEVEL_ERROR); + } + } + + $this->payment = $options; + + return $this; + } + + /** + * @return null|object + */ + public function getIncomingPayment() + { + if (!$this->getMollie(true)) { + return null; + } + + $cHinweis = sprintf('%s / %s', $this->getMollie()->id, $this->getPayment(true)->id); + if (Helper::getSetting('wawiPaymentID') === 'ord') { + $cHinweis = $this->getMollie()->id; + } elseif (Helper::getSetting('wawiPaymentID') === 'tr') { + $cHinweis = $this->getPayment(true)->id; + } + + + /** @var Payment $payment */ + /** @noinspection NullPointerExceptionInspection */ + foreach ($this->getMollie()->payments() as $payment) { + if ( + in_array( + $payment->status, + [PaymentStatus::STATUS_AUTHORIZED, PaymentStatus::STATUS_PAID], + true + ) + ) { + $this->setPayment($payment); + $data = (object)[ + 'fBetrag' => (float)$payment->amount->value, + 'cISO' => $payment->amount->currency, + 'cZahler' => $payment->details->paypalPayerId ?: $payment->customerId, + 'cHinweis' => $payment->details->paypalReference ?: $cHinweis, + ]; + if (isset($payment->details, $payment->details->paypalFee)) { + $data->fZahlungsgebuehr = $payment->details->paypalFee->value; + } + + return $data; + } + } + + return null; + } + + /** + * @return $this + */ + protected function updateOrderNumber() + { + try { + if ($this->getMollie()) { + $this->getMollie()->orderNumber = $this->getBestellung()->cBestellNr; + $this->getMollie()->webhookUrl = Shop::getURL() . '/?mollie=1'; + $this->getMollie()->update(); + } + if ($this->getModel()->cTransactionId) { + $this->API()->Client()->payments->update($this->getModel()->cTransactionId, [ + 'description' => $this->getDescription() + ]); + } + } catch (Exception $e) { + $this->Log('OrderCheckout::updateOrderNumber:' . $e->getMessage(), LOGLEVEL_ERROR); + } + + return $this; + } + + /** + * @param Order $model + * @return $this|AbstractCheckout + */ + protected function setMollie($model) + { + if ($model instanceof Order) { + $this->order = $model; + } + + return $this; + } +} diff --git a/version/207/class/Checkout/Payment/Address.php b/version/207/class/Checkout/Payment/Address.php new file mode 100644 index 0000000..468a08a --- /dev/null +++ b/version/207/class/Checkout/Payment/Address.php @@ -0,0 +1,53 @@ +streetAndNumber = $address->cStrasse . ' ' . $address->cHausnummer; + $resource->postalCode = $address->cPLZ; + $resource->city = $address->cOrt; + $resource->country = $address->cLand; + + if ( + isset($address->cAdressZusatz) + && trim($address->cAdressZusatz) !== '' + ) { + $resource->streetAdditional = trim($address->cAdressZusatz); + } + + // Validity-Check + // TODO: Check for valid Country Code? + // TODO: Check PostalCode requirement Country? + if (!$resource->streetAndNumber || !$resource->city || !$resource->country) { + throw ResourceValidityException::trigger(ResourceValidityException::ERROR_REQUIRED, ['streetAndNumber', 'city', 'country'], $resource); + } + + return $resource; + } +} diff --git a/version/207/class/Checkout/Payment/Amount.php b/version/207/class/Checkout/Payment/Amount.php new file mode 100644 index 0000000..c11c64c --- /dev/null +++ b/version/207/class/Checkout/Payment/Amount.php @@ -0,0 +1,75 @@ + true [5 Rappen Rounding]) + * @return Amount + */ + public static function factory($value, $currency = null, $useRounding = false) + { + if (!$currency) { + $currency = static::FallbackCurrency()->cISO; + } + + $resource = new static(); + + $resource->currency = $currency; + //$resource->value = number_format(round($useRounding ? $resource->round($value * (float)$currency->fFaktor) : $value * (float)$currency->fFaktor, 2), 2, '.', ''); + $resource->value = number_format(round($useRounding ? $resource->round($value) : $value, 2), 2, '.', ''); + + // Validity Check + // TODO: Check ISO Code? + // TODO: Check Value + if (!$resource->currency || !$resource->value) { + throw ResourceValidityException::trigger(ResourceValidityException::ERROR_REQUIRED, ['currency', 'value'], $resource); + } + + return $resource; + } + + /** + * @return stdClass + */ + public static function FallbackCurrency() + { + return isset($_SESSION['Waehrung']) ? $_SESSION['Waehrung'] : Shop::DB()->select('twaehrung', 'cStandard', 'Y'); + } + + /** + * Check if 5 Rappen rounding is necessary + * + * @param mixed $value + * @return float + */ + protected function round($value) + { + $conf = Shop::getSettings([CONF_KAUFABWICKLUNG]); + if (isset($conf['kaufabwicklung']['bestellabschluss_runden5']) && (int)$conf['kaufabwicklung']['bestellabschluss_runden5'] === 1) { + $value = round($value * 20) / 20; + } + + return $value; + } +} diff --git a/version/207/class/Checkout/PaymentCheckout.php b/version/207/class/Checkout/PaymentCheckout.php index e69de29..568be4e 100644 --- a/version/207/class/Checkout/PaymentCheckout.php +++ b/version/207/class/Checkout/PaymentCheckout.php @@ -0,0 +1,235 @@ +getMollie()->isCancelable) { + throw new RuntimeException('Zahlung kann nicht abgebrochen werden.'); + } + $payment = $checkout->API()->Client()->payments->cancel($checkout->getMollie()->id); + $checkout->Log('Zahlung wurde manuell abgebrochen.'); + + return $payment; + } + + /** + * @param false $force + * @return null|Payment + */ + public function getMollie($force = false) + { + if ($force || (!$this->getPayment() && $this->getModel()->kID)) { + try { + $this->setPayment($this->API()->Client()->payments->get($this->getModel()->kID, ['embed' => 'refunds'])); + } catch (Exception $e) { + throw new RuntimeException('Mollie-Payment konnte nicht geladen werden: ' . $e->getMessage()); + } + } + + return $this->getPayment(); + } + + /** + * @return null|Payment + */ + public function getPayment() + { + return $this->_payment; + } + + /** + * @param $payment + * @return $this + */ + public function setPayment($payment) + { + $this->_payment = $payment; + + return $this; + } + + /** + * @param mixed $force + * @throws ApiException + * @throws IncompatiblePlatform + * @return string + */ + public function cancelOrRefund($force = false) + { + if (!$this->getMollie()) { + throw new RuntimeException('Mollie-Order konnte nicht geladen werden: ' . $this->getModel()->kID); + } + if ($force || (int)$this->getBestellung()->cStatus === BESTELLUNG_STATUS_STORNO) { + if ($this->getMollie()->isCancelable) { + $res = $this->API()->Client()->payments->cancel($this->getMollie()->id); + $result = 'Payment cancelled, Status: ' . $res->status; + } else { + $res = $this->API()->Client()->payments->refund($this->getMollie(), ['amount' => $this->getMollie()->amount]); + $result = 'Payment Refund initiiert, Status: ' . $res->status; + } + $this->PaymentMethod()->Log('PaymentCheckout::cancelOrRefund: ' . $result, $this->LogData()); + + return $result; + } + + throw new RuntimeException('Bestellung ist derzeit nicht storniert, Status: ' . $this->getBestellung()->cStatus); + } + + /** + * @param array $paymentOptions + * @return Payment + */ + public function create(array $paymentOptions = []) + { + if ($this->getModel()->kID) { + try { + $this->setPayment($this->API()->Client()->payments->get($this->getModel()->kID)); + if ($this->getPayment()->status === PaymentStatus::STATUS_PAID) { + throw new RuntimeException(self::Plugin()->oPluginSprachvariableAssoc_arr['errAlreadyPaid']); + } + if ($this->getPayment()->status === PaymentStatus::STATUS_OPEN) { + $this->updateModel()->saveModel(); + + return $this->getPayment(); + } + } catch (RuntimeException $e) { + //$this->Log(sprintf("PaymentCheckout::create: Letzte Transaktion '%s' konnte nicht geladen werden: %s", $this->getModel()->kID, $e->getMessage()), LOGLEVEL_ERROR); + throw $e; + } catch (Exception $e) { + $this->Log(sprintf("PaymentCheckout::create: Letzte Transaktion '%s' konnte nicht geladen werden: %s, versuche neue zu erstellen.", $this->getModel()->kID, $e->getMessage()), LOGLEVEL_ERROR); + } + } + + try { + $req = $this->loadRequest($paymentOptions)->jsonSerialize(); + $this->setPayment($this->API()->Client()->payments->create($req)); + $this->Log(sprintf("Payment für '%s' wurde erfolgreich angelegt: %s", $this->getBestellung()->cBestellNr, $this->getPayment()->id)); + $this->updateModel()->saveModel(); + + return $this->getPayment(); + } catch (Exception $e) { + $this->Log(sprintf("PaymentCheckout::create: Neue Transaktion für '%s' konnte nicht erstellt werden: %s.", $this->getBestellung()->cBestellNr, $e->getMessage()), LOGLEVEL_ERROR); + + throw new RuntimeException(sprintf('Mollie-Payment \'%s\' konnte nicht geladen werden: %s', $this->getBestellung()->cBestellNr, $e->getMessage())); + } + } + + /** + * @param array $options + * @return $this|PaymentCheckout + */ + public function loadRequest(&$options = []) + { + parent::loadRequest($options); + + foreach ($options as $key => $value) { + $this->$key = $value; + } + + + $this->description = $this->getDescription(); + + return $this; + } + + + + /** + * @return null|object + */ + public function getIncomingPayment() + { + if (!$this->getMollie()) { + return null; + } + + if (in_array($this->getMollie()->status, [PaymentStatus::STATUS_AUTHORIZED, PaymentStatus::STATUS_PAID], true)) { + $data = []; + $data['fBetrag'] = (float)$this->getMollie()->amount->value; + $data['cISO'] = $this->getMollie()->amount->currency; + $data['cZahler'] = $this->getMollie()->details->paypalPayerId ?: $this->getMollie()->customerId; + $data['cHinweis'] = $this->getMollie()->details->paypalReference ?: $this->getMollie()->id; + if (isset($this->getMollie()->details, $this->getMollie()->details->paypalFee)) { + $data['fZahlungsgebuehr'] = $this->getMollie()->details->paypalFee->value; + } + + return (object)$data; + } + + return null; + } + + /** + * @param Payment $model + * @return $this|AbstractCheckout + */ + protected function setMollie($model) + { + if ($model instanceof Payment) { + $this->setPayment($model); + } + + return $this; + } + + /** + * @return $this + */ + protected function updateOrderNumber() + { + try { + if ($this->getMollie()) { + $this->getMollie()->description = $this->getDescription(); + $this->getMollie()->webhookUrl = Shop::getURL() . '/?mollie=1'; + $this->getMollie()->update(); + } + } catch (Exception $e) { + $this->Log('OrderCheckout::updateOrderNumber:' . $e->getMessage(), LOGLEVEL_ERROR); + } + + return $this; + } +} diff --git a/version/207/class/ExclusiveLock.php b/version/207/class/ExclusiveLock.php index e69de29..c7b834d 100644 --- a/version/207/class/ExclusiveLock.php +++ b/version/207/class/ExclusiveLock.php @@ -0,0 +1,70 @@ +key = $key; + $this->path = rtrim(realpath($path), '/') . '/'; + if (!is_dir($path) || !is_writable($path)) { + throw new RuntimeException("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", 'wb+'); + } + + + public function __destruct() + { + if ($this->own === true) { + $this->unlock(); + } + } + + /** @noinspection ForgottenDebugOutputInspection */ + 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; + } + 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 + } + + public function lock() + { + if (!flock($this->file, LOCK_EX | LOCK_NB)) { //failed + return false; + } + fwrite($this->file, 'Locked - ' . microtime(true) . "\n"); + fflush($this->file); + + $this->own = true; + + return true; // success + } +} diff --git a/version/207/class/Helper.php b/version/207/class/Helper.php index e69de29..b03874f 100644 --- a/version/207/class/Helper.php +++ b/version/207/class/Helper.php @@ -0,0 +1,363 @@ +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) && !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!'); + } + $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 + * @throws Exception + * @return mixed + */ + 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; + } + + 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 + * @throws SmartyException + * @return string + */ + 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 null|Plugin + */ + public static function oPlugin($force = false) + { + if ($force === true) { + self::$oPlugin = new Plugin(self::oPlugin()->kPlugin, true); + } elseif (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 = []; + @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([CONF_EMAILS]); + $mail = trim($settings['emails']['email_master_absender']); + if ($e === true && $mail != '') { + $mail = base64_encode($mail); + $eMail = ''; + foreach (str_split($mail) 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/207/class/Hook/AbstractHook.php b/version/207/class/Hook/AbstractHook.php new file mode 100644 index 0000000..561e401 --- /dev/null +++ b/version/207/class/Hook/AbstractHook.php @@ -0,0 +1,15 @@ +kPlugin)) + && array_key_exists($key, $_SESSION) && !array_key_exists('Zahlungsart', $_SESSION) + ) { + unset($_SESSION[$key]); + } + + if (!array_key_exists('ws_mollie_applepay_available', $_SESSION)) { + // TODO DOKU + if (defined('MOLLIE_APPLEPAY_TPL') && MOLLIE_APPLEPAY_TPL) { + Shop::Smarty()->assign('applePayCheckURL', json_encode(self::Plugin()->cFrontendPfadURLSSL . 'applepay.php')); + pq('body')->append(Shop::Smarty()->fetch(self::Plugin()->cFrontendPfad . 'tpl/applepay.tpl')); + } else { + $checkUrl = self::Plugin()->cFrontendPfadURLSSL . 'applepay.php'; + pq('head')->append(""); + } + } + } + + /** + * @return bool + */ + public static function isAvailable() + { + if (array_key_exists('ws_mollie_applepay_available', $_SESSION)) { + return $_SESSION['ws_mollie_applepay_available']; + } + + return false; + } + + /** + * @param $status bool + */ + public static function setAvailable($status) + { + $_SESSION['ws_mollie_applepay_available'] = $status; + } +} diff --git a/version/207/class/Hook/Checkbox.php b/version/207/class/Hook/Checkbox.php new file mode 100644 index 0000000..87c4334 --- /dev/null +++ b/version/207/class/Hook/Checkbox.php @@ -0,0 +1,60 @@ +cModulId, 'kPlugin_' . self::Plugin()->kPlugin . '_') === false) { + return; + } + + if (array_key_exists('nAnzeigeOrt', $args_arr) && $args_arr['nAnzeigeOrt'] === CHECKBOX_ORT_BESTELLABSCHLUSS && Session::getInstance()->Customer()->nRegistriert) { + $mCustomer = Customer::fromID(Session::getInstance()->Customer()->kKunde, 'kKunde'); + + if ($mCustomer->customerId) { + return; + } + + $checkbox = new \CheckBox(); + $checkbox->kLink = 0; + $checkbox->kCheckBox = -1; + $checkbox->kCheckBoxFunktion = 0; + $checkbox->cName = 'MOLLIE SAVE CUSTOMER'; + $checkbox->cKundengruppe = ';1;'; + $checkbox->cAnzeigeOrt = ';2;'; + $checkbox->nAktiv = 1; + $checkbox->nPflicht = 0; + $checkbox->nLogging = 0; + $checkbox->nSort = 999; + $checkbox->dErstellt = date('Y-m-d H:i:s'); + $checkbox->oCheckBoxSprache_arr = []; + + $langs = gibAlleSprachen(); + foreach ($langs as $lang) { + $checkbox->oCheckBoxSprache_arr[$lang->kSprache] = (object)[ + 'cText' => self::Plugin()->oPluginSprachvariableAssoc_arr['checkboxText'], + 'cBeschreibung' => self::Plugin()->oPluginSprachvariableAssoc_arr['checkboxDescr'], + 'kSprache' => $lang->kSprache, + 'kCheckbox' => -1 + ]; + } + + $checkbox->kKundengruppe_arr = [Session::getInstance()->Customer()->kKundengruppe]; + $checkbox->kAnzeigeOrt_arr = [CHECKBOX_ORT_BESTELLABSCHLUSS]; + $checkbox->cID = 'mollie_create_customer'; + $checkbox->cLink = ''; + + $args_arr['oCheckBox_arr'][] = $checkbox; + } + } +} diff --git a/version/207/class/Hook/Queue.php b/version/207/class/Hook/Queue.php new file mode 100644 index 0000000..06149b7 --- /dev/null +++ b/version/207/class/Hook/Queue.php @@ -0,0 +1,140 @@ +nWaehrendBestellung === 0 + && $args_arr['oBestellung']->fGesamtsumme > 0 + && self::Plugin()->oPluginEinstellungAssoc_arr['onlyPaid'] === 'Y' + && AbstractCheckout::isMollie((int)$args_arr['oBestellung']->kZahlungsart, true) + ) { + $args_arr['oBestellung']->cAbgeholt = 'Y'; + Jtllog::writeLog('Switch cAbgeholt for kBestellung: ' . print_r($args_arr['oBestellung']->kBestellung, 1), JTLLOG_LEVEL_NOTICE); + } + } + + /** + * @param array $args_arr + */ + public static function xmlBestellStatus(array $args_arr) + { + if (AbstractCheckout::isMollie((int)$args_arr['oBestellung']->kBestellung)) { + self::saveToQueue(HOOK_BESTELLUNGEN_XML_BESTELLSTATUS . ':' . (int)$args_arr['oBestellung']->kBestellung, [ + 'kBestellung' => $args_arr['oBestellung']->kBestellung, + 'status' => (int)$args_arr['status'] + ]); + } + } + + /** + * @param $hook + * @param $args_arr + * @param string $type + * @return bool + */ + public static function saveToQueue($hook, $args_arr, $type = 'hook') + { + $mQueue = new QueueModel(); + $mQueue->cType = $type . ':' . $hook; + $mQueue->cData = serialize($args_arr); + + try { + return $mQueue->save(); + } catch (Exception $e) { + Jtllog::writeLog('mollie::saveToQueue: ' . $e->getMessage() . ' - ' . print_r($args_arr, 1)); + + return false; + } + } + + /** + * @param array $args_arr + */ + public static function xmlBearbeiteStorno(array $args_arr) + { + if (AbstractCheckout::isMollie((int)$args_arr['oBestellung']->kBestellung)) { + self::saveToQueue(HOOK_BESTELLUNGEN_XML_BEARBEITESTORNO . ':' . $args_arr['oBestellung']->kBestellung, ['kBestellung' => $args_arr['oBestellung']->kBestellung]); + } + } + + /** + * + */ + public static function headPostGet() + { + if (array_key_exists('mollie', $_REQUEST) && (int)$_REQUEST['mollie'] === 1 && array_key_exists('id', $_REQUEST)) { + if (array_key_exists('hash', $_REQUEST) && $hash = trim(StringHandler::htmlentities(StringHandler::filterXSS($_REQUEST['hash'])), '_')) { + AbstractCheckout::finalizeOrder($hash, $_REQUEST['id'], array_key_exists('test', $_REQUEST)); + } else { + self::saveToQueue($_REQUEST['id'], $_REQUEST['id'], 'webhook'); + } + exit(); + } + if (array_key_exists('m_pay', $_REQUEST)) { + try { + $raw = Shop::DB()->executeQueryPrepared('SELECT kID FROM `xplugin_ws_mollie_payments` WHERE dReminder IS NOT NULL AND MD5(CONCAT(kID, "-", kBestellung)) = :md5', [ + ':md5' => $_REQUEST['m_pay'] + ], 1); + + if (!$raw) { + throw new RuntimeException(self::Plugin()->oPluginSprachvariableAssoc_arr['errOrderNotFound']); + } + + if (strpos($raw->cOrderId, 'tr_') === 0) { + $checkout = PaymentCheckout::fromID($raw->kID); + } else { + $checkout = OrderCheckout::fromID($raw->kID); + } + $checkout->getMollie(true); + $checkout->updateModel()->saveModel(); + + if ( + ($checkout->getBestellung()->dBezahltDatum !== null && $checkout->getBestellung()->dBezahltDatum !== '0000-00-00') + || in_array($checkout->getModel()->cStatus, ['completed', 'paid', 'authorized', 'pending']) + ) { + throw new RuntimeException(self::Plugin()->oPluginSprachvariableAssoc_arr['errAlreadyPaid']); + } + + $options = []; + if (self::Plugin()->oPluginEinstellungAssoc_arr['resetMethod'] !== 'Y') { + $options['method'] = $checkout->getModel()->cMethod; + } + + $mollie = $checkout->create($options); // Order::repayOrder($orderModel->getOrderId(), $options, $api); + $url = $mollie->getCheckoutUrl(); + + header('Location: ' . $url); + exit(); + } catch (RuntimeException $e) { + // TODO Workaround? + //$alertHelper = Shop::Container()->getAlertService(); + //$alertHelper->addAlert(Alert::TYPE_ERROR, $e->getMessage(), 'mollie_repay', ['dismissable' => true]); + } catch (Exception $e) { + Jtllog::writeLog('mollie:repay:error: ' . $e->getMessage() . "\n" . print_r($_REQUEST, 1)); + } + } + } +} diff --git a/version/207/class/Model/AbstractModel.php b/version/207/class/Model/AbstractModel.php new file mode 100644 index 0000000..38a4ab5 --- /dev/null +++ b/version/207/class/Model/AbstractModel.php @@ -0,0 +1,110 @@ +data = $data; + if (!$data) { + $this->new = true; + } + } + + /** + * @param $id + * @param string $col + * @param false $failIfNotExists + * @return static + */ + public static function fromID($id, $col = 'kID', $failIfNotExists = false) + { + if ( + $payment = Shop::DB()->executeQueryPrepared( + 'SELECT * FROM ' . static::TABLE . " WHERE `$col` = :id", + [':id' => $id], + 1 + ) + ) { + return new static($payment); + } + if ($failIfNotExists) { + throw new RuntimeException(sprintf('Model %s in %s nicht gefunden!', $id, static::TABLE)); + } + + return new static(); + } + + /** + * @return null|mixed|stdClass + */ + public function jsonSerialize() + { + return $this->data; + } + + public function __get($name) + { + if (isset($this->data->$name)) { + return $this->data->$name; + } + + return null; + } + + public function __set($name, $value) + { + if (!$this->data) { + $this->data = new stdClass(); + } + $this->data->$name = $value; + } + + public function __isset($name) + { + return isset($this->data->$name); + } + + /** + * @return bool + */ + public function save() + { + if (!$this->data) { + throw new RuntimeException('No Data to save!'); + } + + if ($this->new) { + Shop::DB()->insertRow(static::TABLE, $this->data); + $this->new = false; + + return true; + } + Shop::DB()->updateRow(static::TABLE, static::PRIMARY, $this->data->{static::PRIMARY}, $this->data); + + return true; + } +} diff --git a/version/207/class/Model/Customer.php b/version/207/class/Model/Customer.php new file mode 100644 index 0000000..3d02409 --- /dev/null +++ b/version/207/class/Model/Customer.php @@ -0,0 +1,21 @@ +dCreatedAt) { + $this->dCreatedAt = date('Y-m-d H:i:s'); + } + if ($this->new) { + $this->dReminder = self::NULL; + } + + return parent::save(); + } +} diff --git a/version/207/class/Model/Queue.php b/version/207/class/Model/Queue.php new file mode 100644 index 0000000..1509e50 --- /dev/null +++ b/version/207/class/Model/Queue.php @@ -0,0 +1,46 @@ +cResult = $result; + $this->dDone = $date ?: date('Y-m-d H:i:s'); + + return $this->save(); + } + + public function save() + { + if (!$this->dCreated) { + $this->dCreated = date('Y-m-d H:i:s'); + } + $this->dModified = date('Y-m-d H:i:s'); + + return parent::save(); + } +} diff --git a/version/207/class/Model/Shipment.php b/version/207/class/Model/Shipment.php new file mode 100644 index 0000000..91d93be --- /dev/null +++ b/version/207/class/Model/Shipment.php @@ -0,0 +1,29 @@ +executeQueryPrepared( + 'SELECT p.kBestellung, b.cStatus FROM xplugin_ws_mollie_payments p ' + . 'JOIN tbestellung b ON b.kBestellung = p.kBestellung ' + . "WHERE b.cAbgeholt = 'Y' AND NOT p.bSynced AND b.cStatus IN ('1', '2') AND p.dCreatedAt < NOW() - INTERVAL :d HOUR", + [':d' => $delay], + 2 + ); + + foreach ($open as $o) { + try { + $checkout = AbstractCheckout::fromBestellung($o->kBestellung); + $pm = $checkout->PaymentMethod(); + if ($pm::ALLOW_AUTO_STORNO && $pm::METHOD === $checkout->getMollie()->method) { + if ($checkout->getBestellung()->cAbgeholt === 'Y' && (bool)$checkout->getModel()->bSynced === false) { + if (!in_array($checkout->getMollie()->status, [OrderStatus::STATUS_PAID, OrderStatus::STATUS_COMPLETED, OrderStatus::STATUS_AUTHORIZED], true)) { + $checkout->storno(); + } else { + $checkout->Log(sprintf('AutoStorno: Bestellung bezahlt? %s - Method: %s', $checkout->getMollie()->status, $checkout->getMollie()->method), LOGLEVEL_ERROR); + } + } else { + $checkout->Log('AutoStorno: bereits zur WAWI synchronisiert.', LOGLEVEL_ERROR); + } + } + } catch (Exception $e) { + Helper::logExc($e); + } + } + + return true; + } + + /** + * @param int $limit + */ + public static function run($limit = 10) + { + foreach (self::getOpen($limit) as $todo) { + if (!self::lock($todo)) { + Jtllog::writeLog(sprintf('%s already locked since %s', $todo->kId, $todo->bLock ?: 'just now')); + + continue; + } + + if ((list($type, $id) = explode(':', $todo->cType))) { + try { + switch ($type) { + case 'webhook': + self::handleWebhook($id, $todo); + + break; + + case 'hook': + self::handleHook((int)$id, $todo); + + break; + } + } catch (Exception $e) { + Jtllog::writeLog($e->getMessage() . " ($type, $id)"); + $todo->done("{$e->getMessage()}\n{$e->getFile()}:{$e->getLine()}\n{$e->getTraceAsString()}"); + } + } + + self::unlock($todo); + } + } + + /** + * @param $limit + * @return Generator|QueueModel[] + * @noinspection PhpReturnDocTypeMismatchInspection + * @noinspection SqlResolve + */ + private static function getOpen($limit) + { + if (!defined('MOLLIE_HOOK_DELAY')) { + define('MOLLIE_HOOK_DELAY', 3); + } + $open = Shop::DB()->executeQueryPrepared(sprintf("SELECT * FROM %s WHERE (dDone IS NULL OR dDone = '0000-00-00 00:00:00') AND `bLock` IS NULL AND (cType LIKE 'webhook:%%' OR (cType LIKE 'hook:%%') AND dCreated < DATE_SUB(NOW(), INTERVAL " . (int)MOLLIE_HOOK_DELAY . ' MINUTE)) ORDER BY dCreated DESC LIMIT 0, :LIMIT;', QueueModel::TABLE), [ + ':LIMIT' => $limit + ], 2); + + foreach ($open as $_raw) { + yield new QueueModel($_raw); + } + } + + /** + * @param $todo + * @return bool + * @noinspection SqlResolve + */ + protected static function lock($todo) + { + return $todo->kId && Shop::DB()->executeQueryPrepared(sprintf('UPDATE %s SET `bLock` = NOW() WHERE `bLock` IS NULL AND kId = :kId', QueueModel::TABLE), [ + 'kId' => $todo->kId + ], 3) >= 1; + } + + /** + * @param $id + * @param QueueModel $todo + * @throws Exception + * @return bool + */ + protected static function handleWebhook($id, QueueModel $todo) + { + $checkout = AbstractCheckout::fromID($id); + if ($checkout->getBestellung()->kBestellung && $checkout->PaymentMethod()) { + $checkout->handleNotification(); + + return $todo->done('Status: ' . $checkout->getMollie()->status); + } + + throw new RuntimeException("Bestellung oder Zahlungsart konnte nicht geladen werden: $id"); + } + + /** + * @param $hook + * @param QueueModel $todo + * @throws ApiException + * @throws IncompatiblePlatform + * @throws Exception + * @return bool + */ + protected static function handleHook($hook, QueueModel $todo) + { + $data = unserialize($todo->cData); + if (array_key_exists('kBestellung', $data)) { + switch ($hook) { + case HOOK_BESTELLUNGEN_XML_BESTELLSTATUS: + if ((int)$data['kBestellung']) { + // TODO: #158 What happens when API requests fail? + $checkout = AbstractCheckout::fromBestellung($data['kBestellung']); + + $status = array_key_exists('status', $data) ? (int)$data['status'] : 0; + $result = ''; + if (!$status || $status < BESTELLUNG_STATUS_VERSANDT) { + return $todo->done("Bestellung noch nicht versendet: {$checkout->getBestellung()->cStatus}"); + } + if (!count($checkout->getBestellung()->oLieferschein_arr)) { + $todo->dCreated = date('Y-m-d H:i:s', strtotime('+3 MINUTES')); + $todo->cResult = 'Noch keine Lieferscheine, delay...'; + + return $todo->save(); + } + + /** @var $method JTLMollie */ + if ( + (strpos($checkout->getModel()->kID, 'tr_') === false) + && $checkout->PaymentMethod() + && $checkout->getMollie() + ) { + /** @var OrderCheckout $checkout */ + $checkout->handleNotification(); + if ($checkout->getMollie()->status === OrderStatus::STATUS_COMPLETED) { + $result = 'Mollie Status already ' . $checkout->getMollie()->status; + } elseif ($checkout->getMollie()->isCreated() || $checkout->getMollie()->isPaid() || $checkout->getMollie()->isAuthorized() || $checkout->getMollie()->isShipping() || $checkout->getMollie()->isPending()) { + try { + if ($shipments = Shipment::syncBestellung($checkout)) { + foreach ($shipments as $shipment) { + if (is_string($shipment)) { + $checkout->Log("Shipping-Error: $shipment"); + $result .= "Shipping-Error: $shipment;\n"; + } else { + $checkout->Log("Order shipped: {$shipment->id}"); + $result .= "Order shipped: $shipment->id;\n"; + } + } + } else { + $result = 'No Shipments ready!'; + } + } catch (RuntimeException $e) { + $result = $e->getMessage(); + } catch (Exception $e) { + $result = $e->getMessage() . "\n" . $e->getFile() . ':' . $e->getLine() . "\n" . $e->getTraceAsString(); + } + } else { + $result = sprintf('Unerwarteter Mollie Status "%s" für %s', $checkout->getMollie()->status, $checkout->getBestellung()->cBestellNr); + } + } else { + $result = 'Nothing to do.'; + } + $checkout->Log('Queue::handleHook: ' . $result); + } else { + $result = 'kBestellung missing'; + } + + return $todo->done($result); + + case HOOK_BESTELLUNGEN_XML_BEARBEITESTORNO: + if (self::Plugin()->oPluginEinstellungAssoc_arr['autoRefund'] !== 'Y') { + throw new RuntimeException('Auto-Refund disabled'); + } + + $checkout = AbstractCheckout::fromBestellung((int)$data['kBestellung']); + + return $todo->done($checkout->cancelOrRefund()); + } + } + + return false; + } + + /** + * @param $todo + * @return bool + */ + protected static function unlock($todo) + { + return $todo->kId && Shop::DB()->executeQueryPrepared(sprintf('UPDATE %s SET `bLock` = NULL WHERE kId = :kId OR bLock < DATE_SUB(NOW(), INTERVAL 15 MINUTE)', QueueModel::TABLE), [ + 'kId' => $todo->kId + ], 3) >= 1; + } +} diff --git a/version/207/class/Shipment.php b/version/207/class/Shipment.php index e69de29..a22a8d3 100644 --- a/version/207/class/Shipment.php +++ b/version/207/class/Shipment.php @@ -0,0 +1,325 @@ +kLieferschein = $kLieferschein; + if ($checkout) { + $this->checkout = $checkout; + } + + if (!$this->getLieferschein() || !$this->getLieferschein()->getLieferschein()) { + throw new RuntimeException('Lieferschein konnte nicht geladen werden'); + } + + if (!count($this->getLieferschein()->oVersand_arr)) { + throw new RuntimeException('Kein Versand gefunden!'); + } + + if (!$this->getCheckout()->getBestellung()->oKunde->nRegistriert) { + $this->isGuest = true; + } + } + + public function getLieferschein() + { + if (!$this->oLieferschein && $this->kLieferschein) { + $this->oLieferschein = new Lieferschein($this->kLieferschein); + } + + return $this->oLieferschein; + } + + /** + * @throws Exception + * @return OrderCheckout + */ + public function getCheckout() + { + if (!$this->checkout) { + //TODO evtl. load by lieferschien + throw new Exception('Should not happen, but it did!'); + } + + return $this->checkout; + } + + public static function syncBestellung(OrderCheckout $checkout) + { + $shipments = []; + if ($checkout->getBestellung()->kBestellung) { + $oKunde = $checkout->getBestellung()->oKunde ?: new Kunde($checkout->getBestellung()->kKunde); + + $shippingActive = Helper::getSetting('shippingActive'); + if ($shippingActive === 'N') { + throw new RuntimeException('Shipping deaktiviert'); + } + + if ($shippingActive === 'K' && !$oKunde->nRegistriert && (int)$checkout->getBestellung()->cStatus !== BESTELLUNG_STATUS_VERSANDT) { + throw new RuntimeException('Shipping für Gast-Bestellungen und Teilversand deaktiviert'); + } + + /** @var Lieferschein $oLieferschein */ + foreach ($checkout->getBestellung()->oLieferschein_arr as $oLieferschein) { + try { + $shipment = new self($oLieferschein->getLieferschein(), $checkout); + $mode = self::Plugin()->oPluginEinstellungAssoc_arr['shippingMode']; + switch ($mode) { + case 'A': + // ship directly + if (!$shipment->send() && !$shipment->getShipment()) { + throw new RuntimeException('Shipment konnte nicht gespeichert werden.'); + } + $shipments[] = $shipment->getShipment(); + + break; + + case 'B': + // only ship if complete shipping + if ($oKunde->nRegistriert || (int)$checkout->getBestellung()->cStatus === BESTELLUNG_STATUS_VERSANDT) { + if (!$shipment->send() && !$shipment->getShipment()) { + throw new RuntimeException('Shipment konnte nicht gespeichert werden.'); + } + $shipments[] = $shipment->getShipment(); + + break; + } + + throw new RuntimeException('Gastbestellung noch nicht komplett versendet!'); + } + } catch (RuntimeException $e) { + $shipments[] = $e->getMessage(); + } catch (Exception $e) { + $shipments[] = $e->getMessage(); + $checkout->Log("mollie: Shipment::syncBestellung (BestellNr. {$checkout->getBestellung()->cBestellNr}, Lieferschein: {$oLieferschein->getLieferscheinNr()}) - " . $e->getMessage(), LOGLEVEL_ERROR); + } + } + } + + return $shipments; + } + + /** + * @throws ApiException + * @throws IncompatiblePlatform + * @throws Exception + * @return bool + */ + public function send() + { + if ($this->getShipment()) { + throw new RuntimeException('Lieferschien bereits an Mollie übertragen: ' . $this->getShipment()->id); + } + + if ($this->getCheckout()->getMollie(true)->status === OrderStatus::STATUS_COMPLETED) { + throw new RuntimeException('Bestellung bei Mollie bereits abgeschlossen!'); + } + + $api = $this->getCheckout()->API()->Client(); + $this->shipment = $api->shipments->createForId($this->checkout->getModel()->kID, $this->loadRequest()->jsonSerialize()); + + return $this->updateModel()->saveModel(); + } + + /** + * @param false $force + * @throws ApiException + * @throws IncompatiblePlatform + * @throws Exception + * @return BaseResource|\Mollie\Api\Resources\Shipment + */ + public function getShipment($force = false) + { + if (($force || !$this->shipment) && $this->getModel() && $this->getModel()->cShipmentId) { + $this->shipment = $this->getCheckout()->API()->Client()->shipments->getForId($this->getModel()->cOrderId, $this->getModel()->cShipmentId); + } + + return $this->shipment; + } + + /** + * @throws Exception + * @return ShipmentModel + */ + public function getModel() + { + if (!$this->model && $this->kLieferschein) { + $this->model = ShipmentModel::fromID($this->kLieferschein, 'kLieferschein'); + + if (!$this->model->dCreated) { + $this->model->dCreated = date('Y-m-d H:i:s'); + } + $this->updateModel(); + } + + return $this->model; + } + + /** + * @throws Exception + * @return $this + */ + public function updateModel() + { + $this->getModel()->kLieferschein = $this->kLieferschein; + if ($this->getCheckout()) { + $this->getModel()->cOrderId = $this->getCheckout()->getModel()->kID; + $this->getModel()->kBestellung = $this->getCheckout()->getModel()->kBestellung; + } + if ($this->getShipment()) { + $this->getModel()->cShipmentId = $this->getShipment()->id; + $this->getModel()->cUrl = $this->getShipment()->getTrackingUrl() ?: ''; + } + if (isset($this->tracking)) { + $this->getModel()->cCarrier = $this->tracking['carrier'] ?: ''; + $this->getModel()->cCode = $this->tracking['code'] ?: ''; + } + + return $this; + } + + /** + * @param array $options + * @throws Exception + * @return $this + */ + public function loadRequest(&$options = []) + { + /** @var Versand $oVersand */ + $oVersand = $this->getLieferschein()->oVersand_arr[0]; + if ($oVersand->getIdentCode() && $oVersand->getLogistik()) { + $tracking = [ + 'carrier' => utf8_encode($oVersand->getLogistik()), + 'code' => utf8_encode($oVersand->getIdentCode()), + ]; + if ($oVersand->getLogistikVarUrl()) { + $tracking['url'] = utf8_encode($oVersand->getLogistikURL()); + } + $this->tracking = $tracking; + } + + // TODO: Wenn alle Lieferschiene in der WAWI erstellt wurden, aber nicht im Shop, kommt status 4. + if ($this->isGuest || (int)$this->getCheckout()->getBestellung()->cStatus === BESTELLUNG_STATUS_VERSANDT) { + $this->lines = []; + } else { + $this->lines = $this->getOrderLines(); + } + + return $this; + } + + /** + * @throws Exception + * @return array + */ + protected function getOrderLines() + { + $lines = []; + + if (!count($this->getLieferschein()->oLieferscheinPos_arr)) { + return $lines; + } + + // Bei Stücklisten, sonst gibt es mehrere OrderLines für die selbe ID + $shippedOrderLines = []; + + /** @var Lieferscheinpos $oLieferscheinPos */ + foreach ($this->getLieferschein()->oLieferscheinPos_arr as $oLieferscheinPos) { + $wkpos = Shop::DB()->executeQueryPrepared('SELECT * FROM twarenkorbpos WHERE kBestellpos = :kBestellpos', [ + ':kBestellpos' => $oLieferscheinPos->getBestellPos() + ], 1); + + /** @var OrderLine $orderLine */ + foreach ($this->getCheckout()->getMollie()->lines as $orderLine) { + if ($orderLine->sku === $wkpos->cArtNr && !in_array($orderLine->id, $shippedOrderLines, true)) { + if ($quantity = min($oLieferscheinPos->getAnzahl(), $orderLine->shippableQuantity)) { + $lines[] = [ + 'id' => $orderLine->id, + 'quantity' => $quantity + ]; + } + $shippedOrderLines[] = $orderLine->id; + + break; + } + } + } + + return $lines; + } + + /** + * @throws Exception + * @return bool + */ + public function saveModel() + { + return $this->getModel()->save(); + } +} diff --git a/version/207/class/Traits/Jsonable.php b/version/207/class/Traits/Jsonable.php new file mode 100644 index 0000000..8ba9b19 --- /dev/null +++ b/version/207/class/Traits/Jsonable.php @@ -0,0 +1,23 @@ +jsonSerialize(); + } + + public function jsonSerialize() + { + return array_filter(get_object_vars($this), static function ($value) { + return !($value === null || (is_string($value) && $value === '')); + }); + } +} diff --git a/version/207/class/Traits/Plugin.php b/version/207/class/Traits/Plugin.php new file mode 100644 index 0000000..08069cd --- /dev/null +++ b/version/207/class/Traits/Plugin.php @@ -0,0 +1,30 @@ +requestData) === false) { + throw new \RuntimeException(sprintf("JSON Encode Error: %s\n%s", json_last_error_msg(), print_r($this->requestData, 1))); + } + + return $this->requestData; + } + + public function __get($name) + { + if (!$this->requestData) { + $this->loadRequest(); + } + + return is_string($this->requestData[$name]) ? utf8_decode($this->requestData[$name]) : $this->requestData[$name]; + } + + public function __set($name, $value) + { + if (!$this->requestData) { + $this->requestData = []; + } + + $this->requestData[$name] = is_string($value) ? utf8_encode($value) : $value; + + return $this; + } + + /** + * @param array $options + * @return $this + */ + public function loadRequest(&$options = []) + { + return $this; + } + + + public function __serialize() + { + return $this->requestData ?: []; + } + + public function __isset($name) + { + return $this->requestData[$name] !== null; + } +} diff --git a/version/207/frontend/.htaccess b/version/207/frontend/.htaccess index e69de29..df6c074 100644 --- a/version/207/frontend/.htaccess +++ b/version/207/frontend/.htaccess @@ -0,0 +1,9 @@ + + + Require all granted + + + Order Allow,Deny + Allow from all + + diff --git a/version/207/frontend/131_globalinclude.php b/version/207/frontend/131_globalinclude.php index e69de29..962b5ad 100644 --- a/version/207/frontend/131_globalinclude.php +++ b/version/207/frontend/131_globalinclude.php @@ -0,0 +1,61 @@ +select('tzahlungsession', 'cZahlungsID', $sessionHash); + if ($paymentSession && $paymentSession->kBestellung) { + $oBestellung = new Bestellung($paymentSession->kBestellung); + + if (Shop::getConfig([CONF_KAUFABWICKLUNG])['kaufabwicklung']['bestellabschluss_abschlussseite'] === 'A') { + $oZahlungsID = Shop::DB()->query( + ' + SELECT cId + FROM tbestellid + WHERE kBestellung = ' . (int)$paymentSession->kBestellung, + 1 + ); + if (is_object($oZahlungsID)) { + header('Location: ' . Shop::getURL() . '/bestellabschluss.php?i=' . $oZahlungsID->cId); + exit(); + } + } + $bestellstatus = Shop::DB()->select('tbestellstatus', 'kBestellung', (int)$paymentSession->kBestellung); + header('Location: ' . Shop::getURL() . '/status.php?uid=' . $bestellstatus->cUID); + exit(); + } + } + + ifndef('MOLLIE_REMINDER_PROP', 10); + if (mt_rand(1, MOLLIE_REMINDER_PROP) % MOLLIE_REMINDER_PROP === 0) { + $lock = new \ws_mollie\ExclusiveLock('mollie_reminder', PFAD_ROOT . PFAD_COMPILEDIR); + if ($lock->lock()) { + AbstractCheckout::sendReminders(); + Queue::storno((int)Helper::getSetting('autoStorno')); + + $lock->unlock(); + } + } +} catch (Exception $e) { + Helper::logExc($e); +} diff --git a/version/207/frontend/132_headPostGet.php b/version/207/frontend/132_headPostGet.php index e69de29..9562324 100644 --- a/version/207/frontend/132_headPostGet.php +++ b/version/207/frontend/132_headPostGet.php @@ -0,0 +1,20 @@ +append( + << + /* MOLLIE CHECKOUT STYLES*/ + #fieldset-payment .form-group > div:hover, #checkout-shipping-payment .form-group > div:hover { + background-color: #eee; + color: black; + } + $selector label { + $border + } + + $selector label::after { + clear: both; + content: ' '; + display: block; + } + + $selector label span small { + line-height: 48px; + } + + $selector label img { + float: right; + } + +HTML + ); +} catch (Exception $e) { + Helper::logExc($e); +} diff --git a/version/207/frontend/180_checkbox.php b/version/207/frontend/180_checkbox.php index e69de29..530a9dc 100644 --- a/version/207/frontend/180_checkbox.php +++ b/version/207/frontend/180_checkbox.php @@ -0,0 +1,21 @@ +oPluginEinstellungAssoc_arr['useCustomerAPI'] === 'C') { + \ws_mollie\Hook\Checkbox::execute($args_arr); + } +} catch (Exception $e) { + Helper::logExc($e); +} diff --git a/version/207/frontend/181_sync.php b/version/207/frontend/181_sync.php index e69de29..46fcf31 100644 --- a/version/207/frontend/181_sync.php +++ b/version/207/frontend/181_sync.php @@ -0,0 +1,18 @@ +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 Rmns)TMnX}%M${5 literal 0 HcmV?d00001 diff --git a/version/207/frontend/img/trust_fre.png b/version/207/frontend/img/trust_fre.png index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..ed1a2f6f03c56f6748aac8af0352de7fc0afd3a4 100644 GIT binary patch literal 17319 zcmeIaWm{d#(l&}rVB!{B1Hml>cM0wg+}+*XC3tZ6;O_1g+}+*X{miwVy`H`IIp+tw zAKovs$2G4pYIIlC=&tJft`3!x5k-WXlNj7k?iufmqH+8N*koC2! zvmJh3R`?W79|~N)N*|nxgjgE3JwO7U=U3pbw+W9c8DnD;7ZcVr!_NoYvfr2*H(bug z+a6XOCi>*CzgaEUJ>H+KJWNbXboLzF}|hnF@qh`<|_#%8k)v)1A?a+efU31|zB7h0(C?H&)T#+b}Ums`C@ExH{AkB_brVq(PUJJEPK z?~b?}aDP4fw+Q|teqRi%Kt63Hd7n`nN(Khm3=2RqlcBBW1sn!-*}R@#)Mr>Y3u%$v z{r&ZlBpZIQ;drXNKjPVfWSajT0|1;DEH*YHLzj<`7UKLGvM`1sv;ot}TG@9)Mol3zw9iiG-4*B2wM%1Pz}vMjB8 z2>mng$#heDh&0d>pFUGK|Jqgmcb9tv!QhZ>;cXEp1-m%9cus?!%;Z4EO7b%zkd`qN zA4E#gg#Wje^iaEEC*I#)67=X2J%*DQY%Kc(mM{_F5cKQE#GCE+`qqC}9ZGutZP5Se zkq{UhiY+3r35NYAM^27Fx3d2Fb1hn{Q{R3cLQML9h?f7HZKdG4H!w&qnR-n3Cm1>i zlEN=tw=oL44|C4ymp#<~xCuyVR|FV43`iib>1WgrK+qiZSsgm7sjSf7FZ`E3QPKmL zAHcBmWTv6-sQr6_sm<45WET4<8=9;`W=a3YY5r0-KiDcHKAP&zR=H{QdARX@isyI-XZhbZRwyrf)tUFFL(if6_S|Opj-aMOKwmw1gw^ z*pwHRmX>Ze1CXa5Hhg5uH5v;(-Y$F;+ufZ=t?JT0!3!)^8^E+bAD1#44S!OvHI6*? z$P2<{k2khz1LnWq#UYTwZbyQM{nZ!buqH=0+x_9NK9z0P zaFMtyVf3x1-z3{K|E)&;UDU^|5F*+jnJnIn>+9>>aiUbc0DUv7Kze=|`p#E-VVP{Y zr>BD~vyb<;W8?!K_ggtTv4A>~|4?-u(D8V7NI{_0`7AdoJ=;%MM6Rj~atu~ud%8-m z*YtXKXtrE~jasE5{kfMT(KFNg*(?FtEQUf;Z{sZt+#f3SL(bqBs#>iN<#jzoaXTeSgsN$tM#jdbBAuH()en#mLSffN zb$x$2DAwup9&X!CcNov9HW(B!QVF*Vg<+*oo%h?{eSf(?UUVx9>P|i=t?W>6rk3Tt z66&h!Cg}pIRBE3kePLvbNo6(@B;a!X{qfTIkvE(`^OA3e2Nv*KAON~}*R=@|pMBCw zSzHAIh|lTx^YXi42%q`c-EnCpy`OSZX^m_auleh?%grE>kB}uRBx$pb&zlkpgh8Y8 z+44EABYr{4L8ixH`@=eudtzduh)KF#aLYjLPO3#kj#8;|u?07i_sba@>DiSt$XZ!zXEXkK?0Y+)A z43Th5I=EK2n+S`EOdh=?2X4baXjldXY*pdXF5u~2l8!Qy@f%6lK!YGtNWSc!?f@8A z16H)yloas*7~}#}QW45nOzGXEQq;>_nt-sxf~V7LlI!n$yI%o-Y$^8l2y(yJA}djl zqulI|k+#izwXRaa;?f^|=ahp6k}E^9S}ta9PtVL8#s84GlEfcw89%`g=mB&e2PUJz00Krdb6K&S6sg}is;&lXkV(7y-Kq)o zK>UKXM|q|3SSqhKBZfiw)DMgok;}OfrIEo@2qFuk+(NyN29V*9J1J*fy{`JP-l`t2 z28kj~AZ7Vqx5H_&*}sO~+sSLHwibtkhDN^yJgV*#tjoHJ9`TVQ^3D&J>Ms`lj26$T z)b9@yX_Hx~()&)d!WC2&^%nEEh|tZzH>{^{_Hy2Ofj@G%(b-9c97jq@z+j`Xot%tk zM=9HgI=Iyvf@ilMm*xFDG`NqRSjS1U+^-QgHbm-N;U?af-!>L z9*kIkbBbJR3%n*~82(x3c)ptQ7?dB@KOHExg`(S|(gYF4{_t|qS$Ti|0Gj%KT7->n z%W@ul>9LF;5_0T;r4Z601=;s-DK~EalgOQV`nHp%JW)7goGB5OaAft$wS&F=Ed7sU zB7O^9EYnZf!XFbp@83-_oG^K=|ByfJm|8N)vRbTKIuUN2e4xnkoF>GmKKaRTwd%SPDPe?b z4R5z25ADn%q@FDi(q*auPpJ77^LanbW)=yKJu<)#e|fS*i6%pepth#w5F|?J09z4c z_v*epTI?-7akIVQ1OO>FH;OKd?!&YRJ^Vl`cKV|E+d-BOnqq)!wYKAwaLMb_%|U6# zcX&)%;@cd_Bzi!!pI;(`+(0s;0q}@1Tcg2J9Q1k7-<_|mOlxa;zTGV_yPRusKJCWM zAz#-oXp^!(c1NSV4I;yzP4(1D?=^~C&HC%0RDm5npo*}ZW@{5ZfYotVL^-X`Xn@un<*R_C|;!S~aNE<&c9<6}^03;hYpR%WK(KL#`*J)7+qpd-6_y@+W93cmAG;VyUmxSh^spu$ z-WiB=_>sPxGr0T-0@K(pk{n@Y4R{G=*HvA#2U<2+*PUAEDRC~xyW8jd?>C<&mPuL8 z9bNmP)DzIC))3f68>s%7v*-$>-iEB7o&QBgV)jTlG4(5)mpy!I9x90 z%-c)H8)z_dxHcKA+fE$pnXcQRybY<1zuA)Rdf*uzUE8M^E*`ITyxQ`YLK>1sdO1E+ zy+*I;jJEw@S{1~XXLeF`ICp+J1{uDSYE_|E8o8cv9gCz*i5BwesrkazP6=rTuuNaUPXHGvxK|Xe7PMS4 zkQ78C8CUq8Tnm57Lo2qZJK~ZHbBYnP>ux$B2(pYZ5$Ew3BP?PL45mU!YCveY7B8GV z!YX3*tgV}P4{_d)txoVCNXgMj+iDbY#I02CVaCx^Gzs2?xbUWy${$G4M|RNbbgZIX z?7b5kd>H`QYXHzQ$f_&y!o08QZ!~RWMnk`dIdZk+=lM9c=;QI+h<^I8ry~9fEYtAu z(a6#*`f7JPWP`+JP-&#VZ{4JfPM#cK8DH+LvF|uEG{l?vh{Ljzp&K>GvC>dvf+m~n zb?V$Tc%R~JmduW0^r;^W*+PWY>Dy<;0(48Pyknz1zi5iXMCLNLTTq5JWU8Vk%gg{? z8(D-HMsR6c+3qZd9v?#JE_NsS5T4Q$U60Faym<`MlM1mzHl_~57)V9Bn}obn{V~IU zx_-C$0{Va>3X**sjs5-WC6t4TYpS$Ey8COt5uIwgvX=E+K?-}*?bq=0>vHwBMtYWs zUsbDUCBQH^)PXw#EEi992$;;J711%*^K-+0h?dc8i$=JzhTZD5yDilibu_NKkGS$z zagN7|el*2Io4oV>BAIWav=6@f5ol13>J^wxP$qnRg=vu&*)%}py@;~NeW{QUc2J(d z%T4Tubt)*QJyRg<)8!)6cpjQAf`nlo=3uBK8FvXYJ0i{A05PGWFKwFRBa^5 z`-P*wj3lvXJ?{0?j=o#>GA+=$T5mqt$gtV(ijjt{HS8p6STknUa-t4bHNs37&qzS>96^?DoPkpclE`cUc4) z%=b!uqfTEyinR6e4}l!+D+^Lu_^pDZZ#_p`$AjTGXMm;YFG7tNLKt?BGkv9104Sp?XJw)nlc_muQ7@uV zKtDY6R)hdgRHoZLP96a}_|+bnOx{MK*orXwUG7iaok8UwJDhQ^`II}GjJX}oKkViZ z{x1fEm0~C|8Cwx_vlwu3wm=E?2MV;Eo>$KR=q2u{?>bjf0nT8_2KL!ONd-#SnRE9C zgg~(AG@Z#mg+5%}-a0LwY@*KMx^3AxcbjC0otDXtDWNc#Z?5wzP;oL2oG73y|EqyOCWtu*XkrAoBHFE>GMX#Xo#XjYr13QoZrib8VwJzo& z&L&MP%GuWu{Ah=={?s6yQ*#fTo=rOyJk%3r_qP=BSR|79c*+%`TXsDy{ni z!jH{h(-_k-XCJE(muXP}8&=@MZT{RnycG+f2PdG#b8#H(J6)B{HcsiXL~$Wa1H>I^`U`rfot`yv1lN@m6MUwbZ90tKSf;ngCI{jR`s36$ zz6X>E2J-~oNv5Tf3rURqOJoht`mgf#b$8#J8q9>$$@QYfG1N-)!WBfxt&jhV*kb0X zVXvf)Fq!n+>-1UZq4EFG`Q%?dTg5jGp&^G2$@SK41QTbM5#QEE8X@&rhQ#^{UTz0T zbTINKo=bTggc5$VbimeEq#!?H1jVfoC^jIWZT;n_dKNTy4=O%@{&LG|p58sl_a4z8 zx)E=MMB8UejcClx5gTEn?vPdYvL|^|d{Yf$d)EfK!}RoJb88Vki`+LR)!Uan!2;PJ zGN$Go`YGT8vF)(_ilS6xj;H#dTE~NmG`-^l>zgOS<>{bydrNSR zD-KSwh>2#e(cN2LE;CdU_+GuCf3;=b0>{hb^=jF<|K@?yG|vV2dIMBq6B8B`^v_S` z4_Jx)M<%ts+Hbu;`B;hj>dkg6zYwMBn>8cQ1Yx`1uiSsJ*&m0-d9oTYmSlNRJdhzW zWZ4-{roH zwndbYbGyozNB(N|^dcO;kUXF}&vSOmIqA2~*ZoTg$cYP*=~^>Tr;^j~4|bw*tLq4+ z=$CW^+9wJc_m{s|ZG8G!*&F@K?RB3Y_4GW{#eZgA`4e~36sSz2AF+Pdg0+J61mh6$*uIdxA%F@lL@vspBu zk4)_n#d23%2xCbhf>@y~z>pl2eOWY?k$ybHWL7aunr3@PP)P2L+m zp?-B>{srDDe%BfR=%@A7uFFOdzHWK)6)R|ym)`-2NCG7pu$j4-<-J$g&=?8B`aR$KCq}D)VWrmwg7YwQOi=~Dv z;WG_B^>@}IKnF)~5g$SN1BUCekS&fZZC2 z8OwFE*9>uZ65sq~%o^kns7H51>uvJjc|DuIIJBS$_4MmC~HnQ$-jX@pH_h4ZiHz(Vu6u&% zsi|v$%lFgEwyJj-ifF=nR#_7tHKcuAeN^LMbR`0{vhn6Ka;cKnsJ+*#lA;oHkLx7V zZGb)l{GJ{><8`$tpQd`?+$A;Ais4ufGIgE|YunuwJ^tQAJMU|!DpcDc1jvt2qb4FA{DnIm+QVR{qWVQ1 zZ)W-9qTmK_#%ns#kVL<)dU@I9ZcYV{*S4;bATWjO(|}m%OmZWRM?c5{hIr_C42$DP zKE&>$`mbF?QFvGC48sVl-u`o-kVV9;sj+E7yAg-fhTSQcsR3jItFqT=g*V?y()F=I zZxw8pOK|_Mw=qewQ#~L<+(q9T@JhGKV)Z@2&^RL zhQGpRd|3O_MFC1E4sncSPWIDv1}YlHulxGNU*>8^=tTZeS581-0#`;0PKPGt?>Q* z?bVbHTOZavB100aVSrfL70$4CJ4ixua^s-gT(8Tf;*+m&M32(Vx6_i5>>1Duy2i`* z#_ZZ2biEcE@>I1xM3ry2<2jC80#*Eg48Ys0p=4pm4do+L7fWTDMomx;cBm6BlYl^z z3PM|iKs>UErLkb}{SKS%dlmL{5L)G3Zkz57g{s%q>Ol|6r#iB9&R!gioUeW}-%!wb z&TadIf>@A(NtxKc*M=|rJ+XRsba#It_gQZIv^=^@LWJ*84L!fENR*!Pd3{y%mx*>F zTaW8d?_Uw)Ac=qg#iQiV@QQ1d3rYHHcWpuR9k|I%@?S}OxWH`Tfnh=QO1>4(l!dTa`B{YRnS?-*Qk1*lWq&HNf%mVT`DMz zjn$&z_IXrlo>^~=*|>dFPzOu7;>h%>(K^eh52D$kttpqzANgS44I z&IfhS+A~;#blGzajnIFIg}~sghkBa42?J&@P<)Z|yhpZ91FbzkJp26B(D2~Luo$wz zeB1p+eunn(+#WO@A7|tYWBSXfVpLLJ>)!={J*3;XKe*vkyORxmv5^d7Mc@se-qAzIiGX4QE}4TSe= zS(K0?bjB-ev;jwZ4$j|75?7qGRCE2fV1b^#Tk7zZXOl#&o6V7X7M>2k)~{Qn2qG<} zShDJ6GB0lUxHuoA^Av2^s=`Go&Q zv@WB3Q9fNHizEH}FG_vDc6gH~mG=L@J=yV}!MM;LdHp}tdnr=|G$=Z$SjtJvoh6R{ zFWxv6>ARRM^zarl5Bm?emX8ZwEkHHbsKd$d4?HDA0U;=td($CS`oD0ALZmNByn@$D z{>?wI1ivE*F@TKoBD_xGAGC>b4ha0eqWu0()fK;I@wr#L^LnEb-k$dj%id_ZG>1=F z_A8>sP?AI7_H>DY;0U?m{w-3x>s9}!w8Z^INS%4-VGX{7>yOm$qRvLYE++YeI=I8= zeq`uVv*tCW5>Qr5J$=&X$TaYV{qzr{D1qyj3_=&4CVxsKP$xKQNO-+Ht+-6)U}l`myrV?KG9d?1K+zoRAEmeKKs^jY~mw^Gq+p&i7oG@72kI9RhL%(^7nYc9uphU1gCR+EO)o8vP zt+#X7QlSl<7qbnT0Lm-c++;Y>wxpQGq#B=7S#g4_yvJLb_Je5Ks1Kww{%}m2e4JXg zsR_Qy{C1DG!7;Xt^4ttA(t)qCu!U36H_v=XIpMjB?0SyH6r+#mA=y7FXS1^Hw(4zM03 z=Dh|#2@IJy-_1u@dB1&yY2)(J;P=;;IdJSCW=bMwSe9;IQFIP#2#ieK`p9kkvKdZ% zgXb~*YoR!lF+TN^Xz9I%_zfFgt?6Zv6SKPp-@ZC z4yIK%UG~5igMcLYjeT82+Sfx{N&?(CuFmIJZLN;g&#bPKv1O2Tf#PF7UR^}P9o;)b zWy2zO(GNC`L+I3`=t@-zKhmekT?4|{mCa;&zEGH|doF+&DhEeT&fa1JSC$p&tuO)Y z8XOL;#gzF-{c|Ul(bV%NySqZ1JGbt~7wcSH(=Hp8`7t)*c~azGjGy#}!+Zfo(@8X= z;&V?%Nd-S>Cnm3Iv>JMzV*|(w%;FSDC&DX7L5T6%Sc^u13e$CpEUWeMj+o3Z>y~Oaw$+X0g4MRu_i9 z0BNPPJdPNgaJ5=vf*U};nyB_4uFLn=C%qVSk9r2Wk?iVl%*6mw=ePGD&7@6D%`NAOgvbGos@bhGcU&<#^0S66nkJGtby*YH@6EU~%x38lp&up3KF@CL7WV$n>IEu;-Lm9T2vXw? z4%en@&zFf*Z`9PmzKw+;gy`H9IgGVseG`&1-p?l}W2)5*ripf)M$a*TLIl4%9GT*P z5WTr#rL~&dr7n^9?QAMHH*Ipntk)!+&qNdJ0&HA?Nuf7WP2iD5y`keHdfre8HNJEj z4UlfLn$OSK1!Pdvx0Nx=qvER-;6TKA*rYN)-|?6qAZ8d-v{lSo3U zn5V-LwxR1`0Rm+zY3L4!;#$esmyoiOQoI&G=V!`>V5BSOz&E%EOY~OmJvsx_LhE_v zgyWjA!F{@Uti|KG6h*T7vi$oYopJ?rG>6S*6SnOXAsmc4=H3so)b-qw7|+|}pn+yy zj%Fvs{BpDDrm$(x*S868?e!%AzSpM2X${4xp$Jk-*{X<7Qi*o&1CfFZW&oNz_U%L~ z4xy~dr3)3M2lt`dw*p$p$JWlXY%Yc(@u9XaXi;s$%fU=(9Hj@DszRrMAnz3*WmNU%1<^t$PfP-79p1CY-RC+8n0C9B0q@a6nTAxmd4$$ z<6!5Og(;G1WXYzVbc-qa(&FPoU#__)tDfa^&t0OLqg&>CT4$=AK;K!Gt?7`mab5EX z!Lpt|01^>0(W#DBqa(w;TF<&}q_y*L2g?5XbkFJN1*=@rEDdRY=HSLHbj%~lE;bmEkk{`9T7`AqR? zAgfNZn5hRP>B0S(pGNq=s)*WXKlnvf*^$h(pc7QNlOBamZmjChm6a(%v0O(cne<{| zPn(jvNfL+neM9T8(wu0r8Loa`i}v7ZIz(&zxj!RuXZ4xNQGv`SuW!NIp4Hc9FlY5d z#@;znH!ERfMK$>(ZM;|jIaBRx=BSa@)0TUS=Pd5BPv6G_+v_SWb5WWDuLI7M?fV4Z z$0WKew*ZLrL_NR1%T$`iPv-y0RP@_-b5*-#%V**VBOJv zlk!}%7|p?Cf>AQQhzlZYCev*5oV=boD;>mi`WS@RzG>#uRS4bFbrrevo1aLo53x5~ z7#)eA*Vf*cp0#KVu*m4fYjnQLCwRyWUNiG&xCWa8bgksV^rzN>9S9fMZNQZGm z^6Fd${IIsz7AMo)rKmU)4DEIYSo4-jff(wU^zUSa(w(eqr6`suR|OjP?-1; zg;e49nw$B21uf}dVl$%L@Wn6D+;JPgdfwD5>4baTk4f-5Dlh4@;KgNE)w!{3@7rKS z6+M%li?q-DY+L)HkA}CePEbDKEnO&!M$T{Le!#JJtP@2adeVH(nTNws2AOheP=IBY z_oQF?>Pj)(noBibHjg23krxn^R3=uAqpA+TW)s@jIsIS{pG0jq9d>K!)xB> z<*czTVS`LuT>LLen!7oqr7F2>rWA;`LSs>LeY6`VTd>~lF#{qD8BioOJda8J#-qFHHlKn_|C`)4ZmNM!%dQ`zqW(wM z9Vj|dl!nginxp+uAeHlE$+cW#BzX+t4RA;-0V1&(1?MtiV+D_njvQC48s$MgLwgjq zO|lIzN*TJOR6x{juk1=Lt}-gfl1qGUFcoNY<_w@txXS{^Z18M+a(D+?=b@COt9r{< zv9S&scC4xv(7)Cp{J3_ZLuN9WGJ<3@b=5agZ*1_@wOsGh_`S5ACzS$NZco#RU}96n z{S_N4v^K#r1>|b+7zo2jG{22_2}DObe7(VavXb9VAnj?`u_>&`IjP_XdVa9z7aCBr z;@P?}67gcE(&3Gfxljyglr$;*=J+MigWs_3UL-_x0pAsi4t23+1_+ zgs{X5NffK0+Tb!*8|^317D$$gbD3bY&xkt1%sDpgQX7jE9^#3{gs=Xs6b-6yAL3cb z<;8*yWB@x`+Pn4hv_!NIvWNsL8K!noGQ;XK+E z)wgbe>uv`G@Si4sZz5|1x1+>^mdhAIpI5scXAL?KFPIVZ`ww~=U!L#s_DQPZS0CLVa zP#}>`qu^RPjaAwzWPSpVw6=HX_Gku!qXk5J#IVC-vrdnJ>pOXS*eI0cdsECWR;H^n zwtl%k6VbWoc(La5_kR|NCM<8zNP~rQ=F}6#{F#{;1doNbd;=orEg=LLlCViO%H zSfN*B_g@gYi%z;0{;5{cmR=mdkJ4?mmw;W)NM1pBxC@F&CUzM=*du3W?s1{K#-#}{ z=Z2~0s!t5c_GK?qYt?Aq?R+-Q&)VPF4p05&Mg?Ym^zCC0hD)Gn=RT?~B1vbSgMGC3 zJd15Tb#S2C;&AUni+`?^Oye0W_I5|sf=>EQf!^E<#uZoxd>VNrrL^4n^WTtwei#+RCVquXqBv%wJ>)A{*41`-c( zue5j-A?Uz@y5YZ|cqy<`>{Z7ZX$d^A@*b~;wZh!$vcRMxHIoeC#c%1!$)*#Sx6ghs zgxSG}c+~!r{uH@*td`kH+U}wJ3WRREsODqu^_(u}_;sM&!0J8h-QR9E`?r(dk&Acs z$I@U^13{E7ahy3puGrLLn;(I^0jnUhh9D7e3K4lfe)a+p>;Pz&Acp9SQIZyBowvho zAT0W)B|)`G2=M6QABEI{Fc2`(!6|LYH<_w&Gp$waPi#Jj(6(cpql}6%7>i;Q8=pD!z}!&p|si*TIaeX%@VZ|9=ZZ$txqJayAz0CV)7oDAPY zFhek2t-4?cNp28t)lhc6+;pYE>K4Q+{)>A18rEZvv|ZW!=UW36)gIxukdJ1Ge6QUX8?&(r2$s%LhiF{_pu-(Z-$z};kuinb@pQ0?xRFDL1uX0S)_$P^Px;c|FJS6A$ znmHBIx7M?bOe35~5!kuIL~{_FDr6FPBfW8&)LxUr3+g9XSw_5^7X>*!WMn9Q!tat! zHe`t^SE|LISd7vyPVc^QKH^&v5tf9$*bNm?t9tj{z|^mEcn*G>z3nFRmL8y2XjQo3 znRj3HkT3tmWprFXK6O`4Go^7VK2KZ8B+z_RhI@OC;1dCzg`w|xeUn>cM1hC$;AX}0 zR?St_a_!}8s}e)d{C08t3|3!6nEQkNd=2UqtI=ic4 zuYmEy6bWxMb?hq};>bbv(sbqFPKkM8p4EZtjsw40i5^Q9 z`KDpt6l3)CDz_G1Tk75xJHQ>4wz7!@;ZDIiyH2&o4$YLO&i9M%6U8rDEq6u9@I8!0 z-9;#M$e#pw8RMa}{Be*|&QzRMMWoATLIv4QoOiQ7l<;)%eteoPQ)9|6?~cVhb>GZ` z7U@y7Zn_u$>YD|n>*Rz1q1y(fW!%QvBTvmA7^E?=y=x%{+*LzWE4o74FM=)f?TY!8 zW1<9&K0dbJtsDp|4-5vQlv0U)q0?IE6(YZDd)+D3M;Nhwx>s*VyR|0AvmR!gt}DfR zN)a671f_+fZrAG(ie82H#rw3(?}XE9I*S;hhN<4qtVr$Z$q|r<4cV;LB^?f|uEJf= ze^rl4RIKh&4Ko|K4o0l`sW;sT^nUefZVf5K+m6xZ&2-OHr!sValPym#?HVWdB(@#q zq=^wUxAb^V?_9b$VnJLg=;7mAU60N{*LqNItU<8B?+VxYI7<4)OvEWg6#fG*cjaKO z$^FiJaMzfwHIGMb!YX?;9jF8TNcyg|cbu4w55(TTtgQQ{ytvIvP`$Wrg2J0@0A`nXvv zA=F-Cdd|yI9hVHbIk0B^R^@Zck->Wj>FGRg%yx;oxCAXZN|5SysO-u2>b>%17`8L2 z3TBF0X;FM1^u3<}ov?M?uWJMjY3cZN`Gr`c=Yz7EB5~vldEw(Wxy-nCCrWa>3im{R zayTr*uLm^V4IAFfM28+-SLXE{+H=OQgm+C*O<~qEcVu_R%jAPo7Z7+H-cKji>Q)9K zuM&1D#>yM`W!`u?m7vU%QpIipJmYPFFVf<+>JHUdhdt1HSK=C!pWJSrN_7Um-a1Cv=^quq>@6N(?Kqu}$SzDORL;oj1z&;-AdCLZ9~to1&3qo%uUIO3KRJ<4bTm06OnpRE)xv3hEY*Y#SKUSPHF7A2 zUYsvx6bsA*miHQWbCtQ(Lij`Eg5kwZ8DJLkIj9#pJW4g!*hp&s7~hd?sI2+YJs!!w zvGnwk1zG3g(>*Q6j5F+g^+L~=MSi&Wvvel@Kvj~0fPUC}RD<)tSY4lY3mI&_7=L*H zIvMduJ!8Li#Fe5r5#{^a;#LZtUAHW-;j=X$>WE*C5W6#FUDK3hSJ>NBlJ_)8#N=w6 zgs!S}sf8lxGLo=Xw@_h&(c-A}v$WvyRPqhM$N>%xj(L(yHt%MTNuqkadGXRS+lFTz z5DXZE)jfi>3*Pagt^sCzo>`zfDp}6IyneAIe2sB2HG+WIy_E?F$xJgzyh)~o4-pH1 z)F@vPShLNB(FboE^_GOFFSOqqZZpfK*DGZnh6tS*aoQP-HsMovH^6H`B;wV?A#gcc zPB34nC=Xj0zqQq4BSBL1Y1%@ipfvqsRhT6Zr(BWE$Ahc5#5Dy133!&;4-@g|EwpO} zvKhH`6-3)5xLS2gE?P=YNKc~VMm^tkH_cvm!}S&(=G4*@fM?<<^p!&O_d)>>jSqf6 z38IjTolVjJV+CJ(T-Kt#lMyHe844n*7TyV6-P0psFh1;qSn>P zoD!NmEN*pg#R*E6vr|K1sf}ntek59BjM@ATy(ZLTZxrxm4bpa^p zb^|yie8dvOUc?ktPTi~~(#(SOP(mjIcs7QSm-s>bRE6oe4e$n%EU(R*+R2?k05kv* zJ+TmI(C2itchXtBT1r7{62@avMbEvVChtUU;&f?Joe0=Mvh`M#i5_k9lM#s3BF?;V z#%t_>C0{{75J#uFQ%m_wim-fL;kTU$t|aPqzVtsqElb6lZ8*)2t{fW!ir&;o4?a~~ zdvP2ohe)V9?xY;6X$O8?Hu3z?F2YIGhC750Bj0;) z6l=-)RDQwSs05!u(DfspGW3^U9(-FPM@+HiiOYxat}+*NELd3dYG1O;KpI3Hftb)y zi>}zNBwm5?)}r?^z$jliw;o-(!MbD7Oa?KZAC84}W}TKsVElZcA)OgfTvP5y7FhzZ zXq-p*AtCJjYc^dGC0VVlMC72;W4b#adHH-{{=lBoFk{-b?eG2`lhj!I9h3--i-dw< zYO|RJ*abWQ-;S1Q3)A!!aZfwk&YKTrV-cOL1tg*DArKM&VE0*u`@iR8f%5$y_ffV8 zF!)ui@ETPD>tX8pt{LJujDhM&@Qt5C+75ne>Yd89G!kDR%^RmKgUE|#BZSg3W~J6Z84E$-Mbpk z0O6RgYmtU`ciRWZax(P0^4WT9O7#Wd@bnORnm#sx&GaWm9Jvf0kq4vn(f*z@xF)sAUao zt|;smg=bGg^AnNJwI=SV@}OC+Y2c%lr?WKnv7+eu?n>}k%thSliQZ-yr1c;(c?&st zCTn%I_~hKwEW5mpekw6L-3WAkDXbYATllaNVWDP^#^^-IrvzJWQ=HY?!=LGYZfFF?+={U6?LA*>3)0<@Mgxl5GuI8?BIm+@{s z3U`HO<9D{-U8Imx3hM`K>tqBr2@n^EI8i_J+{BL_H)tw%?v18OH%qEa#@uNPxll%L zdSN21Z+?ebi8oL?Gf7O|HIHB1qmnS?ioc$hCG$+cCVKy|F|YS} ztEx@-Zuv`*oQy1AE?8)gKw|pye=uN_0acQ)t)YuAR;(ZW)D%!vshFt$5D`Gcf$ZNX ze-$ZzNt~m^G5xtDASuow^un)0ZR_g3-b^1K8l4VL(LLGB&SzIVTt8st z1~29KfTY$xlp0@R+t<%v=Q(Gx$#JV;grNHI4N&@0Pcf{D`TivQ4-ew6di4J-Gp_-= z!`0c{amre6JKyQWMd?tcB>9KN1FAvhmnQ`q2R{c#f}qbmVFF47!C@%hsE~@1KuAG{ z{2|W!g0AVF?s(!VL%81+!h|4V+rY8k6}SJz#ri8a9%!& z8^5Q?&!U+`r;!*N8*5AbUwvN$cI^u>oV=Ezn2k$vwVpyfo5}qGgH0Km4H<@7pae>Z zHV{K1qW;?(F2j7arx|17j5cv)b^%6Q=5nJ6#zsbwf5yhz6Oud?)!7|reiTG_J}n}| z{>KpjzN8SU<3r=)tgoQ5e*aYnr=qf!{`FL6s=`eEAIo;6 zh91!b(#@Fvc2RhUvL^N(F8_m@4Y~Q$(MBQYX4^Ue*my#yUcPq_7jdL&>XhGD@W+zO z9>aX5;ddi+%B;YDA79XQ6%Ez|#tz;D&JNK8!4BCJfMpNy`<-aOnojJ>Qg94(@&=f= Mu#8ZJpsxS_1AJc%;s5{u literal 0 HcmV?d00001 diff --git a/version/207/frontend/img/trust_ger.png b/version/207/frontend/img/trust_ger.png index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..e42821b06709e8f4371c66cfb5759d00df0e1afd 100644 GIT binary patch literal 15352 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 diff --git a/version/207/frontend/tpl/applepay.tpl b/version/207/frontend/tpl/applepay.tpl index e69de29..57c2e75 100644 --- a/version/207/frontend/tpl/applepay.tpl +++ b/version/207/frontend/tpl/applepay.tpl @@ -0,0 +1,19 @@ + + diff --git a/version/207/paymentmethod/JTLMollie.php b/version/207/paymentmethod/JTLMollie.php index e69de29..ee887a8 100644 --- a/version/207/paymentmethod/JTLMollie.php +++ b/version/207/paymentmethod/JTLMollie.php @@ -0,0 +1,306 @@ +cModulId = 'kPlugin_' . self::Plugin()->kPlugin . '_mollie' . $moduleID; + } + + /** + * @param Bestellung $order + * @return PaymentMethod + */ + public function setOrderStatusToPaid($order) + { + // If paid already, do nothing + if ((int)$order->cStatus >= BESTELLUNG_STATUS_BEZAHLT) { + return $this; + } + + return parent::setOrderStatusToPaid($order); + } + + + /** + * @param $kBestellung + * @param bool $redirect + * @return bool|string + */ + public static function getOrderCompletedRedirect($kBestellung, $redirect = true) + { + $mode = Shopsetting::getInstance()->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; + } + + + /** + * Prepares everything so that the Customer can start the Payment Process. + * Tells Template Engine. + * + * @param Bestellung $order + * @return void + */ + public function preparePaymentProcess($order) + { + parent::preparePaymentProcess($order); + + try { + if ($this->duringCheckout && !static::ALLOW_PAYMENT_BEFORE_ORDER) { + $this->Log(sprintf('Zahlung vor Bestellabschluss nicht unterstützt (%s)!', $order->cBestellNr), sprintf('#%s', $order->kBestellung), LOGLEVEL_ERROR); + + return; + } + + $payable = (float)$order->fGesamtsumme > 0; + if (!$payable) { + $this->Log(sprintf("Bestellung '%s': Gesamtsumme %.2f, keine Zahlung notwendig!", $order->cBestellNr, $order->fGesamtsumme), sprintf('#%s', $order->kBestellung)); + require_once PFAD_ROOT . PFAD_INCLUDES . 'bestellabschluss_inc.php'; + require_once PFAD_ROOT . PFAD_INCLUDES . 'mailTools.php'; + $finalized = finalisiereBestellung(); + Session::getInstance()->cleanUp(); + self::getOrderCompletedRedirect($finalized->kBestellung); + + return; + } + + $paymentOptions = []; + + $api = array_key_exists($this->moduleID . '_api', self::Plugin()->oPluginEinstellungAssoc_arr) ? self::Plugin()->oPluginEinstellungAssoc_arr[$this->moduleID . '_api'] : 'order'; + + $paymentOptions = array_merge($paymentOptions, $this->getPaymentOptions($order, $api)); + + if ($api === 'payment') { + $checkout = new PaymentCheckout($order); + $payment = $checkout->create($paymentOptions); + /** @noinspection NullPointerExceptionInspection */ + $url = $payment->getCheckoutUrl(); + } else { + $checkout = new OrderCheckout($order); + $mOrder = $checkout->create($paymentOptions); + /** @noinspection NullPointerExceptionInspection */ + $url = $mOrder->getCheckoutUrl(); + } + + ifndef('MOLLIE_REDIRECT_DELAY', 3); + $checkoutMode = self::Plugin()->oPluginEinstellungAssoc_arr['checkoutMode']; + Shop::Smarty()->assign('redirect', $url) + ->assign('checkoutMode', $checkoutMode); + if ($checkoutMode === 'Y' && !headers_sent()) { + header('Location: ' . $url); + } + } catch (Exception $e) { + $this->Log('mollie::preparePaymentProcess: ' . $e->getMessage() . ' - ' . print_r(['cBestellNr' => $order->cBestellNr], 1), '#' . $order->kBestellung, LOGLEVEL_ERROR); + Shop::Smarty()->assign('oMollieException', $e) + ->assign('tryAgain', Shop::getURL() . '/bestellab_again.php?kBestellung=' . $order->kBestellung); + } + } + + public function Log($msg, $data = null, $level = LOGLEVEL_NOTICE) + { + ZahlungsLog::add($this->moduleID, '[' . microtime(true) . ' - ' . $_SERVER['PHP_SELF'] . '] ' . $msg, $data, $level); + + return $this; + } + + public function getPaymentOptions(Bestellung $order, $apiType) + { + return []; + } + + /** + * @param Bestellung $order + * @param string $hash + * @param array $args + */ + public function handleNotification($order, $hash, $args) + { + parent::handleNotification($order, $hash, $args); + + try { + $orderId = $args['id']; + $checkout = null; + if (strpos($orderId, 'tr_') === 0) { + $checkout = new PaymentCheckout($order); + } else { + $checkout = new OrderCheckout($order); + } + $checkout->handleNotification($hash); + } catch (Exception $e) { + $checkout->Log(sprintf("mollie::handleNotification: Fehler bei Bestellung '%s': %s\n%s", $order->cBestellNr, $e->getMessage(), print_r($args, 1)), LOGLEVEL_ERROR); + } + } + + /** + * @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 (API::getMode()) { + $selectable = trim(self::Plugin()->oPluginEinstellungAssoc_arr['test_api_key']) !== ''; + } else { + $selectable = trim(self::Plugin()->oPluginEinstellungAssoc_arr['api_key']) !== ''; + if (!$selectable) { + Jtllog::writeLog('Live API Key missing!'); + } + } + if ($selectable) { + try { + $locale = AbstractCheckout::getLocale($_SESSION['cISOSprache'], Session::getInstance()->Customer()->cLand); + $amount = Session::getInstance()->Basket()->gibGesamtsummeWarenExt([ + C_WARENKORBPOS_TYP_ARTIKEL, + C_WARENKORBPOS_TYP_KUPON, + C_WARENKORBPOS_TYP_GUTSCHEIN, + C_WARENKORBPOS_TYP_NEUKUNDENKUPON, + ], true) * Session::getInstance()->Currency()->fFaktor; + if ($amount <= 0) { + $amount = 0.01; + } + $selectable = self::isMethodPossible( + static::METHOD, + $locale, + Session::getInstance()->Customer()->cLand, + Session::getInstance()->Currency()->cISO, + $amount + ); + } catch (Exception $e) { + Helper::logExc($e); + $selectable = false; + } + } + + return $selectable && parent::isSelectable(); + } + + /** + * @param $method + * @param $locale + * @param $billingCountry + * @param $currency + * @param $amount + * @throws ApiException + * @return bool + */ + protected static function isMethodPossible($method, $locale, $billingCountry, $currency, $amount) + { + $api = new API(API::getMode()); + + if (!array_key_exists('mollie_possibleMethods', $_SESSION)) { + $_SESSION['mollie_possibleMethods'] = []; + } + + $key = md5(serialize([$locale, $billingCountry, $currency, $amount])); + if (!array_key_exists($key, $_SESSION['mollie_possibleMethods'])) { + $active = $api->Client()->methods->allActive([ + 'locale' => $locale, + 'amount' => [ + 'currency' => $currency, + 'value' => number_format($amount, 2, '.', '') + ], + 'billingCountry' => $billingCountry, + 'resource' => 'orders', + 'includeWallets' => 'applepay', + ]); + foreach ($active as $a) { + $_SESSION['mollie_possibleMethods'][$key][] = (object)['id' => $a->id]; + } + } + + if ($method !== '') { + foreach ($_SESSION['mollie_possibleMethods'][$key] as $m) { + if ($m->id === $method) { + return true; + } + } + } else { + return true; + } + + return false; + } + + /** + * @param array $args_arr + * @return bool + */ + public function isValidIntern($args_arr = []) + { + return $this->duringCheckout + ? static::ALLOW_PAYMENT_BEFORE_ORDER && parent::isValidIntern($args_arr) + : parent::isValidIntern($args_arr); + } + + /** + * @return int + */ + public function getExpiryDays() + { + return (int)min(abs((int)Helper::oPlugin()->oPluginEinstellungAssoc_arr[$this->cModulId . '_dueDays']), static::MAX_EXPIRY_DAYS) ?: static::MAX_EXPIRY_DAYS; + } +} diff --git a/version/207/paymentmethod/JTLMollieApplePay.php b/version/207/paymentmethod/JTLMollieApplePay.php index e69de29..ca0b375 100644 --- a/version/207/paymentmethod/JTLMollieApplePay.php +++ b/version/207/paymentmethod/JTLMollieApplePay.php @@ -0,0 +1,20 @@ +oRechnungsadresse->cMail; + $paymentOptions['locale'] = AbstractCheckout::getLocale($_SESSION['cISOSprache'], $order->oRechnungsadresse->cLand); + } + + $dueDays = $this->getExpiryDays(); + if ($dueDays > 3) { + $paymentOptions['dueDate'] = date('Y-m-d', strtotime("+$dueDays DAYS")); + } + + return $paymentOptions; + } +} diff --git a/version/207/paymentmethod/JTLMollieBelfius.php b/version/207/paymentmethod/JTLMollieBelfius.php index e69de29..b7cac71 100644 --- a/version/207/paymentmethod/JTLMollieBelfius.php +++ b/version/207/paymentmethod/JTLMollieBelfius.php @@ -0,0 +1,17 @@ +clearToken(); + } + + protected function clearToken() + { + $this->unsetCache(self::CACHE_TOKEN) + ->unsetCache(self::CACHE_TOKEN_TIMESTAMP); + + return true; + } + + public function handleAdditional($aPost_arr) + { + $components = self::Plugin()->oPluginEinstellungAssoc_arr[$this->moduleID . '_components']; + $profileId = self::Plugin()->oPluginEinstellungAssoc_arr['profileId']; + + if ($components === 'N' || !$profileId || trim($profileId) === '') { + return parent::handleAdditional($aPost_arr); + } + + $cleared = false; + if (array_key_exists('clear', $aPost_arr) && (int)$aPost_arr['clear']) { + $cleared = $this->clearToken(); + } + + if ($components === 'S' && array_key_exists('skip', $aPost_arr) && (int)$aPost_arr['skip']) { + return parent::handleAdditional($aPost_arr); + } + + try { + $trustBadge = (bool)self::Plugin()->oPluginEinstellungAssoc_arr[$this->moduleID . '_loadTrust']; + $locale = AbstractCheckout::getLocale($_SESSION['cISOSprache'], Session::getInstance()->Customer() ? Session::getInstance()->Customer()->cLand : null); + $mode = API::getMode(); + $errorMessage = json_encode(self::Plugin()->oPluginSprachvariableAssoc_arr['mcErrorMessage']); + } catch (Exception $e) { + Jtllog::writeLog($e->getMessage() . "\n" . print_r(['e' => $e], 1)); + + return parent::handleAdditional($aPost_arr); + } + + if (!$cleared && array_key_exists('cardToken', $aPost_arr) && ($token = trim($aPost_arr['cardToken']))) { + return $this->setToken($token) && parent::handleAdditional($aPost_arr); + } + + $token = false; + if (($ctTS = (int)$this->getCache(self::CACHE_TOKEN_TIMESTAMP)) && $ctTS > time()) { + $token = $this->getCache(self::CACHE_TOKEN); + } + + Shop::Smarty()->assign('profileId', $profileId) + ->assign('trustBadge', $trustBadge ? self::Plugin()->cFrontendPfadURLSSL . 'img/trust_' . $_SESSION['cISOSprache'] . '.png' : false) + ->assign('components', $components) + ->assign('locale', $locale ?: 'de_DE') + ->assign('token', $token ?: false) + ->assign('testMode', $mode ?: false) + ->assign('errorMessage', $errorMessage ?: null) + ->assign('mollieLang', self::Plugin()->oPluginSprachvariableAssoc_arr); + + return false; + } + + protected function setToken($token) + { + $this->addCache(self::CACHE_TOKEN, $token) + ->addCache(self::CACHE_TOKEN_TIMESTAMP, time() + 3600); + + return true; + } + + public function getPaymentOptions(Bestellung $order, $apiType) + { + $paymentOptions = []; + + if ($apiType === 'payment') { + if ($order->Lieferadresse !== null) { + if (!$order->Lieferadresse->cMail) { + $order->Lieferadresse->cMail = $order->oRechnungsadresse->cMail; + } + $paymentOptions['shippingAddress'] = Address::factory($order->Lieferadresse); + } + + $paymentOptions['billingAddress'] = Address::factory($order->oRechnungsadresse); + } + if ((int)$this->getCache(self::CACHE_TOKEN_TIMESTAMP) > time() && ($token = trim($this->getCache(self::CACHE_TOKEN)))) { + $paymentOptions['cardToken'] = $token; + } + + return $paymentOptions; + } +} diff --git a/version/207/paymentmethod/JTLMollieEPS.php b/version/207/paymentmethod/JTLMollieEPS.php index e69de29..5120b55 100644 --- a/version/207/paymentmethod/JTLMollieEPS.php +++ b/version/207/paymentmethod/JTLMollieEPS.php @@ -0,0 +1,17 @@ + substr($order->cBestellNr, 0, 13)]; + } +} diff --git a/version/207/paymentmethod/JTLMollieKlarnaPayLater.php b/version/207/paymentmethod/JTLMollieKlarnaPayLater.php index e69de29..3474053 100644 --- a/version/207/paymentmethod/JTLMollieKlarnaPayLater.php +++ b/version/207/paymentmethod/JTLMollieKlarnaPayLater.php @@ -0,0 +1,24 @@ +Lieferadresse !== null) { + if (!$order->Lieferadresse->cMail) { + $order->Lieferadresse->cMail = $order->oRechnungsadresse->cMail; + } + $paymentOptions['shippingAddress'] = Address::factory($order->Lieferadresse); + } + } + + + return $paymentOptions; + } +} diff --git a/version/207/paymentmethod/JTLMolliePaysafecard.php b/version/207/paymentmethod/JTLMolliePaysafecard.php index e69de29..29be769 100644 --- a/version/207/paymentmethod/JTLMolliePaysafecard.php +++ b/version/207/paymentmethod/JTLMolliePaysafecard.php @@ -0,0 +1,23 @@ + $order->oKunde->kKunde] : []; + } +} diff --git a/version/207/paymentmethod/JTLMolliePrzelewy24.php b/version/207/paymentmethod/JTLMolliePrzelewy24.php index e69de29..62a55d5 100644 --- a/version/207/paymentmethod/JTLMolliePrzelewy24.php +++ b/version/207/paymentmethod/JTLMolliePrzelewy24.php @@ -0,0 +1,23 @@ + $order->oRechnungsadresse->cMail] : []; + } +} diff --git a/version/207/paymentmethod/JTLMollieSofort.php b/version/207/paymentmethod/JTLMollieSofort.php index e69de29..892adc3 100644 --- a/version/207/paymentmethod/JTLMollieSofort.php +++ b/version/207/paymentmethod/JTLMollieSofort.php @@ -0,0 +1,18 @@ +OH(NI>=T42<+x9g>;*Gy9DrKtJl=F((p(~XhRMojR(!TROq)4##x zi;wfn&C+>%^UTiFKSt7JYSXp1>ZPgDP*&5InbUcF<%^K^*xKlsoYHP{(wCajZ*$Ra zbJNPo(OY2BWNFmE!S~qO{POeCTVT|{z|(GX;Bt54e}mdsUi8b(sL>`X0000JbW%=J z01%HLkU-Cn-_OsV&!6AlpP5D4UE1#Sax&aZg(%L>z8x33MOZZ8H?WJ;;n51dMe)(}9UH1j29 ze@0RGfq`^s0!X#X7!_srsUP@btltZoyHfrIVq@*+2f)Ge+&BuBcbdrjKu5}NuE;){Yi3#o7gOK=v6Y0{rAbqNgQSz}}0I~5?ej{GsP%?vN z=_l4!?VPOmM>R@!2oOAkd1t|Pb#@H>-d=$PnbBs7=u%Z>9N;0iml z2#guk2rk-V%mMEvxQCZ1@+-_*(mao=fPWKs%h@Mp0)~gcfgO7j{4M(n<{@x^Z^Hk! ze1;0X32xx)(NPC3aetZbtnBss>W2NT-v%Bch%He^5RXIyLDWRp5;o{lcPr>qmkRZj lpHDtfd;A2~X0zTP_aA;i{an>LN7rz#m}I!{TEUogY_hW!fX z1?mg>C*-erx%(so1LG!77srr_xVP7C<}EQ0XbW_HZ(Bb#ysRpA(wRN~nf+#OlTe%( zXkfncL^KKCCrg-Lh=kEnU|a;ZB9QaR>Td+?i96wEUURmd^*;_;}q*?JtCN zs9v0_oUIYrJ>{ItUF)Suj=nY*E;y-_bg}zQ;ZT|@FU4Qeut^B)WfWUjV9g-3v@K+f-ik;kV{MOr_6wK;GGik>mTp$V%-RtP)+CPEi`n!UgTe~DWM4fFWeR( literal 0 HcmV?d00001 diff --git a/version/207/paymentmethod/img/method/bancontact@2x.png b/version/207/paymentmethod/img/method/bancontact@2x.png index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..a87af77d20330ab4ee197fd750d0bd39a5b10f90 100644 GIT binary patch literal 582 zcmV-M0=fN(P)lk!lq%lq?@9+Qr z|M>X$=jZ1jWQqR%{`vX&|JVTk=U{-T&j0$~pTFAg&hoWPVjpU$|LlN(mQMfcfPbmZpr$+j>2Uw#P;ZV{AZe)(UZem0@6X@u|MkEB z;XwWU{r~1*Ky`MXzS=N!uW*i8kF?YfT$A7F^MIC5pQk%!Gip%)000nlQchC<&w%eB zkRX4bpb&7+Z;x=Vl85vF00AONL_t(|UhS6GZp0uI1+V+IBnNQY-qL&T?f<_j%Vs4k zWi4ZPi#+c$LIR;fk}z^m8)w(24LdL-qBSjmiImqQ6%1%eKSC_H5hBJOQ3wcbh=A9j z0E`>M;F1Gj9uRN{NX-L}@Ce`*0RKJE1nw{TTbXGF`gs|rT7l!dln0%_EVm0RbGyKB zqJ*zRaiSTxE%@_=;_x?lSs8dz{y6#LPln}z>8GT40dLB`KB#<1qlM(E;D0OsM*0?TeIhg`dn6;Q{6Fh2l%qOS4K%wo8-q7AUD{?yGF(55vm4C&H_FzBH+J=d4+57}kr Up-!czfB*mh07*qoM6N<$g3OCHTL1t6 literal 0 HcmV?d00001 diff --git a/version/207/paymentmethod/img/method/banktransfer@2x.png b/version/207/paymentmethod/img/method/banktransfer@2x.png index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..c70206bef4893f23fcd59d436273108d2f2eebc7 100644 GIT binary patch literal 801 zcmV++1K#|JP)lk!lq*=;-9+mkX z{{U2_ztrjP@9%)A(*D5?-|6)J(MtZwET6yKpugSt`1lZBsz86cAZf7q`T3Bv*Z%(g z-|F=K#U1|5JO0^dAZoDx_u=pL`RC{7_xJZ;l*j-3@c!I)@AdkSwAlXDS^mf@aG%W2 z;O`J$tN-Md>+9=KiNUYR<6xA=@AUcq@WXGP%>DiS|LnB>%sc+*q+gWBFm$#4l$oJ=bMJL) zN$}UM z^EEI7D0q#*=`w@Mb&#yX6$WP@x&}s<8JvJ@pvqecQO^sez9^Xbs$t>(|Nn0Y_`k@X z`u+Uv`wm6F?mz#2{?4!aFGTBV&I9cbE(!7rW)PTg{{H;_^9ubA3J&Kd+&@2If#l5V zkwEFKo-U3d6>)E`o#Z>Lz~g$+{n^fDUKQE@|Mgd!a9=T#&e{4(sr-HO1o4KQ>uv;= zWX2_)yrQzk;QY@iN0x35n7oK-g-2+63_H(@QU|u6Z>|Z!r6lZ1zes9a?+x$E9%YhzX@O1Ta JS?83{1OT9Jm%RW0 literal 0 HcmV?d00001 diff --git a/version/207/paymentmethod/img/method/creditcard@2x.png b/version/207/paymentmethod/img/method/creditcard@2x.png index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..b08be792753326b65345c752a6f350182a9393d2 100644 GIT binary patch literal 3125 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 P00000NkvXXu0mjf3Vis# literal 0 HcmV?d00001 diff --git a/version/207/paymentmethod/img/method/directdebit@2x.png b/version/207/paymentmethod/img/method/directdebit@2x.png index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..514ff845b84d38cd8eb97b9e2c53e5c117967944 100644 GIT binary patch literal 801 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 literal 0 HcmV?d00001 diff --git a/version/207/paymentmethod/img/method/giropay@2x.png b/version/207/paymentmethod/img/method/giropay@2x.png index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..b787e1fee50c9bcca112f734ef4bcbd4ecfb6d6b 100644 GIT binary patch literal 602 zcmV-g0;T5Kx~EOrH!)pASu;4ojd8OQ8=; zpbt!;!_w#B>GK{}r)iJG@bvggdAR@o{+6-TrM%mCn#w$GvMpk*ho#Tb-RaC5+y)hho537JnGBqPA~G@Ik#rt1jWCNmt_X5yY-;OM4Sm|;L0fCz(H!a59C z!6FQJ1`O=K0(U?&WmHmQ%ovl1g=xY%=0>sX7T{!DDr3#1AfT>{>*NQdp;XxeDnn^6 z;Fg|~18)oh=#B%J574HG=ZK=b0(2)=ZWs@6u|Psp2S`Ms-aSCKNc4dZ3ml0Y1JpF0 zACT7(WFOdH$J={=+}Kh?t@=QTh`Y)S;{lL4q2$K&0aK;&(@GqDK&DI^R~^tLy#OA$ z1Nay30gQkc{Q&0jzz(SpmbnlhVhfzVhaBhB0($}wh1S_^$N7}lg}e4p3Ic|F4;Z~b zTY@72isxg1#8BrSfnxv^S{6kiGl4E$H2v|f@*S9m0aJJk172Vm21F3Hg)IO)g#GGT oVe}rh6KIQG--ZM8)e@S10aM=ZI#^TblmGw#07*qoM6N<$f@FIOx&QzG literal 0 HcmV?d00001 diff --git a/version/207/paymentmethod/img/method/ideal@2x.png b/version/207/paymentmethod/img/method/ideal@2x.png index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..efc4315a96a6b2d9b160578a65fe52206783f2ca 100644 GIT binary patch literal 845 zcmV-T1G4;yP)lk!ZZ65OMGC?}UYf;o;!m;NZf-!qXsn`1tsvqob6RlsGvz=jZ45_xJw({`vX& z+CYuwfU@xL?-Nv%`QPmApT=fqW&i*F(b3WK zzuD%1v(zAZ>+9>Xv$F87&$F|$@bK^%8W`-K#nT^p^1s=^!okAA!Tj&_DJdxZ{r%~X zz3Gp=&=7F!pvK@}pYN~F>5#mWl#|_1mb0_6g@uIHFobn>b?J}1M@UB*8yIC~W#VwE zc6N2$P?z9fpjKB^=ker~0000HbW%=J0PlbhkiUP=Adhe$&v1`#zea&7rvLx}*GWV{ zRCr#^*2j+9Fc5%YO7?ntl9{1;aqqou@0;Fxd;j;y*jNN`HV2Bl>~|3_{4oLqkzy%V z*t96C%}2Z9&SQ)86vWClksDVqqe|=&Z3|YQQjA*4CE6Eai>Qp6VzP3=CKt6Gk}WnU zMr|=|2#YGH?I~G;2n`TD#K5)puk^^z67b+ZZd-naz)7$!d_QRdc|mw#b1~<{2k2)FEaYF&OT-`GX$RPM#Nt`QAi#wXJk>zhFTO>59`Wo^#}<>sMjOed(+{-3ru0A7D$0jI558$ z)N0PF!RsCe2|{A+{jU4@5&uc>v9T(>X>= zpc$wJPDAG6XudKWan^4w_bUdHVBPG<>jQiVOn&QMzg?RgEbW=`(e{u7#up5;D^8W3 z2%8R3n@hIHS^6WCiFSq9p;8&OR7*Sn%M-cP>{s2YOOzKYHtDf;#GS4DUiRI4c22NA XzpeJ7+7%dW00000NkvXXu0mjfybi$$ literal 0 HcmV?d00001 diff --git a/version/207/paymentmethod/img/method/inghomepay@2x.png b/version/207/paymentmethod/img/method/inghomepay@2x.png index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..538f219588886db215757eafd5c5151241f18b5a 100644 GIT binary patch literal 1118 zcmV-k1flzhP)`_0RK|}|55<|Q2_r?0RL0~|5E_}r-1)w9RKX&|5E_}=Gy;L z0RR90|6UOPlVJbp-~WC<|J1+#zn}l9fd6P9|A|olb1?tk&;RxB|Mc(wo^bzkF#pQ0 z|Fn<)>fisgkpF2Q|G%LBsek{okpG@<|H-fazM%hUAODC@|H-ibs(=5~!2gtB|K894 zs(@(VAMyYI01|XkPE!C7&ySx#AdugXK#$)bkdUC?LT6GX000A7Nkl+_F4;G0`t->#NE zT;V&r`f!+EySiCj<6V7Pt?{mYTH&4jj{)gM0TN(F3?6st+kjw6 z>LApXPB>Unt8V~;Cik9f49AhQ!$i7^fuL#4vW=&{86JR|lTsG~BRymzfEs|JX9J1K z03Dw$1C&G3WKK=%kB`J1r1*<~s2`z=k6T78&3xGOL&RV&0xXfJ0Ql@xfEn*A1CX9E zQ!WBD5?VbTK7XTsCp`U6crw}TsH%60W z2hoh@0nLYSxRBab{+9<3C+^Mz9xYb&ZxhMVDb+cqriY2<9AG-<8gN)^Cix5?)@kAU z;?6$;-SN`NKvD-cR@w%n?9AWi0I~xRElDnK5^Rh@FtDVHX8@ZJfJl->N&_A{l2bso z2x`kJr-3lmJ%9)DK@>~Q{7brt3fNKr^rbrq+|{-iAekxBG;uoyGqur4Ei0S?0=Yll zF_SR>W}x;7ttLalDFCI-OXsp?(S;*|rkk|uOcTs~fUR;0m?79z>!T@dSC<#zVpen3 zDj@L*GoMZY$tw7C*m%o|vLvel!qz~FMPzph=x6{KTjppdC7aC#VVdHg)$wl$bf*AC z1-Rnnz*LgVO4|B5HX#U@PXUn*;sq_sC5u*2fG7j7o&o~>%Wn3WWcg~#QmPptG|8+k2H7XW|=xVi9nUeg`1*I2IB*YJ(+JNL|VD24JQDXa_~} zqMBf8fF~Vbz5wvk*3xb81`yK5AZAEW$9)?Qt+BO>C3E@1Aktu4fz|6HW^Y;1@lk!lq%mkX z{~%3y0h-K!%;mq#+4%VQ5J7OCv&KMYjPLUG@9*#T_xE6cpCPBxaK_?)nX{kS?7!yn zfSI!2=Is9d{_pwx05oR#`T5`T`RC{7L9^Llzu!=FmQcCekkjew>+3LDf{>=XK(pDe zzt4c0vd`J#Fs;_V%-D~nykNlKAg9yc^7t^U)_~3BfX(J`#^Vv8&k>-{-}3p8(&?|? z?{JN&{r&x)v&FFA?=V_}aEz&7z~7M5=+D{X&+PS}+3awQs351(ptHqzpNxV4000qm zQchCIy&+X> z=*5Ul;OaQ@NK`Vzy8t_g2?_Jis)3C$i910Xw$PIU9&Uk!LpkskEkL9-LfkOWJAbaP zUroip18r(eg}^hN*BXg{sb1!Yfc6S#iGXvxN(6jb7x=sau0_D;#S-`?0_b=FJSG`H zPqbnfvWg$g}i**@5@#v5NT=$lzqSQdXDg|8f zIHlhJQN%Mfm~#2YP9b1YgB(!GAN!r?CIjA)sTANZfG||7{JhG5H)Vm3e?0>E>_vVi zq!;d4SOSQYxt#%m;F70Lx8o{r!Tt9&c8CI14(M}40nf9jzsNQAmkVA7gAM$Z|1+@m z0b{)*&IIp+jVE#-MjL9Dd6xv65#{P&<3u77*DDnbtf@m157r`vbG^_r?Ff8 d>Rr1A+%FMH_Q$8Zwr>Cc002ovPDHLkV1oT`waEYg literal 0 HcmV?d00001 diff --git a/version/207/paymentmethod/img/method/klarna@2x.png b/version/207/paymentmethod/img/method/klarna@2x.png index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..e28a187b81e7c5a6256fea7382a643762746dd1e 100644 GIT binary patch literal 896 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 literal 0 HcmV?d00001 diff --git a/version/207/paymentmethod/img/method/paypal@2x.png b/version/207/paymentmethod/img/method/paypal@2x.png index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..a816d7201f59ea7cef713f5e7895e66dcd6ee9a7 100644 GIT binary patch literal 626 zcmV-&0*(ENP)zW{Q;0CK+oaK8X?zW{Q<0CB+pa=`#_!2of;na1S+alrro z|IFg@&*bxRu-m`e?~lRb-|hDbcETox$#AdRv()Q`yWm5X&|s$5P@dDD$>-eb_JFwG zpUUS$m(j@K@sPpeFpSLa_WMAU&p?#W{Qdsu^7&w=*MGR*^7#DO>Gd#+%P@?~P@U7S z((9ba=CIQ0sn6-_^!k0a-V=Mp)8_OXfyX(K&a%|&;_mkldc-e_%lZ5LgSp`#gUC6M z&erGk#LeN$0000GbW%=J0M8)rfN+qXfDoX6Z;yYFN6jxl0003wNklC4+MXiktqCYwRgSg6)KJbf z5Lj1?Y5+oU@|#dstX9C|0Ujt`J{M4b8Wr^cdi(ak0iFt>ORE}Nts8qh=FWCkI)}aEnE&{1?2hI?PIY68@ zbOdbw0PvXrf5i!Szy>sZ79ap>ye%)UHj^sMYbqagD6U zaJzaI>n$ypF23oVdS#o6|W|*DFT6j;X_Pjl^+{$7FxcM`F8{J!B6QqfZ6J=?T z0Z*i4z#}$g7~II(N7`*?T& O0000Mm~wpOtGdRMp-ebF zJuNaG78zVbOD!TMdRt_ueTc`Cq7MrUiDqwHL`pp^G2!3~t^fc45_D2dQvi?<&ySzq z&yPSLKp+s`&(ENlBcfvf009O`L_t(|UhS60Zp1JQL@BrJDI>X-t?BLmKQE>PBe{x1 zfE@On=HdqqA=xHol@*94&DRu2G6-2F{`otIN!gG=!IEeT6)Vc2!q5ULZU{>LN^lkQ z6ZNlrj1}04KE#&uMIop;cM5^ytf}zD`79SS9QTk5o_qtj!1)0xvEX2t7f1!iGHgI7 z7&;pYNCh93DJw_?;Rw7pazW)+@E{i;lyGtZ#-9>{b4|RUwsVO?IhoGU0(5hU(VOB0 z?V~Sog7riT<`S21tDgk|d|Kv}cTm1bUaD=+I8@G^{_l6;Dkz}hmJC$nw1J8>=|(U_ sv|A{Db!jJ_!6X#e-V3HE%!Veu0ZmugH{Fk>9RL6T07*qoM6N<$f);_{SO5S3 literal 0 HcmV?d00001 diff --git a/version/207/paymentmethod/tpl/bestellabschluss.tpl b/version/207/paymentmethod/tpl/bestellabschluss.tpl index e69de29..b26d8ef 100644 --- a/version/207/paymentmethod/tpl/bestellabschluss.tpl +++ b/version/207/paymentmethod/tpl/bestellabschluss.tpl @@ -0,0 +1,26 @@ +{if isset($oMollieException)} +
+ {$oMollieException->getMessage()} +
+ +{/if} + +{if isset($redirect) && $redirect != ''} + + {if $checkoutMode == 'D'} + + {/if} +{/if} + diff --git a/version/207/paymentmethod/tpl/mollieComponents.tpl b/version/207/paymentmethod/tpl/mollieComponents.tpl index e69de29..987abf1 100644 --- a/version/207/paymentmethod/tpl/mollieComponents.tpl +++ b/version/207/paymentmethod/tpl/mollieComponents.tpl @@ -0,0 +1,148 @@ +

{$mollieLang.cctitle}

+ +
+ +
+ + {if $token !== false} + +
+
+ {$mollieLang.clearDescr} +
+
+ +
+
+ + {if $trustBadge} +
+ PCI-DSS SAQ-A compliant +
+ {/if} + + {else} + + +
+ +
+
+
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+ +
+
+ + +
+
+ + {if $trustBadge} +
+ PCI-DSS SAQ-A compliant +
+ {/if} + {if $components == 'S'} + + {/if} +
+ +{/if} + + + + + + \ No newline at end of file diff --git a/version/207/tpl/_alerts.tpl b/version/207/tpl/_alerts.tpl new file mode 100644 index 0000000..5279fa3 --- /dev/null +++ b/version/207/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} From c4fc459907a4417117bda90ff7a97b580114206f Mon Sep 17 00:00:00 2001 From: Florian Klamer Date: Fri, 10 Jun 2022 10:58:26 +0200 Subject: [PATCH 280/280] #162 fix Klarna UTF-8 enforcement --- version/207/class/Checkout/Order/Address.php | 10 +++++----- version/207/class/Checkout/Payment/Address.php | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/version/207/class/Checkout/Order/Address.php b/version/207/class/Checkout/Order/Address.php index 9c7a01e..da762ac 100644 --- a/version/207/class/Checkout/Order/Address.php +++ b/version/207/class/Checkout/Order/Address.php @@ -27,13 +27,13 @@ public static function factory($address) { $resource = parent::factory($address); - $resource->title = substr(trim(($address->cAnrede === 'm' ? Shop::Lang()->get('mr') : Shop::Lang()->get('mrs')) . ' ' . $address->cTitel) ?: null, 0, 20); - $resource->givenName = $address->cVorname; - $resource->familyName = $address->cNachname; - $resource->email = $address->cMail ?: null; + $resource->title = html_entity_decode(substr(trim(($address->cAnrede === 'm' ? Shop::Lang()->get('mr') : Shop::Lang()->get('mrs')) . ' ' . $address->cTitel) ?: null, 0, 20)); + $resource->givenName = html_entity_decode($address->cVorname); + $resource->familyName = html_entity_decode($address->cNachname); + $resource->email = html_entity_decode($address->cMail) ?: null; if ($organizationName = trim($address->cFirma)) { - $resource->organizationName = $organizationName; + $resource->organizationName = html_entity_decode($organizationName); } // Validity-Check diff --git a/version/207/class/Checkout/Payment/Address.php b/version/207/class/Checkout/Payment/Address.php index 468a08a..7e33875 100644 --- a/version/207/class/Checkout/Payment/Address.php +++ b/version/207/class/Checkout/Payment/Address.php @@ -29,16 +29,16 @@ class Address extends AbstractResource public static function factory($address) { $resource = new static(); - $resource->streetAndNumber = $address->cStrasse . ' ' . $address->cHausnummer; - $resource->postalCode = $address->cPLZ; - $resource->city = $address->cOrt; - $resource->country = $address->cLand; + $resource->streetAndNumber = html_entity_decode($address->cStrasse . ' ' . $address->cHausnummer); + $resource->postalCode = html_entity_decode($address->cPLZ); + $resource->city = html_entity_decode($address->cOrt); + $resource->country = html_entity_decode($address->cLand); if ( isset($address->cAdressZusatz) && trim($address->cAdressZusatz) !== '' ) { - $resource->streetAdditional = trim($address->cAdressZusatz); + $resource->streetAdditional = html_entity_decode(trim($address->cAdressZusatz)); } // Validity-Check