diff --git a/README.md b/README.md
new file mode 100644
index 0000000..709b789
--- /dev/null
+++ b/README.md
@@ -0,0 +1,71 @@
+# ZENCART PAYMENT INTEGRATION BY NOVALNET
+Zen Cart payment module by Novalnet enables secure integration of payments and payment services for all Zen Cart shops. Novalnet payment module for Zen Cart shop helps merchants to automate payment processing from checkout till collection.
+
+## Integration requirements for Zen Cart
+Novalnet merchant account is required for processing all international and local payments through this ZenCart Payment Gateway. The module is available for the ZenCart versions 1.5.7f in the following languages: EN & DE
+
+## Key features of ZenCart payment integration
+- Easy configuration of all international & local payment methods
+- One PCI DSS certified payment platform for all payment services from checkout to collection
+- Complete automation of all payment processes
+- 60+ risk & payment fraud detection modules to prevent defaults in real time
+- Clear overview of payment status from checkout to receivables
+- Multilevel claims management with integrated handover to collection and various export functions for the accounting
+- Comprehensive fraud prevention solution with more than 60 modules (Machine learning)
+- Reporting & analytics dashboards with multiple export options
+- Automated e-mail notifications for staying up to date on the payment status
+- Automated bookkeeping report in XML, SOAP, CSV, MT940
+- Simple seamless integration of the payment module
+- Secure SSL-encoded gateways
+- Seamless checkout Iframe integration
+- One-click shopping enabled for commonly used payment types
+- Easy confirmation/cancellation of on-hold transactions for selected payment types
+- Refund option for moat of the payment types
+- Responsive templates
+
+For detailed documentation and other technical inquiries, please send us an email at sales@novalnet.de
+
+## Integrated payment methods
+- Direct Debit SEPA
+- Credit/Debit Cards
+- Apple Pay
+- Google Pay
+- Invoice
+- Prepayment
+- Invoice with payment guarantee
+- Direct Debit SEPA with payment guarantee
+- iDEAL
+- Sofort
+- giropay
+- Barzahlen/viacash
+- Przelewy24
+- eps
+- Instalment by Invoice
+- Instalment by Direct Debit SEPA
+- PayPal
+- PostFinance Card
+- PostFinance E-Finance
+- Bancontact
+- Multibanco
+- Online bank transfer
+- Alipay
+- WeChat Pay
+- Trustly
+
+## License
+See our License Agreement at: https://www.novalnet.com/payment-plugins-free-license/
+
+## Documentation & Support
+For more information about the Zen Cart Payment Integration by Novalnet, please get in touch with us: sales@novalnet.de or +49 89 9230683-20
+
+Novalnet AG
+Zahlungsinstitut (ZAG)
+Feringastr. 4
+85774 Unterföhring
+Deutschland
+Website: www.novalnet.de
+
+## Who is Novalnet AG?
+
Novalnet AG is a leading financial service institution offering payment gateways for processing online payments. Operating in the market as a full payment service provider Novalnet AG provides online merchants user-friendly payment integration with all major shop systems and self-programmed sites.
+
Accept, manage and monitor payments all on one platform with one single contract!
+
Our SaaS engine is PCI DSS certified and designed to enable real-time risk management, secured payments via escrow accounts, efficient receivables management, dynamic member and subscription management, customized payment solutions for various business models (e.g. marketplaces, affiliate programs etc.) etc.
+
+
+
+
diff --git a/changelog.txt b/changelog.txt
new file mode 100644
index 0000000..10c38b3
--- /dev/null
+++ b/changelog.txt
@@ -0,0 +1,46 @@
+*** Changelog ***
+
+= 13.2.0 - 2023.03.15 =
+* New - Implemented Novalnet Transaction Overview in the shop admin area
+* New - Barzahlen/viacash payment slip implemented on the payment success page
+* Fix - setPaymentPending parameter implemented for Apple Pay and Google Pay to avoid amount mismatch
+* Fix - Constant value is used for table novalnet_transaction_detail
+* Enhanced - Payment module has been optimized as per the new testcase
+
+= 13.0.1 - 2023.03.29 =
+* Fix - Code structures optimized to match Zen Cart coding standards
+
+= 13.0.1 - 2023.03.07 =
+* Fix - Transaction amount mismatch for PayPal payment
+* Fix - Adjusted payment module for standard Instalment cancellation process
+* Enhanced - Payment module has been updated for Zen Cart 1.5.7f German version
+
+= 13.0.0 - 2023.02.17 =
+Major version release: We've improved the seamless customer experience and brand configurations in the Novalnet Merchant Admin Portal to make it easier to preview and customise the checkout page
+
+= 2.0.0 - 2020.10.01 =
+* New - Implemented Guaranteed Direct Debit SEPA, Guaranteed Invoice, Instalment by Direct Debit SEPA, Instalment by Invoice, Barzahlen, Giropay, Eps, Przelewy24, PostFinace Card and PostFinance E-Finance Payments
+* New - Force 3D secure process has been implemented as per predefined filters and settings in the Novalnet admin portal
+* Enhanced - Implemented new encryption method for redirect payments
+* Enhanced - Credit Card iframe has been optimized
+* Enhanced - Auto configuration call perform via cURL method
+* Enhanced - Adjusted the payment module for IPV6 condition
+* Enhanced - On-hold transaction configuration has been implemented for Credit Card, Direct Debit SEPA, Guaranteed Direct Debit SEPA, Invoice, Guaranteed Invoice, Instalment by Direct Debit SEPA, Instalment by Invoice and PayPal.
+* Enhanced - Callback has been optimized as per the new testcase
+* Fix - Compatible for Zen Cart 1.5.7
+
+= 1.0.2 - 2013.01.02 =
+- Optimized all novalnet payment modules as per new testcase document.
+- Developed Novalnet Ideal Payment Module
+
+= 1.0.1 - 2012.01.12 =
+- Implement the Novalnet paypal payment method and CALLBACK SCRIPT file.
+- Add call back testing method in readme file.
+
+= 1.0.0 - 2011.12.15
+- Readme File(Specification Details included).
+- Zencart Payment Module Installation Guide (PDF included)
+- update_info File included.
+- Check hash implemented in PCI payment modules and include
+- Post back Params (Order no., Invoice Reference).
+- Iframe implemented for Credit Card Payment method.
diff --git a/extras/novalnet_callback.php b/extras/novalnet_callback.php
new file mode 100755
index 0000000..eb076a8
--- /dev/null
+++ b/extras/novalnet_callback.php
@@ -0,0 +1,662 @@
+ [
+ 'type',
+ 'checksum',
+ 'tid',
+ ],
+ 'result' => [
+ 'status',
+ ],
+ 'transaction' => [
+ 'tid',
+ 'payment_type',
+ 'status',
+ ],
+ ];
+
+ /**
+ * Request parameters.
+ *
+ * @var array
+ */
+ protected $event_data = [];
+
+ /**
+ * Order reference values.
+ *
+ * @var array
+ */
+ protected $order_details = [];
+
+ /**
+ * Recived Event type.
+ *
+ * @var string
+ */
+ protected $event_type;
+
+ /**
+ * Recived Event TID.
+ *
+ * @var int
+ */
+ protected $event_tid;
+
+ /**
+ * Recived Event parent TID.
+ *
+ * @var int
+ */
+ protected $parent_tid;
+
+ /**
+ * Core Function : Constructor()
+ *
+ */
+ public function __construct()
+ {
+ try {
+ $this->event_data = json_decode(file_get_contents('php://input'), true);
+ } catch (Exception $e) {
+ $this->displayMessage(['message' => 'Received data is not in the JSON format'. $e]);
+ }
+ $this->authenticateEventData();
+ $this->event_tid = $this->event_data['event']['tid'];
+ $this->event_type = $this->event_data['event']['type'];
+ $this->parent_tid = (!empty($this->event_data['event']['parent_tid'])) ? $this->event_data['event']['parent_tid'] : $this->event_tid;
+
+ $this->order_details = $this->getOrderDetails();
+ if (NovalnetHelper::is_success_status($this->event_data)) {
+ switch ($this->event_type) {
+ case 'PAYMENT':
+ $this->displayMessage(['message' => "The webhook notification received ('".$this->event_data['transaction']['payment_type']."') for the TID: '".$this->event_tid."'"]);
+ break;
+ case 'TRANSACTION_CAPTURE':
+ $this->handleTransactionCapture();
+ break;
+ case 'TRANSACTION_CANCEL':
+ $this->handleTransactionCancel();
+ break;
+ case 'TRANSACTION_REFUND':
+ $this->handleTransactionRefund();
+ break;
+ case 'CREDIT':
+ $this->handleTransactionCredit();
+ break;
+ case 'CHARGEBACK':
+ $this->handleChargeback();
+ break;
+ case 'INSTALMENT':
+ $this->handleInstalment();
+ break;
+ case 'INSTALMENT_CANCEL':
+ $this->handleInstalmentCancel();
+ break;
+ case 'TRANSACTION_UPDATE':
+ $this->handleTransactionUpdate();
+ break;
+ case 'PAYMENT_REMINDER_1':
+ case 'PAYMENT_REMINDER_2':
+ $this->handlePaymentReminder();
+ break;
+ case 'SUBMISSION_TO_COLLECTION_AGENCY':
+ $this->handleCollectionSubmission();
+ break;
+ default:
+ $message = "The webhook notification has been received for the unhandled EVENT type('".$this->event_type."')";
+ $this->displayMessage(['message' => $message]);
+ }
+ }
+ }
+
+ /**
+ * Authenticate the request received from Novalnet or not
+ *
+ */
+ private function authenticateEventData()
+ {
+ $novalnet_host_name = 'pay-nn.de';
+ $request_received_ip = zen_get_ip_address();
+ $novalnet_host_ip = gethostbyname($novalnet_host_name);
+ if (!empty($novalnet_host_ip) && !empty($request_received_ip)) {
+ if (MODULE_PAYMENT_NOVALNET_CALLBACK_TEST_MODE == 'False' && $novalnet_host_ip !== $request_received_ip) {
+ $this->displayMessage(['message' => 'Unauthorised access from the IP ' . $request_received_ip]);
+ }
+ } else {
+ $this->displayMessage(['message' => 'Unauthorised access from the IP. Host/recieved IP is empty']);
+ }
+ $this->validateEventData();
+ $this->validateCheckSum();
+ }
+
+ /**
+ * Validate event data mandatory parameters
+ *
+ */
+ private function validateEventData()
+ {
+ if (!empty($this->event_data['custom']['shop_invoked'])) {
+ $this->displayMessage(['message' => 'Process already handled in the shop.']);
+ }
+ foreach ($this->mandatory as $category => $parameters) {
+ if (empty($this->event_data[ $category ])) {
+ $this->displayMessage(['message' => "Required parameter category($category) not received"]);
+ } elseif (!empty($parameters)) {
+ foreach ($parameters as $parameter) {
+ if (empty($this->event_data[$category][$parameter])) {
+ $this->displayMessage(['message' => "Required parameter($parameter) in the category($category) not received"]);
+ } elseif (in_array($parameter, ['tid', 'parent_tid'], true) && ! preg_match('/^\d{17}$/', $this->event_data[$category][$parameter])) {
+ $this->displayMessage(['message' => "Invalid TID received in the category($category) not received $parameter"]);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Validate checksum
+ *
+ */
+ private function validateCheckSum()
+ {
+ if (!empty($this->event_data['event']['checksum']) && !empty($this->event_tid) && !empty($this->event_data['event']['type'])
+ && !empty($this->event_data['result']['status'])) {
+ $token_string = $this->event_tid . $this->event_data['event']['type'] . $this->event_data['result']['status'];
+ if (isset($this->event_data['transaction']['amount'])) {
+ $token_string .= $this->event_data['transaction']['amount'];
+ }
+ if (isset($this->event_data['transaction']['currency'])) {
+ $token_string .= $this->event_data['transaction']['currency'];
+ }
+ if (defined('MODULE_PAYMENT_NOVALNET_ACCESS_KEY') && !empty(MODULE_PAYMENT_NOVALNET_ACCESS_KEY)) {
+ $token_string .= strrev(MODULE_PAYMENT_NOVALNET_ACCESS_KEY);
+ }
+ $generated_checksum = hash('sha256', $token_string);
+ if ($generated_checksum != $this->event_data['event']['checksum']) {
+ $this->displayMessage(['message' =>'While notifying some data has been changed. The hash check failed']);
+ }
+ }
+ }
+
+ /**
+ * Get order details
+ *
+ */
+ private function getOrderDetails()
+ {
+ global $db;
+ $order_details = [];
+ $novalnet_order_details = $db->Execute("SELECT * FROM ".TABLE_NOVALNET_TRANSACTION_DETAIL." WHERE tid = '".$this->parent_tid."'");
+ $order_number = !empty($novalnet_order_details->fields['order_no']) ? $novalnet_order_details->fields['order_no'] : (!empty($this->event_data['transaction']['order_no']) ? $this->event_data['transaction']['order_no'] : '');
+ // If order number not found in shop and Novalnet
+ if (empty($order_number)) {
+ $this->sentCriticalMail($this->event_data);
+ $this->displayMessage(['message' => 'Order reference not found for the TID '. $this->parent_tid]);
+ }
+ // If the order number at Novalnet and the shop doesn't match
+ if (!empty($this->event_data['transaction']['order_no']) && !empty($novalnet_order_details->fields['order_no'])
+ && (($this->event_data['transaction']['order_no']) != $novalnet_order_details->fields['order_no'])) {
+ $this->displayMessage(['message' => 'Order reference not matching for the order number '. $order_number]);
+ }
+ $shop_order_details = $db->Execute("SELECT order_total, orders_id, orders_status, language_code FROM ".TABLE_ORDERS." WHERE orders_id = '".$novalnet_order_details->fields['order_no']."'");
+ $order_lang = $db->Execute("SELECT directory FROM " . TABLE_LANGUAGES . " WHERE code = '" . $shop_order_details->fields['language_code'] ."'");
+ $this->includeRequiredFiles($order_lang->fields['directory']);
+ $order_details['nn_trans_details'] = $novalnet_order_details->fields;
+ $order_details['shop_order_no'] = $order_number;
+ $order_details['shop_order_details'] = $shop_order_details->fields;
+ return $order_details;
+ }
+
+ /**
+ * Handle transaction capture
+ *
+ */
+ private function handleTransactionCapture()
+ {
+ $novalnet_update_data = [
+ 'status' => $this->event_data['transaction']['status'],
+ ];
+ $order_status = NovalnetHelper::getOrderStatus($this->event_data['transaction']['status'], $this->event_data['transaction']['payment_type']);
+ if (!empty($this->event_data['transaction']['due_date'])) {
+ $comments = PHP_EOL.sprintf(MODULE_PAYMENT_NOVALNET_TRANS_CONFIRM_SUCCESSFUL_MESSAGE, $this->event_data['transaction']['tid'], gmdate('d-m-Y')).PHP_EOL;
+ } else {
+ $comments = PHP_EOL.sprintf(MODULE_PAYMENT_NOVALNET_TRANS_CONFIRM_SUCCESSFUL_MESSAGE_TEXT, gmdate('d-m-Y')).PHP_EOL.PHP_EOL;
+ }
+ if (!empty($this->event_data['instalment']['cycle_dates'])) {
+ $total_amount = ((isset($this->order_details['nn_trans_details']['amount']) ? $this->order_details['nn_trans_details']['amount'] : 0) < $this->event_data['transaction']['amount']) ? $this->event_data['transaction']['amount'] : $this->order_details['nn_trans_details']['amount'];
+ $novalnet_update_data['instalment_cycle_details'] = NovalnetHelper::storeInstalmentdetails($this->event_data, $total_amount);
+ }
+ $order_comment = $comments;
+ $order_comment .= NovalnetHelper::getTransactionDetails($this->event_data);
+ $this->event_data['transaction']['bank_details'] = empty($this->event_data['transaction']['bank_details']) ? (!empty($this->order_details['nn_trans_details']['payment_details']) ? json_decode($this->order_details['nn_trans_details']['payment_details'], true) : []) : $this->event_data['transaction']['bank_details'];
+ if (!empty($this->event_data['transaction']['bank_details'])) {
+ $order_comment .= NovalnetHelper::getBankDetails($this->event_data);
+ }
+ if (!empty($this->event_data['instalment'])) {
+ $order_comment .= NovalnetHelper::getInstalmentDetails($this->event_data);
+ }
+ $this->updateOrderStatusHistory($this->event_data['transaction']['order_no'], $order_status, $order_comment);
+ if (in_array($this->event_data['transaction']['payment_type'], array( 'INSTALMENT_INVOICE','GUARANTEED_INVOICE')) && $this->event_data['transaction']['status'] == 'CONFIRMED') {
+ NovalnetHelper::sendPaymentConfirmationMail($order_comment, $this->event_data['transaction']['order_no']);
+ }
+ $this->updateNovalnetTransaction($novalnet_update_data, "tid='{$this->parent_tid}'");
+ $this->sendWebhookMail($comments);
+ $this->displayMessage(['message' => zen_db_prepare_input($comments . PHP_EOL)]);
+ }
+
+ /**
+ * Handle transaction cancel
+ *
+ */
+ private function handleTransactionCancel()
+ {
+ $comments = sprintf(MODULE_PAYMENT_NOVALNET_TRANS_DEACTIVATED_MESSAGE, gmdate('d-m-Y'), gmdate('H:i:s'));
+ $novalnet_update_data = [
+ 'status' => $this->event_data['transaction']['status'],
+ ];
+ $this->updateNovalnetTransaction($novalnet_update_data, "tid = '{$this->parent_tid}'");
+ $this->updateOrderStatusHistory($this->event_data['transaction']['order_no'], NovalnetHelper::getOrderStatusId(), $comments);
+ $this->sendWebhookMail($comments);
+ $this->displayMessage(['message' => zen_db_prepare_input($comments . PHP_EOL)]);
+ }
+
+
+ /**
+ * Handle transaction refund
+ *
+ */
+ private function handleTransactionRefund()
+ {
+ global $currencies;
+ $order_status_id = '';
+ $refund_amount = 0;
+ $comments = PHP_EOL . sprintf(MODULE_PAYMENT_NOVALNET_REFUND_PARENT_TID_MSG, $this->parent_tid, $currencies->format(($this->event_data['transaction']['refund']['amount']/100), 1, $this->event_data['transaction']['currency']));
+ if (!empty($this->event_data['transaction']['refund']['tid'])) {
+ $comments .= sprintf(MODULE_PAYMENT_NOVALNET_REFUND_CHILD_TID_MSG, $this->event_data['transaction']['refund']['tid']);
+ }
+ $refund_amount = $this->event_data['transaction']['refund']['amount'];
+ $refunded_amount = (isset($this->order_details['nn_trans_details']['refund_amount']) ? $this->order_details['nn_trans_details']['refund_amount'] : 0) + $refund_amount;
+ $novalnet_update_data = array(
+ 'refund_amount' => $refunded_amount,
+ 'status' => $this->event_data['transaction']['status'],
+ );
+ if (in_array($this->event_data['transaction']['refund']['payment_type'], array('INSTALMENT_INVOICE_BOOKBACK','INSTALMENT_SEPA_BOOKBACK'))) {
+ $instalment_details = (!empty($this->order_details['nn_trans_details']['instalment_cycle_details'])) ? json_decode($this->order_details['nn_trans_details']['instalment_cycle_details'], true) : [];
+ if (!empty($instalment_details)) {
+ foreach ($instalment_details as $cycle => $cycle_details) {
+ if (!empty($cycle_details['reference_tid']) && ($cycle_details['reference_tid'] == $this->event_data['transaction']['tid'])) {
+ $instalment_amount = (strpos((string)$instalment_details[$cycle]['instalment_cycle_amount'], '.')) ? $instalment_details[$cycle]['instalment_cycle_amount']*100 : $instalment_details[$cycle]['instalment_cycle_amount'];
+ $instalment_amount = $instalment_amount - $refund_amount;
+ $instalment_details[$cycle]['instalment_cycle_amount'] = $instalment_amount;
+ if ($instalment_details[$cycle]['instalment_cycle_amount'] <= 0) {
+ $instalment_details[$cycle]['status'] = 'Refunded';
+ }
+ }
+ }
+ }
+ $novalnet_update_data['instalment_cycle_details'] = (!empty($instalment_details) ? json_encode($instalment_details) : '{}');
+ }
+ if (isset($this->order_details['nn_trans_details']['amount']) && $refunded_amount >= $this->order_details['nn_trans_details']['amount']) {
+ $order_status_id = NovalnetHelper::getOrderStatusId();
+ }
+ $this->updateNovalnetTransaction($novalnet_update_data, "tid='{$this->parent_tid}'");
+ $this->updateOrderStatusHistory($this->order_details['shop_order_no'], $order_status_id, $comments);
+ $this->sendWebhookMail($comments);
+ $this->displayMessage(['message' => zen_db_prepare_input($comments . PHP_EOL)]);
+ }
+
+ /**
+ * Handle chargeback
+ *
+ */
+ private function handleTransactionCredit()
+ {
+ global $db, $currencies;
+ $update_comments = true;
+ $order_status = '';
+ $comments = PHP_EOL .sprintf(NOVALNET_WEBHOOK_CREDIT_NOTE, $this->parent_tid, $currencies->format(($this->event_data['transaction']['amount']/100), 1, $this->event_data['transaction']['currency']), gmdate('d-m-Y H:i:s'), $this->event_tid);
+ if (in_array($this->event_data['transaction']['payment_type'], ['INVOICE_CREDIT', 'CASHPAYMENT_CREDIT', 'MULTIBANCO_CREDIT'])) {
+ $paid_amount = (!empty($this->order_details['nn_trans_details']['refund_amount'])) ? ((int)$this->order_details['nn_trans_details']['refund_amount'] + (int)$this->order_details['nn_trans_details']['callback_amount']) : $this->order_details['nn_trans_details']['callback_amount'];
+ if ($paid_amount < $this->order_details['nn_trans_details']['amount']) {
+ $total_paid_amount = $paid_amount + $this->event_data['transaction']['amount'];
+ $update_data = array(
+ 'callback_amount' => $total_paid_amount
+ );
+
+ if ($total_paid_amount >= $this->order_details['nn_trans_details']['amount']) { // Full amount paid
+ $order_status = ($this->order_details['nn_trans_details']['payment_type'] == 'INVOICE') ? 3 : 2;
+ } else { // Partial paid
+ $order_status = ($this->order_details['nn_trans_details']['payment_type'] == 'INVOICE') ? 2 : 1;
+ }
+ $update_data['status'] = $this->event_data['transaction']['status'];
+ $this->updateNovalnetTransaction($update_data, "tid='{$this->parent_tid}'");
+ } else {
+ $update_comments = false;
+ $comments = sprintf(('Callback script executed already'), gmdate('d-m-Y'), gmdate('H:i:s'));
+ }
+ }
+ if ($update_comments) {
+ $this->updateOrderStatusHistory($this->order_details['shop_order_no'], $order_status, $comments);
+ $this->sendWebhookMail($comments);
+ }
+ $this->displayMessage(['message' => zen_db_prepare_input($comments . PHP_EOL)]);
+ }
+
+ /**
+ * Handle chargeback
+ *
+ */
+ private function handleChargeback()
+ {
+ global $currencies;
+ $comments = '';
+ if (($this->order_details['nn_trans_details']['status'] == 'CONFIRMED') && !empty($this->event_data ['transaction'] ['amount'])) {
+ $comments =sprintf(NOVALNET_WEBHOOK_CHARGEBACK_NOTE, $this->parent_tid, $currencies->format(($this->event_data['transaction']['amount']/100), 1, $this->event_data['transaction']['currency']), gmdate('d.m.Y'), gmdate('H:i:s'), $this->event_tid);
+ $this->updateOrderStatusHistory($this->event_data['transaction']['order_no'], '', $comments);
+ $this->sendWebhookMail($comments);
+ $this->displayMessage(['message' => zen_db_prepare_input($comments . PHP_EOL)]);
+ }
+ }
+
+ /**
+ * Handle instalment
+ *
+ */
+ private function handleInstalment()
+ {
+ global $currencies;
+ $comment = '';
+ if ($this->event_data['transaction']['status'] == 'CONFIRMED' && !empty($this->event_data['instalment']['cycles_executed'])) {
+ $instalment_details = (!empty($this->order_details['nn_trans_details']['instalment_cycle_details'])) ? json_decode($this->order_details['nn_trans_details']['instalment_cycle_details'], true) : [];
+ $instalment = $this->event_data['instalment'];
+ $cycle_index = $instalment['cycles_executed'] - 1;
+ if (!empty($instalment)) {
+ $instalment_details[$cycle_index]['next_instalment_date'] = (!empty($instalment['next_cycle_date'])) ? $instalment['next_cycle_date'] : '-';
+ if (!empty($this->event_data['transaction']['tid'])) {
+ $instalment_details[$cycle_index]['reference_tid'] = $this->event_data['transaction']['tid'];
+ $instalment_details[$cycle_index]['status'] = 'Paid';
+ $instalment_details[$cycle_index]['paid_date'] = date('Y-m-d H:i:s');
+ }
+ }
+ if (empty($this->event_data ['transaction']['bank_details'])) {
+ $this->event_data ['transaction']['bank_details'] = !empty($this->order_details['nn_trans_details']['payment_details']) ? json_decode($this->order_details['nn_trans_details']['payment_details'], true) : [];
+ }
+ $comment = sprintf(NOVALNET_WEBHOOK_NEW_INSTALMENT_NOTE, $this->parent_tid, $currencies->format(($this->event_data['instalment']['cycle_amount']/100), 1, $this->event_data['transaction']['currency']), gmdate('d-m-Y'), $this->event_tid);
+ $this->updateNovalnetTransaction(array('instalment_cycle_details' => json_encode($instalment_details)), "tid='{$this->parent_tid}'");
+ $comment .= PHP_EOL. NovalnetHelper::insertTransactionDetails($this->event_data, $this->order_details['shop_order_no']);
+ $this->updateOrderStatusHistory($this->event_data['transaction']['order_no'], '', $comment);
+ $this->sendWebhookMail($comment);
+ $this->displayMessage(['message' => zen_db_prepare_input($comment . PHP_EOL)]);
+ }
+ }
+
+ /**
+ * Handle instalment cancel
+ *
+ */
+ private function handleInstalmentCancel()
+ {
+ global $currencies;
+ $comments = '';
+ $novalnet_update_data = [];
+ if ($this->event_data['transaction']['status'] == 'CONFIRMED') {
+ $order_status = '';
+ $instalment_details = isset($this->order_details['nn_trans_details']['instalment_cycle_details']) ? json_decode($this->order_details['nn_trans_details']['instalment_cycle_details'], true) : [];
+ if (!empty($instalment_details)) {
+ $comments = sprintf(MODULE_PAYMENT_NOVALNET_INSTALMENT_CANCEL_ALLCYCLES_TEXT, $this->parent_tid, gmdate('d.m.Y'), $currencies->format(((isset($this->event_data['transaction']['refund']['amount']) ? $this->event_data['transaction']['refund']['amount']/100 : 0)), 1, ($this->event_data['transaction']['refund']['currency'])));
+ foreach ($instalment_details as $key => $instalment_details_data) {
+ if ($instalment_details_data['status'] == 'Pending') {
+ $instalment_details[$key]['status'] = 'Canceled';
+ }
+ if ($instalment_details_data['status'] == 'Paid') {
+ $instalment_details[$key]['status'] = 'Refunded';
+ }
+ }
+ if (isset($this->event_data['instalment']['cancel_type']) && $this->event_data['instalment']['cancel_type'] != 'ALL_CYCLES') {
+ $comments .= sprintf(MODULE_PAYMENT_NOVALNET_INSTALMENT_CANCEL_REMAINING_CYCLES_TEXT, $this->parent_tid, gmdate('d.m.Y'));
+ }
+ }
+ $novalnet_update_data = [
+ 'instalment_cycle_details' => !empty($instalment_details) ? json_encode($instalment_details) : '{}',
+ 'status' => 'DEACTIVATED',
+ ];
+ $this->updateNovalnetTransaction($novalnet_update_data, "tid='{$this->parent_tid}'");
+ $this->updateOrderStatusHistory($this->event_data['transaction']['order_no'], $order_status, $comments);
+ $this->sendWebhookMail($comments);
+ $this->displayMessage(['message' => zen_db_prepare_input($comments . PHP_EOL)]);
+ }
+ }
+
+ /**
+ * Handle transaction update
+ *
+ */
+ private function handleTransactionUpdate()
+ {
+ global $currencies;
+ $transaction_comments = '';
+ $order_status = '';
+ $novalnet_update_data = [
+ 'status' => $this->event_data ['transaction']['status'],
+ ];
+ $amount = (!empty($this->event_data['instalment']['cycle_amount'])) ? $this->event_data['instalment']['cycle_amount'] : $this->event_data['transaction']['amount'];
+ if ($this->event_data['transaction']['update_type'] == 'STATUS') {
+ if ($this->event_data['transaction']['status'] == 'DEACTIVATED') {
+ $transaction_comments = sprintf(MODULE_PAYMENT_NOVALNET_TRANS_DEACTIVATED_MESSAGE, gmdate('d.m.Y'), gmdate('H:i:s'));
+ $order_status = NovalnetHelper::getOrderStatusId();
+ } else if (in_array($this->order_details['nn_trans_details']['status'], array('PENDING', 'ON_HOLD'), true)) {
+ if ($this->event_data['transaction']['status'] == 'ON_HOLD') {
+ $order_status = 99;
+ $transaction_comments = sprintf(NOVALNET_PAYMENT_STATUS_PENDING_TO_ONHOLD_TEXT, $this->event_tid, gmdate('d.m.Y'), gmdate('H:i:s'));
+ } elseif ($this->event_data['transaction']['status'] == 'CONFIRMED') {
+ $order_status = 2;
+ if (!empty($this->event_data['transaction']['bank_details']) || !empty($this->event_data['instalment'])) {
+ if (!empty($this->event_data['transaction']['due_date'])) {
+ $transaction_comments = PHP_EOL.sprintf(NOVALNET_WEBHOOK_TRANSACTION_UPDATE_NOTE_DUE_DATE, $this->event_data['transaction']['tid'], $currencies->format(($this->event_data['transaction']['amount']/100), 1, $this->event_data['transaction']['currency']), $this->event_data['transaction']['due_date']).PHP_EOL.PHP_EOL;
+ } else {
+ $transaction_comments = PHP_EOL.sprintf(NOVALNET_WEBHOOK_TRANSACTION_UPDATE_NOTE, $this->event_data['transaction']['tid'], $currencies->format(($amount/100), 1, $this->event_data['transaction']['currency']), gmdate('d.m.Y')).PHP_EOL.PHP_EOL;
+ }
+ if (empty($this->order_details['nn_trans_details']['instalment_cycle_details'])) {
+ $total_amount = ($this->order_details['nn_trans_details']['amount'] < $this->event_data['transaction']['amount']) ? $this->event_data['transaction']['amount'] : $this->order_details['nn_trans_details']['amount'];
+ $novalnet_update_data['instalment_cycle_details'] = NovalnetHelper::storeInstalmentdetails($this->event_data, $total_amount);
+ }
+ } else {
+ $transaction_comments = PHP_EOL.sprintf(NOVALNET_WEBHOOK_TRANSACTION_UPDATE_NOTE, $this->event_data['transaction']['tid'], $currencies->format(($amount/100), 1, $this->event_data['transaction']['currency']), gmdate('d.m.Y')).PHP_EOL.PHP_EOL;
+ }
+ $novalnet_update_data['callback_amount'] = $this->order_details['nn_trans_details']['amount'];
+ }
+ }
+ } else if ($this->event_data['transaction']['update_type'] == 'AMOUNT') {
+ $transaction_comments = PHP_EOL.sprintf(MODULE_PAYMENT_NOVALNET_AMOUNT_UPDATE_NOTE, $currencies->format(($amount/100), 1, $this->event_data['transaction']['currency']), gmdate('d.m.Y')).PHP_EOL.PHP_EOL;
+ } elseif ($this->event_data['transaction']['update_type'] == 'DUE_DATE') {
+ $transaction_comments = PHP_EOL.sprintf(MODULE_PAYMENT_NOVALNET_DUEDATE_UPDATE_NOTE, $this->event_data['transaction']['due_date'], gmdate('d.m.Y')).PHP_EOL.PHP_EOL;
+ } elseif ($this->event_data['transaction']['update_type'] == 'AMOUNT_DUE_DATE') {
+ $transaction_comments = PHP_EOL.sprintf(MODULE_PAYMENT_NOVALNET_AMOUNT_DUEDATE_UPDATE_NOTE, $currencies->format(($amount/100), 1, $this->event_data['transaction']['currency']), $this->event_data['transaction']['due_date'], gmdate('d.m.Y')).PHP_EOL.PHP_EOL;
+ }
+
+ // Reform the transaction comments.
+ $transaction_comments .= NovalnetHelper::getTransactionDetails($this->event_data);
+ $this->event_data['transaction']['bank_details'] = empty($this->event_data['transaction']['bank_details']) ? (!empty($this->order_details['nn_trans_details']['payment_details']) ? json_decode($this->order_details['nn_trans_details']['payment_details'], true) : []) : $this->event_data['transaction']['bank_details'];
+ if (($this->event_data['transaction']['status'] != 'DEACTIVATED') && !empty($this->event_data['transaction']['bank_details'])) {
+ $transaction_comments .= NovalnetHelper::getBankDetails($this->event_data);
+ }
+ if ($this->event_data['transaction']['payment_type'] === 'CASHPAYMENT') {
+ $nn_barzahlen_stores = json_decode($this->order_details['nn_trans_details']['payment_details'], true);
+ $this->event_data['transaction']['nearest_stores'] = !empty($nn_barzahlen_stores) ? $nn_barzahlen_stores['nearest_stores'] : [];
+ $transaction_comments .= NovalnetHelper::getNearestStoreDetails($this->event_data);
+ }
+ if (!empty($this->event_data['instalment'])) {
+ $transaction_comments .= NovalnetHelper::getInstalmentDetails($this->event_data);
+ } else {
+ if ((int)$this->event_data['transaction']['amount'] != (int)$this->order_details['nn_trans_details']['amount']) {
+ $novalnet_update_data['amount'] = $this->event_data['transaction']['amount'];
+ if ($this->event_data['transaction']['status'] === 'CONFIRMED') {
+ $novalnet_update_data['callback_amount'] = $this->event_data['transaction']['amount'];
+ }
+ }
+ }
+ if (in_array($this->event_data['transaction']['payment_type'], array('INSTALMENT_INVOICE','GUARANTEED_INVOICE')) && in_array($this->event_data['transaction']['status'], array('CONFIRMED', 'ON_HOLD'))) {
+ NovalnetHelper::sendPaymentConfirmationMail($transaction_comments, $this->event_data['transaction']['order_no']);
+ }
+ $this->updateNovalnetTransaction($novalnet_update_data, "tid='{$this->parent_tid}'");
+ $this->updateOrderStatusHistory($this->order_details['shop_order_no'], $order_status, $transaction_comments);
+ $this->sendWebhookMail($transaction_comments);
+ $this->displayMessage(['message' => zen_db_prepare_input($transaction_comments . PHP_EOL)]);
+ }
+
+ /**
+ * Handle Payment Reminder
+ *
+ */
+ private function handlePaymentReminder()
+ {
+ $comments =sprintf(NOVALNET_PAYMENT_REMINDER_NOTE, explode('_', $this->event_type)[2]);
+ $this->updateOrderStatusHistory($this->event_data['transaction']['order_no'], '', $comments);
+ $this->sendWebhookMail($comments);
+ $this->displayMessage([ 'message' => zen_db_prepare_input($comments . PHP_EOL)]);
+ }
+
+ /**
+ * Handle Collection Agency Submission
+ *
+ */
+ private function handleCollectionSubmission()
+ {
+ $comments =sprintf(NOVALNET_COLLECTION_SUBMISSION_NOTE, $this->event_data['collection']['reference']);
+ $this->updateOrderStatusHistory($this->event_data['transaction']['order_no'], '', $comments);
+ $this->sendWebhookMail($comments);
+ $this->displayMessage([ 'message' => zen_db_prepare_input($comments . PHP_EOL)]);
+ }
+
+ /**
+ * Print the Webhook messages.
+ *
+ * @param $message
+ *
+ * @return void
+ */
+ private function displayMessage($message)
+ {
+ echo json_encode($message);
+ exit;
+ }
+
+ /**
+ * Update the details in Shop order status table.
+ *
+ * @param $order_no
+ * @param $order_status_id
+ * @param $comments
+ */
+ private function updateOrderStatusHistory($order_no, $order_status_id = '', $comments = '')
+ {
+ global $db;
+ if ($order_status_id == '') {
+ $current_order_status = $db->Execute("SELECT orders_status FROM " . TABLE_ORDERS . " WHERE orders_id = " . $order_no);
+ $order_status_id = $current_order_status->fields['orders_status'];
+ }
+ $datas_need_to_update['orders_status'] = $order_status_id;
+ // Update order status id in orders table
+ zen_db_perform(TABLE_ORDERS, $datas_need_to_update, "update", "orders_id = '$order_no'");
+ $data_array = array(
+ 'orders_id' => $order_no,
+ 'orders_status_id' => $order_status_id,
+ 'date_added' => date('Y-m-d H:i:s'),
+ 'customer_notified' => 1,
+ 'comments' => zen_db_prepare_input($comments . PHP_EOL)
+ );
+ // Update order details in history table
+ zen_db_perform(TABLE_ORDERS_STATUS_HISTORY, $data_array, 'insert');
+ }
+
+ /*
+ * Update the transaction details in Novalnet table
+ *
+ * @param $data
+ * @param $parameters
+ */
+ private function updateNovalnetTransaction($data, $parameters = '')
+ {
+ if ($parameters == '') {
+ return false;
+ }
+ zen_db_perform(TABLE_NOVALNET_TRANSACTION_DETAIL, $data, 'update', $parameters);
+ }
+
+ /**
+ * Send notification mail to Merchant
+ *
+ * @param $comments
+ */
+ private function sendWebhookMail($comments)
+ {
+ $email = NovalnetHelper::validateEmail(MODULE_PAYMENT_NOVALNET_CALLBACK_MAIL_TO);
+ // Assign email to address
+ $email_to = !empty($email) ? $email : STORE_OWNER_EMAIL_ADDRESS;
+ $order_subject = 'Novalnet Callback Script Access Report - '.STORE_NAME;
+ // Send mail
+ zen_mail($email, $email_to, $order_subject, $comments, STORE_NAME, EMAIL_FROM);
+ }
+
+ /**
+ * Include language file and helper file.
+ */
+ private function includeRequiredFiles($lang)
+ {
+ // include language
+ include_once(DIR_FS_CATALOG . DIR_WS_LANGUAGES. $lang."/modules/payment/novalnet_payments.php");
+
+ // include helper file after language files.
+ require_once(DIR_FS_CATALOG . DIR_WS_MODULES. 'payment/novalnet/NovalnetHelper.php');
+ return;
+ }
+
+ /**
+ * Send critical mail
+ *
+ * @return none
+ */
+ private function sentCriticalMail($data)
+ {
+ $subject = 'Critical error on shop system '.STORE_NAME.': order not found for TID: ' . $data['event']['tid'];
+ $customer_name = $data['customer']['first_name'] . $data['customer']['last_name'];
+ $message = "Dear Store Owner,".PHP_EOL."Please evaluate this transaction and contact our payment module team at Novalnet." .PHP_EOL. PHP_EOL;
+ $message .= 'Merchant ID: ' . $data['merchant']['vendor'] . PHP_EOL;
+ $message .= 'Project ID: ' . $data['merchant']['project'] . PHP_EOL;
+ $message .= 'TID: ' . $data['event']['tid'] . PHP_EOL;
+ $message .= 'TID status: ' . $data['transaction']['status'] . PHP_EOL;
+ $message .= 'Payment type: ' . $data['transaction']['payment_type'] . PHP_EOL;
+ $message .= 'E-mail: ' . $data['customer']['email'] . PHP_EOL;
+
+ $message .= PHP_EOL. PHP_EOL. 'Regards,'.PHP_EOL.'Novalnet Team';
+ zen_mail($customer_name, STORE_OWNER_EMAIL_ADDRESS, $subject, str_replace('', PHP_EOL, $message), '', '', array(), '', '', STORE_NAME, $data['customer']['email']);
+ }
+}
+new NovalnetWebhooks();
diff --git a/includes/extra_datafiles/novalnet.php b/includes/extra_datafiles/novalnet.php
new file mode 100755
index 0000000..d04f859
--- /dev/null
+++ b/includes/extra_datafiles/novalnet.php
@@ -0,0 +1,15 @@
+Please read the Installation Guide before you start and login to the Novalnet Admin Portal using your merchant account. To get a merchant account, mail to sales@novalnet.de or call +49 (089) 923068320
Payment plugin configurations are now available in the Novalnet Admin Portal.Navigate to the Account -> Payment plugin configuration of your projects to configure them.
Our platform offers a test mode for all requests; You can control the behaviour of the payment methods by using the Novalnet test payment data');
+define('MODULE_PAYMENT_NOVALNET_AMOUNT_TRANSFER_NOTE_DUE_DATE', 'Please transfer the amount of %1$s to the following account on or before %2$s');
+define('MODULE_PAYMENT_NOVALNET_AMOUNT_TRANSFER_NOTE', 'Please transfer the amount of %s to the following account.');
+define('MODULE_PAYMENT_NOVALNET_INSTALMENT_AMOUNT_TRANSFER_NOTE_DUE_DATE', 'Please transfer the instalment cycle amount of %1$s to the following account on or before %2$s');
+define('MODULE_PAYMENT_NOVALNET_INSTALMENT_AMOUNT_TRANSFER_NOTE', 'Please transfer the instalment cycle amount of %1$s to the following account.');
+define('MODULE_PAYMENT_NOVALNET_MULTIBANCO_NOTE', 'Please use the following payment reference details to pay the amount of %s at a Multibanco ATM or through your internet banking.');
+define('MODULE_PAYMENT_NOVALNET_BANK_NAME', ' Bank: ');
+define('MODULE_PAYMENT_NOVALNET_IBAN', 'IBAN: ');
+define('MODULE_PAYMENT_NOVALNET_BIC', ' BIC: ');
+define('MODULE_PAYMENT_NOVALNET_ACCOUNT_HOLDER', 'Account holder: ');
+define('MODULE_PAYMENT_NOVALNET_AMOUNT', ' Amount: ');
+define('MODULE_PAYMENT_NOVALNET_PAYMENT_MODE', 'Test order');
+define('MODULE_PAYMENT_NOVALNET_BANK_PLACE', 'Place: ');
+define('MODULE_PAYMENT_NOVALNET_TRANSACTION_ID', 'Novalnet transaction ID: ');
+define('MODULE_PAYMENT_NOVALNET_TRANS_SLIP_EXPIRY_DATE', 'Slip expiry date : ');
+define('MODULE_PAYMENT_NOVALNET_NEAREST_STORE_DETAILS', 'Store(s) near to you: ');
+define('MODULE_PAYMENT_NOVALNET_PAYMENT_REFERENCE_TEXT', 'Please use any of the following payment references when transferring the amount. This is necessary to match it with your corresponding order');
+define('MODULE_PAYMENT_NOVALNET_CONFIRM_TEXT', 'Confirm');
+define('MODULE_PAYMENT_NOVALNET_REFUND_TEXT', 'Refund');
+define('MODULE_PAYMENT_NOVALNET_CANCEL_TEXT', 'Cancel');
+define('MODULE_PAYMENT_NOVALNET_TRANSACTION_ERROR', 'Payment was not successful. An error occured.');
+define('MODULE_PAYMENT_NOVALNET_SELECT_STATUS_OPTION', '--Select--');
+define('MODULE_PAYMENT_NOVALNET_TRANS_CONFIRM_SUCCESSFUL_MESSAGE', 'The transaction has been confirmed successfully for the TID %1$s and the due date updated as %2$s');
+define('MODULE_PAYMENT_NOVALNET_TRANS_CONFIRM_SUCCESSFUL_MESSAGE_TEXT', 'The transaction has been confirmed on %1$s');
+define('MODULE_PAYMENT_NOVALNET_TRANS_DEACTIVATED_MESSAGE', 'The transaction has been cancelled on %1$s');
+define('MODULE_PAYMENT_NOVALNET_INSTALMENT_CANCELED_MESSAGE', 'The transaction has been cancelled for the %1$s on %2$s %3$s');
+define('MODULE_PAYMENT_NOVALNET_AMOUNT_EX', ' (in minimum unit of currency. E.g. enter 100 which is equal to 1.00)');
+define('MODULE_PAYMENT_NOVALNET_REFUND_PARENT_TID_MSG', 'Refund has been initiated for the TID: %1$s with the amount of %2$s.');
+define('MODULE_PAYMENT_NOVALNET_REFUND_CHILD_TID_MSG', 'New TID:%s for the refunded amount');
+define('MODULE_PAYMENT_NOVALNET_INSTALMENT_SUMMARY_BACKEND', 'Instalment summary');
+define('MODULE_PAYMENT_NOVALNET_INSTALMENT_CANCEL_ADMIN_TEXT', 'Instalment cancel');
+define('MODULE_PAYMENT_NOVALNET_INSTALMENT_AMOUNT_BACKEND', 'Amount');
+define('MODULE_PAYMENT_NOVALNET_INSTALMENT_DATE_BACKEND', 'Date');
+define('MODULE_PAYMENT_NOVALNET_INSTALMENT_STATUS_BACKEND', 'Status');
+define('MODULE_PAYMENT_NOVALNET_INSTALMENT_REFERENCE_BACKEND', 'Novalnet Transaction ID');
+define('MODULE_PAYMENT_NOVALNET_INSTALMENT_CANCEL_TEXT', 'Cancel');
+define('MODULE_PAYMENT_NOVALNET_MENTION_GUARANTEE_PAYMENT_PENDING_TEXT', 'Your order is under verification and we will soon update you with the order status. Please note that this may take upto 24 hours.');
+define('MODULE_PAYMENT_NOVALNET_PAYMENT_REFERENCE', 'Payment Reference : %1$s');
+define('NOVALNET_WEBHOOK_CREDIT_NOTE', 'Credit has been successfully received for the TID: %1$s with amount %2$s on %3$s. Please refer PAID order details in our Novalnet Admin Portal for the TID: %4$s');
+define('NOVALNET_WEBHOOK_CHARGEBACK_NOTE', 'Chargeback executed successfully for the TID: %1$s amount: %2$s on %3$s %4$s . The subsequent TID: %5$s');
+define('NOVALNET_WEBHOOK_NEW_INSTALMENT_NOTE', 'A new instalment has been received for the Transaction ID: %1$s with amount %2$s on %3$s. The new instalment transaction ID is: %4$s');
+define('NOVALNET_WEBHOOK_INSTALMENT_CANCEL_NOTE', 'Instalment has been cancelled for the TID: %1$s on %2$s');
+define('NOVALNET_WEBHOOK_TRANSACTION_UPDATE_NOTE_DUE_DATE', 'Transaction updated successfully for the TID: %1$s with amount %2$s and the due date updated as %3$s.');
+define('NOVALNET_WEBHOOK_TRANSACTION_UPDATE_NOTE', 'Transaction updated successfully for the TID: %1$s with amount %2$s on %3$s');
+define('NOVALNET_PAYMENT_REMINDER_NOTE', 'Payment Reminder %1$s has been sent to the customer.');
+define('NOVALNET_COLLECTION_SUBMISSION_NOTE', 'The transaction has been submitted to the collection agency. Collection Reference: %1$s');
+define('NOVALNET_PAYMENT_STATUS_PENDING_TO_ONHOLD_TEXT', 'The transaction status has been changed from pending to on-hold for the TID: %1$s on %2$s');
+define('MODULE_PAYMENT_NOVALNET_PARTNER_PAYMENT_REFERENCE', 'Partner Payment Reference: %s');
+define('MODULE_PAYMENT_NOVALNET_ERROR_MSG', 'Check hash failed');
+define('MODULE_PAYMENT_NOVALNET_TRANS_CONFIRM_TITLE', 'Manage Transaction');
+define('MODULE_PAYMENT_NOVALNET_PAYMENT_CAPTURE_CONFIRM', 'Are you sure you want to capture the payment?');
+define('MODULE_PAYMENT_NOVALNET_PAYMENT_VOID_CONFIRM', 'Are you sure you want to cancel the payment?');
+define('MODULE_PAYMENT_NOVALNET_SELECT_STATUS_TEXT', 'Please select status');
+define('MODULE_PAYMENT_NOVALNET_BACK_TEXT', 'Back');
+define('MODULE_PAYMENT_NOVALNET_REFUND_TITLE', 'Refund process');
+define('MODULE_PAYMENT_NOVALNET_PAYMENT_REFUND_CONFIRM', 'Are you sure you want to refund the amount');
+define('MODULE_PAYMENT_NOVALNET_REFUND_REFERENCE_TEXT', 'Refund reference');
+define('MODULE_PAYMENT_NOVALNET_REFUND_AMT_TITLE', 'Please enter the refund amound');
+define('MODULE_PAYMENT_NOVALNET_REFUND_REASON_TITLE', 'Reason for refund (optional)');
+define('MODULE_PAYMENT_NOVALNET_INSTALMENT_INSTALMENTS_INFO', 'Instalment information');
+define('MODULE_PAYMENT_NOVALNET_INSTALMENT_PROCESSED_INSTALMENTS', 'Processed instalments: ');
+define('MODULE_PAYMENT_NOVALNET_INSTALMENT_DUE_INSTALMENTS', 'Due instalments: ');
+define('MODULE_PAYMENT_NOVALNET_INSTALMENT_NEXT_INSTALMENT_AMOUNT', 'Next instalment amount: ');
+define('MODULE_PAYMENT_NOVALNET_INSTALMENT_NEXT_INSTALMENT_DATE', 'Next instalment date: ');
+define('MODULE_PAYMENT_NOVALNET_INSTALMENT_PAY_DATE_BACKEND', 'Paid date');
+define('MODULE_PAYMENT_NOVALNET_INSTALMENT_NEXT_DATE_BACKEND', 'Instalment date');
+define('MODULE_PAYMENT_NOVALNET_INSTALMENT_PAID_DATE_BACKEND', 'Paid on');
+define('MODULE_PAYMENT_NOVALNET_INSTALMENT_STATUS_PAID', 'Paid');
+define('MODULE_PAYMENT_NOVALNET_INSTALMENT_STATUS_PENDING', 'Pending');
+define('MODULE_PAYMENT_NOVALNET_INSTALMENT_STATUS_REFUNDED', 'Refunded');
+define('MODULE_PAYMENT_NOVALNET_INSTALMENT_STATUS_CANCELED', 'Canceled');
+define('MODULE_PAYMENT_NOVALNET_BOOK_TITLE', 'Book transaction');
+define('MODULE_PAYMENT_NOVALNET_BOOK_AMT_TITLE', 'Transaction booking amount');
+define('MODULE_PAYMENT_NOVALNET_TRANS_BOOKED_MESSAGE', 'Your order has been booked with the amount of %s. Your new TID for the booked amount: %s');
+define('MODULE_PAYMENT_NOVALNET_PAYMENT_ZERO_AMOUNT_BOOK_CONFIRM', 'Are you sure you want to book the order amount?');
+define('MODULE_PAYMENT_NOVALNET_AMOUNT_ERROR_MESSAGE', 'The amount is invalid');
+define('MODULE_PAYMENT_NOVALNET_ZEROAMOUNT_BOOKING_MESSAGE', 'This order processed as a zero amount booking');
+define('MODULE_PAYMENT_NOVALNET_ZEROAMOUNT_BOOKING_TEXT', '
This order will be processed as zero amount booking which store your payment data for further online purchases.');
+define('MODULE_PAYMENT_NOVALNET_INSTALMENT_CANCEL_ALLCYCLES', 'Cancel All Instalment');
+define('MODULE_PAYMENT_NOVALNET_INSTALMENT_CANCEL_ALLCYCLES_TEXT', 'Instalment has been cancelled for the TID: %1$s on %2$s & Refund has been initiated with the amount %3$s');
+define('MODULE_PAYMENT_NOVALNET_INSTALMENT_CANCEL_REMAINING_CYCLES', 'Cancel All Remaining Instalments');
+define('MODULE_PAYMENT_NOVALNET_INSTALMENT_CANCEL_REMAINING_CYCLES_TEXT', 'Instalment has been stopped for the TID: %1$s on %2$s');
+define('MODULE_PAYMENT_NOVALNET_ALLCYCLES_ERROR_MESSAGE', 'Are you sure you want to cancel all cycles?');
+define('MODULE_PAYMENT_NOVALNET_REMAINING_CYCLES_ERROR_MESSAGE', 'Are you sure you want to cancel remaining cycles?');
+define('MODULE_PAYMENT_NOVALNET_WALLET_PAYMENT_SUCCESS_TEXT', 'Your order was successfully processed using Google Pay (Visa **** %s)');
+define('MODULE_PAYMENT_NOVALNET_ONHOLD_EN_ORDER_STATUS', 'Payment authorized (Novalnet)');
+define('MODULE_PAYMENT_NOVALNET_CANCELED_EN_ORDER_STATUS', 'Canceled (Novalnet)');
+define('MODULE_PAYMENT_NOVALNET_ORDER_MAIL_SUBJECT', 'Order Confirmation - Your Order number %1$s with %2$s has been confirmed!');
+define('MODULE_PAYMENT_NOVALNET_ORDER_MAIL_MESSAGE', 'Order Confirmation from %s');
+define('MODULE_PAYMENT_NOVALNET_ORDER_MAIL_DATE', 'Date Ordered: %s');
+define('MODULE_PAYMENT_NOVALNET_ORDER_NUMBER', 'Order number: %s');
+define('MODULE_PAYMENT_NOVALNET_DELIVERY_ADDRESS', 'Delivery address');
+define('MODULE_PAYMENT_NOVALNET_BILLING_ADDRESS', 'Billing address');
+define('MODULE_PAYMENT_NOVALNET_ORDER_CONFIRMATION', 'Payment confirmation:');
+define('MODULE_PAYMENT_NOVALNET_CUSTOMER_SALUTATION', 'Dear Mr/Ms ');
+define('MODULE_PAYMENT_NOVALNET_INCL_TAX_LABEL', 'Incl.Tax');
+define('MODULE_PAYMENT_NOVALNET_EXCL_TAX_LABEL', 'Excl.Tax');
+define('MODULE_PAYMENT_NOVALNET_DISCOUNT_AND_GIFT_VOUCHER_LABEL', 'Discount');
+define('MODULE_PAYMENT_NOVALNET_SHIPPING_LABEL', 'Shipping');
+define('MODULE_PAYMENT_NOVALNET_AMOUNT_UPDATE_NOTE', 'Transaction amount %1$s has been updated successfully on %2$s');
+define('MODULE_PAYMENT_NOVALNET_DUEDATE_UPDATE_NOTE', 'Transaction due date %1$s has been updated successfully on %2$s');
+define('MODULE_PAYMENT_NOVALNET_AMOUNT_DUEDATE_UPDATE_NOTE', 'Transaction amount %1$s and due date %2$s has been updated successfully on %3$s');
+define('MODULE_PAYMENT_NOVALNET_BARZAHLEN_SUCCESS_BUTTON', 'Pay now with Barzahlen');
+define('MODULE_PAYMENT_NOVALNET_WALLET_TOTAL_LABEL', 'Estimated total (No offers applied)');
diff --git a/includes/languages/german/modules/payment/novalnet_payments.php b/includes/languages/german/modules/payment/novalnet_payments.php
new file mode 100755
index 0000000..53851be
--- /dev/null
+++ b/includes/languages/german/modules/payment/novalnet_payments.php
@@ -0,0 +1,124 @@
+Bevor Sie beginnen, lesen Sie bitte die Installationsanleitung und melden Sie sich mit Ihrem Händlerkonto im Novalnet Admin-Portal an. Um ein Händlerkonto zu erhalten, senden Sie bitte eine E-Mail an sales@novalnet.de oder rufen Sie uns unter +49 89 923068320 an
Die Konfigurationen der Zahlungsplugins sind jetzt im Novalnet Admin-Portal verfügbar. Navigieren Sie zu Konto -> Konfiguration des Shops Ihrer Projekte, um sie zu konfigurieren.
Novalnet ermöglicht es Ihnen, das Verhalten der Zahlungsmethode zu überprüfen, bevor Sie in den Produktionsmodus gehen, indem Sie Testzahlungsdaten verwenden. Zugang zu den Novalnet-Testzahlungsdaten finden Sie hier ');
+define('MODULE_PAYMENT_NOVALNET_AMOUNT_TRANSFER_NOTE', 'Bitte überweisen Sie den Betrag %s auf das folgende Konto.');
+define('MODULE_PAYMENT_NOVALNET_INSTALMENT_AMOUNT_TRANSFER_NOTE_DUE_DATE', 'Bitte überweisen Sie den anzahl der raten von %1$s spätestens bis zum %2$s auf das folgende Konto');
+define('MODULE_PAYMENT_NOVALNET_INSTALMENT_AMOUNT_TRANSFER_NOTE', 'Bitte überweisen Sie den anzahl der raten %1$s auf das folgende Konto.');
+define('MODULE_PAYMENT_NOVALNET_MULTIBANCO_NOTE', 'Bitte verwenden Sie die folgende Zahlungsreferenz, um den Betrag von %s an einem Multibanco-Geldautomaten oder über Ihr Onlinebanking zu bezahlen.');
+define('MODULE_PAYMENT_NOVALNET_AMOUNT_TRANSFER_NOTE_DUE_DATE', 'Bitte überweisen Sie den Betrag von %1$s spätestens bis zum %2$s auf das folgende Konto');
+define('MODULE_PAYMENT_NOVALNET_BANK_NAME', 'Bank: ');
+define('MODULE_PAYMENT_NOVALNET_IBAN', 'IBAN: ');
+define('MODULE_PAYMENT_NOVALNET_BIC', ' BIC: ');
+define('MODULE_PAYMENT_NOVALNET_ACCOUNT_HOLDER', 'Kontoinhaber: ');
+define('MODULE_PAYMENT_NOVALNET_AMOUNT', ' Betrag: ');
+define('MODULE_PAYMENT_NOVALNET_PAYMENT_MODE', 'Testbestellung');
+define('MODULE_PAYMENT_NOVALNET_BANK_PLACE', 'Ort: ');
+define('MODULE_PAYMENT_NOVALNET_TRANSACTION_ID', 'Novalnet-Transaktions-ID: ');
+define('MODULE_PAYMENT_NOVALNET_TRANS_SLIP_EXPIRY_DATE', 'Verfallsdatum des Zahlscheins: ');
+define('MODULE_PAYMENT_NOVALNET_NEAREST_STORE_DETAILS', 'Barzahlen-Partnerfilialen in Ihrer Nähe: ');
+define('MODULE_PAYMENT_NOVALNET_PAYMENT_REFERENCE_TEXT', 'Bitte verwenden Sie einen der unten angegebenen Verwendungszwecke für die Überweisung. Nur so kann Ihr Geldeingang Ihrer Bestellung zugeordnet werden');
+define('MODULE_PAYMENT_NOVALNET_CONFIRM_TEXT', 'Bestätigen');
+define('MODULE_PAYMENT_NOVALNET_REFUND_TEXT', 'Rückerstattung');
+define('MODULE_PAYMENT_NOVALNET_CANCEL_TEXT', 'Stornieren');
+define('MODULE_PAYMENT_NOVALNET_TRANSACTION_ERROR', 'Die Zahlung war nicht erfolgreich. Ein Fehler ist aufgetreten.');
+define('MODULE_PAYMENT_NOVALNET_SELECT_STATUS_OPTION', '--Auswählen--');
+define('MODULE_PAYMENT_NOVALNET_TRANS_CONFIRM_SUCCESSFUL_MESSAGE', 'Die Buchung wurde am %1$s Uhr bestätigt');
+define('MODULE_PAYMENT_NOVALNET_TRANS_CONFIRM_SUCCESSFUL_MESSAGE_TEXT', 'Die Buchung wurde am %1$s');
+define('MODULE_PAYMENT_NOVALNET_TRANS_DEACTIVATED_MESSAGE', 'Die Transaktion wurde am %1$s Uhr storniert');
+define('MODULE_PAYMENT_NOVALNET_INSTALMENT_CANCELED_MESSAGE', 'Die Transaktion wurde storniert für die %1$s auf %2$s %3$s');
+define('MODULE_PAYMENT_NOVALNET_AMOUNT_EX', ' (in der kleinsten Währungseinheit, z.B. 100 Cent = entsprechen 1.00 EUR)');
+define('MODULE_PAYMENT_NOVALNET_REFUND_PARENT_TID_MSG', 'Die Rückerstattung für die TID: %1$s mit dem Betrag %2$s wurde veranlasst.');
+define('MODULE_PAYMENT_NOVALNET_REFUND_CHILD_TID_MSG', ' Die neue TID: %s für den erstatteten Betrag');
+define('MODULE_PAYMENT_NOVALNET_INSTALMENT_SUMMARY_BACKEND', 'Zusammenfassung der Ratenzahlung');
+define('MODULE_PAYMENT_NOVALNET_INSTALMENT_CANCEL_ADMIN_TEXT', 'Ratenzahlung Stornieren');
+define('MODULE_PAYMENT_NOVALNET_INSTALMENT_AMOUNT_BACKEND', 'Betrag');
+define('MODULE_PAYMENT_NOVALNET_INSTALMENT_DATE_BACKEND', 'Datum');
+define('MODULE_PAYMENT_NOVALNET_INSTALMENT_STATUS_BACKEND', 'Status');
+define('MODULE_PAYMENT_NOVALNET_INSTALMENT_REFERENCE_BACKEND', 'Novalnet-Transaktions-ID');
+define('MODULE_PAYMENT_NOVALNET_INSTALMENT_CANCEL_TEXT', 'Stornieren');
+define('MODULE_PAYMENT_NOVALNET_MENTION_GUARANTEE_PAYMENT_PENDING_TEXT', 'Ihre Bestellung wird derzeit überprüft. Wir werden Sie in Kürze über den Bestellstatus informieren. Bitte beachten Sie, dass dies bis zu 24 Stunden dauern kann.');
+define('MODULE_PAYMENT_NOVALNET_PAYMENT_REFERENCE', 'Verwendungszweck : %1$s');
+define('NOVALNET_WEBHOOK_CREDIT_NOTE', 'Die Gutschrift für die TID ist erfolgreich eingegangen: %1$s mit Betrag %2$s am %3$s. Bitte entnehmen Sie die TID den Einzelheiten der Bestellung bei BEZAHLT in unserem Novalnet Adminportal: %4$s');
+define('NOVALNET_WEBHOOK_CHARGEBACK_NOTE', 'Chargeback erfolgreich importiert für die TID: %1$s Betrag: %2$s am %3$s um %4$s Uhr. TID der Folgebuchung: %5$s');
+define('NOVALNET_WEBHOOK_NEW_INSTALMENT_NOTE', 'Für die Transaktions-ID ist eine neue Rate eingegangen: %1$s mit Betrag %2$s am %3$s. Die Transaktions-ID der neuen Rate lautet: %4$s');
+define('NOVALNET_WEBHOOK_INSTALMENT_CANCEL_NOTE', 'Die Ratenzahlung für die TID wurde gekündigt: %1$s am %2$s');
+define('NOVALNET_PAYMENT_STATUS_PENDING_TO_ONHOLD_TEXT', 'Der Status der Transaktion mit der TID: %1$s wurde am %2$s um von ausstehend auf ausgesetzt geändert ');
+define('NOVALNET_WEBHOOK_TRANSACTION_UPDATE_NOTE_DUE_DATE', 'Transaktion mit TID %1$s und Betrag %2$s wurde am %3$s um erfolgreich aktualisiert ');
+define('NOVALNET_WEBHOOK_TRANSACTION_UPDATE_NOTE', 'Transaktion mit TID %1$s und Betrag %2$s wurde am um erfolgreich.');
+define('NOVALNET_PAYMENT_REMINDER_NOTE', 'Zahlungserinnerung %1$s wurde an den Kunden gesendet.');
+define('NOVALNET_COLLECTION_SUBMISSION_NOTE', 'Die Transaktion wurde an das Inkassobüro übergeben. Inkasso-Referenz: %1$s');
+define('MODULE_PAYMENT_NOVALNET_PARTNER_PAYMENT_REFERENCE', 'Partner-Zahlungsreferenz: %s');
+define('MODULE_PAYMENT_NOVALNET_ERROR_MSG', 'Prüfung des Hashes fehlgeschlagen');
+define('MODULE_PAYMENT_NOVALNET_TRANS_CONFIRM_TITLE', 'Transaktion verwalten');
+define('MODULE_PAYMENT_NOVALNET_PAYMENT_CAPTURE_CONFIRM', 'Sind Sie sicher, dass Sie die Zahlung erfassen wollen?');
+define('MODULE_PAYMENT_NOVALNET_PAYMENT_VOID_CONFIRM', 'Sind Sie sicher, dass Sie die Zahlung stornieren möchten?');
+define('MODULE_PAYMENT_NOVALNET_SELECT_STATUS_TEXT', 'Bitte Status auswählen');
+define('MODULE_PAYMENT_NOVALNET_BACK_TEXT', 'Zurück');
+define('MODULE_PAYMENT_NOVALNET_REFUND_TITLE', 'Erstattungsverfahren');
+define('MODULE_PAYMENT_NOVALNET_PAYMENT_REFUND_CONFIRM', 'Sind Sie sicher, dass Sie den Betrag erstatten wollen?');
+define('MODULE_PAYMENT_NOVALNET_REFUND_REFERENCE_TEXT', 'Referenz für die Erstattung');
+define('MODULE_PAYMENT_NOVALNET_REFUND_AMT_TITLE', 'Bitte geben Sie den Erstattungsbetrag ein');
+define('MODULE_PAYMENT_NOVALNET_REFUND_REASON_TITLE', 'Grund für die Rückerstattung (optional)');
+define('MODULE_PAYMENT_NOVALNET_INSTALLMENT_TEXT', 'Wählen Sie Ihren Ratenzahlungsplan (Netto-Kreditbetrag: %s )');
+define('MODULE_PAYMENT_NOVALNET_INSTALMENT_INSTALMENTS_INFO', 'Informationen zur Ratenzahlung');
+define('MODULE_PAYMENT_NOVALNET_INSTALMENT_PROCESSED_INSTALMENTS', 'Bearbeitete Raten: ');
+define('MODULE_PAYMENT_NOVALNET_INSTALMENT_DUE_INSTALMENTS', 'Fällige Raten: ');
+define('MODULE_PAYMENT_NOVALNET_INSTALMENT_NEXT_INSTALMENT_AMOUNT', 'Nächster Ratenbetrag: ');
+define('MODULE_PAYMENT_NOVALNET_INSTALMENT_NEXT_INSTALMENT_DATE', 'Nächstes Ratenzahlungsdatum: ');
+define('MODULE_PAYMENT_NOVALNET_INSTALMENT_PAY_DATE_BACKEND', 'Bezahltes Datum');
+define('MODULE_PAYMENT_NOVALNET_INSTALMENT_NEXT_DATE_BACKEND', 'Ratenzahlung Datum');
+define('MODULE_PAYMENT_NOVALNET_INSTALMENT_PAID_DATE_BACKEND', 'Bezahlt am');
+define('MODULE_PAYMENT_NOVALNET_INSTALMENT_STATUS_PAID', 'Bezahlt');
+define('MODULE_PAYMENT_NOVALNET_INSTALMENT_STATUS_PENDING', 'Ausstehend');
+define('MODULE_PAYMENT_NOVALNET_INSTALMENT_STATUS_REFUNDED', 'Rückerstattet');
+define('MODULE_PAYMENT_NOVALNET_INSTALMENT_STATUS_CANCELED', 'Abgesagt');
+define('MODULE_PAYMENT_NOVALNET_BOOK_TITLE', 'Transaktion durchführen');
+define('MODULE_PAYMENT_NOVALNET_BOOK_AMT_TITLE', 'Buchungsbetrag der Transaktion');
+define('MODULE_PAYMENT_NOVALNET_TRANS_BOOKED_MESSAGE', 'Ihre Bestellung wurde mit einem Betrag von %s gebucht. Ihre neue TID für den gebuchten Betrag: %s');
+define('MODULE_PAYMENT_NOVALNET_PAYMENT_ZERO_AMOUNT_BOOK_CONFIRM', 'Sind Sie sich sicher, dass Sie den Bestellbetrag buchen wollen?');
+define('MODULE_PAYMENT_NOVALNET_AMOUNT_ERROR_MESSAGE', 'Ungültiger Betrag');
+define('MODULE_PAYMENT_NOVALNET_ZEROAMOUNT_BOOKING_MESSAGE', 'Diese Transaktion wird mit Nullbuchung bearbeitet');
+define('MODULE_PAYMENT_NOVALNET_ZEROAMOUNT_BOOKING_TEXT', '