diff --git a/.babelrc b/.babelrc new file mode 100644 index 0000000..6d18804 --- /dev/null +++ b/.babelrc @@ -0,0 +1,4 @@ +{ + "presets": ["@babel/preset-env"], + "plugins": ["@babel/plugin-transform-async-to-generator", "@babel/plugin-transform-runtime"] +} diff --git a/Bootstrap.php b/Bootstrap.php index 2371768..9106039 100644 --- a/Bootstrap.php +++ b/Bootstrap.php @@ -1,8 +1,10 @@ listen('shop.hook.' . \HOOK_BESTELLABSCHLUSS_INC_BESTELLUNGINDB, function (array $args) { - /** - * Handle Pending Orders. - * - * Prevent the WaWi from collection an order that is currently PENDING. - * Therefore, we mark the order as already collected (not great but JTL does not have a pending state). - */ try { + /** @var Bestellung $order */ + $order = $args['oBestellung']; + + /** @var SessionHelper $sessionHelper */ + $sessionHelper = Shop::Container()->get(SessionHelper::class); + + // update cBestellNummer because we might already have generated it but bestellungInDB() has generated + // a new one, resulting in a wrong order number in the confirmation mail for example! + $orderNumber = $sessionHelper->get(SessionHelper::KEY_ORDER_ID); + if (!empty($orderNumber) && $orderNumber != $order->cBestellNr) { + $order->cBestellNr = $orderNumber; + } elseif ($sessionHelper->get(SessionHelper::KEY_CHECKOUT_SESSION)) { + $sessionHelper->set(SessionHelper::KEY_ORDER_ID, $order->cBestellNr); + } + + /** + * Handle Pending Orders. + * + * Prevent the WaWi from collection an order that is currently PENDING. + * Therefore, we mark the order as already collected (not great but JTL does not have a pending state). + */ if (Shop::has('360HpOrderPending')) { - $args['oBestellung']->cAbgeholt = 'Y'; + $order->cAbgeholt = 'Y'; } } catch (Throwable $th) { Logger::error( @@ -114,6 +139,23 @@ public function boot(Dispatcher $dispatcher): void } }); + $dispatcher->listen('shop.hook.' . \HOOK_IO_HANDLE_REQUEST, function (array $args) { + // Hook into ajax request handling for apple pay merchant validation + try { + $controller = new ApplePayController( + $this->getPlugin(), + Shop::Container()->get(CertificationService::class), + $args['io'] + ); + $controller->handle(); + } catch (Throwable $th) { + Logger::error( + 'Error ' . $th->getCode() . ':' . $th->getMessage() . ', Exception in Hook ' + . \HOOK_IO_HANDLE_REQUEST + ); + } + }); + // Backend Hooks if (!Shop::isFrontend()) { $dispatcher->listen('backend.notification', function () { @@ -152,8 +194,9 @@ public function installed() // Deactivate Invoice Factoring Payment Method by setting nNutzbar to 0 foreach ($this->getPlugin()->getPaymentMethods()->getMethods() as $method) { - if ($method->getActive() && $method->getUsable() && - $method->getClassName() === HeidelpayInvoiceFactoring::class + if ( + ($method->getActive() || $method->getUsable()) && + in_array($method->getClassName(), $this->getDeprecatedPaymentMethods()) ) { $this->getDB()->update( 'tzahlungsart', @@ -180,8 +223,9 @@ public function updated($oldVersion, $newVersion) { // Deactivate Invoice Factoring Payment Method by setting nNutzbar to 0 foreach ($this->getPlugin()->getPaymentMethods()->getMethods() as $method) { - if (($method->getActive() || $method->getUsable()) && - $method->getClassName() === HeidelpayInvoiceFactoring::class + if ( + ($method->getActive() || $method->getUsable()) && + in_array($method->getClassName(), $this->getDeprecatedPaymentMethods()) ) { $this->getDB()->update( 'tzahlungsart', @@ -219,18 +263,48 @@ public function renderAdminMenuTab(string $tabName, int $menuID, JTLSmarty $smar $controller->setModel($model); $controller->handleAjax(); } catch (Throwable $th) { - return json_encode([ + echo json_encode([ 'status' => 'error', 'messages' => [$th->getMessage()] ]); + die; } } $controller = new AdminOrdersController($this->getPlugin(), $smarty); $controller->setModel($model); + return $controller->handle(); + case JtlLinkHelper::ADMIN_TAB_APPLE_PAY: + /** @var Config $config */ + $config = Shop::Container()->get(Config::class); + if (!$config->get(Config::PRIVATE_KEY)) { + return 'Missing API Key'; + } + $controller = new AdminApplePayController($this->getPlugin(), $smarty); + $controller->setCertService(Shop::Container()->get(CertificationService::class)); + return $controller->handle(); case JtlLinkHelper::ADMIN_TAB_SETTINGS: $controller = new AdminSettingsController($this->getPlugin(), $smarty); + return $controller->handle(); + case JtlLinkHelper::ADMIN_TAB_KEYPAIRS: + $model = new KeyPairModel($this->getDB()); + $controller = new AdminKeyPairsController($this->getPlugin(), $smarty); + $controller->setModel($model); + + // Handle Ajax Requests + if (Request::isAjaxRequest() && Request::getVar('controller') == 'KeyPairs') { + try { + $controller->handleAjax(); + } catch (Throwable $th) { + echo json_encode([ + 'status' => 'error', + 'messages' => [$th->getMessage()] + ]); + die; + } + } + return $controller->handle(); default: return parent::renderAdminMenuTab($tabName, $menuID, $smarty); @@ -240,4 +314,13 @@ public function renderAdminMenuTab(string $tabName, int $menuID, JTLSmarty $smar return $th->getMessage(); } } + + private function getDeprecatedPaymentMethods(): array + { + return [ + HeidelpayInvoiceFactoring::class, + HeidelpayHirePurchaseDirectDebit::class, + HeidelpayFlexiPayDirect::class + ]; + } } diff --git a/CHANGELOG.md b/CHANGELOG.md index 315c744..2055bd5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,116 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +## [1.4.1] (April 2024) +### Changed +- reduce Unzer UI Component fields if they are already filled by the shop +- Unzer Direct Debit only available for EUR + +### Fixed +- Validation of the Unzer UI Components +- use correct currency factor for instalments + +## [1.4.0] (April 2024) +### Added +- New Payment Method **Unzer Direct Debit** +- Missing Translations + +### Fixed +- prefill birthday field if alreay set by shop +- fixed issue with unzer ui component validation +- fixed issue with session new being cleared correctly when changing shipping/billing address in the checkout + +### Changed +- updated payment and system requirements in the documenation + +## [1.3.2] (January 2024) +### Fixed: +- Fixed issue with API Call in Settings after fresh install + +## [1.3.1] (January 2024) +### Added +- Added Key Pair Management +- Added new payment method **Unzer Instalment** +- Added support for PHP 8.2 und PHP 8.3 +- Added improved error handling for api errors + +## Changed +- updated Unzer SDK +- highlight deprecated payment methods + + +## [1.3.0] (August 2023) +### Added +- Added LICENSE and NOTICE + +### Changed +- Changed Payment Method name from Unzer Invoice to Unzer Invoice (Paylater) + +### Fixed +- Clear Plugin Session on the order status page in case that a user aborted its payment process + +### Removed +- Removed deprecated Payment Method **Unzer Instalment**/**Unzer Ratenkauf** +- Removed deprecated Payment Method **Unzer Bank Transfer**/**Unzer Direktüberweisung** + +## [1.2.1] (February 2023) +### Added +- Added compatability for **JTL 5.2 and PHP 8.1** +- Added debug logs for the shipping API call +- Added Reference Text for cancellations + +## Changed +- Show Invoice ID in Order Detail only if either local invoice id or invoice id from the API response is available +- Hide Unzer Insight Portal Button as the correct link to the order cannot be determined reliably + +### Fixed +- Locale Mapping for Unzer UI Component +- Fixed unzer applepay debugging when in sandbox mode +- Fixed issue with submit button staying disabled on invalid input on the additional checkout step +- Fixed rounding issue in total gross amount API field + +## [1.2.0] (November 2022) +### Added +- Added Bancontact as payment method +- Added Unzer Rechnung (Buy Now, Pay Later) as payment method +- Added option to disable automatic setting of incoming payments + +### Changed +- Unzer SDK version updated to 1.2.0.0 + +## [1.1.0] (July 2022) +### Added +- Added company info to customer object +- Added verification and notification if frontend URLs have changed due to JTL/plugin updates and how to correct them +- Added VAT amount to shopping cart object +- Added ApplePay payment method + +### Changed +- Unzer SDK version updated to 1.1.4.2 +- Remove default value for payment method selection, as the NOVA theme already has a back button in the additional payment step. + +### Fixed +- Fixed an issue with instalments sending incorrect/temporary order numbers to Unzer +- Fixed an unhandled error when retrieving refunds in the backend +- Fixed problem with umlauts in intermediate payment step encoded with HTML entities instead of UTF-8 +- Fixed problem with cancelling Invoice (Secured) orders before they are completed +- Fixed problem with wrong order number in order confirmation emails + +## [1.0.2] (March 2022) +### Added +- add minimum customer info (name and email) to all payments + +### Changed +- use short id as transaction id in payment history (WaWi) + +### Fixed +- set default db engine and charset when creating database tables to avoid issues due to weird defaults +- add error handling to avoid issues in the frontend when API is not callable *(ie missing keys)* +- fix issue with -0.0 beeing interpreted as negative in the unzer api +- potential fix for mismatch of order ids between the unzer insight portal and the shop +- error in the placeholder of the public key setting in the backend + + ## [1.0.1] (November 2021) ### Added - JTL Shop 5.1 Compatability @@ -17,6 +127,3 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a ## [1.0.0] (July 2021) ### Added - Initial Release - -[1.0.1]: https://github.com/unzerdev/jtl5/compare/1.0.0...1.0.1 -[1.0.0]: https://github.com/unzerdev/jtl5 \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..086a99c --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2020 - today Unzer GmbH + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/Migrations/Migration20201027083900.php b/Migrations/Migration20201027083900.php index ef5c81d..9b8aeed 100644 --- a/Migrations/Migration20201027083900.php +++ b/Migrations/Migration20201027083900.php @@ -22,7 +22,7 @@ public function up() $this->execute('CREATE TABLE IF NOT EXISTS ' . Config::TABLE . ' ( `key` VARCHAR(255) NOT NULL PRIMARY KEY, `value` VARCHAR(255) NOT NULL - );'); + ) ENGINE=InnoDB CHARSET=utf8 COLLATE utf8_unicode_ci;'); // Create Order Mapping Table $this->execute( @@ -36,7 +36,7 @@ public function up() `payment_type_name` VARCHAR(255), /* payment type name from heidelpay */ `payment_type_id` VARCHAR(255), /* payment type id from heidelpay */ PRIMARY KEY (`jtl_order_id`, `payment_id`) - );' + ) ENGINE=InnoDB CHARSET=utf8 COLLATE utf8_unicode_ci;' ); // Create Charge Mapping Table @@ -46,7 +46,7 @@ public function up() `order_id` INT(10) NOT NULL, /* jtl order table id (kBestellung) */ `charge_id` VARCHAR(255), /* charge id from heidelpay */ `payment_id` VARCHAR(255) /* payment id from heidelpay */ - );' + ) ENGINE=InnoDB CHARSET=utf8 COLLATE utf8_unicode_ci;' ); } diff --git a/Migrations/Migration20220511114913.php b/Migrations/Migration20220511114913.php new file mode 100644 index 0000000..7428384 --- /dev/null +++ b/Migrations/Migration20220511114913.php @@ -0,0 +1,28 @@ +execute( + 'ALTER TABLE ' . Config::TABLE . ' + CHANGE `value` `value` TEXT CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL;' + ); + } + + public function down() + { + } +} diff --git a/Migrations/Migration20221006103000.php b/Migrations/Migration20221006103000.php new file mode 100644 index 0000000..45e5a75 --- /dev/null +++ b/Migrations/Migration20221006103000.php @@ -0,0 +1,28 @@ +execute( + 'ALTER TABLE ' . ChargeMappingModel::CHARGE_TABLE . ' + ADD `delivery_id` INT(10) DEFAULT NULL AFTER `payment_id`;' + ); + } + + public function down() + { + } +} diff --git a/Migrations/Migration20230919100000.php b/Migrations/Migration20230919100000.php new file mode 100644 index 0000000..25a2765 --- /dev/null +++ b/Migrations/Migration20230919100000.php @@ -0,0 +1,35 @@ +execute( + 'CREATE TABLE IF NOT EXISTS ' . KeyPairModel::TABLE . ' ( + `id` INT(10) NOT NULL AUTO_INCREMENT PRIMARY KEY, + `private_key` VARCHAR(255) NOT NULL, + `public_key` VARCHAR(255) NOT NULL, + `is_b2b` TINYINT(1) DEFAULT 0, + `currency_id` INT(10) NOT NULL, + `payment_method_id` INT(10) NOT NULL + ) ENGINE=InnoDB CHARSET=utf8 COLLATE utf8_unicode_ci;' + ); + } + + public function down() + { + if ($this->doDeleteData()) { + $this->execute('DROP TABLE IF EXISTS `' . KeyPairModel::TABLE . '`', ReturnType::DEFAULT); + } + } +} diff --git a/Migrations/Migration20230925100000.php b/Migrations/Migration20230925100000.php new file mode 100644 index 0000000..64f8a8a --- /dev/null +++ b/Migrations/Migration20230925100000.php @@ -0,0 +1,43 @@ +columnExists()) { + $this->execute( + 'ALTER TABLE ' . OrderMappingModel::ORDER_TABLE . ' + ADD COLUMN `payment_method_id` INT(10) NULL' + ); + } + } + + public function down() + { + if ($this->doDeleteData() && $this->columnExists()) { + $this->execute( + 'ALTER TABLE `' . OrderMappingModel::ORDER_TABLE . '` DROP COLUMN payment_method_id', + ReturnType::DEFAULT + ); + } + } + + private function columnExists(): bool + { + return !empty( + $this->getDB()->executeQuery( + 'SHOW COLUMNS FROM ' . OrderMappingModel::ORDER_TABLE . ' LIKE \'payment_method_id\'', + ReturnType::AFFECTED_ROWS + ) + ); + } +} diff --git a/NOTICE b/NOTICE new file mode 100644 index 0000000..e789e5d --- /dev/null +++ b/NOTICE @@ -0,0 +1,13 @@ +Copyright (C) 2020 - today Unzer GmbH + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. \ No newline at end of file diff --git a/README.md b/README.md index e06314f..62fa308 100644 --- a/README.md +++ b/README.md @@ -1,51 +1,56 @@ -# Unzer payment methods (JTL shop 5) +# Unzer Zahlungsarten (JTL-Shop 5) -This plugin integrates the following Unzer payment methods in the JTL Shop: +Dieses Plugin integriert die folgenden Unzer-Zahlungsarten im JTL Shop: - Alipay +- ApplePay +- Bancontact +- Direktüberweisung - EPS - Giropay - iDEAL -- Credit Card / Debit Card +- Kreditkarte +- Lastschrift +- SEPA Lastschrift - PayPal - Przelewy24 +- Ratenkauf +- Rechnungskauf - SOFORT +- Vorkasse - WeChat Pay -- Invoice -- Sepa Direct Debit -- Unzer Bank Transfer -- Unzer Instalment -- Unzer Invoice secured -- Unzer Direct Debit secured -- Unzer Prepayment +- (Veraltet) Unzer Ratenkauf +- (Veraltet) Unzer Rechnungskauf +- (Veraltet) Unzer Rechnungskauf (secured) +- (Veraltet) Unzer Lastschrift Gesichert ## Installation / Update -### System requirements -- JTL-Shop 5.0.0+ and its requirements -- PHP 7.1 - 7.4 -- The following PHP extensions +### Systemvoraussetzungen +- JTL-Shop 5.0.0+ und dessen Vorraussetzungen +- PHP Version: 7.4 - 8.3 +- Die folgenden PHP Erweiterungen - ext-json - ext-curl -- In order to avoid rounding errors when transmitting floating point values to the API we recommend you to set the following value in your `php.ini`, which will select an enhanced algorithm for rounding such numbers. -~~~ini -// php.ini -; When floats & doubles are serialized store serialize_precision significant -; digits after the floating point. The default value ensures that when floats -; are decoded with unserialize, the data will remain the same. -serialize_precision = -1 -~~~ +### Weitere Voraussetzungen +Sie müssen bei Unzer registriert sein. -### Further requirements -You must be registered with Unzer. +#### Apple Pay +Wenn Sie Apple Pay auf Ihrer Seite anbieten möchten, müssen Sie außerdem die folgenden Voraussetzungen erfüllen: -### Plugin installation -The installation of the plugin is done in the standard procedure for JTL-Shop 5 as described [here](https://jtl-devguide.readthedocs.io/projects/jtl-shop/de/latest/shop_plugins/allgemein.html#pluginverwaltung-im-backend-von-jtl-shop). +- Apple Developer Account mit Teilnahme am Apple Developer Program, siehe Mitgliedschaft auswählen - Support - Apple Developer -### Plugin update -For an update, upload the plugin to the `./plugins/` folder or via the plugin manager in the shop backend in the latest version as for an installation (and overwrite all existing plugin files if necessary) or follow the instructions of the Extension Store. -Then go to the plugin manager in the shop backend and press the update button. +> **Ohne Teilnahme am am Apple Developer Program kann Apple Pay im Plugin nicht genutzt werden! Der einfache und kostenlose Apple Developer Account reicht nicht aus!** -## Configuration -After the actual plugin installation, it is necessary to activate the new payment methods and add them to the desired shipping methods. -Further information and configuration can be found in the [Instructions](https://redirect.solution360.de/?r=docsunzerjtl5). \ No newline at end of file +### Plugin-Installation +Die Installation des Plugins erfolgt im Standardverfahren für JTL-Shop 5, wie es [hier](https://jtl-devguide.readthedocs.io/projects/jtl-shop/de/latest/shop_plugins/allgemein.html#pluginverwaltung-im-backend-von-jtl-shop) beschrieben ist. + +### Plugin-Update +Für ein Update laden Sie das Plugin wie bei einer Installation in der neuesten Version hoch (und überschreiben ggf. alle vorhandenen Plugindateien) oder folgen Sie den Hinweisen des Extension Stores. + +Gehen Sie dann in die Pluginverwaltung und betätigen Sie den Update-Button. + +## Konfiguration +Nach der eigentlichen Plugin-Installation ist es notwendig, die neuen Zahlungsmethoden zu aktivieren und zu den gewünschten Versandarten hinzuzufügen. + +Weitere Informationen und Konfiguration finden Sie in der [Anleitung](https://redirect.solution360.de/?r=docsunzerjtl5) \ No newline at end of file diff --git a/adminmenu/js/admin.js b/adminmenu/js/admin.js index 9c1f36c..7e82476 100644 --- a/adminmenu/js/admin.js +++ b/adminmenu/js/admin.js @@ -109,9 +109,13 @@ ); }; - $(document).ready(function () { + $(function () { // Colored Input $('.form-colored').each(previewColor).on('change keyup blur input focus', previewColor); window.hpAdmin = new HeidelpayAdmin(window.hpAdminAjaxUrl); + + $('.hp-admin-content .custom-file-input').on('change',function(e) { + $(this).next('.custom-file-label').html(e.target.files[0].name); + }); }); })(jQuery, window); \ No newline at end of file diff --git a/adminmenu/js/keypairs.js b/adminmenu/js/keypairs.js new file mode 100644 index 0000000..2b8543a --- /dev/null +++ b/adminmenu/js/keypairs.js @@ -0,0 +1,102 @@ +(function ($, window, undefined) { + $(function () { + // Setup + const admin = window.hpAdmin; + const $keyPairs = $('.hp-keypairs'); + const $modal = $('#hp-keypair-modal'); + const $addTrigger = $('#hp-keypairs-add'); + + /** + * + * @param {{template: ?String}} response + */ + const setModalContent = (response) => { + if (response && response.template) { + const $body = $modal.find('.modal-body'); + + var show = () => { + $body.html(response.template); + $modal.modal('show'); + }; + + if ($modal.hasClass('modal-loaded')) { + $modal.modal('hide'); + show(); + } else { + show(); + $modal.addClass('modal-loaded'); + } + } + }; + + /** + * @param {JQuery.Event} e + */ + const onDelete = (e) => { + const form = $(e.target); + const data = { + id: form.closest('tr').data('id'), + jtl_token: form.find('.jtl_token').val() + }; + + e.preventDefault(); + admin.doAjaxCall('KeyPairs:delete', data, (response) => { + if (response && response.listing) { + $('#modal-footer-delete-confirm').modal('hide'); + $keyPairs.html(response.listing); + deleteConfirmation(); + } + }); + }; + + /** + * @param {JQuery.Event} e + */ + const onAdd = (e) => { + e.preventDefault(); + admin.doAjaxCall('KeyPairs:edit', { id: null }, setModalContent); + }; + + /** + * @param {JQuery.Event} e + */ + const onSave = (e) => { + e.preventDefault(); + + const fields = $(e.target).find('input,select'); + const data = {}; + fields.each((i, el) => { + data[el.name] = $(el).is(':checkbox') ? $(el).is(':checked') : $(el).val(); + }); + + admin.doAjaxCall('KeyPairs:save', data, (response) => { + if (response.status !== 'success') { + return; + } + + if (response.template) { + $modal.find('.modal-body').html(response.template); + } + + if (response.listing) { + $keyPairs.html(response.listing); + deleteConfirmation(); + } + }); + }; + + /** + * @param {JQuery.Event} e + */ + const onEdit = (e) => { + e.preventDefault(); + admin.doAjaxCall('KeyPairs:edit', { id: $(e.target).closest('tr').data('id') }, setModalContent); + }; + + // Register Events + $keyPairs.on('submit', '.keypair-action-form', onDelete); + $addTrigger.on('click', onAdd); + $modal.find('form').on('submit', onSave); + $keyPairs.on('click', '[data-edit]', onEdit); + }); +})(jQuery, window); \ No newline at end of file diff --git a/adminmenu/template/applepay.tpl b/adminmenu/template/applepay.tpl new file mode 100644 index 0000000..b711ba2 --- /dev/null +++ b/adminmenu/template/applepay.tpl @@ -0,0 +1,177 @@ +{include file="{$hpAdmin.adminTemplatePath}partials/_header.tpl"} + +
{__('hpSettingsPrivateKeyLabel')} | +{__('hpSettingsPublicKeyLabel')} | +{__('hpKeypairIsB2B')} | +{__('currency')} | +{__('hpPaymentMethod')} | ++ |
---|
{$charge->getId()} | -{$charge->getShortId()} | + {if !empty($hpPayment->getAuthorization())} +|||
{$hpPayment->getAuthorization()->getId()} | +{$hpPayment->getAuthorization()->getShortId()} | - {if $charge->isPending()} + {if $hpPayment->getAuthorization()->isPending()} {__('hpStatePending')} - {elseif $charge->isError()} + {elseif $hpPayment->getAuthorization()->isError()} {__('hpStateFailure')} - {elseif $charge->isSuccess()} + {elseif $hpPayment->getAuthorization()->isSuccess()} {__('hpStateSuccessful')} {else} - {/if} - {if $charge->getMessage()} - + {if $hpPayment->getAuthorization()->getMessage()} + {/if} - | {if isset($charge->getAmount())}{($charge->getAmount())|number_format:2}{else} - {/if}{if isset($charge->getCurrency())} {$charge->getCurrency()}{/if} | +{if isset($hpPayment->getAuthorization()->getAmount())}{number_format($hpPayment->getAuthorization()->getAmount(), 2)}{else} - {/if}{if isset($hpPayment->getAuthorization()->getCurrency())} {$hpPayment->getAuthorization()->getCurrency()}{/if} |
{$charge->getId()} | +{$charge->getShortId()} | ++ {if $charge->isPending()} + {__('hpStatePending')} + {elseif $charge->isError()} + {__('hpStateFailure')} + {elseif $charge->isSuccess()} + {__('hpStateSuccessful')} + {else} + - + {/if} + + {if $charge->getMessage()} + + {/if} + + | {if isset($charge->getAmount())}{number_format($charge->getAmount(), 2)}{else} - {/if}{if isset($charge->getCurrency())} {$charge->getCurrency()}{/if} | +
' + JSON.stringify(data, null, ' ') + '
' + JSON.stringify(data, null, ' ') + '
"+JSON.stringify(t,null," ")+"
' + JSON.stringify(data, null, ' ') + '
' + JSON.stringify(data, null, ' ') + '
diff --git a/frontend/template/instalment_info.tpl b/frontend/template/instalment_info.tpl
new file mode 100644
index 0000000..1b144ad
--- /dev/null
+++ b/frontend/template/instalment_info.tpl
@@ -0,0 +1 @@
+{$info}
\ No newline at end of file
diff --git a/frontend/template/partials/_threatMetrix.tpl b/frontend/template/partials/_threatMetrix.tpl
new file mode 100644
index 0000000..360849e
--- /dev/null
+++ b/frontend/template/partials/_threatMetrix.tpl
@@ -0,0 +1,12 @@
+{if $hpPayment.threatMetrixId}
+
+
+
+{/if}
\ No newline at end of file
diff --git a/info.xml b/info.xml
index 670da30..e1da24a 100644
--- a/info.xml
+++ b/info.xml
@@ -6,7 +6,7 @@
Deaktivieren Sie diese Option nur, wenn Sie die Zahlungseingänge auf andere Art in der JTL-Wawi setzen. (Zum Beispiel per Zahlungsabgleich oder manuell.)"
+
+msgid "hpDeprecationPaymentMethodTitle"
+msgstr "ABSCHAFFUNG: %s"
+
+msgid "hpDeprecationInvoiceNotice"
+msgstr ""
+"Sie verwenden die Zahlungsmethode `%s`. Beachten Sie, dass diese Methode von Unzer abgeschafft wird. Sie wird derzeit noch unterstützt, aber es sind keine weiteren Entwicklungen dafür geplant.\n"
+"\n"
+"Der Ersatz für diese Zahlart ist die neue Zahlart `Unzer Rechnung (Jetzt kaufen, später bezahlen)`.\n"
+"\n"
+"Wenn Sie migrieren möchten, wenden Sie sich bitte an Ihren Ansprechpartner bei Unzer!"
+
+msgid "Key Pairs"
+msgstr "Schlüsselpaare"
+
+msgid "hpKeyPairEdit"
+msgstr "Schlüsselpaar bearbeiten"
+
+msgid "hpKeypairIsB2B"
+msgstr "B2B"
+
+msgid "hpKeypairIsB2BHelp"
+msgstr "Gibt an, ob das Schlüsselpaar nur für B2B Kunden benutzt werden soll."
+
+msgid "hpKeypairCurrencyHelp"
+msgstr "Gibt an für welche Währung das Schlüsselpaar verwendet werden soll."
+
+msgid "hpKeypairPaymentMethodsHelp"
+msgstr "Gibt an für welche Zahlungsart das Schlüsselpaar verwendet werden soll."
+
+msgid "hpSettingsPqSelectorInstalmentInfo"
+msgstr "PQ-Selector für den Ratenzahlungshinweis auf Bestellbestätigungsseite"
+
+msgid "hpSettingsPqSelectorInstalmentInfoHelp"
+msgstr "Der PHP-Query-Selektor für das Einhängen des Ratenzahlungshinweis auf der Bestellbestätigungsseite"
+
+msgid "hpSettingsPqMethodInstalmentInfo"
+msgstr "PQ-Einfügemethode für den Ratenzahlungshinweis auf Bestellbestätigungsseite"
+
+msgid "hpSettingsPqMethodInstalmentInfoHelp"
+msgstr "Die PHP-Query-Einfügemethode für das Einhängen des Ratenzahlungshinweis auf der Bestellbestätigungsseite"
+
+msgid "hpPaymentReference"
+msgstr "Zahlungsreferenz"
+
+msgid "paylater-installment"
+msgstr "Ratenkauf"
+
+msgid "paylater-invoice"
+msgstr "Rechnungskauf"
+
+msgid "paylater-direct-debit"
+msgstr "Lastschrift"
\ No newline at end of file
diff --git a/locale/en-GB/base.mo b/locale/en-GB/base.mo
index 3838d9e..d26514f 100644
Binary files a/locale/en-GB/base.mo and b/locale/en-GB/base.mo differ
diff --git a/locale/en-GB/base.po b/locale/en-GB/base.po
index 0059bfe..93799b2 100644
--- a/locale/en-GB/base.po
+++ b/locale/en-GB/base.po
@@ -11,22 +11,25 @@ msgid "Unzer SEPA-Lastschrift"
msgstr "Unzer SEPA Direct Debit"
msgid "Unzer Lastschrift"
-msgstr "Unzer Direct Debit"
+msgstr "Unzer SEPA Direct Debit"
msgid "Unzer SEPA-Lastschrift (guaranteed)"
-msgstr "Unzer SEPA Direct Debit (secured)"
+msgstr "(Deprecated) Unzer SEPA Direct Debit (secured)"
msgid "Unzer Lastschrift (secured)"
-msgstr "Unzer Direct Debit (secured)"
+msgstr "(Deprecated) Unzer Direct Debit (secured)"
+
+msgid "Unzer Lastschrift (Paylater)"
+msgstr "Unzer Direct Debit"
msgid "Unzer Rechnung"
-msgstr "Unzer Invoice"
+msgstr "(Deprecated) Unzer Invoice"
msgid "Unzer Rechnung (guaranteed)"
-msgstr "Unzer Ivoice (secured)"
+msgstr "(Deprecated) Unzer Invoice Secured"
msgid "Unzer Rechnung (secured)"
-msgstr "Unzer Ivoice (secured)"
+msgstr "(Deprecated) Unzer Invoice Secured"
msgid "Unzer Fakturierung von Rechnungen"
msgstr "Unzer Invoice Factoring"
@@ -74,10 +77,16 @@ msgid "Unzer FlexiPay Installment (Hire Purchase)"
msgstr "Unzer FlexiPay Instalment (Hire Purchase)"
msgid "Unzer Instalment"
-msgstr "Unzer Instalment"
+msgstr "(Deprecated) Unzer Installment"
msgid "Unzer Ratenkauf"
-msgstr "Unzer Instalment"
+msgstr "(Deprecated) Unzer Instalment"
+
+msgid "Unzer Rechnung (Jetzt kaufen, Später bezahlen)"
+msgstr "Unzer Invoice"
+
+msgid "Unzer Ratenzahlung (Paylater)"
+msgstr "Unzer Installment"
msgid "hpError"
msgstr "Error"
@@ -176,19 +185,19 @@ msgid "hpPaymentmethodCard"
msgstr "Credit Card"
msgid "hpPaymentmethodSEPA"
-msgstr "Direct Debit"
+msgstr "SEPA Direct Debit"
msgid "hpPaymentmethodSEPAGuaranteed"
-msgstr "Direct Debit (secured)"
+msgstr "(Deprecated) Direct Debit (secured)"
msgid "hpPaymentmethodInvoice"
-msgstr "Invoice"
+msgstr "(Deprecated) Invoice"
msgid "hpPaymentmethodInvoiceGuaranteed"
-msgstr "Invoice (secured)"
+msgstr "(Deprecated) Invoice (secured)"
msgid "hpPaymentmethodInvoiceFactoring"
-msgstr "Invoice (factoring)"
+msgstr "(Deprecated) Invoice (factoring)"
msgid "hpPaymentmethodPayPal"
msgstr "PayPal"
@@ -218,11 +227,20 @@ msgid "hpPaymentmethodiDEAL"
msgstr "iDEAL"
msgid "hpPaymentmethodHirePurchaseDirectDebit"
-msgstr "Instalment"
+msgstr "(Deprecated) Instalment"
+
+msgid "paylater-invoice"
+msgstr "Invoice"
+
+msgid "paylater-installment"
+msgstr "Installment"
msgid "hpOpenInPortal"
msgstr "Open Order in Insight Portal"
+msgid "hpOpenInPaylaterPortal"
+msgstr "Open in Unzer Pay Later - Merchant Portal"
+
msgid "hpDelivieryAddress"
msgstr "Deliviery Address"
@@ -407,4 +425,153 @@ msgid "hpPaymentMethodDuringCheckoutNotification"
msgstr "The payment method \"%s\" is not usable before order completion."
msgid "hpPaymentMethodNotConfiguredNotification"
-msgstr "The payment method \"%s\" is not configured!"
\ No newline at end of file
+msgstr "The payment method \"%s\" is not configured!"
+
+msgid "hpWarningWebhookUrlChanged"
+msgstr "The URL of the Unzer Webhook Handling page has changed, so the plugin can no longer process incoming payments correctly. See the documentation to find out how to fix the error"
+
+msgid "hpWarningSyncWorkflowUrlChanged"
+msgstr "The URL of the Unzer WaWi Workflow Handling page has changed, so the plugin can no longer activate invoices correctly. See the documentation to find out how to fix the error"
+
+msgid "hpApplePayRefreshCert"
+msgstr "Refresh"
+
+msgid "hpApplePayDownloadCert"
+msgstr "Download CSR"
+
+msgid "hpApplePayUploadCert"
+msgstr "Upload Certificate"
+
+msgid "hpApplePayUpload"
+msgstr "Browse"
+
+msgid "hpApplePayPaymentGeneral"
+msgstr "Allgemein"
+
+msgid "hpApplePayPaymentGeneralMerchantId"
+msgstr "Merchant Identifier"
+
+msgid "hpApplePayPaymentGeneralMerchantIdHelp"
+msgstr "The merchant identifier created in the Apple Developer Account."
+
+msgid "hpApplePayPaymentGeneralMerchantDomain"
+msgstr "Merchant Domain"
+
+msgid "hpApplePayPaymentGeneralMerchantDomainHelp"
+msgstr "The merchant/shop URL that was saved in the Apple Developer Account to use with the merchant ID."
+
+msgid "hpApplePayPaymentProcessingCertificate"
+msgstr "Payment Processing Certificate"
+
+msgid "hpApplePayPaymentProcessingCertificateCSR"
+msgstr "Certificate Signing Request (CSR)"
+
+msgid "hpApplePayPaymentProcessingCertificateCSRHelp"
+msgstr "The Certificate Signing Request (CSR) file to create the Apple Pay Payment Processing certificate."
+
+msgid "hpApplePayPaymentProcessingCertificateApple"
+msgstr "Apple Pay Certificate"
+
+msgid "hpApplePayPaymentProcessingCertificateAppleHelp"
+msgstr "The Payment Processing Certificate created by Apple."
+
+msgid "hpApplePayMerchantIdentityCertificate"
+msgstr "Merchant Identity Certificate"
+
+msgid "hpApplePayMerchantIdentityCertificateCSR"
+msgstr "Certificate Signing Request (CSR)"
+
+msgid "hpApplePayMerchantIdentityCertificateCSRHelp"
+msgstr "The Certificate Signing Request (CSR) file to create the Apple Pay Merchant Identity certificate."
+
+msgid "hpApplePayMerchantIdentityCertificateApple"
+msgstr "Apple Pay Certificate"
+
+msgid "hpApplePayMerchantIdentityCertificateAppleHelp"
+msgstr "The Merchant Indentity Certificate created by Apple."
+
+msgid "hpApplePayUnzerIDs"
+msgstr "Unzer Payment Processing Certificate IDs"
+
+msgid "hpApplePayUpdateCert"
+msgstr "Activate Certificate"
+
+msgid "CERTIFICATE_TRANSFORMATION_ERROR"
+msgstr "Certificate could not be converted to text"
+
+msgid "ERROR_ID_LOAD_ERROR"
+msgstr "Certificate could not be loaded. Please check if the certificate is valid."
+
+msgid "hpSettingsActive"
+msgstr "active"
+
+msgid "hpSettingsAddIncomingPayments"
+msgstr "Add Incoming Payments"
+
+msgid "hpSettingsAddIncomingPaymentsHelp"
+msgstr "Controls whether the plugin sets incoming payments automatically for JTL-Wawi.
You should only ever deactivate this option if you set your incoming payments in JTL-Wawi in a different way (e.g. manually or via the payment synchronisation module.)"
+
+msgid "hpDeprecationPaymentMethodTitle"
+msgstr "DEPRECATION: %s"
+
+msgid "hpDeprecationInvoiceNotice"
+msgstr ""
+"You are using the payment method `%s`, note that this method is now deprecated by Unzer. It is currently supported, but there are no further developments planned for it.\n"
+"\n"
+"The replacement for this payment method is the new `Unzer Invoice (Buy Now Pay Later)` payment method..\n"
+"\n"
+"If you want to migrate, please get in touch with your contact person at Unzer!"
+
+msgid "Ungültiger Private Key."
+msgstr "Invalid private key."
+
+msgid "Ungültiger Public Key. Bitte stellen Sie sicher, dass sie hier Ihren Public Key und nicht Ihren Private Key angeben!"
+msgstr "Invalid public key. Please make sure that you enter your public key here and not your private key!"
+
+msgid "Die Webhooks wurden erfolgreich gespeichert."
+msgstr "The webhooks have been saved successfully."
+
+msgid "Key Pairs"
+msgstr "Key Pairs"
+
+msgid "hpKeyPairEdit"
+msgstr "Edit Key Pair"
+
+msgid "hpKeypairIsB2B"
+msgstr "B2B"
+
+msgid "hpKeypairIsB2BHelp"
+msgstr "Specifies whether the key pair is to be used only for B2B clients."
+
+msgid "hpKeypairCurrencyHelp"
+msgstr "Specifies for which currency the key pair is to be used."
+
+msgid "hpKeypairPaymentMethodsHelp"
+msgstr "Specifies for which payment type the key pair is to be used."
+
+msgid "hpSettingsPqSelectorInstallmentInfo"
+msgstr "PQ-Selector for instalment information on the order confirm page"
+
+msgid "hpSettingsPqSelectorInstallmentInfoHelp"
+msgstr "The PHP Query Selector for the injection of the instalment information on the order confirm page"
+
+msgid "hpSettingsPqMethodInstallmentInfo"
+msgstr "PQ-Method for instalment information on the order confirm page"
+
+msgid "hpSettingsPqMethodInstallmentInfoHelp"
+msgstr "The PHP Query Method for the injection of the instalment information on the order confirm page"
+
+msgid "hpPaymentReference"
+msgstr "Payment Reference"
+
+msgid "paylater-direct-debit"
+msgstr "Direct Debit"
+
+msgid "Hinzufügen"
+msgstr "Add"
+
+msgid "Die Einstellungen wurden erfolgreich gespeichert."
+msgstr "The settings have been saved successfully."
+
+msgid "Dokumentation"
+msgstr "Documentation"
diff --git a/paymentmethod/HeidelpayAlipay.php b/paymentmethod/HeidelpayAlipay.php
index e95d739..188de20 100644
--- a/paymentmethod/HeidelpayAlipay.php
+++ b/paymentmethod/HeidelpayAlipay.php
@@ -1,13 +1,16 @@
adapter->getApi()->charge(
+ // Create / Update existing customer resource if needed
+ $customer = $this->createOrFetchHeidelpayCustomer($this->adapter, $this->sessionHelper, false);
+
+ if ($customer->getId()) {
+ $customer = $this->adapter->getCurrentConnection()->updateCustomer($customer);
+ }
+
+ $charge = new Charge(
$this->getTotalPriceCustomerCurrency($order),
- $order->Waehrung->cISO,
+ $order->Waehrung->getCode(),
+ $this->getReturnURL($order)
+ );
+ $charge->setOrderId($order->cBestellNr ?? null);
+
+ return $this->adapter->getCurrentConnection()->performCharge(
+ $charge,
$payment->getId(),
- $this->getReturnURL($order),
- null,
- $order->cBestellNr ?? null,
+ $customer,
$this->createMetadata()
);
}
diff --git a/paymentmethod/HeidelpayCreditCard.php b/paymentmethod/HeidelpayCreditCard.php
index 7fafcb7..48d726f 100644
--- a/paymentmethod/HeidelpayCreditCard.php
+++ b/paymentmethod/HeidelpayCreditCard.php
@@ -1,4 +1,5 @@
cGueltigkeit = Text::convertUTF8($type->getExpiryDate() ?? '');
$oPaymentInfo->cCVV = Text::convertUTF8($type->getCvc() ?? '');
$oPaymentInfo->cKartenTyp = Text::convertUTF8($type->getBrand() ?? '');
+ $oPaymentInfo->cBankName = '';
+ $oPaymentInfo->cKartenNr = '';
+ $oPaymentInfo->cCVV = '';
+
isset($oPaymentInfo->kZahlungsInfo) ? $oPaymentInfo->updateInDB() : $oPaymentInfo->insertInDB();
@@ -82,7 +91,7 @@ public function getOrderAttributes(Bestellung $order, AbstractTransactionType $t
} catch (Exception $exc) {
$this->errorLog(
'An exception was thrown while trying to get the order attributes '
- . Text::convertUTF8($exc->getMessage()),
+ . Text::convertUTF8($exc->getMessage()),
static::class
);
}
@@ -115,15 +124,26 @@ public function handleStepAdditional(JTLSmarty $view): void
* @inheritDoc
* @return AbstractTransactionType|Charge
*/
- protected function performTransaction(BasePaymentType $payment, $order): AbstractTransactionType
+ protected function performTransaction(BasePaymentType $payment, Bestellung $order): AbstractTransactionType
{
- return $this->adapter->getApi()->charge(
+ // Create / Update existing customer resource if needed
+ $customer = $this->createOrFetchHeidelpayCustomer($this->adapter, $this->sessionHelper, false);
+
+ if ($customer->getId()) {
+ $customer = $this->adapter->getCurrentConnection()->updateCustomer($customer);
+ }
+
+ $charge = new Charge(
$this->getTotalPriceCustomerCurrency($order),
- $order->Waehrung->cISO,
+ $order->Waehrung->getCode(),
+ $this->getReturnURL($order)
+ );
+ $charge->setOrderId($order->cBestellNr ?? null);
+
+ return $this->adapter->getCurrentConnection()->performCharge(
+ $charge,
$payment->getId(),
- $this->getReturnURL($order),
- null,
- $order->cBestellNr ?? null,
+ $customer,
$this->createMetadata()
);
}
diff --git a/paymentmethod/HeidelpayEPS.php b/paymentmethod/HeidelpayEPS.php
index 53a6e4d..400e7df 100644
--- a/paymentmethod/HeidelpayEPS.php
+++ b/paymentmethod/HeidelpayEPS.php
@@ -1,13 +1,16 @@
adapter->getApi()->charge(
+ // Create / Update existing customer resource if needed
+ $customer = $this->createOrFetchHeidelpayCustomer($this->adapter, $this->sessionHelper, false);
+
+ if ($customer->getId()) {
+ $customer = $this->adapter->getCurrentConnection()->updateCustomer($customer);
+ }
+
+ $charge = new Charge(
$this->getTotalPriceCustomerCurrency($order),
- $order->Waehrung->cISO,
+ $order->Waehrung->getCode(),
+ $this->getReturnURL($order)
+ );
+ $charge->setOrderId($order->cBestellNr ?? null);
+
+ return $this->adapter->getCurrentConnection()->performCharge(
+ $charge,
$payment->getId(),
- $this->getReturnURL($order),
- null,
- $order->cBestellNr ?? null,
+ $customer,
$this->createMetadata()
);
}
diff --git a/paymentmethod/HeidelpayFlexiPayDirect.php b/paymentmethod/HeidelpayFlexiPayDirect.php
index 31c4521..35937c0 100644
--- a/paymentmethod/HeidelpayFlexiPayDirect.php
+++ b/paymentmethod/HeidelpayFlexiPayDirect.php
@@ -1,13 +1,16 @@
adapter->getApi()->charge(
+ // Create / Update existing customer resource if needed
+ $customer = $this->createOrFetchHeidelpayCustomer($this->adapter, $this->sessionHelper, false);
+
+ if ($customer->getId()) {
+ $customer = $this->adapter->getApi()->updateCustomer($customer);
+ }
+
+ $charge = new Charge(
$this->getTotalPriceCustomerCurrency($order),
- $order->Waehrung->cISO,
+ $order->Waehrung->getCode(),
+ $this->getReturnURL($order)
+ );
+ $charge->setOrderId($order->cBestellNr ?? null);
+
+ return $this->adapter->getApi()->performCharge(
+ $charge,
$payment->getId(),
- $this->getReturnURL($order),
- null,
- $order->cBestellNr ?? null,
+ $customer,
$this->createMetadata()
);
}
+
+ /**
+ * @inheritDoc
+ */
+ public function isValid(object $customer, Cart $cart): bool
+ {
+ //! Note: Payment Method is deprecated -> should not be used anymore
+ return false;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function isSelectable(): bool
+ {
+ //! Note: Payment Method is deprecated -> should not be used anymore
+ return false;
+ }
}
diff --git a/paymentmethod/HeidelpayGiropay.php b/paymentmethod/HeidelpayGiropay.php
index f60cdb8..bb95268 100644
--- a/paymentmethod/HeidelpayGiropay.php
+++ b/paymentmethod/HeidelpayGiropay.php
@@ -1,13 +1,16 @@
adapter->getApi()->charge(
+ // Create / Update existing customer resource if needed
+ $customer = $this->createOrFetchHeidelpayCustomer($this->adapter, $this->sessionHelper, false);
+
+ if ($customer->getId()) {
+ $customer = $this->adapter->getCurrentConnection()->updateCustomer($customer);
+ }
+
+ $charge = new Charge(
$this->getTotalPriceCustomerCurrency($order),
- $order->Waehrung->cISO,
+ $order->Waehrung->getCode(),
+ $this->getReturnURL($order)
+ );
+ $charge->setOrderId($order->cBestellNr ?? null);
+
+ return $this->adapter->getCurrentConnection()->performCharge(
+ $charge,
$payment->getId(),
- $this->getReturnURL($order),
- null,
- $order->cBestellNr ?? null,
+ $customer,
$this->createMetadata()
);
}
diff --git a/paymentmethod/HeidelpayHirePurchaseDirectDebit.php b/paymentmethod/HeidelpayHirePurchaseDirectDebit.php
index 3a97b34..acacace 100644
--- a/paymentmethod/HeidelpayHirePurchaseDirectDebit.php
+++ b/paymentmethod/HeidelpayHirePurchaseDirectDebit.php
@@ -1,4 +1,5 @@
cBIC = Text::convertUTF8($type->getBic() ?? '');
$oPaymentInfo->cKontoNr = $oPaymentInfo->cIBAN;
$oPaymentInfo->cBLZ = $oPaymentInfo->cBIC;
+ $oPaymentInfo->cBankName = '';
+ $oPaymentInfo->cKartenNr = '';
+ $oPaymentInfo->cCVV = '';
isset($oPaymentInfo->kZahlungsInfo) ? $oPaymentInfo->updateInDB() : $oPaymentInfo->insertInDB();
@@ -148,12 +156,30 @@ public function handleStepAdditional(JTLSmarty $view): void
$this->sessionHelper->getFrontendSession()->getCart()->gibGesamtsummeWaren(true),
2
);
- $data['currency'] = $this->sessionHelper->getFrontendSession()->getCurrency()->cISO;
+ $data['currency'] = $this->sessionHelper->getFrontendSession()->getCurrency()->getCode();
$data['orderDate'] = date('Y-m-d');
$view->assign('hpPayment', $data);
}
+ /**
+ * @inheritDoc
+ */
+ public function isValid(object $customer, Cart $cart): bool
+ {
+ //! Note: Payment Method is deprecated -> should not be used anymore
+ return false;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function isSelectable(): bool
+ {
+ //! Note: Payment Method is deprecated -> should not be used anymore
+ return false;
+ }
+
/**
* Check if payment settings are correct.
* @inheritDoc
@@ -205,8 +231,8 @@ public function handleStepReviewOrder(JTLSmarty $view): ?string
$this->handler->prepareView();
try {
- $paymentId = $this->sessionHelper->get(SessionHelper::KEY_PAYMENT_ID, '');
- $payment = $this->adapter->getApi()->fetchPayment($paymentId);
+ $paymentId = $this->sessionHelper->get(SessionHelper::KEY_PAYMENT_ID);
+ $payment = $this->adapter->getCurrentConnection()->fetchPayment($paymentId);
// If currency or basket change, redirect to select payment screen to reauthorize new amounts!
if ($this->handler->currencyChanged($payment) || $this->handler->basketChanged($payment)) {
@@ -312,7 +338,13 @@ private function authorizeInstalmentTransaction(): bool
{
// We need to register an order id here otherwise the auth call will fail!
// @see: BillPay for similiar behavior
- $orderId = \baueBestellnummer();
+ if (Compatibility::isShopAtLeast52()) {
+ $orderId = $this->sessionHelper->get(SessionHelper::KEY_ORDER_ID) ?? getOrderHandler()->createOrderNo();
+ } else {
+ $orderId = $this->sessionHelper->get(SessionHelper::KEY_ORDER_ID) ?? \baueBestellnummer();
+ }
+
+ $this->sessionHelper->set(SessionHelper::KEY_ORDER_ID, $orderId);
// Create or fetch customer resource
$session = $this->sessionHelper->getFrontendSession();
@@ -329,7 +361,7 @@ private function authorizeInstalmentTransaction(): bool
// Update existing customer resource if needed
if ($customer->getId()) {
- $customer = $this->adapter->getApi()->updateCustomer($customer);
+ $customer = $this->adapter->getCurrentConnection()->updateCustomer($customer);
$this->debugLog('Updated Customer Resource: ' . $customer->jsonSerialize(), static::class);
}
@@ -343,13 +375,16 @@ private function authorizeInstalmentTransaction(): bool
$paymentType = $this->adapter->fetchPaymentType();
// Authorize Transaction
- $authorization = $this->adapter->getApi()->authorize(
+ $auth = (new Authorization(
$paymentType->getTotalPurchaseAmount(),
- $session->getCurrency()->cISO,
+ $session->getCurrency()->getCode(),
+ Shop::Container()->getLinkService()->getStaticRoute('bestellvorgang.php')
+ ))->setOrderId($orderId);
+
+ $authorization = $this->adapter->getCurrentConnection()->performAuthorization(
+ $auth,
$paymentType,
- Shop::Container()->getLinkService()->getStaticRoute('bestellvorgang.php'),
$customer,
- $orderId,
$this->createMetadata(),
$basket
);
@@ -372,7 +407,7 @@ private function authorizeInstalmentTransaction(): bool
$this->sessionHelper->redirectError(
Text::convertUTF8($authorization->getMessage()->getCustomer()),
'heidelpayTransactionError',
- PaymentHandler::REDIRECT_ON_FAILURE_URL
+ PaymentHandler::REDIRECT_TO_PAYMENT_SELECTION_URL
);
} catch (UnzerApiException $exc) {
$msg = $exc->getMerchantMessage() . ' | Id: ' . $exc->getErrorId() . ' | Code: ' . $exc->getCode();
@@ -380,7 +415,7 @@ private function authorizeInstalmentTransaction(): bool
$this->sessionHelper->redirectError(
Text::convertUTF8($exc->getClientMessage()),
'UnzerApiException',
- PaymentHandler::REDIRECT_ON_FAILURE_URL
+ PaymentHandler::REDIRECT_TO_PAYMENT_SELECTION_URL
);
} catch (RuntimeException $exc) {
$this->errorLog(
@@ -390,14 +425,14 @@ private function authorizeInstalmentTransaction(): bool
$this->sessionHelper->redirectError(
$this->trans(Config::LANG_PAYMENT_PROCESS_RUNTIME_EXCEPTION),
'paymentRuntimeException',
- PaymentHandler::REDIRECT_ON_FAILURE_URL
+ PaymentHandler::REDIRECT_TO_PAYMENT_SELECTION_URL
);
} catch (Exception $exc) {
$this->errorLog('An error occured in the payment process: ' . $exc->getMessage(), static::class);
$this->sessionHelper->redirectError(
$this->trans(Config::LANG_PAYMENT_PROCESS_EXCEPTION),
'paymentRuntimeException',
- PaymentHandler::REDIRECT_ON_FAILURE_URL
+ PaymentHandler::REDIRECT_TO_PAYMENT_SELECTION_URL
);
}
}
diff --git a/paymentmethod/HeidelpayInvoice.php b/paymentmethod/HeidelpayInvoice.php
index db3d475..3bb2549 100644
--- a/paymentmethod/HeidelpayInvoice.php
+++ b/paymentmethod/HeidelpayInvoice.php
@@ -1,15 +1,20 @@
plugin->getPaymentMethods()->getMethodByID($this->moduleID);
+
+ if ($payMethod !== null && $payMethod->getActive()) {
+ $this->kZahlungsart = $payMethod->getMethodID();
+ $result = Shop::Container()->getDB()->select('tversandartzahlungsart', 'kZahlungsart', $this->kZahlungsart);
+
+ if ($result) {
+ $notification = new NotificationEntry(
+ NotificationEntry::TYPE_INFO,
+ sprintf(__('hpDeprecationPaymentMethodTitle'), $payMethod->getName()),
+ sprintf(nl2br(__('hpDeprecationInvoiceNotice')), $payMethod->getName())
+ );
+
+ $notification->setPluginId((string) $this->plugin->getID());
+ Notification::getInstance()->addNotify($notification);
+ }
+ }
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function isSelectable(): bool
+ {
+ // Add deprecation notice log IF payment method is selectable (ie being actively used)
+ $isSelectable = parent::isSelectable();
+ $payMethod = $this->plugin->getPaymentMethods()->getMethodByID($this->moduleID);
+
+ if ($isSelectable && $payMethod !== null && $payMethod->getActive()) {
+ $this->noticeLog(
+ sprintf(nl2br(__('hpDeprecationInvoiceNotice')), $payMethod->getName())
+ );
+ }
+
+ return $isSelectable;
+ }
/**
* Data the merchant needs to put on the Invoice.
@@ -53,6 +103,9 @@ public function getOrderAttributes(Bestellung $order, AbstractTransactionType $t
$oPaymentInfo->cKontoNr = $oPaymentInfo->cIBAN;
$oPaymentInfo->cBLZ = $oPaymentInfo->cBIC;
$oPaymentInfo->cVerwendungszweck = Text::convertUTF8($transaction->getDescriptor() ?? '');
+ $oPaymentInfo->cBankName = '';
+ $oPaymentInfo->cKartenNr = '';
+ $oPaymentInfo->cCVV = '';
isset($oPaymentInfo->kZahlungsInfo) ? $oPaymentInfo->updateInDB() : $oPaymentInfo->insertInDB();
@@ -68,15 +121,26 @@ public function getOrderAttributes(Bestellung $order, AbstractTransactionType $t
* @inheritDoc
* @return AbstractTransactionType|Charge
*/
- protected function performTransaction(BasePaymentType $payment, $order): AbstractTransactionType
+ protected function performTransaction(BasePaymentType $payment, Bestellung $order): AbstractTransactionType
{
- return $this->adapter->getApi()->charge(
+ // Create / Update existing customer resource if needed
+ $customer = $this->createOrFetchHeidelpayCustomer($this->adapter, $this->sessionHelper, false);
+
+ if ($customer->getId()) {
+ $customer = $this->adapter->getCurrentConnection()->updateCustomer($customer);
+ }
+
+ $charge = new Charge(
$this->getTotalPriceCustomerCurrency($order),
- $order->Waehrung->cISO,
+ $order->Waehrung->getCode(),
+ $this->getReturnURL($order)
+ );
+ $charge->setOrderId($order->cBestellNr ?? null);
+
+ return $this->adapter->getCurrentConnection()->performCharge(
+ $charge,
$payment->getId(),
- $this->getReturnURL($order),
- null,
- $order->cBestellNr ?? null,
+ $customer,
$this->createMetadata()
);
}
diff --git a/paymentmethod/HeidelpayInvoiceFactoring.php b/paymentmethod/HeidelpayInvoiceFactoring.php
index 8553cc7..37d6376 100644
--- a/paymentmethod/HeidelpayInvoiceFactoring.php
+++ b/paymentmethod/HeidelpayInvoiceFactoring.php
@@ -1,4 +1,5 @@
debugLog('Basket Resource: ' . $basket->jsonSerialize(), static::class);
- return $this->adapter->getApi()->charge(
+ $charge = new Charge(
$this->getTotalPriceCustomerCurrency($order),
- $order->Waehrung->cISO,
+ $order->Waehrung->getCode(),
+ $this->getReturnURL($order)
+ );
+ $charge->setOrderId($order->cBestellNr ?? null);
+
+ return $this->adapter->getApi()->performCharge(
+ $charge,
$payment->getId(),
- $this->getReturnURL($order),
$customer,
- $order->cBestellNr ?? null,
$this->createMetadata(),
$basket
);
diff --git a/paymentmethod/HeidelpayInvoiceGuaranteed.php b/paymentmethod/HeidelpayInvoiceGuaranteed.php
index 7a7b61c..14a205c 100644
--- a/paymentmethod/HeidelpayInvoiceGuaranteed.php
+++ b/paymentmethod/HeidelpayInvoiceGuaranteed.php
@@ -1,9 +1,11 @@
cancel(null, CancelReasonCodes::REASON_CODE_CANCEL);
+ $reference = str_replace(
+ ['%ORDER_ID%', '%SHOPNAME%'],
+ [$order->cBestellNr, Shop::getSettingValue(CONF_GLOBAL, 'global_shopname')],
+ $this->trans(Config::LANG_CANCEL_PAYMENT_REFERENCE)
+ );
+
+ return $transaction->cancel(null, CancelReasonCodes::REASON_CODE_CANCEL, $reference);
}
/**
@@ -63,12 +73,14 @@ public function cancelPaymentTransaction(
*/
public function handleStepAdditional(JTLSmarty $view): void
{
+ $this->adapter->getConnectionForSession();
$shopCustomer = $this->sessionHelper->getFrontendSession()->getCustomer();
$customer = $this->createOrFetchHeidelpayCustomer(
$this->adapter,
$this->sessionHelper,
$this->isB2BCustomer($shopCustomer)
);
+
$customer->setShippingAddress(
$this->createHeidelpayAddress(
$this->sessionHelper->getFrontendSession()->get('Lieferadresse')
@@ -110,7 +122,7 @@ public function validateAdditional(): bool
* @inheritDoc
* @return AbstractTransactionType|Charge
*/
- protected function performTransaction(BasePaymentType $payment, $order): AbstractTransactionType
+ protected function performTransaction(BasePaymentType $payment, Bestellung $order): AbstractTransactionType
{
// Create or fetch customer resource
$shopCustomer = $this->sessionHelper->getFrontendSession()->getCustomer();
@@ -125,7 +137,7 @@ protected function performTransaction(BasePaymentType $payment, $order): Abstrac
// Update existing customer resource if needed
if ($customer->getId()) {
- $customer = $this->adapter->getApi()->updateCustomer($customer);
+ $customer = $this->adapter->getCurrentConnection()->updateCustomer($customer);
$this->debugLog('Updated Customer Resource: ' . $customer->jsonSerialize(), static::class);
}
@@ -139,13 +151,17 @@ protected function performTransaction(BasePaymentType $payment, $order): Abstrac
);
$this->debugLog('Basket Resource: ' . $basket->jsonSerialize(), static::class);
- return $this->adapter->getApi()->charge(
+ $charge = new Charge(
$this->getTotalPriceCustomerCurrency($order),
- $order->Waehrung->cISO,
+ $order->Waehrung->getCode(),
+ $this->getReturnURL($order)
+ );
+ $charge->setOrderId($order->cBestellNr ?? null);
+
+ return $this->adapter->getCurrentConnection()->performCharge(
+ $charge,
$payment->getId(),
- $this->getReturnURL($order),
$customer,
- $order->cBestellNr ?? null,
$this->createMetadata(),
$basket
);
diff --git a/paymentmethod/HeidelpayPayPal.php b/paymentmethod/HeidelpayPayPal.php
index 7299e8a..80b7c76 100644
--- a/paymentmethod/HeidelpayPayPal.php
+++ b/paymentmethod/HeidelpayPayPal.php
@@ -1,8 +1,10 @@
createOrFetchHeidelpayCustomer($this->adapter, $this->sessionHelper, false);
@@ -47,16 +49,20 @@ protected function performTransaction(BasePaymentType $payment, $order): Abstrac
// Update existing customer resource if needed
if ($customer->getId()) {
- $customer = $this->adapter->getApi()->updateCustomer($customer);
+ $customer = $this->adapter->getCurrentConnection()->updateCustomer($customer);
}
- return $this->adapter->getApi()->charge(
+ $charge = new Charge(
$this->getTotalPriceCustomerCurrency($order),
- $order->Waehrung->cISO,
+ $order->Waehrung->getCode(),
+ $this->getReturnURL($order)
+ );
+ $charge->setOrderId($order->cBestellNr ?? null);
+
+ return $this->adapter->getCurrentConnection()->performCharge(
+ $charge,
$payment->getId(),
- $this->getReturnURL($order),
$customer,
- $order->cBestellNr ?? null,
$this->createMetadata()
);
}
diff --git a/paymentmethod/HeidelpayPrepayment.php b/paymentmethod/HeidelpayPrepayment.php
index 4ded596..578d665 100644
--- a/paymentmethod/HeidelpayPrepayment.php
+++ b/paymentmethod/HeidelpayPrepayment.php
@@ -1,4 +1,5 @@
cKontoNr = $oPaymentInfo->cIBAN;
$oPaymentInfo->cBLZ = $oPaymentInfo->cBIC;
$oPaymentInfo->cVerwendungszweck = Text::convertUTF8($transaction->getDescriptor() ?? '');
+ $oPaymentInfo->cBankName = '';
+ $oPaymentInfo->cKartenNr = '';
+ $oPaymentInfo->cCVV = '';
isset($oPaymentInfo->kZahlungsInfo) ? $oPaymentInfo->updateInDB() : $oPaymentInfo->insertInDB();
@@ -70,15 +76,26 @@ public function getOrderAttributes(Bestellung $order, AbstractTransactionType $t
* @inheritDoc
* @return AbstractTransactionType|Charge
*/
- protected function performTransaction(BasePaymentType $payment, $order): AbstractTransactionType
+ protected function performTransaction(BasePaymentType $payment, Bestellung $order): AbstractTransactionType
{
- return $this->adapter->getApi()->charge(
+ // Create / Update existing customer resource if needed
+ $customer = $this->createOrFetchHeidelpayCustomer($this->adapter, $this->sessionHelper, false);
+
+ if ($customer->getId()) {
+ $customer = $this->adapter->getCurrentConnection()->updateCustomer($customer);
+ }
+
+ $charge = new Charge(
$this->getTotalPriceCustomerCurrency($order),
- $order->Waehrung->cISO,
+ $order->Waehrung->getCode(),
+ $this->getReturnURL($order)
+ );
+ $charge->setOrderId($order->cBestellNr ?? null);
+
+ return $this->adapter->getCurrentConnection()->performCharge(
+ $charge,
$payment->getId(),
- $this->getReturnURL($order),
- null,
- $order->cBestellNr ?? null,
+ $customer,
$this->createMetadata()
);
}
diff --git a/paymentmethod/HeidelpayPrzelewy24.php b/paymentmethod/HeidelpayPrzelewy24.php
index dcc570c..3ffc6dd 100644
--- a/paymentmethod/HeidelpayPrzelewy24.php
+++ b/paymentmethod/HeidelpayPrzelewy24.php
@@ -1,13 +1,16 @@
adapter->getApi()->charge(
+ // Create / Update existing customer resource if needed
+ $customer = $this->createOrFetchHeidelpayCustomer($this->adapter, $this->sessionHelper, false);
+
+ if ($customer->getId()) {
+ $customer = $this->adapter->getCurrentConnection()->updateCustomer($customer);
+ }
+
+ $charge = new Charge(
$this->getTotalPriceCustomerCurrency($order),
- $order->Waehrung->cISO,
+ $order->Waehrung->getCode(),
+ $this->getReturnURL($order)
+ );
+ $charge->setOrderId($order->cBestellNr ?? null);
+
+ return $this->adapter->getCurrentConnection()->performCharge(
+ $charge,
$payment->getId(),
- $this->getReturnURL($order),
- null,
- $order->cBestellNr ?? null,
+ $customer,
$this->createMetadata()
);
}
diff --git a/paymentmethod/HeidelpaySEPADirectDebit.php b/paymentmethod/HeidelpaySEPADirectDebit.php
index de4da70..eae63f6 100644
--- a/paymentmethod/HeidelpaySEPADirectDebit.php
+++ b/paymentmethod/HeidelpaySEPADirectDebit.php
@@ -1,8 +1,10 @@
adapter->getApi()->charge(
+ // Create / Update existing customer resource if needed
+ $customer = $this->createOrFetchHeidelpayCustomer($this->adapter, $this->sessionHelper, false);
+
+ if ($customer->getId()) {
+ $customer = $this->adapter->getCurrentConnection()->updateCustomer($customer);
+ }
+
+ $charge = new Charge(
$this->getTotalPriceCustomerCurrency($order),
- $order->Waehrung->cISO,
+ $order->Waehrung->getCode(),
+ $this->getReturnURL($order)
+ );
+ $charge->setOrderId($order->cBestellNr ?? null);
+
+ return $this->adapter->getCurrentConnection()->performCharge(
+ $charge,
$payment->getId(),
- $this->getReturnURL($order),
- null,
- $order->cBestellNr ?? null,
+ $customer,
$this->createMetadata()
);
}
diff --git a/paymentmethod/HeidelpaySEPADirectDebitGuaranteed.php b/paymentmethod/HeidelpaySEPADirectDebitGuaranteed.php
index db4c691..a1e648b 100644
--- a/paymentmethod/HeidelpaySEPADirectDebitGuaranteed.php
+++ b/paymentmethod/HeidelpaySEPADirectDebitGuaranteed.php
@@ -1,4 +1,5 @@
cancel(null, CancelReasonCodes::REASON_CODE_CANCEL);
+ $reference = str_replace(
+ ['%ORDER_ID%', '%SHOPNAME%'],
+ [$order->cBestellNr, Shop::getSettingValue(CONF_GLOBAL, 'global_shopname')],
+ $this->trans(Config::LANG_CANCEL_PAYMENT_REFERENCE)
+ );
+
+ return $transaction->cancel(null, CancelReasonCodes::REASON_CODE_CANCEL, $reference);
}
/**
@@ -72,6 +82,7 @@ public function cancelPaymentTransaction(
*/
public function handleStepAdditional(JTLSmarty $view): void
{
+ $this->adapter->getConnectionForSession();
$shopCustomer = $this->sessionHelper->getFrontendSession()->getCustomer();
$customer = $this->createOrFetchHeidelpayCustomer(
$this->adapter,
@@ -148,7 +159,7 @@ protected function performTransaction(BasePaymentType $payment, $order): Abstrac
// Update existing customer resource if needed
if ($customer->getId()) {
- $customer = $this->adapter->getApi()->updateCustomer($customer);
+ $customer = $this->adapter->getCurrentConnection()->updateCustomer($customer);
$this->debugLog('Updated Customer Resource: ' . $customer->jsonSerialize(), static::class);
}
@@ -158,17 +169,21 @@ protected function performTransaction(BasePaymentType $payment, $order): Abstrac
$session->getCart(),
$order->Waehrung,
$session->getLanguage(),
- $payment->getId()
+ $order->cBestellNr ?? $payment->getId()
);
$this->debugLog('Basket Resource: ' . $basket->jsonSerialize(), static::class);
- return $this->adapter->getApi()->charge(
+ $charge = new Charge(
$this->getTotalPriceCustomerCurrency($order),
- $order->Waehrung->cISO,
+ $order->Waehrung->getCode(),
+ $this->getReturnURL($order)
+ );
+ $charge->setOrderId($order->cBestellNr ?? null);
+
+ return $this->adapter->getCurrentConnection()->performCharge(
+ $charge,
$payment->getId(),
- $this->getReturnURL($order),
$customer,
- $order->cBestellNr ?? null,
$this->createMetadata(),
$basket
);
diff --git a/paymentmethod/HeidelpaySofort.php b/paymentmethod/HeidelpaySofort.php
index de3fca9..4add54e 100644
--- a/paymentmethod/HeidelpaySofort.php
+++ b/paymentmethod/HeidelpaySofort.php
@@ -1,13 +1,16 @@
adapter->getApi()->charge(
+ // Create / Update existing customer resource if needed
+ $customer = $this->createOrFetchHeidelpayCustomer($this->adapter, $this->sessionHelper, false);
+
+ if ($customer->getId()) {
+ $customer = $this->adapter->getCurrentConnection()->updateCustomer($customer);
+ }
+
+ $charge = new Charge(
$this->getTotalPriceCustomerCurrency($order),
- $order->Waehrung->cISO,
+ $order->Waehrung->getCode(),
+ $this->getReturnURL($order)
+ );
+ $charge->setOrderId($order->cBestellNr ?? null);
+
+ return $this->adapter->getCurrentConnection()->performCharge(
+ $charge,
$payment->getId(),
- $this->getReturnURL($order),
- null,
- $order->cBestellNr ?? null,
+ $customer,
$this->createMetadata()
);
}
diff --git a/paymentmethod/HeidelpayWeChatPay.php b/paymentmethod/HeidelpayWeChatPay.php
index 4f304e5..e3178d0 100644
--- a/paymentmethod/HeidelpayWeChatPay.php
+++ b/paymentmethod/HeidelpayWeChatPay.php
@@ -1,13 +1,16 @@
adapter->getApi()->charge(
+ // Create / Update existing customer resource if needed
+ $customer = $this->createOrFetchHeidelpayCustomer($this->adapter, $this->sessionHelper, false);
+
+ if ($customer->getId()) {
+ $customer = $this->adapter->getCurrentConnection()->updateCustomer($customer);
+ }
+
+ $charge = new Charge(
$this->getTotalPriceCustomerCurrency($order),
- $order->Waehrung->cISO,
+ $order->Waehrung->getCode(),
+ $this->getReturnURL($order)
+ );
+ $charge->setOrderId($order->cBestellNr ?? null);
+
+ return $this->adapter->getCurrentConnection()->performCharge(
+ $charge,
$payment->getId(),
- $this->getReturnURL($order),
- null,
- $order->cBestellNr ?? null,
+ $customer,
$this->createMetadata()
);
}
diff --git a/paymentmethod/HeidelpayiDEAL.php b/paymentmethod/HeidelpayiDEAL.php
index dc4adf9..4983cba 100644
--- a/paymentmethod/HeidelpayiDEAL.php
+++ b/paymentmethod/HeidelpayiDEAL.php
@@ -1,13 +1,16 @@
adapter->getApi()->charge(
+ // Create / Update existing customer resource if needed
+ $customer = $this->createOrFetchHeidelpayCustomer($this->adapter, $this->sessionHelper, false);
+
+ if ($customer->getId()) {
+ $customer = $this->adapter->getCurrentConnection()->updateCustomer($customer);
+ }
+
+ $charge = new Charge(
$this->getTotalPriceCustomerCurrency($order),
- $order->Waehrung->cISO,
+ $order->Waehrung->getCode(),
+ $this->getReturnURL($order)
+ );
+ $charge->setOrderId($order->cBestellNr ?? null);
+
+ return $this->adapter->getCurrentConnection()->performCharge(
+ $charge,
$payment->getId(),
- $this->getReturnURL($order),
- null,
- $order->cBestellNr ?? null,
+ $customer,
$this->createMetadata()
);
}
diff --git a/paymentmethod/UnzerApplePay.php b/paymentmethod/UnzerApplePay.php
new file mode 100644
index 0000000..f54613d
--- /dev/null
+++ b/paymentmethod/UnzerApplePay.php
@@ -0,0 +1,142 @@
+getTemplateVars('hpPayment') ?: [];
+ $session = $this->sessionHelper->getFrontendSession();
+ $countryCode = end(explode('-', $data['locale']));
+
+ $data['snippets'] = [
+ 'NOT_SUPPORTED' => $this->plugin->getLocalization()->getTranslation(Config::LANG_APPLE_PAY_NOT_SUPPORTED)
+ ?? Config::LANG_APPLE_PAY_NOT_SUPPORTED,
+ 'CANCEL_BY_USER' => $this->plugin->getLocalization()->getTranslation(Config::LANG_APPLE_PAY_CANCEL_BY_USER)
+ ?? Config::LANG_APPLE_PAY_CANCEL_BY_USER
+ ];
+
+ $data['paymentRequest'] = [
+ 'countryCode' => $countryCode,
+ 'currencyCode' => $session->getCurrency()->getCode(),
+ 'supportedNetworks' => ['visa', 'masterCard'],
+ 'merchantCapabilities' => ['supports3DS'],
+ 'total' => [
+ 'label' => Shop::getSettingValue(\CONF_GLOBAL, 'global_shopname'),
+ 'amount' => round($session->getCart()->gibGesamtsummeWaren(true), 2),
+ ],
+ 'lineItems' => $this->createApplePayLineItems(
+ $session->getCart(),
+ $session->getCurrency(),
+ $session->getLanguage()
+ ),
+ ];
+
+ $view->assign('hpPayment', $data);
+ }
+
+ /**
+ * Checks if apple pay method is fully configured
+ *
+ * @param array $args
+ * @return boolean
+ */
+ public function isValidIntern($args = []): bool
+ {
+ try {
+ /** @var CertificationService $certService */
+ $certService = Shop::Container()->get(CertificationService::class);
+
+ /** @var Config $config */
+ $config = Shop::Container()->get(Config::class);
+
+ $merchantId = $config->get(Config::APPLEPAY_MERCHANT_IDENTIFIER);
+ $merchantDomain = $config->get(Config::APPLEPAY_MERCHANT_DOMAIN);
+ $merchantCert = $certService->get(Config::APPLEPAY_MERCHANT_SIGNED_PEM);
+ $merchantPrivateKey = $certService->get(Config::APPLEPAY_MERCHANT_PRIVATE_KEY);
+ $paymentCert = $certService->get(Config::APPLEPAY_PAYMENT_SIGNED_PEM);
+ $paymentPrivateKey = $certService->get(Config::APPLEPAY_PAYMENT_PRIVATE_KEY);
+
+ if (
+ empty($merchantId) || empty($merchantDomain) ||
+ empty($merchantCert) || empty($merchantPrivateKey) ||
+ empty($paymentCert) || empty($paymentPrivateKey)
+ ) {
+ $this->debugLog('ApplePay Payment Method not fully configured', self::class);
+ return false;
+ }
+ } catch (Exception $exc) {
+ $this->errorLog(
+ 'An error occured while validating apple pay payment method: ' . $exc->getMessage(),
+ self::class
+ );
+
+ return false;
+ }
+
+ return parent::isValidIntern($args);
+ }
+
+ /**
+ * @inheritDoc
+ * @return AbstractTransactionType|Charge
+ */
+ protected function performTransaction(BasePaymentType $payment, $order): AbstractTransactionType
+ {
+ // Create a customer with shipping address for Paypal's Buyer Protection
+ $customer = $this->createOrFetchHeidelpayCustomer($this->adapter, $this->sessionHelper, false);
+ $customer->setShippingAddress($this->createHeidelpayAddress($order->Lieferadresse));
+ $customer->setBillingAddress($this->createHeidelpayAddress($order->oRechnungsadresse));
+
+ // Update existing customer resource if needed
+ if ($customer->getId()) {
+ $customer = $this->adapter->getCurrentConnection()->updateCustomer($customer);
+ }
+
+ $charge = new Charge(
+ $this->getTotalPriceCustomerCurrency($order),
+ $order->Waehrung->getCode(),
+ $this->getReturnURL($order)
+ );
+ $charge->setOrderId($order->cBestellNr ?? null);
+
+ return $this->adapter->getCurrentConnection()->performCharge(
+ $charge,
+ $payment->getId(),
+ $customer,
+ $this->createMetadata()
+ );
+ }
+}
diff --git a/paymentmethod/UnzerBancontact.php b/paymentmethod/UnzerBancontact.php
new file mode 100644
index 0000000..2a3a582
--- /dev/null
+++ b/paymentmethod/UnzerBancontact.php
@@ -0,0 +1,80 @@
+get(Config::class);
+ $data = $view->getTemplateVars('hpPayment') ?: [];
+
+ $data['styling'] = [
+ Config::FONT_COLOR => $config->get(Config::FONT_COLOR),
+ Config::FONT_FAMILY => $config->get(Config::FONT_FAMILY),
+ Config::FONT_SIZE => $config->get(Config::FONT_SIZE),
+ ];
+
+ $view->assign('hpPayment', $data);
+ }
+
+ /**
+ * @inheritDoc
+ * @return AbstractTransactionType|Charge
+ */
+ protected function performTransaction(BasePaymentType $payment, $order): AbstractTransactionType
+ {
+ // Create a customer with shipping address for Paypal's Buyer Protection
+ $customer = $this->createOrFetchHeidelpayCustomer($this->adapter, $this->sessionHelper, false);
+ $customer->setShippingAddress($this->createHeidelpayAddress($order->Lieferadresse));
+ $customer->setBillingAddress($this->createHeidelpayAddress($order->oRechnungsadresse));
+
+ // Update existing customer resource if needed
+ if ($customer->getId()) {
+ $customer = $this->adapter->getCurrentConnection()->updateCustomer($customer);
+ }
+
+ $charge = new Charge(
+ $this->getTotalPriceCustomerCurrency($order),
+ $order->Waehrung->getCode(),
+ $this->getReturnURL($order)
+ );
+ $charge->setOrderId($order->cBestellNr ?? null);
+
+ return $this->adapter->getCurrentConnection()->performCharge(
+ $charge,
+ $payment->getId(),
+ $customer,
+ $this->createMetadata()
+ );
+ }
+}
diff --git a/paymentmethod/UnzerPaylaterDirectDebit.php b/paymentmethod/UnzerPaylaterDirectDebit.php
new file mode 100644
index 0000000..e885b41
--- /dev/null
+++ b/paymentmethod/UnzerPaylaterDirectDebit.php
@@ -0,0 +1,216 @@
+adapter->getConnectionForOrder($order);
+
+ $reference = str_replace(
+ ['%ORDER_ID%', '%SHOPNAME%'],
+ [$order->cBestellNr, Shop::getSettingValue(CONF_GLOBAL, 'global_shopname')],
+ $this->trans(Config::LANG_CANCEL_PAYMENT_REFERENCE)
+ );
+
+ $cancel = (new Cancellation($transaction->getAmount()))->setPaymentReference($reference);
+
+ // Cancel before charge (reversal)
+ if ($transaction instanceof Authorization) {
+ return $api->cancelAuthorizedPayment($payment, $cancel);
+ }
+
+ // Cancel after charge (refund)
+ return $api->cancelChargedPayment($payment, $cancel);
+ }
+
+ /**
+ * Save the payment reference and some other bank data.
+ *
+ * @param Bestellung $order
+ * @param Authorization $transaction
+ * @return array
+ */
+ public function getOrderAttributes(Bestellung $order, AbstractTransactionType $transaction): array
+ {
+ return [
+ self::ATTR_IBAN => $transaction->getIban(),
+ self::ATTR_BIC => $transaction->getBic(),
+ self::ATTR_TRANSACTION_DESCRIPTOR => $transaction->getDescriptor(),
+ self::ATTR_ACCOUNT_HOLDER => $transaction->getHolder()
+ ];
+ }
+
+ /**
+ * Different billing and shipping address is allowed, BUT first and last name should be the same.
+ *
+ * @return bool
+ */
+ public function isSelectable(): bool
+ {
+ // @see: https://unz.atlassian.net/browse/S360-21?focusedCommentId=322832
+ // if (isset($_SESSION['Bestellung']->kLieferadresse) && $_SESSION['Bestellung']->kLieferadresse == -1) {
+ // /** @var Lieferadresse $shipping */
+ // $shipping = $this->sessionHelper->getFrontendSession()->get('Lieferadresse');
+ // $billing = $this->sessionHelper->getFrontendSession()->getCustomer();
+
+ // if ($shipping->cVorname !== $billing->cVorname || $shipping->cNachname !== $billing->cNachname) {
+ // $this->debugLog(
+ // 'Hide Unzer Paylater Direct Debit as the names for shipping and billing address are different.',
+ // static::class
+ // );
+ // return false;
+ // }
+ // }
+ if (
+ $this->isB2BCustomer($this->sessionHelper->getFrontendSession()->getCustomer()) ||
+ $this->sessionHelper->getFrontendSession()->getCurrency()->getCode() !== 'EUR'
+ ) {
+ return false;
+ }
+
+ return parent::isSelectable();
+ }
+
+ /**
+ * Add Customer Resource to view.
+ *
+ * @param JTLSmarty $view
+ * @return void
+ */
+ public function handleStepAdditional(JTLSmarty $view): void
+ {
+ $this->adapter->getConnectionForSession();
+ $shopCustomer = $this->sessionHelper->getFrontendSession()->getCustomer();
+ $customer = $this->createOrFetchHeidelpayCustomer(
+ $this->adapter,
+ $this->sessionHelper,
+ $this->isB2BCustomer($shopCustomer)
+ );
+ $customer->setShippingAddress(
+ $this->createHeidelpayAddress(
+ $this->sessionHelper->getFrontendSession()->get('Lieferadresse')
+ )
+ );
+
+ $data = $view->getTemplateVars('hpPayment') ?: [];
+ $data['customer'] = $customer;
+ $data['isB2B'] = $this->isB2BCustomer($shopCustomer);
+
+ $view->assign('hpPayment', $data);
+ }
+
+ /**
+ * Generate and add threat metrix id (fraud prevention).
+ *
+ * @param JTLSmarty $view
+ * @return null|string
+ */
+ public function handleStepReviewOrder(JTLSmarty $view): ?string
+ {
+ $data = $view->getTemplateVars('hpPayment') ?: [];
+ $data['threatMetrixId'] = $this->sessionHelper->generateThreatMetrixId();
+ $view->assign('hpPayment', $data);
+
+ return 'template/partials/_threatMetrix';
+ }
+
+ protected function performTransaction(BasePaymentType $payment, Bestellung $order): AbstractTransactionType
+ {
+ // Create or fetch customer resource
+ $shopCustomer = $this->sessionHelper->getFrontendSession()->getCustomer();
+ $customer = $this->createOrFetchHeidelpayCustomer(
+ $this->adapter,
+ $this->sessionHelper,
+ $this->isB2BCustomer($shopCustomer)
+ );
+ $customer->setShippingAddress($this->createHeidelpayAddress($order->Lieferadresse));
+ $customer->setBillingAddress($this->createHeidelpayAddress($order->oRechnungsadresse));
+ $this->debugLog('Customer Resource: ' . $customer->jsonSerialize(), static::class);
+
+ // Update existing customer resource if needed
+ if ($customer->getId()) {
+ $customer = $this->adapter->getCurrentConnection()->updateCustomer($customer);
+ $this->debugLog('Updated Customer Resource: ' . $customer->jsonSerialize(), static::class);
+ }
+
+ // Create Basket
+ $session = $this->sessionHelper->getFrontendSession();
+ $basket = $this->createHeidelpayBasket(
+ $session->getCart(),
+ $order->Waehrung,
+ $session->getLanguage(),
+ $order->cBestellNr ?? $payment->getId()
+ );
+ $this->debugLog('Basket Resource: ' . $basket->jsonSerialize(), static::class);
+
+ // Authorize Transaction
+ $riskData = (new RiskData())
+ ->setThreatMetrixId($this->sessionHelper->get(SessionHelper::KEY_THREAT_METRIX_ID))
+ ->setRegistrationLevel($shopCustomer->nRegistriert == '1' ? '1' : '0')
+ ->setRegistrationDate(
+ DateTime::createFromFormat('Y-m-d', $shopCustomer->dErstellt ?? date('Y-m-d'))->format('Ymd')
+ );
+
+ $authorization = new Authorization(
+ $this->getTotalPriceCustomerCurrency($order),
+ $order->Waehrung->getCode(),
+ $this->getReturnURL($order)
+ );
+ $authorization->setOrderId($order->cBestellNr ?? null);
+ $authorization->setRiskData($riskData);
+
+ return $this->adapter->getCurrentConnection()->performAuthorization(
+ $authorization,
+ $payment->getId(),
+ $customer,
+ $this->createMetadata(),
+ $basket
+ );
+ }
+}
diff --git a/paymentmethod/UnzerPaylaterInstallment.php b/paymentmethod/UnzerPaylaterInstallment.php
new file mode 100644
index 0000000..49bd088
--- /dev/null
+++ b/paymentmethod/UnzerPaylaterInstallment.php
@@ -0,0 +1,293 @@
+adapter->getConnectionForOrder($order);
+
+ $reference = str_replace(
+ ['%ORDER_ID%', '%SHOPNAME%'],
+ [$order->cBestellNr, Shop::getSettingValue(CONF_GLOBAL, 'global_shopname')],
+ $this->trans(Config::LANG_CANCEL_PAYMENT_REFERENCE)
+ );
+
+ $cancel = (new Cancellation($transaction->getAmount()))->setPaymentReference($reference);
+
+ // Cancel before charge (reversal)
+ if ($transaction instanceof Authorization) {
+ return $api->cancelAuthorizedPayment($payment, $cancel);
+ }
+
+ // Cancel after charge (refund)
+ return $api->cancelChargedPayment($payment, $cancel);
+ }
+
+ /**
+ * Data the merchant needs to put on the Invoice.
+ *
+ * The information iban, bic, descriptor and holder data must be be stated on the invoice
+ * so that the customer can make the bank transfer.
+ *
+ * The customer should be informed that he should use the descriptor during online banking transfer.
+ * This is the identifier that links the payment to the customer.
+ *
+ * We also save this data as payment info (tzahlungsinfo) to it is easily accessible.
+ *
+ * @param Bestellung $order
+ * @param Authorization $transaction
+ * @return array
+ */
+ public function getOrderAttributes(Bestellung $order, AbstractTransactionType $transaction): array
+ {
+ // save payment information
+ $oPaymentInfo = new ZahlungsInfo(0, $order->kBestellung);
+ $oPaymentInfo->kKunde = $order->kKunde;
+ $oPaymentInfo->kBestellung = $order->kBestellung;
+ $oPaymentInfo->cInhaber = Text::convertUTF8($transaction->getHolder() ?? '');
+ $oPaymentInfo->cIBAN = Text::convertUTF8($transaction->getIban() ?? '');
+ $oPaymentInfo->cBIC = Text::convertUTF8($transaction->getBic() ?? '');
+ $oPaymentInfo->cKontoNr = $oPaymentInfo->cIBAN;
+ $oPaymentInfo->cBLZ = $oPaymentInfo->cBIC;
+ $oPaymentInfo->cVerwendungszweck = Text::convertUTF8($transaction->getDescriptor() ?? '');
+ $oPaymentInfo->cBankName = '';
+ $oPaymentInfo->cKartenNr = '';
+ $oPaymentInfo->cCVV = '';
+
+ isset($oPaymentInfo->kZahlungsInfo) ? $oPaymentInfo->updateInDB() : $oPaymentInfo->insertInDB();
+
+ return [
+ self::ATTR_IBAN => $oPaymentInfo->cIBAN,
+ self::ATTR_BIC => $oPaymentInfo->cBIC,
+ self::ATTR_TRANSACTION_DESCRIPTOR => $oPaymentInfo->cVerwendungszweck,
+ self::ATTR_ACCOUNT_HOLDER => $oPaymentInfo->cInhaber,
+ ];
+ }
+
+ /**
+ * Only allow B2C Customers
+ */
+ public function isSelectable(): bool
+ {
+ $shopCustomer = $this->sessionHelper->getFrontendSession()->getCustomer();
+ return !$this->isB2BCustomer($shopCustomer) && parent::isSelectable();
+ }
+
+ /**
+ * Load data for installment
+ *
+ * @inheritDoc
+ */
+ public function handleStepAdditional(JTLSmarty $view): void
+ {
+ $this->adapter->getConnectionForSession();
+ $shopCustomer = $this->sessionHelper->getFrontendSession()->getCustomer();
+ $customer = $this->createOrFetchHeidelpayCustomer(
+ $this->adapter,
+ $this->sessionHelper,
+ $this->isB2BCustomer($shopCustomer)
+ );
+ $customer->setShippingAddress(
+ $this->createHeidelpayAddress(
+ $this->sessionHelper->getFrontendSession()->get('Lieferadresse')
+ )
+ );
+ $customer->setBillingAddress(
+ $this->createHeidelpayAddress($this->sessionHelper->getFrontendSession()->getCustomer())
+ );
+
+ $data = $view->getTemplateVars('hpPayment') ?: [];
+ $data['customer'] = $customer;
+ $data['amount'] = round(
+ $this->sessionHelper->getFrontendSession()->getCart()->gibGesamtsummeWaren(true)
+ * Frontend::getCurrency()->getConversionFactor(),
+ 2
+ );
+ $data['currency'] = $this->sessionHelper->getFrontendSession()->getCurrency()->getCode();
+ $data['country'] = $customer->getBillingAddress()->getCountry() ?? 'DE';
+
+ $view->assign('hpPayment', $data);
+ }
+
+ /**
+ * Save customer resource id in the session.
+ *
+ * @SuppressWarnings(PHPMD.Superglobals)
+ * @return bool
+ */
+ public function validateAdditional(): bool
+ {
+ $postPaymentData = $_POST['paymentData'] ?? [];
+
+ // Save Customer ID if it exists
+ if (isset($postPaymentData['customerId'])) {
+ $this->sessionHelper->set(SessionHelper::KEY_CUSTOMER_ID, $postPaymentData['customerId']);
+
+ // Save Basket Checksum + currency
+ $this->sessionHelper->set(
+ SessionHelper::KEY_CART_CHECKSUM,
+ Cart::getChecksum($this->sessionHelper->getFrontendSession()->getCart())
+ );
+ $this->sessionHelper->set(
+ SessionHelper::KEY_CART_CURRENCY,
+ $this->sessionHelper->getFrontendSession()->getCurrency()->getCode()
+ );
+
+ return true && parent::validateAdditional();
+ }
+
+ return parent::validateAdditional();
+ }
+
+ /**
+ * Generate and add threat metrix id (fraud prevention).
+ *
+ * @param JTLSmarty $view
+ * @return null|string
+ */
+ public function handleStepReviewOrder(JTLSmarty $view): ?string
+ {
+ $data = $view->getTemplateVars('hpPayment') ?: [];
+ $data['threatMetrixId'] = $this->sessionHelper->generateThreatMetrixId();
+ $view->assign('hpPayment', $data);
+
+ // Check if basket changed
+ $currency = $this->sessionHelper->getFrontendSession()->getCurrency();
+ $basket = $this->sessionHelper->getFrontendSession()->getCart();
+
+ if (
+ Cart::getChecksum($basket) !== $this->sessionHelper->get(SessionHelper::KEY_CART_CHECKSUM) ||
+ $currency->getCode() !== $this->sessionHelper->get(SessionHelper::KEY_CART_CURRENCY)
+ ) {
+ $this->sessionHelper->clearCheckoutSession();
+ $this->sessionHelper->clear(SessionHelper::KEY_CART_CHECKSUM);
+ $this->sessionHelper->clear(SessionHelper::KEY_CART_CURRENCY);
+ $this->sessionHelper->addErrorAlert(
+ 'Aborting Checkout. Currency or Basket mismatch. Reauthorization needed!',
+ $this->trans(Config::LANG_CONFIRMATION_CHECKSUM),
+ 'basketMismatch',
+ PaymentHandler::REDIRECT_TO_PAYMENT_SELECTION_URL,
+ static::class
+ );
+
+ return null;
+ }
+
+ return 'template/partials/_threatMetrix';
+ }
+
+ /**
+ * Authorizes the order on unzer side.
+ *
+ * With a successful authorize transaction, the amount is authorized and a payment resource is created.
+ * At this point no money has been transferred.
+ *
+ * The charge transaction calls are made when the order is shipped.
+ * With a successful charge transaction, the amount has been prepared to be insured.
+ *
+ * @inheritDoc
+ * @return AbstractTransactionType|Authorization
+ */
+ protected function performTransaction(BasePaymentType $payment, Bestellung $order): AbstractTransactionType
+ {
+ // Create or fetch customer resource
+ $shopCustomer = $this->sessionHelper->getFrontendSession()->getCustomer();
+ $customer = $this->createOrFetchHeidelpayCustomer(
+ $this->adapter,
+ $this->sessionHelper,
+ $this->isB2BCustomer($shopCustomer)
+ );
+ $customer->setShippingAddress($this->createHeidelpayAddress($order->Lieferadresse));
+ $customer->setBillingAddress($this->createHeidelpayAddress($order->oRechnungsadresse));
+ $this->debugLog('Customer Resource: ' . $customer->jsonSerialize(), static::class);
+
+ // Update existing customer resource if needed
+ if ($customer->getId()) {
+ $customer = $this->adapter->getCurrentConnection()->updateCustomer($customer);
+ $this->debugLog('Updated Customer Resource: ' . $customer->jsonSerialize(), static::class);
+ }
+
+ // Create Basket
+ $session = $this->sessionHelper->getFrontendSession();
+ $basket = $this->createHeidelpayBasket(
+ $session->getCart(),
+ $order->Waehrung,
+ $session->getLanguage(),
+ $order->cBestellNr ?? $payment->getId()
+ );
+ $this->debugLog('Basket Resource: ' . $basket->jsonSerialize(), static::class);
+
+ // Authorize Transaction
+ $riskData = (new RiskData())
+ ->setThreatMetrixId($this->sessionHelper->get(SessionHelper::KEY_THREAT_METRIX_ID))
+ ->setRegistrationLevel($shopCustomer->nRegistriert == '1' ? '1' : '0')
+ ->setRegistrationDate(
+ DateTime::createFromFormat('Y-m-d', $shopCustomer->dErstellt ?? date('Y-m-d'))->format('Ymd')
+ );
+
+ $authorization = new Authorization(
+ $this->getTotalPriceCustomerCurrency($order),
+ $order->Waehrung->getCode(),
+ $this->getReturnURL($order)
+ );
+ $authorization->setOrderId($order->cBestellNr ?? null);
+ $authorization->setRiskData($riskData);
+
+ return $this->adapter->getCurrentConnection()->performAuthorization(
+ $authorization,
+ $payment->getId(),
+ $customer,
+ $this->createMetadata(),
+ $basket
+ );
+ }
+}
diff --git a/paymentmethod/UnzerPaylaterInvoice.php b/paymentmethod/UnzerPaylaterInvoice.php
new file mode 100644
index 0000000..4bc28d4
--- /dev/null
+++ b/paymentmethod/UnzerPaylaterInvoice.php
@@ -0,0 +1,309 @@
+adapter->getConnectionForOrder($order);
+
+ $reference = str_replace(
+ ['%ORDER_ID%', '%SHOPNAME%'],
+ [$order->cBestellNr, Shop::getSettingValue(CONF_GLOBAL, 'global_shopname')],
+ $this->trans(Config::LANG_CANCEL_PAYMENT_REFERENCE)
+ );
+
+ $cancel = (new Cancellation($transaction->getAmount()))->setPaymentReference($reference);
+
+ // Cancel before charge (reversal)
+ if ($transaction instanceof Authorization) {
+ return $api->cancelAuthorizedPayment($payment, $cancel);
+ }
+
+ // Cancel after charge (refund)
+ return $api->cancelChargedPayment($payment, $cancel);
+ }
+
+
+ /**
+ * Data the merchant needs to put on the Invoice.
+ *
+ * The information iban, bic, descriptor and holder data must be be stated on the invoice
+ * so that the customer can make the bank transfer.
+ *
+ * The customer should be informed that he should use the descriptor during online banking transfer.
+ * This is the identifier that links the payment to the customer.
+ *
+ * We also save this data as payment info (tzahlungsinfo) to it is easily accessible.
+ *
+ * @param Bestellung $order
+ * @param Authorization $transaction
+ * @return array
+ */
+ public function getOrderAttributes(Bestellung $order, AbstractTransactionType $transaction): array
+ {
+ // save payment information
+ $oPaymentInfo = new ZahlungsInfo(0, $order->kBestellung);
+ $oPaymentInfo->kKunde = $order->kKunde;
+ $oPaymentInfo->kBestellung = $order->kBestellung;
+ $oPaymentInfo->cInhaber = Text::convertUTF8($transaction->getHolder() ?? '');
+ $oPaymentInfo->cIBAN = Text::convertUTF8($transaction->getIban() ?? '');
+ $oPaymentInfo->cBIC = Text::convertUTF8($transaction->getBic() ?? '');
+ $oPaymentInfo->cKontoNr = $oPaymentInfo->cIBAN;
+ $oPaymentInfo->cBLZ = $oPaymentInfo->cBIC;
+ $oPaymentInfo->cVerwendungszweck = Text::convertUTF8($transaction->getDescriptor() ?? '');
+ $oPaymentInfo->cBankName = '';
+ $oPaymentInfo->cKartenNr = '';
+ $oPaymentInfo->cCVV = '';
+
+ isset($oPaymentInfo->kZahlungsInfo) ? $oPaymentInfo->updateInDB() : $oPaymentInfo->insertInDB();
+
+ return [
+ self::ATTR_IBAN => $oPaymentInfo->cIBAN,
+ self::ATTR_BIC => $oPaymentInfo->cBIC,
+ self::ATTR_TRANSACTION_DESCRIPTOR => $oPaymentInfo->cVerwendungszweck,
+ self::ATTR_ACCOUNT_HOLDER => $oPaymentInfo->cInhaber,
+ ];
+ }
+
+ /**
+ * Add Customer Resource to view.
+ *
+ * @param JTLSmarty $view
+ * @return void
+ */
+ public function handleStepAdditional(JTLSmarty $view): void
+ {
+ $this->adapter->getConnectionForSession();
+ $shopCustomer = $this->sessionHelper->getFrontendSession()->getCustomer();
+ $customer = $this->createOrFetchHeidelpayCustomer(
+ $this->adapter,
+ $this->sessionHelper,
+ $this->isB2BCustomer($shopCustomer)
+ );
+ $customer->setShippingAddress(
+ $this->createHeidelpayAddress(
+ $this->sessionHelper->getFrontendSession()->get('Lieferadresse')
+ )
+ );
+
+ $data = $view->getTemplateVars('hpPayment') ?: [];
+ $data['customer'] = $customer;
+ $data['isB2B'] = $this->isB2BCustomer($shopCustomer);
+
+ $view->assign('hpPayment', $data);
+ }
+
+ /**
+ * Generate and add threat metrix id (fraud prevention).
+ *
+ * @param JTLSmarty $view
+ * @return null|string
+ */
+ public function handleStepReviewOrder(JTLSmarty $view): ?string
+ {
+ $data = $view->getTemplateVars('hpPayment') ?: [];
+ $data['threatMetrixId'] = $this->sessionHelper->generateThreatMetrixId();
+ $view->assign('hpPayment', $data);
+
+ return 'template/partials/_threatMetrix';
+ }
+
+ /**
+ * Save customer resource id in the session.
+ *
+ * Save different billing address in session AND in the DB!
+ *
+ * @SuppressWarnings(PHPMD.Superglobals)
+ * @return bool
+ */
+ public function validateAdditional(): bool
+ {
+ $postPaymentData = $_POST['paymentData'] ?? [];
+
+ // Save Customer ID if it exists
+ if (isset($postPaymentData['customerId'])) {
+ $this->sessionHelper->set(SessionHelper::KEY_CUSTOMER_ID, $postPaymentData['customerId']);
+ $shopCustomer = $this->sessionHelper->getFrontendSession()->getCustomer();
+ $customer = $this->adapter->getConnectionForSession()->fetchCustomer($postPaymentData['customerId']);
+
+ if (!isset($_SESSION['Bestellung'])) {
+ $_SESSION['Bestellung'] = new stdClass();
+ }
+
+ /** @var Lieferadresse $shipping */
+ $shipping = $this->sessionHelper->getFrontendSession()->get('Lieferadresse');
+
+ if ($this->isB2BCustomer($shopCustomer)) {
+ // Split name into first and lastname
+ $names = $this->getNamesFromAddress($customer->getShippingAddress());
+ $shipping->cVorname = $names['firstname'] ?: $shipping->cVorname;
+ $shipping->cNachname = $names['lastname'] ?: $shipping->cNachname;
+ $shipping->cBundesland = $customer->getShippingAddress()->getState();
+ $shipping->cPLZ = $customer->getShippingAddress()->getZip();
+ $shipping->cOrt = $customer->getShippingAddress()->getCity();
+ $shipping->cLand = $customer->getShippingAddress()->getCountry();
+
+ // split street into street and street number
+ $street = $this->getStreetFromAddress($customer->getShippingAddress());
+ $shipping->cHausnummer = $street['number'] ?: $shipping->cHausnummer;
+ $shipping->cStrasse = $street['street'] ?: $shipping->cStrasse;
+ }
+
+ // Update Billing Address
+ // Split name into first and lastname
+ $names = $this->getNamesFromAddress($customer->getBillingAddress());
+ $shopCustomer->cVorname = $names['firstname'] ?: $shopCustomer->cVorname;
+ $shopCustomer->cNachname = $names['lastname'] ?: $shopCustomer->cNachname;
+
+ if ($this->isB2BCustomer($shopCustomer)) {
+ $shopCustomer->cBundesland = $customer->getBillingAddress()->getState();
+ $shopCustomer->cPLZ = $customer->getBillingAddress()->getZip();
+ $shopCustomer->cOrt = $customer->getBillingAddress()->getCity();
+ $shopCustomer->cLand = $customer->getBillingAddress()->getCountry();
+
+ // split street into street and street number
+ $street = $this->getStreetFromAddress($customer->getBillingAddress());
+ $shopCustomer->cHausnummer = $street['number'] ?: $shopCustomer->cHausnummer;
+ $shopCustomer->cStrasse = $street['street'] ?: $shopCustomer->cStrasse;
+ }
+
+ if ($customer->getShippingAddress()->getShippingType() === ShippingTypes::DIFFERENT_ADDRESS) {
+ // Set kLieferadresse to -1 in the order so that JTL knows to use the delivery address from the session
+ // and not use the billing adress as the delivery address
+ $_SESSION['Bestellung']->kLieferadresse = -1;
+ // $this->sessionHelper->getFrontendSession()->setCustomer($shopCustomer);
+ }
+
+ return true && parent::validateAdditional();
+ }
+
+ return parent::validateAdditional();
+ }
+
+ /**
+ * Authorizes the order on unzer side.
+ *
+ * With a successful authorize transaction, the amount is authorized and a payment resource is created.
+ * At this point no money has been transferred.
+ *
+ * The charge transaction calls are made when the order is shipped.
+ * With a successful charge transaction, the amount has been prepared to be insured.
+ *
+ * @inheritDoc
+ * @return AbstractTransactionType|Authorization
+ */
+ protected function performTransaction(BasePaymentType $payment, $order): AbstractTransactionType
+ {
+ // Create or fetch customer resource
+ $shopCustomer = $this->sessionHelper->getFrontendSession()->getCustomer();
+ $customer = $this->createOrFetchHeidelpayCustomer(
+ $this->adapter,
+ $this->sessionHelper,
+ $this->isB2BCustomer($shopCustomer)
+ );
+
+ if ($customer->getShippingAddress()->getStreet() === null) {
+ $customer->setShippingAddress($this->createHeidelpayAddress($order->Lieferadresse));
+ }
+
+ $customer->getBillingAddress()->setShippingType(
+ $order->kLieferadresse == -1 ? ShippingTypes::DIFFERENT_ADDRESS : ShippingTypes::EQUALS_BILLING
+ );
+
+ if ($customer->getBillingAddress()->getStreet() === null) {
+ $customer->setBillingAddress($this->createHeidelpayAddress($order->oRechnungsadresse));
+ }
+
+ $this->debugLog('Customer Resource: ' . $customer->jsonSerialize(), static::class);
+
+ // Update existing customer resource if needed
+ if ($customer->getId()) {
+ $customer = $this->adapter->getCurrentConnection()->updateCustomer($customer);
+ $this->debugLog('Updated Customer Resource: ' . $customer->jsonSerialize(), static::class);
+ }
+
+ // Create Basket
+ $session = $this->sessionHelper->getFrontendSession();
+ $basket = $this->createHeidelpayBasket(
+ $session->getCart(),
+ $order->Waehrung,
+ $session->getLanguage(),
+ $order->cBestellNr ?? $payment->getId()
+ );
+ $this->debugLog('Basket Resource: ' . $basket->jsonSerialize(), static::class);
+
+ // Authorize Transaction
+ $riskData = (new RiskData())
+ ->setThreatMetrixId($this->sessionHelper->get(SessionHelper::KEY_THREAT_METRIX_ID))
+ ->setRegistrationLevel($shopCustomer->nRegistriert == '1' ? '1' : '0')
+ ->setRegistrationDate(
+ DateTime::createFromFormat('Y-m-d', $shopCustomer->dErstellt ?? date('Y-m-d'))->format('Ymd')
+ );
+
+ $authorization = new Authorization(
+ $this->getTotalPriceCustomerCurrency($order),
+ $order->Waehrung->getCode(),
+ $this->getReturnURL($order)
+ );
+ $authorization->setOrderId($order->cBestellNr ?? null);
+ $authorization->setRiskData($riskData);
+
+ return $this->adapter->getCurrentConnection()->performAuthorization(
+ $authorization,
+ $payment->getId(),
+ $customer,
+ $this->createMetadata(),
+ $basket
+ );
+ }
+}
diff --git a/paymentmethod/template/_includes.tpl b/paymentmethod/template/_includes.tpl
index c0d059b..a02cdd6 100644
--- a/paymentmethod/template/_includes.tpl
+++ b/paymentmethod/template/_includes.tpl
@@ -1,7 +1,7 @@
-
+
-
+