From e57faf57a7ace75ff7089a29ec4c4ff2cf562253 Mon Sep 17 00:00:00 2001 From: "release@novalnetsolutions.com" Date: Thu, 13 Jun 2024 18:14:43 +0530 Subject: [PATCH] first commit --- Bootstrap.php | 89 + Migrations/Migration20210608221920.php | 78 + NovalnetPaymentHelper.php | 245 ++ NovalnetWebhookHandler.php | 1017 +++++++ README.md | 87 + adminmenu/NovalnetBackendTabRenderer.php | 234 ++ adminmenu/css/novalnet_admin.css | 49 + adminmenu/js/novalnet_admin.js | 354 +++ adminmenu/templates/novalnet_info.tpl | 46 + .../templates/novalnet_order_details.tpl | 77 + adminmenu/templates/novalnet_orders.tpl | 133 + changelog.txt | 55 + frontend/NovalnetCheckout.php | 28 + frontend/NovalnetCheckoutController.php | 181 ++ frontend/NovalnetHookHandler.php | 425 +++ frontend/NovalnetPostDataController.php | 317 ++ frontend/NovalnetReturn.php | 28 + frontend/NovalnetReturnController.php | 180 ++ frontend/js/novalnet_cc_logo.js | 54 + frontend/js/novalnet_wallet.js | 63 + frontend/js/novalnet_wallet_helper.js | 197 ++ frontend/template/account/order_details.tpl | 34 + frontend/template/basket/index.tpl | 12 + frontend/template/novalnet_return.tpl | 1 + frontend/template/novalnet_summary_page.tpl | 137 + .../template/novalnet_wallet_checkout.tpl | 27 + frontend/template/productdetails/basket.tpl | 24 + info.xml | 2651 +++++++++++++++++ locale/de-DE/base.mo | Bin 0 -> 15033 bytes locale/de-DE/base.po | 321 ++ locale/en-GB/base.mo | Bin 0 -> 14041 bytes locale/en-GB/base.po | 321 ++ paymentmethod/NovalnetAlipay.php | 221 ++ paymentmethod/NovalnetApplepay.php | 304 ++ paymentmethod/NovalnetBancontact.php | 221 ++ paymentmethod/NovalnetCashpayment.php | 221 ++ paymentmethod/NovalnetCreditcard.php | 372 +++ paymentmethod/NovalnetEps.php | 223 ++ paymentmethod/NovalnetGiropay.php | 221 ++ paymentmethod/NovalnetGooglepay.php | 305 ++ paymentmethod/NovalnetGuaranteedInvoice.php | 273 ++ paymentmethod/NovalnetGuaranteedSepa.php | 293 ++ paymentmethod/NovalnetIdeal.php | 221 ++ paymentmethod/NovalnetInstalmentInvoice.php | 289 ++ paymentmethod/NovalnetInstalmentSepa.php | 313 ++ paymentmethod/NovalnetInvoice.php | 220 ++ paymentmethod/NovalnetMultibanco.php | 204 ++ paymentmethod/NovalnetOnlineBankTransfer.php | 221 ++ paymentmethod/NovalnetPaymentGateway.php | 977 ++++++ paymentmethod/NovalnetPaypal.php | 253 ++ paymentmethod/NovalnetPostfinance.php | 221 ++ paymentmethod/NovalnetPostfinanceCard.php | 221 ++ paymentmethod/NovalnetPrepayment.php | 214 ++ paymentmethod/NovalnetPrzelewy24.php | 221 ++ paymentmethod/NovalnetSepa.php | 278 ++ paymentmethod/NovalnetSofort.php | 221 ++ paymentmethod/NovalnetTrustly.php | 221 ++ paymentmethod/NovalnetWeChatPay.php | 220 ++ paymentmethod/css/novalnet_payment_form.css | 80 + paymentmethod/images/novalnet_alipay.png | Bin 0 -> 1830 bytes paymentmethod/images/novalnet_amex.png | Bin 0 -> 1777 bytes paymentmethod/images/novalnet_applepay.png | Bin 0 -> 1733 bytes paymentmethod/images/novalnet_bancontact.png | Bin 0 -> 2763 bytes paymentmethod/images/novalnet_cartasi.png | Bin 0 -> 1460 bytes paymentmethod/images/novalnet_cartebleue.png | Bin 0 -> 2791 bytes paymentmethod/images/novalnet_cashpayment.png | Bin 0 -> 1636 bytes paymentmethod/images/novalnet_cc.png | Bin 0 -> 7501 bytes paymentmethod/images/novalnet_dinersclub.png | Bin 0 -> 2044 bytes paymentmethod/images/novalnet_discover.png | Bin 0 -> 1940 bytes paymentmethod/images/novalnet_eps.png | Bin 0 -> 1064 bytes paymentmethod/images/novalnet_giropay.png | Bin 0 -> 1223 bytes paymentmethod/images/novalnet_googlepay.png | Bin 0 -> 1121 bytes paymentmethod/images/novalnet_ideal.png | Bin 0 -> 1481 bytes paymentmethod/images/novalnet_invoice.png | Bin 0 -> 613 bytes paymentmethod/images/novalnet_jcb.png | Bin 0 -> 2198 bytes paymentmethod/images/novalnet_maestro.png | Bin 0 -> 1337 bytes paymentmethod/images/novalnet_mastercard.png | Bin 0 -> 1384 bytes paymentmethod/images/novalnet_multibanco.png | Bin 0 -> 2104 bytes .../images/novalnet_onlinebanktransfer.png | Bin 0 -> 5405 bytes .../images/novalnet_onlinetransfer.png | Bin 0 -> 1947 bytes paymentmethod/images/novalnet_paypal.png | Bin 0 -> 1976 bytes paymentmethod/images/novalnet_postfinance.png | Bin 0 -> 1986 bytes .../images/novalnet_postfinance_card.png | Bin 0 -> 2351 bytes paymentmethod/images/novalnet_prepayment.png | Bin 0 -> 978 bytes paymentmethod/images/novalnet_przelewy24.png | Bin 0 -> 2180 bytes paymentmethod/images/novalnet_sepa.png | Bin 0 -> 1152 bytes paymentmethod/images/novalnet_trustly.png | Bin 0 -> 1044 bytes paymentmethod/images/novalnet_unionpay.png | Bin 0 -> 2654 bytes paymentmethod/images/novalnet_visa.png | Bin 0 -> 1610 bytes paymentmethod/images/novalnet_wechatpay.png | Bin 0 -> 2092 bytes paymentmethod/js/novalnet_applepay_hide.js | 52 + paymentmethod/js/novalnet_payment_form.js | 301 ++ paymentmethod/js/novalnet_wallet_payment.js | 123 + paymentmethod/template/novalnet_applepay.tpl | 15 + paymentmethod/template/novalnet_cc.tpl | 78 + paymentmethod/template/novalnet_googlepay.tpl | 12 + .../template/novalnet_guaranteed_invoice.tpl | 43 + .../template/novalnet_guaranteed_sepa.tpl | 101 + .../template/novalnet_instalment_invoice.tpl | 80 + .../template/novalnet_instalment_sepa.tpl | 135 + paymentmethod/template/novalnet_sepa.tpl | 83 + 101 files changed, 15737 insertions(+) create mode 100755 Bootstrap.php create mode 100755 Migrations/Migration20210608221920.php create mode 100755 NovalnetPaymentHelper.php create mode 100755 NovalnetWebhookHandler.php create mode 100644 README.md create mode 100755 adminmenu/NovalnetBackendTabRenderer.php create mode 100755 adminmenu/css/novalnet_admin.css create mode 100755 adminmenu/js/novalnet_admin.js create mode 100755 adminmenu/templates/novalnet_info.tpl create mode 100755 adminmenu/templates/novalnet_order_details.tpl create mode 100755 adminmenu/templates/novalnet_orders.tpl create mode 100644 changelog.txt create mode 100755 frontend/NovalnetCheckout.php create mode 100755 frontend/NovalnetCheckoutController.php create mode 100755 frontend/NovalnetHookHandler.php create mode 100755 frontend/NovalnetPostDataController.php create mode 100755 frontend/NovalnetReturn.php create mode 100755 frontend/NovalnetReturnController.php create mode 100755 frontend/js/novalnet_cc_logo.js create mode 100755 frontend/js/novalnet_wallet.js create mode 100755 frontend/js/novalnet_wallet_helper.js create mode 100755 frontend/template/account/order_details.tpl create mode 100755 frontend/template/basket/index.tpl create mode 100755 frontend/template/novalnet_return.tpl create mode 100755 frontend/template/novalnet_summary_page.tpl create mode 100755 frontend/template/novalnet_wallet_checkout.tpl create mode 100755 frontend/template/productdetails/basket.tpl create mode 100755 info.xml create mode 100755 locale/de-DE/base.mo create mode 100755 locale/de-DE/base.po create mode 100755 locale/en-GB/base.mo create mode 100755 locale/en-GB/base.po create mode 100755 paymentmethod/NovalnetAlipay.php create mode 100755 paymentmethod/NovalnetApplepay.php create mode 100755 paymentmethod/NovalnetBancontact.php create mode 100755 paymentmethod/NovalnetCashpayment.php create mode 100755 paymentmethod/NovalnetCreditcard.php create mode 100755 paymentmethod/NovalnetEps.php create mode 100755 paymentmethod/NovalnetGiropay.php create mode 100755 paymentmethod/NovalnetGooglepay.php create mode 100755 paymentmethod/NovalnetGuaranteedInvoice.php create mode 100755 paymentmethod/NovalnetGuaranteedSepa.php create mode 100755 paymentmethod/NovalnetIdeal.php create mode 100755 paymentmethod/NovalnetInstalmentInvoice.php create mode 100755 paymentmethod/NovalnetInstalmentSepa.php create mode 100755 paymentmethod/NovalnetInvoice.php create mode 100755 paymentmethod/NovalnetMultibanco.php create mode 100755 paymentmethod/NovalnetOnlineBankTransfer.php create mode 100755 paymentmethod/NovalnetPaymentGateway.php create mode 100755 paymentmethod/NovalnetPaypal.php create mode 100755 paymentmethod/NovalnetPostfinance.php create mode 100755 paymentmethod/NovalnetPostfinanceCard.php create mode 100755 paymentmethod/NovalnetPrepayment.php create mode 100755 paymentmethod/NovalnetPrzelewy24.php create mode 100755 paymentmethod/NovalnetSepa.php create mode 100755 paymentmethod/NovalnetSofort.php create mode 100755 paymentmethod/NovalnetTrustly.php create mode 100755 paymentmethod/NovalnetWeChatPay.php create mode 100755 paymentmethod/css/novalnet_payment_form.css create mode 100755 paymentmethod/images/novalnet_alipay.png create mode 100755 paymentmethod/images/novalnet_amex.png create mode 100755 paymentmethod/images/novalnet_applepay.png create mode 100755 paymentmethod/images/novalnet_bancontact.png create mode 100755 paymentmethod/images/novalnet_cartasi.png create mode 100755 paymentmethod/images/novalnet_cartebleue.png create mode 100755 paymentmethod/images/novalnet_cashpayment.png create mode 100755 paymentmethod/images/novalnet_cc.png create mode 100755 paymentmethod/images/novalnet_dinersclub.png create mode 100755 paymentmethod/images/novalnet_discover.png create mode 100755 paymentmethod/images/novalnet_eps.png create mode 100755 paymentmethod/images/novalnet_giropay.png create mode 100755 paymentmethod/images/novalnet_googlepay.png create mode 100755 paymentmethod/images/novalnet_ideal.png create mode 100755 paymentmethod/images/novalnet_invoice.png create mode 100755 paymentmethod/images/novalnet_jcb.png create mode 100755 paymentmethod/images/novalnet_maestro.png create mode 100755 paymentmethod/images/novalnet_mastercard.png create mode 100755 paymentmethod/images/novalnet_multibanco.png create mode 100755 paymentmethod/images/novalnet_onlinebanktransfer.png create mode 100755 paymentmethod/images/novalnet_onlinetransfer.png create mode 100755 paymentmethod/images/novalnet_paypal.png create mode 100755 paymentmethod/images/novalnet_postfinance.png create mode 100755 paymentmethod/images/novalnet_postfinance_card.png create mode 100755 paymentmethod/images/novalnet_prepayment.png create mode 100755 paymentmethod/images/novalnet_przelewy24.png create mode 100755 paymentmethod/images/novalnet_sepa.png create mode 100755 paymentmethod/images/novalnet_trustly.png create mode 100755 paymentmethod/images/novalnet_unionpay.png create mode 100755 paymentmethod/images/novalnet_visa.png create mode 100755 paymentmethod/images/novalnet_wechatpay.png create mode 100755 paymentmethod/js/novalnet_applepay_hide.js create mode 100755 paymentmethod/js/novalnet_payment_form.js create mode 100755 paymentmethod/js/novalnet_wallet_payment.js create mode 100755 paymentmethod/template/novalnet_applepay.tpl create mode 100755 paymentmethod/template/novalnet_cc.tpl create mode 100755 paymentmethod/template/novalnet_googlepay.tpl create mode 100755 paymentmethod/template/novalnet_guaranteed_invoice.tpl create mode 100755 paymentmethod/template/novalnet_guaranteed_sepa.tpl create mode 100755 paymentmethod/template/novalnet_instalment_invoice.tpl create mode 100755 paymentmethod/template/novalnet_instalment_sepa.tpl create mode 100755 paymentmethod/template/novalnet_sepa.tpl diff --git a/Bootstrap.php b/Bootstrap.php new file mode 100755 index 0000000..3ca8da6 --- /dev/null +++ b/Bootstrap.php @@ -0,0 +1,89 @@ +getPlugin()); + + // Custom frontend operations for the Novalnet Plugin + $dispatcher->listen('shop.hook.' . \HOOK_BESTELLABSCHLUSS_INC_BESTELLUNGINDB, [$novalnetHookHandler, 'orderStatusPage']); + $dispatcher->listen('shop.hook.' . \HOOK_SMARTY_OUTPUTFILTER, [$novalnetHookHandler, 'contentUpdate']); + $dispatcher->listen('shop.hook.' . \HOOK_BESTELLVORGANG_PAGE, [$novalnetHookHandler, 'removeSavedDetails']); + $dispatcher->listen('shop.hook.' . \HOOK_JTL_PAGE, [$novalnetHookHandler, 'accountPage']); + $dispatcher->listen('shop.hook.' . \HOOK_BESTELLABSCHLUSS_INC_BESTELLUNGINDB_ENDE, [$novalnetHookHandler, 'changeWawiPickupStatus']); + $dispatcher->listen('shop.hook.' . \HOOK_IO_HANDLE_REQUEST, function (array $args) { + $novalnetPostDataController = new NovalnetPostDataController($args['io'], $args['request'], $this->getPlugin()); + $novalnetPostDataController->handlePostData(); + }); + + if (isset($_REQUEST['novalnet_webhook'])) { + + // When the Novalnet webhook is triggered and known through URL, we call the appropriate Novalnet webhook handler + $novalnetWebhookHandler = new NovalnetWebhookHandler($this->getPlugin()); + $dispatcher->listen('shop.hook.' . \HOOK_INDEX_NAVI_HEAD_POSTGET, [$novalnetWebhookHandler, 'handleNovalnetWebhook']); + } + + if (isset($_REQUEST['novalnet_refund'])) { + + // When the Novalnet webhook is triggered and known through URL, we call the appropriate Novalnet webhook handler + $novalnetWebhookHandler = new NovalnetWebhookHandler($this->getPlugin()); + $dispatcher->listen('shop.hook.' . \HOOK_INDEX_NAVI_HEAD_POSTGET, [$novalnetWebhookHandler, 'handleNovalnetRefund']); + } + } + } + + /** + * @param string $tabName + * @param int $menuID + * @param JTLSmarty $smarty + * @return string + */ + public function renderAdminMenuTab(string $tabName, int $menuID, JTLSmarty $smarty): string + { + // Render Novalnet Plugin's backend tabs and it's related functions + $backendRenderer = new NovalnetBackendTabRenderer($this->getPlugin(), $this->getDB()); + return $backendRenderer->renderNovalnetTabs($tabName, $menuID, $smarty); + } +} + diff --git a/Migrations/Migration20210608221920.php b/Migrations/Migration20210608221920.php new file mode 100755 index 0000000..b4b1e9e --- /dev/null +++ b/Migrations/Migration20210608221920.php @@ -0,0 +1,78 @@ +execute('CREATE TABLE IF NOT EXISTS `xplugin_novalnet_transaction_details` ( + `kId` int(10) NOT NULL AUTO_INCREMENT, + `cNnorderid` VARCHAR(64) NOT NULL, + `nNntid` BIGINT(20) NOT NULL, + `cZahlungsmethode` VARCHAR(64) NOT NULL, + `cMail` VARCHAR(255) NOT NULL, + `cStatuswert` VARCHAR(64), + `nBetrag` INT(11) NOT NULL, + `cSaveOnetimeToken` TINYINT(1) DEFAULT 0, + `cTokenInfo` LONGTEXT DEFAULT NULL, + `cAdditionalInfo` LONGTEXT DEFAULT NULL, + INDEX (cNnorderid, nNntid, cZahlungsmethode), + PRIMARY KEY (`kId`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci' + ); + + $this->execute('CREATE TABLE IF NOT EXISTS `xplugin_novalnet_callback` ( + `kId` INT(10) NOT NULL AUTO_INCREMENT, + `cNnorderid` VARCHAR(64) NOT NULL, + `nCallbackTid` BIGINT(20) NOT NULL, + `nReferenzTid` BIGINT(20) NOT NULL, + `cZahlungsmethode` VARCHAR(64) NOT NULL, + `dDatum` datetime NOT NULL, + `nCallbackAmount` INT(11) DEFAULT NULL, + `cWaehrung` VARCHAR(64) DEFAULT NULL, + INDEX (cNnorderid), + PRIMARY KEY (`kId`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci' + ); + } + + /** + * Delete Novalnet transaction details table during the novalnet plugin uninstallation + * + */ + public function down() + { + $this->execute('DROP TABLE IF EXISTS `xplugin_novalnet_transaction_details`'); + $this->execute('DROP TABLE IF EXISTS `xplugin_novalnet_callback`'); + } +} diff --git a/NovalnetPaymentHelper.php b/NovalnetPaymentHelper.php new file mode 100755 index 0000000..9c55b48 --- /dev/null +++ b/NovalnetPaymentHelper.php @@ -0,0 +1,245 @@ +plugin = $this->getNovalnetPluginObject(); + } + + /** + * Get plugin object + * + * @return object + */ + public function getNovalnetPluginObject() + { + return Helper::getPluginById('jtl_novalnet'); + } + + /** + * Retrieve configuration values stored under Novalnet Plugin + * + * @param string $configuration + * @param bool|string $paymentName + * @return mixed + */ + public function getConfigurationValues(string $configuration, $paymentName = false) + { + $configValue = $paymentName ? $paymentName . '_' . $configuration : $configuration; + + if (!empty($this->plugin->getConfig()->getValue($configValue))) { + + // Only for the tariff ID field, we extract the value which is separated by tariff value and type + if ($configValue == 'novalnet_tariffid') { + $tariffValue = trim($this->plugin->getConfig()->getValue('novalnet_tariffid')); + $tariffId = explode('-', $tariffValue); + return $tariffId[0]; + } + return is_string($this->plugin->getConfig()->getValue($configValue)) ? trim($this->plugin->getConfig()->getValue($configValue)) : $this->plugin->getConfig()->getValue($configValue); + } + + return null; + } + + /** + * Returning the list of the European Union countries for checking the country code of Guaranteed consumer + * + * @return array + */ + public function getEuropeanRegionCountryCodes(): array + { + return ['AT', 'BE', 'BG', 'CY', 'CZ', 'DE', 'DK', 'EE', 'ES', 'FI', 'FR', 'GR', 'HR', 'HU', 'IE', 'IT', 'LT', 'LU', 'LV', 'MT', 'NL', 'PL', 'PT', 'RO', 'SE', 'SI', 'SK', 'UK', 'CH']; + } + + /** + * Building the required billing and shipping details from customer session + * + * @return array + */ + public function getRequiredBillingShippingDetails(): array + { + // Extracting the billing address from Frontend Module + $billingAddress = Frontend::getCustomer(); + + $billingShippingDetails['billing'] = $billingShippingDetails['shipping'] = [ + 'street' => $billingAddress->cStrasse, + 'house_no' => $billingAddress->cHausnummer, + 'city' => $billingAddress->cOrt, + 'zip' => $billingAddress->cPLZ, + 'country_code' => $billingAddress->cLand + ]; + + // Extracting the shipping address from the session object + if (!empty($_SESSION['Lieferadresse'])) { + + $shippingAddress = $_SESSION['Lieferadresse']; + + $billingShippingDetails['shipping'] = [ + 'street' => $shippingAddress->cStrasse, + 'house_no' => $shippingAddress->cHausnummer, + 'city' => $shippingAddress->cOrt, + 'zip' => $shippingAddress->cPLZ, + 'country_code' => $shippingAddress->cLand + ]; + } + return $billingShippingDetails; + } + + /** + * Retrieving the reference details for one-click shopping + * + * @param string $paymentName + * @return array + */ + public function getPaymentReferenceValues($paymentName): ?array + { + $customerDetails = Frontend::getCustomer(); + + if (($customerDetails->kKunde) != '') { + $storedValues = Shop::Container()->getDB()->query('SELECT nNntid, cStatuswert, cTokenInfo FROM xplugin_novalnet_transaction_details WHERE cZahlungsmethode LIKE "%' . $paymentName . '" AND cMail = "' . $customerDetails->cMail . '" AND cSaveOnetimeToken = 1 AND cTokenInfo != "" ORDER BY kId DESC LIMIT 3', 2); + return ($storedValues != '') ? $storedValues : null; + } + return null; + } + + /** + * Convert the order amount from decimal to integer + * + * @return int + */ + public function getOrderAmount($order = null): int + { + if($order == null) { + $convertedOrderAmount = Currency::convertCurrency(Frontend::getCart()->gibGesamtsummeWaren(true), Frontend::getCurrency()->getCode()); + if (($convertedOrderAmount) == '') { + $convertedOrderAmount = $_SESSION['Warenkorb']->gibGesamtsummeWaren(true); + } + $orderAmount = str_replace(',', '.', sprintf('%.2f', $convertedOrderAmount)); + return (int) ($orderAmount * 100); + } else { + $orderAmount = ((float)$order->fGesamtsumme * (float)$order->fWaehrungsFaktor)*100; + return $orderAmount; + } + } + + /** + * Process the database update + * + * @param string $tableName + * @param string $keyName + * @param string $keyValue + * @param object $object + * @return none + */ + public function performDbUpdateProcess(string $tableName, $keyName, $keyValue, $object): void + { + Shop::Container()->getDB()->update($tableName , $keyName , $keyValue, (object) $object); + } + + /** + * Unsets the Novalnet payment sessions + * + * @return none + */ + public function novalnetSessionCleanUp(string $paymentName): void + { + $sessionValues = array( + 'nn_'.$paymentName.'_request', + 'nn_'.$paymentName.'_payment_response', + 'nn_comments', + 'novalnetWalletResponse', + 'nn_order_obj', + 'nn_wallet_token', + 'nn_wallet_amount', + 'nn_wallet_doredirect' + ); + + foreach($sessionValues as $sessionVal) { + unset($_SESSION[$paymentName]); + unset($_SESSION[$sessionVal]); + } + } + + /** + * Get language texts for the fields + * + * @param array $languages + * @return array + */ + public function getNnLanguageText(array $languages, $langCode = null): array + { + foreach($languages as $lang) { + $languageTexts[$lang] = $this->plugin->getLocalization()->getTranslation($lang, $langCode); + } + return $languageTexts; + } + + /** + * Get translated text for the provided Novalnet text key + * + * @param string $key + * @return string + */ + public function getNnLangTranslationText(string $key, $langCode = null): string + { + return $this->plugin->getLocalization()->getTranslation($key, $langCode); + } + + /** + * Get server or remote address from the global variable + * + * @param string $addressType + * @return mixed + */ + public function getNnIpAddress($addressType) + { + if ($addressType == 'REMOTE_ADDR') { + # Shop's core function that fetches the remote address + $remoteAddress = (Request::getRealIP() != '') ? Request::getRealIP() : $_SERVER[$addressType]; + return $remoteAddress; + } + return $_SERVER[$addressType]; + } +} diff --git a/NovalnetWebhookHandler.php b/NovalnetWebhookHandler.php new file mode 100755 index 0000000..ff4d989 --- /dev/null +++ b/NovalnetWebhookHandler.php @@ -0,0 +1,1017 @@ +novalnetPaymentGateway = new NovalnetPaymentGateway(); + } + + public function handleNovalnetWebhook() + { + try { + $this->eventData = json_decode(file_get_contents('php://input'), true); + } catch (Exception $e) { + $this->displayMessage('Received data is not in the JSON format' . $e); + } + + // validated the IP Address + $this->validateIpAddress(); + + // Validates the webhook params before processing + $this->validateEventParams(); + + // Set Event data + $this->eventType = $this->eventData['event']['type']; + $this->parentTid = (!empty($this->eventData['event']['parent_tid'])) ? $this->eventData['event']['parent_tid'] : $this->eventData['event']['tid']; + $this->eventTid = $this->eventData['event']['tid']; + + // Retreiving the shop's order information based on the transaction + $this->orderDetails = $this->getOrderReference(); + + $this->languageCode = ($this->orderDetails->kSprache == 1) ? 'ger' : 'eng'; + + if ($this->eventData['result']['status'] == 'SUCCESS') { + + switch ($this->eventType) { + case 'PAYMENT': + $this->displayMessage('The Payment has been received'); + break; + case 'TRANSACTION_CAPTURE': + case 'TRANSACTION_CANCEL': + $this->handleNnTransactionCaptureCancel(); + break; + case 'TRANSACTION_UPDATE': + $this->handleNnTransactionUpdate(); + break; + case 'TRANSACTION_REFUND': + $this->handleNnTransactionRefund(); + break; + case 'CREDIT': + $this->handleNnTransactionCredit(); + break; + case 'CHARGEBACK': + $this->handleNnChargeback(); + break; + case 'INSTALMENT': + $this->handleNnInstalment(); + break; + case 'INSTALMENT_CANCEL': + $this->handleNnInstalmentCancel(); + break; + default: + $this->displayMessage('The webhook notification has been received for the unhandled EVENT type ( ' . $this->eventType . ')' ); + } + } + } + + /** + * Display webhook notification message + * + * @param string $message + * @return none + */ + public function displayMessage($message): void + { + print $message; + exit; + } + + /** + * Validate the IP control check + * + * @return none + */ + public function validateIpAddress(): void + { + $novalnetHostIP = gethostbyname('pay-nn.de'); + $requestReceivedIP = $this->getRemoteAddress($novalnetHostIP); + + if (($novalnetHostIP) == '') { + $this->displayMessage('Novalnet HOST IP missing'); + } + + // Condition to check whether the callback is called from authorized IP + if (($novalnetHostIP !== $requestReceivedIP) && ($this->novalnetPaymentGateway->novalnetPaymentHelper->getConfigurationValues('novalnet_webhook_testmode')) == '') { + $this->displayMessage('Unauthorised access from the IP ' . $requestReceivedIP); + } + } + + /** + * Retrieves the original remote ip address with and without proxy + * + * @return string + */ + public function getRemoteAddress($novalnetHostIP) + { + $ip_keys = array('HTTP_X_FORWARDED_HOST', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_REAL_IP', 'HTTP_CLIENT_IP', 'HTTP_X_FORWARDED', 'HTTP_X_CLUSTER_CLIENT_IP', 'HTTP_FORWARDED_FOR', 'HTTP_FORWARDED', 'REMOTE_ADDR'); + foreach ($ip_keys as $key) { + if (array_key_exists($key, $_SERVER) === true) { + if(in_array($key, ['HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED_HOST'])) { + $forwardedIP = !empty($_SERVER[$key]) ? explode(',', $_SERVER[$key]) : []; + if(in_array($novalnetHostIP, $forwardedIP)) { + return $novalnetHostIP; + } else { + return $_SERVER[$key]; + } + } + return $_SERVER[$key]; + } + } + } + + /** + * Validates the event parameters + * + * @return none + */ + public function validateEventParams() + { + if(!empty( $this->eventData ['custom'] ['shop_invoked'])) { + $this->displayMessage('Process already handled in the shop.'); + } + + // Mandatory webhook params + $requiredParams = ['event' => ['type', 'checksum', 'tid'], 'result' => ['status']]; + + // Validate required parameters + foreach ($requiredParams as $category => $parameters) { + if (($this->eventData[$category]) == '') { + // Could be a possible manipulation in the notification data + $this->displayMessage('Required parameter category(' . $category. ') not received'); + } elseif (($parameters) != '') { + foreach ($parameters as $parameter) { + if (($this->eventData[$category][$parameter]) == '') { + // Could be a possible manipulation in the notification data + $this->displayMessage('Required parameter(' . $parameter . ') in the category (' . $category . ') not received'); + } + } + } + } + + // Validate the received checksum. + $this->validateChecksum(); + } + + /** + * Validate checksum + * + * @return none + */ + public function validateChecksum() + { + $accessKey = $this->novalnetPaymentGateway->novalnetPaymentHelper->getConfigurationValues('novalnet_private_key'); + $tokenString = $this->eventData['event']['tid'] . $this->eventData['event']['type'] . $this->eventData['result']['status']; + + if (isset($this->eventData['transaction']['amount'])) { + $tokenString .= $this->eventData['transaction']['amount']; + } + + if (isset($this->eventData['transaction']['currency'])) { + $tokenString .= $this->eventData['transaction']['currency']; + } + + if (($accessKey) != '') { + $tokenString .= strrev($accessKey); + } + + $generatedChecksum = hash('sha256', $tokenString); + if ($generatedChecksum !== $this->eventData['event']['checksum']) { + $this->displayMessage('While notifying some data has been changed. The hash check failed'); + } + } + + /** + * Get order details from the shop's database + * + * @return object + */ + public function getOrderReference(): object + { + // Looking into the Novalnet database if the transaction exists + $novalnetOrder = Shop::Container()->getDB()->query('SELECT cNnorderid, cZahlungsmethode, cStatuswert, nBetrag, cSaveOnetimeToken, cTokenInfo FROM xplugin_novalnet_transaction_details WHERE nNntid = "' . $this->parentTid . '"', ReturnType::SINGLE_OBJECT); + + // If both the order number from Novalnet and in shop is missing, then something is wrong + if (empty($this->eventData['transaction']['order_no']) && empty($novalnetOrder->cNnorderid)) { + $this->displayMessage('Order reference not found for the TID ' . $this->parentTid); + } + + $orderNumberToSearch = !empty($novalnetOrder->cNnorderid) ? $novalnetOrder->cNnorderid : $this->eventData['transaction']['order_no']; + + // If the order in the Novalnet server to the order number in Novalnet database doesn't match, then there is an issue + if (!empty($this->eventData['transaction']['order_no']) && !empty($novalnetOrder->cNnorderid) && (($this->eventData['transaction']['order_no']) != $novalnetOrder->cNnorderid)) { + $this->displayMessage('Order reference not matching for the order number ' . $orderNumberToSearch); + } + + $shopOrder = Shop::Container()->getDB()->query('SELECT kBestellung FROM tbestellung WHERE cBestellNr = "' . $orderNumberToSearch . '"', ReturnType::SINGLE_OBJECT); + + // Loads order object from shop + $order = new Bestellung((int) $shopOrder->kBestellung); + $order->fuelleBestellung(true, 0, false); + + // If the order is not found in Novalnet's database, it is communication failure + if (empty($novalnetOrder->cNnorderid)) { + + // We look into the shop's core database to create the order object for further handling + if (!empty($shopOrder->kBestellung)) { + // Handles communication failure scenario + $this->handleCommunicationBreak($order); + } else { + $this->displayMessage('Transaction mapping failed ' . $orderNumberToSearch); + } + } + + return (object) array_merge((array) $order, (array) $novalnetOrder); + } + + /** + * Handling communication breakup + * + * @param object $order + * @return none + */ + public function handleCommunicationBreak(object $order): void + { + $jtlPaymentmethod = Method::create($order->Zahlungsart->cModulId); + + $orderLanguage = ($order->kSprache == 1) ? 'ger' : 'eng'; + + $webhookComments = ''; + + $webhookComments .= $order->cZahlungsartName; + + $webhookComments .= \PHP_EOL . $this->novalnetPaymentGateway->novalnetPaymentHelper->getNnLangTranslationText('jtl_novalnet_transaction_tid', $orderLanguage) . $this->parentTid; + + if (!empty($this->eventData['transaction']['test_mode'])) { + $webhookComments .= \PHP_EOL . $this->novalnetPaymentGateway->novalnetPaymentHelper->getNnLangTranslationText('jtl_novalnet_test_order', $orderLanguage); + } + + $isPaidNow = false; + + // Deactivating the WAWI synchronization + $updateWawi = 'Y'; + + // Setting the payment Name + if (in_array($this->eventData['transaction']['payment_type'], array('DIRECT_DEBIT_SEPA', 'GUARANTEED_DIRECT_DEBIT_SEPA', 'INSTALMENT_DIRECT_DEBIT_SEPA'))) { + $paymentName = str_replace('DIRECT_DEBIT_', '', $this->eventData['transaction']['payment_type']); + } else { + $paymentName = (($this->eventData['transaction']['payment_type'] == 'CREDITCARD') ? 'CC' : (($this->eventData['transaction']['payment_type'] == 'ONLINE_TRANSFER') ? 'SOFORT' : $this->eventData['transaction']['payment_type'])); + } + + if ($this->eventData['result']['status'] == 'SUCCESS') { + + if ($this->eventData['transaction']['status']) { + + if ($this->eventData['transaction']['status'] == 'PENDING') { + $orderStatus = \BESTELLUNG_STATUS_OFFEN; + } elseif ($this->eventData['transaction']['status'] == 'ON_HOLD') { + $orderStatus = constant($this->novalnetPaymentGateway->novalnetPaymentHelper->getConfigurationValues('novalnet_onhold_order_status')); + } elseif ($this->eventData['transaction']['status'] == 'CONFIRMED') { + // For the successful case, we enable the WAWI synchronization + $updateWawi = 'N'; + $isPaidNow = true; + + $orderStatus = constant($this->novalnetPaymentGateway->novalnetPaymentHelper->getConfigurationValues('order_completion_status', strtolower('NOVALNET_'.$paymentName))); + + // Add the current transaction payment into db + $incomingPayment = new stdClass(); + $incomingPayment->fBetrag = $order->fGesamtsummeKundenwaehrung; + $incomingPayment->cISO = $order->Waehrung->cISO; + $incomingPayment->cHinweis = $this->parentTid; + $jtlPaymentmethod->name = $order->cZahlungsartName; + + $jtlPaymentmethod->addIncomingPayment($order, $incomingPayment); + } else { + $orderStatus = \BESTELLUNG_STATUS_STORNO; + $webhookComments .= \PHP_EOL . $this->eventData['result']['status_text']; + } + } + + // Sending the order update mail here as due to the communcation failure, the update mail would not have reached + $jtlPaymentmethod->sendMail($order->kBestellung, MAILTEMPLATE_BESTELLUNG_AKTUALISIERT); + + } else { + $orderStatus = \BESTELLUNG_STATUS_STORNO; + $webhookComments .= \PHP_EOL . $this->eventData['result']['status_text']; + } + + // Entering the details into the Novalnet's transactions details for consistency and further operations + $this->novalnetPaymentGateway->insertOrderDetailsIntoNnDb($order, $this->eventData, strtolower('NOVALNET_'.$paymentName)); + + // Completing the callback notification + $this->webhookFinalprocess($webhookComments, $orderStatus, $updateWawi, $isPaidNow); + } + + /** + * Handling the Novalnet transaction authorization process + * + * @return none + */ + public function handleNnTransactionCaptureCancel(): void + { + // Capturing or cancellation of a transaction occurs only when the transaction is found as ON_HOLD in the shop + if (in_array($this->orderDetails->cStatuswert, array('PENDING', 'ON_HOLD'))) { + + $isPaidNow = false; + + // If the transaction is captured, we update necessary alterations in DB + if ($this->eventType == 'TRANSACTION_CAPTURE') { + + // Activating the WAWI synchronization + $updateWawi = 'N'; + + $webhookComments = \PHP_EOL . sprintf($this->novalnetPaymentGateway->novalnetPaymentHelper->getNnLangTranslationText('jtl_novalnet_confirmation_text', $this->languageCode), date('d.m.Y'), date('H:i:s')); + + $amount = (strpos($this->eventData['transaction']['payment_type'], 'INSTALMENT') !== false) ? $this->eventData['instalment']['cycle_amount'] : $this->eventData['transaction']['amount']; + + if ($this->eventData['transaction']['payment_type'] == 'PAYPAL') { + $tokenInfo = !empty($this->orderDetails->cTokenInfo) ?? ''; + $this->eventData['transaction']['payment_data']['token'] = $tokenInfo['token']; + } + + // Certain payment methods require their tokens to be stored during capture + if ($this->orderDetails->cSaveOnetimeToken == 1 && (empty($this->orderDetails->cTokenInfo) || !empty($tokenInfo))) { + $this->novalnetPaymentGateway->novalnetPaymentHelper->performDbUpdateProcess('xplugin_novalnet_transaction_details', 'cNnorderid', $this->orderDetails->cBestellNr, ['cTokenInfo' => json_encode($this->eventData['transaction']['payment_data'])]); + } + + // Instalment payment methods cycle information + if (!empty($this->eventData['instalment'])) { + $this->novalnetPaymentGateway->novalnetPaymentHelper->performDbUpdateProcess('xplugin_novalnet_transaction_details', 'cNnorderid', $this->orderDetails->cBestellNr, ['cAdditionalInfo' => json_encode($this->eventData['instalment'])]); + } + + + // Only for the Invoice Payment type, we have to wait for the credit entry + if ($this->eventData['transaction']['payment_type'] != 'INVOICE') { + // Loads the order object + $order = new Bestellung((int) ($this->orderDetails->kBestellung)); + $order->fuelleBestellung(true, 0, false); + + // Add the incoming payments if the transaction was confirmed + $jtlPaymentmethod = Method::create($this->orderDetails->Zahlungsart->cModulId); + + $incomingPayment = new stdClass(); + $incomingPayment->fBetrag = $this->orderDetails->fGesamtsummeKundenwaehrung; + $incomingPayment->cISO = $this->orderDetails->Waehrung->cISO; + $incomingPayment->cHinweis = $this->parentTid; + $jtlPaymentmethod->name = $this->orderDetails->cZahlungsartName; + + // Add the current transaction payment into db + $jtlPaymentmethod->addIncomingPayment($order, $incomingPayment); + + $isPaidNow = true; + } + + // Order status required to be changed for the payment type + $orderStatus = constant($this->novalnetPaymentGateway->novalnetPaymentHelper->getConfigurationValues('order_completion_status', $this->orderDetails->cZahlungsmethode)); + + + } elseif($this->eventType == 'TRANSACTION_CANCEL') { + + $webhookComments = \PHP_EOL . sprintf($this->novalnetPaymentGateway->novalnetPaymentHelper->getNnLangTranslationText('jtl_novalnet_transaction_cancellation', $this->languageCode), date('d.m.Y'), date('H:i:s')); + + $orderStatus = \BESTELLUNG_STATUS_STORNO; + + // We do not want that cancelled orders picked up in WAWI + $updateWawi = 'Y'; + } + + $this->eventData['transaction']['amount'] = ($this->eventData['transaction']['payment_type'] == 'INVOICE') ? 0 : $this->eventData['transaction']['amount']; + $this->webhookFinalprocess($webhookComments, $orderStatus, $updateWawi, $isPaidNow); + + + } else { + $this->displayMessage('Transaction already captured/cancelled'); + } + } + + /** + * Handling the Novalnet transaction update process + * + * @return none + */ + public function handleNnTransactionUpdate(): void + { + // Paid is set to NULL + $isPaidNow = false; + + // orderStatus is set to empty + $orderStatus = ''; + + // Set the WAWI status + $updateWawi = ($this->eventData['transaction']['status'] == 'CONFIRMED') ? 'N' : 'Y'; + + if ($this->eventData['transaction']['update_type'] == 'STATUS') { + + if ($this->eventData['transaction']['status'] == 'DEACTIVATED') { + + $webhookComments = sprintf($this->novalnetPaymentGateway->novalnetPaymentHelper->getNnLangTranslationText('jtl_novalnet_transaction_cancellation', $this->languageCode), date('d.m.Y'), date('H:i:s')); + + // Cancellation of the order status + $orderStatus = \BESTELLUNG_STATUS_STORNO; + + } else { + + if ($this->orderDetails->cStatuswert == 'PENDING' && in_array($this->eventData['transaction']['status'], ['ON_HOLD', 'CONFIRMED'])) { + + $webhookComments = ''; + + if (in_array($this->eventData['transaction']['payment_type'], ['INVOICE', 'PREPAYMENT', 'GUARANTEED_INVOICE', 'INSTALMENT_INVOICE'])) { + $webhookComments = $this->novalnetPaymentGateway->getBankdetailsInformation($this->orderDetails, $this->eventData, $this->languageCode); + } + + // For on-hold, we only update the order status + if ($this->eventData['transaction']['status'] == 'ON_HOLD') { + // Building the onhold activation text + $webhookComments .= \PHP_EOL . \PHP_EOL . sprintf($this->novalnetPaymentGateway->novalnetPaymentHelper->getNnLangTranslationText('jtl_novalnet_pending_to_onhold_status_change', $this->languageCode), $this->parentTid, date('d.m.Y'), date('H:i:s')); + + $orderStatus = constant($this->novalnetPaymentGateway->novalnetPaymentHelper->getConfigurationValues('novalnet_onhold_order_status')); + } else { + + $amount = (strpos($this->eventData['transaction']['payment_type'], 'INSTALMENT') !== false) ? $this->eventData['instalment']['cycle_amount'] : $this->eventData['transaction']['amount']; + + $updateAmount = $this->novalnetPaymentGateway->convertCurrencyFormatter($this->orderDetails->kBestellung, ($amount)); + + // Building the confirmation text + $webhookComments .= \PHP_EOL . \PHP_EOL . sprintf($this->novalnetPaymentGateway->novalnetPaymentHelper->getNnLangTranslationText('jtl_novalnet_update_confirmation_text', $this->languageCode), $this->parentTid, $updateAmount, date('d.m.Y'), date('H:i:s')); + + // Instalment payment methods cycle information + if (!empty($this->eventData['instalment'])) { + $this->novalnetPaymentGateway->novalnetPaymentHelper->performDbUpdateProcess('xplugin_novalnet_transaction_details', 'cNnorderid', $this->orderDetails->cBestellNr, ['cAdditionalInfo' => json_encode($this->eventData['instalment'])]); + } + + $orderStatus = constant($this->novalnetPaymentGateway->novalnetPaymentHelper->getConfigurationValues('order_completion_status', $this->orderDetails->cZahlungsmethode)); + + if ($this->eventData['transaction']['payment_type'] != 'INVOICE') { + // Paid is set to NULL + $isPaidNow = true; + } + } + } + + } + } else { + + $webhookComments = ''; + + $updateAmount = $this->novalnetPaymentGateway->convertCurrencyFormatter($this->orderDetails->kBestellung, ($this->eventData['transaction']['amount'])); + $dueDateUpdateMessage = \PHP_EOL . sprintf($this->novalnetPaymentGateway->novalnetPaymentHelper->getNnLangTranslationText('jtl_novalnet_duedate_update_message', $this->languageCode), $updateAmount, date('d.m.Y', strtotime($this->eventData['transaction']['due_date'])), date('d.m.Y'), date('H:i:s')); + + // Amount update process + if($this->eventData['transaction']['amount'] != $this->orderDetails->nBetrag && !in_array($this->eventData['transaction']['payment_type'], array('INSTALMENT_INVOICE', 'INSTALMENT_SEPA'))) { + $this->novalnetPaymentGateway->novalnetPaymentHelper->performDbUpdateProcess('xplugin_novalnet_transaction_details', 'cNnorderid', $this->orderDetails->cBestellNr, ['nBetrag' => $this->eventData['transaction']['amount']]); + } + + $amountUpdateMessage = \PHP_EOL . sprintf($this->novalnetPaymentGateway->novalnetPaymentHelper->getNnLangTranslationText('jtl_novalnet_amount_update_message', $this->languageCode), $updateAmount, date('d.m.Y'), date('H:i:s')); + + $webhookComments .= (($this->eventData['transaction']['update_type'] == 'AMOUNT') ? $amountUpdateMessage : (($this->eventData['transaction']['update_type'] == 'DUE_DATE') ? $dueDateUpdateMessage : $dueDateUpdateMessage . $amountUpdateMessage)); + + } + + $this->webhookFinalprocess($webhookComments, $orderStatus, $updateWawi, $isPaidNow); + } + + /** + * Handling the transaction refund process + * + * @return none + */ + public function handleNnTransactionRefund(): void + { + + if ($this->eventData['result']['status'] == 'SUCCESS') { + + $refundedAmount = $this->novalnetPaymentGateway->convertCurrencyFormatter($this->orderDetails->kBestellung, ($this->eventData['transaction']['refund']['amount'])); + + $webhookComments = \PHP_EOL . sprintf($this->novalnetPaymentGateway->novalnetPaymentHelper->getNnLangTranslationText('jtl_novalnet_refund_execution', $this->languageCode), $this->parentTid, $refundedAmount); + + if (!empty($this->eventData['transaction']['refund']['tid'])) { + $webhookComments .= \PHP_EOL . sprintf($this->novalnetPaymentGateway->novalnetPaymentHelper->getNnLangTranslationText('jtl_novalnet_new_tid_refund_execution', $this->languageCode), $this->eventData['transaction']['refund']['tid']); + } + + // In case of full refund, deactivation is processed + if ($this->eventData['transaction']['status'] == 'DEACTIVATED') { + + // We do not send to webhookFinalprocess for update as it will cause problems with WAWI synchronization + $this->novalnetPaymentGateway->novalnetPaymentHelper->performDbUpdateProcess('tbestellung', 'cBestellNr', $this->orderDetails->cBestellNr, ['cStatus' => \BESTELLUNG_STATUS_STORNO]); + } + + $txAdditonalDetails = Shop::Container()->getDB()->query('SELECT cAdditionalInfo FROM xplugin_novalnet_transaction_details WHERE cNnorderid = "' . $this->orderDetails->cBestellNr . '"', ReturnType::SINGLE_OBJECT); + + $txAdditonalInfo = !empty($txAdditonalDetails->cAdditionalInfo) ? json_decode($txAdditonalDetails->cAdditionalInfo, true) : []; + + $txAdditonalInfo['refunded_amount'] = $this->eventData['transaction']['refunded_amount'] + $this->eventData['transaction']['refund']['amount']; + + $this->novalnetPaymentGateway->novalnetPaymentHelper->performDbUpdateProcess('xplugin_novalnet_transaction_details', 'cNnorderid', $this->orderDetails->cBestellNr, ['cAdditionalInfo' => json_encode($txAdditonalInfo)]); + + } + + $this->webhookFinalprocess($webhookComments); + } + + /** + * Handling the credit process + * + * @return none + */ + public function handleNnTransactionCredit(): void + { + $creditAmount = $this->novalnetPaymentGateway->convertCurrencyFormatter($this->orderDetails->kBestellung, ($this->eventData['transaction']['amount'])); + + $webhookComments = \PHP_EOL . sprintf($this->novalnetPaymentGateway->novalnetPaymentHelper->getNnLangTranslationText('jtl_novalnet_webhook_initial_execution', $this->languageCode), $this->parentTid, $creditAmount, date('d.m.Y'), date('H:i:s'), $this->eventTid); + + if (in_array($this->eventData['transaction']['payment_type'], ['INVOICE_CREDIT', 'CASHPAYMENT_CREDIT', 'ONLINE_TRANSFER_CREDIT', 'MULTIBANCO_CREDIT'])) { + + $callbackDetails = Shop::Container()->getDB()->query('SELECT SUM(nCallbackAmount) AS kCallbackAmount FROM xplugin_novalnet_callback WHERE cNnorderid = "' . $this->orderDetails->cBestellNr . '" and nCallbackTid != nReferenzTid', ReturnType::SINGLE_OBJECT); + + $refundDetails = Shop::Container()->getDB()->query('SELECT cAdditionalInfo FROM xplugin_novalnet_transaction_details WHERE cNnorderid = "' . $this->orderDetails->cBestellNr . '"', ReturnType::SINGLE_OBJECT); + + + $callbackDetails->kCallbackAmount = !empty($callbackDetails->kCallbackAmount) ? $callbackDetails->kCallbackAmount : 0; + + $orderPaidAmount = $callbackDetails->kCallbackAmount + $this->eventData['transaction']['amount']; + $orderAmount = $this->orderDetails->fGesamtsumme * 100; + + $refundInfo = !empty($refundDetails->cAdditionalInfo) ? json_decode($refundDetails->cAdditionalInfo, true) : 0; + + $orderPaidAmount = $orderPaidAmount - (!empty($refundInfo['refunded_amount']) ? $refundInfo['refunded_amount'] : 0); + $orderAmount = $orderAmount - (!empty($refundInfo['refunded_amount']) ? $refundInfo['refunded_amount'] : 0); + + if ($orderPaidAmount >= $orderAmount) { + // Loads the order object + $order = new Bestellung((int) ($this->orderDetails->kBestellung)); + $order->fuelleBestellung(true, 0, false); + + // Add the current transaction payment into db + $jtlPaymentmethod = Method::create($this->orderDetails->Zahlungsart->cModulId); + + $incomingPayment = new stdClass(); + $incomingPayment->fBetrag = $this->orderDetails->fGesamtsummeKundenwaehrung; + $incomingPayment->cISO = $this->orderDetails->Waehrung->cISO; + $incomingPayment->cHinweis = $this->parentTid; + $jtlPaymentmethod->name = $this->orderDetails->cZahlungsartName; + + $jtlPaymentmethod->addIncomingPayment($order, $incomingPayment); + + $orderStatus = ($this->eventData['transaction']['payment_type'] == 'ONLINE_TRANSFER_CREDIT') ? \BESTELLUNG_STATUS_BEZAHLT : constant($this->novalnetPaymentGateway->novalnetPaymentHelper->getConfigurationValues('callback_status', $this->orderDetails->cZahlungsmethode)); + + $this->webhookFinalprocess($webhookComments, $orderStatus, 'N', true); + + } else { + $this->webhookFinalprocess($webhookComments); + } + } else { + $this->webhookFinalprocess($webhookComments); + } + } + + /** + * Handling the chargeback process + * + * @return none + */ + public function handleNnChargeback(): void + { + $chargeBackAmount = $this->novalnetPaymentGateway->convertCurrencyFormatter($this->orderDetails->kBestellung, ($this->eventData['transaction']['amount'])); + + if ($this->eventData['transaction']['payment_type'] == 'RETURN_DEBIT_SEPA') { + $webhookComments = \PHP_EOL . sprintf($this->novalnetPaymentGateway->novalnetPaymentHelper->getNnLangTranslationText('jtl_novalnet_return_debit_execution_text', $this->languageCode), $this->parentTid, $chargeBackAmount, date('d.m.Y'), date('H:i:s'), $this->eventTid); + + } elseif ($this->eventData['transaction']['payment_type'] == 'REVERSAL') { + $webhookComments = \PHP_EOL . sprintf($this->novalnetPaymentGateway->novalnetPaymentHelper->getNnLangTranslationText('jtl_novalnet_reversal_execution_text', $this->languageCode), $this->parentTid, $chargeBackAmount, date('d.m.Y'), date('H:i:s'), $this->eventTid); + } else { + $webhookComments = \PHP_EOL . sprintf($this->novalnetPaymentGateway->novalnetPaymentHelper->getNnLangTranslationText('jtl_novalnet_chargeback_execution_text', $this->languageCode), $this->parentTid, $chargeBackAmount, date('d.m.Y'), date('H:i:s'), $this->eventTid); + } + + $this->webhookFinalprocess($webhookComments); + } + + /** + * Handling the Instalment payment execution + * + * @return none + */ + public function handleNnInstalment(): void + { + if ($this->eventData['transaction']['status'] == 'CONFIRMED' && !empty($this->eventData['instalment']['cycles_executed'])) { + $additionalInstalmentMsg = $nextSepaInstalmentMsg = ''; + + $installmentAmount = $this->novalnetPaymentGateway->convertCurrencyFormatter($this->orderDetails->kBestellung, ($this->eventData['instalment']['cycle_amount'])); + + $webhookComments = \PHP_EOL . sprintf($this->novalnetPaymentGateway->novalnetPaymentHelper->getNnLangTranslationText('jtl_novalnet_instalment_payment_execution', $this->languageCode), $this->parentTid, $installmentAmount, date('d.m.Y'), date('H:i:s'), $this->eventTid); + + $additionalInfo = Shop::Container()->getDB()->query('SELECT cAdditionalInfo FROM xplugin_novalnet_transaction_details WHERE cNnorderid = "' . $this->orderDetails->cBestellNr . '"', ReturnType::SINGLE_OBJECT); + + $instalmentCyclesInfo = json_decode($additionalInfo->cAdditionalInfo, true); + $insCycleCount = $this->eventData['instalment']['cycles_executed']; + $instalmentCyclesInfo[$insCycleCount]['tid'] = $this->eventTid; + + $this->novalnetPaymentGateway->novalnetPaymentHelper->performDbUpdateProcess('xplugin_novalnet_transaction_details', 'cNnorderid', $this->orderDetails->cBestellNr, ['cAdditionalInfo' => json_encode($instalmentCyclesInfo)]); + + if (empty($this->eventData['instalment']['prepaid'])) { + if ($this->eventData['transaction']['payment_type'] == 'INSTALMENT_INVOICE') { + $additionalInstalmentMsg = \PHP_EOL . $this->novalnetPaymentGateway->getBankdetailsInformation($this->orderDetails, $this->eventData, $this->languageCode); + + } + } + + $instalmentInfo = $this->novalnetPaymentGateway->getInstalmentInfoFromDb($this->orderDetails->cBestellNr, $this->languageCode, $this->orderDetails->kBestellung); + + $webhookComments .= $nextSepaInstalmentMsg; + // Send mail notification to customer regarding the new instalment creation + $this->sendInstalmentMailNotification($instalmentInfo, $additionalInstalmentMsg); + + $this->webhookFinalprocess($webhookComments); + } + } + + /** + * Handling the Instalment cancelation + * + * @return none + */ + public function handleNnInstalmentCancel(): void + { + if ($this->eventData['transaction']['status'] == 'CONFIRMED' && $this->orderDetails->cStatuswert != 'DEACTIVATED') { + $additionalInfo = Shop::Container()->getDB()->queryPrepared('SELECT cAdditionalInfo FROM xplugin_novalnet_transaction_details WHERE cNnorderid = :cNnorderid', [':cNnorderid' => $this->orderDetails->cBestellNr,], ReturnType::SINGLE_OBJECT); + + $instalmentCyclesInfo = json_decode($additionalInfo->cAdditionalInfo, true); + + $instalmentCyclesInfo['is_full_instalment_cancel'] = ($this->eventData['instalment']['cancel_type'] == 'ALL_CYCLES') ? 'all_cycles' : 'remaining_cycles'; + + $this->novalnetPaymentGateway->novalnetPaymentHelper->performDbUpdateProcess('xplugin_novalnet_transaction_details', 'cNnorderid', $this->orderDetails->cBestellNr, ['cAdditionalInfo' => json_encode($instalmentCyclesInfo)]); + + $webhookComments = PHP_EOL . sprintf($this->novalnetPaymentGateway->novalnetPaymentHelper->getNnLangTranslationText('jtl_novalnet_instalment_cancellation', $this->languageCode), $this->parentTid, date('d.m.Y'), date('H:i:s')); + + if ($instalmentCyclesInfo['is_full_instalment_cancel'] == 'remaining_cycles') { + $webhookComments = sprintf($this->novalnetPaymentGateway->novalnetPaymentHelper->getNnLangTranslationText('jtl_novalnet_instalment_cancellation_remaining_cycle', $this->languageCode), $this->parentTid, date('d.m.Y'), date('H:i:s')); + $this->webhookFinalprocess($webhookComments); + } else { + $this->novalnetPaymentGateway->novalnetPaymentHelper->performDbUpdateProcess('xplugin_novalnet_transaction_details', 'cNnorderid', $this->orderDetails->cBestellNr, ['cStatuswert' => 'DEACTIVATED']); + $this->webhookFinalprocess($webhookComments, \BESTELLUNG_STATUS_STORNO, 'Y'); + } + } + } + + /** + * Performs final callback process + * + * @param string $webhookMessage + * @param string $orderStatusToUpdate + * @param string $updateWawiStatus + * @param bool $isPaidNow + * @return none + */ + public function webhookFinalprocess($webhookMessage, $orderStatusToUpdate = '', $updateWawiStatus = 'N', $isPaidNow = false) + { + $oldTransactionComment = Shop::Container()->getDB()->query('SELECT cKommentar, kSprache FROM tbestellung WHERE cBestellNr = "' . $this->orderDetails->cBestellNr . '"', ReturnType::SINGLE_OBJECT); + + if (strpos($this->eventData['transaction']['payment_type'], 'INVOICE') !== false) { + if($this->eventType == 'TRANSACTION_CAPTURE') { + if (strpos($oldTransactionComment->cKommentar, 'auf das folgende Konto') !== false && $oldTransactionComment->kSprache == 1) { + $oldTransactionComment->cKommentar = str_replace('auf das folgende Konto', 'spätestens bis zum ' . date('d.m.Y', strtotime($this->eventData['transaction']['due_date'])) . ' auf das folgende Konto', $oldTransactionComment->cKommentar); + } else { + $oldTransactionComment->cKommentar = str_replace('to the following account', 'to the following account on or before ' . date('d.m.Y', strtotime($this->eventData['transaction']['due_date'])) , $oldTransactionComment->cKommentar); + } + } + + if(($this->eventType == 'INSTALMENT' || $this->eventType == 'TRANSACTION_UPDATE' && in_array($this->eventData['transaction']['update_type'], array('DUE_DATE', 'AMOUNT_DUE_DATE'))) && (preg_match('/before(.*)/', $oldTransactionComment->cKommentar, $matches) || preg_match('/zum(.*)/', $oldTransactionComment->cKommentar, $matches))) { + + $oldTransactionComment->cKommentar = ($oldTransactionComment->kSprache == 1) ? str_replace($matches[1], date('d.m.Y', strtotime($this->eventData['transaction']['due_date'])) . ' auf das folgende Konto', $oldTransactionComment->cKommentar) : str_replace($matches[0], 'before ' . date('d.m.Y', strtotime($this->eventData['transaction']['due_date'])) , $oldTransactionComment->cKommentar); + } + + + if ($this->eventType == 'INSTALMENT' && preg_match("/([0-9]{17})/s", $oldTransactionComment->cKommentar, $matches)) { + if (strpos($oldTransactionComment->cKommentar, 'Novalnet-Transaktions-ID:') !== false && $oldTransactionComment->kSprache == 1) { + $oldTransactionComment->cKommentar = str_replace('Novalnet-Transaktions-ID: ' . $matches[0], 'Novalnet-Transaktions-ID: ' . $this->eventTid, $oldTransactionComment->cKommentar); + $oldTransactionComment->cKommentar = str_replace('Zahlungsreferenz: ' . $matches[0], 'Zahlungsreferenz: ' . $this->eventTid, $oldTransactionComment->cKommentar); + } else { + $oldTransactionComment->cKommentar = str_replace('Novalnet transaction ID: ' . $matches[0], 'Novalnet transaction ID: ' . $this->eventTid, $oldTransactionComment->cKommentar); + $oldTransactionComment->cKommentar = str_replace('Payment Reference: ' . $matches[0], 'Payment Reference: ' . $this->eventTid, $oldTransactionComment->cKommentar); + } + } + + if(($this->eventType == 'INSTALMENT' || $this->eventType == 'TRANSACTION_UPDATE' && in_array($this->eventData['transaction']['update_type'], array('AMOUNT', 'AMOUNT_DUE_DATE'))) && (preg_match('/(.*)to the following/', $oldTransactionComment->cKommentar, $matches) || preg_match('/(.*)spätestens/', $oldTransactionComment->cKommentar, $matches))) { + $updatedOrderAmount = $this->eventType == 'INSTALMENT' ? $this->eventData['instalment']['cycle_amount'] : + $this->eventData['transaction']['amount']; + + $oldTransactionComment->cKommentar = ($oldTransactionComment->kSprache == 1) ? str_replace($matches[1], 'Bitte überweisen Sie den Betrag von ' . number_format($updatedOrderAmount / 100 , 2, ',', '') . ' '. $this->orderDetails->Waehrung->htmlEntity, $oldTransactionComment->cKommentar) : str_replace($matches[1], 'Please transfer the amount of ' . number_format($updatedOrderAmount / 100 , 2, ',', '') . ' '. $this->orderDetails->Waehrung->htmlEntity , $oldTransactionComment->cKommentar); + } + } + + $webhookComments = !empty($oldTransactionComment->cKommentar) ? ($oldTransactionComment->cKommentar . \PHP_EOL . $webhookMessage) : $webhookMessage; + + $orderNo = !empty($this->orderDetails->cBestellNr) ? ($this->orderDetails->cBestellNr) : $this->eventData['transaction']['order_no']; + + if (!empty($orderStatusToUpdate)) { + // Updating the necessary details into the core order table related to the webhook transaction + $this->novalnetPaymentGateway->novalnetPaymentHelper->performDbUpdateProcess('tbestellung', 'cBestellNr', $orderNo, ['cKommentar' => $webhookComments, 'cStatus' => $orderStatusToUpdate, 'cAbgeholt' => $updateWawiStatus, 'dBezahltDatum' => ($isPaidNow ? 'NOW()' : '')]); + } else { + $this->novalnetPaymentGateway->novalnetPaymentHelper->performDbUpdateProcess('tbestellung', 'cBestellNr', $orderNo, ['cKommentar' => $webhookComments, 'cAbgeholt' => $updateWawiStatus, 'dBezahltDatum' => ($isPaidNow ? 'NOW()' : '')]); + } + + // Updating in the Novalnet transaction table + $this->novalnetPaymentGateway->novalnetPaymentHelper->performDbUpdateProcess('xplugin_novalnet_transaction_details', 'cNnorderid', $orderNo, ['cStatuswert' => $this->eventData['transaction']['status']]); + + // Logging the webhook event notification for further handling and troubleshooting + $this->logWebhookProcess(); + + + // Send the order update mail when the transaction has been confirmed or amount and due date update + if ($this->eventType == 'TRANSACTION_CAPTURE' || (isset($this->eventData['transaction']['update_type']) && in_array($this->eventData['transaction']['update_type'], array('AMOUNT', 'DUE_DATE', 'AMOUNT_DUE_DATE'))) || (isset($this->eventData['transaction']['update_type']) && $this->eventData['transaction']['update_type'] == 'STATUS' && $this->eventData['transaction']['status'] == 'CONFIRMED')) { + $jtlPaymentmethod = Method::create($this->orderDetails->Zahlungsart->cModulId); + + $jtlPaymentmethod->sendMail($this->orderDetails->kBestellung, MAILTEMPLATE_BESTELLUNG_AKTUALISIERT); + + } + + // Send mail for merchant + $this->sendMailNotification($webhookMessage); + } + + /** + * To log webhook process into the callback table + * + * @return none + */ + public function logWebhookProcess() + { + $insertCallback = new stdClass(); + $insertCallback->cNnorderid = !empty($this->orderDetails->cBestellNr) ? $this->orderDetails->cBestellNr : ''; + $insertCallback->nCallbackTid = $this->parentTid; + $insertCallback->nReferenzTid = $this->eventTid; + $insertCallback->cZahlungsmethode = !empty($this->orderDetails->cZahlungsartName) ? $this->orderDetails->cZahlungsartName : ''; + $insertCallback->dDatum = date('Y-m-d H:i:s'); + $insertCallback->nCallbackAmount = ($this->eventType == 'TRANSACTION_REFUND') ? $this->eventData['transaction']['refund']['amount'] : (isset($this->eventData['transaction']['amount']) ? $this->eventData['transaction']['amount'] : 0); + $insertCallback->cWaehrung = !empty($this->orderDetails->Waehrung->code) ? $this->orderDetails->Waehrung->code : ''; + + Shop::Container()->getDB()->insert('xplugin_novalnet_callback', $insertCallback); + } + + /** + * Triggers mail notification to the mail address specified + * + * @param array $webhookMessage + * @return none + */ + public function sendMailNotification($webhookMessage) + { + // Looping in through the core plugin's mail templates + foreach ($this->novalnetPaymentGateway->novalnetPaymentHelper->plugin->getMailTemplates()->getTemplatesAssoc() as $mailTemplate) { + + if ($mailTemplate->cModulId == 'novalnetwebhookmail' && $mailTemplate->cAktiv == 'Y') { + + $adminDetails = Shop::Container()->getDB()->query('SELECT cMail from tadminlogin LIMIT 1', ReturnType::SINGLE_OBJECT); + + // Notification is sent only when the admin login email is configured + if (!empty($adminDetails->cMail)) { + + $data = new stdClass(); + $data->webhookMessage = nl2br($webhookMessage); + $data->tkunde = $this->orderDetails->oKunde; + + // Constructing the mail object + $mail = new Mail(); + $mail->setToMail($adminDetails->cMail); + + // Replacing the template variable with the webhook message + $mail = $mail->createFromTemplateID('kPlugin_' . $this->novalnetPaymentGateway->novalnetPaymentHelper->plugin->getID() . '_novalnetwebhookmail', $data); + + // Preparing the shop send email function for dispatching the custom email + $mailer = Shop::Container()->get(Mailer::class); + $mailer->send($mail); + } + break; + } + } + $this->displayMessage($webhookMessage); + } + + public function sendInstalmentMailNotification(array $instalmentInfo, string $additionalInfo) { + // Looping in through the core plugin's mail templates + foreach ($this->novalnetPaymentGateway->novalnetPaymentHelper->plugin->getMailTemplates()->getTemplatesAssoc() as $mailTemplate) { + + if ($mailTemplate->cModulId == 'novalnetinstalmentmail' && $mailTemplate->cAktiv == 'Y') { + $instalmentMsg = \PHP_EOL . $this->novalnetPaymentGateway->novalnetPaymentHelper->getNnLangTranslationText('jtl_novalnet_next_instalment_message', $this->languageCode); + + $instalmentMsg .= '

' . $this->novalnetPaymentGateway->novalnetPaymentHelper->getNnLangTranslationText('jtl_novalnet_invoice_payments_order_number_reference', $this->languageCode) . $this->orderDetails->cBestellNr; + $instalmentMsg .= '
' . $this->orderDetails->cZahlungsartName; + + $instalmentMsg .= nl2br($additionalInfo); + + $webhookMessage = '

'.$this->novalnetPaymentGateway->novalnetPaymentHelper->getNnLangTranslationText('jtl_novalnet_instalment_information', $this->languageCode).'

+ + + + + + + + + + + + '; + foreach ($instalmentInfo['insDetails'] as $key => $instalment) { + $status = ($instalment['tid'] != '-') ? ($this->languageCode == 'ger' ? 'Bezahlt' : 'Paid') : ($this->languageCode == 'ger' ? 'Offen' : 'Open'); + $webhookMessage .= ' + + + + + + + '; + } + $webhookMessage .= ' + +
'. $this->novalnetPaymentGateway->novalnetPaymentHelper->getNnLangTranslationText('jtl_novalnet_serial_no', $this->languageCode). '' .$this->novalnetPaymentGateway->novalnetPaymentHelper->getNnLangTranslationText('jtl_novalnet_transaction_tid', $this->languageCode).''.$this->novalnetPaymentGateway->novalnetPaymentHelper->getNnLangTranslationText('jtl_novalnet_instalment_amount', $this->languageCode).''.$this->novalnetPaymentGateway->novalnetPaymentHelper->getNnLangTranslationText('jtl_novalnet_instalment_future_date', $this->languageCode).'Status
'.$key.''.$instalment['tid'].''.$instalment['cycle_amount'].''.$instalment['future_instalment_date'].''.$status.'
'; + + $data = new stdClass(); + $data->nextInstalmentMsg = $instalmentMsg; + $data->instalmentMessage = $webhookMessage; + $data->tkunde = $this->orderDetails->oKunde; + + // Constructing the mail object + $mail = new Mail(); + $mail->setToMail($this->orderDetails->oKunde->cMail); + + // Replacing the template variable with the webhook message + $mail = $mail->createFromTemplateID('kPlugin_' . $this->novalnetPaymentGateway->novalnetPaymentHelper->plugin->getID() . '_novalnetinstalmentmail', $data); + + // Preparing the shop send email function for dispatching the custom email + $mailer = Shop::Container()->get(Mailer::class); + $mailer->send($mail); + } + } + } + + public function handleNovalnetRefund() { + + // Get the order number from wawi + $getKeyValues = $_POST; + $orderNumber = array_keys($getKeyValues); + + // Get the amount, and TID from Database + $orderDetails = Shop::Container()->getDB()->query('SELECT nBetrag, nNntid, cAdditionalInfo FROM xplugin_novalnet_transaction_details WHERE cNnorderid = "' . $orderNumber[0] . '"', ReturnType::SINGLE_OBJECT); + $oldTransactionComment = Shop::Container()->getDB()->query('SELECT cKommentar, kSprache FROM tbestellung WHERE cBestellNr = "' . $orderNumber[0] . '"', ReturnType::SINGLE_OBJECT); + $amount = json_decode($orderDetails->nBetrag, true); + $tid = json_decode($orderDetails->nNntid, true); + $txAdditonalDetails = json_decode($orderDetails->cAdditionalInfo, true); + $lang = json_decode($oldTransactionComment->kSprache, true); + $this->languageCode = $lang == 2 ? 'eng' : 'ger'; + + // Form the refund request Parameters + $data = []; + $data['transaction'] = [ + 'tid' => $tid, + 'amount' => $amount, + ]; + $data['custom'] = [ + 'lang' => $lang == 2 ? 'EN' : 'DE', + 'shop_invoked' => 1 + ]; + + // Do the refund call to Novalnet server + $response = $this->novalnetPaymentGateway->performServerCall($data, 'transaction_refund'); + + // Create a new entry into callback table for the refund details + $insertCallback = new stdClass(); + $insertCallback->cNnorderid = !empty($response['transaction']['order_no']) ? $response['transaction']['order_no'] : ''; + $insertCallback->nCallbackTid = $response['transaction']['tid']; + $insertCallback->nReferenzTid = $response['transaction']['refund']['tid']; + $insertCallback->cZahlungsmethode = ''; + $insertCallback->dDatum = date('Y-m-d H:i:s'); + $insertCallback->nCallbackAmount = ($response['transaction']['refund']['amount']) ? $response['transaction']['refund']['amount'] : (isset($response['transaction']['amount']) ? $response['transaction']['amount'] : 0); + $insertCallback->cWaehrung = !empty($response['transaction']['currency']) ? $response['transaction']['currency'] : ''; + Shop::Container()->getDB()->insert('xplugin_novalnet_callback', $insertCallback); + + // Handling the refund success response + if ($response['result']['status'] == 'SUCCESS') { + // Form the refund new tid comments by the response + $refundedAmount = $this->novalnetPaymentGateway->convertCurrencyFormatter($this->orderDetails->kBestellung, ($this->eventData['transaction']['refund']['amount'])); + $webhookComments = \PHP_EOL . sprintf($this->novalnetPaymentGateway->novalnetPaymentHelper->getNnLangTranslationText('jtl_novalnet_refund_execution', $this->languageCode), $this->parentTid, $refundedAmount); + if (!empty($response['transaction']['refund']['tid'])) { + $webhookComments .= PHP_EOL . sprintf($this->novalnetPaymentGateway->novalnetPaymentHelper->getNnLangTranslationText('jtl_novalnet_new_tid_refund_execution', $this->languageCode), $response['transaction']['refund']['tid']); + } + + // Store the refunded amount details into the Database + $txAdditonalInfo = !empty($txAdditonalDetails) ? $txAdditonalDetails : []; + $txAdditonalInfo['refunded_amount'] = $response['transaction']['refunded_amount']; + $this->novalnetPaymentGateway->novalnetPaymentHelper->performDbUpdateProcess('xplugin_novalnet_transaction_details', 'cNnorderid', $orderNumber[0], ['cAdditionalInfo' => json_encode($txAdditonalInfo)]); + + } else { + $webhookComments = PHP_EOL . $response['result']['status_text']; + } + + // Store the refund comments into the Database + $oldTransactionComment = Shop::Container()->getDB()->query('SELECT cKommentar, kSprache FROM tbestellung WHERE cBestellNr = "' . $orderNumber[0] . '"', ReturnType::SINGLE_OBJECT); + $webhookMessage = !empty($oldTransactionComment->cKommentar) ? ($oldTransactionComment->cKommentar . \PHP_EOL . $webhookComments) : $webhookComments; + $cKommentar = array('cKommentar' => $webhookMessage); + $cStatus = []; + // In case of full refund, deactivation is processed + if ($response['transaction']['status'] == 'DEACTIVATED') { + // We do not send to webhookFinalprocess for update as it will cause problems with WAWI synchronization + $cStatus = array('cStatus' => \BESTELLUNG_STATUS_STORNO); + } + + $updateValues = array_merge($cKommentar, $cStatus); + // Update comments and status into the Database + $this->novalnetPaymentGateway->novalnetPaymentHelper->performDbUpdateProcess('tbestellung', 'cBestellNr', $orderNumber[0], $updateValues); + + } + +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..5dbf1bf --- /dev/null +++ b/README.md @@ -0,0 +1,87 @@ +# JTL5 SHOP PAYMENT PLUGIN BY NOVALNET + +The JTL shop payment plugin by Novalnet enables secure integration of payments and payment services for all JTL shops. Novalnet payment plugin for JTL shop helps merchants to automate payment processing from checkout till collection. + +## Integration Requirements for JTL5 Shop Payment Plugin + +The module is available for the 5.0.0 - 5.3.2 versions in the following languages: EN & DE and requires PHP versions 5.6 and higher. +Novalnet merchant account is required for processing all international and local payments in JTL shop. You can get yours here: https://www.novalnet.de/kontakt/sales + +## Key Features of JTL5 Shop Payment Plugin + +* Easy configuration of all payment methods (local & international) +* Up-to-date payment portfolio & automated processing +* Plug & Play platform eliminating the need of extra plugins/scripts/contracts +* PCI-certified payment integration +* Credit Card with 3D Secure +* Seamless checkout Iframe integration +* Comprehensive fraud prevention solution with more than 60 modules +* Secure SSL encoded gateways +* On-hold transaction configuration in the shop admin panel +* One click shopping supported Credit/Debit Cards & Direct Debit SEPA +* Zero amount authorization supported for Credit/Debit Cards, Direct Debit SEPA, Apple Pay & Google Pay +* Real-time synchronization of data between JTL-Shop and JTL-Wawi +* Responsive templates + +For detailed documentation and other technical inquiries, please send us an email at sales@novalnet.de + +## Integrated Payment Methods + +- Direct Debit SEPA +- Direct Debit ACH +- Credit/Debit Cards +- Apple Pay +- Google Pay +- Invoice +- Prepayment +- Invoice with payment guarantee +- Direct Debit SEPA with payment guarantee +- Instalment by Invoice +- Instalment by Direct Debit SEPA +- iDEAL +- Sofort +- giropay +- Barzahlen/viacash +- Przelewy24 +- eps +- PayPal +- MB Way +- PostFinance Card +- PostFinance E-Finance +- Bancontact +- Multibanco +- Online bank transfer +- Alipay +- WeChat Pay +- Trustly +- Blik +- Payconiq + +## Installation of JTL5 Shop Payment Plugin + +Follow these steps for JTL shop Payment Integration by Novalnet: +1. Get the payment plugin for JTL shop & detailed documentation by contacting us +2. Upload the payment plugin to your JTL shop +3. Activate the plugin +4. Configure Product Activation Key & Payment access key in the shop admin panel +5. Activate & configure the preferred payment types in your shop admin panel + +## License + +See our License Agreement at: https://www.novalnet.com/payment-plugins-free-license/ + +## Documentation & Support +For more information about the JTL 5 Shop Payment Integration by Novalnet, please get in touch with us: sales@novalnet.de or +49 89 9230683-20
+ +Novalnet AG
+Zahlungsinstitut (ZAG)
+Gutenbergstraße 7
+D-85748 Garching
+Deutschland
+E-mail: sales@novalnet.de
+Tel: +49 89 9230683-20
+Web: www.novalnet.de + +## Who is Novalnet? + +Novalnet AG is a German payment provider offering payment gateways for online merchants and marketplaces worldwide. Our PCI DSS certified SaaS engine is designed to automate the entire payment process from checkout to debt collection – with a single integration. We cover real-time risk management; secure payments (local + international) through escrow accounts, integrate receivables management, dynamic member and subscription management as well as other customized payment solutions to your JTL shop. For a complete and seamless shop system we do support JTL-Wawi integration for JTL shop. diff --git a/adminmenu/NovalnetBackendTabRenderer.php b/adminmenu/NovalnetBackendTabRenderer.php new file mode 100755 index 0000000..d47650a --- /dev/null +++ b/adminmenu/NovalnetBackendTabRenderer.php @@ -0,0 +1,234 @@ +plugin = $plugin; + $this->db = $db; + $this->novalnetPaymentGateway = new NovalnetPaymentGateway(); + } + + /** + * @param string $tabName + * @param int $menuID + * @param JTLSmarty $smarty + * @return string + * @throws \SmartyException + */ + public function renderNovalnetTabs(string $tabName, int $menuID, JTLSmarty $smarty): string + { + $this->smarty = $smarty; + + if ($tabName == 'Info') { + return $this->renderNovalnetInfoPage(); + } elseif ($tabName == 'Bestellungen') { + return $this->renderNovalnetOrdersPage($menuID); + } else { + throw new InvalidArgumentException('Cannot render tab ' . $tabName); + } + } + + /** + * Display the Novalnet info template page + * + * @return string + */ + private function renderNovalnetInfoPage(): string + { + $novalnetRequestType = !empty($_REQUEST['nn_request_type']) ? $_REQUEST['nn_request_type'] : null; + $langCode = ($_SESSION['AdminAccount']->language == 'de-DE') ? 'ger' : 'eng'; + $novalnetWebhookUrl = !empty($this->novalnetPaymentGateway->novalnetPaymentHelper->getConfigurationValues('novalnet_webhook_url')) ? $this->novalnetPaymentGateway->novalnetPaymentHelper->getConfigurationValues('novalnet_webhook_url') : Shop::getURL() . '/?novalnet_webhook'; + + if (!empty($novalnetRequestType)) { + // Based on the request type, we either auto-configure the merchant settings or configure the webhook URL + if ($novalnetRequestType == 'autofill') { + $this->handleMerchantAutoConfig($_REQUEST); + } elseif ($novalnetRequestType == 'configureWebhook') { + $this->configureWebhookUrl($_REQUEST); + } + } + + return $this->smarty->assign('pluginDetails', $this->plugin) + ->assign('postUrl', Shop::getURL() . '/' . \PFAD_ADMIN . 'plugin.php?kPlugin=' . $this->plugin->getID()) + ->assign('languageTexts', $this->novalnetPaymentGateway->novalnetPaymentHelper->getNnLanguageText(['jtl_novalnet_notification_text', 'jtl_novalnet_configure_webhook', 'jtl_novalnet_webhook_alert_text', 'jtl_novalnet_webhook_notification_text', 'jtl_novalnet_webhook_error_text', 'jtl_novalnet_webhook_configuration_tooltip', 'jtl_novalnet_due_date_error_text', 'jtl_novalnet_guarantee_min_amount_error_text', 'jtl_novalnet_instalment_min_amount_error_text', 'jtl_novalnet_guarantee_condition_text', 'jtl_novalnet_instalment_condition_text', 'jtl_novalnet_webhook_notification', 'jtl_novalnet_paypal_configuration_text', 'jtl_novalnet_info_page_text', 'jtl_novalnet_multiselect_option_text', 'jtl_novalnet_google_pay_merchant_id_error'], $langCode)) + ->assign('shopLang', $_SESSION['AdminAccount']->language) + ->assign('adminUrl', $this->plugin->getPaths()->getadminURL()) + ->assign('webhookUrl', $novalnetWebhookUrl) + ->assign('shopName', Shop::getSettingValue(\CONF_GLOBAL, 'global_shopname')) + ->fetch($this->plugin->getPaths()->getAdminPath() . 'templates/novalnet_info.tpl'); + } + + /** + * Display the Novalnet order template + * + * @param int $menuID + * @return string + */ + private function renderNovalnetOrdersPage(int $menuID): string + { + $novalnetRequestType = !empty($_REQUEST['nn_request_type']) ? $_REQUEST['nn_request_type'] : null; + + if (!empty($novalnetRequestType)) { + $this->displayNovalnetorderDetails($_REQUEST, $menuID); + } + + $orders = []; + $nnOrderCount = $this->db->query('SELECT cNnorderid FROM xplugin_novalnet_transaction_details', ReturnType::AFFECTED_ROWS); + $pagination = (new Pagination('novalnetorders'))->setItemCount($nnOrderCount)->assemble(); + $langCode = ($_SESSION['AdminAccount']->language == 'de-DE') ? 'ger' : 'eng'; + + $orderArr = $this->db->query('SELECT DISTINCT ord.kBestellung FROM tbestellung ord JOIN xplugin_novalnet_transaction_details nov WHERE ord.cBestellNr = nov.cNnorderid ORDER BY ord.kBestellung DESC LIMIT ' . $pagination->getLimitSQL(), ReturnType::ARRAY_OF_OBJECTS); + + foreach ($orderArr as $order) { + $orderId = (int) $order->kBestellung; + $ordObj = new Bestellung($orderId); + $ordObj->fuelleBestellung(true, 0, false); + $orders[$orderId] = $ordObj; + } + + if ($_SESSION['AdminAccount']->language == 'de-DE') { + $paymentStatus = ['5' => 'teilversendet', '4' => 'versendet', '3' => 'bezahlt', '2' => 'in Bearbeitung' , '1' => 'offen' , '-1' => 'Storno']; + } else { + $paymentStatus = ['5' => 'partially shipped', '4' => 'shipped', '3' => 'paid', '2' => 'in processing' , '1' => 'open' , '-1' => 'canceled']; + } + + return $this->smarty->assign('orders', $orders) + ->assign('pagination', $pagination) + ->assign('pluginId', $this->plugin->getID()) + ->assign('postUrl', Shop::getURL() . '/' . \PFAD_ADMIN . 'plugin.php?kPlugin=' . $this->plugin->getID()) + ->assign('paymentStatus', $paymentStatus) + ->assign('hash', 'plugin-tab-' . $menuID) + ->assign('languageTexts', $this->novalnetPaymentGateway->novalnetPaymentHelper->getNnLanguageText(['jtl_novalnet_order_number', 'jtl_novalnet_customer_text', 'jtl_novalnet_payment_name_text', 'jtl_novalnet_wawi_pickup', 'jtl_novalnet_total_amount_text', 'jtl_novalnet_order_creation_date', 'jtl_novalnet_orders_not_available'], $langCode)) + ->fetch($this->plugin->getPaths()->getAdminPath() . 'templates/novalnet_orders.tpl'); + } + + /** + * Handling of the merchant auto configuration process + * + * @param array $post + * @return none + */ + private function handleMerchantAutoConfig(array $post): void + { + $autoConfigRequestParams = []; + $autoConfigRequestParams['merchant']['signature'] = $post['nn_public_key']; + $autoConfigRequestParams['custom']['lang'] = ($_SESSION['AdminAccount']->language == 'de-DE') ? 'DE' : 'EN'; + + $responseData = $this->novalnetPaymentGateway->performServerCall($autoConfigRequestParams, 'merchant_details', $post['nn_private_key']); + print json_encode($responseData); + exit; + } + + + /** + * Configuring webhook URL in admin portal + * + * @param array $post + * @return none + */ + private function configureWebhookUrl(array $post): void + { + $webhookRequestParams = []; + $webhookRequestParams['merchant']['signature'] = $post['nn_public_key']; + $webhookRequestParams['webhook']['url'] = $post['nn_webhook_url']; + $webhookRequestParams['custom']['lang'] = ($_SESSION['AdminAccount']->language == 'de-DE') ? 'DE' : 'EN'; + + $responseData = $this->novalnetPaymentGateway->performServerCall($webhookRequestParams, 'webhook_configure', $post['nn_private_key']); + + // Upon successful intimation in Novalnet server, we also store it in the internal DB + if ($responseData['result']['status'] == 'SUCCESS') { + $this->novalnetPaymentGateway->novalnetPaymentHelper->performDbUpdateProcess('tplugineinstellungen', 'cName', 'novalnet_webhook_url', ['cWert' => $post['nn_webhook_url']]); + } + + print json_encode($responseData); + exit; + } + + /** + * Display the Novalnet transaction details template + * + * @param int $menuID + * @return string + */ + private function displayNovalnetorderDetails(array $post, int $menuID): string + { + $getOrder = $this->db->query('SELECT ord.kBestellung, ord.cKommentar, ord.kSprache FROM tbestellung ord JOIN xplugin_novalnet_transaction_details nov ON ord.cBestellNr = nov.cNnorderid WHERE cNnorderid = "' . $post['order_no'] . '"', ReturnType::SINGLE_OBJECT); + + $langCode = ($getOrder->kSprache == 1) ? 'ger' : 'eng'; + + $instalmentInfo = $this->novalnetPaymentGateway->getInstalmentInfoFromDb($post['order_no'], $langCode, $getOrder->kBestellung); + + $smartyVar = $this->smarty->assign('adminUrl', $this->plugin->getPaths()->getadminURL()) + ->assign('orderNo', $post['order_no']) + ->assign('languageTexts',$this->novalnetPaymentGateway->novalnetPaymentHelper->getNnLanguageText(['jtl_novalnet_invoice_payments_order_number_reference'], $langCode)) + ->assign('orderComment', $getOrder) + ->assign('menuId', '#plugin-tab-' . $menuID) + ->assign('instalmentDetails', $instalmentInfo) + ->fetch($this->plugin->getPaths()->getAdminPath() . 'templates/novalnet_order_details.tpl'); + + print $smartyVar; + exit; + } +} + diff --git a/adminmenu/css/novalnet_admin.css b/adminmenu/css/novalnet_admin.css new file mode 100755 index 0000000..c5d566c --- /dev/null +++ b/adminmenu/css/novalnet_admin.css @@ -0,0 +1,49 @@ +.nn_fa { + float: right; + font-size: 15px; +} + +.nn_additional_content { + border-left: 3px solid #5cbcf6 !important; + padding: 5px 10px; + background-color: #f5f7fa; + border: 1px solid #f5f7fa; +} + +.nn_content { + font-size: 13px; +} + +#nn_header { + color :#e85b0e; + font-size:14px; + font-weight:bold; +} + +.body_div { + padding:5px; + overflow-y:auto; + margin-bottom : 2%; + height:82%; +} + +#overlay_window_block_body h1 { + font-weight:bold; +} + +#nn_transaction_details { + line-height: 2.0; +} + +.nn_back_tab { + color: white; + float: right; + padding-left: 15px; + padding-right: 15px; +} + +.nn_webhook_button, .nn_webhook_notify, .nn_paypal_notify { + margin-left: 35% !important; +} + + diff --git a/adminmenu/js/novalnet_admin.js b/adminmenu/js/novalnet_admin.js new file mode 100755 index 0000000..85e5fa6 --- /dev/null +++ b/adminmenu/js/novalnet_admin.js @@ -0,0 +1,354 @@ +jQuery(document).ready(function() { + // Validate the Google Pay Seller name + if(jQuery('#novalnet_googlepay_seller_name').val() == '') { + jQuery('#novalnet_googlepay_seller_name').val(jQuery('#nn_shop_name').val()); + } + + // Validate the Apple Pay Seller name + if(jQuery('#novalnet_applepay_seller_name').val() == '') { + jQuery('#novalnet_applepay_seller_name').val(jQuery('#nn_shop_name').val()); + } + + // Add minimum, maximum length and case sensitive attribute to merchant country code + jQuery('#novalnet_googlepay_country_code').attr({minlength: 2, maxlength: 2}); + jQuery('#novalnet_googlepay_country_code').on('input',function ( event ) { + let merchantCountryCode = jQuery(this).val().replace( /[^A-Z]+/g, "" ).replace( /\s+/g, "" ); + jQuery(this).val(merchantCountryCode); + }); + + // Select all credit card types + if (jQuery('#novalnet_cc_accepted_card_types').val() == '') { + jQuery('#novalnet_cc_accepted_card_types option').each(function() { + var optionVal = jQuery(this).val(); + jQuery('#novalnet_cc_accepted_card_types option[value=' + optionVal + ']').attr('selected', true); + + }); + } + + // Select all credit card types + jQuery.each(['#novalnet_applepay_button_display', '#novalnet_googlepay_button_display'], function (index, element) { + if (jQuery(element).val() == '') { + jQuery(element + ' option').each(function() { + var optionVal = jQuery(this).val(); + jQuery(element + ' option[value=' + optionVal + ']').attr('selected', true); + }); + } + }); + + // Select default instalment cycles + jQuery.each(['#novalnet_instalment_invoice_cycles', '#novalnet_instalment_sepa_cycles'], function (index, element) { + if (jQuery('#nn_shop_lang').val() != 'de-DE') { + jQuery(element + ' ' + 'option').each(function() { + jQuery(this).text(jQuery(this).html().replace(/\bZyklen\b/g, 'Cycle')); + }); + } + + if (jQuery(element).val() == '') { + jQuery(element + ' ' + 'option').each(function() { + if (jQuery(this).val() <= 36) { + jQuery(element + ' ' + 'option[value=' + jQuery(this).val() + ']').attr('selected', true); + } + }); + } + }); + + // Alert if the multiple selection doesn' have anyne selection + jQuery.each(['#novalnet_cc_accepted_card_types', '#novalnet_instalment_invoice_cycles', '#novalnet_instalment_sepa_cycles'], function (index, element) { + jQuery(element).on('change', function () { + if (!jQuery(element + ' ' + "option:selected").length) { + handleErrorElement(jQuery(element), jQuery('#nn_multiselect_text').val()); + } + }); + }); + + // set the toggle for the payment settings + var paymentSettings = jQuery('.tab-content').children()[2]; + + jQuery(paymentSettings).find('[class*=subheading]').append(''); + + jQuery(paymentSettings).find('.mb-3').hover(function () { + jQuery(this).css('cursor', 'pointer'); + }); + + // Show and hide the authorization amount field value + jQuery.each(['cc', 'sepa', 'invoice', 'paypal', 'guaranteed_invoice', 'guaranteed_sepa', 'instalment_invoice', 'instalment_sepa', 'googlepay', 'applepay'],function(index, value) { + if(jQuery(paymentSettings).find('#novalnet_'+value+'_payment_action').val() == 0) { + jQuery(paymentSettings).find('#novalnet_'+value+'_manual_check_limit').parent().parent().hide(); + } + jQuery(paymentSettings).find('#novalnet_'+value+'_payment_action').on('change',function(event){ + if(jQuery(paymentSettings).find('#novalnet_'+value+'_payment_action').val() == 0) { + jQuery(paymentSettings).find('#novalnet_'+value+'_manual_check_limit').parent().parent().hide(); + } else { + jQuery(paymentSettings).find('#novalnet_'+value+'_manual_check_limit').parent().parent().show(); + } + }); + }); + + // Set the error class if the condition not met + jQuery('#novalnet_sepa_due_date, #novalnet_invoice_due_date, #novalnet_prepayment_due_date, #novalnet_guaranteed_invoice_min_amount, #novalnet_guaranteed_sepa_min_amount, #novalnet_instalment_invoice_min_amount, #novalnet_instalment_sepa_min_amount').parent().on('change', function() { + if (jQuery(this).hasClass('set_error')) jQuery(this).removeClass('set_error'); + }); + + // Payment settings toggle + jQuery('.nn_fa').each(function(){ + jQuery(this).parent().addClass('nn-toggle-heading'); + jQuery(this).parent().next().next().addClass('nn-toggle-content'); + }); + jQuery('.nn-toggle-content').hide(); + + jQuery('.nn-toggle-heading').on('click',function(){ + jQuery(this).next().next().toggle(700); + if( jQuery(this).children('i').hasClass('fa-chevron-circle-down') ) { + jQuery(this).children('i').addClass('fa-chevron-circle-up').removeClass('fa-chevron-circle-down'); + } else { + jQuery(this).children('i').addClass('fa-chevron-circle-down').removeClass('fa-chevron-circle-up'); + } + }); + + // Hide the client key field + jQuery('input[id=novalnet_client_key]').parent().parent('.form-group').addClass('hide_client_key'); + jQuery('.hide_client_key').hide(); + + if (jQuery('#novalnet_tariffid').val() == undefined) { + jQuery('input[name=novalnet_tariffid]').attr('id', 'novalnet_tariffid'); + } + + // Display the alert box if the public and private key was not configured + if (jQuery('input[name=novalnet_public_key]').val() == '' && jQuery('input[name=novalnet_private_key]').val() == '') { + jQuery('.content-header').prepend('
' + ' ' + jQuery('input[name=nn_lang_notification]').val() + '
'); + + + } + + // Autofill the merchant details + if (jQuery('input[name=novalnet_public_key]').val() != undefined && jQuery('input[name=novalnet_public_key]').val() != '') { + fillMerchantConfiguration(); + } else if (jQuery('input[name=novalnet_public_key]').val() == '') { + jQuery('#novalnet_tariffid').val(''); + } + + jQuery('input[name=novalnet_public_key], input[name=novalnet_private_key]' ).on('change', function () { + if (jQuery('input[name=novalnet_public_key]').val() != '' && jQuery('input[name=novalnet_private_key]').val() != '') { + fillMerchantConfiguration(); + } else { + jQuery('#novalnet_tariffid').val(''); + } + }); + + // Set the webhook URL + jQuery('input[name=novalnet_webhook_url]').val(jQuery('#nn_webhook_url').val()); + let text = jQuery('input[name=nn_webhook_change]').val(); + jQuery('#novalnet_webhook_url').parent().parent().after('
'); + + jQuery('#nn_webhook_configure_button').on('click', function() { + if(jQuery('#novalnet_webhook_url').val() != undefined && jQuery('#novalnet_webhook_url').val() != '') { + if (confirm(text) == true) { + configureWebhookUrlAdminPortal(); + } else { + location.reload(); + } + } else { + alert(jQuery('input[name=nn_webhook_invalid]').val()); + } + }); + + // Backend payment configuration validation + jQuery('button[name=speichern]').on('click', function(event){ + // SEPA payment due date validation + jQuery.each(['#novalnet_sepa_due_date'], function (index, element) { + if (jQuery.trim(jQuery(element).val()) != '' && (isNaN(jQuery(element).val()) || jQuery(element).val() < 2 || jQuery(element).val() > 14)) { + handleErrorElement(jQuery(element), jQuery('#nn_invalid_due_date').val()); + } + }); + + // INVOICE and Prepayment due date validation + if (jQuery.trim(jQuery('#novalnet_invoice_due_date').val()) != '' && (isNaN(jQuery('#novalnet_invoice_due_date').val()) || jQuery('#novalnet_invoice_due_date').val() < 7 )) { + handleErrorElement(jQuery('#novalnet_invoice_due_date'), jQuery('#nn_invalid_due_date').val()); + } + + if (jQuery.trim(jQuery('#novalnet_prepayment_due_date').val()) != '' && (isNaN(jQuery('#novalnet_prepayment_due_date').val()) || jQuery('#novalnet_prepayment_due_date').val() < 7 || jQuery('#novalnet_prepayment_due_date').val() > 28)) { + handleErrorElement(jQuery('#novalnet_prepayment_due_date'), jQuery('#nn_invalid_due_date').val()); + } + + // Minimum Instalment amount validation + jQuery.each(['#novalnet_instalment_invoice_min_amount', '#novalnet_instalment_sepa_min_amount'], function (index, element) { + if (jQuery.trim(jQuery(element).val()) != '' && (isNaN(jQuery(element).val()) || jQuery(element).val() < 1998)) { + handleErrorElement(jQuery(element), jQuery('#nn_instalment_min_amount_error_text').val()); + } + }); + + // Minimum guarantee payment amount validation + jQuery.each(['#novalnet_guaranteed_invoice_min_amount', '#novalnet_guaranteed_sepa_min_amount'], function (index, element) { + if (jQuery.trim(jQuery(element).val()) != '' && (isNaN(jQuery(element).val()) || jQuery(element).val() < 999)) { + + handleErrorElement(jQuery(element), jQuery('#nn_guarantee_min_amount_error_text').val()); + } + }); + + jQuery.each(['#novalnet_cc_accepted_card_types', '#novalnet_instalment_invoice_cycles', '#novalnet_instalment_sepa_cycles'], function (index, element) { + if (jQuery(element).val() == '') { + handleErrorElement(jQuery(element), jQuery('#nn_multiselect_text').val()); + } + }); + }); + + // Display the payment messages below the payment type + jQuery.each(['#novalnet_instalment_invoice_enablemode', '#novalnet_instalment_sepa_enablemode'], function (index, element) { + jQuery(element).closest('.nn-toggle-content').prepend(('
' + jQuery('#nn_instalment_payment_conditions').val() + '
')); + }); + + jQuery.each(['#novalnet_guaranteed_invoice_enablemode', '#novalnet_guaranteed_sepa_enablemode'], function (index, element) { + jQuery(element).closest('.nn-toggle-content').prepend(('
' + jQuery('#nn_guarantee_payment_conditions').val() + '
')); + }); + + jQuery('#novalnet_paypal_enablemode').closest('.nn-toggle-content').prepend(('
' + jQuery('#nn_paypal_api_configure').val() + '
')); + + jQuery('#novalnet_webhook_testmode').parent().parent().parent().parent().after(('
' + jQuery('#nn_webhook_notification').val() + '

')); +}); + +function fillMerchantConfiguration() { + var autoconfigurationRequestParams = { 'nn_public_key' : jQuery('input[name=novalnet_public_key]').val(), 'nn_private_key' : jQuery('input[name=novalnet_private_key]').val(), 'nn_request_type' : 'autofill' }; + transactionRequestHandler(autoconfigurationRequestParams); +} + +function transactionRequestHandler(requestParams) +{ + requestParams = typeof(requestParams !== 'undefined') ? requestParams : ''; + + var requestUrl = jQuery('input[id=nn_post_url]').val() ; + if ('XDomainRequest' in window && window.XDomainRequest !== null) { + var xdr = new XDomainRequest(); + var query = jQuery.param(requestParams); + xdr.open('GET', requestUrl + query) ; + xdr.onload = function () { + autofillMerchantDetails(this.responseText); + }; + xdr.onerror = function () { + _result = false; + }; + xdr.send(); + } else { + jQuery.ajax({ + url : requestUrl, + type : 'post', + dataType : 'html', + data : requestParams, + global : false, + async : false, + success : function (result) { + autofillMerchantDetails(result); + } + }); + } +} + +function autofillMerchantDetails(result) +{ + var fillParams = jQuery.parseJSON(result); + + if (fillParams.result.status != 'SUCCESS') { + jQuery('input[name="novalnet_public_key"],input[name="novalnet_private_key"]').val(''); + jQuery('.content-header').prepend('
' + fillParams.result.status_text + '
'); + jQuery('#novalnet_tariffid').val(''); + return false; + } + + var tariffKeys = Object.keys(fillParams.merchant.tariff); + var saved_tariff_id = jQuery('#novalnet_tariffid').val(); + var tariff_id; + + try { + var select_text = decodeURIComponent(escape('Auswählen')); + } catch(e) { + var select_text = 'Auswählen'; + } + + jQuery('#novalnet_tariffid').replaceWith(''); + + jQuery('#novalnet_tariffid').find('option').remove(); + + for (var i = 0; i < tariffKeys.length; i++) + { + if (tariffKeys[i] !== undefined) { + jQuery('#novalnet_tariffid').append( + jQuery( + '