diff --git a/composer.json b/composer.json new file mode 100755 index 0000000..3e98f88 --- /dev/null +++ b/composer.json @@ -0,0 +1,43 @@ +{ + "name": "novalnet/novalnet-payment", + "description": "PCI Compliant, seamless integration with the various types of payment and payment-related services integrated into one unique platform", + "version": "v13.1.0", + "type": "shopware-platform-plugin", + "license": "MIT", + "authors": [ + { + "name": "Novalnet AG", + "homepage": "https://www.novalnet.de" + } + ], + "extra": { + "shopware-plugin-class": "Novalnet\\NovalnetPayment\\NovalnetPayment", + "plugin-icon": "src/Resources/config/plugin.png", + "copyright": "(c) by Novalnet AG", + "label": { + "de-DE": "Novalnet Zahlung", + "en-GB": "Novalnet Payments" + }, + "description": { + "de-DE": "PCI-konforme Zahlungsabwicklung mit einer Vielzahl an Payment-Services und nahtloser Integration für eine einfache Anbindung.", + "en-GB": "PCI compliant payment solution, covering a full scope of payment services and seamless integration for easy adaptability." + }, + "manufacturerLink": { + "de-DE": "https://www.novalnet.de", + "en-GB": "https://www.novalnet.com" + }, + "supportLink": { + "de-DE": "https://www.novalnet.de", + "en-GB": "https://www.novalnet.com" + } + }, + "autoload": { + "psr-4": { + "Novalnet\\NovalnetPayment\\": "src/" + } + }, + "require": { + "shopware/core": "~6.4.3.1 | 6.4.x", + "shopware/storefront": "~6.4.3.1 | 6.4.x" + } +} diff --git a/src/Content/PaymentTransaction/NovalnetPaymentTransactionCollection.php b/src/Content/PaymentTransaction/NovalnetPaymentTransactionCollection.php new file mode 100755 index 0000000..70dadea --- /dev/null +++ b/src/Content/PaymentTransaction/NovalnetPaymentTransactionCollection.php @@ -0,0 +1,42 @@ +setFlags(new PrimaryKey(), new Required()), + (new IntField('tid', 'tid'))->setFlags(new Required()), + (new StringField('payment_type', 'paymentType'))->setFlags(new Required()), + (new FloatField('amount', 'amount'))->setFlags(), + (new StringField('currency', 'currency'))->setFlags(), + (new FloatField('paid_amount', 'paidAmount'))->setFlags(), + (new FloatField('refunded_amount', 'refundedAmount'))->setFlags(), + (new StringField('gateway_status', 'gatewayStatus'))->setFlags(new Required()), + (new NumberRangeField('order_no', 'orderNo'))->setFlags(new Required()), + (new NumberRangeField('customer_no', 'customerNo'))->setFlags(new Required()), + (new LongTextField('additional_details', 'additionalDetails'))->setFlags(), + (new StringField('token_info', 'tokenInfo'))->setFlags(), + ]); + } +} diff --git a/src/Content/PaymentTransaction/NovalnetPaymentTransactionEntity.php b/src/Content/PaymentTransaction/NovalnetPaymentTransactionEntity.php new file mode 100755 index 0000000..f5003b5 --- /dev/null +++ b/src/Content/PaymentTransaction/NovalnetPaymentTransactionEntity.php @@ -0,0 +1,213 @@ +tid; + } + + public function setTid(int $tid): void + { + $this->tid = $tid; + } + + public function getId(): string + { + return $this->id; + } + + public function setId(string $id): void + { + $this->id = $id; + } + + public function getPaymentType(): string + { + return $this->paymentType; + } + + public function setPaymentType(string $paymentType): void + { + $this->paymentType = $paymentType; + } + + public function getAmount(): ?int + { + return (int) $this->amount; + } + + public function setAmount(int $amount): void + { + $this->amount = $amount; + } + + public function getCurrency(): ?string + { + return (string) $this->currency; + } + + public function setCurrency(string $currency): void + { + $this->currency = $currency; + } + + public function getPaidAmount(): ? int + { + return (int) $this->paidAmount; + } + + public function setPaidAmount(int $paidAmount): void + { + $this->paidAmount = $paidAmount; + } + + public function getRefundedAmount(): ?int + { + return (int) $this->refundedAmount; + } + + public function setRefundedAmount(int $refundedAmount): void + { + $this->refundedAmount = $refundedAmount; + } + + public function getGatewayStatus(): string + { + return $this->gatewayStatus; + } + + public function setGatewayStatus(string $gatewayStatus): void + { + $this->gatewayStatus = $gatewayStatus; + } + + public function getOrderNo(): string + { + return $this->orderNo; + } + + public function setOrderNo(string $orderNo): void + { + $this->orderNo = $orderNo; + } + + public function getCustomerNo(): string + { + return $this->customerNo; + } + + public function setCustomerNo(string $customerNo): void + { + $this->customerNo = $customerNo; + } + + public function getAdditionalDetails(): ?string + { + return $this->additionalDetails; + } + + public function setAdditionalDetails(string $additionalDetails): void + { + $this->additionalDetails = $additionalDetails; + } + + public function getTokenInfo(): ?string + { + return $this->tokenInfo; + } + + public function setTokenInfo(string $tokenInfo): void + { + $this->paymentType = $paymentType; + } +} diff --git a/src/Controller/Administration/AdminController.php b/src/Controller/Administration/AdminController.php new file mode 100755 index 0000000..48b8525 --- /dev/null +++ b/src/Controller/Administration/AdminController.php @@ -0,0 +1,513 @@ +helper = $helper; + $this->translator = $translator; + $this->transactionHelper = $transactionHelper; + } + + /** + * @Route( + * "/api/v{version}/_action/novalnet-payment/validate-api-credentials", + * name="api.action.noval.payment.compatibility.validate.api.credentials", + * methods={"POST"} + * ) + * + * @Route( + * "/api/_action/novalnet-payment/validate-api-credentials", + * name="api.action.noval.payment.validate.api.credentials", + * methods={"POST"} + * ) + */ + public function validateApiCredentials(Request $request, Context $context): JsonResponse + { + $data = []; + + if ($request->get('clientId') && $request->get('accessKey')) { + $parameters['merchant'] = [ + 'signature' => $request->get('clientId'), + ]; + $parameters['custom'] = [ + 'lang' => $this->helper->getLocaleCodeFromContext($context), + ]; + + $response = $this->helper->sendPostRequest($parameters, $this->helper->getActionEndpoint('merchant_details'), $request->get('accessKey')); + if (! empty($response['result']['status']) && $response['result']['status'] == 'SUCCESS') { + if (!empty($response['merchant']['tariff'])) { + $tariffs = []; + foreach ($response['merchant']['tariff'] as $key => $values) { + $tariffs[] = [ + 'id' => $key, + 'name' => $values['name'], + ]; + } + sort($tariffs); + $data = ['serverResponse' => $response, 'tariffResponse' => $tariffs]; + } + } else { + $data = ['serverResponse' => $response]; + } + } + return new JsonResponse($data); + } + + /** + * @Route( + * "/api/v{version}/_action/novalnet-payment/transaction-amount", + * name="api.action.noval.payment.compatibility.transaction.amount", + * methods={"POST"} + * ) + * + * @Route( + * "/api/_action/novalnet-payment/transaction-amount", + * name="api.action.noval.payment.transaction.amount", + * methods={"POST"} + * ) + */ + public function getNovalnetData(Request $request, Context $context): JsonResponse + { + $novalnetTransactionData = []; + if (!empty($request->get('orderNumber'))) { + $transactionData = $this->transactionHelper->fetchNovalnetTransactionData((string) $request->get('orderNumber'), $context); + if (!empty($transactionData)) + { + $transactionData->setPaymentType($this->helper->getUpdatedPaymentType($transactionData->getpaymentType())); + $novalnetTransactionData = ['data' => $transactionData ]; + } + } + return new JsonResponse($novalnetTransactionData); + } + + /** + * @Route( + * "/api/v{version}/_action/novalnet-payment/refund-amount", + * name="api.action.noval.payment.compatibility.refund.amount", + * methods={"POST"} + * ) + * + * @Route( + * "/api/_action/novalnet-payment/refund-amount", + * name="api.action.noval.payment.refund.amount", + * methods={"POST"} + * ) + */ + + public function refundAmount(Request $request, Context $context): JsonResponse + { + $refundResponse =[]; + if (!empty($request->get('orderNumber'))) { + $transactionData = $this->transactionHelper->fetchNovalnetTransactionData((string) $request->get('orderNumber'), $context); + $refundAmount = (int) round($request->get('refundAmount')); + + if (!empty($transactionData)) { + $orderReference = $this->transactionHelper->getOrder($request->request->get('orderNumber'), $context); + $localeCode = $this->helper->getLocaleFromOrder($orderReference->getOrderId()); + + if ((int) $transactionData->getRefundedAmount() >= (int) $transactionData->getAmount()) { + return new JsonResponse(['result' => ['status_text' => $this->translator->trans('NovalnetPayment.text.refundAlreadyExists', [], null, $localeCode)]]); + } + + if ($refundAmount > (int) $transactionData->getAmount()) { + return new JsonResponse(['result' => ['status_text' => $this->translator->trans('NovalnetPayment.text.invalidRefundAmount', [], null, $localeCode)]]); + } + + $orderReference = $this->transactionHelper->getOrder($request->get('orderNumber'), $context); + + if (!empty($orderReference)) { + $refundResponse = $this->transactionHelper->refundTransaction($transactionData, $orderReference, $context, $refundAmount, $request); + } + } + } + return new JsonResponse($refundResponse); + } + + /** + * @Route( + * "/api/v{version}/_action/novalnet-payment/manage-payment", + * name="api.action.noval.payment.compatibility.manage.payment", + * methods={"POST"} + * ) + * + * @Route( + * "/api/_action/novalnet-payment/manage-payment", + * name="api.action.noval.payment.manage.payment", + * methods={"POST"} + * ) + */ + + public function managePayment(Request $request, Context $context): JsonResponse + { + $managePayment = []; + if (!empty($request->get('orderNumber'))&& !empty($request->get('status'))) { + $transactionData = $this->transactionHelper->fetchNovalnetTransactionData((string) $request->get('orderNumber'), $context); + + if (!empty($transactionData)) { + $orderReference = $this->transactionHelper->getOrder($request->get('orderNumber'), $context); + if (!empty($orderReference)) { + $status = ($request->get('status')) =='100' ? 'transaction_capture' : 'transaction_cancel'; + $managePayment = $this->transactionHelper->manageTransaction($transactionData, $orderReference, $context, $status); + } + } + } + return new JsonResponse($managePayment); + } + + /** + * @Route( + * "/api/v{version}/_action/novalnet-payment/instalment-cancel", + * name="api.action.noval.payment.compatibility.instalment.cancel", + * methods={"POST"} + * ) + * + * @Route( + * "/api/_action/novalnet-payment/instalment-cancel", + * name="api.action.noval.payment.instalment.cancel", + * methods={"POST"} + * ) + */ + public function instalmentCancel(Request $request, Context $context): JsonResponse + { + $instalmentCancel = []; + + if (!empty($request->get('orderNumber')) && !empty($request->get('cancelType'))) { + $transactionData = $this->transactionHelper->fetchNovalnetTransactionData((string) $request->get('orderNumber'), $context); + + if (!empty($transactionData)) { + $orderReference = $this->transactionHelper->getOrder($request->get('orderNumber'), $context); + if (!empty($orderReference)) { + $instalmentCancel = $this->transactionHelper->instalmentCancelType($transactionData, $orderReference, $context, $request); + } + } + } + return new JsonResponse($instalmentCancel); + } + + /** + * @Route( + * "/api/v{version}/_action/novalnet-payment/book-amount", + * name="api.action.noval.payment.compatibility.book.amount", + * methods={"POST"} + * ) + * + * @Route( + * "/api/_action/novalnet-payment/book-amount", + * name="api.action.noval.payment.book.amount", + * methods={"POST"} + * ) + */ + public function bookAmount(Request $request, Context $context): JsonResponse + { + $bookResponse =[]; + + if (!empty($request->get('orderNumber'))) { + $transactionData = $this->transactionHelper->fetchNovalnetTransactionData((string) $request->get('orderNumber'), $context); + $bookAmount = (int) round($request->get('bookAmount')); + + if (!empty($transactionData)) { + $orderEntity = $this->transactionHelper->getOrderEntity($request->get('orderNumber'), $context); + + if (!empty($orderEntity)) { + $bookResponse = $this->transactionHelper->bookOrderAmount($transactionData, $orderEntity, $context, $bookAmount); + } + } + } + return new JsonResponse($bookResponse); + } + + /** + * @Route( + * "/api/v{version}/_action/novalnet-payment/novalnet-paymentmethod", + * name="api.action.noval.payment.compatibility.novalnet.paymentmethod", + * methods={"POST"} + * ) + * + * @Route( + * "/api/_action/novalnet-payment/novalnet-paymentmethod", + * name="api.action.noval.payment.novalnet.paymentmethod", + * methods={"POST"} + * ) + */ + public function getNovalnetPaymentMethodName(Request $request, Context $context): JsonResponse + { + if (!empty($request->get('orderNumber'))) { + $transactionData = $this->transactionHelper->fetchNovalnetTransactionData((string) $request->get('orderNumber'), $context); + + if (!empty($transactionData)) { + $paymentName = $transactionData->getAdditionalDetails(); + $paymentmethod = $this->helper->unserializeData($paymentName); + if (isset($paymentmethod['payment_name']) && !empty($paymentmethod['payment_name'])) { + return new JsonResponse(['paymentName' => $paymentmethod['payment_name']]); + } + } + } + + return new JsonResponse([]); + } + + /** + * @Route( + * "/api/v{version}/_action/novalnet-payment/webhook-url-configure", + * name="api.action.noval.payment.compatibility.webhook.url.configure", + * methods={"GET","POST"} + * ) + * + * @Route( + * "/api/_action/novalnet-payment/webhook-url-configure", + * name="api.action.noval.payment.webhook.url.configure", + * methods={"GET","POST"} + * ) + */ + public function configureWebhook(Request $request, Context $context): JsonResponse + { + if (!empty($request->get('url')) && !empty($request->get('productActivationKey')) && !empty($request->get('paymentAccessKey'))) { + $parameters = [ + 'merchant' => [ + 'signature' => $request->get('productActivationKey'), + ], + 'webhook' => [ + 'url' => $request->get('url'), + ], + 'custom' => [ + 'lang' => $this->helper->getLocaleCodeFromContext($context), + ], + ]; + + $response = $this->helper->sendPostRequest($parameters, $this->helper->getActionEndpoint('webhook_configure'), $request->get('paymentAccessKey')); + return new JsonResponse($response); + } + return new JsonResponse(['result' => '']); + } + /** + * @Route( + * "/api/v{version}/_action/novalnet-payment/novalnet-Payment", + * name="api.action.noval.payment.compatibility.novalnet.Payment", + * methods={"GET","POST"} + * ) + * + * @Route( + * "/api/_action/novalnet-payment/novalnet-payment", + * name="api.action.noval.payment.novalnet.payment", + * methods={"GET","POST"} + * ) + */ + public function novalnetPayment(Request $request, Context $context): JsonResponse + { + if (!empty($request->get('shippingaddress')) && !empty($request->get('billingaddress')) && !empty($request->get('amount')) && !empty($request->get('currency')) && !empty($request->get('customer'))) { + $customer = $request->get('customer'); + $paymentSettings = $this->helper->getNovalnetPaymentSettings($customer['salesChannel']['id']); + + $themename = $this->helper->getThemeName($customer['salesChannel']['id'], $context); + + // Built merchant parameters. + $parameters['merchant'] = [ + 'signature' => str_replace(' ', '', $paymentSettings['NovalnetPayment.settings.clientId']), + 'tariff' => $paymentSettings['NovalnetPayment.settings.tariff'] + ]; + + if (!empty($customer)) { + $parameters['customer'] = $this->customerDetails($customer, $request->get('shippingaddress'), $request->get('billingaddress')); + } + $parameters['transaction'] = [ + 'amount' => $request->get('amount') * 100, + 'currency' => $request->get('currency'), + 'system_ip' => $_SERVER['SERVER_ADDR'], + 'system_name' => 'shopware6', + 'system_version' => $this->helper->getVersionInfo($context) . '-NNT' .$themename, + ]; + $parameters['hosted_page'] = [ + 'hide_blocks' => ['ADDRESS_FORM', 'SHOP_INFO', 'LANGUAGE_MENU', 'TARIFF','HEADER'], + 'skip_pages' => ['CONFIRMATION_PAGE', 'SUCCESS_PAGE', 'PAYMENT_PAGE'], + 'type' => 'PAYMENTFORM', + 'display_payments' => ['INVOICE', 'PREPAYMENT', 'CASHPAYMENT', 'MULTIBANCO'] + ]; + + $parameters['custom'] = [ + 'lang' => $this->helper->getLocaleCodeFromContext($context), + ]; + + $response = $this->helper->sendPostRequest($parameters, $this->helper->getActionEndpoint('seamless_payment'), str_replace(' ', '', $paymentSettings['NovalnetPayment.settings.accessKey'])); + return new JsonResponse($response); + } + + return new JsonResponse(['result' => '']); + } + + /** + * Form customer details. + * + * @param array $customer + * @param array $shipping + * @param array $billing + * + * @return array + */ + public function customerDetails($customer, $shipping, $billing) : array + { + $data = []; + $data =[ + 'first_name' => $customer['firstName'], + 'last_name' => $customer['lastName'], + 'email' => $customer['email'], + 'customer_no' => $customer['customerNumber'] + ]; + + $data['customer_ip'] = $this->helper->getIp(); + if (empty($data['customer_ip'])) { + $data['customer_ip'] = $customer['remoteAddress']; + } + if (!empty($shipping)) { + $shippingaddress = [ + 'street' => $shipping['street'].' '.$shipping['additionalAddressLine1'].' '.$shipping['additionalAddressLine2'], + 'city' => $shipping['city'], + 'zip' => $shipping['zipcode'], + 'country_code' => !empty($shipping['country']['iso']) ? $shipping['country']['iso'] : $this->helper->getCountry($billing['countryId']) + ]; + if (!empty($shipping['company'])) { + $shippingaddress['company'] = $shipping['company']; + } + } + + if (!empty($billing)) { + $billingaddress = [ + 'street' => $billing['street'].' '.$billing['additionalAddressLine1'].' '.$billing['additionalAddressLine2'], + 'city' => $billing['city'], + 'zip' => $billing['zipcode'], + 'country_code' => !empty($billing['country']['iso']) ? $billing['country']['iso'] : $this->helper->getCountry($billing['countryId']) + ]; + if (!empty($billing['company'])) { + $billingaddress['company'] = $billing['company']; + } + } + if ($shippingaddress == $billingaddress) { + $data ['shipping'] ['same_as_billing'] = 1; + } else { + $data ['shipping'] = $shippingaddress; + } + $data ['billing'] = $billingaddress; + return $data; + } + + /** + * @Route( + * "/api/v{version}/_action/novalnet-payment/novalnet-select-payment", + * name="api.action.noval.payment.compatibility.novalnet.select.payment", + * methods={"GET","POST"} + * ) + * + * @Route( + * "/api/_action/novalnet-payment/novalnet-select-payment", + * name="api.action.noval.payment.novalnet.select.payment", + * methods={"GET","POST"} + * ) + */ + public function novalnetSelectPayment(Request $request, Context $context) + { + if (!empty($request->get('paymentSelected'))) { + $transactionData = $this->transactionHelper->orderBackend((string) $request->get('paymentSelected'), $context); + } + } + + /** + * @Route( + * "/api/v{version}/_action/novalnet-payment/payment-value-data", + * name="api.action.noval.payment.compatibility.payment.value.data", + * methods={"GET","POST"} + * ) + * + * @Route( + * "/api/_action/novalnet-payment/payment-value-data", + * name="api.action.noval.payment.payment.value.data", + * methods={"GET","POST"} + * ) + */ + public function paymentValueData(Request $request, Context $context): JsonResponse + { + if (!empty($request->get('value')) && !empty($request->get('customer'))) { + $paymentDetails = $this->helper->unserializeData($request->get('value')); + $result = $this->helper->orderBackendPaymentData($paymentDetails, $request->get('customer'), $context); + return new JsonResponse(['success' => $result ]); + } + + return new JsonResponse([]); + } + + /** + * @Route( + * "/api/v{version}/_action/novalnet-payment/shop-version", + * name="api.action.noval.payment.compatibility.shop.version", + * methods={"GET","POST"} + * ) + * + * @Route( + * "/api/_action/novalnet-payment/shop-version", + * name="api.action.noval.payment.shop.version", + * methods={"GET","POST"} + * ) + */ + public function getAdminShopVersion(): JsonResponse + { + $result = $this->helper->getShopVersion(); + return new JsonResponse(['version' => $result]); + } +} diff --git a/src/Controller/Storefront/FrontendController.php b/src/Controller/Storefront/FrontendController.php new file mode 100755 index 0000000..1f7a243 --- /dev/null +++ b/src/Controller/Storefront/FrontendController.php @@ -0,0 +1,233 @@ +helper = $helper; + $this->router = $router; + } + + /** + * @Route("/store/changePaymentData", name="frontend.novalnet.storeCustomerData", options={"seo"="false"}, defaults={"csrf_protected"=false, "XmlHttpRequest"=true}, methods={"GET", "POST"}) + */ + public function storeCustomerData(Request $request, SalesChannelContext $context): JsonResponse + { + $data = $this->helper->unserializeData((string) $request->getContent()); + + $paymentSettings = $this->helper->getNovalnetPaymentSettings($context->getSalesChannel()->getId()); + + // Built merchant parameters. + $parameters['merchant'] = [ + 'signature' => str_replace(' ', '', $paymentSettings['NovalnetPayment.settings.clientId']), + 'tariff' => $paymentSettings['NovalnetPayment.settings.tariff'] + ]; + + $customer = $context->getCustomer(); + + // Built customer parameters. + if (!empty($customer)) { + $parameters['customer'] = $this->helper->getCustomerData($customer); + } + + //Build Transaction paramters. + $parameters['transaction'] = [ + 'amount' => 0, + 'order_no' => $data['parentOrderNumber'], + 'currency' => $context->getCurrency()->getIsoCode() ? $context->getCurrency()->getIsoCode() : $context->getSalesChannel()->getCurrency()->getIsoCode(), + 'create_token' => 1, + 'test_mode' => (int) $data['booking_details']['test_mode'], + 'payment_type' => $data['payment_details']['type'], + 'system_name' => 'Shopware', + 'system_ip' => $this->helper->getIp('SYSTEM'), + 'system_version' => $this->helper->getVersionInfo($context->getContext()), + ]; + + if (!empty($data['booking_details']['do_redirect']) || (!empty($data['payment_details']['process_mode']) && $data['payment_details']['process_mode'] == 'redirect')) + { + $parameters['transaction']['return_url'] = $parameters['transaction']['error_return_url'] = $this->generateAbsoluteUrl('frontend.novalnet.returnAction'); + } + + $paymentDataKeys = ['account_holder', 'iban', 'bic', 'wallet_token', 'pan_hash', 'unique_id', 'account_number', 'routing_number']; + + foreach ($paymentDataKeys as $paymentDataKey) { + if (!empty($data['booking_details'][$paymentDataKey])) { + $parameters['transaction']['payment_data'][$paymentDataKey] = $data['booking_details'][$paymentDataKey]; + } + } + + if (!empty($data['booking_details']['payment_ref']['token'])) { + $parameters['transaction']['payment_data']['token'] = $data['booking_details']['payment_ref']['token']; + } + + // Built custom parameters. + $parameters['custom'] = [ + 'lang' => $this->helper->getLocaleCodeFromContext($context->getContext()), + 'input1' => 'subscriptionId', + 'inputval1' => $data['aboId'], + 'input2' => 'paymentMethodId', + 'inputval2' => $data['paymentMethodId'], + 'input3' => 'change_payment', + 'inputval3' => 1 + ]; + + $response = $this->helper->sendPostRequest($parameters, $this->helper->getActionEndpoint('payment'), $paymentSettings['NovalnetPayment.settings.accessKey']); + + if ($response['result']['status'] === 'FAILURE') { + return new JsonResponse(['success' => false, 'message' => $response['result']['status_text']]); + } else { + if (!empty($response['result']['redirect_url'])) { + $this->helper->setSession('iframeData', $data); + return new JsonResponse(['success' => true, 'redirect_url' => $response['result']['redirect_url']]); + } + + $insertData = [ + 'id' => Uuid::randomHex(), + 'paymentType' => $response['transaction']['payment_type'], + 'paidAmount' => 0, + 'tid' => $response['transaction']['tid'], + 'gatewayStatus' => $response['transaction']['status'], + 'amount' => $response['transaction']['amount'], + 'currency' => $response['transaction']['currency'], + 'orderNo' => $response['transaction']['order_no'], + 'customerNo' => !empty($response['customer']['customer_no']) ? $response['customer']['customer_no'] : '', + 'tokenInfo' => $response['transaction']['payment_data']['token'], + 'additionalDetails' => [ + 'payment_name' => !empty($data['payment_details']['name']) ? $data['payment_details']['name'] : $this->helper->getUpdatedPaymentName($response['transaction']['payment_type']), + 'change_payment' => true, + 'subscription' => $data + ] + ]; + + if (!empty($response['transaction']['payment_data']['token'])) { + $insertData['additionalDetails']['token'] = $response['transaction']['payment_data']['token']; + } + + $insertData['additionalDetails'] = $this->helper->serializeData($insertData['additionalDetails']); + + // Upsert data into novalnet_transaction_details.repository + $this->helper->updateTransactionData($insertData, $context->getContext()); + + return new JsonResponse(['success' => true]); + } + } + + /** + * Generate the absolute URL. + * + * @param string $name + * @param array $parameter + * + * @return string + */ + public function generateAbsoluteUrl(string $name, array $parameter = []) + { + return $this->router->generate($name, $parameter, UrlGeneratorInterface::ABSOLUTE_URL); + } + + /** + * @Route("/novalnet/returnAction", name="frontend.novalnet.returnAction", options={"seo"="false"}, defaults={"csrf_protected"=false}, methods={"GET", "POST"}) + */ + public function returnAction(Request $request, SalesChannelContext $context): RedirectResponse + { + if ($request->query->get('status') == 'SUCCESS') { + $data = $this->helper->getSession('iframeData'); + $response = $this->helper->fetchTransactionDetails($request, $context); + + // insert novalnet transaction details + $insertData = [ + 'id' => Uuid::randomHex(), + 'paymentType' => $response['transaction']['payment_type'], + 'paidAmount' => 0, + 'tid' => $response['transaction']['tid'], + 'gatewayStatus' => $response['transaction']['status'], + 'amount' => $response['transaction']['amount'], + 'currency' => $response['transaction']['currency'], + 'orderNo' => $response['transaction']['order_no'], + 'customerNo' => !empty($response['customer']['customer_no']) ? $response['customer']['customer_no'] : '', + 'tokenInfo' => $response['transaction']['payment_data']['token'], + 'additionalDetails' => [ + 'payment_name' => $this->helper->getUpdatedPaymentName($response['transaction']['payment_type']), + 'change_payment' => true, + 'subscription' => $data + ] + ]; + + if (!empty($response['transaction']['payment_data']['token'])) { + $insertData['additionalDetails']['token'] = $response['transaction']['payment_data']['token']; + } + + $insertData['additionalDetails'] = $this->helper->serializeData($insertData['additionalDetails']); + + // Upsert data into novalnet_transaction_details.repository + $this->helper->updateTransactionData($insertData, $context->getContext()); + + return $this->redirectToRoute( + 'frontend.novalnet.subscription.change.payment', + ['aboId' => $response['custom']['inputval1'], 'paymentMethodId' => $response['custom']['inputval2']] + ); + + } else { + $response = $this->helper->fetchTransactionDetails($request, $context); + $this->addFlash(self::DANGER, $request->query->get('status_text') ?? 'Payment method not able to change'); + if (!empty($response['custom']['subscriptionId']) || !empty($response['custom']['inputval1'])) + { + return $this->redirectToRoute( + 'frontend.novalnet.subscription.orders.detail', + ['aboId' => !empty($response['custom']['subscriptionId']) ? $response['custom']['subscriptionId'] : $response['custom']['inputval1']] + ); + } + return $this->redirectToRoute('frontend.novalnet.subscription.orders'); + } + } +} diff --git a/src/Controller/Storefront/WebhookController.php b/src/Controller/Storefront/WebhookController.php new file mode 100755 index 0000000..2d7bdfe --- /dev/null +++ b/src/Controller/Storefront/WebhookController.php @@ -0,0 +1,1009 @@ + [ + 'type', + 'checksum', + 'tid' + ], + 'merchant' => [ + 'vendor', + 'project' + ], + 'transaction' => [ + 'tid', + 'payment_type', + 'status', + ], + 'result' => [ + 'status' + ], + ]; + + /** + * {@inheritdoc} + */ + public function __construct( + NovalnetHelper $helper, + NovalnetOrderTransactionHelper $transactionHelper, + TranslatorInterface $translator, + OrderTransactionStateHandler $orderTransactionStateHandler, + StateMachineRegistry $stateMachineRegistry, + EntityRepository $orderTransactionRepository, + ArchiveMailService $archiveMailService = null, + AbstractMailService $mailService = null + ) { + $this->helper = $helper; + $this->transactionHelper = $transactionHelper; + $this->translator = $translator; + $this->orderTransactionStateHandler = $orderTransactionStateHandler; + $this->stateMachineRegistry = $stateMachineRegistry; + $this->orderTransactionRepository = $orderTransactionRepository; + $this->mailService = $archiveMailService ?? $mailService; + } + + /** + * @Route("/novalnet/callback", name="api.action.novalnetpayment.status-action", defaults={"csrf_protected"=false}, methods={"GET","POST"}) + */ + public function statusAction(Request $request, SalesChannelContext $salesChannelContext): Response + { + $this->salesChannelContext = $salesChannelContext; + $this->eventData = $this->helper->unserializeData((string) $request->getContent()); + if (!$this->eventData) { + $this->response = ['message' => "Received data is not in the JSON format"]; + return $this->debugMessage(); + } + + $this->paymentSettings = $this->helper->getNovalnetPaymentSettings($this->salesChannelContext->getSalesChannel()->getId()); + + if (!$this->authenticateRequestIp() || !$this->validateEventData() || !$this->validateChecksum()) { + return $this->debugMessage(); + } + + $this->eventType = $this->eventData ['event'] ['type']; + $this->eventTid = $this->eventData ['event'] ['tid']; + $this->parentTid = $this->eventTid; + + if (! empty($this->eventData ['event'] ['parent_tid'])) { + $this->parentTid = $this->eventData ['event'] ['parent_tid']; + } + + // Get order reference. + if (!$this->getOrderReference()) { + return $this->debugMessage(); + } + + if (! empty($this->eventData ['instalment']['cycle_amount'])) { + $this->formattedAmount = $this->helper->amountInBiggerCurrencyUnit((int) $this->eventData ['instalment']['cycle_amount'], $this->eventData ['transaction'] ['currency'], $this->salesChannelContext->getContext()); + } elseif (!empty($this->eventData ['transaction'] ['amount'])) { + $this->formattedAmount = $this->helper->amountInBiggerCurrencyUnit((int) $this->eventData ['transaction'] ['amount'], $this->eventData ['transaction'] ['currency'], $this->salesChannelContext->getContext()); + } + $this->response ['message'] = ''; + + if ($this->helper->isSuccessStatus($this->eventData)) { + switch ($this->eventType) { + case "PAYMENT": + $this->response ['message'] .= 'Novalnet Callback executed. The Transaction ID already existed'; + break; + + case "CREDIT": + $callbackComments = $this->creditProcess(); + break; + + case "TRANSACTION_CAPTURE": + case "TRANSACTION_CANCEL": + $callbackComments = $this->transactionCaptureVoid(); + break; + + case "INSTALMENT": + $callbackComments = $this->instalmentProcess(); + break; + + case "CHARGEBACK": + case "RETURN_DEBIT": + case "REVERSAL": + $callbackComments = $this->chargebackProcess(); + break; + + case "PAYMENT_REMINDER_1": + case "PAYMENT_REMINDER_2": + $callbackComments = $this->paymentReminderProcess(); + break; + + case "SUBMISSION_TO_COLLECTION_AGENCY": + $callbackComments = $this->collectionProcess(); + break; + + case "TRANSACTION_UPDATE": + $callbackComments = $this->transactionUpdate(); + break; + + case "TRANSACTION_REFUND": + $callbackComments = $this->transactionrefund(); + break; + + case "INSTALMENT_CANCEL": + $callbackComments = $this->instalmentCancelProcess(); + break; + + default: + $this->response ['message'] .= "The webhook notification has been received for the unhandled EVENT type($this->eventType)"; + } + } else { + $this->response ['message'] .= 'The Payment has been received'; + } + if (!empty($callbackComments)) { + $this->response['message'] .= $callbackComments; + $this->sendNotificationEmail(); + } + return $this->debugMessage(); + } + + /** + * Authenticate server request + * + * @return void + */ + public function authenticateRequestIp() : bool + { + // Authenticating the server request based on IP. + $requestReceivedIp = $this->helper->getIp(); + + $novalnetHostIp = gethostbyname($this->novalnetHostName); + + if (!empty($requestReceivedIp) && ! empty($novalnetHostIp)) { + if ($requestReceivedIp !== $novalnetHostIp && empty($this->paymentSettings ['NovalnetPayment.settings.deactivateIp'])) { + $this->response = ['message' => "Unauthorised access from the IP $requestReceivedIp"]; + return false; + } + } else { + $this->response = [ 'message' => 'Unauthorised access from the IP. Host/recieved IP is empty' ]; + return false; + } + + return true; + } + + /** + * Validate EventData + * + * @return bool + */ + + public function validateEventData() : bool + { + if (! empty($this->eventData ['custom'] ['shop_invoked'])) { + $this->response = [ 'message' => 'Process already handled in the shop.' ]; + return false; + } + + foreach ($this->mandatoryParams as $category => $parameters) { + if (empty($this->eventData [ $category ])) { + // Could be a possible manipulation in the notification data. + $this->response = [ 'message' => "Required parameter category($category) not received" ]; + } elseif (! empty($parameters)) { + foreach ($parameters as $parameter) { + if (empty($this->eventData [ $category ] [ $parameter ])) { + // Could be a possible manipulation in the notification data. + $this->response = [ 'message' => "Required parameter($parameter) in the category($category) not received" ]; + return false; + } elseif (in_array($parameter, [ 'tid', 'parent_tid' ], true) && ! preg_match('/^\d{17}$/', (string) $this->eventData [ $category ] [ $parameter ])) { + $this->response = [ 'message' => "Invalid TID received in the category($category) not received $parameter" ]; + return false; + } + } + } + } + return true; + } + + /** + * Validate checksum + * + * @return bool + */ + + public function validateChecksum() : bool + { + $tokenString = $this->eventData ['event'] ['tid'] . $this->eventData ['event'] ['type']. $this->eventData ['result'] ['status']; + + if (isset($this->eventData ['transaction'] ['amount'])) { + $tokenString .= $this->eventData ['transaction'] ['amount']; + } + if (isset($this->eventData ['transaction'] ['currency'])) { + $tokenString .= $this->eventData ['transaction'] ['currency']; + } + + $paymentAccessKey = $this->paymentSettings['NovalnetPayment.settings.accessKey']; + if (! empty($paymentAccessKey)) { + $tokenString .= strrev($paymentAccessKey); + } + $generatedChecksum = hash('sha256', $tokenString); + + if ($generatedChecksum !== $this->eventData ['event'] ['checksum']) { + $this->response = [ 'message' => 'While notifying some data has been changed. The hash check failed' ]; + return false; + } + + return true; + } + + /** + * Print the Webhook messages. + * + * @return Response + */ + public function debugMessage() : Response + { + return new Response($this->helper->serializeData($this->response)); + } + + /** + * Get order reference from the novalnet_transaction_detail table on shop database. + * + * @return bool + */ + + public function getOrderReference() :bool + { + $orderNumber = ''; + $paymentMethod = ''; + + if (! empty($this->eventData ['transaction'] ['order_no']) || ! empty($this->parentTid)) { + if (! empty($this->eventData ['transaction'] ['order_no'])) { + $orderNumber = $this->eventData ['transaction'] ['order_no']; + } + + $this->order = $this->transactionHelper->getOrderEntity($orderNumber, $this->salesChannelContext->getContext()); + $this->orderTransaction = $this->transactionHelper->getOrder($orderNumber, $this->salesChannelContext->getContext()); + $this->locale = $this->helper->getLocaleCodeFromContext($this->salesChannelContext->getContext(), true, $this->order->getLanguageId()); + + if (!empty($this->orderTransaction)) { + $paymentMethod = $this->transactionHelper->getPaymentMethodById($this->orderTransaction->getPaymentMethodId(), $this->salesChannelContext->getContext()); + if (!empty($paymentMethod)) { + $this->paymentMethodName = $this->helper->getPaymentMethodName($paymentMethod); + } + } + + if (!$this->helper->checkString($this->paymentMethodName)) { + $this->response = ['message' => 'Order Reference not exist in Database!']; + return false; + } + $this->orderReference = $this->transactionHelper->fetchNovalnetTransactionData((string) $orderNumber, $this->salesChannelContext->getContext(), (string) $this->parentTid); + + if (!empty($this->orderReference) && ($this->eventData['transaction']['amount'] > 0) && ($this->orderReference->getAmount() == 0 && in_array($this->helper->getUpdatedPaymentType($this->orderReference->getPaymentType()), ['CREDITCARD', 'DIRECT_DEBIT_SEPA', 'GOOGLEPAY', 'DIRECT_DEBIT_ACH']))) { + if ($this->helper->isSuccessStatus($this->eventData)) { + $bookAmountInBiggerUnit = $this->helper->amountInBiggerCurrencyUnit($this->eventData['transaction'] ['amount'], $this->eventData['transaction'] ['currency'], $context); + $message = $this->newLine . sprintf($this->translator->trans('NovalnetPayment.text.bookedComment', [], null, $this->locale), $bookAmountInBiggerUnit, $this->eventData['transaction'] ['tid']); + + + $this->transactionHelper->postProcess($this->orderTransaction, $this->salesChannelContext->getContext(), $message, [ + 'id' => $this->orderReference->getId(), + 'tid' => $this->eventData['transaction']['tid'], + 'amount' => $this->eventData['transaction']['amount'], + 'paidAmount' => $this->eventData['transaction']['amount'], + 'gatewayStatus' => $this->eventData['transaction']['status'], + ]); + + try { + $this->orderTransactionStateHandler->paid($this->orderTransaction->getId(), $this->salesChannelContext->getContext()); + + } catch (IllegalTransitionException $exception) { + } + $this->response['message'] .= $message; + + return false; + } + } + } + + if (empty($this->orderReference)) { + if ($this->eventData ['transaction'] ['payment_type'] === 'ONLINE_TRANSFER_CREDIT') { + if (! empty($this->parentTid)) { + $this->eventData ['transaction'] ['tid'] = $this->parentTid; + $this->updateInitialPayment($paymentMethod); + $this->orderReference = $this->transactionHelper->fetchNovalnetTransactionData((string) $orderNumber, $this->salesChannelContext->getContext()); + return false; + } + } else { + $this->updateInitialPayment($paymentMethod); + return false; + } + } + return true; + } + + /** + * Handle communication failure + * + * @param PaymentMethodEntity $paymentMethod + */ + public function updateInitialPayment(PaymentMethodEntity $paymentMethod): void + { + $handlerIdentifier = $paymentMethod->getHandlerIdentifier(); + + if (strpos($handlerIdentifier, "\NovalnetPayment")) { + $handlerIdentifier = 'Novalnet\NovalnetPayment\Service\NovalnetPayment'; + } + + $paymentMethodInstance = new $handlerIdentifier( + $this->helper, + $this->transactionHelper, + $this->orderTransactionStateHandler, + $this->orderTransactionRepository + ); + + $paymentTransaction = new AsyncPaymentTransactionStruct($this->orderTransaction, $this->order, $this->generateUrl('frontend.checkout.cart.page')); + + if (method_exists($paymentMethodInstance, 'checkTransactionStatus')) { + $paymentMethodInstance->checkTransactionStatus($this->orderTransaction, $this->eventData, $this->salesChannelContext, $paymentTransaction, '1'); + if (!empty($this->orderTransaction) && !empty($this->orderTransaction->getCustomFields()['novalnet_comments'])) { + $this->response = [ 'message' => 'The transaction details has been updated successfully' ]; + } else { + $this->response = [ 'message' => 'Communication failure has been handled successfully. The transaction details has been updated' ]; + } + } else { + $this->response = [ 'message' => 'Payment not found in the order' ]; + } + } + + /** + * Handle payment credit process + * + * @return string + */ + private function creditProcess(): string + { + $upsertData = []; + if ((int) $this->orderReference->getPaidAmount() < (int) $this->orderReference->getAmount() && in_array($this->eventData['transaction']['payment_type'], ['INVOICE_CREDIT', 'CASHPAYMENT_CREDIT', 'MULTIBANCO_CREDIT', 'ONLINE_TRANSFER_CREDIT', 'DEBT_COLLECTION_DE'])) { + $paidAmount = (int) $this->orderReference->getPaidAmount() + (int) $this->eventData['transaction']['amount']; + $totalAmount = (int) $this->orderReference->getAmount() - (int) $this->orderReference->getRefundedAmount(); + + $upsertData['id'] = $this->orderReference->getId(); + $upsertData['gatewayStatus'] = $this->eventData['transaction']['status']; + $upsertData['paidAmount'] = $paidAmount; + + if ($this->eventData['transaction']['payment_type'] === 'ONLINE_TRANSFER_CREDIT') { + $callbackComments = $this->newLine . sprintf($this->translator->trans('NovalnetPayment.text.creditMessage', [], null, $this->locale), $this->parentTid, $this->formattedAmount, date('d/m/Y H:i:s'), $this->parentTid); + } else { + $callbackComments = $this->newLine . sprintf($this->translator->trans('NovalnetPayment.text.creditMessage', [], null, $this->locale), $this->parentTid, $this->formattedAmount, date('d/m/Y H:i:s'), $this->eventTid); + } + $this->transactionHelper->postProcess($this->orderTransaction, $this->salesChannelContext->getContext(), $callbackComments, $upsertData); + + if (($paidAmount >= $totalAmount)) { + try { + if (version_compare($this->helper->getShopVersion(), '6.4.7.0', '>=')) { + $this->orderTransactionStateHandler->process($this->orderTransaction->getId(), $this->salesChannelContext->getContext()); + } + $this->orderTransactionStateHandler->paid($this->orderTransaction->getId(), $this->salesChannelContext->getContext()); + } catch (IllegalTransitionException $exception) { + } + } elseif ($paidAmount !=0 && $paidAmount < $totalAmount) { + $this->orderTransactionStateHandler->payPartially($this->orderTransaction->getId(), $this->salesChannelContext->getContext()); + } + return $callbackComments; + } else { + $callbackComments = $this->newLine . sprintf($this->translator->trans('NovalnetPayment.text.creditMessage', [], null, $this->locale), $this->parentTid, $this->formattedAmount, date('d/m/Y H:i:s'), $this->eventTid); + $this->transactionHelper->postProcess($this->orderTransaction, $this->salesChannelContext->getContext(), $callbackComments, []); + return $callbackComments; + } + } + + /** + * Handle transaction Capture process + * + * @return string + */ + private function transactionCaptureVoid(): string + { + $callbackComments = ''; + $appendComments = true; + $upsertData =[]; + if (in_array($this->orderReference->getGatewayStatus(), ['ON_HOLD', 'PENDING'])) { + $upsertData['id'] = $this->orderReference->getId(); + + $transactionStatus = $this->eventData['transaction']['status']; + $salesChannelContext = $this->salesChannelContext->getContext(); + + if ($this->eventType === 'TRANSACTION_CAPTURE') { + if ($this->helper->getUpdatedPaymentType($this->orderReference->getPaymentType()) === 'INVOICE') { + $transactionStatus = 'PENDING'; + } + + if (in_array($transactionStatus, ['CONFIRMED', 'PENDING'])) { + $transactionAdditionDetails = $this->helper->unserializeData($this->orderReference->getAdditionalDetails()); + if (!empty($this->orderReference->getAdditionalDetails()) && !empty($this->orderReference->getPaymentType()) && in_array($this->helper->getUpdatedPaymentType($this->orderReference->getPaymentType()), ['INVOICE', 'GUARANTEED_INVOICE', 'PREPAYMENT', 'INSTALMENT_INVOICE'])) { + $appendComments = false; + if (!empty($transactionAdditionDetails['bankDetails'])) { + $bankDetails = $transactionAdditionDetails['bankDetails']; + } elseif (!empty($transactionAdditionDetails['account_holder'])) { + $bankDetails = $transactionAdditionDetails; + } + + if (!empty($bankDetails)) { + $this->eventData['transaction']['bank_details'] = $bankDetails; + } + $callbackComments .= $this->helper->formBankDetails($this->eventData, $salesChannelContext, $this->order->getLanguageId()) . $this->newLine; + } + + if (!empty($this->orderReference->getPaymentType()) && in_array($this->helper->getUpdatedPaymentType($this->orderReference->getPaymentType()), ['GUARANTEED_DIRECT_DEBIT_SEPA', 'INSTALMENT_DIRECT_DEBIT_SEPA'])) { + $appendComments = false; + $callbackComments .= $this->helper->formBankDetails($this->eventData, $salesChannelContext, $this->order->getLanguageId()) . $this->newLine; + } + + if ($transactionStatus == 'CONFIRMED') { + $upsertData['paidAmount'] = $this->orderReference->getAmount(); + if (in_array($this->eventData['transaction']['payment_type'], ['INSTALMENT_INVOICE', 'INSTALMENT_DIRECT_DEBIT_SEPA'])) { + $upsertData['additionalDetails'] = $transactionAdditionDetails; + $this->eventData['transaction']['amount'] = $this->orderReference->getAmount(); + $upsertData['additionalDetails']['InstalmentDetails'] = $this->transactionHelper->getInstalmentInformation($this->eventData, $this->locale); + $upsertData['additionalDetails'] = $this->helper->serializeData($upsertData['additionalDetails']); + } + } + } + $callbackComments .= $this->newLine . sprintf($this->translator->trans('NovalnetPayment.text.confirmMessage', [], null, $this->locale), date('d/m/Y H:i:s')); + } else { + if (!empty($this->orderReference->getAdditionalDetails()) && !empty($this->orderReference->getPaymentType()) && in_array($this->helper->getUpdatedPaymentType($this->orderReference->getPaymentType()), ['INVOICE', 'GUARANTEED_INVOICE','INSTALMENT_INVOICE'])) { + $appendComments = false; + if (!empty($transactionAdditionDetails['bankDetails'])) { + $bankDetails = $transactionAdditionDetails['bankDetails']; + } elseif (!empty($transactionAdditionDetails['account_holder'])) { + $bankDetails = $transactionAdditionDetails; + } + + if (!empty($bankDetails)) { + $this->eventData['transaction']['bank_details'] = $bankDetails; + } + + $callbackComments .= $this->helper->formBankDetails($this->eventData, $salesChannelContext, $this->order->getLanguageId()) . $this->newLine; + } + + if (!empty($this->orderReference->getPaymentType()) && in_array($this->helper->getUpdatedPaymentType($this->orderReference->getPaymentType()), ['GUARANTEED_DIRECT_DEBIT_SEPA', 'INSTALMENT_DIRECT_DEBIT_SEPA'])) { + $appendComments = false; + $callbackComments .= $this->helper->formBankDetails($this->eventData, $salesChannelContext, $this->order->getLanguageId()) . $this->newLine; + } + $callbackComments .= $this->newLine . sprintf($this->translator->trans('NovalnetPayment.text.faliureMessage', [], null, $this->locale), date('d/m/Y H:i:s')); + } + + $upsertData['gatewayStatus'] = $transactionStatus; + + $this->transactionHelper->postProcess($this->orderTransaction, $salesChannelContext, $callbackComments, $upsertData, $appendComments); + + if (in_array($this->eventData['transaction']['payment_type'], ['INVOICE', 'GUARANTEED_INVOICE', 'INSTALMENT_INVOICE', 'INSTALMENT_DIRECT_DEBIT_SEPA'])) { + $this->transactionHelper->prepareMailContent($this->order, $this->salesChannelContext, $callbackComments); + } + + try { + if ($transactionStatus == 'CONFIRMED') { + $this->orderTransactionStateHandler->paid($this->orderTransaction->getId(), $salesChannelContext); + } elseif ($transactionStatus == 'PENDING') { + $this->orderTransactionStateHandler->process($this->orderTransaction->getId(), $salesChannelContext); + } elseif ($this->eventType === 'TRANSACTION_CANCEL') { + $this->orderTransactionStateHandler->cancel($this->orderTransaction->getId(), $salesChannelContext); + } + } catch (IllegalTransitionException $exception) { + } + } else { + $this->response ['message'] = 'Order already processed.'; + } + + return $callbackComments; + } + + + + /** + * Handle payment INSTALMENT process + * + * @return string + */ + private function instalmentProcess(): string + { + if (in_array($this->eventData['transaction']['payment_type'], ['INSTALMENT_INVOICE', 'INSTALMENT_DIRECT_DEBIT_SEPA']) && $this->orderReference->getGatewayStatus() == 'CONFIRMED') { + $comments = sprintf($this->translator->trans('NovalnetPayment.text.instalmentPrepaidMessage', [], null, $this->locale), $this->parentTid, $this->formattedAmount, $this->eventTid).$this->newLine; + } + + $upsertData['id'] = $this->orderReference->getId(); + $upsertData['additionalDetails'] = $this->updateInstalmentInfo(); + + $this->transactionHelper->postProcess($this->orderTransaction, $this->salesChannelContext->getContext(), $comments, $upsertData, true); + $this->transactionHelper->prepareMailContent($this->order, $this->salesChannelContext, $comments, true); + + return $comments; + } + + /** + * Form the instalment data into serialize + * + * @return string + */ + private function updateInstalmentInfo(): string + { + $configurationDetails = $this->helper->unserializeData($this->orderReference->getAdditionalDetails()); + $instalmentData = $this->eventData['instalment']; + $configurationDetails['InstalmentDetails'][$instalmentData['cycles_executed']] = [ + 'amount' => $instalmentData['cycle_amount'], + 'cycleDate' => !empty($instalmentData['next_cycle_date']) ? date('Y-m-d', strtotime($instalmentData['next_cycle_date'])) : '', + 'cycleExecuted' => $instalmentData['cycles_executed'], + 'dueCycles' => $instalmentData['pending_cycles'], + 'paidDate' => date('Y-m-d'), + 'status' => $this->translator->trans('NovalnetPayment.text.paidMsg', [], null, $this->locale), + 'reference' => (string) $this->eventData['transaction']['tid'], + 'refundAmount' => 0, + ]; + return $this->helper->serializeData($configurationDetails); + } + + /** + * Handle payment CHARGEBACK/RETURN_DEBIT/REVERSAL process + * + * @return string + */ + private function chargebackProcess(): string + { + $callbackComments = ''; + if ($this->orderReference->getGatewayStatus()=='CONFIRMED' && ! empty($this->eventData ['transaction'] ['amount'])) { + $callbackComments = $this->newLine . sprintf($this->translator->trans('NovalnetPayment.text.chargebackComments', [], null, $this->locale), $this->parentTid, $this->formattedAmount, date('d/m/Y H:i:s'), $this->eventTid); + + $this->transactionHelper->postProcess($this->orderTransaction, $this->salesChannelContext->getContext(), $callbackComments); + + if ($this->eventData ['transaction'] ['amount'] >= $this->orderReference->getAmount()) { + try { + $this->stateMachineRegistry->transition( + new Transition( + OrderTransactionDefinition::ENTITY_NAME, + $this->orderTransaction->getId(), + StateMachineTransitionActions::ACTION_CHARGEBACK, + 'stateId' + ), + $this->salesChannelContext->getContext() + ); + } catch (IllegalTransitionException $exception) { + } + } + } + return $callbackComments; + } + + /** + * Handle payment reminder process + * + * @return string + */ + private function paymentReminderProcess(): string + { + $callbackComments = ''; + + if (in_array($this->orderReference->getGatewayStatus(), ['CONFIRMED', 'PENDING'])) { + $reminderCount = explode('_', $this->eventType); + $reminderCount = end($reminderCount); + $callbackComments = $this->newLine . sprintf($this->translator->trans('NovalnetPayment.text.paymentReminder', [], null, $this->locale), $reminderCount); + + $this->transactionHelper->postProcess($this->orderTransaction, $this->salesChannelContext->getContext(), $callbackComments); + } + return $callbackComments; + } + + /** + * Handle collection process + * + * @return string + */ + private function collectionProcess(): string + { + $callbackComments = ''; + + if (in_array($this->orderReference->getGatewayStatus(), ['CONFIRMED', 'PENDING'])) { + $callbackComments = $this->newLine . sprintf($this->translator->trans('NovalnetPayment.text.collectionSubmission', [], null, $this->locale), $this->eventData['collection']['reference']); + $this->transactionHelper->postProcess($this->orderTransaction, $this->salesChannelContext->getContext(), $callbackComments); + } + return $callbackComments; + } + + /** + * Handle transaction update + * + * @return string + */ + + private function transactionUpdate(): string + { + $transactionStatus = $this->eventData['transaction']['status']; + $salesChannelContext = $this->salesChannelContext->getContext(); + + $upsertData = [ + 'id' => $this->orderReference->getId(), + 'gatewayStatus' => $transactionStatus, + ]; + + $callbackComments = ''; + $appendComments = true; + + if (in_array($transactionStatus, ['CONFIRMED', 'PENDING', 'ON_HOLD', 'DEACTIVATED' ])) { + if (in_array($this->eventData['transaction']['update_type'], ['DUE_DATE', 'AMOUNT_DUE_DATE'])) { + $upsertData['amount'] = $this->eventData['transaction']['amount']; + $dueDate = date('d/m/Y', strtotime($this->eventData['transaction']['due_date'])); + + if ($this->eventData['transaction']['payment_type'] === 'CASHPAYMENT') { + $callbackComments .= $this->newLine . sprintf($this->translator->trans('NovalnetPayment.text.cashDueDateComments', [], null, $this->locale), $this->formattedAmount, $dueDate); + } else { + $callbackComments .= $this->newLine . sprintf($this->translator->trans('NovalnetPayment.text.dueDateComments', [], null, $this->locale), $this->formattedAmount, $dueDate); + } + } elseif ($this->eventData['transaction']['update_type'] == 'STATUS') { + $transactionAdditionDetails = $this->helper->unserializeData($this->orderReference->getAdditionalDetails()); + if (in_array($this->eventData['transaction']['payment_type'], ['GUARANTEED_INVOICE', 'INSTALMENT_INVOICE', 'INVOICE', 'GUARANTEED_DIRECT_DEBIT_SEPA', 'INSTALMENT_DIRECT_DEBIT_SEPA'])) { + $appendComments = false; + if (!empty($this->orderReference->getAdditionalDetails())) { + if (!empty($transactionAdditionDetails['bankDetails'])) { + $bankDetails = $transactionAdditionDetails['bankDetails']; + } elseif (!empty($transactionAdditionDetails['account_holder'])) { + $bankDetails = $transactionAdditionDetails; + } + if (!empty($bankDetails) && ($transactionStatus != 'DEACTIVATED')) { + $this->eventData['transaction']['bank_details'] = $bankDetails; + } + } + $callbackComments = $this->helper->formBankDetails($this->eventData, $salesChannelContext, $this->order->getLanguageId()); + } + + if ($transactionStatus === 'DEACTIVATED') { + $callbackComments .= $this->newLine . $this->newLine . sprintf($this->translator->trans('NovalnetPayment.text.faliureMessage', [], null, $this->locale), date('d/m/Y H:i:s')); + } elseif ($this->orderReference->getGatewayStatus() == 'PENDING') { + $upsertData['amount'] = $this->eventData['transaction']['amount']; + + if ($transactionStatus === 'ON_HOLD') { + $callbackComments .= sprintf($this->newLine . $this->translator->trans('NovalnetPayment.text.updateOnholdComments', [], null, $this->locale), $this->eventTid, date('d/m/Y H:i:s')); + } elseif ($transactionStatus === 'CONFIRMED') { + $callbackComments .= $this->newLine . $this->newLine . sprintf($this->translator->trans('NovalnetPayment.text.updateComments1', [], null, $this->locale), $this->eventTid, $this->formattedAmount, date('d/m/Y H:i:s')); + + if (in_array($this->eventData['transaction']['payment_type'], ['INSTALMENT_INVOICE', 'INSTALMENT_DIRECT_DEBIT_SEPA'])) { + $upsertData['additionalDetails'] = $transactionAdditionDetails; + $this->eventData['transaction']['amount'] = $this->orderReference->getAmount(); + $upsertData['additionalDetails']['InstalmentDetails'] = $this->transactionHelper->getInstalmentInformation($this->eventData, $this->locale); + $upsertData['additionalDetails'] = $this->helper->serializeData($upsertData['additionalDetails']); + } elseif (in_array($this->eventData['transaction']['payment_type'], ['PAYPAL', 'PRZELEWY24', 'TRUSTLY'])) { + $callbackComments = sprintf($this->newLine. $this->translator->trans('NovalnetPayment.text.redirectUpdateComment', [], null, $this->locale), $this->eventTid, date('d/m/Y H:i:s')); + } + + $upsertData['paidAmount'] = $this->eventData['transaction']['amount']; + } + } + } else { + if (!empty($this->eventData['transaction']['amount'])) { + $upsertData['amount'] = $this->eventData['transaction']['amount']; + } + $callbackComments .= sprintf($this->newLine . $this->newLine . $this->translator->trans('NovalnetPayment.text.updateComments1', [], null, $this->locale), $this->eventTid, $this->formattedAmount, date('d/m/Y H:i:s')); + } + } + + $this->transactionHelper->postProcess($this->orderTransaction, $salesChannelContext, $callbackComments, $upsertData, $appendComments); + + try { + if ($transactionStatus === 'DEACTIVATED') { + $this->orderTransactionStateHandler->cancel($this->orderTransaction->getId(), $salesChannelContext); + } elseif ((($transactionStatus === 'ON_HOLD') || ($transactionStatus === 'CONFIRMED' && $this->eventData['transaction']['amount'] == 0)) && !in_array($this->eventData['transaction']['payment_type'], ['INVOICE', 'PAYPAL'])) { + $this->orderTransactionStateHandler->authorize($this->orderTransaction->getId(), $salesChannelContext); + } elseif ($transactionStatus=== 'CONFIRMED') { + $this->orderTransactionStateHandler->paid($this->orderTransaction->getId(), $salesChannelContext); + } elseif (($transactionStatus === 'ON_HOLD')) { + $this->orderTransactionStateHandler->reopen($this->orderTransaction->getId(), $salesChannelContext); + } + } catch (IllegalTransitionException $exception) { + } + + if (in_array($this->eventData['transaction']['payment_type'], ['INVOICE', 'GUARANTEED_INVOICE', 'INSTALMENT_INVOICE', 'INSTALMENT_DIRECT_DEBIT_SEPA']) && in_array($transactionStatus, ['CONFIRMED', 'PENDING', 'ON_HOLD'])) { + $this->transactionHelper->prepareMailContent($this->order, $this->salesChannelContext, $callbackComments); + } + + return $callbackComments; + } + + /** + * Transaction refund + * + * @return string + */ + + private function transactionrefund(): string + { + $callbackComments = ''; + + if (!empty($this->eventData['transaction']['refund']['amount'])) { + $refundAmount = $this->eventData['transaction']['refund']['amount']; + } else { + $refundAmount = (int) $this->orderReference->getAmount() - (int) $this->orderReference->getRefundedAmount(); + } + + if (!empty($refundAmount)) { + $refundedAmountInBiggerUnit = $this->helper->amountInBiggerCurrencyUnit((int) $refundAmount, $this->eventData ['transaction'] ['currency'], $this->salesChannelContext->getContext()); + + $callbackComments = $this->newLine . sprintf($this->translator->trans('NovalnetPayment.text.refundComment', [], null, $this->locale), $this->parentTid, $refundedAmountInBiggerUnit); + + if (!empty($this->eventData['transaction']['refund']['tid'])) { + $callbackComments .= sprintf($this->translator->trans('NovalnetPayment.text.refundCommentForNewTid', [], null, $this->locale), $this->eventData['transaction']['refund']['tid']); + } + $additionalDetails = $this->helper->unserializeData($this->orderReference->getAdditionalDetails()); + + if (in_array($this->helper->getUpdatedPaymentType($this->orderReference->getpaymentType()), ['INSTALMENT_INVOICE', 'INSTALMENT_DIRECT_DEBIT_SEPA'])) { + $additionalDetails['InstalmentDetails'] = $this->transactionHelper->updateInstalmentCycle($additionalDetails['InstalmentDetails'], (int)$refundAmount, (string) $this->parentTid, $this->locale); + } + + $totalRefundedAmount = (int) $this->orderReference->getRefundedAmount() + (int) $refundAmount; + $this->transactionHelper->postProcess($this->orderTransaction, $this->salesChannelContext->getContext(), $callbackComments, [ + 'id' => $this->orderReference->getId(), + 'refundedAmount' => $totalRefundedAmount, + 'gatewayStatus' => $this->eventData['transaction']['status'], + 'additionalDetails' => $this->helper->serializeData($additionalDetails), + + ]); + + if ($totalRefundedAmount >= $this->orderReference->getAmount()) { + try { + $this->orderTransactionStateHandler->refund($this->orderTransaction->getId(), $this->salesChannelContext->getContext()); + } catch (IllegalTransitionException $exception) { + } + } + } + return $callbackComments; + } + + + /** + * instalment cancel + * + * @return string + */ + + private function instalmentCancelProcess(): string + { + $callbackComments = ''; + + $additionalDetails = $this->helper->unserializeData($this->orderReference->getAdditionalDetails()); + + if (isset($this->eventData['transaction']['refund'])) { + $refundedAmountInBiggerUnit = $this->helper->amountInBiggerCurrencyUnit((int) $this->eventData['transaction']['refund']['amount'], $this->orderReference->getCurrency(), $this->salesChannelContext->getContext()); + $callbackComments .= $this->newLine . sprintf($this->translator->trans('NovalnetPayment.text.instalmentRefundComment', [], null, $this->locale), $this->parentTid, date('Y-m-d H:i:s'), $refundedAmountInBiggerUnit); + $totalRefundedAmount = $this->orderReference->getAmount(); + } else { + $callbackComments .= $this->newLine . sprintf($this->translator->trans('NovalnetPayment.text.instalmentRemainRefundComment', [], null, $this->locale), $this->parentTid, date('Y-m-d H:i:s')); + $totalRefundedAmount = 0; + foreach ($additionalDetails['InstalmentDetails'] as $instalment) { + $totalRefundedAmount += empty($instalment['reference']) ? $instalment['amount'] : 0; + } + } + + $additionalDetails['InstalmentDetails'] = $this->transactionHelper->updateInstalmentCancel($additionalDetails['InstalmentDetails'], $this->eventData['instalment']['cancel_type'], $this->locale); + $additionalDetails['cancelType'] = $this->eventData['instalment']['cancel_type']; + + $this->transactionHelper->postProcess($this->orderTransaction, $this->salesChannelContext->getContext(), $callbackComments, [ + 'id' => $this->orderReference->getId(), + 'refundedAmount' => $totalRefundedAmount, + 'gatewayStatus' => $this->eventData['transaction']['status'], + 'additionalDetails' => $this->helper->serializeData($additionalDetails), + ]); + + if ($totalRefundedAmount >= $this->orderReference->getAmount()) { + try { + $this->orderTransactionStateHandler->cancel($this->orderTransaction->getId(), $this->salesChannelContext->getContext()); + } catch (IllegalTransitionException $exception) { + } + } + + return $callbackComments; + } + + /** + * Send notify email after callback process. + * + * @return void + */ + public function sendNotificationEmail(): void + { + if (!empty($this->paymentSettings['NovalnetPayment.settings.mailTo']) && ! empty($this->response['message'])) { + $toEmail = explode(',', $this->paymentSettings['NovalnetPayment.settings.mailTo']); + $data = new DataBag(); + $mailSubject = 'Novalnet Callback Script Access Report - '; + if (! empty($this->eventData ['transaction']['order_no'])) { + $mailSubject .= 'Order No : ' . $this->eventData ['transaction']['order_no']; + } + $mailSubject .= ' in the ' . (!empty($this->salesChannelContext->getSalesChannel()->getTranslated()) ? $this->salesChannelContext->getSalesChannel()->getTranslated()['name'] : $this->salesChannelContext->getSalesChannel()->getName()); + + $senderEmail = []; + foreach ($toEmail as $email) { + if ($this->helper->isValidEmail($email)) { + $senderEmail = array_merge($senderEmail, [$email => $email]); + } + } + $data->set( + 'recipients', + $senderEmail + ); + $data->set('senderName', 'Novalnet'); + $data->set('salesChannelId', null); + $data->set('contentHtml', str_replace('/ ', '
', $this->response['message'])); + $data->set('contentPlain', $this->response['message']); + $data->set('subject', $mailSubject); + + try { + $this->mailService->send( + $data->all(), + $this->salesChannelContext->getContext(), + [] + ); + } catch (\Exception $e) { + throw($e); + } + } + } +} diff --git a/src/Helper/NovalnetHelper.php b/src/Helper/NovalnetHelper.php new file mode 100755 index 0000000..c7e6ccb --- /dev/null +++ b/src/Helper/NovalnetHelper.php @@ -0,0 +1,1137 @@ +translator = $translator; + $this->router = $router; + $this->container = $container; + $this->systemConfigService = $systemConfigService; + $this->requestStack = $requestStack; + $this->languageRepository = $this->container->get('language.repository'); + $this->themeRepository = $this->container->get('theme.repository'); + $this->customerRepository = $this->container->get('customer.repository'); + $this->currencyFormatter = $currencyFormatter; + $this->contextPersister = $contextPersister; + $this->shopVersion = $shopVersion; + } + + /** + * Request to payment gateway action. + * + * @param array $parameters + * @param string $url + * @param string $accessKey + * + * @return array + */ + public function sendPostRequest(array $parameters, string $url, string $accessKey) : array + { + $client = new Client([ + 'headers' => [ + 'charset' => 'utf-8', + 'Accept' => 'application/json', + 'X-NN-Access-Key' => base64_encode(str_replace(' ', '', $accessKey)), + ], + 'json' => $parameters + ]); + + try { + $response = $client->post($url)->getBody()->getContents(); + + } catch (RequestException $requestException) { + return [ + 'result' => [ + 'status' => 'FAILURE', + 'status_code' => '106', + 'status_text' => $requestException->getMessage(), + ], + ]; + } + + return $this->unserializeData($response); + } + + /** + * Perform serialize data. + * + * @param array $data + * + * @return string + */ + public function serializeData(array $data): string + { + $result = '{}'; + + if (!empty($data)) { + $result = json_encode($data, JSON_UNESCAPED_SLASHES); + if (json_last_error() === 0) { + return $result; + } + } + + return $result; + } + + /** + * Format the given string. + * + * @param string $string + * @param string $find + * @param string $replace + * + * @return string + */ + public function formatString(string $string, string $find = 'novalnet', string $replace = '') : string + { + return str_ireplace($find, $replace, $string); + } + /** + * Get action URL + * + * @param string $action + * + * @return string + */ + public function getActionEndpoint(string $action = '') : string + { + return $this->endpoint . str_replace('_', '/', $action); + } + + /** + * Perform unserialize data. + * + * @param string|null $data + * @param bool $needAsArray + * + * @return array + */ + public function unserializeData(string $data = null, bool $needAsArray = true): array + { + $result = []; + if (!empty($data)) { + $result = json_decode($data, $needAsArray, 512, JSON_BIGINT_AS_STRING); + if (json_last_error() === 0) { + return $result; + } + } + + return $result; + } + + /** + * Return Shop Version. + * + * @return string + */ + public function getShopVersion(): string + { + return $this->shopVersion; + } + /** + * Get Shopware & Novalnet version information + * @param Context $context + * + * @return string + */ + public function getVersionInfo(Context $context) : string + { + return $this->shopVersion . '-NN' . '13.1.0'; + } + + /** + * get the novalnet Iframe From Url. + * + * @param SalesChannelContext $salesChannelContext + * @param mixed $transaction + * @param string $paymentMethod + * @param boolean $subscription + * + * + * @return string + */ + public function getNovalnetIframeUrl(SalesChannelContext $salesChannelContext, $transaction, string $paymentMethod, bool $subscription = false) : string + { + $paymentSettings = $this->getNovalnetPaymentSettings($salesChannelContext->getSalesChannel()->getId()); + // Start to built basic parameters. + $redirectUrl = ''; + $amount = 0; + if (method_exists($transaction, 'getOrder')) { + $amount = $this->amountInLowerCurrencyUnit($transaction->getOrder()->getPrice()->getTotalPrice()); + } elseif (method_exists($transaction, 'getCart')) { + $amount = $this->amountInLowerCurrencyUnit($transaction->getCart()->getprice()->getTotalPrice()); + } + + $themename = $this->getThemeName($salesChannelContext->getsalesChannel()->getId(), $salesChannelContext->getContext()); + // Built merchant parameters. + $parameters['merchant'] = [ + 'signature' => str_replace(' ', '', $paymentSettings['NovalnetPayment.settings.clientId']), + 'tariff' => $paymentSettings['NovalnetPayment.settings.tariff'] + ]; + $customer = $salesChannelContext->getCustomer(); + if (!empty($customer)) { + $parameters['customer'] = $this->getCustomerData($customer); + } + $parameters['transaction'] = [ + 'amount' => $amount, + 'currency' => $salesChannelContext->getCurrency()->getisoCode(), + 'system_ip' => $_SERVER['SERVER_ADDR'], + 'system_name' => 'shopware6', + 'system_version' => $this->getVersionInfo($salesChannelContext->getContext()) . '-NNT' .$themename, + ]; + $parameters['hosted_page'] = [ + 'hide_blocks' => ['ADDRESS_FORM', 'SHOP_INFO', 'LANGUAGE_MENU', 'TARIFF','HEADER'], + 'skip_pages' => ['CONFIRMATION_PAGE', 'SUCCESS_PAGE', 'PAYMENT_PAGE'], + 'type' => 'PAYMENTFORM' + ]; + + + + if (!empty($subscription)) { + $parameters['hosted_page']['display_payments_mode'] = ['SUBSCRIPTION']; + } + $parameters['custom'] = [ + 'lang' => $this->getLocaleCodeFromContext($salesChannelContext->getContext()), + ]; + + $response = $this->sendPostRequest($parameters, $this->getActionEndpoint('seamless_payment'), str_replace(' ', '', $paymentSettings['NovalnetPayment.settings.accessKey'])); + + if ($response['result']['status'] == 'SUCCESS') { + $redirectUrl = $response['result']['redirect_url']; + }; + + return $redirectUrl; + } + + /** + + * @param Context $context + + * @param string $saleschannelId + * + * @return string + */ + public function getThemeName(string $saleschannelId, Context $context) : string + { + $criteria = new Criteria(); + $criteria->addFilter(new EqualsFilter('salesChannels.id', $saleschannelId)); + $theme = $this->themeRepository->search($criteria, $context); + $themecollection = $theme->getelements(); + $themeTechnicalName = ''; + foreach ($themecollection as $key => $data) { + if ($data->isActive() == 1) { + $themeTechnicalName = $data->getTechnicalName(); + break; + } + } + return $themeTechnicalName; + } + + /** + * Returns the Novalnet backend configuration. + * + * @param string $salesChannelId + * + * @return array + */ + public function getNovalnetPaymentSettings(string $salesChannelId): array + { + return $this->systemConfigService->getDomain( + 'NovalnetPayment.settings', + $salesChannelId, + true + ); + } + + /** + * Get formatted Novalnet payment + * + * @param PaymentMethodEntity|null $paymentMethodEntity + + * @return string + */ + public function getPaymentMethodName(PaymentMethodEntity $paymentMethodEntity = null): ?string + { + $paymentMethodName = ''; + if (!empty($paymentMethodEntity) && method_exists($paymentMethodEntity, 'getShortName') && $paymentMethodEntity->getShortName() !== null) { + $paymentMethodName = (new CamelCaseToSnakeCaseNameConverter())->denormalize((string) $paymentMethodEntity->getShortName()); + $paymentMethodName = strtolower($paymentMethodName); + } elseif (!empty($paymentMethodEntity) && !empty($paymentMethodEntity->getCustomFields()) && !empty($paymentMethodEntity->getCustomFields()['novalnet_payment_method_name'])) { + $paymentMethodName = $paymentMethodEntity->getCustomFields()['novalnet_payment_method_name']; + } + return $paymentMethodName; + } + + + /** + * Get customer data + * + * @param CustomerEntity $customerEntity + * + * @return array + */ + public function getCustomerData(CustomerEntity $customerEntity) + { + $customer = []; + // Get billing details. + list($billingCustomer, $billingAddress) = $this->getAddress($customerEntity, 'billing'); + + if (! empty($billingCustomer)) { + $customer = $billingCustomer; + } + $customer ['billing'] = $billingAddress; + + if (!empty($customerEntity->getActiveBillingAddress()->getPhoneNumber())) { + $customer['tel'] = $customerEntity->getActiveBillingAddress()->getPhoneNumber(); + } + + list($shippingCustomer, $shippingAddress) = $this->getAddress($customerEntity, 'shipping'); + + // Add shipping details. + if (!empty($shippingAddress)) { + if ($billingAddress === $shippingAddress) { + $customer ['shipping'] ['same_as_billing'] = 1; + } else { + $customer ['shipping'] = $shippingAddress; + } + } + if (!empty($customerEntity->getSalutation())) { + $salutationKey = $customerEntity->getSalutation()->getSalutationKey(); + $customer ['gender'] = ($salutationKey == 'mr') ? 'm' : ($salutationKey == 'mrs' ? 'f' : 'u'); + } + + $customer['customer_ip'] = $this->getIp(); + if (empty($customer['customer_ip'])) { + $customer['customer_ip'] = $customerEntity->getRemoteAddress(); + } + $customer['customer_no'] = $customerEntity->getCustomerNumber(); + return $customer; + } + + /** + * Get address + * + * @param CustomerEntity|null $customerEntity + * @param string $type + * + * @return array + */ + public function getAddress(CustomerEntity $customerEntity = null, string $type): array + { + $address = []; + $customer = []; + if (!empty($customerEntity)) { + if ($type === 'shipping') { + $addressData = $customerEntity->getActiveShippingAddress() ?? $customerEntity->getDefaultShippingAddress(); + } else { + $addressData = $customerEntity->getActiveBillingAddress() ?? $customerEntity->getDefaultBillingAddress(); + } + if (!empty($addressData) && !empty($addressData->getCountry())) { + $customer['first_name'] = $addressData->getFirstName(); + $customer['last_name'] = $addressData->getLastName(); + $customer['email'] = $customerEntity->getEmail(); + if (!empty($addressData->getCompany())) { + $address['company'] = $addressData->getCompany(); + } + + $address['street'] = $addressData->getStreet().' '.$addressData->getAdditionalAddressLine1().' '.$addressData->getAdditionalAddressLine2(); + $address['city'] = $addressData->getCity(); + $address['zip'] = $addressData->getZipCode(); + $address['country_code'] = $addressData->getCountry()->getIso(); + } + } + + return [$customer, $address]; + } + + /** + * Converting given amount into smaller unit + * + * @param float|null $amount + * + * @return float + */ + public function amountInLowerCurrencyUnit(float $amount = null): ?float + { + return $amount * 100; + } + + /** + * Get the system IP address. + * + * @param string $type + * @return string + */ + public function getIp(string $type = 'REMOTE') : string + { + $ipAddress = ''; + + // Check to determine the IP address type + if ($type === 'REMOTE') { + if (!empty($this->requestStack->getCurrentRequest())) { + $ipAddress = $this->requestStack->getCurrentRequest()->getClientIp(); + } + } else { + if (empty($_SERVER['SERVER_ADDR']) && !empty($_SERVER['SERVER_NAME'])) { + // Handled for IIS server + $ipAddress = gethostbyname($_SERVER['SERVER_NAME']); + } elseif (!empty($_SERVER['SERVER_ADDR'])) { + $ipAddress = $_SERVER['SERVER_ADDR']; + } + } + return $ipAddress; + } + + /** + * To fetch the shop language from context. + * + * @param Context $context + * @param boolean $formattedLocale + * @param string|null $languageId + * + * @return string + */ + public function getLocaleCodeFromContext(Context $context, bool $formattedLocale = false, string $languageId = null): string + { + $languageId = $languageId ?? $context->getLanguageId(); + $criteria = new Criteria([$languageId]); + $criteria->addAssociation('locale'); + $languageCollection = $this->languageRepository->search($criteria, $context)->getEntities(); + + $language = $languageCollection->get($languageId); + if (!$formattedLocale) { + if (null === $language) { + return 'DE'; + } + + $locale = $language->getLocale(); + if (!$locale) { + return 'DE'; + } + $lang = explode('-', $locale->getCode()); + return strtoupper($lang[0]); + } else { + if (null === $language) { + return 'de-DE'; + } + + $locale = $language->getLocale(); + if (!$locale) { + return 'de-DE'; + } + if (!in_array($locale->getCode(), ['de-DE', 'en-GB'])) { + $languageID = Defaults::LANGUAGE_SYSTEM; + $languageCriteria = new Criteria([$languageID]); + $languageCriteria->addAssociation('locale'); + $language = $this->languageRepository->search($languageCriteria, $context)->first(); + return $language->getLocale()->getCode(); + } + + return in_array($locale->getCode(), ['de-DE', 'en-GB']) ? $locale->getCode() : 'de-DE'; + } + } + + /** + * Check for success status + * + * @param array $data + * + * @return bool + */ + public function isSuccessStatus(array $data): bool + { + return (bool) ((! empty($data['result']['status']) && 'SUCCESS' === $data['result']['status']) || (! empty($data['status']) && 'SUCCESS' === $data['status'])); + } + + /** + * Form Bank details comments. + * + * @param array $input + * @param Context $context + * @param string|null $languageId + * + * @return string + */ + public function formBankDetails(array $input, Context $context, string $languageId = null) : string + { + $comments = $this->formOrderComments($input, $context, $languageId); + $localeCode = $this->getLocaleCodeFromContext($context, true, $languageId); + $paymentType = $input['transaction']['payment_type']; + $translator = $this->translator; + + if (isset($input ['transaction']['amount']) && $input ['transaction']['amount']== 0 && in_array($paymentType, ['PREPAYMENT', 'INVOICE'])) { + $comments .= ''; + } elseif (!empty($input['transaction']['status']) && $input['transaction']['status'] != 'DEACTIVATED') { + if (!empty($input['transaction']['status'] === 'PENDING' && preg_match('/INVOICE/', $paymentType) && (preg_match('/GUARANTEED/', $paymentType) || preg_match('/INSTALMENT/', $paymentType))) + + ) { + $comments .= $this->newLine . $translator->trans('NovalnetPayment.text.invoiceGuaranteePendingMsg', [], null, $localeCode); + } elseif (!empty($input ['transaction']['bank_details'])) { + $bankDetails = $input ['transaction']['bank_details']; + if ($input['transaction']['amount'] != 0) { + $amountInBiggerCurrencyUnit = $this->amountInBiggerCurrencyUnit($input ['transaction']['amount'], $input ['transaction']['currency']); + } + + if (!empty($amountInBiggerCurrencyUnit)) { + if (in_array($input['transaction']['status'], [ 'CONFIRMED', 'PENDING' ], true) && ! empty($input ['transaction']['due_date'])) { + $comments .= $this->newLine . sprintf($translator->trans('NovalnetPayment.text.amountTransaferNoteWithDueDate', [], null, $localeCode), $amountInBiggerCurrencyUnit, date('d/m/Y', strtotime($input ['transaction']['due_date']))) . $this->newLine; + } else { + $comments .= $this->newLine . sprintf($translator->trans('NovalnetPayment.text.amountTransaferNote', [], null, $localeCode), $amountInBiggerCurrencyUnit) . $this->newLine; + } + } + + $comments .= $this->newLine . sprintf($translator->trans('NovalnetPayment.text.accountHolder', [], null, $localeCode), $bankDetails['account_holder']); + $comments .= $this->newLine . sprintf($translator->trans('NovalnetPayment.text.bank', [], null, $localeCode), $bankDetails['bank_name']); + $comments .= $this->newLine . sprintf($translator->trans('NovalnetPayment.text.bankPlace', [], null, $localeCode), $bankDetails['bank_place']); + $comments .= $this->newLine . sprintf($translator->trans('NovalnetPayment.text.iban', [], null, $localeCode), $bankDetails['iban']); + $comments .= $this->newLine . sprintf($translator->trans('NovalnetPayment.text.bic', [], null, $localeCode), $bankDetails['bic']) . $this->newLine; + + // Form reference comments. + $comments .= $this->newLine . $translator->trans('NovalnetPayment.text.paymentReferenceNote', [], null, $localeCode). $this->newLine; + /* translators: %s: TID */ + $comments .= sprintf($translator->trans('NovalnetPayment.text.paymentReference', [], null, $localeCode), '1', 'TID '. $input ['transaction']['tid']); + + if (! empty($input ['transaction']['invoice_ref'])) { + $comments .= $this->newLine . sprintf($translator->trans('NovalnetPayment.text.paymentReference', [], null, $localeCode), '2', $input ['transaction']['invoice_ref']); + } + } + + if (!empty($input['transaction']['nearest_stores'])) { + if (! empty($input ['transaction']['due_date'])) { + $comments .= $this->newLine . sprintf($translator->trans('NovalnetPayment.text.slipExpiryDate', [], null, $localeCode), date('d/m/Y', strtotime($input ['transaction']['due_date']))) . $this->newLine . $this->newLine; + } + + $comments .= $translator->trans('NovalnetPayment.text.cashpaymentStore', [], null, $localeCode) . $this->newLine; + + foreach ($input['transaction']['nearest_stores'] as $key => $nearestStore) { + $comments .= $nearestStore['store_name'] . $this->newLine; + $comments .= $nearestStore['street'] . $this->newLine; + $comments .= $nearestStore['city'] . $this->newLine; + $comments .= $nearestStore['zip'] . $this->newLine; + + if (!empty($nearestStore['country_code'])) { + $comments .= Countries::getName($nearestStore['country_code']) . $this->newLine . $this->newLine; + } + } + } + + + if (! empty($input['transaction']['partner_payment_reference'])) { + $amountInBiggerCurrencyUnit = $this->amountInBiggerCurrencyUnit($input ['transaction']['amount'], $input ['transaction']['currency']); + + $comments .= $this->newLine . $this->newLine . sprintf($translator->trans('NovalnetPayment.text.multibancoReference', [], null, $localeCode), $amountInBiggerCurrencyUnit); + $comments .= $this->newLine . sprintf($translator->trans('NovalnetPayment.text.instalmentPaymentReference', [], null, $localeCode), $input['transaction']['partner_payment_reference']); + } + } + + return $comments; + } + + /** + * Form payment comments. + * + * @param array $input + * @param Context $context + * @param string|null $languageId + * + * @return string + */ + public function formOrderComments(array $input, Context $context, string $languageId = null) : string + { + $comments = ''; + $localeCode = $this->getLocaleCodeFromContext($context, true, $languageId); + $paymentType = $input['transaction']['payment_type']; + $paymentdata = $this->getSession('novalnetPaymentdata'); + if (!empty($input ['transaction']['tid'])) { + $comments .= sprintf($this->translator->trans('NovalnetPayment.text.transactionId', [], null, $localeCode), $input ['transaction']['tid']) ; + if (!empty($input ['transaction'] ['test_mode'])) { + $comments .= $this->newLine . $this->translator->trans('NovalnetPayment.text.testOrder', [], null, $localeCode); + } + if ($input['transaction']['status'] === 'PENDING' && + (preg_match('/SEPA/', $paymentType) + && (preg_match('/GUARANTEED/', $paymentType) || preg_match('/INSTALMENT/', $paymentType)))) { + $comments .= $this->newLine . $this->translator->trans('NovalnetPayment.text.sepaGuaranteePendingMsg', [], null, $localeCode); + } + } + + if (!empty($input['transaction']['status']) && $input['transaction']['status'] === 'CONFIRMED' && $input['transaction']['amount'] == 0 && in_array($paymentType, ['CREDITCARD', 'DIRECT_DEBIT_SEPA', 'GOOGLEPAY', 'DIRECT_DEBIT_ACH']) && (!empty($paymentdata['booking_details']['payment_action']) && $paymentdata['booking_details']['payment_action'] == 'zero_amount')) { + $comments .= $this->newLine . $this->newLine . $this->translator->trans('NovalnetPayment.text.zeroAmountAlertMsg', [], null, $localeCode); + } + + if ((! empty($input['result']['status']) && 'FAILURE' === $input['result']['status'])) { + $comments .= $this->newLine . $this->newLine . $input ['result']['status_text']; + } + + return $comments; + } + + /** + * Converting given amount into bigger unit + * + * @param int $amount + * @param string $currency + * @param Context|null $context + * + * @return string + */ + public function amountInBiggerCurrencyUnit(int $amount, string $currency = '', Context $context = null) : ?string + { + $formatedAmount = (float) sprintf('%.2f', $amount / 100); + if (!empty($currency)) { + if (empty($context)) { + $context = Context::createDefaultContext(); + } + $formatedAmount = $this->currencyFormatter->formatCurrencyByLanguage($formatedAmount, $currency, $context->getLanguageId(), $context); + } + return (string) $formatedAmount; + } + + /** + * Retrieves messages from server response. + * + * @param array $data + * + * @return string + */ + public function getResponseText(array $data) : string + { + if (! empty($data ['result']['status_text'])) { + return $data ['result']['status_text']; + } + + if (! empty($data ['status_text'])) { + return $data ['status_text']; + } + return $this->translator->trans('NovalnetPayment.text.paymentError'); + } + + /** + * Generate Checksum Token + * + * @param Request $request + * @param string $accessKey + * @param string $txnSecret + * + * @return bool + */ + public function isValidChecksum(Request $request, string $accessKey, string $txnSecret): bool + { + if (! empty($request->get('checksum')) && ! empty($request->get('tid')) && ! empty($request->get('status')) && ! empty($accessKey) && ! empty($txnSecret)) { + $checksum = hash('sha256', $request->get('tid') . $txnSecret . $request->get('status') . strrev($accessKey)); + if ($checksum === $request->get('checksum')) { + return true; + } + } + return false; + } + + /** + * Fetch transaction details + * + * @param Request $request + * @param SalesChannelContext $salesChannelContext + * + * @return array + */ + public function fetchTransactionDetails(Request $request, SalesChannelContext $salesChannelContext): array + { + $paymentSettings = $this->getNovalnetPaymentSettings($salesChannelContext->getSalesChannel()->getId()); + $transactionDetails= []; + if ($request->get('tid')) { + $parameter = [ + 'transaction' => [ + 'tid' => $request->get('tid') + ], + 'custom' => [ + 'lang' => $this->getLocaleCodeFromContext($salesChannelContext->getContext()) + ] + ]; + $transactionDetails = $this->sendPostRequest($parameter, $this->getActionEndpoint('transaction_details'), $paymentSettings['NovalnetPayment.settings.accessKey']); + } + return $transactionDetails; + } + + /** + * Checks for the given string in given text. + * + * @param string $string The string value. + * @param string $data The data value. + * + * @return boolean + */ + public static function checkString($string, $data = 'novalnet') + { + if (!empty($string)) { + return (false !== strpos($string, $data)); + } + return false; + } + + /** + * Update Novalnet Transaction Data + * + * @param array $data + * @param Context $context + * + * @return void + */ + public function updateTransactionData(array $data, Context $context) + { + $this->container->get('novalnet_transaction_details.repository')->upsert([$data], $context); + } + + + /** + * To fetch the shop language from order id. + * Fixed language issue in translator. + * + * @param string $orderId + * + * @return string + */ + public function getLocaleFromOrder(string $orderId): string + { + $orderCriteria = new Criteria([$orderId]); + $orderCriteria->addAssociation('language'); + $orderCriteria->addAssociation('language.locale'); + $order = $this->container->get('order.repository')->search($orderCriteria, Context::createDefaultContext())->first(); + $locale = $order->getLanguage()->getLocale(); + if (!$locale) { + return 'de-DE'; + } + return in_array($locale->getCode(), ['de-DE', 'en-GB']) ? $locale->getCode() : 'de-DE'; + } + + /** + * Check mail if validate or not. + * + * @param string $mail + * + * @return bool + */ + public function isValidEmail($mail): bool + { + return (bool) (new EmailValidator())->isValid($mail, new RFCValidation()); + } + + /** + * Check mail if validate or not. + * + * @param array $paymentDetails + * @param array $customer + * + * @return bool + */ + public function orderBackendPaymentData(array $paymentDetails, array $customer, Context $context): string + { + $result = ''; + if (!empty($customer)) { + $customerid = $customer['id']; + $customerCriteria = new Criteria([$customerid]); + $customerDetails = $this->container->get('customer.repository')->search($customerCriteria, $context)->first(); + + if (!empty($paymentDetails)) { + $novalnetPaymentDetails = [ + 'novalnetOrderBackendParameters' => $paymentDetails + ]; + + $customerDetails->setcustomFields($novalnetPaymentDetails); + + $upsertData = [ + 'id' => $customerid, + 'customFields' => $customerDetails->getCustomFields() + ]; + + $this->container->get('customer.repository')->update([$upsertData], $context); + + $result = 'success'; + } + } + + return $result; + } + public function getCustomerDetails(string $customerid) : ?array + { + + $customerCriteria = new Criteria([$customerid]); + $customerDetails = $this->container->get('customer.repository')->search($customerCriteria, Context::createDefaultContext())->first(); + return !empty($customerDetails->getcustomFields()) ? $customerDetails->getcustomFields() : []; + } + + /** + * Set Session using key and data + * + * @param string $key + * @param $data + * + * @return void + */ + public function setSession(string $key, $data): void + { + $this->requestStack->getSession()->set($key, $data); + } + + /** + * Get Session using key + * + * @param string $key + */ + public function getSession(string $key) + { + return $this->requestStack->getSession()->get($key); + } + + /** + * Has Session using key + * + * @param string $key + * + * @return bool + */ + public function hasSession(string $key): bool + { + return $this->requestStack->getSession()->has($key); + } + + /** + * Remove Session + * + * @param string $key + * + */ + public function removeSession(string $key) + { + $this->requestStack->getSession()->remove($key); + } + + /** + * Get Updated Payment Type + * + * @param string $type + * + * @return string + */ + + function getUpdatedPaymentType($type) : string + { + + $types = [ + 'novalnetinvoice' => 'INVOICE', + 'novalnetprepayment' => 'PREPAYMENT', + 'novalnetsepa' => 'DIRECT_DEBIT_SEPA', + 'novalnetsepaguarantee' => 'GUARANTEED_DIRECT_DEBIT_SEPA', + 'novalnetinvoiceguarantee' => 'GUARANTEED_INVOICE', + 'novalnetcreditcard' => 'CREDITCARD', + 'novalnetinvoiceinstalment' => 'INSTALMENT_INVOICE', + 'novalnetsepainstalment' => 'INSTALMENT_DIRECT_DEBIT_SEPA', + 'novalnetcashpayment' => 'CASHPAYMENT', + 'novalnetmultibanco' => 'MULTIBANCO', + 'novalnetsofort' => 'ONLINE_TRANSFER', + 'novalnetideal' => 'IDEAL', + 'novalneteps' => 'EPS', + 'novalnettrustly' => 'TRUSTLY', + 'novalnetgiropay' => 'GIROPAY', + 'novalnetpaypal' => 'PAYPAL', + 'novalnetpostfinancecard' => 'POSTFINANCE_CARD', + 'novalnetpostfinance' => 'POSTFINANCE', + 'novalnetgooglepay' => 'GOOGLEPAY', + 'novalnetapplepay' => 'APPLEPAY', + 'novalnetwechatpay' => 'WECHATPAY', + 'novalnetalipay' => 'ALIPAY', + 'novalnetprzelewy24' => 'PRZELEWY24', + 'novalnetbancontact' => 'BANCONTACT' + ]; + + if (!empty($types[$type])) { + return $types[$type]; + } + + return $type; + } + + /** + * Get Country Code + * + * @param string $type + * + * @return string + */ + + public function getCountry(string $countryId) : string + { + $countryCode = ''; + if (!empty($countryId)) { + $countryCriteria = new Criteria([$countryId]); + $countryDetails = $this->container->get('country.repository')->search($countryCriteria, Context::createDefaultContext())->first(); + $countryCode = $countryDetails->getIso(); + } + return $countryCode; + } + + /** + * Get Updated Payment Name + * + * @param string $type + * + * @return string + */ + function getUpdatedPaymentName($type) : string + { + $types = [ + 'CREDITCARD' => 'Credit/Debit Cards', + 'DIRECT_DEBIT_SEPA' => 'Direct Debit SEPA', + 'GUARANTEED_DIRECT_DEBIT_SEPA' => 'Direct Debit SEPA', + 'INSTALMENT_DIRECT_DEBIT_SEPA' => 'Instalment by SEPA direct debit', + 'INVOICE' => 'Invoice', + 'GUARANTEED_INVOICE' => 'Invoice', + 'INSTALMENT_INVOICE' => 'Instalment by invoice', + 'PREPAYMENT' => 'Prepayment', + 'CASHPAYMENT' => 'Cash Payment', + 'ONLINE_TRANSFER' => 'Sofort', + 'IDEAL' => 'iDEAL', + 'GIROPAY' => 'Giropay', + 'EPS' => 'eps', + 'PAYPAL' => 'PayPal', + 'PRZELEWY24' => 'Przelewy24', + 'POSTFINANCE' => 'PostFinance E-Finance', + 'POSTFINANCE_CARD' => 'PostFinance Card', + 'MULTIBANCO' => 'Multibanco', + 'BANCONTACT' => 'Bancontact', + 'APPLEPAY' => 'Apple Pay', + 'GOOGLEPAY' => 'Google Pay', + 'TRUSTLY' => 'Trustly', + 'ALIPAY' => 'Alipay', + 'WECHATPAY' => 'WeChat Pay' + ]; + + if (!empty($types[$type])) { + return $types[$type]; + } + + return $type; + } + + /** + * Get Transaction Payment Name + * + * @param string $type + * + * @return string + */ + function getTransactionPaymentName($type) : string + { + $types = [ + 'CREDITCARD' => 'novalnetcreditcard', + 'DIRECT_DEBIT_SEPA' => 'novalnetsepa', + 'GUARANTEED_DIRECT_DEBIT_SEPA' => 'novalnetsepaguarantee', + 'INVOICE' => 'novalnetinvoice', + 'GUARANTEED_INVOICE' => 'novalnetinvoiceguarantee', + 'PREPAYMENT' => 'novalnetprepayment', + 'CASHPAYMENT' => 'novalnetcashpayment', + 'MULTIBANCO' => 'novalnetmultibanco', + 'APPLEPAY' => 'novalnetapplepay', + 'GOOGLEPAY' => 'novalnetgooglepay', + ]; + + if (!empty($types[$type])) { + return $types[$type]; + } + + return $type; + } + + /** + * Get error message from session. + * + * @param string $transactionId + * @param string $saleschannelId + * + * @return string + */ + public function getNovalnetErrorMessage(string $transactionId, string $saleschannelId) : ?string + { + $errorMessage = ''; + if ($this->requestStack->getSession()->has('novalnetErrorMessage')) { + $errorMessage = $this->requestStack->getSession()->get('novalnetErrorMessage'); + $this->requestStack->getSession()->remove('novalnetErrorMessage'); + } + return $errorMessage; + } + + /** + * get language + * + * @param Request $request + + * + * @return string + */ + + public function getCurrentRequest(Request $request) : ?string + { + $currentrequest = $this->requestStack->getCurrentRequest(); + return $currentrequest; + } + + /** + * get the Order Language Id + * + * @param string $orderId + * @param Context $context + * + * @return string + */ + + public function getOrderLanguageId(string $orderId, Context $context) : ?string + { + $orderCriteria = new Criteria([$orderId]); + $orderCriteria->addAssociation('language'); + $orderCriteria->addAssociation('language.locale'); + $order = $this->container->get('order.repository')->search($orderCriteria, Context::createDefaultContext())->first(); + return $order->getLanguageId() ? $order->getLanguageId() : ''; + } +} diff --git a/src/Helper/NovalnetOrderTransactionHelper.php b/src/Helper/NovalnetOrderTransactionHelper.php new file mode 100755 index 0000000..9b4d53d --- /dev/null +++ b/src/Helper/NovalnetOrderTransactionHelper.php @@ -0,0 +1,1080 @@ +helper = $helper; + $this->orderTransactionState = $orderTransactionState; + $this->translator = $translator; + $this->orderRepository = $orderRepository; + $this->orderTransactionRepository = $orderTransactionRepository; + $this->container = $container; + $this->paymentMethodRepository = $this->container->get('payment_method.repository'); + $this->novalnetTransactionRepository = $this->container->get('novalnet_transaction_details.repository'); + $this->mailService = $archiveMailService ?? $mailService; + $this->mailTemplateRepository = $this->container->get('mail_template.repository'); + } + + /** + * Fetch Novalnet transaction data. + * + * @param string $orderNumber + * @param Context|null $context + * @param string|null $tid + * + * @return NovalnetPaymentTransactionEntity + */ + public function fetchNovalnetTransactionData(string $orderNumber, $context = null, string $tid = null) : ? NovalnetPaymentTransactionEntity + { + $criteria = new criteria(); + + if (!empty($tid)) { + $criteria->addFilter(new OrFilter([ + new EqualsFilter('novalnet_transaction_details.orderNo', $orderNumber), + new EqualsFilter('novalnet_transaction_details.tid', $tid) + ])); + } else { + $criteria->addFilter(new EqualsFilter('novalnet_transaction_details.orderNo', $orderNumber)); + } + + $criteria->addFilter(new NotFilter('AND', [new ContainsFilter('novalnet_transaction_details.additionalDetails', 'change_payment')])); + + $criteria->addSorting( + new FieldSorting('createdAt', FieldSorting::DESCENDING) + ); + + return $this->novalnetTransactionRepository->search($criteria, $context ?? Context::createDefaultContext())->first(); + } + + /** + * Fetch Novalnet transaction data for template. + * + * @param string $orderNumber + * @param Context|null $context + * + * @return NovalnetPaymentTransactionEntity + */ + public function fetchNovalnetTransactionDataForTemplate(string $orderNumber, Context $context = null) : ? NovalnetPaymentTransactionEntity + { + $criteria = new criteria(); + $criteria->addFilter(new EqualsFilter('novalnet_transaction_details.orderNo', $orderNumber)); + + $criteria->addSorting( + new FieldSorting('createdAt', FieldSorting::DESCENDING) + ); + + return $this->novalnetTransactionRepository->search($criteria, $context ?? Context::createDefaultContext())->first(); + } + + /** + * Fetch payment name. + * + * @param salesChannelContext|null $salesChannelContext + * @param string $orderNumber + * + * @return string + */ + public function getPaymentName(SalesChannelContext $salesChannelContext, string $orderNumber): ?string + { + $paymentMethodName = ''; + $transactionData = $this->fetchNovalnetTransactionData((string) $orderNumber, $salesChannelContext->getContext()); + if (!empty($transactionData) && !empty($transactionData->getAdditionalDetails())) { + $additionalDetails = $this->helper->unserializeData($transactionData->getAdditionalDetails()); + $paymentMethodName = !empty($additionalDetails['payment_name']) ? $additionalDetails['payment_name'] : ''; + } + + return $paymentMethodName; + } + + /** + * Fetch payment name. + * + * @param salesChannelContext|null $salesChannelContext + * @param string $orderNumber + * + * @return string + */ + public function getChangedPaymentName(SalesChannelContext $salesChannelContext, string $orderNumber): ?string + { + $paymentMethodName = ''; + $transactionData = $this->fetchNovalnetTransactionDataForTemplate((string) $orderNumber, $salesChannelContext->getContext()); + if (!empty($transactionData) && !empty($transactionData->getAdditionalDetails())) { + $additionalDetails = $this->helper->unserializeData($transactionData->getAdditionalDetails()); + $paymentMethodName = !empty($additionalDetails['payment_name']) ? $additionalDetails['payment_name'] : ''; + } + + return $paymentMethodName; + } + + /** + * Fetch order. + * + * @param string $orderNumber + * @param Context $context + * + * @return OrderEntity|null + */ + public function getOrderEntity(string $orderNumber, Context $context) : ?OrderEntity + { + $criteria = new criteria(); + $criteria->addFilter(new EqualsFilter('orderNumber', $orderNumber)); + $criteria->addAssociation('transactions'); + $criteria->addSorting( + new FieldSorting('transactions.createdAt', FieldSorting::ASCENDING) + ); + $order = $this->orderRepository->search($criteria, $context)->first(); + + if ($order === null) { + return null; + } + return $order; + } + + /** + * Get order. + * + * @param string $orderNumber + * @param Context $context + * + * @return OrderTransactionEntity|null + */ + public function getOrder(string $orderNumber, Context $context): ?OrderTransactionEntity + { + $order = $this->getOrderEntity($orderNumber, $context); + + if ($order === null) { + return null; + } + + $transactionCollection = $order->getTransactions(); + + if ($transactionCollection === null) { + return null; + } + + $firstTransaction = $transactionCollection->first(); + $lastTransaction = $transactionCollection->last(); + if ($firstTransaction->getCreatedAt()->format('Y-m-d H:i:s') > $lastTransaction->getCreatedAt()->format('Y-m-d H:i:s')) { + $transaction = $firstTransaction; + } else { + $transaction = $lastTransaction; + } + + if ($transaction === null) { + return null; + } + + return $transaction; + } + + + /** + * Finds a payment method by id. + * + * @param string $paymentMethodId + * @param Context|null $context + * + * @return PaymentMethodEntity|null + */ + public function getPaymentMethodById(string $paymentMethodId, Context $context = null): ?PaymentMethodEntity + { + $paymentMethodCriteria = new Criteria(); + $paymentMethodCriteria->addFilter(new EqualsFilter('id', $paymentMethodId)); + $paymentMethod = $this->paymentMethodRepository->search( + $paymentMethodCriteria, + $context ?? Context::createDefaultContext() + ); + if ($paymentMethod->count() === 0) { + return null; + } + + return $paymentMethod->first(); + } + + /** + * Post payment process + * + * @param OrderTransactionEntity $transaction + * @param Context $context + * @param string $comments + * @param array $upsertData + * @param bool $append + */ + public function postProcess(OrderTransactionEntity $transaction, Context $context, string $comments, array $upsertData = [], bool $append = true) : void + { + if (!empty($upsertData)) { + $this->novalnetTransactionRepository->update([$upsertData], $context); + } + if (!empty($transaction->getCustomFields()) && !empty($comments)) { + $oldComments = $transaction->getCustomFields()['novalnet_comments']; + + if (!empty($oldComments) && !empty($append)) { + $oldCommentsAppend = explode("&&", $oldComments); + + $oldCommentsAppend['0'] = $oldCommentsAppend['0'] . $this->newLine . $comments; + + $comments = implode('&&', $oldCommentsAppend); + } + $data = [ + 'id' => $transaction->getId(), + 'customFields' => [ + 'novalnet_comments' => $comments, + ], + ]; + $this->orderTransactionRepository->update([$data], $context); + } + } + + /** + * send novalnet mail. + * + * @param OrderEntity $order + * @param SalesChannelContext $salesChannelContext + * @param string $note + * @param boolean $instalmentRecurring + * + */ + public function prepareMailContent(OrderEntity $order, SalesChannelContext $salesChannelContext, string $note, $instalmentRecurring = false): void + { + if (!empty($order->getOrderCustomer())) { + $orderReference = $this->getOrderCriteria($order->getId(), $salesChannelContext->getContext(), $order->getOrderCustomer()->getCustomerId()); + try { + $emailConfigs = $this->helper->getNovalnetPaymentSettings($salesChannelContext->getSalesChannel()->getId()); + if (!empty($emailConfigs['NovalnetPayment.settings.emailMode']) && $emailConfigs['NovalnetPayment.settings.emailMode'] == 1) { + $this->sendMail($salesChannelContext, $orderReference, $note, $instalmentRecurring); + } + } catch (\RuntimeException $e) { + //Ignore + } + } + } + + + /** + * get the order reference details. + * + * @param string|null $orderId + * @param Context $context + * @param string|null $customerId + * + * @return OrderEntity + */ + public function getOrderCriteria(string $orderId = null, Context $context, string $customerId = null): OrderEntity + { + if (!empty($orderId)) { + $orderCriteria = new Criteria([$orderId]); + } else { + $orderCriteria = new Criteria([]); + } + if (!empty($customerId)) { + $orderCriteria->addFilter( + new EqualsFilter('order.orderCustomer.customerId', $customerId) + ); + } + $orderCriteria->addAssociation('orderCustomer.salutation'); + $orderCriteria->addAssociation('orderCustomer.customer'); + $orderCriteria->addAssociation('currency'); + $orderCriteria->addAssociation('stateMachineState'); + $orderCriteria->addAssociation('lineItems'); + $orderCriteria->addAssociation('transactions'); + $orderCriteria->addAssociation('transactions.paymentMethod'); + $orderCriteria->addAssociation('addresses'); + $orderCriteria->addAssociation('deliveries.shippingMethod'); + $orderCriteria->addAssociation('addresses.country'); + $orderCriteria->addAssociation('deliveries.shippingOrderAddress.country'); + $orderCriteria->addAssociation('salesChannel'); + $orderCriteria->addAssociation('price'); + $orderCriteria->addAssociation('taxStatus'); + return $this->orderRepository->search($orderCriteria, $context)->first(); + } + + /** + * send novalnet order mail. + * + * @param SalesChannelContext $salesChannelContext + * @param OrderEntity $order + * @param string $note + * @param boolean $instalmentRecurring + */ + public function sendMail(SalesChannelContext $salesChannelContext, OrderEntity $order, string $note, bool $instalmentRecurring = false): void + { + $customer = $order->getOrderCustomer(); + if (null === $customer) { + return; + } + $paymentName = ''; + $transaction = $order->getTransactions()->last(); + + $instalmentInfo = []; + + $novalnetTransaction = $this->fetchNovalnetTransactionData($order->getOrderNumber(), $salesChannelContext->getContext()); + $novalnetTransaction->setPaymentType($this->helper->getUpdatedPaymentType($novalnetTransaction->getPaymentType())); + + if (!empty($novalnetTransaction)) { + $additionalDetails = $this->helper->unserializeData($novalnetTransaction->getAdditionalDetails()); + $paymentName = $additionalDetails['payment_name']; + + if (strpos($novalnetTransaction->getPaymentType(), 'INSTALMENT') !== false && $novalnetTransaction->getGatewayStatus() === 'CONFIRMED') { + $instalmentInfo = $additionalDetails; + } + } + + $mailTemplate = $this->getMailTemplate($salesChannelContext->getContext(), 'novalnet_order_confirmation_mail'); + + if (empty($mailTemplate)) { + return; + } + $data = new ParameterBag(); + $data->set( + 'recipients', + [ + $customer->getEmail() => $customer->getFirstName().' '.$customer->getLastName(), + ] + ); + $data->set('senderName', $mailTemplate->getTranslation('senderName')); + $data->set('salesChannelId', $order->getSalesChannelId()); + + $data->set('contentHtml', $mailTemplate->getTranslation('contentHtml')); + $data->set('contentPlain', $mailTemplate->getTranslation('contentPlain')); + + if ($instalmentRecurring) { + $data->set('subject', sprintf($this->translator->trans('NovalnetPayment.text.instalmentMailSubject'), $mailTemplate->getTranslation('senderName'), $order->getOrderNumber())); + } else { + $data->set('subject', $mailTemplate->getTranslation('subject')); + } + $notes = $this->getFinishNovalnetComments($note); + try { + $this->mailService->send( + $data->all(), + $salesChannelContext->getContext(), + [ + 'order' => $order, + 'note' => $notes, + 'instalment' => $instalmentRecurring, + 'salesChannel' => $salesChannelContext->getSalesChannel(), + 'context' => $salesChannelContext, + 'instalmentInfo' => $instalmentInfo, + 'paymentName' => $paymentName, + 'novalnetDetails' => $novalnetTransaction + ] + ); + } catch (\RuntimeException $e) { + //Ignore + } + } + + /** + * get the order mail template. + * + * @param Context $context + * @param string $technicalName + * + * @return MailTemplateEntity|null + */ + public function getMailTemplate(Context $context, string $technicalName): ? MailTemplateEntity + { + $criteria = new Criteria(); + $criteria->addFilter(new EqualsFilter('mailTemplateType.technicalName', $technicalName)); + $criteria->setLimit(1); + + /** @var MailTemplateEntity|null $mailTemplate */ + $mailTemplate = $this->mailTemplateRepository->search($criteria, $context)->first(); + + return $mailTemplate; + } + + /** + * Refund Transaction data. + * + * @param NovalnetPaymentTransactionEntity $transactionData + * @param OrderTransactionEntity $transaction + * @param Context $context + * @param int $refundAmount + * @param Request $request + * + * @return array + */ + + public function refundTransaction(NovalnetPaymentTransactionEntity $transactionData, OrderTransactionEntity $transaction, Context $context, int $refundAmount, Request $request) : array + { + $parameter = []; + $paymentType = $this->helper->getUpdatedPaymentType($transactionData->getpaymentType()); + + $parameter['transaction'] = [ + 'tid' => !empty($request->get('instalmentCycleTid')) ? $request->get('instalmentCycleTid') : $transactionData->getTid(), + ]; + + $localeCode = $this->helper->getLocaleFromOrder($transaction->getOrderId()); + $parameter['custom'] = [ + 'shop_invoked' => 1, + 'lang' => strtoupper(substr($localeCode, 0, 2)), + ]; + + if ($request->get('reason')) { + $parameter['transaction']['reason'] = $request->get('reason'); + } + + if (!empty($refundAmount)) { + $parameter['transaction']['amount'] = $refundAmount; + } + $paymentSettings = $this->helper->getNovalnetPaymentSettings($this->getSalesChannelIdByOrderId($transaction->getOrderId(), $context)); + + $response = $this->helper->sendPostRequest($parameter, $this->helper->getActionEndpoint('transaction_refund'), $paymentSettings['NovalnetPayment.settings.accessKey']); + + if ($this->helper->isSuccessStatus($response)) { + $currency = !empty($response['transaction']['currency']) ? $response['transaction']['currency'] : $response['transaction']['refund']['currency']; + + if (!empty($response['transaction']['refund']['amount'])) { + $refundedAmountInBiggerUnit = $this->helper->amountInBiggerCurrencyUnit($response['transaction']['refund']['amount'], $currency, $context); + } else { + $refundedAmountInBiggerUnit = $this->helper->amountInBiggerCurrencyUnit($refundAmount, $transactionData->getCurrency(), $context); + } + + $message = $this->newLine . sprintf($this->translator->trans('NovalnetPayment.text.refundComment', [], null, $localeCode), $transactionData->getTid(), $refundedAmountInBiggerUnit); + + if (! empty($response['transaction']['refund']['tid'])) { + $message .= sprintf($this->translator->trans('NovalnetPayment.text.refundCommentForNewTid', [], null, $localeCode), $response ['transaction']['refund']['tid']); + } + + $additionalDetails = $this->helper->unserializeData($transactionData->getAdditionalDetails()); + + if (preg_match('/INSTALMENT/', $paymentType)) { + $additionalDetails['InstalmentDetails'] = $this->updateInstalmentCycle($additionalDetails['InstalmentDetails'], $refundAmount, (string)$request->get('instalmentCycleTid'), $localeCode); + } + + $totalRefundedAmount = (int) $transactionData->getRefundedAmount() + (int) $refundAmount; + $this->postProcess($transaction, $context, $message, [ + 'id' => $transactionData->getId(), + 'refundedAmount' => $totalRefundedAmount, + 'gatewayStatus' => $response['transaction']['status'], + 'additionalDetails' => $this->helper->serializeData($additionalDetails), + + ]); + + if ($totalRefundedAmount >= $transactionData->getAmount()) { + try { + $this->orderTransactionState->refund($transaction->getId(), $context); + } catch (IllegalTransitionException $exception) { + $this->orderTransactionState->cancel($transaction->getId(), $context); + } + } + } + return $response; + } + + /** + * Refund Transaction data. + * + * @param NovalnetPaymentTransactionEntity $transactionData + * @param OrderTransactionEntity $transaction + * @param Context $context + * @param string $status + * + * + * @return array + */ + public function manageTransaction(NovalnetPaymentTransactionEntity $transactionData, OrderTransactionEntity $transaction, Context $context, string $status): array + { + $response = []; + $languageId = $this->helper->getOrderLanguageId($transaction->getOrderId(), $context); + $localeCode = $this->helper->getLocaleFromOrder($transaction->getOrderId()); + $paymentType = $this->helper->getUpdatedPaymentType($transactionData->getpaymentType()); + if ($status) { + $parameters = [ + 'transaction' => [ + 'tid' => $transactionData->getTid() + ], + 'custom' => [ + 'shop_invoked' => 1, + 'lang' => strtoupper(substr($localeCode, 0, 2)) + ] + ]; + $paymentSettings = $this->helper->getNovalnetPaymentSettings($this->getSalesChannelIdByOrderId($transaction->getOrderId(), $context)); + + $response = $this->helper->sendPostRequest($parameters, $this->helper->getActionEndpoint($status), $paymentSettings['NovalnetPayment.settings.accessKey']); + if ($this->helper->isSuccessStatus($response)) { + $message = ''; + $appendComments = true; + + $response['manageEvent'] = $status; + $responsePaymentType = $response['transaction']['payment_type']; + + if (! empty($response['transaction']['status'])) { + $transactionStatus = $response['transaction']['status']; + $upsertData = [ + 'id' => $transactionData->getId(), + 'gatewayStatus' => $transactionStatus + ]; + + if (in_array($transactionStatus, ['CONFIRMED', 'PENDING'])) { + $transactionAdditionDetails = $this->helper->unserializeData($transactionData->getAdditionalDetails()); + if (!empty($transactionData->getAdditionalDetails()) && !empty($paymentType) && preg_match('/INVOICE/', $paymentType) || preg_match('/PREPAYMENT/', $paymentType)) { + $appendComments = false; + $response['transaction']['bank_details'] = !empty($transactionAdditionDetails['bankDetails']) ? $transactionAdditionDetails['bankDetails'] : $transactionAdditionDetails; + $message .= $this->helper->formBankDetails($response, $context, $languageId) . $this->newLine; + } + + if ($transactionStatus == 'CONFIRMED') { + $upsertData['paidAmount'] = $transactionData->getAmount(); + + if (preg_match('/INSTALMENT/', $paymentType)) { + $upsertData['additionalDetails'] = $this->helper->unserializeData($transactionData->getAdditionalDetails()); + $response['transaction']['amount'] = $transactionData->getAmount(); + $upsertData['additionalDetails']['InstalmentDetails'] = $this->getInstalmentInformation($response, $localeCode); + $upsertData['additionalDetails'] = $this->helper->serializeData($upsertData['additionalDetails']); + } + } + + $message .= sprintf($this->translator->trans('NovalnetPayment.text.confirmMessage', [], null, $localeCode), date('d/m/Y H:i:s')); + } elseif ($transactionStatus === 'DEACTIVATED') { + $appendComments = false; + $message .= $this->helper->formBankDetails($response, $context, $languageId); + $message .= $this->newLine . $this->newLine . sprintf($this->translator->trans('NovalnetPayment.text.faliureMessage', [], null, $localeCode), date('d/m/Y H:i:s')); + } + + $this->postProcess($transaction, $context, $message, $upsertData, $appendComments); + + if ($transactionStatus === 'CONFIRMED') { + $this->orderTransactionState->paid($transaction->getId(), $context); + } elseif ($transactionStatus === 'PENDING') { + $this->orderTransactionState->process($transaction->getId(), $context); + } elseif ($transactionStatus !== 'PENDING') { + $this->orderTransactionState->cancel($transaction->getId(), $context); + } + } + } + } + return $response; + } + + + /** + * get the SalesChannel Id By OrderId + * + * @param string $orderId + * @param Context $context + * + * @return string + */ + private function getSalesChannelIdByOrderId(string $orderId, Context $context): string + { + $order = $this->orderRepository->search(new Criteria([$orderId]), $context)->first(); + if ($order === null) { + throw new OrderNotFoundException($orderId); + } + + return $order->getSalesChannelId(); + } + + /** + * Update Novalnet instalment cycles + * + * @param array $instalmentDetails + * @param int $amount + * @param string $instalmentCycleTid + * @param string $localeCode + * + * @return array + */ + public function updateInstalmentCycle(array $instalmentDetails, int $amount, string $instalmentCycleTid, string $localeCode): array + { + foreach ($instalmentDetails as $key => $values) { + if ($values['reference'] == $instalmentCycleTid) { + $instalmentDetails[$key]['refundAmount'] = (int) $values['refundAmount'] + $amount; + if ($instalmentDetails[$key]['refundAmount'] >= $values['amount']) { + $instalmentDetails[$key]['status'] = $this->translator->trans('NovalnetPayment.text.refundedMsg', [], null, $localeCode); + } + } + } + + return $instalmentDetails; + } + + /** + * instalment Cancel Type + * + * @param NovalnetPaymentTransactionEntity $transactionData + * @param OrderTransactionEntity $transaction + * @param Context $context + * @param Request $request + * @return array + */ + + public function instalmentCancelType(NovalnetPaymentTransactionEntity $transactionData, OrderTransactionEntity $transaction, Context $context, Request $request) : array + { + $localeCode = $this->helper->getLocaleFromOrder($transaction->getOrderId()); + + $parameter = [ + 'instalment' => [ + 'tid' => $transactionData->getTid(), + 'cancel_type' => $request->get('cancelType') + ], + 'custom' => [ + 'shop_invoked' => 1, + 'lang' => strtoupper(substr($localeCode, 0, 2)) + ] + ]; + + $paymentSettings = $this->helper->getNovalnetPaymentSettings($this->getSalesChannelIdByOrderId($transaction->getOrderId(), $context)); + $response = $this->helper->sendPostRequest($parameter, $this->helper->getActionEndpoint('instalment_cancel'), $paymentSettings['NovalnetPayment.settings.accessKey']); + + if ($this->helper->isSuccessStatus($response)) { + $additionalDetails = $this->helper->unserializeData($transactionData->getAdditionalDetails()); + if (isset($response['transaction']['refund'])) { + $refundedAmountInBiggerUnit = $this->helper->amountInBiggerCurrencyUnit($response['transaction']['refund']['amount'], $transactionData->getCurrency(), $context); + $message = $this->newLine . sprintf($this->translator->trans('NovalnetPayment.text.instalmentRefundComment', [], null, $localeCode), $transactionData->getTid(), date('Y-m-d H:i:s'), $refundedAmountInBiggerUnit); + $totalRefundedAmount = $transactionData->getAmount(); + } else { + $message = $this->newLine . sprintf($this->translator->trans('NovalnetPayment.text.instalmentRemainRefundComment', [], null, $localeCode), $transactionData->getTid(), date('Y-m-d H:i:s')); + $totalRefundedAmount = $transactionData->getRefundedAmount(); + foreach ($additionalDetails['InstalmentDetails'] as $instalment) { + $totalRefundedAmount += empty($instalment['reference']) ? $instalment['amount'] : 0; + } + } + $additionalDetails['InstalmentDetails'] = $this->updateInstalmentCancel($additionalDetails['InstalmentDetails'], $response['instalment']['cancel_type'], $localeCode); + $additionalDetails['cancelType'] = $request->get('cancelType'); + + $this->postProcess($transaction, $context, $message, [ + 'id' => $transactionData->getId(), + 'refundedAmount' => $totalRefundedAmount, + 'gatewayStatus' => $response['transaction']['status'], + 'additionalDetails' => $this->helper->serializeData($additionalDetails), + ]); + + if ($totalRefundedAmount >= $transactionData->getAmount()) { + try { + $this->orderTransactionState->cancel($transaction->getId(), $context); + } catch (IllegalTransitionException $exception) { + } + } + } + + return $response; + } + + /** + * Update Novalnet instalment cycles + * + * @param array $instalmentDetails + * @param string|null $cycleType + * @param string $localeCode + * + * @return array + */ + public function updateInstalmentCancel(array $instalmentDetails, ?string $cycleType, string $localeCode): array + { + foreach ($instalmentDetails as $key => $values) { + if ($cycleType == 'ALL_CYCLES' || empty($cycleType)) { + $instalmentDetails[$key]['refundAmount'] = !empty($values['reference']) ? $values['amount'] : 0; + $instalmentDetails[$key]['status'] = !empty($values['reference']) ? $this->translator->trans('NovalnetPayment.text.refundedMsg', [], null, $localeCode) : $this->translator->trans('NovalnetPayment.text.cancelMsg', [], null, $localeCode); + } elseif ($cycleType == 'REMAINING_CYCLES' && empty($values['reference'])) { + $instalmentDetails[$key]['status'] = $this->translator->trans('NovalnetPayment.text.cancelMsg', [], null, $localeCode); + } + } + return $instalmentDetails; + } + + /** + * Zero book amount . + * + * @param NovalnetPaymentTransactionEntity $transactionData + * @param OrderEntity $order + * @param Context $context + * @param int $bookAmount + * + * + * @return array + */ + public function bookOrderAmount(NovalnetPaymentTransactionEntity $transactionData, OrderEntity $order, Context $context, int $bookAmount) : array + { + $localeCode = $this->helper->getLocaleFromOrder($order->getId()); + + if (!empty($transactionData->getAdditionalDetails())) { + $paymentSettings = $this->helper->getNovalnetPaymentSettings($order->getSalesChannelId()); + $parameter = $this->helper->unserializeData($transactionData->getAdditionalDetails()); + + $parameters = !empty($parameter['novalnetRequestParameters']) ? $parameter['novalnetRequestParameters'] : $parameter; + + if (empty($parameters['merchant'])) { + $orderCollection = $this->getOrderCriteria($order->getId(), $context, $order->getOrderCustomer()->getCustomerId()); + + $parameters = []; + $parameters['merchant'] = [ + 'signature' => str_replace(' ', '', $paymentSettings['NovalnetPayment.settings.clientId']), + 'tariff' => $paymentSettings['NovalnetPayment.settings.tariff'] + ]; + + // Built custom parameters. + $parameters['custom'] = [ + 'lang' => $localeCode, + 'input2' => 'shop_token', + 'inputval2' => Random::getAlphanumericString(32) + ]; + $parameters['transaction'] = [ + 'order_no' => $order->getOrderNumber(), + 'currency' => $transactionData->getCurrency(), + 'payment_type' => $transactionData->getPaymentType(), + 'system_name' => 'Shopware', + 'system_ip' => $this->helper->getIp('SYSTEM'), + 'system_version' => $this->helper->getVersionInfo($context), + ]; + $parameters['transaction']['payment_type'] = $transactionData->getPaymentType(); + $parameters['customer'] = $this->bookAmountRequest($orderCollection, $context); + $parameters['customer']['email'] = $order->getOrderCustomer()->getEmail(); + $parameters['customer']['customer_ip'] = $order->getOrderCustomer()->getRemoteAddress(); + $parameters['customer']['customer_no'] = $order->getOrderCustomer()->getCustomerNumber(); + } + + $parameters['transaction']['amount'] = $bookAmount; + $parameters['transaction']['payment_data'] = ['token' => $parameter['token'] ? $parameter['token'] : $transactionData->getTokenInfo()]; + unset( + $parameter['payment_name'], + $parameter['token'], + $parameters['transaction']['create_token'], + $parameters['transaction']['return_url'], + $parameters['transaction']['error_return_url'], + $parameter['novalnetRequestParameters'] + ); + + $response = $this->helper->sendPostRequest($parameters, $this->helper->getActionEndpoint('payment'), $paymentSettings['NovalnetPayment.settings.accessKey']); + + if ($this->helper->isSuccessStatus($response)) { + $bookAmountInBiggerUnit = $this->helper->amountInBiggerCurrencyUnit($response['transaction'] ['amount'], $response['transaction'] ['currency'], $context); + $message = $this->newLine . sprintf($this->translator->trans('NovalnetPayment.text.bookedComment', [], null, $localeCode), $bookAmountInBiggerUnit, $response['transaction'] ['tid']); + $transaction = $this->getOrder($order->getOrderNumber(), $context); + + $this->postProcess($transaction, $context, $message, [ + 'id' => $transactionData->getId(), + 'tid' => $response['transaction']['tid'], + 'amount' => $response['transaction']['amount'], + 'paidAmount' => $response['transaction']['amount'], + 'gatewayStatus' => $response['transaction']['status'], + ]); + + try { + $this->orderTransactionState->paid($transaction->getId(), $context); + } catch (IllegalTransitionException $exception) { + } + } + } + return $response; + } + + /** + * Form instalment information. + * + * @param array $response + * @param string $localeCode + * + * @return array + */ + public function getInstalmentInformation(array $response, string $localeCode): array + { + $instalmentData = $response['instalment']; + $additionalDetails = []; + + if (!empty($instalmentData['cycle_dates'])) { + $futureInstalmentDate = $instalmentData['cycle_dates']; + foreach (array_keys($futureInstalmentDate) as $cycle) { + $additionalDetails[$cycle] = [ + 'amount' => $instalmentData['cycle_amount'], + 'cycleDate' => !empty($futureInstalmentDate[$cycle + 1]) ? date('Y-m-d', strtotime($futureInstalmentDate[$cycle + 1])) : '', + 'cycleExecuted' => '', + 'dueCycles' => '', + 'paidDate' => '', + 'status' => $this->translator->trans('NovalnetPayment.text.pendingMsg', [], null, $localeCode), + 'reference' => '', + 'refundAmount' => 0, + ]; + + if ($cycle == count($instalmentData['cycle_dates'])) { + $amount = $response['transaction']['amount'] - ($instalmentData['cycle_amount'] * ($cycle - 1)); + $additionalDetails[$cycle] = array_merge($additionalDetails[$cycle], [ + 'amount' => $amount + ]); + } + + if ($cycle == 1) { + $additionalDetails[$cycle] = array_merge($additionalDetails[$cycle], [ + 'cycleExecuted' => !empty($instalmentData['cycles_executed']) ? $instalmentData['cycles_executed'] : '', + 'dueCycles' => !empty($instalmentData['pending_cycles']) ? $instalmentData['pending_cycles'] : '', + 'paidDate' => date('Y-m-d'), + 'status' => $this->translator->trans('NovalnetPayment.text.paidMsg', [], null, $localeCode), + 'reference' => (string) $response['transaction']['tid'], + 'refundAmount' => 0, + ]); + } + } + } + + return $additionalDetails; + } + + /** + * Get Subscription Details. + * + * @param Context $context + * @param string $orderNumber + * + * @return array + */ + public function getSubscriptionDetails(Context $context, string $orderNumber) : array + { + $criteria = new criteria(); + $criteria->addFilter(new EqualsFilter('novalnet_transaction_details.orderNo', $orderNumber)); + $criteria->addSorting(new FieldSorting('createdAt', FieldSorting::DESCENDING)); + $orderDetails = $this->novalnetTransactionRepository->search($criteria, $context)->first(); + $subscription = $this->helper->unserializeData($orderDetails->getAdditionalDetails()); + $datas = []; + if (!empty($subscription['subscription'])) { + $datas = [ + 'payment_details' => $subscription['subscription']['payment_details'], + 'booking_details' => [ + 'test_mode' => $subscription['subscription']['booking_details'] ['test_mode'] + ] + ]; + if (!empty($subscription['subscription']['booking_details'] ['payment_action'])) { + $datas['payment_action'] = $subscription['subscription']['booking_details'] ['payment_action']; + } + if (!empty($subscription['subscription']['booking_details'] ['due_date'])) { + $datas['booking_details']['due_date'] = $subscription['subscription']['booking_details'] ['due_date']; + } + } else { + $datas = [ + 'payment_details' => [ + 'type' => $this->helper->getUpdatedPaymentType($orderDetails->getPaymentType()), + 'process_mode' => 'direct', + ], + 'booking_details' => [ + 'test_mode' => 0 + ], + ]; + } + + return $datas; + } + + /** + * Fetch Novalnet last transaction data by customer id . + * + * @param string $customerNumber + * @param string $paymentName + * @param Context|null $context + * + * @return NovalnetPaymentTransactionEntity + */ + public function fetchNovalnetReferenceData(string $customerNumber, string $paymentType, Context $context = null): ? NovalnetPaymentTransactionEntity + { + + $oldpaymentName = $this->helper->getTransactionPaymentName($paymentType); + $criteria = new Criteria(); + $criteria->addFilter(new AndFilter([ + new EqualsFilter('novalnet_transaction_details.customerNo', $customerNumber), + new EqualsAnyFilter('novalnet_transaction_details.paymentType', [$paymentType, $oldpaymentName]), + ])); + + if ($paymentType == 'GUARANTEED_INVOICE') { + $criteria->addFilter(new ContainsFilter('novalnet_transaction_details.additionalDetails', 'dob')); + } else { + $criteria->addFilter(new NotFilter('AND', [new EqualsFilter('novalnet_transaction_details.tokenInfo', null)])); + $criteria->addFilter(new EqualsAnyFilter('novalnet_transaction_details.gatewayStatus', ['CONFIRMED', 'PENDING', 'ON_HOLD'])); + } + + $criteria->addSorting( + new FieldSorting('createdAt', FieldSorting::DESCENDING) + ); + $novalnetReferenceData = $this->novalnetTransactionRepository->search($criteria, $context ?? Context::createDefaultContext())->first(); + return $novalnetReferenceData; + } + + /* + * Get Finish page Novalnet Comments + * + * @param string|null $comments + * + * @return string + */ + public function getFinishNovalnetComments(string $comments) : ?string + { + if (!empty($comments)) { + $finishNovalnetComments = explode("&&", $comments); + } + return $finishNovalnetComments[0] ? $finishNovalnetComments[0] : $comments; + } + + /** + * Zero book amount Request . + * + * @param OrderEntity $order + * @param Context $context + + * @return array + */ + public function bookAmountRequest(OrderEntity $order, Context $context): array + { + $customer = []; + if (!empty($order)) { + $addresses = $order->getAddresses()->getelements(); + foreach ($addresses as $id => $value) { + if ($order->getBillingAddressId() == $id) { + $billingAddress = $this->customAddress($value); + $customer ['billing'] = $billingAddress; + $customer['first_name'] = $value->getFirstName(); + $customer['last_name'] = $value->getLastName(); + } + } + $shipping = $order->getDeliveries()->first(); + $shippingAddress = $this->customAddress($shipping->getshippingOrderAddress()); + + if (!empty($shippingAddress)) { + if ($billingAddress === $shippingAddress) { + $customer ['shipping'] ['same_as_billing'] = 1; + } else { + $customer ['shipping'] = $shippingAddress; + } + } + } + return $customer; + } + + public function customAddress($addressData) : array + { + $address = []; + + if (!empty($addressData) && !empty($addressData->getCountry())) { + if (!empty($addressData->getCompany())) { + $address['company'] = $addressData->getCompany(); + } + + $address['street'] = $addressData->getStreet().' '.$addressData->getAdditionalAddressLine1().' '.$addressData->getAdditionalAddressLine2(); + $address['city'] = $addressData->getCity(); + $address['zip'] = $addressData->getZipCode(); + $address['country_code'] = $addressData->getCountry()->getIso(); + } + return $address; + } +} diff --git a/src/Installer/MediaProvider.php b/src/Installer/MediaProvider.php new file mode 100755 index 0000000..78aeb8c --- /dev/null +++ b/src/Installer/MediaProvider.php @@ -0,0 +1,83 @@ +mediaService = $mediaService; + $this->connection = $container->get(Connection::class); + } + + /** + * Get Media ID + * + * @param string $paymentMethod + * @param Context $context + * + * @return string|null + */ + public function getMediaId(string $paymentMethod, Context $context): ?string + { + $fileName = $paymentMethod . '-icon'; + + $iconId = $this->connection->fetchOne('SELECT `id` FROM `media` WHERE file_name = "'.$fileName.'"'); + + // Return the already existing file in the same name. + if ($iconId) { + return Uuid::fromBytesToHex($iconId); + } + + // Insert media file to library. + $file = file_get_contents(dirname(__DIR__, 1).'/Resources/public/storefront/assets/img/'.$paymentMethod.'.png'); + $mediaId = ''; + if ($file) { + $mediaId = $this->mediaService->saveFile($file, 'png', 'image/png', $fileName, $context, 'Novalnet Payment - Icons', null, false); + } + return $mediaId; + } +} diff --git a/src/Installer/PaymentMethodInstaller.php b/src/Installer/PaymentMethodInstaller.php new file mode 100755 index 0000000..08e70ea --- /dev/null +++ b/src/Installer/PaymentMethodInstaller.php @@ -0,0 +1,1128 @@ + [ + 'name' => 'Novalnet Zahlung', + 'description' => 'Bieten Sie Ihren Kunden auf sichere und vertrauenswürdige Weise alle weltweit unterstützten Zahlungsarten. Mit Novalnet können Sie Ihre Verkäufe steigern und Ihren Kunden ein ansprechendes Zahlungserlebnis aus einem Guss bieten.', + ], + 'en-GB' => [ + 'name' => 'Novalnet Payment', + 'description' => 'Secured and trusted means of accepting all payment methods supported worldwide. Novalnet provides the most convenient way to increase your sales and deliver seamless checkout experience for your customers.', + ], + ]; + + /** + * @var array + */ + + private $customFields= [ + 'name' => 'novalnet', + 'config' => [ + 'label' => [ + 'en-GB' => 'Novalnet Comments', + 'de-DE' => 'Novalnet Comments', + ], + ], + 'customFields' => [ + [ + 'name' => 'novalnet_comments', + 'active' => true, + 'type' => CustomFieldTypes::TEXT, + 'config' => [ + 'componentName' => 'sw-field', + 'customFieldType' => 'text', + 'customFieldPosition' => 1, + 'label' => [ + 'en-GB' => 'Novalnet Coments', + 'de-DE' => 'Novalnet Kommentare', + ], + ], + ], + ], + 'relations' => [ + [ + 'entityName' => 'order_transaction', + ] + ] + ]; + + /** + * @var array + */ + protected $defaultConfiguration = [ + 'emailMode' => true, + ]; + + /** + * @var Context + */ + private $context; + + /** + * @var ContainerInterface + */ + private $container; + + /** + * @constant string + */ + protected const SYSTEM_CONFIG_DOMAIN = 'NovalnetPayment.settings.'; + + + /** + * Constructs a `PaymentMethodInstaller` + * + * @param ContainerInterface $container + * @param Context $context + */ + public function __construct(ContainerInterface $container, Context $context) + { + $this->context = $context; + $this->container = $container; + $this->mailTemplateRepo = $this->container->get('mail_template.repository'); + $this->mailTemplateTypeRepo = $this->container->get('mail_template_type.repository'); + } + + /** + * Get payment name + * + * @param string $locale + * + * @return string + */ + public function getName(string $locale): string + { + $translations = $this->getTranslations(); + $name = ''; + if (! empty($translations[$locale]['name'])) { + $name = $translations[$locale]['name']; + } + return $name; + } + + /** + * Get payment description + * + * @param string $locale + * + * @return string + */ + public function getDescription(string $locale): string + { + $translations = $this->getTranslations(); + $description = ''; + if (! empty($translations[$locale]['description'])) { + $description = $translations[$locale]['description']; + } + return $description; + } + + /** + * Get payment translations + * + * @return array + */ + public function getTranslations(): array + { + return $this->translations; + } + + /** + * Add Payment Methods on plugin installation + * + */ + public function install(): void + { + $this->addPaymentMethods(); + $this->createMailEvents(); + $this->alterPaymentTokenTable(); + } + + /** + * Add Payment Methods on plugin update process + * + */ + public function update(): void + { + $this->addPaymentMethods(); + $this->updateMediaData(); + $this->alterPaymentTokenTable(); + } + + /** + * Add payment logo into media on plugin activation + * + */ + public function activate(): void + { + $this->updateMediaData(); + } + + /** + * Deactivate Payment Methods + * + */ + public function deactivate(): void + { + $this->deactivatePaymentMethods(); + } + + /** + * Deactivate Payment Methods + * + */ + public function uninstall(): void + { + $this->deactivatePaymentMethods(); + } + + /** + * Delete plugin related system configurations. + * + */ + public function removeConfiguration(): void + { + $systemConfigRepository = $this->container->get('system_config.repository'); + $criteria = (new Criteria()) + ->addFilter(new ContainsFilter('configurationKey', self::SYSTEM_CONFIG_DOMAIN)); + + $idSearchResult = $systemConfigRepository->searchIds($criteria, $this->context); + + $ids = array_map(static function ($id) { + return ['id' => $id]; + }, $idSearchResult->getIds()); + + $systemConfigRepository->delete($ids, $this->context); + } + + /** + * Add plugin related Payment Method. + * + */ + + private function addPaymentMethods(): void + { + $defaultLocale = (in_array($this->getDefaultLocaleCode(), ['de-DE', 'en-GB'])) ? $this->getDefaultLocaleCode() : 'en-GB'; + $context = $this->context; + $this->getPaymentMethodEntity(); + $paymentMethodId = $this->getPaymentMethods(); + + // Skip insertion if the payment already exists. + if (empty($paymentMethodId)) { + $translations = $this->getTranslations(); + $paymentData = [ + [ + 'name' => $this->getName($defaultLocale), + 'description' => $this->getDescription($defaultLocale), + 'position' => -1001, + 'handlerIdentifier' => NovalnetPayment::class, + 'translations' => $translations, + 'afterOrderEnabled' => true, + 'customFields' => [ + 'novalnet_payment_method_name' => 'novalnetpay', + ], + ] + ]; + + $this->context->scope(Context::SYSTEM_SCOPE, function (Context $context) use ($paymentData): void { + $this->container->get('payment_method.repository')->upsert($paymentData, $context); + }); + + $paymentMethodId = $this->getPaymentMethods(); + $channels = $this->container->get('sales_channel.repository')->searchIds(new Criteria(), $this->context); + + // Enable payment method on available channels. + if (!empty($this->container->get('sales_channel_payment_method.repository'))) { + foreach ($channels->getIds() as $channel) { + $data = [ + 'salesChannelId' => $channel, + 'paymentMethodId' => $paymentMethodId, + ]; + $this->container->get('sales_channel_payment_method.repository')->upsert([$data], $this->context); + } + } + } + + $this->updateCustomFieldsForTranslations('novalnetpay', $paymentMethodId); + + // Set default configurations value for payment methods + $customFields = $this->customFields; + $customFieldExistsId = $this->customFieldsExist('novalnet', $this->context); + + if (!$customFieldExistsId && !empty($this->container->get('custom_field_set.repository'))) { + $this->container->get('custom_field_set.repository')->upsert([$customFields], $this->context); + } + + $systemConfig = $this->container->get(SystemConfigService::class); + + if (!empty($systemConfig)) { + foreach ($this->defaultConfiguration as $key => $value) { + if (!empty($value)) { + $systemConfig->set(self::SYSTEM_CONFIG_DOMAIN . $key, $value); + } + } + } + } + + + /** + * Get Novalnet Payment method instance + * + * @return string + */ + private function getPaymentMethods(): ?string + { + /** @var EntityRepository $paymentRepository */ + $paymentRepository = $this->container->get('payment_method.repository'); + + // Fetch ID for update + $paymentCriteria = (new Criteria())->addFilter(new EqualsFilter('handlerIdentifier', NovalnetPayment::class)); + $paymentmethodId = $paymentRepository->searchIds($paymentCriteria, $this->context)->firstId(); + + return $paymentmethodId; + } + + /** + * Deactivate Payment methods + */ + private function deactivatePaymentMethods(): void + { + $paymentMethodId = $this->getPaymentMethods(); + + if (!$paymentMethodId) { + return; + } + + // Deactivate the payment methods. + $this->container->get('payment_method.repository')->update([ + [ + 'id' => $paymentMethodId, + 'active' => false, + ], + ], $this->context); + + // Deactivate the custom fields. + $customFieldExistsId = $this->customFieldsExist('novalnet', $this->context); + if (!$customFieldExistsId) { + return; + } + + $customField = [ + 'id' => $customFieldExistsId, + 'active' => false, + ]; + $this->container->get('custom_field_set.repository')->upsert([$customField], $this->context); + } + + /** + * Get default langauge during plugin installation + * + * @return string|null + */ + private function getDefaultLocaleCode(): ?string + { + $criteria = new Criteria([Defaults::LANGUAGE_SYSTEM]); + $criteria->addAssociation('locale'); + + $systemDefaultLanguage = $this->container->get('language.repository')->search($criteria, $this->context)->first(); + + $locale = $systemDefaultLanguage->getLocale(); + if (!$locale) { + return null; + } + return $locale->getCode(); + } + + + /** + * Update payment custom fields + * + * @param string $paymentcode + * @param string $paymentMethodId + * + */ + private function updateCustomFieldsForTranslations(string $paymentcode, string $paymentMethodId): void + { + $customFields['novalnet_payment_method_name'] = $paymentcode; + if (! empty($customFields)) { + $customFields = json_encode($customFields, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); + } + /** @var Connection $connection */ + $connection = $this->container->get(Connection::class); + + $connection->exec(sprintf(" + UPDATE `payment_method_translation` + SET + `custom_fields` = '%s' + WHERE + `custom_fields` IS NULL AND + `payment_method_id` = UNHEX('%s'); + ", $customFields, $paymentMethodId)); + } + + /** + * payment custom fields Exist + * + * @param string $customFieldName + * @param Context $context + * + * @return string|null + */ + + private function customFieldsExist(string $customFieldName, Context $context): ?string + { + $criteria = new Criteria(); + $criteria->addFilter(new EqualsFilter('name', $customFieldName)); + + if (empty($this->container->get('custom_field_set.repository'))) { + return null; + } + $result = $this->container->get('custom_field_set.repository')->searchIds($criteria, $this->context); + + if (!$result->getTotal()) { + return null; + } + + $customeFields = $result->getIds(); + return array_shift($customeFields); + } + + /** + * Delete plugin related mail configuration. + * + */ + public function deleteMailSettings(): void + { + $criteria = new Criteria(); + $criteria->addFilter(new EqualsFilter('mailTemplateType.technicalName', 'novalnet_order_confirmation_mail')); + + $mailData = $this->mailTemplateRepo->search($criteria, $this->context)->first(); + + if ($mailData) { + // delete subscription mail template + $this->mailTemplateRepo->delete([['id' => $mailData->getId()]], $this->context); + $this->mailTemplateTypeRepo->delete([['id' => $mailData->getMailTemplateTypeId()]], $this->context); + } + } + + /** + * Prepare and update media files on plugin activation + * + * @return void + */ + private function updateMediaData(): void + { + $paymentMethodId = $this->getPaymentMethods(); + + if (!$paymentMethodId) { + return; + } + $paymentMethodEntity = $this->getPaymentMethodMedia(); + // Initiate MediaProvider. + $mediaProvider = $this->container->get(MediaProvider::class); + + if (!is_null($mediaProvider)) { + if (is_null($paymentMethodEntity->getMediaId())) { + $mediaId = $mediaProvider->getMediaId('novalnetpay', $this->context); + $this->container->get('payment_method.repository')->update([ + [ + 'id' => $paymentMethodId, + 'mediaId' => $mediaId, + ], + ], $this->context); + } + } + } + + /** + * Create/Update novalnet order confirmation mail template + * + * @return void + */ + public function createMailEvents(): void + { + $mailType = $this->getMailTemplateType(); + $mailTemplateTypeId = Uuid::randomHex(); + $mailTemplateId = Uuid::randomHex(); + + if (!empty($mailType)) { + $mailTemplateId = $mailType->getId(); + $mailTemplateTypeId = $mailType->getMailTemplateTypeId(); + } + + $this->mailTemplateRepo->upsert([ + [ + 'id' => $mailTemplateId, + 'translations' => [ + 'de-DE' => [ + 'subject' => 'Bestellbestätigung', + 'contentHtml' => $this->getHtmlTemplateDe(), + 'contentPlain'=> $this->getPlainTemplateDe(), + 'description' => 'Novalnet Bestellbestätigung', + 'senderName' => '{{ salesChannel.name }}', + ], + 'en-GB' => [ + 'subject' => 'Order confirmation', + 'contentHtml' => $this->getHtmlTemplateEn(), + 'contentPlain'=> $this->getPlainTemplateEn(), + 'description' => 'Novalnet Order confirmation', + 'senderName' => '{{ salesChannel.name }}', + ], + ], + 'mailTemplateType' => [ + 'id' => $mailTemplateTypeId, + 'technicalName' => 'novalnet_order_confirmation_mail', + 'translations' => [ + 'de-DE' => [ + 'name' => 'Bestellbestätigung', + ], + 'en-GB' => [ + 'name' => 'Order Confirmation', + ], + ], + 'availableEntities' => [ + 'order' => 'order', + 'salesChannel' => 'sales_channel', + ], + ], + ] + ], $this->context); + } + + /** + * Get Payment method entity + * + */ + private function getPaymentMethodEntity(): void + { + $criteria = new Criteria(); + $criteria->addFilter(new PrefixFilter('payment_method.handlerIdentifier', 'Novalnet\NovalnetPayment\Service')); + $paymentListed = $this->container->get('payment_method.repository')->search($criteria, $this->context); + $paymentLists = $paymentListed->getelements(); + + if (!empty($paymentLists)) { + foreach ($paymentLists as $payment) { + if ($payment->gethandlerIdentifier() != 'Novalnet\NovalnetPayment\Service\NovalnetPayment') { + if (!$payment->getId()) { + continue; + } + + // Deactivate the payment methods. + $this->container->get('payment_method.repository')->update([ + [ + 'id' => $payment->getId(), + 'active' => false, + ], + ], $this->context); + + $channels = $this->container->get('sales_channel.repository')->searchIds(new Criteria(), $this->context); + + // Enable payment method on available channels. + if (!empty($this->container->get('sales_channel_payment_method.repository'))) { + foreach ($channels->getIds() as $channel) { + $data = [ + 'salesChannelId' => $channel, + 'paymentMethodId' => $payment->getId(), + ]; + $this->container->get('sales_channel_payment_method.repository')->delete([$data], $this->context); + } + } + } + } + } + } + + /** + * Get Payment method entity + * + * @param string $handlerIdentifier + * + * @retrun PaymentMethodEntity|null + */ + private function getPaymentMethodMedia(): ?PaymentMethodEntity + { + $criteria = new Criteria(); + $criteria->addFilter(new EqualsFilter('handlerIdentifier', 'Novalnet\NovalnetPayment\Service\NovalnetPayment')); + + return $this->container->get('payment_method.repository')->search($criteria, $this->context)->first(); + } + + + /** + * Alter Payment Token Table + */ + public function alterPaymentTokenTable(): void + { + /** @var Connection $connection */ + $connection = $this->container->get(Connection::class); + + $isTableExists = $connection->executeQuery(' + SELECT COUNT(*) as exists_tbl + FROM information_schema.tables + WHERE table_name IN ("novalnet_transaction_details") + AND table_schema = database() + ')->fetch(); + + if (!empty($isTableExists['exists_tbl'])) { + $isColumnExists = $connection->fetchOne('SHOW COLUMNS FROM `novalnet_transaction_details` LIKE "token_info"'); + + if (empty($isColumnExists)) { + $connection->exec(' + ALTER TABLE `novalnet_transaction_details` + ADD `token_info` varchar(255) DEFAULT NULL COMMENT "Transaction Token" AFTER `additional_details`; + '); + } + } + + } + + /** + * Get English HTML Template + * + * @return string + */ + private function getHtmlTemplateEn(): string + { + return '
+ + {% set currencyIsoCode = order.currency.isoCode %} + {{order.orderCustomer.salutation.letterName }} {{order.orderCustomer.firstName}} {{order.orderCustomer.lastName}},
+
+ {% if instalment == false %} + Thank you for your order at {{ salesChannel.name }} (Number: {{order.orderNumber}}) on {{ order.orderDateTime|format_datetime("medium", "short", locale="en-GB") }}.
+ {% else %} + The next instalment cycle have arrived for the instalment order (OrderNumber: {{order.orderNumber}}) placed at the store {{ salesChannel.name }} on {{ order.orderDateTime|format_datetime("medium", "short", locale="en-GB") }}.
+ {% endif %} +
+ Information on your order:
+
+ + + + + + + + + + + {% for lineItem in order.lineItems|reverse %} + + + + + + + + {% endfor %} +
Pos.DescriptionQuantitiesPriceTotal
{{ loop.index }} + {{ lineItem.label|u.wordwrap(80) }}
+ {% if lineItem.payload.productNumber is defined %} Art. No.: {{ lineItem.payload.productNumber|u.wordwrap(80) }} {% endif %} +
{{ lineItem.quantity }}{{ lineItem.unitPrice|currency(currencyIsoCode) }}{{ lineItem.totalPrice|currency(currencyIsoCode) }}
+ + {% set delivery =order.deliveries.first %} + + + {% set displayRounded = order.totalRounding.interval != 0.01 or order.totalRounding.decimals != order.itemRounding.decimals %} + {% set decimals = order.totalRounding.decimals %} + {% set total = order.price.totalPrice %} + {% if displayRounded %} + {% set total = order.price.rawTotal %} + {% set decimals = order.itemRounding.decimals %} + {% endif %} +

+
+
+ {% if delivery is not null %} + Shipping costs: {{order.deliveries.first.shippingCosts.totalPrice|currency(currencyIsoCode) }}
+ {% endif %} + Net total: {{ order.amountNet|currency(currencyIsoCode) }}
+ + {% for calculatedTax in order.price.calculatedTaxes %} + {% if order.taxStatus is same as(\'net\') %}plus{% else %}including{% endif %} {{ calculatedTax.taxRate }}% VAT. {{ calculatedTax.tax|currency(currencyIsoCode) }}
+ {% endfor %} + {% if not displayRounded %}{% endif %}Total gross: {{ order.amountTotal|currency(currencyIsoCode,decimals=decimals) }}{% if not displayRounded %}{% endif %}
+ {% if displayRounded %} + Rounded total gross: {{ order.price.totalPrice|currency(currencyIsoCode,decimals=order.totalRounding.decimals) }}
+ {% endif %} + +
+ + Selected payment type: {% if paymentName is not empty %} {{ paymentName }} {% else %} {{ order.transactions|last.paymentMethod.name }} {% endif %}
+ {{ order.transactions|last.paymentMethod.description }}
+
+ + Comments:
+ {{ note|replace({"/ ": "
"}) | raw }}
+
+ + {% if "INSTALMENT_INVOICE" in novalnetDetails.paymentType or "INSTALMENT_DIRECT_DEBIT_SEPA" in novalnetDetails.paymentType %} + {% if instalmentInfo is not empty %} + + + + + + + + + + + {% for info in instalmentInfo.InstalmentDetails %} + {%set amount = info.amount/100 %} + + + + + + + {% endfor %} + +
S.NoNovalnet Transaction IDAmountNext Instalment Date
{{ loop.index }}{{ info.reference ? info.reference : "-" }}{{ amount ? amount|currency(currencyIsoCode): "-" }}{{ info.cycleDate ? info.cycleDate|date("d/m/Y"): "-" }}
+
+ {% endif %} + {% endif %} + + {% if delivery is not null %} + Selected shipping type: {{ delivery.shippingMethod.translated.name }}
+ {{ delivery.shippingMethod.translated.description }}
+
+ {% endif %} + + {% set billingAddress = order.addresses.get(order.billingAddressId) %} + Billing address:
+ {{ billingAddress.company }}
+ {{ billingAddress.firstName }} {{ billingAddress.lastName }}
+ {{ billingAddress.street }}
+ {{ billingAddress.zipcode }} {{ billingAddress.city }}
+ {{ billingAddress.country.name }}
+
+ {% if delivery is not null %} + Shipping address:
+ {{ delivery.shippingOrderAddress.company }}
+ {{ delivery.shippingOrderAddress.firstName }} {{ delivery.shippingOrderAddress.lastName }}
+ {{ delivery.shippingOrderAddress.street }}
+ {{ delivery.shippingOrderAddress.zipcode}} {{ delivery.shippingOrderAddress.city }}
+ {{ delivery.shippingOrderAddress.country.name }}
+
+ {% endif %} + {% if billingAddress.vatId %} + + Your VAT-ID: {{ billingAddress.vatId }} + In case of a successful order and if you are based in one of the EU countries, you will receive your goods exempt from turnover tax.
+ {% endif %} +
+ You can check the current status of your order on our website under "My account" - "My orders" anytime: {{ rawUrl("frontend.account.order.single.page", { "deepLinkCode": order.deepLinkCode }, salesChannel.domains|first.url) }} +
+ If you have any questions, do not hesitate to contact us. + +

+
+
'; + } + + /** + * Get English Plain Template + * + * @return string + */ + private function getPlainTemplateEn(): string + { + return '{% set currencyIsoCode = order.currency.isoCode %} + {{ order.orderCustomer.salutation.letterName }} {{order.orderCustomer.firstName}} {{order.orderCustomer.lastName}}, + + {% if instalment == false %} + Thank you for your order at {{ salesChannel.name }} (Number: {{order.orderNumber}}) on {{ order.orderDateTime|format_datetime("medium", "short", locale="en-GB") }}. + {% else %} + The next instalment cycle have arrived for the instalment order (OrderNumber: {{order.orderNumber}}) placed at the store {{ salesChannel.name }} on {{ order.orderDateTime|format_datetime("medium", "short", locale="en-GB") }}. + {% endif %} + + Information on your order: + + Pos. Art.No. Description Quantities Price Total + + {% for lineItem in order.lineItems|reverse %} + {{ loop.index }} {% if lineItem.payload.productNumber is defined %}{{ lineItem.payload.productNumber|u.wordwrap(80) }}{% endif %} {{ lineItem.label|u.wordwrap(80) }} {{ lineItem.quantity }} {{ lineItem.unitPrice|currency(currencyIsoCode) }} {{ lineItem.totalPrice|currency(currencyIsoCode) }} + {% endfor %} + + {% set delivery = order.deliveries.first %} + + {% set displayRounded = order.totalRounding.interval != 0.01 or order.totalRounding.decimals != order.itemRounding.decimals %} + {% set decimals = order.totalRounding.decimals %} + {% set total = order.price.totalPrice %} + {% if displayRounded %} + {% set total = order.price.rawTotal %} + {% set decimals = order.itemRounding.decimals %} + {% endif %} + + {% if delivery is not null %} + Shipping costs: {{order.deliveries.first.shippingCosts.totalPrice|currency(currencyIsoCode) }} + {% endif %} + Net total: {{ order.amountNet|currency(currencyIsoCode) }} + {% for calculatedTax in order.price.calculatedTaxes %} + {% if order.taxStatus is same as(\'net\') %}plus{% else %}including{% endif %} {{ calculatedTax.taxRate }}% VAT. {{ calculatedTax.tax|currency(currencyIsoCode) }}
+ {% endfor %} + Total gross: {{ order.amountTotal|currency(currencyIsoCode,decimals=decimals) }} + {% if displayRounded %} + Rounded total gross: {{ order.price.totalPrice|currency(currencyIsoCode,decimals=order.totalRounding.decimals) }} + {% endif %} + + Selected payment type: {% if paymentName is not empty %} {{ paymentName }} {% else %} {{ order.transactions|last.paymentMethod.name }} {% endif %} + {{ order.transactions|last.paymentMethod.description }} + + Comments: + {{ note|replace({"/ ": "
"}) | raw }} + + {% if "INSTALMENT_INVOICE" in novalnetDetails.paymentType or "INSTALMENT_DIRECT_DEBIT_SEPA" in novalnetDetails.paymentType %} + {% if instalmentInfo is not empty %} + S.No. Novalnet Transaction ID Amount Next Instalment Date + {% for info in instalmentInfo.InstalmentDetails %} + {%set amount = info.amount/100 %} + {{ loop.index }} {{ info.reference ? info.reference : "-" }} {{ amount ? amount|currency(currencyIsoCode): "-" }} {{ info.cycleDate ? info.cycleDate|date("d/m/Y"): "-" }} + {% endfor %} + {% endif %} + {% endif %} + + {% if delivery is not null %} + Selected shipping type: {{ delivery.shippingMethod.translated.name }} + {{ delivery.shippingMethod.translated.description }} + {% endif %} + + {% set billingAddress = order.addresses.get(order.billingAddressId) %} + Billing address: + {{ billingAddress.company }} + {{ billingAddress.firstName }} {{ billingAddress.lastName }} + {{ billingAddress.street }} + {{ billingAddress.zipcode }} {{ billingAddress.city }} + {{ billingAddress.country.name }} + + {% if delivery is not null %} + Shipping address: + {{ delivery.shippingOrderAddress.company }} + {{ delivery.shippingOrderAddress.firstName }} {{ delivery.shippingOrderAddress.lastName }} + {{ delivery.shippingOrderAddress.street }} + {{ delivery.shippingOrderAddress.zipcode}} {{ delivery.shippingOrderAddress.city }} + {{ delivery.shippingOrderAddress.country.name }} + + {% endif %} + + {% if billingAddress.vatId %} + Your VAT-ID: {{ billingAddress.vatId }} + In case of a successful order and if you are based in one of the EU countries, you will receive your goods exempt from turnover tax. + {% endif %} + + You can check the current status of your order on our website under "My account" - "My orders" anytime: {{ rawUrl("frontend.account.order.single.page", { "deepLinkCode": order.deepLinkCode }, salesChannel.domains|first.url) }} + If you have any questions, do not hesitate to contact us. + '; + } + + /** + * Get German HTML Template + * + * @return string + */ + private function getHtmlTemplateDe(): string + { + return '
+ + {% set currencyIsoCode = order.currency.isoCode %} + {{order.orderCustomer.salutation.letterName }} {{order.orderCustomer.firstName}} {{order.orderCustomer.lastName}},
+
+ {% if instalment == false %} + vielen Dank für Ihre Bestellung im {{ salesChannel.name }} (Nummer: {{order.orderNumber}}) am {{ order.orderDateTime|format_datetime("medium", "short", locale="de-DE") }}.
+ {% else %} + Für Ihre (Bestellung Nr: {{order.orderNumber}}) bei {{ salesChannel.name }}, ist die nächste Rate fällig. Bitte beachten Sie weitere Details unten am {{ order.orderDateTime|format_datetime("medium", "short", locale="de-DE") }}.
+ {% endif %} +
+ Informationen zu Ihrer Bestellung:
+
+ + + + + + + + + + + {% for lineItem in order.lineItems |reverse %} + + + + + + + + {% endfor %} +
Pos.BezeichnungMengePreisSumme
{{ loop.index }} + {{ lineItem.label|u.wordwrap(80) }}
+ {% if lineItem.payload.productNumber is defined %} Artikel-Nr: {{ lineItem.payload.productNumber|u.wordwrap(80) }} {% endif %} +
{{ lineItem.quantity }}{{ lineItem.unitPrice|currency(currencyIsoCode) }}{{ lineItem.totalPrice|currency(currencyIsoCode) }}
+ + {% set delivery =order.deliveries.first %} + + {% set displayRounded = order.totalRounding.interval != 0.01 or order.totalRounding.decimals != order.itemRounding.decimals %} + {% set decimals = order.totalRounding.decimals %} + {% set total = order.price.totalPrice %} + {% if displayRounded %} + {% set total = order.price.rawTotal %} + {% set decimals = order.itemRounding.decimals %} + {% endif %} +

+
+
+ {% if delivery is not null %} + Versandkosten: {{order.deliveries.first.shippingCosts.totalPrice|currency(currencyIsoCode) }}
+ {% endif %} + Gesamtkosten Netto: {{ order.amountNet|currency(currencyIsoCode) }}
+ {% for calculatedTax in order.price.calculatedTaxes %} + {% if order.taxStatus is same as(\'net\') %}zzgl{% else %}inkl{% endif %} {{ calculatedTax.taxRate }}% MWST. {{ calculatedTax.tax|currency(currencyIsoCode) }}
+ {% endfor %} + {% if not displayRounded %}{% endif %}Gesamtkosten Brutto: {{ order.amountTotal|currency(currencyIsoCode,decimals=decimals) }}{% if not displayRounded %}{% endif %}
+ {% if displayRounded %} + Gesamtkosten Brutto gerundet: {{ order.price.totalPrice|currency(currencyIsoCode,decimals=order.totalRounding.decimals) }}
+ {% endif %} +
+ Gewählte Zahlungsart: {% if paymentName is not empty %} {{ paymentName }} {% else %} {{ order.transactions|last.paymentMethod.name }} {% endif %}
+ {{ order.transactions|last.paymentMethod.description }}
+
+ + Kommentare:
+ {{ note|replace({"/ ": "
"}) | raw }}
+
+ + {% if "INSTALMENT_INVOICE" in novalnetDetails.paymentType or "INSTALMENT_DIRECT_DEBIT_SEPA" in novalnetDetails.paymentType %} + {% if instalmentInfo is not empty %} + + + + + + + + + + + {% for info in instalmentInfo.InstalmentDetails %} + {%set amount = info.amount/100 %} + + + + + + + {% endfor %} + +
S.NrNovalnet-Transaktions-IDBetragNächste Rate fällig am
{{ loop.index }}{{ info.reference ? info.reference : "-" }}{{ amount ? amount|currency(currencyIsoCode): "-" }}{{ info.cycleDate ? info.cycleDate|date("d/m/Y"): "-" }}
+
+ {% endif %} + {% endif %} + + {% if delivery is not null %} + Gewählte Versandtart: {{ delivery.shippingMethod.translated.name }}
+ {{ delivery.shippingMethod.translated.description }}
+
+ {% endif %} + + {% set billingAddress = order.addresses.get(order.billingAddressId) %} + Rechnungsaddresse:
+ {{ billingAddress.company }}
+ {{ billingAddress.firstName }} {{ billingAddress.lastName }}
+ {{ billingAddress.street }}
+ {{ billingAddress.zipcode }} {{ billingAddress.city }}
+ {{ billingAddress.country.name }}
+
+ + {% if delivery is not null %} + Lieferadresse:
+ {{ delivery.shippingOrderAddress.company }}
+ {{ delivery.shippingOrderAddress.firstName }} {{ delivery.shippingOrderAddress.lastName }}
+ {{ delivery.shippingOrderAddress.street }}
+ {{ delivery.shippingOrderAddress.zipcode}} {{ delivery.shippingOrderAddress.city }}
+ {{ delivery.shippingOrderAddress.country.name }}
+
+ + {% endif %} + + {% if billingAddress.vatId %} + Ihre Umsatzsteuer-ID: {{ billingAddress.vatId }} + Bei erfolgreicher Prüfung und sofern Sie aus dem EU-Ausland + bestellen, erhalten Sie Ihre Ware umsatzsteuerbefreit.
+ {% endif %} +
+
+ Den aktuellen Status Ihrer Bestellung können Sie auch jederzeit auf unserer Webseite im Bereich "Mein Konto" - "Meine Bestellungen" abrufen: {{ rawUrl("frontend.account.order.single.page", { "deepLinkCode": order.deepLinkCode }, salesChannel.domains|first.url) }} +
+ Für Rückfragen stehen wir Ihnen jederzeit gerne zur Verfügung. + +

+
+
'; + } + + /** + * Get German Plain Template + * + * @return string + */ + private function getPlainTemplateDe(): string + { + return '{% set currencyIsoCode = order.currency.isoCode %} + {{order.orderCustomer.salutation.letterName }} {{order.orderCustomer.firstName}} {{order.orderCustomer.lastName}}, + + {% if instalment == false %} + vielen Dank für Ihre Bestellung im {{ salesChannel.name }} (Nummer: {{order.orderNumber}}) am {{ order.orderDateTime|format_datetime("medium", "short", locale="de-DE") }}. + {% else %} + Für Ihre (Bestellung Nr: {{order.orderNumber}}) bei {{ salesChannel.name }}, ist die nächste Rate fällig. Bitte beachten Sie weitere Details unten am {{ order.orderDateTime|format_datetime("medium", "short", locale="de-DE")}}. + {% endif %} + + Informationen zu Ihrer Bestellung: + + Pos. Artikel-Nr. Beschreibung Menge Preis Summe + {% for lineItem in order.lineItems |reverse %} + {{ loop.index }} {% if lineItem.payload.productNumber is defined %}{{ lineItem.payload.productNumber|u.wordwrap(80) }}{% endif %} {{ lineItem.label|u.wordwrap(80) }} {{ lineItem.quantity }} {{ lineItem.unitPrice|currency(currencyIsoCode) }} {{ lineItem.totalPrice|currency(currencyIsoCode) }} + {% endfor %} + + {% set delivery =order.deliveries.first %} + + {% set displayRounded = order.totalRounding.interval != 0.01 or order.totalRounding.decimals != order.itemRounding.decimals %} + {% set decimals = order.totalRounding.decimals %} + {% set total = order.price.totalPrice %} + {% if displayRounded %} + {% set total = order.price.rawTotal %} + {% set decimals = order.itemRounding.decimals %} + {% endif %} + + {% if delivery is not null %} + Versandtkosten: {{order.deliveries.first.shippingCosts.totalPrice|currency(currencyIsoCode) }} + {% endif %} + Gesamtkosten Netto: {{ order.amountNet|currency(currencyIsoCode) }} + {% for calculatedTax in order.price.calculatedTaxes %} + {% if order.taxStatus is same as(\'net\') %}zzgl{% else %}inkl{% endif %} {{ calculatedTax.taxRate }}% MWST. {{ calculatedTax.tax|currency(currencyIsoCode) }}
+ {% endfor %} + Gesamtkosten Brutto: {{ order.amountTotal|currency(currencyIsoCode,decimals=decimals) }} + {% if displayRounded %} + Gesamtkosten Brutto gerundet: {{ order.price.totalPrice|currency(currencyIsoCode,decimals=order.totalRounding.decimals) }} + {% endif %} + + Gewählte Zahlungsart: {% if paymentName is not empty %} {{ paymentName }} {% else %} {{ order.transactions|last.paymentMethod.name }} {% endif %} + {{ order.transactions|last.paymentMethod.description }} + + Kommentare: + {{ note|replace({"/ ": "
"}) | raw }} + + {% if "INSTALMENT_INVOICE" in novalnetDetails.paymentType or "INSTALMENT_DIRECT_DEBIT_SEPA" in novalnetDetails.paymentType %} + {% if instalmentInfo is not empty %} + S.Nr Novalnet-Transaktions-ID Betrag Nächste Rate fällig am + {% for info in instalmentInfo.InstalmentDetails %} + {%set amount = info.amount/100 %} + {{ loop.index }} {{ info.reference ? info.reference : "-" }} {{ amount ? amount|currency(currencyIsoCode): "-" }} {{ info.cycleDate ? info.cycleDate|date("d/m/Y"): "-" }} + {% endfor %} + {% endif %} + {% endif %} + + {% if delivery is not null %} + Gewählte Versandtart: {{ delivery.shippingMethod.translated.name }} + {{ delivery.shippingMethod.translated.description }} + {% endif %} + + {% set billingAddress = order.addresses.get(order.billingAddressId) %} + Rechnungsadresse: + {{ billingAddress.company }} + {{ billingAddress.firstName }} {{ billingAddress.lastName }} + {{ billingAddress.street }} + {{ billingAddress.zipcode }} {{ billingAddress.city }} + {{ billingAddress.country.name }} + + {% if delivery is not null %} + Lieferadresse: + {{ delivery.shippingOrderAddress.company }} + {{ delivery.shippingOrderAddress.firstName }} {{ delivery.shippingOrderAddress.lastName }} + {{ delivery.shippingOrderAddress.street }} + {{ delivery.shippingOrderAddress.zipcode}} {{ delivery.shippingOrderAddress.city }} + {{ delivery.shippingOrderAddress.country.name }} + + {% endif %} + + {% if billingAddress.vatId %} + Ihre Umsatzsteuer-ID: {{ billingAddress.vatId }} + Bei erfolgreicher Prüfung und sofern Sie aus dem EU-Ausland + bestellen, erhalten Sie Ihre Ware umsatzsteuerbefreit. + {% endif %} + + Den aktuellen Status Ihrer Bestellung können Sie auch jederzeit auf unserer Webseite im Bereich "Mein Konto" - "Meine Bestellungen" abrufen: {{ rawUrl("frontend.account.order.single.page", { "deepLinkCode": order.deepLinkCode }, salesChannel.domains|first.url) }} + Für Rückfragen stehen wir Ihnen jederzeit gerne zur Verfügung. + + '; + } + + /** + * Get Mail template entity + * + * @return MailTemplateEntity|null + */ + private function getMailTemplateType(): ?MailTemplateEntity + { + $criteria = new Criteria(); + $criteria->addFilter(new EqualsFilter('mailTemplateType.technicalName', 'novalnet_order_confirmation_mail')); + return $this->mailTemplateRepo->search($criteria, $this->context)->first(); + } +} diff --git a/src/Migration/Migration1678945880AddNovalnetPaymentTable.php b/src/Migration/Migration1678945880AddNovalnetPaymentTable.php new file mode 100755 index 0000000..7dff95b --- /dev/null +++ b/src/Migration/Migration1678945880AddNovalnetPaymentTable.php @@ -0,0 +1,44 @@ +executeUpdate(' + CREATE TABLE IF NOT EXISTS `novalnet_transaction_details` ( + `id` binary(16) NOT NULL, + `tid` BIGINT(20) UNSIGNED DEFAULT NULL COMMENT "Novalnet Transaction Reference ID", + `payment_type` VARCHAR(50) DEFAULT NULL COMMENT "Executed Payment type of this order", + `amount` INT(11) UNSIGNED DEFAULT 0 COMMENT "Transaction amount", + `currency` VARCHAR(11) DEFAULT NULL COMMENT "Transaction currency", + `paid_amount` INT(11) UNSIGNED DEFAULT 0 COMMENT "Paid amount", + `refunded_amount` INT(11) UNSIGNED DEFAULT 0 COMMENT "Refunded amount", + `gateway_status` VARCHAR(30) DEFAULT NULL COMMENT "Novalnet transaction status", + `order_no` VARCHAR(64) DEFAULT NULL COMMENT "Order ID from shop", + `customer_no` VARCHAR(255) COMMENT "Customer Number from shop", + `additional_details` LONGTEXT DEFAULT NULL COMMENT "Additional details", + `token_info` VARCHAR(255) DEFAULT NULL COMMENT "Transaction Token", + `created_at` datetime DEFAULT CURRENT_TIMESTAMP COMMENT "Created date", + `updated_at` datetime DEFAULT CURRENT_TIMESTAMP COMMENT "Updated date", + PRIMARY KEY (`id`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT="Novalnet Transaction History" + '); + } + + public function updateDestructive(Connection $connection): void + { + // implement update destructive + } +} diff --git a/src/NovalnetPayment.php b/src/NovalnetPayment.php new file mode 100755 index 0000000..b0ef8f1 --- /dev/null +++ b/src/NovalnetPayment.php @@ -0,0 +1,102 @@ +container, $installContext->getContext()))->install(); + parent::install($installContext); + } + + /** + * Plugin update process + * + * @param UpdateContext $updateContext + */ + public function update(UpdateContext $updateContext): void + { + (new PaymentMethodInstaller($this->container, $updateContext->getContext()))->update(); + parent::update($updateContext); + } + + /** + * Plugin uninstall process + * + * @param UninstallContext $uninstallContext + */ + public function uninstall(UninstallContext $uninstallContext): void + { + $uninstaller = new PaymentMethodInstaller($this->container, $uninstallContext->getContext()); + $uninstaller->uninstall(); + + + if (!$uninstallContext->keepUserData()) { + $uninstaller->removeConfiguration(); + $uninstaller->deleteMailSettings(); + } + parent::uninstall($uninstallContext); + } + + /** + * Plugin activate process + * + * @param ActivateContext $activateContext + */ + public function activate(ActivateContext $activateContext): void + { + (new PaymentMethodInstaller($this->container, $activateContext->getContext()))->activate(); + parent::activate($activateContext); + } + + /** + * Plugin deactivate process + * + * @param DeactivateContext $deactivateContext + */ + public function deactivate(DeactivateContext $deactivateContext): void + { + (new PaymentMethodInstaller($this->container, $deactivateContext->getContext()))->deactivate(); + parent::deactivate($deactivateContext); + } +} diff --git a/src/Resources/app/administration/src/acl/index.js b/src/Resources/app/administration/src/acl/index.js new file mode 100755 index 0000000..c2d0d8e --- /dev/null +++ b/src/Resources/app/administration/src/acl/index.js @@ -0,0 +1,67 @@ +Shopware.Service('privileges') + .addPrivilegeMappingEntry({ + category: 'permissions', + parent: 'orders', + key: 'novalnet_extension', + roles: { + viewer: { + privileges: [ + 'novalnet_transaction_details:read', + ], + dependencies: [], + }, + editor: { + privileges: [ + 'novalnet_transaction_details:update', + 'order_transaction:read', + 'order_transaction:update', + ], + dependencies: [ + 'novalnet_extension.viewer', + 'order.editor', + ], + }, + creator: { + privileges: [ + 'novalnet_transaction_details:create', + ], + dependencies: [ + 'novalnet_extension.viewer', + 'novalnet_extension.editor', + ], + }, + deleter: { + privileges: [ + 'novalnet_transaction_details:delete', + ], + dependencies: [ + 'novalnet_extension.viewer', + ], + }, + }, + }); +Shopware.Service('privileges').addPrivilegeMappingEntry({ + category: 'permissions', + parent: 'novalnet_payment', + key: 'novalnet_payment', + roles: { + viewer: { + privileges: [ + 'system_config:read', + 'sales_channel:read', + ], + dependencies: [], + }, + editor: { + privileges: [ + 'system_config:update', + 'system_config:create', + 'system_config:delete', + 'sales_channel:update', + ], + dependencies: [ + 'novalnet_payment.viewer', + ], + }, + }, +}); diff --git a/src/Resources/app/administration/src/core/service/api/novalnet-payment-api-credentials.service.js b/src/Resources/app/administration/src/core/service/api/novalnet-payment-api-credentials.service.js new file mode 100755 index 0000000..6f5833b --- /dev/null +++ b/src/Resources/app/administration/src/core/service/api/novalnet-payment-api-credentials.service.js @@ -0,0 +1,228 @@ +const ApiService = Shopware.Classes.ApiService; + +class NovalPaymentApiCredentialsService extends ApiService { + constructor(httpClient, loginService, apiEndpoint = 'novalnet-payment') { + super(httpClient, loginService, apiEndpoint); + } + + validateApiCredentials(clientId, accessKey) { + const headers = this.getBasicHeaders(); + + return this.httpClient + .post( + `_action/${this.getApiBasePath()}/validate-api-credentials`, + { + clientId, + accessKey + }, + { + headers: this.getBasicHeaders() + } + ) + .then((response) => { + return ApiService.handleResponse(response); + }); + } + + getNovalnetAmount(orderNumber){ + const headers = this.getBasicHeaders(); + + return this.httpClient + .post( + `_action/${this.getApiBasePath()}/transaction-amount`, + { + orderNumber + }, + { + headers: this.getBasicHeaders() + } + ) + .then((response) => { + return ApiService.handleResponse(response); + }); + } + + refundPayment(orderNumber, refundAmount, reason, instalmentCycleTid){ + const headers = this.getBasicHeaders(); + + return this.httpClient + .post( + `_action/${this.getApiBasePath()}/refund-amount`, + { + orderNumber, + refundAmount, + reason, + instalmentCycleTid + }, + { + headers: this.getBasicHeaders() + } + ) + .then((response) => { + return ApiService.handleResponse(response); + }); + } + + managePayment(orderNumber, status){ + const headers = this.getBasicHeaders(); + + return this.httpClient + .post( + `_action/${this.getApiBasePath()}/manage-payment`, + { + orderNumber: orderNumber, + status: status + }, + { + headers: this.getBasicHeaders() + } + ) + .then((response) => { + return ApiService.handleResponse(response); + }); + } + + instalmentCancel(orderNumber, cancelType){ + const headers = this.getBasicHeaders(); + + return this.httpClient + .post( + `_action/${this.getApiBasePath()}/instalment-cancel`, + { + orderNumber, + cancelType + }, + { + headers: this.getBasicHeaders() + } + ) + .then((response) => { + return ApiService.handleResponse(response); + }); + } + + BookOrderAmount(orderNumber, bookAmount) { + const apiRoute = `_action/${this.getApiBasePath()}/book-amount`; + + return this.httpClient.post( + apiRoute, + { + orderNumber, + bookAmount + }, + { + headers: this.getBasicHeaders() + } + ).then((response) => { + return ApiService.handleResponse(response); + }); + } + + getNovalnetPaymentMethod (orderNumber) { + const apiRoute = `_action/${this.getApiBasePath()}/novalnet-paymentmethod`; + + return this.httpClient.post( + apiRoute, + { + orderNumber + + }, + { + headers: this.getBasicHeaders() + } + ).then((response) => { + return ApiService.handleResponse(response); + }); + } + + configureWebhookUrl(url, productActivationKey, paymentAccessKey) { + const apiRoute = `_action/${this.getApiBasePath()}/webhook-url-configure`; + + return this.httpClient.post( + apiRoute, + { + url, + productActivationKey, + paymentAccessKey + }, + { + headers: this.getBasicHeaders() + } + ).then((response) => { + return ApiService.handleResponse(response); + }); + } + + novalnetPayment(shippingaddress, billingaddress, amount, currency, customer) { + const apiRoute = `_action/${this.getApiBasePath()}/novalnet-payment`; + + return this.httpClient.post( + apiRoute, + { + shippingaddress, + billingaddress, + amount, + currency, + customer + }, + { + headers: this.getBasicHeaders() + } + ).then((response) => { + return ApiService.handleResponse(response); + }); + } + + paymentDetails(paymentSelected) { + const apiRoute = `_action/${this.getApiBasePath()}/novalnet-select-payment`; + + return this.httpClient.post( + apiRoute, + { + paymentSelected + }, + { + headers: this.getBasicHeaders() + } + ).then((response) => { + return ApiService.handleResponse(response); + }); + } + + paymentValue(value, customer) { + const apiRoute = `_action/${this.getApiBasePath()}/payment-value-data`; + + return this.httpClient.post( + apiRoute, + { + value, + customer + }, + { + headers: this.getBasicHeaders() + } + ).then((response) => { + return ApiService.handleResponse(response); + }); + } + + getShopVersion() { + const apiRoute = `_action/${this.getApiBasePath()}/shop-version`; + + return this.httpClient.post( + apiRoute, + { + + }, + { + headers: this.getBasicHeaders() + } + ).then((response) => { + return ApiService.handleResponse(response); + }); + } + + +} + +export default NovalPaymentApiCredentialsService; diff --git a/src/Resources/app/administration/src/init/api-service.init.js b/src/Resources/app/administration/src/init/api-service.init.js new file mode 100755 index 0000000..d540c7e --- /dev/null +++ b/src/Resources/app/administration/src/init/api-service.init.js @@ -0,0 +1,11 @@ +import NovalPaymentApiCredentialsService + from '../../src/core/service/api/novalnet-payment-api-credentials.service'; + +const { Application } = Shopware; + +Application.addServiceProvider('NovalPaymentApiCredentialsService', (container) => { + const initContainer = Application.getContainer('init'); + + return new NovalPaymentApiCredentialsService(initContainer.httpClient, container.loginService); +}); + diff --git a/src/Resources/app/administration/src/main.js b/src/Resources/app/administration/src/main.js new file mode 100755 index 0000000..dcbc5ea --- /dev/null +++ b/src/Resources/app/administration/src/main.js @@ -0,0 +1,3 @@ +import './module/novalnet-payment'; +import './init/api-service.init'; +import './acl'; diff --git a/src/Resources/app/administration/src/module/novalnet-payment/components/novalnet-payment-credentials/index.js b/src/Resources/app/administration/src/module/novalnet-payment/components/novalnet-payment-credentials/index.js new file mode 100755 index 0000000..d585e13 --- /dev/null +++ b/src/Resources/app/administration/src/module/novalnet-payment/components/novalnet-payment-credentials/index.js @@ -0,0 +1,263 @@ +import template from './novalnet-payment-credentials.html.twig'; +import './novalnet-payment-credentials.scss'; + +const { Component, Mixin } = Shopware; +const { Criteria } = Shopware.Data; +const { object, types } = Shopware.Utils; + +Component.register('novalnet-payment-credentials', { + template, + + mixins: [ + Mixin.getByName('notification'), + Mixin.getByName('sw-inline-snippet') + ], + + name: 'NovalnetPaymentCredentials', + icon: 'default-action-settings', + + props: { + actualConfigData: { + type: Object, + required: true + }, + allConfigs: { + type: Object, + required: true + }, + selectedSalesChannelId: { + required: true + }, + domain: { + type: String, + required: true, + default: '' + } + }, + + data() { + const url = window.location .protocol + "//" + window.location.host + window.location.pathname; + const generatedUrl = url.split("/admin").join(""); + return { + allConfigs: {}, + config: {}, + tariffOptions: [], + actualConfigData: {}, + shouldDisable: false, + projectMode: false, + apiActivationKey: '', + paymentAccessKey: '', + tariffId: '', + isLoading: false, + isRequested : '', + showMessage: false, + buttonLoad: false, + NovalnetPaymentCallBackUrl : generatedUrl + "/novalnet/callback", + generalInformation: this.$tc('novalnet-payment.module.generalInfo'), + PaymentConfiguration: this.$tc('novalnet-payment.module.PaymentConfiguration') + } + }, + + inject: [ + 'repositoryFactory', + 'NovalPaymentApiCredentialsService', + 'systemConfigApiService', + 'acl', + ], + + watch: { + actualConfigData: { + handler(configData) { + if (!configData) { + return; + } + + this.$emit('input', configData); + }, + deep: true + } + }, + + computed: { + actualConfigData: { + get() { + return this.allConfigs[this.selectedSalesChannelId]; + }, + set(config) { + this.allConfigs = { + ...this.allConfigs, + [this.selectedSalesChannelId]: config + }; + } + }, + }, + + created() { + this.createdComponent(); + }, + + updated() { + this.createdComponent(); + }, + + methods: { + checkTextFieldInheritance(value) { + if (typeof value !== 'string') { + return true; + } + + return value.length <= 0; + }, + + checkBoolFieldInheritance(value) { + return typeof value !== 'boolean'; + }, + + checkNumberFieldInheritance(value) { + return typeof value !== 'int'; + }, + onCheckApi() { + if(event.target.name === 'NovalnetPayment.settings.clientId') { + this.apiActivationKey = this.actualConfigData['NovalnetPayment.settings.clientId'] = event.target.value; + } else if(event.target.name === 'NovalnetPayment.settings.accessKey') { + this.paymentAccessKey = this.actualConfigData['NovalnetPayment.settings.accessKey'] = event.target.value; + } + + if (this.apiActivationKey === '' && this.paymentAccessKey === '') + { + + this.createNotificationError({ + title: this.$tc('novalnet-payment.settingForm.titleError'), + message: this.$tc('novalnet-payment.settingForm.apiFailureMessage') + }); + + return; + } + + this.isRequested = ''; + this.showMessage = true; + this.createdComponent(); + }, + + createdComponent() { + const me = this; + if(this.actualConfigData !== undefined && this.isRequested !== this.selectedSalesChannelId) + { + this.isRequested = this.selectedSalesChannelId; + this.apiActivationKey = this.actualConfigData['NovalnetPayment.settings.clientId'] || this.allConfigs.null['NovalnetPayment.settings.clientId']; + this.paymentAccessKey = (this.actualConfigData['NovalnetPayment.settings.accessKey'] || this.allConfigs.null['NovalnetPayment.settings.accessKey']); + if(this.apiActivationKey !== undefined && this.apiActivationKey !== '' && this.paymentAccessKey !== undefined && this.paymentAccessKey !== '' ) + { + this.apiActivationKey = this.apiActivationKey.replace(/\s/g, ""); + this.paymentAccessKey = this.paymentAccessKey.replace(/\s/g, ""); + this.isLoading = true; + this.NovalPaymentApiCredentialsService.validateApiCredentials(this.apiActivationKey, this.paymentAccessKey).then((response) => { + const status = response.serverResponse.result.status_code; + this.isLoading = false; + if(status !== 100) + { + if(this.showMessage === true) + { + this.createNotificationError({ + title: this.$tc('novalnet-payment.settingForm.titleError'), + message: response.serverResponse.result.status_text, + autoClose: true + }); + } + this.showMessage = false; + + } else { + me.tariffOptions = []; + response.tariffResponse.forEach(((tariff) => { + + this.actualConfigData['NovalnetPayment.settings.clientKey'] = response.serverResponse.merchant.client_key; + + me.tariffOptions.push({ + value: tariff.id, + label: tariff.name + }); + + if(this.tariffId === undefined || this.tariffId === '') + { + this.tariffId = tariff.id; + } + + if(this.showMessage === true) + { + this.createNotificationSuccess({ + title: this.$tc('novalnet-payment.settingForm.titleSuccess'), + message: this.$tc('novalnet-payment.settingForm.successMessage'), + autoClose: true + }); + } + + this.showMessage = false; + if(response.serverResponse.merchant.test_mode === 1) + { + this.projectMode = true; + } + })); + + } + + }).catch((errorResponse) => { + this.isLoading = false; + }); + } + } + }, + + configureWebhookUrl() { + const productActivationKey = this.apiActivationKey || this.actualConfigData['NovalnetPayment.settings.clientKey']; + const accessKey = this.paymentAccessKey || this.actualConfigData['NovalnetPayment.settings.accessKey']; + + if ( productActivationKey === undefined || productActivationKey === '' || accessKey === undefined || accessKey === '') + { + this.createNotificationError({ + title: this.$tc('novalnet-payment.settingForm.titleError'), + message: this.$tc('novalnet-payment.settingForm.apiFailureMessage') + }); + + return; + } + + if( this.NovalnetPaymentCallBackUrl) + { + if (/^(http|https):\/\/[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,}(:[0-9]{1,5})?(\/.*)?$/i.test(this.NovalnetPaymentCallBackUrl) === false) + { + this.createNotificationError({ + message: this.$tc('novalnet-payment.settingForm.webhookUrlFailure') + }); + return false; + } + + this.buttonLoad = true; + + this.NovalPaymentApiCredentialsService.configureWebhookUrl(this.NovalnetPaymentCallBackUrl, productActivationKey, accessKey).then((response) => { + + if(response.result.status !== undefined && response.result.status != null && response.result.status !== '' && response.result.status === 'SUCCESS') + { + this.createNotificationSuccess({ + message: this.$tc('novalnet-payment.settingForm.webhookUrlSuccess') + }); + } else if(response.result.status_text !== undefined && response.result.status_text != null && response.result.status_text !== '') { + this.createNotificationError({ + message: response.result.status_text, + }); + } else { + this.createNotificationError({ + message: this.$tc('novalnet-payment.settingForm.webhookUrlFailure') + }); + } + this.buttonLoad = false; + + }).catch((errorResponse) => { + this.buttonLoad = false; + }); + } + } + + + } + +}); diff --git a/src/Resources/app/administration/src/module/novalnet-payment/components/novalnet-payment-credentials/novalnet-payment-credentials.html.twig b/src/Resources/app/administration/src/module/novalnet-payment/components/novalnet-payment-credentials/novalnet-payment-credentials.html.twig new file mode 100755 index 0000000..3d9f386 --- /dev/null +++ b/src/Resources/app/administration/src/module/novalnet-payment/components/novalnet-payment-credentials/novalnet-payment-credentials.html.twig @@ -0,0 +1,174 @@ +{% block novalnet_payment_content_card_channel_config_credentials %} + +
+ + + {% block novalnet_payment_content_card_channel_config_credentials_card_container %} + + + {% block novalnet_payment_content_card_channel_config_credentials_card_container_settings %} +
+ + {{ $tc('novalnet-payment.module.projectInfo') }} + + +
+
+
+
+
+ + {% block novalnet_payment_content_card_channel_config_credentials_card_container_settings_client_id %} + + + + + + + {% endblock %} + {% block novalnet_payment_content_card_channel_config_credentials_card_container_settings_break %} +
+ {% endblock %} + + {% block novalnet_payment_content_card_channel_config_credentials_card_container_settings_client_secret %} + + + + + + + + + + {% endblock %} +
+ {% endblock %} + + {% block novalnet_payment_content_card_loading %} + + {% endblock %} + +
+ {% endblock %} +
+ {% endblock %} + {% block novalnet_payment_content_card_channel_config_merchant_credentials %} + + {% block novalnet_payment_content_card_channel_config_merchant_credentials_card_container %} + + {% block novalnet_payment_content_card_channel_config_merchant_credentials_card_container_settings %} +
+ {% block novalnet_payment_content_card_channel_config_merchant_credentials_card_container_settings_ip %} + + + + + + {{ $tc('novalnet-payment.settingForm.merchantSettings.callbackUrl.button') }} + + + + + + + + {% endblock %} +
+ {% endblock %} +
+ {% endblock %} +
+
+
+{% endblock %} diff --git a/src/Resources/app/administration/src/module/novalnet-payment/components/novalnet-payment-credentials/novalnet-payment-credentials.scss b/src/Resources/app/administration/src/module/novalnet-payment/components/novalnet-payment-credentials/novalnet-payment-credentials.scss new file mode 100755 index 0000000..b60743e --- /dev/null +++ b/src/Resources/app/administration/src/module/novalnet-payment/components/novalnet-payment-credentials/novalnet-payment-credentials.scss @@ -0,0 +1,8 @@ +.novalnet_payment-settings-project{ + font-size: 14px; + margin-bottom: 8px; +} + +.novalnet-payment-callback-field{ + margin-bottom: 15px; +} diff --git a/src/Resources/app/administration/src/module/novalnet-payment/components/novalnet-payment-settings-icon/index.js b/src/Resources/app/administration/src/module/novalnet-payment/components/novalnet-payment-settings-icon/index.js new file mode 100755 index 0000000..41d027a --- /dev/null +++ b/src/Resources/app/administration/src/module/novalnet-payment/components/novalnet-payment-settings-icon/index.js @@ -0,0 +1,7 @@ +import template from './novalnet-payment-settings-icon.html.twig'; + +const { Component } = Shopware; + +Component.register('novalnet-payment-settings-icon', { + template +}); diff --git a/src/Resources/app/administration/src/module/novalnet-payment/components/novalnet-payment-settings-icon/novalnet-payment-settings-icon.html.twig b/src/Resources/app/administration/src/module/novalnet-payment/components/novalnet-payment-settings-icon/novalnet-payment-settings-icon.html.twig new file mode 100755 index 0000000..803d615 --- /dev/null +++ b/src/Resources/app/administration/src/module/novalnet-payment/components/novalnet-payment-settings-icon/novalnet-payment-settings-icon.html.twig @@ -0,0 +1,3 @@ +{% block novalnet_payment_settings_icon %} + +{% endblock %} diff --git a/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/component/sw-order-create-details-payment/index.js b/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/component/sw-order-create-details-payment/index.js new file mode 100755 index 0000000..7919073 --- /dev/null +++ b/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/component/sw-order-create-details-payment/index.js @@ -0,0 +1,187 @@ +import template from './sw-order-create-details-payment.twig'; + + +/** + * @package customer-order + */ +const { Component, Mixin, Filter, Context } = Shopware; +const Criteria = Shopware.Data.Criteria; +const { currency } = Shopware.Utils.format; + + +Component.register('sw-order-create-details-payment', { + template, + + inject: [ + 'NovalPaymentApiCredentialsService', + 'repositoryFactory', + ], + + mixins: [ + Mixin.getByName('notification'), + ], + + props: { + customer: { + type: Object, + }, + + cartPrice: { + type: Object, + }, + + currency: { + type: Object, + }, + isLoading: { + type: Boolean, + required: true, + } + }, + + data() { + return { + isLoading : false, + loaded : false, + shouldDisable : true, + iframe: { + src: '' + }, + paymentformurl : '', + novalnetPayment : false + + }; + }, + + watch: { + + customer: { + deep: true, + handler() { + + if(this.customer == null){ + return; + } + + const paymentRepository = this.repositoryFactory.create('payment_method'); + const paymentCriteria = new Criteria(1, 1); + paymentCriteria.addFilter(Criteria.equals('id', this.customer.salesChannel.paymentMethodId)); + paymentRepository.search(paymentCriteria, Context.api).then((searchResult) => { + const payment = searchResult.first(); + if(!payment){ + return + } + + if( (payment.customFields != null) && (payment.customFields.novalnet_payment_method_name == 'novalnetpay')){ + + if(this.currency == null){ + this.createNotificationError({ + title: this.$tc('novalnet-payment.settingForm.titleError'), + message: this.$tc('novalnet-payment.settingForm.currencyFailureMessage') + }); + + return; + } + + if(this.cartPrice != null && (this.cartPrice.totalPrice == 0 || this.cartPrice.totalPrice == null) ){ + this.createNotificationError({ + title: this.$tc('novalnet-payment.settingForm.titleError'), + message: this.$tc('novalnet-payment.settingForm.lineitemFailureMessage') + }); + + return; + } + + this.novalnetPayment = true; + + let billingaddress = ''; + let shippingaddress = ''; + + if( (this.customer.billingAddress !== null) || (this.customer.defaultBillingAddress !== null)){ + + billingaddress = this.customer.billingAddress ? this.customer.billingAddress : this.customer.defaultBillingAddress; + } + + if( (this.customer.shippingAddress !== null) || (this.customer.defaultShippingAddress !== null)){ + + shippingaddress = this.customer.shippingAddress ? this.customer.shippingAddress : this.customer.defaultShippingAddress; + } + let me = this.NovalPaymentApiCredentialsService; + let customerPaymentDetails = this.customer; + + this.NovalPaymentApiCredentialsService.novalnetPayment(shippingaddress, billingaddress, this.cartPrice.totalPrice , this.currency.isoCode, this.customer ).then((payment) => { + + if(payment != '' && payment != undefined) + { + if(payment.result.status =='SUCCESS' && payment.result.redirect_url != '' && payment.result.redirect_url != undefined ){ + + this.iframe.src = payment.result.redirect_url; + + this.loaded = true; + const recaptchaScript = document.createElement('script'); + recaptchaScript.setAttribute('src', 'https://cdn.novalnet.de/js/pv13/checkout.js?' + new Date().getTime()); + recaptchaScript.type = 'text/javascript'; + document.head.appendChild(recaptchaScript); + this.paymentformurl = recaptchaScript; + this.paymentformurl.addEventListener('load', ()=>{ + this.onWindowLoad(me, customerPaymentDetails); + } ); + } + } + + }).catch((errorResponse) => { + this.createNotificationError({ + message: `${errorResponse.title}: ${errorResponse.message}` + }); + }); + } + + }); + }, + immediate: true + + } + + }, + + + methods: { + onWindowLoad(e, customer) { + const paymentForm = new NovalnetPaymentForm(); + const submit = document.querySelector('.sw-button-process'); + const keyname = 'ordernovalnetpayment'; + let paymentType = ''; + let request = { + iframe: '#adminnovalnetPaymentiframe', + initForm: { + uncheckPayments: true, + showButton: false, + } + }; + + paymentForm.initiate(request); + paymentForm.validationResponse((data) => { + paymentForm.initiate(request); + }); + + paymentForm.selectedPayment((function(selectPaymentData) { + paymentType = selectPaymentData.payment_details.type; + + })); + + submit.addEventListener('click', (event) => { + event.preventDefault(); + event.stopImmediatePropagation(); + paymentForm.getPayment((function(paymentDetails) { + let value = JSON.stringify(paymentDetails); + e.paymentValue(value, customer).then((payment) => { + }); + })); + }); + + }, + + }, + + +}); diff --git a/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/component/sw-order-create-details-payment/sw-order-create-details-payment.twig b/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/component/sw-order-create-details-payment/sw-order-create-details-payment.twig new file mode 100755 index 0000000..d77de53 --- /dev/null +++ b/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/component/sw-order-create-details-payment/sw-order-create-details-payment.twig @@ -0,0 +1,16 @@ +{% block sw_order_create_detail_payment_info %} + + + +{% endblock %} diff --git a/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/component/sw-order-general-info/index.js b/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/component/sw-order-general-info/index.js new file mode 100755 index 0000000..cd306d9 --- /dev/null +++ b/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/component/sw-order-general-info/index.js @@ -0,0 +1,79 @@ +import template from './sw-order-general-info.html.twig'; + + +/** + * @package customer-order + */ + +const { Component, Mixin } = Shopware; +const { Criteria } = Shopware.Data; + + +Component.override('sw-order-general-info', { + template, + + inject: [ + 'NovalPaymentApiCredentialsService', + 'repositoryFactory', + ], + + mixins: [ + Mixin.getByName('notification'), + ], + + props: { + order: { + type: Object, + required: true, + }, + }, + + data() { + return { + paymentMethod : '' + }; + }, + + watch: { + + order: { + deep: true, + handler() { + if (this.order == '') { + return; + } + + if (this.order.transactions.last().paymentMethod.customFields != null && this.order.transactions.last().paymentMethod.customFields.novalnet_payment_method_name != undefined && this.order.transactions.last().paymentMethod.customFields.novalnet_payment_method_name == "novalnetpay") { + + this.NovalPaymentApiCredentialsService.getNovalnetPaymentMethod(this.order.orderNumber).then((payment) => { + if(payment != undefined && payment != null) + { + if(payment.paymentName != undefined && payment.paymentName != null){ + this.paymentMethod = payment.paymentName; + } + else { + this.paymentMethod = this.order.transactions.last().paymentMethod.translated.distinguishableName; + } + } + else { + this.paymentMethod = this.order.transactions.last().paymentMethod.translated.distinguishableName; + } + }).catch((errorResponse) => { + this.createNotificationError({ + message: `${errorResponse.title}: ${errorResponse.message}` + }); + }); + } + else { + + this.paymentMethod = this.order.transactions.last().paymentMethod.translated.distinguishableName; + } + }, + immediate: true + } + } + + + + +}); diff --git a/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/component/sw-order-general-info/sw-order-general-info.html.twig b/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/component/sw-order-general-info/sw-order-general-info.html.twig new file mode 100755 index 0000000..183244b --- /dev/null +++ b/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/component/sw-order-general-info/sw-order-general-info.html.twig @@ -0,0 +1,18 @@ +{% block sw_order_detail_base_general_info_summary_sub_description %} +
+ {{ $tc('sw-order.generalTab.info.summary.on') }} + {{ order.orderDateTime | date({ + hour: '2-digit', + minute: '2-digit', + day: '2-digit', + month: '2-digit', + year: 'numeric' + }) }} + {{ $tc('sw-order.generalTab.info.summary.with') }} + {{ paymentMethod }} + +
+{% endblock %} diff --git a/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/component/sw-order-user-card/index.js b/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/component/sw-order-user-card/index.js new file mode 100755 index 0000000..6a9c365 --- /dev/null +++ b/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/component/sw-order-user-card/index.js @@ -0,0 +1,83 @@ +import template from './sw-order-user-card.html.twig'; + + +/** + * @package customer-order + */ + +const { Component, Mixin } = Shopware; +const { Criteria } = Shopware.Data; + + +Component.override('sw-order-user-card', { + template, + + inject: [ + 'NovalPaymentApiCredentialsService', + 'repositoryFactory', + ], + + mixins: [ + Mixin.getByName('notification'), + ], + + props: { + currentOrder: { + type: Object, + required: true, + }, + isLoading: { + type: Boolean, + required: true, + } + }, + + data() { + return { + paymentMethod : '' + }; + }, + + watch: { + + currentOrder: { + deep: true, + handler() { + if (this.currentOrder == '') { + return; + } + + if (this.currentOrder.transactions.last().paymentMethod.customFields != null && this.currentOrder.transactions.last().paymentMethod.customFields.novalnet_payment_method_name != undefined && this.currentOrder.transactions.last().paymentMethod.customFields.novalnet_payment_method_name == "novalnetpay"){ + + this.NovalPaymentApiCredentialsService.getNovalnetPaymentMethod(this.currentOrder.orderNumber).then((payment) => { + if(payment != undefined && payment != null) + { + if(payment.paymentName != undefined && payment.paymentName != null){ + this.paymentMethod = payment.paymentName; + } + else { + this.paymentMethod = this.currentOrder.transactions.last().paymentMethod.translated.distinguishableName; + } + } + else { + this.paymentMethod = this.currentOrder.transactions.last().paymentMethod.translated.distinguishableName; + } + + }).catch((errorResponse) => { + this.createNotificationError({ + message: `${errorResponse.title}: ${errorResponse.message}` + }); + }); + } + else { + this.paymentMethod = this.currentOrder.transactions.last().paymentMethod.translated.distinguishableName; + } + }, + immediate: true + } + } + + + + +}); diff --git a/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/component/sw-order-user-card/sw-order-user-card.html.twig b/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/component/sw-order-user-card/sw-order-user-card.html.twig new file mode 100755 index 0000000..613eebe --- /dev/null +++ b/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/component/sw-order-user-card/sw-order-user-card.html.twig @@ -0,0 +1,8 @@ +{% block sw_order_detail_base_secondary_info_payment %} + +{% endblock %} diff --git a/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/view/novalnet-payment-book-amount-modal/index.js b/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/view/novalnet-payment-book-amount-modal/index.js new file mode 100755 index 0000000..bde7afa --- /dev/null +++ b/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/view/novalnet-payment-book-amount-modal/index.js @@ -0,0 +1,96 @@ +import template from './novalnet-payment-book-amount-modal.html.twig'; + +const { Component, Mixin } = Shopware; +const { currency } = Shopware.Utils.format; + +Component.register('novalnet-payment-book-amount-modal', { + template, + + props: { + orderAmount: { + type: Number, + required: true + }, + order: { + type: Object, + required: true + } + }, + + inject: [ + 'NovalPaymentApiCredentialsService', + 'repositoryFactory' + ], + + mixins: [ + Mixin.getByName('notification'), + Mixin.getByName('sw-inline-snippet') + ], + + data() { + return { + reason: '', + disable: false, + }; + }, + + methods: { + + closeModal() { + this.$emit('modal-close'); + }, + + novalnetBookAmount() + { + const orderAmount = this.orderAmount; + const orderNumber = this.order.orderNumber; + + if(orderAmount == 0) + { + this.createNotificationError({ + message: this.$tc('novalnet-payment.settingForm.amountError') + }); + return; + } + + this.disable = true; + this.NovalPaymentApiCredentialsService.BookOrderAmount( + orderNumber, + orderAmount + ).then((response) => { + + if( response.result != undefined && response.result != null && response.result != '') + { + if(response.result.status != undefined && response.result.status != null && response.result.status != '' && response.result.status == 'SUCCESS') + { + this.createNotificationSuccess({ + message: this.$tc('novalnet-payment.settingForm.extension.bookedSuccess') + }); + } else if(response.result.status_text != undefined && response.result.status_text != null && response.result.status_text != '') { + + this.createNotificationError({ + message: response.result.status_text, + }); + } else { + this.createNotificationError({ + message: this.$tc('novalnet-payment.settingForm.failureMessage') + }); + } + } else { + + this.createNotificationError({ + message: this.$tc('novalnet-payment.settingForm.failureMessage') + }); + } + this.$emit('modal-close'); + setTimeout(this.$router.go, 3000); + }).catch((errorResponse) => { + this.createNotificationError({ + message: `${errorResponse.title}: ${errorResponse.message}`, + autoClose: false + }); + this.$emit('modal-close'); + }); + }, + } +}); diff --git a/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/view/novalnet-payment-book-amount-modal/novalnet-payment-book-amount-modal.html.twig b/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/view/novalnet-payment-book-amount-modal/novalnet-payment-book-amount-modal.html.twig new file mode 100755 index 0000000..87336ed --- /dev/null +++ b/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/view/novalnet-payment-book-amount-modal/novalnet-payment-book-amount-modal.html.twig @@ -0,0 +1,34 @@ +{% block novalnet_payment_order_refund_modal %} + + + {% block novalnet_payment_order_zero_amount_modal_content %} + + {% endblock %} + + {% block novalnet_payment_order_zero_amount_modal_actions %} + + {% endblock %} + +{% endblock %} diff --git a/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/view/novalnet-payment-instalment-cancel-modal/index.js b/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/view/novalnet-payment-instalment-cancel-modal/index.js new file mode 100755 index 0000000..ef74024 --- /dev/null +++ b/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/view/novalnet-payment-instalment-cancel-modal/index.js @@ -0,0 +1,87 @@ +import template from './novalnet-payment-instalment-cancel-modal.html.twig'; + +const { Component, Mixin } = Shopware; +const { currency } = Shopware.Utils.format; + +Component.register('novalnet-payment-instalment-cancel-modal', { + template, + + props: { + cancelType: { + type: String, + required: true + }, + order: { + type: Object, + required: true + } + }, + + inject: [ + 'NovalPaymentApiCredentialsService', + 'repositoryFactory' + ], + + mixins: [ + Mixin.getByName('notification'), + Mixin.getByName('sw-inline-snippet') + ], + + data() { + return { + disable: false, + }; + }, + + methods: { + + closeModal() { + this.$emit('modal-close'); + }, + + novalnetInstalmentCancel() + { + const orderNumber = this.order.orderNumber; + const cancelType = this.cancelType; + this.disable = true; + + this.NovalPaymentApiCredentialsService.instalmentCancel( + orderNumber, + cancelType, + ).then((response) => { + + if(response.result != '') + { + if(response.result.status != undefined && response.result.status != null && response.result.status != '' && response.result.status == 'SUCCESS') + { + this.createNotificationSuccess({ + message: this.$tc('novalnet-payment.settingForm.extension.instalmentSuccessMsg') + }); + } else if(response.result.status_text != undefined && response.result.status_text != null && response.result.status_text != '') { + + this.createNotificationError({ + message: response.result.status_text, + }); + } else { + this.createNotificationError({ + message: this.$tc('novalnet-payment.settingForm.failureMessage') + }); + } + } else { + + this.createNotificationError({ + message: this.$tc('novalnet-payment.settingForm.failureMessage') + }); + } + this.$emit('modal-close'); + setTimeout(this.$router.go, 3000); + }).catch((errorResponse) => { + this.createNotificationError({ + message: `${errorResponse.title}: ${errorResponse.message}`, + autoClose: false + }); + this.$emit('modal-close'); + }); + }, + } +}); diff --git a/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/view/novalnet-payment-instalment-cancel-modal/novalnet-payment-instalment-cancel-modal.html.twig b/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/view/novalnet-payment-instalment-cancel-modal/novalnet-payment-instalment-cancel-modal.html.twig new file mode 100755 index 0000000..ebac008 --- /dev/null +++ b/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/view/novalnet-payment-instalment-cancel-modal/novalnet-payment-instalment-cancel-modal.html.twig @@ -0,0 +1,32 @@ +{% block novalnet_payment_order_cancel_modal %} + + + {% block novalnet_payment_order_cancel_modal_content %} + + {% endblock %} + + {% block novalnet_payment_order_cancel_modal_actions %} + + {% endblock %} + +{% endblock %} diff --git a/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/view/novalnet-payment-manage-transaction-modal/index.js b/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/view/novalnet-payment-manage-transaction-modal/index.js new file mode 100755 index 0000000..d2323fb --- /dev/null +++ b/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/view/novalnet-payment-manage-transaction-modal/index.js @@ -0,0 +1,104 @@ +import template from './novalnet-payment-manage-transaction-modal.html.twig'; + +const { Component, Mixin } = Shopware; +const { currency } = Shopware.Utils.format; + +Component.register('novalnet-payment-manage-transaction-modal', { + template, + + props: { + status: { + type: Number, + required: true + }, + order: { + type: Object, + required: true + } + }, + + inject: [ + 'NovalPaymentApiCredentialsService', + 'repositoryFactory' + ], + + mixins: [ + Mixin.getByName('notification'), + Mixin.getByName('sw-inline-snippet') + ], + + data() { + return { + confirm: true, + cancel: false, + disable: false + }; + }, + + methods: { + + closeModal() { + this.$emit('modal-close'); + }, + + novalnetOnhold() + { + let status = this.status; + const orderNumber = this.order.orderNumber; + + if( status == '' || status == undefined ) + { + this.createNotificationError({ + message: this.$tc('novalnet-payment.settingForm.extension.onholdLabel') + }); + return; + } + + this.disable = true; + + this.NovalPaymentApiCredentialsService.managePayment( + orderNumber, + status + ).then((response) => { + + if(response !=''){ + + if(response.result.status == 'SUCCESS') + { + if(response.manageEvent == 'transaction_capture') { + this.createNotificationSuccess({ + message: this.$tc('novalnet-payment.settingForm.extension.onholdSuccess') + }); + } else if(response.manageEvent == 'transaction_cancel') { + this.createNotificationSuccess({ + message: this.$tc('novalnet-payment.settingForm.extension.onholdCancel') + }); + } + } else if(response.result.status_text != undefined && response.result.status_text != null && response.result.status_text != '') { + + this.createNotificationError({ + message: response.result.status_text, + }); + } else { + this.createNotificationError({ + message: this.$tc('novalnet-payment.settingForm.failureMessage') + }); + } + } + else { + this.createNotificationError({ + message: this.$tc('novalnet-payment.settingForm.failureMessage') + }); + } + this.$emit('modal-close'); + setTimeout(this.$router.go, 3000); + }).catch((errorResponse) => { + this.createNotificationError({ + message: `${errorResponse.title}: ${errorResponse.message}`, + autoClose: false + }); + this.$emit('modal-close'); + }); + } + } +}); diff --git a/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/view/novalnet-payment-manage-transaction-modal/novalnet-payment-manage-transaction-modal.html.twig b/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/view/novalnet-payment-manage-transaction-modal/novalnet-payment-manage-transaction-modal.html.twig new file mode 100755 index 0000000..0158a7e --- /dev/null +++ b/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/view/novalnet-payment-manage-transaction-modal/novalnet-payment-manage-transaction-modal.html.twig @@ -0,0 +1,32 @@ +{% block novalnet_payment_order_manage_modal %} + + + {% block novalnet_payment_order_manage_modal_content %} + + {% endblock %} + + {% block novalnet_payment_order_manage_modal_actions %} + + {% endblock %} + +{% endblock %} diff --git a/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/view/novalnet-payment-refund-modal/index.js b/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/view/novalnet-payment-refund-modal/index.js new file mode 100755 index 0000000..97f8e1f --- /dev/null +++ b/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/view/novalnet-payment-refund-modal/index.js @@ -0,0 +1,112 @@ +import template from './novalnet-payment-refund-modal.html.twig'; + +const { Component, Mixin } = Shopware; +const { currency } = Shopware.Utils.format; + +Component.register('novalnet-payment-refund-modal', { + template, + + props:{ + + refundableAmount : { + type : Number, + required : true + }, + + order: { + type : Object, + required : true + }, + + item: { + type : Object, + required : true + } + + }, + + inject: [ + + 'NovalPaymentApiCredentialsService', + 'repositoryFactory', + ], + + mixins: [ + Mixin.getByName('notification'), + Mixin.getByName('sw-inline-snippet') + ], + + data(){ + return { + reason: '', + disable: false, + }; + }, + + methods: { + + closeModal() { + this.$emit('modal-close'); + }, + + novalnetRefund() + { + let refundAmount = this.refundableAmount; + const reason = this.reason; + const orderNumber = this.order.orderNumber; + + if(refundAmount == '0') + { + this.createNotificationError({ + message: this.$tc('novalnet-payment.settingForm.amountRefundError') + }); + return; + } + + this.disable = true; + + this.NovalPaymentApiCredentialsService.refundPayment( + orderNumber, + refundAmount, + reason, + this.item.reference, + ).then((response) => { + if(response.result != undefined && response.result != null && response.result != '') { + + if(response.result.status != undefined && response.result.status != null && response.result.status != '' && response.result.status == 'SUCCESS'){ + + this.createNotificationSuccess({ + message: this.$tc('novalnet-payment.settingForm.extension.refundSuccess') + }); + } + else if(response.result.status_text != undefined && response.result.status_text != null && response.result.status_text != '') { + + this.createNotificationError({ + message: response.result.status_text, + }); + } + else { + + this.createNotificationError({ + message: this.$tc('novalnet-payment.settingForm.failureMessage') + }); + } + } + else{ + + this.createNotificationError({ + message: this.$tc('novalnet-payment.settingForm.failureMessage') + }); + } + this.$emit('modal-close'); + setTimeout(this.$router.go, 3000); + }).catch((errorResponse) => { + this.createNotificationError({ + message: `${errorResponse.title}: ${errorResponse.message}`, + autoClose: false + }); + this.$emit('modal-close'); + }); + }, + } +}); diff --git a/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/view/novalnet-payment-refund-modal/novalnet-payment-refund-modal.html.twig b/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/view/novalnet-payment-refund-modal/novalnet-payment-refund-modal.html.twig new file mode 100755 index 0000000..105febd --- /dev/null +++ b/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/view/novalnet-payment-refund-modal/novalnet-payment-refund-modal.html.twig @@ -0,0 +1,39 @@ +{% block novalnet_payment_order_refund_modal %} + + + {% block novalnet_payment_order_refund_modal_content %} + + {% endblock %} + + {% block novalnet_payment_order_refund_modal_actions %} + + {% endblock %} + +{% endblock %} diff --git a/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/view/sw-order-create-base/index.js b/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/view/sw-order-create-base/index.js new file mode 100755 index 0000000..3f2fca1 --- /dev/null +++ b/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/view/sw-order-create-base/index.js @@ -0,0 +1,66 @@ +import template from './sw-order-create-base.html.twig'; + + +const { Component, State, Mixin, Filter, Context } = Shopware; +const Criteria = Shopware.Data.Criteria; +const { currency } = Shopware.Utils.format; + +Component.override('sw-order-create-base', { + template, + + inject: [ + 'NovalPaymentApiCredentialsService', + 'repositoryFactory', + 'acl', + ], + + mixins: [ + Mixin.getByName('notification') + ], + + + + data() { + return { + isLoading: false, + + }; + }, + + computed: { + + customer() { + return State.get('swOrder').customer; + }, + + cart() { + return State.get('swOrder').cart; + }, + cartPrice() { + return this.cart.price; + }, + + currency() { + return State.get('swOrder').context.currency; + }, + displayRounded() { + if (!this.cartPrice) { + return false; + } + return this.cartPrice.rawTotal !== this.cartPrice.totalPrice; + }, + + orderTotal() { + if (!this.cartPrice) { + return 0; + } + + if (this.displayRounded) { + return this.cartPrice.rawTotal; + } + return this.cartPrice.totalPrice; + + }, + }, + +}); diff --git a/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/view/sw-order-create-base/sw-order-create-base.html.twig b/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/view/sw-order-create-base/sw-order-create-base.html.twig new file mode 100755 index 0000000..f042ec1 --- /dev/null +++ b/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/view/sw-order-create-base/sw-order-create-base.html.twig @@ -0,0 +1,13 @@ +{% block sw_order_create_details %} + {% parent %} + + +{% endblock %} diff --git a/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/view/sw-order-create-base/sw-order-create-base.scss b/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/view/sw-order-create-base/sw-order-create-base.scss new file mode 100755 index 0000000..233599b --- /dev/null +++ b/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/view/sw-order-create-base/sw-order-create-base.scss @@ -0,0 +1,86 @@ +.novalnet-payment-extension-order-detail-page { + padding: 30px; + border-bottom: 1px solid #d1d9e0 +} + +.novalnet-payment-buyer-details { + height: 80px; + width: 100%; + display: flex; +} + +.novalnet-payment-buyer-details-icon-container { + width: 80px; + background: rgb(249, 250, 251); + border-radius: 7px; + border: 1px solid rgb(209, 217, 224); + display: flex; + flex-flow: row nowrap; + justify-content: center; + align-items: center; +} + +.novalnet-payment-buyer-details-info-name { + margin-top: 16px; + margin-left: 24px; +} + +.novalnet-payment-buyer-details-info-full-name { + font-weight: 600; + font-size: 18px; +} + +.novalnet-payment-buyer-details-info-email { + font-size: 14px; +} + +.novalnet-payment-amount-info-total-amount { + font-size: 18px; + font-weight: 600; + height: 25px; + margin-right: 26px; +} + +.novalnet-payment-captured-amount-help-icon, +.novalnet-payment-refuned-amount-help-icon { + margin-left: 8px; +} + +.novalnet-payment-amount-captured-amount { + color: green; + font-size: 14px; +} + +.novalnet-payment-refuned-amount { + color: red; + font-size: 14px; +} + +.novalnet-payment-amount-info-charge-date { + margin-right: 26px; + font-size: 14px; + margin-top: 3px; +} + +.novalnet-payment-amount-info-amount { + margin: 0 0 0 auto; + width: 11em; +} + +.novalnet-payment-checkout-info-header, dt { + font-size: 14px; + font-weight: 600; + line-height: 22px; + margin-bottom: 4px; +} + +.novalnet-payment-checkout-info-comments { + font-size: 14px; +} + +.novalnet-payment-checkout-info-label, +.novalnet-payment-checkout-status-info { + font-size: 14px; +} + + diff --git a/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/view/sw-order-create-details/index.js b/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/view/sw-order-create-details/index.js new file mode 100755 index 0000000..5784c97 --- /dev/null +++ b/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/view/sw-order-create-details/index.js @@ -0,0 +1,194 @@ +import template from './sw-order-create-details.html.twig'; + +const { Component, State, Mixin, Filter, Context, ContextSwitchParameters} = Shopware; +const Criteria = Shopware.Data.Criteria; +const { currency } = Shopware.Utils.format; + +Component.override('sw-order-create-details', { + template, + + inject: [ + 'NovalPaymentApiCredentialsService', + 'repositoryFactory', + 'acl', + ], + + mixins: [ + Mixin.getByName('notification') + ], + + data() { + return { + isLoading: false, + loaded : false, + shouldDisable : true, + iframe: { + src: '' + }, + paymentformurl : '', + novalnetPayment : false + }; + }, + + computed: { + customer() { + return State.get('swOrder').customer; + }, + cart() { + return State.get('swOrder').cart; + }, + currency(){ + return State.get('swOrder').context.currency; + }, + cartPrice() { + return this.cart.price; + }, + salesChannelContext(){ + return State.get('swOrder').context; + }, + }, + + watch: { + salesChannelContext: { + deep: true, + handler() { + if (!this.customer || !this.isCartTokenAvailable) { + return; + } + + this.isLoading = true; + const paymentRepository = this.repositoryFactory.create('payment_method'); + const paymentCriteria = new Criteria(1, 1); + paymentCriteria.addFilter(Criteria.equals('id', this.salesChannelContext.paymentMethod.id)); + paymentRepository.search(paymentCriteria, Context.api).then((searchResult) => { + const payment = searchResult.first(); + if (!payment) { + return + } + + this.novalnetPayment = false; + if ((payment.customFields != null) && (payment.customFields.novalnet_payment_method_name == 'novalnetpay')) { + if (this.currency == null) { + this.createNotificationError({ + title: this.$tc('novalnet-payment.settingForm.titleError'), + message: this.$tc('novalnet-payment.settingForm.currencyFailureMessage') + }); + + return; + } + + if (this.cartPrice != null && (this.cartPrice.totalPrice == 0 || this.cartPrice.totalPrice == null)) { + this.createNotificationError({ + title: this.$tc('novalnet-payment.settingForm.titleError'), + message: this.$tc('novalnet-payment.settingForm.lineitemFailureMessage') + }); + + return; + } + + this.novalnetPayment = true; + let billingaddress = ''; + let shippingaddress = ''; + let contextBillingAddress = ''; + let contextShippingAddress = ''; + + if ((this.context.billingAddressId !='') || (this.salesChannelContext.customer.defaultBillingAddress !== null)) { + if (this.context.billingAddressId !='') { + this.customer.addresses.forEach(value => { + if (value.id == this.context.billingAddressId) { + contextBillingAddress = value; + } + }); + } + + billingaddress = contextBillingAddress != '' ? contextBillingAddress : this.salesChannelContext.customer.defaultBillingAddress; + } + + if ((this.context.shippingAddressId !='') || (this.salesChannelContext.customer.defaultShippingAddress !== null)) { + if (this.context.shippingAddressId !='') { + this.customer.addresses.forEach(value => { + if (value.id == this.context.shippingAddressId) { + contextShippingAddress = value; + } + }); + } + + shippingaddress = contextShippingAddress !='' ? contextShippingAddress : this.salesChannelContext.customer.defaultShippingAddress; + } + + let me = this.NovalPaymentApiCredentialsService; + let customerPaymentDetails = this.customer; + this.NovalPaymentApiCredentialsService.novalnetPayment(shippingaddress, billingaddress, this.cartPrice.totalPrice , this.currency.isoCode, this.customer ).then((payment) => { + if (payment != '' && payment != undefined) { + if (payment.result.status =='SUCCESS' && payment.result.redirect_url != '' && payment.result.redirect_url != undefined) { + this.iframe.src = payment.result.redirect_url; + this.loaded = true; + const recaptchaScript = document.createElement('script'); + recaptchaScript.setAttribute('src', 'https://cdn.novalnet.de/js/pv13/checkout.js?' + new Date().getTime()); + recaptchaScript.type = 'text/javascript'; + document.head.appendChild(recaptchaScript); + this.paymentformurl = recaptchaScript; + this.paymentformurl.addEventListener('load', ()=> { + document.querySelector('.sw-button-process').disabled = false; + this.onWindowLoad(me, customerPaymentDetails); + }); + } + } + }).catch((errorResponse) => { + this.createNotificationError({ + message: `${errorResponse.title}: ${errorResponse.message}` + }); + }); + } + }); + }, + }, + + customer: { + deep: true, + handler() { + if (this.customer == null) { + return; + } + }, + immediate: true + } + }, + + methods: { + onWindowLoad(e, customer) { + const paymentForm = new NovalnetPaymentForm(); + const submit = document.querySelector('.sw-button-process'); + const keyname = 'ordernovalnetpayment'; + + let paymentType = '', + request = { + iframe: '#adminnovalnetPaymentiframe', + initForm: { + uncheckPayments: false, + showButton: false, + } + }; + + paymentForm.initiate(request); + paymentForm.validationResponse((data) => { + paymentForm.initiate(request); + }); + + paymentForm.selectedPayment((function(selectPaymentData) { + paymentType = selectPaymentData.payment_details.type; + + })); + + submit.addEventListener('click', (event) => { + event.preventDefault(); + event.stopImmediatePropagation(); + paymentForm.getPayment((function(paymentDetails) { + let value = JSON.stringify(paymentDetails); + e.paymentValue(value, customer).then((payment) => { + }); + })); + }); + }, + }, +}); diff --git a/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/view/sw-order-create-details/sw-order-create-details.html.twig b/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/view/sw-order-create-details/sw-order-create-details.html.twig new file mode 100755 index 0000000..cd552da --- /dev/null +++ b/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/view/sw-order-create-details/sw-order-create-details.html.twig @@ -0,0 +1,23 @@ +{% block sw_order_create_details_payment %} + + {% parent %} + {% block sw_order_create_details_payment_novalnet_seaction %} + + + {% endblock %} +{% endblock %} diff --git a/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/view/sw-order-create-general/index.js b/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/view/sw-order-create-general/index.js new file mode 100755 index 0000000..9a15de9 --- /dev/null +++ b/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/view/sw-order-create-general/index.js @@ -0,0 +1,83 @@ + +const { Component, State, Mixin, Filter, Context, ContextSwitchParameters} = Shopware; +const Criteria = Shopware.Data.Criteria; +const { currency } = Shopware.Utils.format; + +Component.override('sw-order-create-general', { + inject: [ + 'NovalPaymentApiCredentialsService', + 'repositoryFactory', + 'acl', + ], + + mixins: [ + Mixin.getByName('notification') + ], + + data() { + return { + isLoading: false, + }; + }, + + computed: { + customer() { + return State.get('swOrder').customer; + }, + cart() { + return State.get('swOrder').cart; + }, + currency(){ + return State.get('swOrder').context.currency; + }, + cartPrice() { + return this.cart.price; + }, + salesChannelContext(){ + return State.get('swOrder').context; + }, + }, + + watch: { + salesChannelContext: { + deep: true, + handler() { + + if (!this.customer) { + return; + } + + this.isLoading = true; + const paymentRepository = this.repositoryFactory.create('payment_method'); + const paymentCriteria = new Criteria(1, 1); + paymentCriteria.addFilter(Criteria.equals('id', this.salesChannelContext.paymentMethod.id)); + paymentRepository.search(paymentCriteria, Context.api).then((searchResult) => { + const payment = searchResult.first(); + if (!payment) { + return + } + this.novalnetPayment = false; + if ((payment.customFields != null) && (payment.customFields.novalnet_payment_method_name == 'novalnetpay')) { + this.onWindowLoad(); + } + }); + }, + }, + + customer: { + deep: true, + handler() { + if (this.customer == null) { + return; + } + }, + immediate: true + } + }, + + methods: { + onWindowLoad() { + document.querySelector('.sw-button-process').disabled = true; + } + }, +}); diff --git a/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/view/sw-order-detail-base/index.js b/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/view/sw-order-detail-base/index.js new file mode 100755 index 0000000..03dc9cc --- /dev/null +++ b/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/view/sw-order-detail-base/index.js @@ -0,0 +1,367 @@ +import template from './sw-order.html.twig'; +import './sw-order.scss'; + +const { Component, Mixin, Filter, Context } = Shopware; +const Criteria = Shopware.Data.Criteria; +const { currency } = Shopware.Utils.format; + +Component.override('sw-order-detail-base', { + template, + + inject: [ + 'NovalPaymentApiCredentialsService', + 'repositoryFactory', + 'acl', + ], + + mixins: [ + Mixin.getByName('notification') + ], + + props: { + orderId: { + type: String, + required: true + }, + paymentDetails: { + type: Object, + required: true + }, + }, + + + data() { + return { + isLoading: false, + order: {}, + orderAmount : 0, + isNovalnetPayment: false, + stateMachineState : null, + novalnetComments : '', + orderTotalAmount : '', + orderPaidAmount: 0, + orderRefundedAmount: 0, + canRefund : false, + refundModalVisible : false, + confirmModalVisible: false, + cancelModalVisible: false, + item: {}, + status: 0, + canCaptureVoid: false, + refundableAmount : 0, + canInstalmentShow: false, + InstalmentInfo: [], + cancelType : '', + canInstalmentCancel: false, + canInstalmentAllCancel: false, + canInstalmentRemainCancel: false, + instalmentRefundAmount : 0, + instalmentRefundModalVisible: false, + canZeroAmountBooking: false, + zeroAmountVisible:false, + payLater: [ + 'INVOICE', + 'CASHPAYMENT', + 'MULTIBANCO', + 'PREPAYMENT' + ], + instalmentPayments: [ + 'INSTALMENT_INVOICE', + 'INSTALMENT_DIRECT_DEBIT_SEPA' + ], + onholdStatus: ['91', '99', '98', '85'] + + + }; + }, + + computed: { + + getInstalmentColums() { + const columnDefinitions = [{ + property: 'number', + dataIndex: 'number', + label: this.$tc('novalnet-payment.settingForm.instalmentNumber'), + width: '50px' + }, + { + property: 'reference', + dataIndex: 'reference', + label: this.$tc('novalnet-payment.settingForm.instalmentReference'), + width: '120px' + }, + { + property: 'amount', + dataIndex: 'amount', + label: this.$tc('novalnet-payment.settingForm.instalmentAmount'), + width: '80px' + },{ + property: 'totalAmount', + dataIndex: 'totalAmount', + visible: false + }, + { + property: 'refundAmount', + dataIndex: 'refundAmount', + visible: false + }, + { + property: 'nextCycle', + dataIndex: 'nextCycle', + label: this.$tc('novalnet-payment.settingForm.instalmentDate'), + width: '120px' + }, { + property: 'status', + dataIndex: 'status', + label: this.$tc('novalnet-payment.settingForm.instalmentStatus'), + width: '80px' + }]; + + return columnDefinitions; + } + }, + + + watch: { + orderId: { + deep: true, + handler(){ + + if(!this.orderId){ + this.setNovalnetPayment(null); + return; + } + + const orderRepository = this.repositoryFactory.create('order'); + const orderCriteria = new Criteria(1, 1); + orderCriteria.addAssociation('transactions'); + orderCriteria.addAssociation('currency'); + orderCriteria.addFilter(Criteria.equals('id', this.orderId)); + + orderRepository.search(orderCriteria, Context.api).then((searchResult) => { + const order = searchResult.first(); + if(!order){ + return + } + + if (!this.identifier) { + this.identifier = order.orderNumber; + } + let isNovalnet = false; + let comments = ''; + let translation = this.$tc('novalnet-payment.module.comments'); + + order.transactions.sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt) ).forEach((orderTransaction) => { + if (orderTransaction.customFields && + orderTransaction.customFields.novalnet_comments + ) { + this.stateMachineState = orderTransaction.stateMachineState.name; + + isNovalnet = true; + if(comments !=''){ + comments += "
" + translation + "
"; + } + comments += orderTransaction.customFields.novalnet_comments.split("/ ").join("
"); + return true; + } + }); + + if( isNovalnet ) { + this.novalnetComments = comments.split("&&").join("
" + translation + "
"); + this.setNovalnetPayment( true ); + this.isNovalnetPayment = true; + } else { + this.setNovalnetPayment(false); + this.isNovalnetPayment = false; + } + + this.canRefund = false; this.canCaptureVoid = false; this.canInstalmentShow = false; this.InstalmentInfo = []; this.canInstalmentCancel = false; this.canZeroAmountBooking = false; this.canInstalmentAllCancel = false; this.canInstalmentRemainCancel = false; + + this.NovalPaymentApiCredentialsService.getNovalnetAmount(order.orderNumber).then((payment) => { + + if(payment.data != '' && payment.data != undefined) + { + if(payment.data.gatewayStatus) { + + this.refundableAmount = Number(payment.data.amount) - Number(payment.data.refundedAmount); + this.orderAmount = Math.round(Number(order.price.totalPrice) * 100); + + if ( payment.data.amount != 0) { + this.orderTotalAmount = currency (payment.data.amount / 100, order.currency.shortName); + } else { + this.orderTotalAmount = currency (order.price.totalPrice, order.currency.shortName); + } + + if (payment.data.paidAmount != 0) { + this.orderPaidAmount = currency (payment.data.paidAmount / 100, order.currency.shortName); + } else { + this.orderPaidAmount = currency (0, order.currency.shortName); + } + + if (payment.data.refundedAmount != 0) { + this.orderRefundedAmount = currency (payment.data.refundedAmount / 100, order.currency.shortName); + } else { + this.orderRefundedAmount = currency (0, order.currency.shortName); + } + + let additionalDetails = JSON.parse(payment.data.additionalDetails); + + if(((payment.data.amount > 0 && payment.data.gatewayStatus == 'CONFIRMED' && !this.instalmentPayments.includes(payment.data.paymentType) && Number(payment.data.refundedAmount) < Number(payment.data.amount)) || (payment.data.gatewayStatus == 'PENDING' && this.payLater.includes(payment.data.paymentType))) && payment.data.paymentType != 'MULTIBANCO' ) + { + this.canRefund = true; + } + else if(payment.data.gatewayStatus == 'ON_HOLD' || this.onholdStatus.includes(payment.data.gatewayStatus) ) + { + this.canCaptureVoid = true; + } + else if (this.instalmentPayments.includes(payment.data.paymentType) && payment.data.gatewayStatus == 'CONFIRMED' && !additionalDetails.cancelType) + { + this.canInstalmentCancel = true; + } + else if (((payment.data.paymentType == 'CREDITCARD') || (payment.data.paymentType == 'DIRECT_DEBIT_SEPA') || (payment.data.paymentType == 'GOOGLEPAY') || (payment.data.paymentType == 'DIRECT_DEBIT_ACH')) && Number(payment.data.amount) == 0 && this.orderAmount != 0) + { + this.canZeroAmountBooking = true; + } + + if( payment.data.gatewayStatus == 'CONFIRMED' && this.instalmentPayments.includes(payment.data.paymentType) && additionalDetails.InstalmentDetails != '' ) { + + this.canInstalmentShow = true; + this.instalmentRefundAmount = payment.data.refundedAmount; + var counter = 1; + + Object.values(additionalDetails.InstalmentDetails).forEach(values => { + this.InstalmentInfo.push({ + 'nextCycle': values.cycleDate, + 'amount': currency (values.amount / 100, order.currency.shortName), + 'reference': values.reference, + 'status': values.status, + 'totalAmount': values.amount, + 'refundAmount': values.refundAmount, + 'number': counter + }); + counter++; + }); + + if(payment.data.refundedAmount != 0){ + this.canInstalmentCancel = false; + this.canInstalmentAllCancel = false; + } + + if (this.InstalmentInfo != undefined && this.InstalmentInfo != null) { + this.InstalmentInfo.forEach(value => { + if(value['reference'] == '' || value['reference'] == null) + { + this.canInstalmentRemainCancel = true; + } + }); + } + if(additionalDetails.cancelType != undefined && additionalDetails.cancelType !=''){ + this.canInstalmentRemainCancel = false; + } + + if(this.canInstalmentRemainCancel == false && payment.data.refundedAmount == 0 ){ + this.canInstalmentCancel = false; + this.canInstalmentAllCancel = true; + } else if(this.canInstalmentCancel == true){ + this.canInstalmentRemainCancel = false; + } + } + + } + } + + }); + + }).finally(() => { + this.setNovalnetPayment(false); + }); + }, + immediate: true + } + }, + + methods: { + + setNovalnetPayment( novalnetPayment ) { + if( novalnetPayment ) { + this.isNovalnetPayment = novalnetPayment; + } + }, + + showRefundModal(){ + + this.refundModalVisible = true; + }, + + showConfirmModal() { + this.status = 100; + this.confirmModalVisible = true; + }, + + showCancelModal() { + this.status = 103; + this.cancelModalVisible = true; + }, + + instalmentRefund(item) { + this.refundableAmount = item.totalAmount - item.refundAmount; + this.item = item; + this.refundModalVisible = true; + }, + + disableInstalmentRefund(item) { + if( item.reference == undefined || item.reference == '' || item.refundAmount >= item.totalAmount || !this.acl.can('novalnet_extension.editor')) + { + return true; + } + + return false; + }, + + showInstalmentCancelModal() { + if (this.InstalmentInfo != undefined && this.InstalmentInfo != null) + { + this.InstalmentInfo.forEach(value => { + if(value['reference'] == '' || value['reference'] == null) + { + this.canInstalmentRemainCancel = true; + } + }); + } + if(this.instalmentRefundAmount == 0){ + this.canInstalmentAllCancel = true; + } + this.canInstalmentCancel = false; + }, + + showInstalmentAllCancelModal() { + this.instalmentRefundModalVisible = true; + this.cancelType = 'CANCEL_ALL_CYCLES'; + }, + + showInstalmentRemainCancelModal(){ + this.instalmentRefundModalVisible = true; + this.cancelType = 'CANCEL_REMAINING_CYCLES'; + }, + + showZeroAmountBlock() { + this.zeroAmountVisible = true; + }, + + closeModals() { + this.refundModalVisible = false; + this.confirmModalVisible = false; + this.cancelModalVisible = false; + this.instalmentRefundModalVisible = false; + this.zeroAmountVisible = false; + }, + + reloadPaymentDetails() { + this.closeModals(); + this.$nextTick().then(() => { + this.$emit('reload-payment'); + }); + } + } + +}); diff --git a/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/view/sw-order-detail-base/sw-order.html.twig b/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/view/sw-order-detail-base/sw-order.html.twig new file mode 100755 index 0000000..6ecfba6 --- /dev/null +++ b/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/view/sw-order-detail-base/sw-order.html.twig @@ -0,0 +1,280 @@ +{% block sw_order_detail_customer_comment_card %} + {% parent %} + + +{% endblock %} diff --git a/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/view/sw-order-detail-base/sw-order.scss b/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/view/sw-order-detail-base/sw-order.scss new file mode 100755 index 0000000..a7cca1a --- /dev/null +++ b/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/view/sw-order-detail-base/sw-order.scss @@ -0,0 +1,86 @@ +.novalnet-payment-order-page { + padding: 30px; + border-bottom: 1px solid #d1d9e0 +} + +.novalnet-payment-buyer-notification { + height: 80px; + width: 100%; + display: flex; +} + +.novalnet-payment-buyer-notification-icon-container { + width: 80px; + background: rgb(249, 250, 251); + border-radius: 4px; + border: 1px solid rgb(209, 217, 224); + display: flex; + flex-flow: row nowrap; + justify-content: center; + align-items: center; +} + +.novalnet-payment-buyer-info-name { + margin-top: 16px; + margin-left: 24px; +} + +.novalnet-payment-buyer-info-full-name { + font-weight: 600; + font-size: 18px; +} + +.novalnet-payment-buyer-info-email { + font-size: 14px; +} + +.novalnet-payment-amount-info-total-amount { + font-size: 18px; + font-weight: 600; + height: 25px; + margin-right: 26px; +} + +.novalnet-payment-captured-amount-help-icon, +.novalnet-payment-refuned-amount-help-icon { + margin-left: 8px; +} + +.novalnet-payment-amount-captured-amount { + color: green; + font-size: 14px; +} + +.novalnet-payment-refuned-amount { + color: red; + font-size: 14px; +} + +.novalnet-payment-amount-info-charge-date { + margin-right: 26px; + font-size: 14px; + margin-top: 3px; +} + +.novalnet-payment-amount-info-amount { + margin: 0 0 0 auto; + width: 11em; +} + +.novalnet-payment-checkout-info-header, dt { + font-size: 14px; + font-weight: 600; + line-height: 22px; + margin-bottom: 4px; +} + +.novalnet-payment-checkout-info-comments { + font-size: 14px; +} + +.novalnet-payment-checkout-info-label, +.novalnet-payment-checkout-status-info { + font-size: 14px; +} + + diff --git a/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/view/sw-order-detail-details/index.js b/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/view/sw-order-detail-details/index.js new file mode 100755 index 0000000..fa73e9d --- /dev/null +++ b/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/view/sw-order-detail-details/index.js @@ -0,0 +1,380 @@ +import template from './sw-order-detail-details.html.twig'; +import './sw-order-detail-details.scss'; + +const { Context, Component, Filter, Utils } = Shopware; +const { Criteria } = Shopware.Data; +const { currency } = Shopware.Utils.format; + +Component.override('sw-order-detail-details', { + template, + + inject: [ + 'NovalPaymentApiCredentialsService', + 'repositoryFactory', + 'acl', + ], + + mixins: ['notification'], + + props: { + orderId: { + type: String, + required: true + }, + paymentDetails: { + type: Object, + required: true + }, + }, + + data() { + return { + status: 0, + displayAmount: 0, + displayPaidAmount: 0, + refundedAmount: 0, + orderAmount : 0, + InstalmentInfo: [], + item: {}, + novalnetComments: '', + isNovalnetPayment: false, + refundModalVisible: false, + confirmModalVisible: false, + zeroAmountVisible: false, + cancelModalVisible: false, + canInstalmentAllCancel: false, + canInstalmentRemainCancel: false, + instalmentRefundModalVisible: false, + instalmentRefundAmount : 0, + paymentMethod: '', + payLater: [ + 'INVOICE', + 'CASHPAYMENT', + 'MULTIBANCO', + 'PREPAYMENT' + ], + instalmentPayments: [ + 'INSTALMENT_INVOICE', + 'INSTALMENT_DIRECT_DEBIT_SEPA' + ], + onholdStatus: ['91', '99', '98', '85'] + } + }, + + computed: { + + getInstalmentColums() { + const columnDefinitions = [{ + property: 'number', + dataIndex: 'number', + label: this.$tc('novalnet-payment.settingForm.instalmentNumber'), + width: '50px' + }, + { + property: 'reference', + dataIndex: 'reference', + label: this.$tc('novalnet-payment.settingForm.instalmentReference'), + width: '120px' + }, + { + property: 'amount', + dataIndex: 'amount', + label: this.$tc('novalnet-payment.settingForm.instalmentAmount'), + width: '80px' + }, { + property: 'totalAmount', + dataIndex: 'totalAmount', + visible: false + }, + { + property: 'refundAmount', + dataIndex: 'refundAmount', + visible: false + },{ + property: 'nextCycle', + dataIndex: 'nextCycle', + label: this.$tc('novalnet-payment.settingForm.instalmentDate'), + width: '120px' + }, { + property: 'status', + dataIndex: 'status', + label: this.$tc('novalnet-payment.settingForm.instalmentStatus'), + width: '80px' + }]; + + return columnDefinitions; + } + }, + + watch: { + orderId: { + deep: true, + handler() { + if (!this.orderId) { + this.setNovalnetPayment(false); + return; + } + + const orderRepository = this.repositoryFactory.create('order'); + const orderCriteria = new Criteria(1, 1); + orderCriteria.addAssociation('transactions'); + orderCriteria.addAssociation('currency'); + + orderCriteria.addFilter(Criteria.equals('id', this.orderId)); + + orderRepository.search(orderCriteria, Context.api).then((searchResult) => { + const order = searchResult.first(); + + if (!order) { + return; + } + + if (!this.identifier) { + this.identifier = order.orderNumber; + } + let isNovalnet = false; + let comments = ''; + let translation = this.$tc('novalnet-payment.module.comments'); + + order.transactions.sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt) ).forEach((orderTransaction) => { + if (orderTransaction.customFields && + orderTransaction.customFields.novalnet_comments + ) { + + this.stateMachineState = orderTransaction.stateMachineState.name; + + isNovalnet = true; + if(comments != '') + { + comments += "
" + translation + "
"; + } + comments += orderTransaction.customFields.novalnet_comments.split("/ ").join("
"); + + return true; + } + }); + if( isNovalnet ) { + this.novalnetComments = comments.split("&&").join("
" + translation + "
"); + this.setNovalnetPayment(true); + } else { + this.setNovalnetPayment(false); + } + + if (this.order.transactions.last().paymentMethod.customFields != null && this.order.transactions.last().paymentMethod.customFields.novalnet_payment_method_name != undefined && this.order.transactions.last().paymentMethod.customFields.novalnet_payment_method_name == "novalnetpay") { + + this.NovalPaymentApiCredentialsService.getNovalnetPaymentMethod(this.order.orderNumber).then((payment) => { + if(payment != undefined && payment != null) + { + if(payment.paymentName != undefined && payment.paymentName != null){ + this.paymentMethod = payment.paymentName; + } + else { + this.paymentMethod = this.order.transactions.last().paymentMethod.translated.distinguishableName; + } + } + else { + this.paymentMethod = this.order.transactions.last().paymentMethod.translated.distinguishableName; + } + }).catch((errorResponse) => { + this.createNotificationError({ + message: `${errorResponse.title}: ${errorResponse.message}` + }); + }); + } + else { + + this.paymentMethod = this.order.transactions.last().paymentMethod.translated.distinguishableName; + } + + + this.canCaptureVoid = false;this.canRefund = false;this.canZeroAmountBooking = false;this.canInstalmentCancel = false;this.canInstalmentShow = false;this.InstalmentInfo = []; this.canInstalmentAllCancel = false; this.canInstalmentRemainCancel = false; + + this.NovalPaymentApiCredentialsService.getNovalnetAmount(order.orderNumber).then((payment) => { + if(payment.data != '' && payment.data != undefined) + { + if(payment.data.gatewayStatus) { + let additionalDetails = JSON.parse(payment.data.additionalDetails); + + this.refundableAmount = Number(payment.data.amount) - Number(payment.data.refundedAmount); + this.orderAmount = Math.round(Number(order.price.totalPrice) * 100); + + if(payment.data.gatewayStatus == 'ON_HOLD' || this.onholdStatus.includes(payment.data.gatewayStatus)) + { + this.canCaptureVoid = true; + } else if (((payment.data.amount > 0 && payment.data.gatewayStatus == 'CONFIRMED' && !this.instalmentPayments.includes(payment.data.paymentType) && Number(payment.data.refundedAmount) < Number(payment.data.amount)) || (payment.data.gatewayStatus == 'PENDING' && this.payLater.includes(payment.data.paymentType))) && payment.data.paymentType != 'MULTIBANCO' ) + { + this.canRefund = true; + } else if (this.instalmentPayments.includes(payment.data.paymentType) && payment.data.gatewayStatus == 'CONFIRMED' && !additionalDetails.cancelType) + { + this.canInstalmentCancel = true; + + } else if (((payment.data.paymentType == 'CREDITCARD') || (payment.data.paymentType == 'DIRECT_DEBIT_SEPA') || (payment.data.paymentType == 'GOOGLEPAY') || (payment.data.paymentType == 'DIRECT_DEBIT_ACH')) && Number(payment.data.amount) == 0 && this.orderAmount != 0) + { + this.canZeroAmountBooking = true; + } + + if ( payment.data.amount != 0) { + this.displayAmount = currency (payment.data.amount / 100, order.currency.shortName); + } else { + this.displayAmount = currency (order.price.totalPrice, order.currency.shortName); + } + + if (payment.data.paidAmount != 0) { + this.displayPaidAmount = currency (payment.data.paidAmount / 100, order.currency.shortName); + } else { + this.displayPaidAmount = currency (0, order.currency.shortName); + } + + if (payment.data.refundedAmount != 0) { + this.refundedAmount = currency (payment.data.refundedAmount / 100, order.currency.shortName); + } else { + this.refundedAmount = currency (0, order.currency.shortName); + } + + if( (this.instalmentPayments.includes(payment.data.paymentType)) && payment.data.gatewayStatus == 'CONFIRMED' && additionalDetails.InstalmentDetails != '') + { + this.canInstalmentShow = true; + this.instalmentRefundAmount = payment.data.refundedAmount; + var counter = 1; + + Object.values(additionalDetails.InstalmentDetails).forEach(values => { + this.InstalmentInfo.push ({ + 'amount': currency (values.amount / 100, order.currency.shortName), + 'totalAmount': values.amount, + 'nextCycle': values.cycleDate, + 'reference': values.reference, + 'status': values.status, + 'refundAmount': values.refundAmount, + 'number': counter + }); + counter++; + }); + + if(payment.data.refundedAmount != 0){ + this.canInstalmentCancel = false; + this.canInstalmentAllCancel = false; + } + + if (this.InstalmentInfo != undefined && this.InstalmentInfo != null) + { + this.InstalmentInfo.forEach(value => { + if(value['reference'] == '' || value['reference'] == null) + { + this.canInstalmentRemainCancel = true; + } + }); + } + + if(additionalDetails.cancelType != undefined && additionalDetails.cancelType !=''){ + this.canInstalmentRemainCancel = false; + } + + if(this.canInstalmentRemainCancel == false && payment.data.refundedAmount == 0 ){ + this.canInstalmentCancel = false; + this.canInstalmentAllCancel = true; + } else if(this.canInstalmentCancel == true){ + this.canInstalmentRemainCancel = false; + } + + } + } + } + + }).catch((errorResponse) => { + this.createNotificationError({ + message: `${errorResponse.title}: ${errorResponse.message}` + }); + }); + + }).finally(() => { + this.setNovalnetPayment(false); + }); + }, + immediate: true + } + }, + + methods: { + setNovalnetPayment( novalnetPayment ) { + if( novalnetPayment ) { + this.isNovalnetPayment = novalnetPayment; + } + }, + + showConfirmModal() { + this.status = 100; + this.confirmModalVisible = true; + }, + + showRefundModal() { + this.refundModalVisible = true; + }, + + closeModals() { + this.refundModalVisible = false; + this.confirmModalVisible = false; + this.cancelModalVisible = false; + this.zeroAmountVisible = false; + this.instalmentRefundModalVisible = false; + }, + + showInstalmentAllCancelModal() { + this.instalmentRefundModalVisible = true; + this.cancelType = 'CANCEL_ALL_CYCLES'; + }, + + showInstalmentRemainCancelModal(){ + this.instalmentRefundModalVisible = true; + this.cancelType = 'CANCEL_REMAINING_CYCLES'; + }, + + showCancelModal() { + this.status = 103; + this.cancelModalVisible = true; + }, + + showZeroAmountBlock() { + this.zeroAmountVisible = true; + }, + + reloadPaymentDetails() { + this.closeModals(); + // Wait for the next tick to trigger the reload. Otherwise the Modal won't be hidden correctly. + this.$nextTick().then(() => { + this.$emit('reload-payment'); + }); + }, + + instalmentRefund(item) { + this.refundableAmount = item.totalAmount - item.refundAmount; + this.item = item; + this.refundModalVisible = true; + }, + + showInstalmentCancelModal() { + if (this.InstalmentInfo != undefined && this.InstalmentInfo != null) + { + this.InstalmentInfo.forEach(value => { + if(value['reference'] == '' || value['reference'] == null) + { + this.canInstalmentRemainCancel = true; + } + }); + } + + if(this.instalmentRefundAmount == 0){ + this.canInstalmentAllCancel = true; + } + this.canInstalmentCancel = false; + }, + + disableInstalmentRefund(item) { + if( item.reference == undefined || item.reference == '' || item.refundAmount >= item.totalAmount || !this.acl.can('novalnet_extension.editor')) + { + return true; + } + + return false; + } + } +}); diff --git a/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/view/sw-order-detail-details/sw-order-detail-details.html.twig b/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/view/sw-order-detail-details/sw-order-detail-details.html.twig new file mode 100755 index 0000000..95df792 --- /dev/null +++ b/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/view/sw-order-detail-details/sw-order-detail-details.html.twig @@ -0,0 +1,315 @@ +{% block sw_order_detail_details_payment %} + + + + + + {% block sw_order_detail_details_payment_billing_address %} + + {% endblock %} + + + {% block sw_order_detail_details_payment_method_select %} + + {% if paymentMethod !='' %} + + + {% else %} + + {% endif %} + + {% endblock %} + + + + + {% block sw_order_detail_details_payment_novalnet_seaction %} + + + {% endblock %} +{% endblock %} diff --git a/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/view/sw-order-detail-details/sw-order-detail-details.scss b/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/view/sw-order-detail-details/sw-order-detail-details.scss new file mode 100755 index 0000000..cf7ffa7 --- /dev/null +++ b/src/Resources/app/administration/src/module/novalnet-payment/extension/sw-order/view/sw-order-detail-details/sw-order-detail-details.scss @@ -0,0 +1,103 @@ +dt { + font-weight: 600; + + &:not(:first-child), &:only-of-type{ + padding-top: 10px; + } +} + +.novalnet-payment-action-toolbar { + margin-top: 15px; +} + +.novalnet-payment_chechout-info-customer-comments { + margin-bottom: 10px; +} + +.novalnet-payment-order-page { + padding: 30px; + + border-bottom: 1px solid #d1d9e0 +} + +.novalnet-payment-buyer-notification { + height: 80px; + width: 100%; + display: flex; +} + +.novalnet-payment-buyer-notification-icon-container { + width: 80px; + background: rgb(249, 250, 251); + border-radius: 4px; + border: 1px solid rgb(209, 217, 224); + display: flex; + flex-flow: row nowrap; + justify-content: center; + align-items: center; +} + +.novalnet-payment-buyer-info-name { + margin-top: 16px; + margin-left: 24px; +} + +.novalnet-payment-buyer-info-full-name { + font-weight: 600; + font-size: 18px; +} + +.novalnet-payment-buyer-info-email { + font-size: 14px; +} + +.novalnet-payment-amount-info-total-amount { + font-size: 18px; + font-weight: 600; + height: 25px; + margin-right: 26px; +} + +.novalnet-payment-captured-amount-help-icon, +.novalnet-payment-refuned-amount-help-icon { + margin-left: 8px; +} + +.novalnet-payment-amount-captured-amount { + color: green; + font-size: 14px; +} + +.novalnet-payment-refuned-amount { + color: red; + font-size: 14px; +} + +.novalnet-payment-amount-info-charge-date { + margin-right: 26px; + font-size: 14px; + margin-top: 3px; +} + +.novalnet-payment-amount-info-amount { + margin: 0 0 0 auto; + width: 11em; +} + +.novalnet-payment-checkout-info-header, dt { + font-size: 14px; + font-weight: 600; + line-height: 22px; + margin-bottom: 4px; +} + +.novalnet-payment-checkout-info-comments { + font-size: 14px; +} + +.novalnet-payment-checkout-info-label, +.novalnet-payment-checkout-status-info { + font-size: 14px; +} + + diff --git a/src/Resources/app/administration/src/module/novalnet-payment/index.js b/src/Resources/app/administration/src/module/novalnet-payment/index.js new file mode 100755 index 0000000..3a9962e --- /dev/null +++ b/src/Resources/app/administration/src/module/novalnet-payment/index.js @@ -0,0 +1,69 @@ +import './page/novalnet-payment-settings'; +import './components/novalnet-payment-credentials'; +import './components/novalnet-payment-settings-icon'; +import './extension/sw-order/view/sw-order-detail-base'; +import './extension/sw-order/view/sw-order-detail-details'; +import './extension/sw-order/view/sw-order-create-details'; +import './extension/sw-order/view/sw-order-create-base'; +import './extension/sw-order/view/sw-order-create-general'; +import './extension/sw-order/view/novalnet-payment-refund-modal'; +import './extension/sw-order/view/novalnet-payment-manage-transaction-modal'; +import './extension/sw-order/view/novalnet-payment-instalment-cancel-modal'; +import './extension/sw-order/view/novalnet-payment-book-amount-modal'; +import './extension/sw-order/component/sw-order-user-card'; +import './extension/sw-order/component/sw-order-create-details-payment'; +import './extension/sw-order/component/sw-order-general-info'; + +import deDE from './snippet/de_DE.json'; +import enGB from './snippet/en_GB.json'; + +const { Module } = Shopware; + +Module.register('novalnet-payment', { + + type : 'plugin', + name : 'NovalnetPayment', + title : 'novalnet-payment.module.title', + description :'novalnet-payment.module.description', + + + snippets: { + 'de-DE': deDE, + 'en-GB': enGB + }, + routes: { + index: { + component: 'novalnet-payment-settings', + path: 'index', + meta: { + parentPath: 'sw.settings.index', + privilege: 'novalnet_payment.viewer', + } + }, + detail: { + component: 'novalnet-payment-settings', + path: 'settings', + redirect: { + name: 'novalnet.payment.credentials' + }, + children: { + credentials: { + component: 'novalnet-payment-credentials', + path: 'credentials', + meta: { + parentPath: 'sw.settings.index', + privilege: 'novalnet_payment.viewer', + } + } + } + } + + }, + settingsItem: { + group: 'plugins', + to: 'novalnet.payment.detail.credentials', + iconComponent: 'novalnet-payment-settings-icon', + backgroundEnabled: true, + privilege: 'novalnet_payment.viewer' + } +}); diff --git a/src/Resources/app/administration/src/module/novalnet-payment/page/novalnet-payment-settings/index.js b/src/Resources/app/administration/src/module/novalnet-payment/page/novalnet-payment-settings/index.js new file mode 100755 index 0000000..650d083 --- /dev/null +++ b/src/Resources/app/administration/src/module/novalnet-payment/page/novalnet-payment-settings/index.js @@ -0,0 +1,234 @@ +import template from './novalnet-payment-settings.html.twig'; +import './novalnet-payment-settings.scss'; + + +const { Component, Mixin, Defaults, Context} = Shopware; +const { Criteria } = Shopware.Data; + +Component.register('novalnet-payment-settings', { + template, + + mixins: [ + Mixin.getByName('notification'), + Mixin.getByName('sw-inline-snippet') + ], + + inject: [ + 'repositoryFactory', + 'NovalPaymentApiCredentialsService', + 'acl', + ], + + + data() { + return { + isLoading: false, + isValidating: false, + isSaveSuccessful: false, + isValidateSuccessful: false, + clientIdFilled: false, + clientSecretFilled: false, + shopVersion : false, + config: {}, + salesChannels: [] + + }; + }, + + computed: { + + validateButtonDisabled() { + return this.isLoading || this.isValidating; + }, + + novalnetConfigRoute() { + return { + name: 'novalnet.payment.detail.credentials' + }; + }, + salesChannelRepository() { + return this.repositoryFactory.create('sales_channel'); + } + }, + + created() { + this.createdComponent(); + }, + + watch: { + config: { + deep: true, + handler() { + + const defaultConfig = this.$refs.configComponent.allConfigs.null; + const salesChannelId = this.$refs.configComponent.selectedSalesChannelId; + + if (salesChannelId === null) { + this.clientIdFilled = !!this.config['NovalnetPayment.settings.clientId']; + } else { + this.clientIdFilled = !!this.config['NovalnetPayment.settings.clientId'] + || !!defaultConfig['NovalnetPayment.settings.clientId']; + this.clientSecretFilled = !!this.config['NovalnetPayment.settings.clientSecret']; + } + + this.NovalPaymentApiCredentialsService.getShopVersion().then((shopVersion) => { + if(shopVersion != '' && shopVersion != undefined && shopVersion.version >= '6.5.0.0' ) { + + this.shopVersion = true; + } + }).catch((errorResponse) => { + this.createNotificationError({ + message: `${errorResponse.title}: ${errorResponse.message}` + }); + }); + }, + + }, + + }, + + methods: { + createdComponent() { + this.isLoading = true; + const criteria = new Criteria(); + criteria.addFilter(Criteria.equalsAny('typeId', [ + Defaults.storefrontSalesChannelTypeId, + Defaults.apiSalesChannelTypeId + ])); + this.salesChannelRepository.search(criteria, Shopware.Context.api).then(res => { + res.add({ + id: null, + translated: { + name: this.$tc('sw-sales-channel-switch.labelDefaultOption') + } + }); + this.salesChannels = res; + }).finally(() => { + this.isLoading = false; + }); + }, + onSave() { + this.isSaveSuccessful = false; + this.isLoading = true; + + const clientId = this.getConfigValue('clientId'); + const accessKey = this.getConfigValue('accessKey'); + + if(this.getConfigValue('clientId') !== '' && this.getConfigValue('clientId') !== undefined) + { + const clientId = this.getConfigValue('clientId').replace(/\s/g, ""); + } + + if(this.getConfigValue('accessKey') !== '' && this.getConfigValue('accessKey') !== undefined) + { + const clientId = this.getConfigValue('accessKey').replace(/\s/g, ""); + } + + + if (clientId == undefined || clientId == '') + { + this.isLoading = false; + this.createNotificationError({ + title: this.$tc('novalnet-payment.settingForm.titleError'), + message: this.$tc('novalnet-payment.settingForm.emptyMessage') + }); + + return; + } else if(accessKey == undefined || accessKey == '') { + + this.isLoading = false; + this.createNotificationError({ + title: this.$tc('novalnet-payment.settingForm.titleError'), + message: this.$tc('novalnet-payment.settingForm.emptyAccessKeyMessage') + }); + + return; + } + + this.checkBackendConfiguration(); + }, + + getConfigValue(field) { + const defaultConfig = this.$refs.configComponent.allConfigs.null; + const salesChannelId = this.$refs.configComponent.selectedSalesChannelId; + + if (salesChannelId === null) { + return this.config[`NovalnetPayment.settings.${field}`]; + } + + return this.config[`NovalnetPayment.settings.${field}`] + || defaultConfig[`NovalnetPayment.settings.${field}`]; + }, + + checkBackendConfiguration() { + const me = this; + const clientId = this.getConfigValue('clientId').replace(/\s/g, ""); + const accessKey = this.getConfigValue('accessKey').replace(/\s/g, ""); + + this.NovalPaymentApiCredentialsService.validateApiCredentials(clientId, accessKey).then((response) => { + this.isLoading = false; + + if(response.serverResponse == undefined || response.serverResponse == '') + { + this.createNotificationError({ + title: this.$tc('novalnet-payment.settingForm.titleError'), + message: this.$tc('novalnet-payment.settingForm.apiFailureMessage') + }); + + return; + } + + const status = response.serverResponse.result.status_code; + if(status != 100) + { + this.createNotificationError({ + title: this.$tc('novalnet-payment.settingForm.titleError'), + message: response.serverResponse.result.status_text + }); + + return; + }else + { + response.tariffResponse.forEach(((tariff) => { + if(this.config['NovalnetPayment.settings.tariff'] == undefined || this.config['NovalnetPayment.settings.tariff'] == '') + { + this.config['NovalnetPayment.settings.tariff'] = tariff.id; + } + })); + + this.config['NovalnetPayment.settings.clientKey'] = response.serverResponse.merchant.client_key; + this.$refs.configComponent.save().then((res) => { + this.isSaveSuccessful = true; + + if (res) { + this.config = res; + } + + }).catch(() => { + this.isLoading = false; + }); + + this.createNotificationSuccess({ + title: this.$tc('novalnet-payment.settingForm.titleSuccess'), + message: this.$tc('novalnet-payment.settingForm.successMessage') + }); + + return; + } + }).catch((errorResponse) => { + this.createNotificationError({ + title: this.$tc('novalnet-payment.settingForm.titleError'), + message: this.$tc('novalnet-payment.settingForm.errorMessage') + }); + this.isLoading = false; + this.isTestSuccessful = false; + }); + }, + + }, + metaInfo() { + return { + title: this.$createTitle() + }; + }, +}); diff --git a/src/Resources/app/administration/src/module/novalnet-payment/page/novalnet-payment-settings/novalnet-payment-settings.html.twig b/src/Resources/app/administration/src/module/novalnet-payment/page/novalnet-payment-settings/novalnet-payment-settings.html.twig new file mode 100755 index 0000000..3957a91 --- /dev/null +++ b/src/Resources/app/administration/src/module/novalnet-payment/page/novalnet-payment-settings/novalnet-payment-settings.html.twig @@ -0,0 +1,93 @@ +{% block novalnet_payment_settings %} + + {% block novalnet_payment_settings_header %} + + {% endblock %} + + {% block novalnet_payment_settings_actions %} + + {% endblock %} + + {% block novalnet_payment_content %} + + + {% endblock %} + + +{% endblock %} diff --git a/src/Resources/app/administration/src/module/novalnet-payment/page/novalnet-payment-settings/novalnet-payment-settings.scss b/src/Resources/app/administration/src/module/novalnet-payment/page/novalnet-payment-settings/novalnet-payment-settings.scss new file mode 100755 index 0000000..9fb72ef --- /dev/null +++ b/src/Resources/app/administration/src/module/novalnet-payment/page/novalnet-payment-settings/novalnet-payment-settings.scss @@ -0,0 +1,50 @@ +@import "~scss/variables"; + + +.novalnet-sales-channel { + max-width: 800px; + margin: 0 auto 40px; + position: relative; + color: #52667a; +} + +.novalnet-field--osm-description { + margin: -10px 0 20px 0; +} + +.novalnet_payment-settings-credentials, .novalnet_payment-settings-merchant-credentials{ + margin: 30px; +} + +.novalnet_payment_card_title{ + margin: 15px; + font-size: 18px; + line-height: 24px; + color: #52667a; + display: inline-block; + width: 90%; +} + +.novalnet_payment_css_card_title{ + margin-left: 30px; + font-size: 18px; + line-height: 24px; + color: #52667a; + display: inline-block; +} + +.novalnet_payment_card_head_down_bar{ + display: inline-block; +} + +@media only screen and (max-width: 600px) { + .novalnet_payment_card_title { + width: 75%; + } +} + +@media only screen and (min-device-width : 768px) and (max-device-width : 1024px) { + .novalnet_payment_card_title { + width: 85%; + } +} diff --git a/src/Resources/app/administration/src/module/novalnet-payment/snippet/de_DE.json b/src/Resources/app/administration/src/module/novalnet-payment/snippet/de_DE.json new file mode 100755 index 0000000..09bc940 --- /dev/null +++ b/src/Resources/app/administration/src/module/novalnet-payment/snippet/de_DE.json @@ -0,0 +1,118 @@ +{ + "novalnet-payment" : { + "module" : { + "title": "Novalnet", + "description": "PCI-konforme und lückenlose Integration mit verschiedenen Zahlungsarten und Zahlungsdienstleistungen auf einer Plattform.", + "projectInfo": "Ihr Projekt befindet sich im Testmodus", + "comments": "Kommentare", + "generalInfo": "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", + "globalTitle": "Konfigurationseinstellungen", + "installationInfo": "Für die Einrichtung und Verwendung des Plugins finden Sie die Installationsanleitung Here", + "PaymentConfiguration" : "Wichtiger Hinweis:Die Konfiguration der Zahlungsplugins sind jetzt im Novalnet Admin Portal verfügbar. Navigieren Sie zu Projekts > Wählen Sie Ihr Projekt > Konfiguration des Zahlungsplugins, 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 " + + }, + "settingForm": { + "title": "Novalnet", + "statusTitle": "Zustand", + "amountError": "Ungültiger Betrag", + "buttons": { + "save": "Speichern" + }, + "credentials": { + "cardTitle": "Novalnet API-Konfiguration", + "activationKey": { + "label": "Aktivierungsschlüssel des Produkts *", + "tooltipText": "Ihr Produktaktivierungsschlüssel ist ein eindeutiger Token für die Händlerauthentifizierung und Zahlungsabwicklung.Ihr Produktaktivierungsschlüssel ist ein eindeutiges Token für die Händlerauthentifizierung und Zahlungsabwicklung. Ihren Produktaktivierungsschlüssel finden Sie im Novalnet Admin-Portal : Projekts > Wählen Sie Ihr Projekt > API-Anmeldeinformationen > API-Signatur (Produktaktivierungsschlüssel)" + }, + "accessKey": { + "label": "Zahlungs-Zugriffsschlüssel *", + "tooltipText": "Ihr geheimer Schlüssel zur Verschlüsselung der Daten, um Manipulation und Betrug zu vermeiden. Ihren Paymentzugriffsschlüssel finden Sie im Novalnet Admin-Portal : Projekts > Wählen Sie Ihr Projekt > API-Anmeldeinformationen > Paymentzugriffsschlüssel" + }, + "tariff": { + "label": "Auswahl der Tarif-ID *", + "tooltipText": "Wählen Sie eine Tarif-ID, die dem bevorzugten Tarifplan entspricht, den Sie im Novalnet Admin-Portal für dieses Projekt erstellt haben", + "emptyText": "Tarif-ID auswählen" + }, + "orderEmailMode": { + "label": " Bestellbestätigung per E-Mail aktivieren", + "tooltipText":"Aktivieren Sie diesen Reiter, um eine weitere Bestellbestätigungs-E-Mail mit Novalnet-Transaktionsdetails an den Endkunden für Bestellungen zu senden, die über Rechnung, Vorkasse, Barzahlen oder Multibanco getätigt wurden. (Standardmäßig wird die erste Bestellbestätigungs-E-Mail an Endkunden ohne Novalnet-Transaktionsdetails gesendet.)" + } + }, + "merchantSettings": { + "cardTitle": "Benachrichtigungs- / Webhook-URL festlegen", + "deactivateIp": { + "label": "Manuelles Testen der Benachrichtigungs / Webhook-URL erlauben", + "tooltipText": "Aktivieren Sie diese Option, um die Novalnet-Benachrichtigungs-/Webhook-URL manuell zu testen. Deaktivieren Sie die Option, bevor Sie Ihren Shop liveschalten, um unautorisierte Zugriffe von Dritten zu blockieren." + }, + "mailTo": { + "label": "E-Mails senden an", + "tooltipText": "E-Mail-Benachrichtigungen werden an diese E-Mail-Adresse gesendet" + }, + "callbackUrl": { + "label": "Benachrichtigungs- / Webhook-URL", + "button": "Konfigurieren", + "tooltipText": "Sie müssen die folgende Webhook-URL im Novalnet Admin-Portal hinzufügen. Dadurch können Sie Benachrichtigungen über den Transaktionsstatus erhalten." + } + }, + "extension":{ + "paidTooltip": "Gezahlter Gesamtbetrag", + "refundTooltip": "Rückerstatteter Betrag", + "refundButton": "Rückerstattung", + "amountTitle": "Rückerstattungsbetrag", + "refundDescription": "Geben Sie bitte den erstatteten Betrag ein (in der kleinsten Währungseinheit, z.B. 100 Cent = entsprechen 1.00 EUR)", + "refundReference": "Referenz für die Rückerstattung", + "confirmLabel": "Bestätigen", + "cancelLabel": "Stornieren", + "cancelAllCycleMessage": "Sind Sie sicher, dass Sie alle Ratenzahlungen stornieren wollen?", + "cancelRemainingCycleMessage": "Sind Sie sicher, dass Sie die verbleibende Zyklusrate stornieren möchten?", + "Managetitle": "Transaktion verwalten", + "confirmMessage": "Sind Sie sicher, dass Sie die Zahlung einziehen möchten?", + "cancelMessage": "Sind Sie sicher, dass Sie die Zahlung stornieren wollen?", + "refundSuccess": "Die Rückerstattung war erfolgreich.", + "onholdSuccess": "Die Transaktion wurde bestätigt", + "onholdCancel": "Die Transaktion wurde storniert", + "instalmentCancelLabel": "Ratenzahlung Stornieren", + "instalmentAllCancelLabel":"Gesamte Ratenzahlung stornieren", + "instalmentRemainCancelLabel":"Alle übrigen Installationen abbrechen", + "instalmentSuccessMsg": "Die Ratenzahlung wurde erfolgreich abgebrochen.", + "zeroAmountButton": "Buchbetrag", + "bookedSuccess": "Ihr gebuchter Betrag war erfolgreich.", + "zeroAmountTitle": "Gebuchter Auftrag für diesen Betrag", + "zeroAmountDescription": "Bitte geben Sie den Betrag ein (in der kleinsten Währungseinheit, z.B. 100, was 1,00 entspricht)", + "bookButton": "Buchen Sie" + + }, + "titleSuccess": "Success", + "successMessage": "Die Novalnet-Händlerdaten wurden erfolgreich eingestellt.", + "titleError": "Error", + "apiFailureMessage": "Konfigurieren Sie bitte die zentralen Novalnet-Einstellungen", + "customerFailureMessage": "Bitte wählen Sie Ihren Kunden", + "currencyFailureMessage": "Bitte wählen Sie eine Währung", + "lineitemFailureMessage": "Bitte Produkt hinzufügen", + "amountRefundError": "Ungültiger Rückerstattungsbetrag", + "failureMessage": "Bitte füllen Sie die erforderlichen Felder aus", + "instalmentNumber": "S.No", + "instalmentReference": "Novalnet-Transaktions-ID", + "instalmentDate": "Nächste Rate fällig am", + "instalmentAmount": "Betrag", + "instalmentStatus": "Status", + "instalmentInfo": "Zusammenfassung der Ratenzahlung", + "webhookUrlFailure": "Bitte geben Sie eine gültige Webhook-URL ein", + "webhookUrlSuccess": "Callbackskript-/ Webhook-URL wurde erfolgreich im Novalnet Admin Portal konfiguriert" + + } + }, + "sw-privileges": { + "permissions": { + "novalnet_extension": { + "label": "Novalnet-Erweiterungen" + }, + "parents": { + "novalnet_payment": "Novalnet" + }, + "novalnet_payment": { + "label": "Novalnet Einstellungen" + } + } + } +} diff --git a/src/Resources/app/administration/src/module/novalnet-payment/snippet/en_GB.json b/src/Resources/app/administration/src/module/novalnet-payment/snippet/en_GB.json new file mode 100755 index 0000000..2479708 --- /dev/null +++ b/src/Resources/app/administration/src/module/novalnet-payment/snippet/en_GB.json @@ -0,0 +1,118 @@ +{ + "novalnet-payment" : { + "module" : { + "title": "Novalnet", + "description": "PCI compliant and seamless integration with various payment types and payment processing services in one unique platform...", + "projectInfo": "Your project is in test mode", + "comments": "Comments", + "generalInfo": "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", + "globalTitle": "Global Configuration", + "installationInfo": "For setup and handling of the Novalnet-Payment plugin you can find the installation guide Here", + "PaymentConfiguration" : "Important notice: Payment plugin configurations are now available in the Novalnet Admin Portal. Navigate to the Projects > choose your project > Payment plugin configuration, to configure them.

Novalnet allows you to verify the payment method behaviour before going into production mode by using test payment data. Access the Novalnet test payment data available Here " + }, + "settingForm": { + "title": "Novalnet", + "statusTitle": "Status", + "amountError": "Invalid amount", + "buttons": { + "save": "Save" + }, + "credentials": { + "cardTitle": "Novalnet API Configuration", + "activationKey": { + "label": "Product activation key *", + "tooltipText": "Your product activation key is a unique token for merchant authentication and payment processing. Get your Product activation key from the Novalnet Admin Portal : Projects > Choose your project > API credentials > API Signature (Product activation key)" + }, + "accessKey": { + "label": "Payment access key *", + "tooltipText": "Your secret key used to encrypt the data to avoid user manipulation and fraud. Get your Payment access key from the Novalnet Admin Portal Projects > Choose your project > API credentials > Payment access key" + }, + "tariff": { + "label": "Select Tariff ID *", + "tooltipText": "Select a Tariff ID to match the preferred tariff plan you created at the Novalnet Admin Portal for this project", + "emptyText": "Select Tariff ID" + }, + "orderEmailMode": { + "label": "Enable Order Confirmation E-mail", + "tooltipText": "Enable this configuration to send another Order Confirmation e-mail with Novalnet transaction details to the end customer for orders made through Invoice, Prepayment, Cashpayment, and Multibanco payments. (By default initial Order confirmation e-mail will send to end customers without Novalnet transaction details)" + } + }, + "merchantSettings": { + "cardTitle": "Notification / Webhook URL Setup", + "deactivateIp": { + "label": "Allow manual testing of the Notification / Webhook URL", + "tooltipText": "Enable this to test the Novalnet Notification / Webhook URL manually. Disable this before setting your shop live to block unauthorized calls from external parties" + }, + "mailTo": { + "label": "Send e-mail to", + "tooltipText": "Notification / Webhook URL execution messages will be sent to this e-mail" + }, + "callbackUrl": { + "label": "Notification / Webhook URL", + "button": "Configure", + "tooltipText": "You must configure the webhook endpoint in your Novalnet Admin portal. This will allow you to receive notifications about the transaction." + } + }, + + "extension":{ + "paidTooltip": "Total paid amount", + "refundTooltip": "Refuned amount", + "refundButton": "Refund", + "amountTitle": "Refund amount", + "zeroAmountTitle": "Order Booked for this amount", + "refundDescription": "Please enter the refund amount (in minimum unit of currency. E.g. enter 100 which is equal to 1.00)", + "refundReference": "Refund reference", + "confirmLabel": "Confirm", + "cancelLabel": "Cancel", + "Managetitle": "Manage Transaction", + "confirmMessage": "Are you sure you want to capture the payment?", + "cancelMessage": "Are you sure you want to cancel the payment?", + "cancelAllCycleMessage": "Are you sure you want to cancel all cycle installment?", + "cancelRemainingCycleMessage": "Are you sure you want to cancel remaining cycle installment?", + "refundSuccess": "Your refund was successful.", + "onholdSuccess": "The transaction has been confirmed.", + "onholdCancel": "The transaction has been canceled", + "instalmentCancelLabel": "Instalment Cancel", + "instalmentAllCancelLabel":"Cancel All Instalment", + "instalmentRemainCancelLabel":"Cancel All Remaining Instalment", + "instalmentSuccessMsg": "Instalment canceled successfully.", + "zeroAmountButton": "Book Amount", + "bookedSuccess": "Your amount booked was successful.", + "zeroAmountDescription": "Please enter the amount (in minimum unit of currency. E.g. enter 100 which is equal to 1.00)", + "bookButton": "Book" + }, + "titleSuccess": "Success", + "successMessage": "Novalnet merchant details are configured successfully.", + "titleError": "Error", + "apiFailureMessage": "Please configure Novalnet Global Configuration", + "customerFailureMessage": "Please select your customer", + "currencyFailureMessage": "Please select currency", + "lineitemFailureMessage": "Please Add Product", + "amountRefundError": "Invalid refund amount", + "failureMessage": "Please fill in the required fields", + "instalmentNumber": "S.No", + "instalmentReference": "Novalnet Transaction ID", + "instalmentDate": "Next Instalment Date", + "instalmentAmount": "Amount", + "instalmentStatus": "Status", + "instalmentInfo": "Instalment Summary", + "webhookUrlFailure": "Please enter the valid Webhook URL", + "webhookUrlSuccess": "Notification / Webhook URL is configured successfully in Novalnet Admin Portal" + + + } + }, + "sw-privileges": { + "permissions": { + "novalnet_extension": { + "label": "Novalnet Extensions" + }, + "parents": { + "novalnet_payment": "Novalnet" + }, + "novalnet_payment": { + "label": "Novalnet Settings" + } + } + } +} diff --git a/src/Resources/app/storefront/dist/storefront/js/novalnet-payment.js b/src/Resources/app/storefront/dist/storefront/js/novalnet-payment.js new file mode 100755 index 0000000..23420d1 --- /dev/null +++ b/src/Resources/app/storefront/dist/storefront/js/novalnet-payment.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([["novalnet-payment"],{qseZ:function(e,t,n){"use strict";n.r(t);var r=n("FGIj"),o=n("3xtq"),a=n("prSB"),l=n("k8s9"),u=n("477Q"),c=n("2Y4b"),i=n("gHbT");function m(e){return(m="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function s(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function d(e,t){for(var n=0;n .payment-type > .payment-form{display: none !important;}"}}),p.initiate(w),p.validationResponse((function(e){p.initiate(w)})),e.forEach((function(e){!0===e.checked&&p.uncheckPayment()})),p.selectedPayment((function(e){if(a.a.setItem(f,e.payment_details.type),null!=document.getElementById("confirmOrderForm")&&("GOOGLEPAY"==e.payment_details.type||"APPLEPAY"==e.payment_details.type?document.getElementById("confirmOrderForm").style.display="none":document.getElementById("confirmOrderForm").style.display="block"),0==s.length&&null==m){if(n.value!==t.value){o.a.create(),document.querySelector("#paymentMethod"+n.value).checked=!0;var r=c.a.serialize(h),l=h.getAttribute("action");v.post(l,r,(function(e){o.a.remove(),window.PluginManager.initializePlugins(),document.querySelector("#novalnetId").closest("form").submit()}))}}else document.querySelector("#paymentMethod"+n.value).checked=!0})),1!=s.length&&null==m||document.querySelectorAll('input[name="paymentMethodId"]').forEach((function(e){return e.addEventListener("click",(function(t){e.value!=n.value&&p.uncheckPayment()}))})),p.walletResponse({onProcessCompletion:function(e){return"SUCCESS"==e.result.status?(null!=m&&null!=m?(null!=document.getElementById("parentOrderNumber")&&(e.parentOrderNumber=document.getElementById("parentOrderNumber").value,e.aboId=document.getElementById("aboId").value,e.paymentMethodId=n.value),v.post(document.getElementById("storeCustomerDataUrl").value,JSON.stringify(e),(function(e){var t=JSON.parse(e);if(1==t.success&&null!=t.redirect_url)window.location.replace(t.redirect_url);else{if(1!=t.success)return y._displayErrorMsgSubs(t.message),{status:"FAILURE",statusText:"failure"};document.querySelector("#novalnetchangePaymentForm").submit()}}))):(document.querySelector("#novalnet-paymentdata").value=JSON.stringify(e),setTimeout((function(){document.querySelector("#confirmOrderForm").submit()}),500)),{status:"SUCCESS",statusText:"successfull"}):{status:"FAILURE",statusText:"failure"}}}),null!=r&&null!=r&&r.addEventListener("click",(function(e){if(n.value===t.value){var r=document.querySelector("#tos"),o=document.querySelector("#revocation");if(null!=r&&!r.checked&&null!=o&&!o.checked)return!1;if(null!=document.getElementById("confirmFormSubmit"))document.getElementById("confirmFormSubmit").disabled=!0,new u.a(document.getElementById("confirmFormSubmit")).create();else{var a=document.querySelector('#confirmOrderForm button[type="submit"]');a.disabled=!0,new u.a(a).create()}e.preventDefault(),e.stopImmediatePropagation(),p.getPayment((function(e){"100"==e.result.statusCode||"SUCCESS"==e.result.status?(document.querySelector("#novalnet-paymentdata").value=JSON.stringify(e),document.querySelector("#confirmOrderForm").submit()):(document.querySelector("#novalnet-paymentdata").value="",y._displayErrorMsg(e.result.message),y._showSubmitForm())}))}})),null!=m&&null!=m&&m.addEventListener("click",(function(e){document.querySelector('input[name="paymentMethodId"]:checked').value==n.value&&(e.preventDefault(),e.stopImmediatePropagation(),p.getPayment((function(e){if("100"==e.result.statusCode||"SUCCESS"==e.result.status){var t=new u.a(m);t.create(),null!=document.getElementById("parentOrderNumber")&&(e.parentOrderNumber=document.getElementById("parentOrderNumber").value,e.aboId=document.getElementById("aboId").value,e.paymentMethodId=n.value),v.post(document.getElementById("storeCustomerDataUrl").value,JSON.stringify(e),(function(e){var n=JSON.parse(e);1==n.success&&null!=n.redirect_url?window.location.replace(n.redirect_url):1==n.success?document.querySelector("#novalnetchangePaymentForm").submit():(y._displayErrorMsgSubs(n.message),t.remove())}))}else y._displayErrorMsgSubs(e.result.message)})))})),null!=d&&null!=d&&d.addEventListener("submit",(function(e){if(document.querySelector('input[name="paymentMethodId"]:checked').value==n.value){var t=c.a.serialize(h),r=h.getAttribute("action");v.post(r,t,(function(e){o.a.remove(),window.PluginManager.initializePlugins()}))}}))}))}},{key:"_createScript",value:function(e){var t="https://cdn.novalnet.de/js/pv13/checkout.js?"+(new Date).getTime(),n=document.createElement("script");n.type="text/javascript",n.src=t,n.addEventListener("load",e.bind(this),!1),document.head.appendChild(n)}},{key:"_displayErrorMsg",value:function(e){document.querySelector(".flashbags").innerHTML="";var t=document.createElement("div"),n=document.createElement("div"),r=document.createElement("div"),o=document.createElement("span");t.className="alert alert-danger alert-has-icon",n.className="alert-content-container",r.className="alert-content",o.className="icon icon-blocked",o.innerHTML='',t.appendChild(o),t.appendChild(n),n.appendChild(r),r.innerHTML=e,document.querySelector(".flashbags").appendChild(t),document.querySelector(".flashbags").scrollIntoView()}},{key:"_displayErrorMsgSubs",value:function(e){for(var t=document.getElementsByClassName("alert alert-danger alert-has-icon");t.length>0;)t[0].parentNode.removeChild(t[0]);var n=document.getElementById("novalnetchangePaymentForm"),r=document.createElement("div"),o=document.createElement("div"),a=document.createElement("div"),l=document.createElement("span");r.className="alert alert-danger alert-has-icon",o.className="alert-content-container",a.className="alert-content",l.className="icon icon-blocked",l.innerHTML='',r.appendChild(l),r.appendChild(o),o.appendChild(a),a.innerHTML=e,n.parentNode.insertBefore(r,n),r.scrollIntoView()}},{key:"_showSubmitForm",value:function(){if(null!=document.getElementById("confirmFormSubmit"))document.getElementById("confirmFormSubmit").disabled=!1,new u.a(document.getElementById("confirmFormSubmit")).remove();else{var e=document.querySelector('#confirmOrderForm button[type="submit"]');e.disabled=!1,new u.a(e).remove()}}}])&&d(n.prototype,r),m&&d(n,m),t}(r.a);window.PluginManager.register("NovalnetPayment",v,"#novalnet-payment-script")}},[["qseZ","runtime","vendor-node","vendor-shared"]]]); \ No newline at end of file diff --git a/src/Resources/app/storefront/src/main.js b/src/Resources/app/storefront/src/main.js new file mode 100755 index 0000000..d6f2adf --- /dev/null +++ b/src/Resources/app/storefront/src/main.js @@ -0,0 +1,8 @@ +// import all necessary storefront plugins +import NovalnetPayment from './novalnet-payment/novalnet-payment.plugin'; + + +// register them via the existing PluginManager +const PluginManager = window.PluginManager; +PluginManager.register('NovalnetPayment', NovalnetPayment, '#novalnet-payment-script'); + diff --git a/src/Resources/app/storefront/src/novalnet-payment/novalnet-payment.plugin.js b/src/Resources/app/storefront/src/novalnet-payment/novalnet-payment.plugin.js new file mode 100755 index 0000000..26c2f02 --- /dev/null +++ b/src/Resources/app/storefront/src/novalnet-payment/novalnet-payment.plugin.js @@ -0,0 +1,286 @@ +import Plugin from 'src/plugin-system/plugin.class'; +import PageLoadingIndicatorUtil from 'src/utility/loading-indicator/page-loading-indicator.util'; +import CookieStorageHelper from 'src/helper/storage/cookie-storage.helper'; +import HttpClient from 'src/service/http-client.service'; +import ButtonLoadingIndicator from 'src/utility/loading-indicator/button-loading-indicator.util'; +import FormSerializeUtil from 'src/utility/form/form-serialize.util'; +import DomAccess from 'src/helper/dom-access.helper'; + +export default class NovalnetPayment extends Plugin { + init() { + this._createScript((function() { + let paymentMethods = document.querySelectorAll('input[name="paymentMethodId"]'), + selectedPaymentId = document.querySelector('input[name=paymentMethodId]:checked'), + novalnetpayId = document.querySelector("#novalnetId"), + submitButton = document.querySelector('#confirmOrderForm button[type="submit"]'), + subscriptionSubmitButton = document.querySelector('#novalnetchangePaymentForm button[type="submit"]'), + accountPayment = document.querySelectorAll('form[action$="/account/payment"]'), + accountsubmitButton = document.querySelector('form[action$="/account/payment"]'), + me = this, + paymentForm = new NovalnetPaymentForm(), + cookieName = "novalnetpayNameCookie", + client = new HttpClient(), + selectPayment = CookieStorageHelper.getItem(cookieName), + form = novalnetpayId.closest('form'), + nnCheckPayment = true, + walletConfiguration = DomAccess.getDataAttribute(me.el, 'data-lineitems', false); + + if(selectedPaymentId == undefined){ + selectedPaymentId = document.querySelector("#novalnetId").checked = true; + } + + if(novalnetpayId.value === selectedPaymentId.value) { + nnCheckPayment = false; + } + + let request = { + iframe: "#novalnetPaymentIframe", + initForm: { + orderInformation : { + lineItems: walletConfiguration + }, + showButton: false, + uncheckPayments : nnCheckPayment, + } + }; + + if (CookieStorageHelper.getItem(cookieName) != false && CookieStorageHelper.getItem(cookieName) != undefined && !nnCheckPayment && novalnetpayId.value === selectedPaymentId.value ) { + request.initForm.checkPayment = selectPayment; + } + + if (accountPayment.length == 1) { + request.initForm.styleText = {forceStyling:{text: ".payment-type-container > .payment-type > .payment-form{display: none !important;}"}}; + } + + paymentForm.initiate(request); + + paymentForm.validationResponse((data) => { + paymentForm.initiate(request); + }); + + paymentMethods.forEach((function(e) { + !0 === e.checked && paymentForm.uncheckPayment() + })), + + paymentForm.selectedPayment((function(selectPaymentData) { + CookieStorageHelper.setItem(cookieName, selectPaymentData.payment_details.type); + + if (document.getElementById("confirmOrderForm") != undefined) { + if (selectPaymentData.payment_details.type == 'GOOGLEPAY' || selectPaymentData.payment_details.type == 'APPLEPAY') { + document.getElementById("confirmOrderForm").style.display = "none"; + } else { + document.getElementById("confirmOrderForm").style.display = "block"; + } + } + + if (accountPayment.length == 0 && subscriptionSubmitButton == undefined) { + if (novalnetpayId.value !== selectedPaymentId.value) { + PageLoadingIndicatorUtil.create(); + document.querySelector('#paymentMethod' + novalnetpayId.value).checked = true; + const data = FormSerializeUtil.serialize(form); + const action = form.getAttribute('action'); + client.post(action, data, response => { + PageLoadingIndicatorUtil.remove(); + window.PluginManager.initializePlugins(); + document.querySelector("#novalnetId").closest('form').submit(); + }); + } + } else { + document.querySelector('#paymentMethod' + novalnetpayId.value).checked = true; + } + })); + + if (accountPayment.length == 1 || subscriptionSubmitButton != undefined) { + document.querySelectorAll('input[name="paymentMethodId"]').forEach((payment) => payment.addEventListener('click', (event) => { + if (payment.value != novalnetpayId.value) { + paymentForm.uncheckPayment(); + } + })); + } + + // receive wallet payment Response like gpay and applepay + paymentForm.walletResponse({ + onProcessCompletion: function (response) { + if (response.result.status == 'SUCCESS') { + if (subscriptionSubmitButton != undefined && subscriptionSubmitButton != null) { + if (document.getElementById('parentOrderNumber') != undefined) + { + response.parentOrderNumber = document.getElementById('parentOrderNumber').value; + response.aboId = document.getElementById('aboId').value; + response.paymentMethodId = novalnetpayId.value; + } + client.post(document.getElementById('storeCustomerDataUrl').value, JSON.stringify(response), result => { + const res = JSON.parse(result); + if(res.success == true && res.redirect_url != undefined) + { + window.location.replace(res.redirect_url); + } else if(res.success == true) + { + document.querySelector('#novalnetchangePaymentForm').submit(); + } else { + me._displayErrorMsgSubs(res.message); + return {status: 'FAILURE', statusText: 'failure'}; + } + }); + } else { + document.querySelector('#novalnet-paymentdata').value = JSON.stringify(response); + setTimeout(function() { + document.querySelector('#confirmOrderForm').submit(); + }, 500); + } + return {status: 'SUCCESS', statusText: 'successfull'}; + } else { + return {status: 'FAILURE', statusText: 'failure'}; + } + } + }); + + if (submitButton != undefined && submitButton != null) { + submitButton.addEventListener('click', (event) => { + if (novalnetpayId.value === selectedPaymentId.value) { + let tosInput = document.querySelector('#tos'); + let revocation = document.querySelector('#revocation'); + + if ((tosInput != undefined && !tosInput.checked) && (revocation != undefined && !revocation.checked)) { + return false; + } + + if (document.getElementById("confirmFormSubmit") != undefined) { + document.getElementById("confirmFormSubmit").disabled = true; + const loader = new ButtonLoadingIndicator(document.getElementById("confirmFormSubmit")); + loader.create(); + } else { + let submitButton = document.querySelector('#confirmOrderForm button[type="submit"]'); + submitButton.disabled = true; + const loader = new ButtonLoadingIndicator(submitButton); + loader.create(); + } + + event.preventDefault(); + event.stopImmediatePropagation(); + paymentForm.getPayment((function(paymentDetails) { + if (paymentDetails.result.statusCode == '100' || paymentDetails.result.status == 'SUCCESS') { + document.querySelector('#novalnet-paymentdata').value = JSON.stringify(paymentDetails); + document.querySelector('#confirmOrderForm').submit(); + + } else { + document.querySelector('#novalnet-paymentdata').value = ''; + me._displayErrorMsg(paymentDetails.result.message); + me._showSubmitForm(); + } + })); + } + }); + } + + if (subscriptionSubmitButton != undefined && subscriptionSubmitButton != null) { + subscriptionSubmitButton.addEventListener('click', (event) => { + if (document.querySelector('input[name="paymentMethodId"]:checked').value == novalnetpayId.value) { + + event.preventDefault(); + event.stopImmediatePropagation(); + + paymentForm.getPayment((function(paymentDetails) { + if (paymentDetails.result.statusCode == '100' || paymentDetails.result.status == 'SUCCESS') { + + const loader = new ButtonLoadingIndicator(subscriptionSubmitButton); + loader.create(); + + if (document.getElementById('parentOrderNumber') != undefined) + { + paymentDetails.parentOrderNumber = document.getElementById('parentOrderNumber').value; + paymentDetails.aboId = document.getElementById('aboId').value; + paymentDetails.paymentMethodId = novalnetpayId.value; + } + client.post(document.getElementById('storeCustomerDataUrl').value, JSON.stringify(paymentDetails), response => { + const res = JSON.parse(response); + if(res.success == true && res.redirect_url != undefined) + { + window.location.replace(res.redirect_url); + } else if(res.success == true) + { + document.querySelector('#novalnetchangePaymentForm').submit(); + } else { + me._displayErrorMsgSubs(res.message); + loader.remove(); + } + }); + } else { + me._displayErrorMsgSubs(paymentDetails.result.message); + } + })); + } + }); + } + + if (accountsubmitButton != null && accountsubmitButton != undefined) { + accountsubmitButton.addEventListener('submit', (event) => { + if (document.querySelector('input[name="paymentMethodId"]:checked').value == novalnetpayId.value) { + const data = FormSerializeUtil.serialize(form); + const action = form.getAttribute('action'); + client.post(action, data, response => { + PageLoadingIndicatorUtil.remove(); + window.PluginManager.initializePlugins(); + }); + } + }); + } + })); + } + + _createScript(callback) { + const url = 'https://cdn.novalnet.de/js/pv13/checkout.js?' + new Date().getTime(); + const script = document.createElement('script'); + script.type = 'text/javascript'; + script.src = url; + script.addEventListener('load', callback.bind(this), false); document.head.appendChild(script); + } + + _displayErrorMsg(errorMessage) { + document.querySelector('.flashbags').innerHTML = ''; + let parentDiv = document.createElement('div'); + let childDiv1 = document.createElement('div'); + let childDiv2 = document.createElement('div'); + let spanTag = document.createElement('span'); + parentDiv.className= "alert alert-danger alert-has-icon";childDiv1.className= "alert-content-container";childDiv2.className= "alert-content";spanTag.className= "icon icon-blocked"; + spanTag.innerHTML = ''; + parentDiv.appendChild(spanTag);parentDiv.appendChild(childDiv1);childDiv1.appendChild(childDiv2); + childDiv2.innerHTML = errorMessage; + document.querySelector('.flashbags').appendChild(parentDiv); + document.querySelector('.flashbags').scrollIntoView(); + } + + _displayErrorMsgSubs(errorMessage) { + const elements = document.getElementsByClassName('alert alert-danger alert-has-icon'); + + while(elements.length > 0){ + elements[0].parentNode.removeChild(elements[0]); + } + + var formElement = document.getElementById('novalnetchangePaymentForm'); + let parentDiv = document.createElement('div'); + let childDiv1 = document.createElement('div'); + let childDiv2 = document.createElement('div'); + let spanTag = document.createElement('span'); + parentDiv.className= "alert alert-danger alert-has-icon";childDiv1.className= "alert-content-container";childDiv2.className= "alert-content";spanTag.className= "icon icon-blocked"; + spanTag.innerHTML = ''; + parentDiv.appendChild(spanTag);parentDiv.appendChild(childDiv1);childDiv1.appendChild(childDiv2); + childDiv2.innerHTML = errorMessage; + + formElement.parentNode.insertBefore(parentDiv, formElement); + parentDiv.scrollIntoView(); + } + + _showSubmitForm() { + if(document.getElementById("confirmFormSubmit") != undefined) { + document.getElementById("confirmFormSubmit").disabled = false; + const loader = new ButtonLoadingIndicator(document.getElementById("confirmFormSubmit")); + loader.remove(); + } else { + let submitButton = document.querySelector('#confirmOrderForm button[type="submit"]'); + submitButton.disabled = false; + const loader = new ButtonLoadingIndicator(submitButton); + loader.remove(); + } + } +} diff --git a/src/Resources/app/storefront/src/scss/base.scss b/src/Resources/app/storefront/src/scss/base.scss new file mode 100755 index 0000000..c34ec12 --- /dev/null +++ b/src/Resources/app/storefront/src/scss/base.scss @@ -0,0 +1,138 @@ +.nnhide { + display: none !important; +} + +div[class^="nn-apple-pay-button"], div[class^="nn-google-pay-button"] { + margin-top: 0.25rem; +} + +div[class^="nn-apple-pay-button"] > button { + width: 100% +} + +.novalnet-test-mode { + position: relative; + background-color: #0080c9; + color: #fff; + padding: 10px 20px; + font-size: 10px; + text-align: center; + text-transform: uppercase; + letter-spacing: 1px; + line-height: 0.8px; + border-radius: 0px 0px 5px 5px; + transition: transform 0.5s ease 0.5s; + animation: novalnet-test-mode-blinker 2s linear infinite; + font-weight: bold; + float:right; +} + +#novalnetSepaMandate:hover { + cursor:pointer; + text-decoration: underline; +} + +#novalnetsepa-payment, #novalnetsepaguarantee-payment, #novalnetcreditcard-payment, #novalnetinvoiceguarantee-payment, #novalnetinvoiceinstalment-payment, #novalnetsepainstalment-payment { + display: none; +} + +#novalnetsepa-payment-form, #novalnetsepaguarantee-payment-form, #novalnetcreditcard-payment-form, #novalnetinvoiceguarantee-payment-form, #novalnetinvoiceinstalment-payment-form, #novalnetsepainstalment-payment-form { + display: block; +} + +.nn-payment-notification { + display:none; +} + +.nn-zero-amount-notification { + display:none; +} + +@keyframes novalnet-test-mode-blinker { + 50% { + opacity: 0; + } +} + +.novalnet-input-field-container { + width: 100%; +} + +#sepa_mandate_toggle { + cursor:pointer; + color: #5f7285; +} + +#sepa_mandate_toggle:hover { + text-decoration:underline; +} + +#sepa_mandate { + cursor:pointer; + color: #5f7285; +} + +#sepa_mandate:hover { + text-decoration:underline; +} + +.novalnet-challenge-window-overlay { + position: fixed ! important; + width: 100% ! important; + height: 100% ! important; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: rgba(0,0,0,0.5); + z-index: 2; + cursor: pointer; +} + +@media only screen and (max-width: 600px) { + #nnIframe { + width: 100%; + } +} + +.novalnet-SavedPaymentMethods { + list-style: none outside; + margin: 0; + .novalnet-SavedPaymentMethods-token, + .novalnet-SavedPaymentMethods-new { + margin: 0 0 0.5em; + label { + cursor: pointer; + } + } + .novalnet-SavedPaymentMethods-tokenInput { + vertical-align: middle; + margin: -3px 1em 0 0; + position: relative; + } +} + +.novalnetInstalmentInfo { + cursor: pointer; + text-decoration: none; + background-color: transparent; + width: fit-content; + margin-top: 5px; + margin-bottom: 5px; +} + +.novalnetinstalment-table { + border: 1px solid; + border-color: #bcc1c7; + text-align: center; +} + +.novalnetorder-comments +{ + padding: 1rem; +} + +.novalnetorder-comments-header +{ + padding: 0rem 1rem; +} diff --git a/src/Resources/config/plugin.png b/src/Resources/config/plugin.png new file mode 100755 index 0000000..cf08ece Binary files /dev/null and b/src/Resources/config/plugin.png differ diff --git a/src/Resources/config/routes.xml b/src/Resources/config/routes.xml new file mode 100755 index 0000000..25081e7 --- /dev/null +++ b/src/Resources/config/routes.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/src/Resources/config/services.xml b/src/Resources/config/services.xml new file mode 100755 index 0000000..d20f1cb --- /dev/null +++ b/src/Resources/config/services.xml @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + %kernel.shopware_version% + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Resources/public/administration/css/novalnet-payment.css b/src/Resources/public/administration/css/novalnet-payment.css new file mode 100755 index 0000000..7940b21 --- /dev/null +++ b/src/Resources/public/administration/css/novalnet-payment.css @@ -0,0 +1 @@ +.novalnet-sales-channel{max-width:800px;margin:0 auto 40px;position:relative;color:#52667a}.novalnet-field--osm-description{margin:-10px 0 20px}.novalnet_payment-settings-credentials,.novalnet_payment-settings-merchant-credentials{margin:30px}.novalnet_payment_card_title{margin:15px;width:90%}.novalnet_payment_card_title,.novalnet_payment_css_card_title{font-size:18px;line-height:24px;color:#52667a;display:inline-block}.novalnet_payment_css_card_title{margin-left:30px}.novalnet_payment_card_head_down_bar{display:inline-block}@media only screen and (max-width:600px){.novalnet_payment_card_title{width:75%}}@media only screen and (min-device-width:768px)and (max-device-width:1024px){.novalnet_payment_card_title{width:85%}}.novalnet_payment-settings-project{font-size:14px;margin-bottom:8px}.novalnet-payment-callback-field{margin-bottom:15px}dt{font-weight:600}dt:not(:first-child),dt:only-of-type{padding-top:10px}.novalnet-payment-action-toolbar{margin-top:15px}.novalnet-payment_chechout-info-customer-comments{margin-bottom:10px}.novalnet-payment-order-page{padding:30px;border-bottom:1px solid #d1d9e0}.novalnet-payment-buyer-notification{height:80px;width:100%;display:flex}.novalnet-payment-buyer-notification-icon-container{width:80px;background:#f9fafb;border-radius:4px;border:1px solid #d1d9e0;display:flex;flex-flow:row nowrap;justify-content:center;align-items:center}.novalnet-payment-buyer-info-name{margin-top:16px;margin-left:24px}.novalnet-payment-buyer-info-full-name{font-weight:600;font-size:18px}.novalnet-payment-buyer-info-email{font-size:14px}.novalnet-payment-amount-info-total-amount{font-size:18px;font-weight:600;height:25px;margin-right:26px}.novalnet-payment-captured-amount-help-icon,.novalnet-payment-refuned-amount-help-icon{margin-left:8px}.novalnet-payment-amount-captured-amount{color:green;font-size:14px}.novalnet-payment-refuned-amount{color:red;font-size:14px}.novalnet-payment-amount-info-charge-date{margin-right:26px;font-size:14px;margin-top:3px}.novalnet-payment-amount-info-amount{margin:0 0 0 auto;width:11em}.novalnet-payment-checkout-info-header,dt{font-size:14px;font-weight:600;line-height:22px;margin-bottom:4px}.novalnet-payment-checkout-info-comments,.novalnet-payment-checkout-info-label,.novalnet-payment-checkout-status-info{font-size:14px} \ No newline at end of file diff --git a/src/Resources/public/administration/js/novalnet-payment.js b/src/Resources/public/administration/js/novalnet-payment.js new file mode 100755 index 0000000..878a6af --- /dev/null +++ b/src/Resources/public/administration/js/novalnet-payment.js @@ -0,0 +1 @@ +!function(t){var e={};function n(a){if(e[a])return e[a].exports;var o=e[a]={i:a,l:!1,exports:{}};return t[a].call(o.exports,o,o.exports,n),o.l=!0,o.exports}n.m=t,n.c=e,n.d=function(t,e,a){n.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:a})},n.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},n.t=function(t,e){if(1&e&&(t=n(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var a=Object.create(null);if(n.r(a),Object.defineProperty(a,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var o in t)n.d(a,o,function(e){return t[e]}.bind(null,o));return a},n.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(e,"a",e),e},n.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},n.p="/bundles/novalnetpayment/",n(n.s="Cb2X")}({"0b8U":function(t,e,n){},Cb2X:function(t,e,n){"use strict";n.r(e);n("Hg1N");var a=Shopware,o=a.Component,i=a.Mixin,l=a.Defaults,r=(a.Context,Shopware.Data.Criteria);o.register("novalnet-payment-settings",{template:'{% block novalnet_payment_settings %}\n \n {% block novalnet_payment_settings_header %}\n \n {% endblock %}\n \n {% block novalnet_payment_settings_actions %}\n \n {% endblock %}\n \n {% block novalnet_payment_content %}\n\t\t\t\n\t\t\t\n {% endblock %} \n \n \n{% endblock %}\n',mixins:[i.getByName("notification"),i.getByName("sw-inline-snippet")],inject:["repositoryFactory","NovalPaymentApiCredentialsService","acl"],data:function(){return{isLoading:!1,isValidating:!1,isSaveSuccessful:!1,isValidateSuccessful:!1,clientIdFilled:!1,clientSecretFilled:!1,shopVersion:!1,config:{},salesChannels:[]}},computed:{validateButtonDisabled:function(){return this.isLoading||this.isValidating},novalnetConfigRoute:function(){return{name:"novalnet.payment.detail.credentials"}},salesChannelRepository:function(){return this.repositoryFactory.create("sales_channel")}},created:function(){this.createdComponent()},watch:{config:{deep:!0,handler:function(){var t=this,e=this.$refs.configComponent.allConfigs.null;null===this.$refs.configComponent.selectedSalesChannelId?this.clientIdFilled=!!this.config["NovalnetPayment.settings.clientId"]:(this.clientIdFilled=!!this.config["NovalnetPayment.settings.clientId"]||!!e["NovalnetPayment.settings.clientId"],this.clientSecretFilled=!!this.config["NovalnetPayment.settings.clientSecret"]),this.NovalPaymentApiCredentialsService.getShopVersion().then((function(e){""!=e&&null!=e&&e.version>="6.5.0.0"&&(t.shopVersion=!0)})).catch((function(e){t.createNotificationError({message:"".concat(e.title,": ").concat(e.message)})}))}}},methods:{createdComponent:function(){var t=this;this.isLoading=!0;var e=new r;e.addFilter(r.equalsAny("typeId",[l.storefrontSalesChannelTypeId,l.apiSalesChannelTypeId])),this.salesChannelRepository.search(e,Shopware.Context.api).then((function(e){e.add({id:null,translated:{name:t.$tc("sw-sales-channel-switch.labelDefaultOption")}}),t.salesChannels=e})).finally((function(){t.isLoading=!1}))},onSave:function(){this.isSaveSuccessful=!1,this.isLoading=!0;var t=this.getConfigValue("clientId"),e=this.getConfigValue("accessKey");if(""!==this.getConfigValue("clientId")&&void 0!==this.getConfigValue("clientId"))this.getConfigValue("clientId").replace(/\s/g,"");if(""!==this.getConfigValue("accessKey")&&void 0!==this.getConfigValue("accessKey"))this.getConfigValue("accessKey").replace(/\s/g,"");return null==t||""==t?(this.isLoading=!1,void this.createNotificationError({title:this.$tc("novalnet-payment.settingForm.titleError"),message:this.$tc("novalnet-payment.settingForm.emptyMessage")})):null==e||""==e?(this.isLoading=!1,void this.createNotificationError({title:this.$tc("novalnet-payment.settingForm.titleError"),message:this.$tc("novalnet-payment.settingForm.emptyAccessKeyMessage")})):void this.checkBackendConfiguration()},getConfigValue:function(t){var e=this.$refs.configComponent.allConfigs.null;return null===this.$refs.configComponent.selectedSalesChannelId?this.config["NovalnetPayment.settings.".concat(t)]:this.config["NovalnetPayment.settings.".concat(t)]||e["NovalnetPayment.settings.".concat(t)]},checkBackendConfiguration:function(){var t=this,e=this.getConfigValue("clientId").replace(/\s/g,""),n=this.getConfigValue("accessKey").replace(/\s/g,"");this.NovalPaymentApiCredentialsService.validateApiCredentials(e,n).then((function(e){if(t.isLoading=!1,null!=e.serverResponse&&""!=e.serverResponse)return 100!=e.serverResponse.result.status_code?void t.createNotificationError({title:t.$tc("novalnet-payment.settingForm.titleError"),message:e.serverResponse.result.status_text}):(e.tariffResponse.forEach((function(e){null!=t.config["NovalnetPayment.settings.tariff"]&&""!=t.config["NovalnetPayment.settings.tariff"]||(t.config["NovalnetPayment.settings.tariff"]=e.id)})),t.config["NovalnetPayment.settings.clientKey"]=e.serverResponse.merchant.client_key,t.$refs.configComponent.save().then((function(e){t.isSaveSuccessful=!0,e&&(t.config=e)})).catch((function(){t.isLoading=!1})),void t.createNotificationSuccess({title:t.$tc("novalnet-payment.settingForm.titleSuccess"),message:t.$tc("novalnet-payment.settingForm.successMessage")}));t.createNotificationError({title:t.$tc("novalnet-payment.settingForm.titleError"),message:t.$tc("novalnet-payment.settingForm.apiFailureMessage")})})).catch((function(e){t.createNotificationError({title:t.$tc("novalnet-payment.settingForm.titleError"),message:t.$tc("novalnet-payment.settingForm.errorMessage")}),t.isLoading=!1,t.isTestSuccessful=!1}))}},metaInfo:function(){return{title:this.$createTitle()}}});n("FGZA");function s(t){return s="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},s(t)}function c(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(t);e&&(a=a.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),n.push.apply(n,a)}return n}function d(t){for(var e=1;e\n\t
\n\t\t\n\n\t\t\t{% block novalnet_payment_content_card_channel_config_credentials_card_container %}\n\t\t\t\t\n\n\t\t\t\t\t{% block novalnet_payment_content_card_channel_config_credentials_card_container_settings %}\n\t\t\t\t\t\t
\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t{{ $tc(\'novalnet-payment.module.projectInfo\') }}\n\t\t\t\t\t\t\n\n\t\t\t\t\t\t
\n\t\t\t\t\t\t
\n\t\t\t\t\t\t
\n\t\t\t\t\t\t
\n\t\t\t\t\t\t
\n\n\t\t\t\t\t\t\t{% block novalnet_payment_content_card_channel_config_credentials_card_container_settings_client_id %}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t{% endblock %}\n\t\t\t\t\t\t\t{% block novalnet_payment_content_card_channel_config_credentials_card_container_settings_break %}\n\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t{% endblock %}\n\n\t\t\t\t\t\t\t{% block novalnet_payment_content_card_channel_config_credentials_card_container_settings_client_secret %}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t{% endblock %}\n\t\t\t\t\t\t
\n\t\t\t\t\t{% endblock %}\n\n\t\t\t\t\t{% block novalnet_payment_content_card_loading %}\n \n {% endblock %}\n\n\t\t\t\t
\n\t\t\t{% endblock %}\n\t\t
\n\t{% endblock %}\n\t{% block novalnet_payment_content_card_channel_config_merchant_credentials %}\n\t\t\n\t\t\t{% block novalnet_payment_content_card_channel_config_merchant_credentials_card_container %}\n\t\t\t\t\n\t\t\t\t\t{% block novalnet_payment_content_card_channel_config_merchant_credentials_card_container_settings %}\n\t\t\t\t\t\t
\n\t\t\t\t\t\t\t{% block novalnet_payment_content_card_channel_config_merchant_credentials_card_container_settings_ip %}\n\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t{{ $tc(\'novalnet-payment.settingForm.merchantSettings.callbackUrl.button\') }}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t{% endblock %}\n\t\t\t\t\t\t
\n\t\t\t\t\t{% endblock %}\n\t\t\t\t
\n\t\t\t{% endblock %}\n\t\t
\n\t
\n\n{% endblock %}\n',mixins:[f.getByName("notification"),f.getByName("sw-inline-snippet")],name:"NovalnetPaymentCredentials",icon:"default-action-settings",props:{actualConfigData:{type:Object,required:!0},allConfigs:{type:Object,required:!0},selectedSalesChannelId:{required:!0},domain:{type:String,required:!0,default:""}},data:function(){return{allConfigs:{},config:{},tariffOptions:[],actualConfigData:{},shouldDisable:!1,projectMode:!1,apiActivationKey:"",paymentAccessKey:"",tariffId:"",isLoading:!1,isRequested:"",showMessage:!1,buttonLoad:!1,NovalnetPaymentCallBackUrl:(window.location.protocol+"//"+window.location.host+window.location.pathname).split("/admin").join("")+"/novalnet/callback",generalInformation:this.$tc("novalnet-payment.module.generalInfo"),PaymentConfiguration:this.$tc("novalnet-payment.module.PaymentConfiguration")}},inject:["repositoryFactory","NovalPaymentApiCredentialsService","systemConfigApiService","acl"],watch:{actualConfigData:{handler:function(t){t&&this.$emit("input",t)},deep:!0}},computed:{actualConfigData:{get:function(){return this.allConfigs[this.selectedSalesChannelId]},set:function(t){this.allConfigs=d(d({},this.allConfigs),{},m({},this.selectedSalesChannelId,t))}}},created:function(){this.createdComponent()},updated:function(){this.createdComponent()},methods:{checkTextFieldInheritance:function(t){return"string"!=typeof t||t.length<=0},checkBoolFieldInheritance:function(t){return"boolean"!=typeof t},checkNumberFieldInheritance:function(t){return"int"!=typeof t},onCheckApi:function(){"NovalnetPayment.settings.clientId"===event.target.name?this.apiActivationKey=this.actualConfigData["NovalnetPayment.settings.clientId"]=event.target.value:"NovalnetPayment.settings.accessKey"===event.target.name&&(this.paymentAccessKey=this.actualConfigData["NovalnetPayment.settings.accessKey"]=event.target.value),""!==this.apiActivationKey||""!==this.paymentAccessKey?(this.isRequested="",this.showMessage=!0,this.createdComponent()):this.createNotificationError({title:this.$tc("novalnet-payment.settingForm.titleError"),message:this.$tc("novalnet-payment.settingForm.apiFailureMessage")})},createdComponent:function(){var t=this,e=this;void 0!==this.actualConfigData&&this.isRequested!==this.selectedSalesChannelId&&(this.isRequested=this.selectedSalesChannelId,this.apiActivationKey=this.actualConfigData["NovalnetPayment.settings.clientId"]||this.allConfigs.null["NovalnetPayment.settings.clientId"],this.paymentAccessKey=this.actualConfigData["NovalnetPayment.settings.accessKey"]||this.allConfigs.null["NovalnetPayment.settings.accessKey"],void 0!==this.apiActivationKey&&""!==this.apiActivationKey&&void 0!==this.paymentAccessKey&&""!==this.paymentAccessKey&&(this.apiActivationKey=this.apiActivationKey.replace(/\s/g,""),this.paymentAccessKey=this.paymentAccessKey.replace(/\s/g,""),this.isLoading=!0,this.NovalPaymentApiCredentialsService.validateApiCredentials(this.apiActivationKey,this.paymentAccessKey).then((function(n){var a=n.serverResponse.result.status_code;t.isLoading=!1,100!==a?(!0===t.showMessage&&t.createNotificationError({title:t.$tc("novalnet-payment.settingForm.titleError"),message:n.serverResponse.result.status_text,autoClose:!0}),t.showMessage=!1):(e.tariffOptions=[],n.tariffResponse.forEach((function(a){t.actualConfigData["NovalnetPayment.settings.clientKey"]=n.serverResponse.merchant.client_key,e.tariffOptions.push({value:a.id,label:a.name}),void 0!==t.tariffId&&""!==t.tariffId||(t.tariffId=a.id),!0===t.showMessage&&t.createNotificationSuccess({title:t.$tc("novalnet-payment.settingForm.titleSuccess"),message:t.$tc("novalnet-payment.settingForm.successMessage"),autoClose:!0}),t.showMessage=!1,1===n.serverResponse.merchant.test_mode&&(t.projectMode=!0)})))})).catch((function(e){t.isLoading=!1}))))},configureWebhookUrl:function(){var t=this,e=this.apiActivationKey||this.actualConfigData["NovalnetPayment.settings.clientKey"],n=this.paymentAccessKey||this.actualConfigData["NovalnetPayment.settings.accessKey"];if(void 0!==e&&""!==e&&void 0!==n&&""!==n){if(this.NovalnetPaymentCallBackUrl){if(!1===/^(http|https):\/\/[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,}(:[0-9]{1,5})?(\/.*)?$/i.test(this.NovalnetPaymentCallBackUrl))return this.createNotificationError({message:this.$tc("novalnet-payment.settingForm.webhookUrlFailure")}),!1;this.buttonLoad=!0,this.NovalPaymentApiCredentialsService.configureWebhookUrl(this.NovalnetPaymentCallBackUrl,e,n).then((function(e){void 0!==e.result.status&&null!=e.result.status&&""!==e.result.status&&"SUCCESS"===e.result.status?t.createNotificationSuccess({message:t.$tc("novalnet-payment.settingForm.webhookUrlSuccess")}):void 0!==e.result.status_text&&null!=e.result.status_text&&""!==e.result.status_text?t.createNotificationError({message:e.result.status_text}):t.createNotificationError({message:t.$tc("novalnet-payment.settingForm.webhookUrlFailure")}),t.buttonLoad=!1})).catch((function(e){t.buttonLoad=!1}))}}else this.createNotificationError({title:this.$tc("novalnet-payment.settingForm.titleError"),message:this.$tc("novalnet-payment.settingForm.apiFailureMessage")})}}});Shopware.Component.register("novalnet-payment-settings-icon",{template:'{% block novalnet_payment_settings_icon %}\n \n{% endblock %}\n'});n("mrDW");var y=Shopware,v=y.Component,g=y.Mixin,b=(y.Filter,y.Context),_=Shopware.Data.Criteria,w=Shopware.Utils.format.currency;v.override("sw-order-detail-base",{template:'{% block sw_order_detail_customer_comment_card %}\n\t{% parent %}\n\t\n\n{% endblock %}\n',inject:["NovalPaymentApiCredentialsService","repositoryFactory","acl"],mixins:[g.getByName("notification")],props:{orderId:{type:String,required:!0},paymentDetails:{type:Object,required:!0}},data:function(){return{isLoading:!1,order:{},orderAmount:0,isNovalnetPayment:!1,stateMachineState:null,novalnetComments:"",orderTotalAmount:"",orderPaidAmount:0,orderRefundedAmount:0,canRefund:!1,refundModalVisible:!1,confirmModalVisible:!1,cancelModalVisible:!1,item:{},status:0,canCaptureVoid:!1,refundableAmount:0,canInstalmentShow:!1,InstalmentInfo:[],cancelType:"",canInstalmentCancel:!1,canInstalmentAllCancel:!1,canInstalmentRemainCancel:!1,instalmentRefundAmount:0,instalmentRefundModalVisible:!1,canZeroAmountBooking:!1,zeroAmountVisible:!1,payLater:["INVOICE","CASHPAYMENT","MULTIBANCO","PREPAYMENT"],instalmentPayments:["INSTALMENT_INVOICE","INSTALMENT_DIRECT_DEBIT_SEPA"],onholdStatus:["91","99","98","85"]}},computed:{getInstalmentColums:function(){return[{property:"number",dataIndex:"number",label:this.$tc("novalnet-payment.settingForm.instalmentNumber"),width:"50px"},{property:"reference",dataIndex:"reference",label:this.$tc("novalnet-payment.settingForm.instalmentReference"),width:"120px"},{property:"amount",dataIndex:"amount",label:this.$tc("novalnet-payment.settingForm.instalmentAmount"),width:"80px"},{property:"totalAmount",dataIndex:"totalAmount",visible:!1},{property:"refundAmount",dataIndex:"refundAmount",visible:!1},{property:"nextCycle",dataIndex:"nextCycle",label:this.$tc("novalnet-payment.settingForm.instalmentDate"),width:"120px"},{property:"status",dataIndex:"status",label:this.$tc("novalnet-payment.settingForm.instalmentStatus"),width:"80px"}]}},watch:{orderId:{deep:!0,handler:function(){var t=this;if(this.orderId){var e=this.repositoryFactory.create("order"),n=new _(1,1);n.addAssociation("transactions"),n.addAssociation("currency"),n.addFilter(_.equals("id",this.orderId)),e.search(n,b.api).then((function(e){var n=e.first();if(n){t.identifier||(t.identifier=n.orderNumber);var a=!1,o="",i=t.$tc("novalnet-payment.module.comments");n.transactions.sort((function(t,e){return new Date(e.createdAt)-new Date(t.createdAt)})).forEach((function(e){if(e.customFields&&e.customFields.novalnet_comments)return t.stateMachineState=e.stateMachineState.name,a=!0,""!=o&&(o+="
"+i+"
"),o+=e.customFields.novalnet_comments.split("/ ").join("
"),!0})),a?(t.novalnetComments=o.split("&&").join("
"+i+"
"),t.setNovalnetPayment(!0),t.isNovalnetPayment=!0):(t.setNovalnetPayment(!1),t.isNovalnetPayment=!1),t.canRefund=!1,t.canCaptureVoid=!1,t.canInstalmentShow=!1,t.InstalmentInfo=[],t.canInstalmentCancel=!1,t.canZeroAmountBooking=!1,t.canInstalmentAllCancel=!1,t.canInstalmentRemainCancel=!1,t.NovalPaymentApiCredentialsService.getNovalnetAmount(n.orderNumber).then((function(e){if(""!=e.data&&null!=e.data&&e.data.gatewayStatus){t.refundableAmount=Number(e.data.amount)-Number(e.data.refundedAmount),t.orderAmount=Math.round(100*Number(n.price.totalPrice)),0!=e.data.amount?t.orderTotalAmount=w(e.data.amount/100,n.currency.shortName):t.orderTotalAmount=w(n.price.totalPrice,n.currency.shortName),0!=e.data.paidAmount?t.orderPaidAmount=w(e.data.paidAmount/100,n.currency.shortName):t.orderPaidAmount=w(0,n.currency.shortName),0!=e.data.refundedAmount?t.orderRefundedAmount=w(e.data.refundedAmount/100,n.currency.shortName):t.orderRefundedAmount=w(0,n.currency.shortName);var a=JSON.parse(e.data.additionalDetails);if((e.data.amount>0&&"CONFIRMED"==e.data.gatewayStatus&&!t.instalmentPayments.includes(e.data.paymentType)&&Number(e.data.refundedAmount)=t.totalAmount||!this.acl.can("novalnet_extension.editor")},showInstalmentCancelModal:function(){var t=this;null!=this.InstalmentInfo&&null!=this.InstalmentInfo&&this.InstalmentInfo.forEach((function(e){""!=e.reference&&null!=e.reference||(t.canInstalmentRemainCancel=!0)})),0==this.instalmentRefundAmount&&(this.canInstalmentAllCancel=!0),this.canInstalmentCancel=!1},showInstalmentAllCancelModal:function(){this.instalmentRefundModalVisible=!0,this.cancelType="CANCEL_ALL_CYCLES"},showInstalmentRemainCancelModal:function(){this.instalmentRefundModalVisible=!0,this.cancelType="CANCEL_REMAINING_CYCLES"},showZeroAmountBlock:function(){this.zeroAmountVisible=!0},closeModals:function(){this.refundModalVisible=!1,this.confirmModalVisible=!1,this.cancelModalVisible=!1,this.instalmentRefundModalVisible=!1,this.zeroAmountVisible=!1},reloadPaymentDetails:function(){var t=this;this.closeModals(),this.$nextTick().then((function(){t.$emit("reload-payment")}))}}});n("onW/");var C=Shopware,k=C.Context,N=C.Component,S=(C.Filter,C.Utils,Shopware.Data.Criteria),A=Shopware.Utils.format.currency;N.override("sw-order-detail-details",{template:'{% block sw_order_detail_details_payment %}\n\t\n\t\n\t\n\n \n {% block sw_order_detail_details_payment_billing_address %}\n \n {% endblock %}\n\n \n {% block sw_order_detail_details_payment_method_select %}\n \n\t\t\t{% if paymentMethod !=\'\' %}\n\t\t\t\t \n\t\t\t\t\n\t\t\t{% else %}\n\t\t\t\t\n\t\t\t{% endif %}\t\n \n {% endblock %}\n\n \n \n\t\n\t{% block sw_order_detail_details_payment_novalnet_seaction %}\n\t\t\n\t\t\n\t{% endblock %}\n{% endblock %}\n',inject:["NovalPaymentApiCredentialsService","repositoryFactory","acl"],mixins:["notification"],props:{orderId:{type:String,required:!0},paymentDetails:{type:Object,required:!0}},data:function(){return{status:0,displayAmount:0,displayPaidAmount:0,refundedAmount:0,orderAmount:0,InstalmentInfo:[],item:{},novalnetComments:"",isNovalnetPayment:!1,refundModalVisible:!1,confirmModalVisible:!1,zeroAmountVisible:!1,cancelModalVisible:!1,canInstalmentAllCancel:!1,canInstalmentRemainCancel:!1,instalmentRefundModalVisible:!1,instalmentRefundAmount:0,paymentMethod:"",payLater:["INVOICE","CASHPAYMENT","MULTIBANCO","PREPAYMENT"],instalmentPayments:["INSTALMENT_INVOICE","INSTALMENT_DIRECT_DEBIT_SEPA"],onholdStatus:["91","99","98","85"]}},computed:{getInstalmentColums:function(){return[{property:"number",dataIndex:"number",label:this.$tc("novalnet-payment.settingForm.instalmentNumber"),width:"50px"},{property:"reference",dataIndex:"reference",label:this.$tc("novalnet-payment.settingForm.instalmentReference"),width:"120px"},{property:"amount",dataIndex:"amount",label:this.$tc("novalnet-payment.settingForm.instalmentAmount"),width:"80px"},{property:"totalAmount",dataIndex:"totalAmount",visible:!1},{property:"refundAmount",dataIndex:"refundAmount",visible:!1},{property:"nextCycle",dataIndex:"nextCycle",label:this.$tc("novalnet-payment.settingForm.instalmentDate"),width:"120px"},{property:"status",dataIndex:"status",label:this.$tc("novalnet-payment.settingForm.instalmentStatus"),width:"80px"}]}},watch:{orderId:{deep:!0,handler:function(){var t=this;if(this.orderId){var e=this.repositoryFactory.create("order"),n=new S(1,1);n.addAssociation("transactions"),n.addAssociation("currency"),n.addFilter(S.equals("id",this.orderId)),e.search(n,k.api).then((function(e){var n=e.first();if(n){t.identifier||(t.identifier=n.orderNumber);var a=!1,o="",i=t.$tc("novalnet-payment.module.comments");n.transactions.sort((function(t,e){return new Date(e.createdAt)-new Date(t.createdAt)})).forEach((function(e){if(e.customFields&&e.customFields.novalnet_comments)return t.stateMachineState=e.stateMachineState.name,a=!0,""!=o&&(o+="
"+i+"
"),o+=e.customFields.novalnet_comments.split("/ ").join("
"),!0})),a?(t.novalnetComments=o.split("&&").join("
"+i+"
"),t.setNovalnetPayment(!0)):t.setNovalnetPayment(!1),null!=t.order.transactions.last().paymentMethod.customFields&&null!=t.order.transactions.last().paymentMethod.customFields.novalnet_payment_method_name&&"novalnetpay"==t.order.transactions.last().paymentMethod.customFields.novalnet_payment_method_name?t.NovalPaymentApiCredentialsService.getNovalnetPaymentMethod(t.order.orderNumber).then((function(e){null!=e&&null!=e&&null!=e.paymentName&&null!=e.paymentName?t.paymentMethod=e.paymentName:t.paymentMethod=t.order.transactions.last().paymentMethod.translated.distinguishableName})).catch((function(e){t.createNotificationError({message:"".concat(e.title,": ").concat(e.message)})})):t.paymentMethod=t.order.transactions.last().paymentMethod.translated.distinguishableName,t.canCaptureVoid=!1,t.canRefund=!1,t.canZeroAmountBooking=!1,t.canInstalmentCancel=!1,t.canInstalmentShow=!1,t.InstalmentInfo=[],t.canInstalmentAllCancel=!1,t.canInstalmentRemainCancel=!1,t.NovalPaymentApiCredentialsService.getNovalnetAmount(n.orderNumber).then((function(e){if(""!=e.data&&null!=e.data&&e.data.gatewayStatus){var a=JSON.parse(e.data.additionalDetails);if(t.refundableAmount=Number(e.data.amount)-Number(e.data.refundedAmount),t.orderAmount=Math.round(100*Number(n.price.totalPrice)),"ON_HOLD"==e.data.gatewayStatus||t.onholdStatus.includes(e.data.gatewayStatus)?t.canCaptureVoid=!0:(e.data.amount>0&&"CONFIRMED"==e.data.gatewayStatus&&!t.instalmentPayments.includes(e.data.paymentType)&&Number(e.data.refundedAmount)=t.totalAmount||!this.acl.can("novalnet_extension.editor")}}});var I=Shopware,P=I.Component,x=I.State,M=I.Mixin,F=(I.Filter,I.Context),T=(I.ContextSwitchParameters,Shopware.Data.Criteria);Shopware.Utils.format.currency;P.override("sw-order-create-details",{template:'{% block sw_order_create_details_payment %}\n\n\t{% parent %}\n\t{% block sw_order_create_details_payment_novalnet_seaction %}\n\t\t\n\t\t\n\t{% endblock %}\n{% endblock %}\n',inject:["NovalPaymentApiCredentialsService","repositoryFactory","acl"],mixins:[M.getByName("notification")],data:function(){return{isLoading:!1,loaded:!1,shouldDisable:!0,iframe:{src:""},paymentformurl:"",novalnetPayment:!1}},computed:{customer:function(){return x.get("swOrder").customer},cart:function(){return x.get("swOrder").cart},currency:function(){return x.get("swOrder").context.currency},cartPrice:function(){return this.cart.price},salesChannelContext:function(){return x.get("swOrder").context}},watch:{salesChannelContext:{deep:!0,handler:function(){var t=this;if(this.customer&&this.isCartTokenAvailable){this.isLoading=!0;var e=this.repositoryFactory.create("payment_method"),n=new T(1,1);n.addFilter(T.equals("id",this.salesChannelContext.paymentMethod.id)),e.search(n,F.api).then((function(e){var n=e.first();if(n&&(t.novalnetPayment=!1,null!=n.customFields&&"novalnetpay"==n.customFields.novalnet_payment_method_name)){if(null==t.currency)return void t.createNotificationError({title:t.$tc("novalnet-payment.settingForm.titleError"),message:t.$tc("novalnet-payment.settingForm.currencyFailureMessage")});if(null!=t.cartPrice&&(0==t.cartPrice.totalPrice||null==t.cartPrice.totalPrice))return void t.createNotificationError({title:t.$tc("novalnet-payment.settingForm.titleError"),message:t.$tc("novalnet-payment.settingForm.lineitemFailureMessage")});t.novalnetPayment=!0;var a="",o="",i="",l="";""==t.context.billingAddressId&&null===t.salesChannelContext.customer.defaultBillingAddress||(""!=t.context.billingAddressId&&t.customer.addresses.forEach((function(e){e.id==t.context.billingAddressId&&(i=e)})),a=""!=i?i:t.salesChannelContext.customer.defaultBillingAddress),""==t.context.shippingAddressId&&null===t.salesChannelContext.customer.defaultShippingAddress||(""!=t.context.shippingAddressId&&t.customer.addresses.forEach((function(e){e.id==t.context.shippingAddressId&&(l=e)})),o=""!=l?l:t.salesChannelContext.customer.defaultShippingAddress);var r=t.NovalPaymentApiCredentialsService,s=t.customer;t.NovalPaymentApiCredentialsService.novalnetPayment(o,a,t.cartPrice.totalPrice,t.currency.isoCode,t.customer).then((function(e){if(""!=e&&null!=e&&"SUCCESS"==e.result.status&&""!=e.result.redirect_url&&null!=e.result.redirect_url){t.iframe.src=e.result.redirect_url,t.loaded=!0;var n=document.createElement("script");n.setAttribute("src","https://cdn.novalnet.de/js/pv13/checkout.js?"+(new Date).getTime()),n.type="text/javascript",document.head.appendChild(n),t.paymentformurl=n,t.paymentformurl.addEventListener("load",(function(){document.querySelector(".sw-button-process").disabled=!1,t.onWindowLoad(r,s)}))}})).catch((function(e){t.createNotificationError({message:"".concat(e.title,": ").concat(e.message)})}))}}))}}},customer:{deep:!0,handler:function(){this.customer},immediate:!0}},methods:{onWindowLoad:function(t,e){var n=new NovalnetPaymentForm,a=document.querySelector(".sw-button-process"),o={iframe:"#adminnovalnetPaymentiframe",initForm:{uncheckPayments:!1,showButton:!1}};n.initiate(o),n.validationResponse((function(t){n.initiate(o)})),n.selectedPayment((function(t){t.payment_details.type})),a.addEventListener("click",(function(a){a.preventDefault(),a.stopImmediatePropagation(),n.getPayment((function(n){var a=JSON.stringify(n);t.paymentValue(a,e).then((function(t){}))}))}))}}});var E=Shopware,R=E.Component,$=E.State,B=E.Mixin;E.Filter,E.Context,Shopware.Data.Criteria,Shopware.Utils.format.currency;R.override("sw-order-create-base",{template:'{% block sw_order_create_details %}\n\t{% parent %}\n\t\n\n{% endblock %}\n',inject:["NovalPaymentApiCredentialsService","repositoryFactory","acl"],mixins:[B.getByName("notification")],data:function(){return{isLoading:!1}},computed:{customer:function(){return $.get("swOrder").customer},cart:function(){return $.get("swOrder").cart},cartPrice:function(){return this.cart.price},currency:function(){return $.get("swOrder").context.currency},displayRounded:function(){return!!this.cartPrice&&this.cartPrice.rawTotal!==this.cartPrice.totalPrice},orderTotal:function(){return this.cartPrice?this.displayRounded?this.cartPrice.rawTotal:this.cartPrice.totalPrice:0}}});n("Trp/");var D=Shopware,L=D.Component,O=D.Mixin;Shopware.Utils.format.currency;L.register("novalnet-payment-refund-modal",{template:'{% block novalnet_payment_order_refund_modal %}\n \n\t\t\n\t\t\t{% block novalnet_payment_order_refund_modal_content %}\n\t\t\t\t\n\t\t\t{% endblock %}\n\n\t\t\t{% block novalnet_payment_order_refund_modal_actions %}\n\t\t\t\t\n\t\t\t{% endblock %}\n \n{% endblock %}\n',props:{refundableAmount:{type:Number,required:!0},order:{type:Object,required:!0},item:{type:Object,required:!0}},inject:["NovalPaymentApiCredentialsService","repositoryFactory"],mixins:[O.getByName("notification"),O.getByName("sw-inline-snippet")],data:function(){return{reason:"",disable:!1}},methods:{closeModal:function(){this.$emit("modal-close")},novalnetRefund:function(){var t=this,e=this.refundableAmount,n=this.reason,a=this.order.orderNumber;"0"!=e?(this.disable=!0,this.NovalPaymentApiCredentialsService.refundPayment(a,e,n,this.item.reference).then((function(e){null!=e.result&&null!=e.result&&""!=e.result?null!=e.result.status&&null!=e.result.status&&""!=e.result.status&&"SUCCESS"==e.result.status?t.createNotificationSuccess({message:t.$tc("novalnet-payment.settingForm.extension.refundSuccess")}):null!=e.result.status_text&&null!=e.result.status_text&&""!=e.result.status_text?t.createNotificationError({message:e.result.status_text}):t.createNotificationError({message:t.$tc("novalnet-payment.settingForm.failureMessage")}):t.createNotificationError({message:t.$tc("novalnet-payment.settingForm.failureMessage")}),t.$emit("modal-close"),setTimeout(t.$router.go,3e3)})).catch((function(e){t.createNotificationError({message:"".concat(e.title,": ").concat(e.message),autoClose:!1}),t.$emit("modal-close")}))):this.createNotificationError({message:this.$tc("novalnet-payment.settingForm.amountRefundError")})}}});var j=Shopware,V=j.Component,z=j.Mixin;Shopware.Utils.format.currency;V.register("novalnet-payment-manage-transaction-modal",{template:'{% block novalnet_payment_order_manage_modal %}\n \n\n {% block novalnet_payment_order_manage_modal_content %}\n \n {% endblock %}\n\n {% block novalnet_payment_order_manage_modal_actions %}\n \n {% endblock %}\n \n{% endblock %}\n',props:{status:{type:Number,required:!0},order:{type:Object,required:!0}},inject:["NovalPaymentApiCredentialsService","repositoryFactory"],mixins:[z.getByName("notification"),z.getByName("sw-inline-snippet")],data:function(){return{confirm:!0,cancel:!1,disable:!1}},methods:{closeModal:function(){this.$emit("modal-close")},novalnetOnhold:function(){var t=this,e=this.status,n=this.order.orderNumber;""!=e&&null!=e?(this.disable=!0,this.NovalPaymentApiCredentialsService.managePayment(n,e).then((function(e){""!=e?"SUCCESS"==e.result.status?"transaction_capture"==e.manageEvent?t.createNotificationSuccess({message:t.$tc("novalnet-payment.settingForm.extension.onholdSuccess")}):"transaction_cancel"==e.manageEvent&&t.createNotificationSuccess({message:t.$tc("novalnet-payment.settingForm.extension.onholdCancel")}):null!=e.result.status_text&&null!=e.result.status_text&&""!=e.result.status_text?t.createNotificationError({message:e.result.status_text}):t.createNotificationError({message:t.$tc("novalnet-payment.settingForm.failureMessage")}):t.createNotificationError({message:t.$tc("novalnet-payment.settingForm.failureMessage")}),t.$emit("modal-close"),setTimeout(t.$router.go,3e3)})).catch((function(e){t.createNotificationError({message:"".concat(e.title,": ").concat(e.message),autoClose:!1}),t.$emit("modal-close")}))):this.createNotificationError({message:this.$tc("novalnet-payment.settingForm.extension.onholdLabel")})}}});var U=Shopware,K=U.Component,q=U.Mixin;Shopware.Utils.format.currency;K.register("novalnet-payment-instalment-cancel-modal",{template:'{% block novalnet_payment_order_cancel_modal %}\n \n\n\t\t\t{% block novalnet_payment_order_cancel_modal_content %}\n\t\t\t\t\n\t\t\t{% endblock %}\n\n\t\t\t{% block novalnet_payment_order_cancel_modal_actions %}\n\t\t\t\t\n\t\t\t{% endblock %}\n \n{% endblock %}\n',props:{cancelType:{type:String,required:!0},order:{type:Object,required:!0}},inject:["NovalPaymentApiCredentialsService","repositoryFactory"],mixins:[q.getByName("notification"),q.getByName("sw-inline-snippet")],data:function(){return{disable:!1}},methods:{closeModal:function(){this.$emit("modal-close")},novalnetInstalmentCancel:function(){var t=this,e=this.order.orderNumber,n=this.cancelType;this.disable=!0,this.NovalPaymentApiCredentialsService.instalmentCancel(e,n).then((function(e){""!=e.result?null!=e.result.status&&null!=e.result.status&&""!=e.result.status&&"SUCCESS"==e.result.status?t.createNotificationSuccess({message:t.$tc("novalnet-payment.settingForm.extension.instalmentSuccessMsg")}):null!=e.result.status_text&&null!=e.result.status_text&&""!=e.result.status_text?t.createNotificationError({message:e.result.status_text}):t.createNotificationError({message:t.$tc("novalnet-payment.settingForm.failureMessage")}):t.createNotificationError({message:t.$tc("novalnet-payment.settingForm.failureMessage")}),t.$emit("modal-close"),setTimeout(t.$router.go,3e3)})).catch((function(e){t.createNotificationError({message:"".concat(e.title,": ").concat(e.message),autoClose:!1}),t.$emit("modal-close")}))}}});var H=Shopware,W=H.Component,Z=H.Mixin;Shopware.Utils.format.currency;W.register("novalnet-payment-book-amount-modal",{template:'{% block novalnet_payment_order_refund_modal %}\n \n\t\t\n\t\t\t{% block novalnet_payment_order_zero_amount_modal_content %}\n\t\t\t\t\n\t\t\t{% endblock %}\n\n\t\t\t{% block novalnet_payment_order_zero_amount_modal_actions %}\n\t\t\t\t\n\t\t\t{% endblock %}\n \n{% endblock %}\n',props:{orderAmount:{type:Number,required:!0},order:{type:Object,required:!0}},inject:["NovalPaymentApiCredentialsService","repositoryFactory"],mixins:[Z.getByName("notification"),Z.getByName("sw-inline-snippet")],data:function(){return{reason:"",disable:!1}},methods:{closeModal:function(){this.$emit("modal-close")},novalnetBookAmount:function(){var t=this,e=this.orderAmount,n=this.order.orderNumber;0!=e?(this.disable=!0,this.NovalPaymentApiCredentialsService.BookOrderAmount(n,e).then((function(e){null!=e.result&&null!=e.result&&""!=e.result?null!=e.result.status&&null!=e.result.status&&""!=e.result.status&&"SUCCESS"==e.result.status?t.createNotificationSuccess({message:t.$tc("novalnet-payment.settingForm.extension.bookedSuccess")}):null!=e.result.status_text&&null!=e.result.status_text&&""!=e.result.status_text?t.createNotificationError({message:e.result.status_text}):t.createNotificationError({message:t.$tc("novalnet-payment.settingForm.failureMessage")}):t.createNotificationError({message:t.$tc("novalnet-payment.settingForm.failureMessage")}),t.$emit("modal-close"),setTimeout(t.$router.go,3e3)})).catch((function(e){t.createNotificationError({message:"".concat(e.title,": ").concat(e.message),autoClose:!1}),t.$emit("modal-close")}))):this.createNotificationError({message:this.$tc("novalnet-payment.settingForm.amountError")})}}});var G=Shopware,Y=G.Component,J=G.Mixin;Shopware.Data.Criteria;Y.override("sw-order-user-card",{template:"{% block sw_order_detail_base_secondary_info_payment %}\n\t\t\n{% endblock %}\n",inject:["NovalPaymentApiCredentialsService","repositoryFactory"],mixins:[J.getByName("notification")],props:{currentOrder:{type:Object,required:!0},isLoading:{type:Boolean,required:!0}},data:function(){return{paymentMethod:""}},watch:{currentOrder:{deep:!0,handler:function(){var t=this;""!=this.currentOrder&&(null!=this.currentOrder.transactions.last().paymentMethod.customFields&&null!=this.currentOrder.transactions.last().paymentMethod.customFields.novalnet_payment_method_name&&"novalnetpay"==this.currentOrder.transactions.last().paymentMethod.customFields.novalnet_payment_method_name?this.NovalPaymentApiCredentialsService.getNovalnetPaymentMethod(this.currentOrder.orderNumber).then((function(e){null!=e&&null!=e&&null!=e.paymentName&&null!=e.paymentName?t.paymentMethod=e.paymentName:t.paymentMethod=t.currentOrder.transactions.last().paymentMethod.translated.distinguishableName})).catch((function(e){t.createNotificationError({message:"".concat(e.title,": ").concat(e.message)})})):this.paymentMethod=this.currentOrder.transactions.last().paymentMethod.translated.distinguishableName)},immediate:!0}}});var X=Shopware,Q=X.Component,tt=X.Mixin,et=(X.Filter,X.Context),nt=Shopware.Data.Criteria;Shopware.Utils.format.currency;Q.register("sw-order-create-details-payment",{template:'{% block sw_order_create_detail_payment_info %}\n\t\n\t\t\n\t\n{% endblock %}\n',inject:["NovalPaymentApiCredentialsService","repositoryFactory"],mixins:[tt.getByName("notification")],props:{customer:{type:Object},cartPrice:{type:Object},currency:{type:Object},isLoading:{type:Boolean,required:!0}},data:function(){return{isLoading:!1,loaded:!1,shouldDisable:!0,iframe:{src:""},paymentformurl:"",novalnetPayment:!1}},watch:{customer:{deep:!0,handler:function(){var t=this;if(null!=this.customer){var e=this.repositoryFactory.create("payment_method"),n=new nt(1,1);n.addFilter(nt.equals("id",this.customer.salesChannel.paymentMethodId)),e.search(n,et.api).then((function(e){var n=e.first();if(n&&null!=n.customFields&&"novalnetpay"==n.customFields.novalnet_payment_method_name){if(null==t.currency)return void t.createNotificationError({title:t.$tc("novalnet-payment.settingForm.titleError"),message:t.$tc("novalnet-payment.settingForm.currencyFailureMessage")});if(null!=t.cartPrice&&(0==t.cartPrice.totalPrice||null==t.cartPrice.totalPrice))return void t.createNotificationError({title:t.$tc("novalnet-payment.settingForm.titleError"),message:t.$tc("novalnet-payment.settingForm.lineitemFailureMessage")});t.novalnetPayment=!0;var a="",o="";null===t.customer.billingAddress&&null===t.customer.defaultBillingAddress||(a=t.customer.billingAddress?t.customer.billingAddress:t.customer.defaultBillingAddress),null===t.customer.shippingAddress&&null===t.customer.defaultShippingAddress||(o=t.customer.shippingAddress?t.customer.shippingAddress:t.customer.defaultShippingAddress);var i=t.NovalPaymentApiCredentialsService,l=t.customer;t.NovalPaymentApiCredentialsService.novalnetPayment(o,a,t.cartPrice.totalPrice,t.currency.isoCode,t.customer).then((function(e){if(""!=e&&null!=e&&"SUCCESS"==e.result.status&&""!=e.result.redirect_url&&null!=e.result.redirect_url){t.iframe.src=e.result.redirect_url,t.loaded=!0;var n=document.createElement("script");n.setAttribute("src","https://cdn.novalnet.de/js/pv13/checkout.js?"+(new Date).getTime()),n.type="text/javascript",document.head.appendChild(n),t.paymentformurl=n,t.paymentformurl.addEventListener("load",(function(){t.onWindowLoad(i,l)}))}})).catch((function(e){t.createNotificationError({message:"".concat(e.title,": ").concat(e.message)})}))}}))}},immediate:!0}},methods:{onWindowLoad:function(t,e){var n=new NovalnetPaymentForm,a=document.querySelector(".sw-button-process"),o={iframe:"#adminnovalnetPaymentiframe",initForm:{uncheckPayments:!0,showButton:!1}};n.initiate(o),n.validationResponse((function(t){n.initiate(o)})),n.selectedPayment((function(t){t.payment_details.type})),a.addEventListener("click",(function(a){a.preventDefault(),a.stopImmediatePropagation(),n.getPayment((function(n){var a=JSON.stringify(n);t.paymentValue(a,e).then((function(t){}))}))}))}}});var at=Shopware,ot=at.Component,it=at.Mixin;Shopware.Data.Criteria;ot.override("sw-order-general-info",{template:"{% block sw_order_detail_base_general_info_summary_sub_description %}\n\t
\n\t\t{{ $tc('sw-order.generalTab.info.summary.on') }}\n\t\t{{ order.orderDateTime | date({\n\t\t\thour: '2-digit',\n\t\t\tminute: '2-digit',\n\t\t\tday: '2-digit',\n\t\t\tmonth: '2-digit',\n\t\t\tyear: 'numeric'\n\t\t}) }}\n\t\t{{ $tc('sw-order.generalTab.info.summary.with') }}\n\t\t{{ paymentMethod }} \n\t\t\n\t
\n{% endblock %}\n",inject:["NovalPaymentApiCredentialsService","repositoryFactory"],mixins:[it.getByName("notification")],props:{order:{type:Object,required:!0}},data:function(){return{paymentMethod:""}},watch:{order:{deep:!0,handler:function(){var t=this;""!=this.order&&(null!=this.order.transactions.last().paymentMethod.customFields&&null!=this.order.transactions.last().paymentMethod.customFields.novalnet_payment_method_name&&"novalnetpay"==this.order.transactions.last().paymentMethod.customFields.novalnet_payment_method_name?this.NovalPaymentApiCredentialsService.getNovalnetPaymentMethod(this.order.orderNumber).then((function(e){null!=e&&null!=e&&null!=e.paymentName&&null!=e.paymentName?t.paymentMethod=e.paymentName:t.paymentMethod=t.order.transactions.last().paymentMethod.translated.distinguishableName})).catch((function(e){t.createNotificationError({message:"".concat(e.title,": ").concat(e.message)})})):this.paymentMethod=this.order.transactions.last().paymentMethod.translated.distinguishableName)},immediate:!0}}});var lt=n("RTjX"),rt=n("NvEy");function st(t){return st="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},st(t)}function ct(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function dt(t,e){for(var n=0;n2&&void 0!==arguments[2]?arguments[2]:"novalnet-payment";return ct(this,i),o.call(this,t,e,n)}return e=i,n=[{key:"validateApiCredentials",value:function(t,e){return this.getBasicHeaders(),this.httpClient.post("_action/".concat(this.getApiBasePath(),"/validate-api-credentials"),{clientId:t,accessKey:e},{headers:this.getBasicHeaders()}).then((function(t){return ht.handleResponse(t)}))}},{key:"getNovalnetAmount",value:function(t){return this.getBasicHeaders(),this.httpClient.post("_action/".concat(this.getApiBasePath(),"/transaction-amount"),{orderNumber:t},{headers:this.getBasicHeaders()}).then((function(t){return ht.handleResponse(t)}))}},{key:"refundPayment",value:function(t,e,n,a){return this.getBasicHeaders(),this.httpClient.post("_action/".concat(this.getApiBasePath(),"/refund-amount"),{orderNumber:t,refundAmount:e,reason:n,instalmentCycleTid:a},{headers:this.getBasicHeaders()}).then((function(t){return ht.handleResponse(t)}))}},{key:"managePayment",value:function(t,e){return this.getBasicHeaders(),this.httpClient.post("_action/".concat(this.getApiBasePath(),"/manage-payment"),{orderNumber:t,status:e},{headers:this.getBasicHeaders()}).then((function(t){return ht.handleResponse(t)}))}},{key:"instalmentCancel",value:function(t,e){return this.getBasicHeaders(),this.httpClient.post("_action/".concat(this.getApiBasePath(),"/instalment-cancel"),{orderNumber:t,cancelType:e},{headers:this.getBasicHeaders()}).then((function(t){return ht.handleResponse(t)}))}},{key:"BookOrderAmount",value:function(t,e){var n="_action/".concat(this.getApiBasePath(),"/book-amount");return this.httpClient.post(n,{orderNumber:t,bookAmount:e},{headers:this.getBasicHeaders()}).then((function(t){return ht.handleResponse(t)}))}},{key:"getNovalnetPaymentMethod",value:function(t){var e="_action/".concat(this.getApiBasePath(),"/novalnet-paymentmethod");return this.httpClient.post(e,{orderNumber:t},{headers:this.getBasicHeaders()}).then((function(t){return ht.handleResponse(t)}))}},{key:"configureWebhookUrl",value:function(t,e,n){var a="_action/".concat(this.getApiBasePath(),"/webhook-url-configure");return this.httpClient.post(a,{url:t,productActivationKey:e,paymentAccessKey:n},{headers:this.getBasicHeaders()}).then((function(t){return ht.handleResponse(t)}))}},{key:"novalnetPayment",value:function(t,e,n,a,o){var i="_action/".concat(this.getApiBasePath(),"/novalnet-payment");return this.httpClient.post(i,{shippingaddress:t,billingaddress:e,amount:n,currency:a,customer:o},{headers:this.getBasicHeaders()}).then((function(t){return ht.handleResponse(t)}))}},{key:"paymentDetails",value:function(t){var e="_action/".concat(this.getApiBasePath(),"/novalnet-select-payment");return this.httpClient.post(e,{paymentSelected:t},{headers:this.getBasicHeaders()}).then((function(t){return ht.handleResponse(t)}))}},{key:"paymentValue",value:function(t,e){var n="_action/".concat(this.getApiBasePath(),"/payment-value-data");return this.httpClient.post(n,{value:t,customer:e},{headers:this.getBasicHeaders()}).then((function(t){return ht.handleResponse(t)}))}},{key:"getShopVersion",value:function(){var t="_action/".concat(this.getApiBasePath(),"/shop-version");return this.httpClient.post(t,{},{headers:this.getBasicHeaders()}).then((function(t){return ht.handleResponse(t)}))}}],n&&dt(e.prototype,n),a&&dt(e,a),Object.defineProperty(e,"prototype",{writable:!1}),i}(ht),vt=yt,gt=Shopware.Application;gt.addServiceProvider("NovalPaymentApiCredentialsService",(function(t){var e=gt.getContainer("init");return new vt(e.httpClient,t.loginService)}));n("bNNs")},FGZA:function(t,e,n){var a=n("gTZt");a.__esModule&&(a=a.default),"string"==typeof a&&(a=[[t.i,a,""]]),a.locals&&(t.exports=a.locals);(0,n("SZ7m").default)("67b56fd8",a,!0,{})},Hg1N:function(t,e,n){var a=n("0b8U");a.__esModule&&(a=a.default),"string"==typeof a&&(a=[[t.i,a,""]]),a.locals&&(t.exports=a.locals);(0,n("SZ7m").default)("464ed6ca",a,!0,{})},NvEy:function(t){t.exports=JSON.parse('{"novalnet-payment":{"module":{"title":"Novalnet","description":"PCI compliant and seamless integration with various payment types and payment processing services in one unique platform...","projectInfo":"Your project is in test mode","comments":"Comments","generalInfo":"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","globalTitle":"Global Configuration","installationInfo":"For setup and handling of the Novalnet-Payment plugin you can find the installation guide Here","PaymentConfiguration":"Important notice: Payment plugin configurations are now available in the Novalnet Admin Portal. Navigate to the Projects > choose your project > Payment plugin configuration, to configure them.

Novalnet allows you to verify the payment method behaviour before going into production mode by using test payment data. Access the Novalnet test payment data available Here "},"settingForm":{"title":"Novalnet","statusTitle":"Status","amountError":"Invalid amount","buttons":{"save":"Save"},"credentials":{"cardTitle":"Novalnet API Configuration","activationKey":{"label":"Product activation key *","tooltipText":"Your product activation key is a unique token for merchant authentication and payment processing. Get your Product activation key from the Novalnet Admin Portal : Projects > Choose your project > API credentials > API Signature (Product activation key)"},"accessKey":{"label":"Payment access key *","tooltipText":"Your secret key used to encrypt the data to avoid user manipulation and fraud. Get your Payment access key from the Novalnet Admin Portal Projects > Choose your project > API credentials > Payment access key"},"tariff":{"label":"Select Tariff ID *","tooltipText":"Select a Tariff ID to match the preferred tariff plan you created at the Novalnet Admin Portal for this project","emptyText":"Select Tariff ID"},"orderEmailMode":{"label":"Enable Order Confirmation E-mail","tooltipText":"Enable this configuration to send another Order Confirmation e-mail with Novalnet transaction details to the end customer for orders made through Invoice, Prepayment, Cashpayment, and Multibanco payments. (By default initial Order confirmation e-mail will send to end customers without Novalnet transaction details)"}},"merchantSettings":{"cardTitle":"Notification / Webhook URL Setup","deactivateIp":{"label":"Allow manual testing of the Notification / Webhook URL","tooltipText":"Enable this to test the Novalnet Notification / Webhook URL manually. Disable this before setting your shop live to block unauthorized calls from external parties"},"mailTo":{"label":"Send e-mail to","tooltipText":"Notification / Webhook URL execution messages will be sent to this e-mail"},"callbackUrl":{"label":"Notification / Webhook URL","button":"Configure","tooltipText":"You must configure the webhook endpoint in your Novalnet Admin portal. This will allow you to receive notifications about the transaction."}},"extension":{"paidTooltip":"Total paid amount","refundTooltip":"Refuned amount","refundButton":"Refund","amountTitle":"Refund amount","zeroAmountTitle":"Order Booked for this amount","refundDescription":"Please enter the refund amount (in minimum unit of currency. E.g. enter 100 which is equal to 1.00)","refundReference":"Refund reference","confirmLabel":"Confirm","cancelLabel":"Cancel","Managetitle":"Manage Transaction","confirmMessage":"Are you sure you want to capture the payment?","cancelMessage":"Are you sure you want to cancel the payment?","cancelAllCycleMessage":"Are you sure you want to cancel all cycle installment?","cancelRemainingCycleMessage":"Are you sure you want to cancel remaining cycle installment?","refundSuccess":"Your refund was successful.","onholdSuccess":"The transaction has been confirmed.","onholdCancel":"The transaction has been canceled","instalmentCancelLabel":"Instalment Cancel","instalmentAllCancelLabel":"Cancel All Instalment","instalmentRemainCancelLabel":"Cancel All Remaining Instalment","instalmentSuccessMsg":"Instalment canceled successfully.","zeroAmountButton":"Book Amount","bookedSuccess":"Your amount booked was successful.","zeroAmountDescription":"Please enter the amount (in minimum unit of currency. E.g. enter 100 which is equal to 1.00)","bookButton":"Book"},"titleSuccess":"Success","successMessage":"Novalnet merchant details are configured successfully.","titleError":"Error","apiFailureMessage":"Please configure Novalnet Global Configuration","customerFailureMessage":"Please select your customer","currencyFailureMessage":"Please select currency","lineitemFailureMessage":"Please Add Product","amountRefundError":"Invalid refund amount","failureMessage":"Please fill in the required fields","instalmentNumber":"S.No","instalmentReference":"Novalnet Transaction ID","instalmentDate":"Next Instalment Date","instalmentAmount":"Amount","instalmentStatus":"Status","instalmentInfo":"Instalment Summary","webhookUrlFailure":"Please enter the valid Webhook URL","webhookUrlSuccess":"Notification / Webhook URL is configured successfully in Novalnet Admin Portal"}},"sw-privileges":{"permissions":{"novalnet_extension":{"label":"Novalnet Extensions"},"parents":{"novalnet_payment":"Novalnet"},"novalnet_payment":{"label":"Novalnet Settings"}}}}')},RTjX:function(t){t.exports=JSON.parse('{"novalnet-payment":{"module":{"title":"Novalnet","description":"PCI-konforme und lückenlose Integration mit verschiedenen Zahlungsarten und Zahlungsdienstleistungen auf einer Plattform.","projectInfo":"Ihr Projekt befindet sich im Testmodus","comments":"Kommentare","generalInfo":"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","globalTitle":"Konfigurationseinstellungen","installationInfo":"Für die Einrichtung und Verwendung des Plugins finden Sie die Installationsanleitung Here","PaymentConfiguration":"Wichtiger Hinweis:Die Konfiguration der Zahlungsplugins sind jetzt im Novalnet Admin Portal verfügbar. Navigieren Sie zu Projekts > Wählen Sie Ihr Projekt > Konfiguration des Zahlungsplugins, 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 "},"settingForm":{"title":"Novalnet","statusTitle":"Zustand","amountError":"Ungültiger Betrag","buttons":{"save":"Speichern"},"credentials":{"cardTitle":"Novalnet API-Konfiguration","activationKey":{"label":"Aktivierungsschlüssel des Produkts *","tooltipText":"Ihr Produktaktivierungsschlüssel ist ein eindeutiger Token für die Händlerauthentifizierung und Zahlungsabwicklung.Ihr Produktaktivierungsschlüssel ist ein eindeutiges Token für die Händlerauthentifizierung und Zahlungsabwicklung. Ihren Produktaktivierungsschlüssel finden Sie im Novalnet Admin-Portal : Projekts > Wählen Sie Ihr Projekt > API-Anmeldeinformationen > API-Signatur (Produktaktivierungsschlüssel)"},"accessKey":{"label":"Zahlungs-Zugriffsschlüssel *","tooltipText":"Ihr geheimer Schlüssel zur Verschlüsselung der Daten, um Manipulation und Betrug zu vermeiden. Ihren Paymentzugriffsschlüssel finden Sie im Novalnet Admin-Portal : Projekts > Wählen Sie Ihr Projekt > API-Anmeldeinformationen > Paymentzugriffsschlüssel"},"tariff":{"label":"Auswahl der Tarif-ID *","tooltipText":"Wählen Sie eine Tarif-ID, die dem bevorzugten Tarifplan entspricht, den Sie im Novalnet Admin-Portal für dieses Projekt erstellt haben","emptyText":"Tarif-ID auswählen"},"orderEmailMode":{"label":" Bestellbestätigung per E-Mail aktivieren","tooltipText":"Aktivieren Sie diesen Reiter, um eine weitere Bestellbestätigungs-E-Mail mit Novalnet-Transaktionsdetails an den Endkunden für Bestellungen zu senden, die über Rechnung, Vorkasse, Barzahlen oder Multibanco getätigt wurden. (Standardmäßig wird die erste Bestellbestätigungs-E-Mail an Endkunden ohne Novalnet-Transaktionsdetails gesendet.)"}},"merchantSettings":{"cardTitle":"Benachrichtigungs- / Webhook-URL festlegen","deactivateIp":{"label":"Manuelles Testen der Benachrichtigungs / Webhook-URL erlauben","tooltipText":"Aktivieren Sie diese Option, um die Novalnet-Benachrichtigungs-/Webhook-URL manuell zu testen. Deaktivieren Sie die Option, bevor Sie Ihren Shop liveschalten, um unautorisierte Zugriffe von Dritten zu blockieren."},"mailTo":{"label":"E-Mails senden an","tooltipText":"E-Mail-Benachrichtigungen werden an diese E-Mail-Adresse gesendet"},"callbackUrl":{"label":"Benachrichtigungs- / Webhook-URL","button":"Konfigurieren","tooltipText":"Sie müssen die folgende Webhook-URL im Novalnet Admin-Portal hinzufügen. Dadurch können Sie Benachrichtigungen über den Transaktionsstatus erhalten."}},"extension":{"paidTooltip":"Gezahlter Gesamtbetrag","refundTooltip":"Rückerstatteter Betrag","refundButton":"Rückerstattung","amountTitle":"Rückerstattungsbetrag","refundDescription":"Geben Sie bitte den erstatteten Betrag ein (in der kleinsten Währungseinheit, z.B. 100 Cent = entsprechen 1.00 EUR)","refundReference":"Referenz für die Rückerstattung","confirmLabel":"Bestätigen","cancelLabel":"Stornieren","cancelAllCycleMessage":"Sind Sie sicher, dass Sie alle Ratenzahlungen stornieren wollen?","cancelRemainingCycleMessage":"Sind Sie sicher, dass Sie die verbleibende Zyklusrate stornieren möchten?","Managetitle":"Transaktion verwalten","confirmMessage":"Sind Sie sicher, dass Sie die Zahlung einziehen möchten?","cancelMessage":"Sind Sie sicher, dass Sie die Zahlung stornieren wollen?","refundSuccess":"Die Rückerstattung war erfolgreich.","onholdSuccess":"Die Transaktion wurde bestätigt","onholdCancel":"Die Transaktion wurde storniert","instalmentCancelLabel":"Ratenzahlung Stornieren","instalmentAllCancelLabel":"Gesamte Ratenzahlung stornieren","instalmentRemainCancelLabel":"Alle übrigen Installationen abbrechen","instalmentSuccessMsg":"Die Ratenzahlung wurde erfolgreich abgebrochen.","zeroAmountButton":"Buchbetrag","bookedSuccess":"Ihr gebuchter Betrag war erfolgreich.","zeroAmountTitle":"Gebuchter Auftrag für diesen Betrag","zeroAmountDescription":"Bitte geben Sie den Betrag ein (in der kleinsten Währungseinheit, z.B. 100, was 1,00 entspricht)","bookButton":"Buchen Sie"},"titleSuccess":"Success","successMessage":"Die Novalnet-Händlerdaten wurden erfolgreich eingestellt.","titleError":"Error","apiFailureMessage":"Konfigurieren Sie bitte die zentralen Novalnet-Einstellungen","customerFailureMessage":"Bitte wählen Sie Ihren Kunden","currencyFailureMessage":"Bitte wählen Sie eine Währung","lineitemFailureMessage":"Bitte Produkt hinzufügen","amountRefundError":"Ungültiger Rückerstattungsbetrag","failureMessage":"Bitte füllen Sie die erforderlichen Felder aus","instalmentNumber":"S.No","instalmentReference":"Novalnet-Transaktions-ID","instalmentDate":"Nächste Rate fällig am","instalmentAmount":"Betrag","instalmentStatus":"Status","instalmentInfo":"Zusammenfassung der Ratenzahlung","webhookUrlFailure":"Bitte geben Sie eine gültige Webhook-URL ein","webhookUrlSuccess":"Callbackskript-/ Webhook-URL wurde erfolgreich im Novalnet Admin Portal konfiguriert"}},"sw-privileges":{"permissions":{"novalnet_extension":{"label":"Novalnet-Erweiterungen"},"parents":{"novalnet_payment":"Novalnet"},"novalnet_payment":{"label":"Novalnet Einstellungen"}}}}')},SZ7m:function(t,e,n){"use strict";function a(t,e){for(var n=[],a={},o=0;on.parts.length&&(a.parts.length=n.parts.length)}else{var l=[];for(o=0;o +{% endblock %} diff --git a/src/Resources/views/documents/invoice.html.twig b/src/Resources/views/documents/invoice.html.twig new file mode 100755 index 0000000..d522f9a --- /dev/null +++ b/src/Resources/views/documents/invoice.html.twig @@ -0,0 +1,43 @@ +{% sw_extends '@Framework/documents/invoice.html.twig' %}{% block document_payment_shipping_inner %} + + {% set paymentMethod = order.transactions.last.paymentMethod|getPaymentMethodName() %} + {% block document_payment %} + {% if 'novalnet' in paymentMethod %} + {% set paymentName = context|getPaymentName(order.ordernumber) %} + {% if paymentName is not empty %} + {{ 'document.paymentShippingInfo.paymentMethod'|trans({'%paymentMethod%': paymentName})|sw_sanitize }}
+ {% else %} + {{ 'document.paymentShippingInfo.paymentMethod'|trans({'%paymentMethod%': order.transactions.last.paymentMethod.name})|sw_sanitize }}
+ {% endif %} + {% endif %} + {% endblock %} + + {% block document_shipping %} + {{ 'document.paymentShippingInfo.shippingMethod'|trans({'%shippingMethod%': order.deliveries.first.shippingMethod.name})|sw_sanitize }}

+ {% endblock %} + {% block document_payment_shipping_additional %} + {{ 'document.paymentShippingInfo.additionalInfo'|trans|sw_sanitize }}
+ {% endblock %} + {% block document_payment_shipping_service_date_notice %} + {{ 'document.serviceDateNotice'|trans|sw_sanitize }}
+ {% endblock %} + + + {% set comments = '' %} + + {% for transaction in order.transactions|sort((a, b) => a.createdAt <=> b.createdAt) %} + {% if transaction.customFields.novalnet_comments != '' %} + {% set comments = transaction.customFields.novalnet_comments %} + {% endif %} + + {% if 'Novalnet' not in transaction.paymentMethod.handlerIdentifier %} + {% set comments = '' %} + {% endif %} + {% endfor %} + + {% if comments != '' %} + {% set novalnetInvoiceDocument = comments|getFinishNovalnetComments() %} +
{{"NovalnetPayment.text.commentsHeader"|trans}}
+ {{ novalnetInvoiceDocument|replace({'/ ': "
"}) | raw }} + {% endif %} +{% endblock %} diff --git a/src/Resources/views/storefront/component/payment/payment-method.html.twig b/src/Resources/views/storefront/component/payment/payment-method.html.twig new file mode 100755 index 0000000..a161b5f --- /dev/null +++ b/src/Resources/views/storefront/component/payment/payment-method.html.twig @@ -0,0 +1,48 @@ +{% sw_extends '@Storefront/storefront/component/payment/payment-method.html.twig' %} + + {% block component_payment_method_field %} + + {% set authAmount = ( page.cart.price.totalPrice ? page.cart.price.totalPrice : page.order.price.totalPrice ) * 100 %} + {% set novalnetPaymentHandler = context|novalnetPaymentHandler(payment.handlerIdentifier) %} + {% set novalnetConfiguration = ( page.cart.extensions.novalnetConfiguration.all ? page.cart.extensions.novalnetConfiguration.all : (page.order.extensions.novalnetSubscription.id or page.order.extensions.subsOrders.id)) %} + + {% if subscriptionForm is not empty %} + {% set formName = "form = novalnetchangePaymentForm" %} + {% else %} + {% set formName = "form = confirmOrderForm" %} + {% endif %} + + {% if novalnetPaymentHandler == 'NovalnetPayment' %} + {% set novalnetpay = (novalnetConfiguration is not empty || app.request.get('_route') == 'frontend.novalnet.subscription.orders.detail') ? context|novalnetPayment(page, 'novalnetpay', 1) : context|novalnetPayment(page, 'novalnetpay') %} + + + +
+ {{ parent()}} +
+ + {% set articleData = [] %} + + {% set cart = page.cart ? page.cart : page.order %} + + {% for lineItem in cart.lineItems %} + {% set articleData = articleData|merge([{ label: lineItem.label ~ " (" ~ lineItem.quantity ~ " x " ~ lineItem.price.unitPrice|currency(context.currency.isoCode) ~ ")", type: 'SUBTOTAL', amount: (lineItem.price.totalPrice * 100)|round }]) %} + {% endfor %} + + {% for delivery in cart.deliveries %} + {% set articleData = articleData|merge([{ label: delivery.shippingMethod.translated.name ~ " (" ~ delivery.shippingCosts.quantity ~ " x " ~ delivery.shippingCosts.unitPrice|currency(context.currency.isoCode) ~ ")", type: 'SUBTOTAL', amount: (delivery.shippingCosts.totalPrice * 100)|round }]) %} + {% endfor %} + + {% for tax in cart.price.calculatedTaxes %} + {% set articleData = articleData|merge([{ label: "NovalnetPayment.text.vatLabel"|trans({'%vat%': tax.taxRate|trans|sw_sanitize})|sw_sanitize, type: 'SUBTOTAL', amount: (tax.tax * 100)|round }]) %} + {% endfor %} +
+ +
+ {% else %} + {{ parent()}} + {% endif %} + + {% endblock %} + + diff --git a/src/Resources/views/storefront/page/account/novalnet-subscription/detail.html.twig b/src/Resources/views/storefront/page/account/novalnet-subscription/detail.html.twig new file mode 100755 index 0000000..015bff1 --- /dev/null +++ b/src/Resources/views/storefront/page/account/novalnet-subscription/detail.html.twig @@ -0,0 +1,41 @@ +{% sw_extends '@NovalnetSubscription/storefront/page/account/novalnet-subscription/detail.html.twig' %} + +{% block novalnet_account_main_body_payment_content %} + + {% set paymentMethodName = paymentMethod|getPaymentMethodName() %} + + {% if paymentMethodName == 'novalnetpayment' %} + {% set paymentName = context|getChangedPaymentName(abo.order.ordernumber) %} + {% if paymentName is not empty %} + {{ paymentName }} + {% else %} + {{ paymentMethod.translated.name ?? paymentMethod.name }} + {% endif %} + {% else %} + {{ parent() }} + {% endif %} + +{% endblock %} + + +{% block novalnet_account_main_body_content_order_payment_info %} + + {% set activePaymentMethod = '' %} + {% for transaction in subCycle.order.transactions|sort((a, b) => a.createdAt <=> b.createdAt) %} + {% set activePaymentMethod = transaction.paymentMethod %} + {% endfor %} + + {% set paymentMethodName = activePaymentMethod|getPaymentMethodName() %} + + {% if paymentMethodName == 'novalnetpayment' %} + {% set paymentName = context|getPaymentName(subCycle.order.ordernumber) %} + {% if paymentName is not empty %} + {{ paymentName }} + {% else %} + {{ activePaymentMethod.translated.name ?? activePaymentMethod.name }} + {% endif %} + {% else %} + {{ parent() }} + {% endif %} + +{% endblock %} diff --git a/src/Resources/views/storefront/page/account/order-history/order-detail.html.twig b/src/Resources/views/storefront/page/account/order-history/order-detail.html.twig new file mode 100755 index 0000000..1724faa --- /dev/null +++ b/src/Resources/views/storefront/page/account/order-history/order-detail.html.twig @@ -0,0 +1,72 @@ +{% sw_extends '@Storefront/storefront/page/account/order-history/order-detail.html.twig' %} +{% set paymentMethod = order.transactions|last.paymentMethod|getPaymentMethodName() %} + + {% block page_account_order_item_detail_payment_method_value %} + {% if 'novalnet' in paymentMethod %} + {% set paymentName = context|getPaymentName(order.ordernumber) %} +
+ {% if paymentName is not empty %} + {{ paymentName }} + {% else %} + {{ order.transactions|last.paymentMethod.translated.name }} + {% endif %} +
+ {% else %} + {{ parent() }} + {% endif %} + {% endblock %} + + + {% block page_account_order_item_detail_table_footer %} + {{ parent() }} + {% block page_account_order_item_detail_comments_additional %} + {% for transaction in order.transactions|sort((a, b) => b.createdAt <=> a.createdAt) %} + {% set paymentMethodName =context|getPaymentMethodNovalnetName(order.ordernumber) %} + {% if 'novalnet' in paymentMethod and transaction.getCustomFields()['novalnet_comments'] != '' %} + {% block page_account_order_item_detail_comments %} + {% set novalnetOrderComments = transaction.getCustomFields()['novalnet_comments']|getNovalnetComments() %} + {% block page_account_order_item_detail_comments_label %} +
{{"NovalnetPayment.text.commentsHeader"|trans}}
+ {% endblock %} + + {% block page_account_order_item_detail_comments_value %} +
+ {{ novalnetOrderComments|replace({'/ ': "
"}) | raw }} +
+ {% endblock %} + {% if paymentMethodName in ['INSTALMENT_INVOICE', 'INSTALMENT_DIRECT_DEBIT_SEPA'] %} + {% set instalmentInfo = context|getNovalnetInstalmentInfo(order.ordernumber) %} + {% if instalmentInfo is not empty %} + + + + + + + + + + + + {% set instalmentData = instalmentInfo.InstalmentDetails %} + {% for info in instalmentData %} + {%set amount = info.amount/100 %} + + + + + + + + {% endfor %} + +
{{"NovalnetPayment.text.sno"|trans}}{{"NovalnetPayment.text.tid"|trans}}{{"NovalnetPayment.text.amount"|trans}}{{"NovalnetPayment.text.date"|trans}}{{"NovalnetPayment.text.status"|trans}}
{{ loop.index }}{{ info.reference ? info.reference : '-' }}{{ amount ? amount|currency(): '-' }}{{ info.cycleDate ? info.cycleDate|date('d/m/Y'): '-' }}{{ info.status }}
+ {% endif %} + {% endif %} + + {% endblock %} + {% endif %} + {% endfor %} + {% endblock %} + + {% endblock %} diff --git a/src/Resources/views/storefront/page/account/order-history/order-item.html.twig b/src/Resources/views/storefront/page/account/order-history/order-item.html.twig new file mode 100755 index 0000000..75afe17 --- /dev/null +++ b/src/Resources/views/storefront/page/account/order-history/order-item.html.twig @@ -0,0 +1,26 @@ +{% sw_extends '@Storefront/storefront/page/account/order-history/order-item.html.twig' %} + + +{% set paymentMethod = order.transactions|last.paymentMethod|getPaymentMethodName() %} + +{% block page_account_order_item_order_table_body_cell_payment_method %} + + {% if 'novalnet' in paymentMethod %} + {% set paymentName = context|getPaymentName(order.ordernumber) %} + +
+ + {{ "account.orderPaymentMethod"|trans|sw_sanitize }}{{ "account.colonCharacter"|trans|sw_sanitize }} + + {% if paymentName is not empty %} + {{ paymentName }} + {% else %} + {{ order.transactions|last.paymentMethod.translated.name }} + {% endif %} +
+ {% else %} + + {{ parent() }} + + {% endif %} +{% endblock %} diff --git a/src/Resources/views/storefront/page/account/order/index.html.twig b/src/Resources/views/storefront/page/account/order/index.html.twig new file mode 100755 index 0000000..a2ef647 --- /dev/null +++ b/src/Resources/views/storefront/page/account/order/index.html.twig @@ -0,0 +1,22 @@ +{% sw_extends '@Storefront/storefront/page/account/order/index.html.twig' %} +{% block page_checkout_confirm_header %} + {% set transaction = page.order.transactions.elements|first %} + {% set errorMessage = transaction.id|getNovalnetErrorMessage(page.order.salesChannelId) %} + {% if errorMessage is not empty %} + +

+ {{ "account.completePayment"|trans|sw_sanitize }} +

+ {% else %} + {{ parent() }} + {% endif %} +{% endblock %} diff --git a/src/Resources/views/storefront/page/checkout/confirm/index.html.twig b/src/Resources/views/storefront/page/checkout/confirm/index.html.twig new file mode 100755 index 0000000..ff558b1 --- /dev/null +++ b/src/Resources/views/storefront/page/checkout/confirm/index.html.twig @@ -0,0 +1,9 @@ +{% sw_extends '@Storefront/storefront/page/checkout/confirm/index.html.twig' %} + +{% block page_checkout_confirm %} +{{ parent() }} +
+ +
+{% endblock %} + diff --git a/src/Resources/views/storefront/page/checkout/finish/finish-details.html.twig b/src/Resources/views/storefront/page/checkout/finish/finish-details.html.twig new file mode 100755 index 0000000..8dab4f0 --- /dev/null +++ b/src/Resources/views/storefront/page/checkout/finish/finish-details.html.twig @@ -0,0 +1,48 @@ +{% sw_extends '@Storefront/storefront/page/checkout/finish/finish-details.html.twig' %} + +{% set paymentMethod = page.order.transactions|last.paymentMethod|getPaymentMethodName() %} +{% set paymentMethodResponse = context|cashPaymentResponse() %} + +{% block page_checkout_finish_order_payment_method%} + + {% if 'novalnet' in paymentMethod %} + {% set paymentName = context|getPaymentName(page.order.orderNumber) %} +

+ {{ "checkout.finishInfoPayment"|trans|sw_sanitize }} + {{ paymentName }} +

+ + {% if paymentMethodResponse.transaction.payment_type == 'CASHPAYMENT' %} +

+ {% if paymentMethodResponse.transaction.checkout_token %} + + + {% endif %} +

+ {% if paymentMethodResponse.transaction.checkout_token %} + + + {% endif %} + {% endif %} + + {% else %} + {{ parent() }} + {% endif %} + +

+ {% if page.order.transactions.last.getCustomFields()['novalnet_comments'] is not empty %} + {% set novalnetFinishComments = page.order.transactions.last.getCustomFields()['novalnet_comments']|getFinishNovalnetComments() %} + {{ "NovalnetPayment.text.commentsHeader"|trans|sw_sanitize }} + {{ novalnetFinishComments|replace({'/ ': "
"}) | raw }} + {% endif %} +

+{% endblock %} diff --git a/src/Service/NovalnetPayment.php b/src/Service/NovalnetPayment.php new file mode 100755 index 0000000..f28d817 --- /dev/null +++ b/src/Service/NovalnetPayment.php @@ -0,0 +1,698 @@ +helper = $helper; + $this->transactionHelper = $transactionHelper; + $this->orderTransactionStateHandler = $orderTransactionStateHandler; + $this->orderTransactionRepository = $orderTransactionRepository; + if (!is_null($contextPersister)) { + $this->contextPersister = $contextPersister; + } + } + + /** + * The pay function will be called after the customer completed the order. + * Allows to process the order and store additional information. + * + * A redirect to the url will be performed + * + * Throw a @see AsyncPaymentProcessException exception if an error ocurres while processing the payment + * + * @param AsyncPaymentTransactionStruct $transaction + * @param RequestDataBag $dataBag + * @param SalesChannelContext $context + * + * @throws AsyncPaymentProcessException + */ + + public function pay(AsyncPaymentTransactionStruct $transaction, RequestDataBag $dataBag, SalesChannelContext $context): RedirectResponse + { + try { + $response = $this->handlePaymentProcess($context, $transaction, $dataBag); + + } catch (\Exception $e) { + throw new AsyncPaymentProcessException($transaction->getOrderTransaction()->getId(), 'An error occurred during the communication with external payment gateway'.PHP_EOL.$e->getMessage()); + } + + if (!empty($response['result']['redirect_url'])) { + $this->helper->setSession('novalnetTxnSecret', $response['transaction']['txn_secret']); + // Redirect to external gateway + return new RedirectResponse($response['result']['redirect_url']); + } + + $this->helper->setSession('novalnetResponse', $response); + + if (!empty($dataBag->get('isBackendOrderCreation'))) { + $this->checkTransactionStatus($transaction->getOrderTransaction(), $response, $context, $transaction); + } + + // Redirect to external gateway + return new RedirectResponse($transaction->getreturnUrl()); + } + + /** + * The finalize function will be called when the user is redirected back to shop from the payment gateway. + * + * Throw a @see AsyncPaymentFinalizeException exception if an error ocurres while calling an external payment API + * Throw a @see CustomerCanceledAsyncPaymentException exception if the customer canceled the payment process on + * payment provider page + * + * @param AsyncPaymentTransactionStruct $transaction + * @param Request $request + * @param SalesChannelContext $salesChannelContext + * + * @throws AsyncPaymentFinalizeException + * @throws CustomerCanceledAsyncPaymentException + */ + public function finalize(AsyncPaymentTransactionStruct $transaction, Request $request, SalesChannelContext $salesChannelContext): void + { + try { + $response = $this->helper->getSession('novalnetResponse'); + if (empty($response)) { + $response = $this->handleRedirectResponse($request, $salesChannelContext, $transaction->getOrderTransaction()); + } + $this->checkTransactionStatus($transaction->getOrderTransaction(), $response, $salesChannelContext, $transaction); + } catch (\Exception $e) { + throw new AsyncPaymentFinalizeException($transaction->getOrderTransaction()->getId(), 'An error occurred during the communication with external payment gateway' . PHP_EOL . $e->getMessage()); + } + } + + /** + * The recurring function will be called during recurring payment. + * Allows to process the order and store additional information. + * + * @param AsyncPaymentTransactionStruct $transaction + * @param RequestDataBag $dataBag + * @param SalesChannelContext $salesChannelContext + * + * @throws AsyncPaymentProcessException + */ + public function recurring(AsyncPaymentTransactionStruct $transaction, RequestDataBag $dataBag, SalesChannelContext $salesChannelContext): bool + { + $response = $this->handlePaymentProcess($salesChannelContext, $transaction, $dataBag); + $this->checkTransactionStatus($transaction->getOrderTransaction(), $response, $salesChannelContext, $transaction, '1'); + if ($this->helper->isSuccessStatus($response)) { + return true; + } else { + return false; + } + } + + /** + * Handle Paymennt process + * + * @param SalesChannelContext $context + * @param mixed $transaction + * @param RequestDataBag $dataBag + * + * @return array + */ + public function handlePaymentProcess(SalesChannelContext $context, $transaction, RequestDataBag $dataBag = null): array + { + if (!empty($dataBag->get('novalnetpaymentFormData'))) { + $data = $dataBag->get('novalnetpaymentFormData')->all(); + $paymentData = $this->helper->unserializeData($data['paymentData']); + } elseif (!empty($dataBag->get('isBackendOrderCreation'))) { + $paymentData = $dataBag->get('BackendPaymentDetails'); + } elseif (!empty($dataBag->get('isRecurringOrder'))) { + $parentOrderNo = $this->helper->getSession('novalnetSubscriptionParentOrder'); + if (!empty($parentOrderNo)) { + $subscription = $this->transactionHelper->getSubscriptionDetails($context->getContext(), $parentOrderNo); + $paymentData = !empty($subscription) ? $subscription : []; + }; + } else { + $session = $this->helper->getSession('novalnetpaymentFormData'); + $paymentData = $this->helper->unserializeData($session['paymentData']); + } + + $this->helper->setSession('novalnetPaymentdata', $paymentData); + + $parameters = $this->generateBasicParameters($context, $transaction, $paymentData, $dataBag); + $paymentSettings = $this->helper->getNovalnetPaymentSettings($context->getSalesChannel()->getId()); + $this->helper->setSession('novalnetRequestParameters', $parameters); + $paymentaction = isset($paymentData['booking_details']['payment_action']) ? $paymentData['booking_details']['payment_action'] : 'payment'; + return $this->helper->sendPostRequest($parameters, $this->getPaymentEndpoint($paymentaction), $paymentSettings['NovalnetPayment.settings.accessKey']); + } + + /** + * Built basic parameters + * + * @param SalesChannelContext $context + * @param mixed $transaction + * @param array $paymentData + * @param RequestDataBag $dataBag + * + * @return array + */ + public function generateBasicParameters(SalesChannelContext $context, $transaction, array $paymentData, RequestDataBag $dataBag = null): array + { + $paymentSettings = $this->helper->getNovalnetPaymentSettings($context->getSalesChannel()->getId()); + + // Start to built basic parameters. + $parameters = []; + + if (!empty($dataBag->get('isSubscriptionOrder'))) { + $this->helper->setSession('isSubscriptionOrder', true); + }; + + // Built merchant parameters. + $parameters['merchant'] = [ + 'signature' => str_replace(' ', '', $paymentSettings['NovalnetPayment.settings.clientId']), + 'tariff' => $paymentSettings['NovalnetPayment.settings.tariff'] + ]; + + $customer = $context->getCustomer(); + + // Built customer parameters. + if (!empty($customer)) { + $parameters['customer'] = $this->helper->getCustomerData($customer); + } + + if (!empty($paymentData['booking_details']['birth_date'])) { + $parameters['customer']['birth_date'] = $paymentData['booking_details']['birth_date']; + unset($parameters['customer']['billing']['company']); + } + + $parameters['transaction'] = [ + 'amount' => $this->helper->amountInLowerCurrencyUnit($transaction->getOrder()->getPrice()->getTotalPrice()), + 'order_no' => $transaction->getOrder()->getOrderNumber(), + 'test_mode' => (int) $paymentData['booking_details']['test_mode'], + 'payment_type' => $paymentData['payment_details']['type'], + 'system_name' => 'Shopware', + 'system_ip' => $this->helper->getIp('SYSTEM'), + 'system_version' => $this->helper->getVersionInfo($context->getContext()), + ]; + + if (!empty($paymentData['booking_details']['due_date'])) { + $parameters['transaction']['due_date'] = date('Y-m-d', strtotime('+' . $paymentData['booking_details']['due_date'] . ' days')); + } + + if (!empty($paymentData['booking_details']['payment_action']) && $paymentData['booking_details']['payment_action'] == 'zero_amount') { + $parameters['transaction']['amount'] = 0; + $parameters['transaction']['create_token'] = 1; + } + + $paymentDataKeys = ['account_holder', 'iban', 'bic', 'wallet_token', 'pan_hash', 'unique_id', 'account_number', 'routing_number']; + + foreach ($paymentDataKeys as $paymentDataKey) { + if (!empty($paymentData['booking_details'][$paymentDataKey])) { + $parameters['transaction']['payment_data'][$paymentDataKey] = $paymentData['booking_details'][$paymentDataKey]; + } + } + + if (!empty($paymentData['booking_details']['payment_ref']['token'])) { + $parameters['transaction']['payment_data']['token'] = $paymentData['booking_details']['payment_ref']['token']; + } + + if (!empty($paymentData['booking_details']['enforce_3d'])) { + $parameters['transaction']['enforce_3d'] = 1; + } + + if ($paymentData['payment_details']['process_mode'] == 'redirect' || + (!empty($paymentData['booking_details']['do_redirect']) && + ($paymentData['booking_details']['do_redirect'] = '1' || $paymentData['booking_details']['do_redirect'] = true)) + ) { + $parameters['transaction']['return_url'] = $parameters['transaction']['error_return_url'] = $transaction->getReturnUrl(); + } + + if (!empty($paymentData['booking_details']['create_token'])) { + $parameters['transaction']['create_token'] = $paymentData['booking_details']['create_token']; + } + + if (!empty($paymentData['booking_details']['cycle'])) { + $parameters['instalment']= [ + 'interval' => '1m', + 'cycles' => $paymentData['booking_details']['cycle'] + ]; + } + + if (!empty($context->getSalesChannel()->getCurrency())) { + $parameters['transaction']['currency'] = $context->getCurrency()->getIsoCode() ? $context->getCurrency()->getIsoCode() : $context->getSalesChannel()->getCurrency()->getIsoCode(); + } + + if ($paymentData['payment_details']['type'] == 'PAYPAL') { + $parameters['cart_info']= $this->paypalSheetDetails($transaction); + } + + if (!empty($dataBag->get('isRecurringOrder'))) { + $paymentMethod = $paymentData['payment_details']['type']; + if (!in_array($paymentMethod, ['INVOICE', 'PREPAYMENT'])) { + $data = $this->transactionHelper->fetchNovalnetReferenceData($customer->getCustomerNumber(), $paymentMethod, $context->getContext()); + if (!is_null($data)) + { + $addtionalDetails = $this->helper->unserializeData($data->getAdditionalDetails()); + + if (isset($parameters ['transaction'] ['return_url']) && isset($parameters ['transaction'] ['error_return_url'])) { + unset($parameters ['transaction'] ['return_url'], $parameters ['transaction'] ['error_return_url']); + } + + if (!empty($data->getTokenInfo())) { + $parameters ['transaction'] ['payment_data'] ['token'] = $data->getTokenInfo() ?? ''; + } + + if (empty($parameters['customer']['billing']['company'])) { + $parameters ['customer'] ['birth_date'] = $addtionalDetails['dob'] ?? ''; + } + } + } + } + // Built custom parameters. + $parameters['custom'] = [ + 'lang' => $this->helper->getLocaleCodeFromContext($context->getContext()), + 'input2' => 'shop_token', + 'inputval2' => Random::getAlphanumericString(32) + ]; + + if (!empty($dataBag->get('isBackendOrderCreation'))) { + $parameters ['custom']['input4'] = 'BackendOrder'; + $parameters ['custom']['inputval4'] = '1'; + } + return $parameters; + } + + /** + * Built paypal lineItems to show in paypal page. + * + * @param mixed $transaction + * @return array + */ + public function paypalSheetDetails($transaction): array + { + $totalAmount = 0; + foreach ($transaction->getOrder()->getLineItems()->getElements() as $lineItem) { + $totalAmount += $lineItem->getPrice()->getTotalPrice(); + $cartinfo['line_items'][] = array( 'name'=> $lineItem->getLabel(), 'price' => round((float) sprintf('%0.2f', $lineItem->getPrice()->getUnitPrice()) * 100), 'quantity' => $lineItem->getQuantity(), 'description' => $lineItem->getDescription(), 'category' => 'physical' ); + } + + foreach ($transaction->getOrder()->getDeliveries()->getElements() as $delivery) { + $totalAmount += $delivery->getShippingCosts()->getTotalPrice(); + $cartinfo['items_shipping_price'] = round((float) sprintf('%0.2f', $delivery->getShippingCosts()->getTotalPrice()) * 100); + } + + if ($transaction->getOrder()->getPrice()->getTotalPrice() > $totalAmount) { + foreach ($transaction->getOrder()->getPrice()->getCalculatedTaxes()->getElements() as $tax) { + $cartinfo['items_tax_price'] = round((float) sprintf('%0.2f', $tax->getTax()) * 100); + } + } + return $cartinfo; + } + + /** + * Get Novalnet endpoint to send the payment request + * + * @param string $paymentaction + * + * @return string + */ + public function getPaymentEndpoint(string $paymentaction) : string + { + $action = 'payment'; + if ($paymentaction == 'authorized') { + $action = 'authorize'; + } + return $this->helper->getActionEndpoint($action); + } + + /** + * Check the response parameters for transaction status + + * @param OrderTransactionEntity $orderTransaction + * @param array $response + * @param SalesChannelContext $salesChannelContext + + */ + public function checkTransactionStatus(OrderTransactionEntity $orderTransaction, array $response, SalesChannelContext $salesChannelContext, $transaction = null, string $isExpress = null): void + { + if ($this->helper->isSuccessStatus($response)) { + $this->transactionSuccess($orderTransaction, $response, $salesChannelContext, $transaction); + } else { + $this->transactionFailure($orderTransaction, $response, $salesChannelContext, $transaction, $isExpress); + } + } + + /** + * Handle redirect response + * + * @param Request $request + * @param SalesChannelContext $salesChannelContext + * @param OrderTransactionEntity $orderTransaction + * + * @return array + */ + public function handleRedirectResponse(Request $request, SalesChannelContext $salesChannelContext, OrderTransactionEntity $orderTransaction): array + { + $paymentSettings = $this->helper->getNovalnetPaymentSettings($salesChannelContext->getSalesChannel()->getId()); + $response = []; + $txnsecert = $this->helper->getSession('novalnetTxnSecret'); + $novalnetParameter = $this->helper->getSession('novalnetRequestParameters'); + + if (!empty($txnsecert) && $this->helper->isValidChecksum($request, $paymentSettings['NovalnetPayment.settings.accessKey'], $txnsecert)) + { + $response = $this->helper->fetchTransactionDetails($request, $salesChannelContext); + + if (!empty($response['result']['status_code']) && $response['result']['status_code'] == '200018') + { + $response = $this->formatQuerystring($request); + $response['transaction']['test_mode'] = !empty($novalnetParameter['transaction']['test_mode']) ? $novalnetParameter['transaction']['test_mode'] : ''; + } + } else { + $response = $this->formatQuerystring($request); + $response['result']['status_text'] = 'Please note some data has been changed while redirecting'; + $response['transaction']['test_mode'] = !empty($novalnetParameter['transaction']['test_mode']) ? $novalnetParameter['transaction']['test_mode'] : ''; + } + + return $response; + } + /** + * Handle transaction success process + * + * @param OrderTransactionEntity $orderTransaction + * @param array $response + * @param SalesChannelContext $salesChannelContext + */ + public function transactionSuccess(OrderTransactionEntity $orderTransaction, array $response, SalesChannelContext $salesChannelContext, $transaction = null): void + { + try { + $paymentStatus = ''; + + $paymentdata = $this->helper->getSession('novalnetPaymentdata'); + $paymentResponse = $this->helper->setSession('novalnetPaymentResponse', $response); + + $insertData = [ + 'id' => Uuid::randomHex(), + 'paymentType' => $response['transaction']['payment_type'], + 'paidAmount' => 0, + 'tid' => $response['transaction']['tid'], + 'gatewayStatus' => $response['transaction']['status'], + 'amount' => $response['transaction']['amount'], + 'currency' => $response['transaction']['currency'], + 'orderNo' => $response['transaction']['order_no'], + 'customerNo' => !empty($response['customer']['customer_no']) ? $response['customer']['customer_no'] : '', + 'additionalDetails' => [ + 'payment_name' => !empty($paymentdata['payment_details']['name']) ? $paymentdata['payment_details']['name'] : $this->helper->getUpdatedPaymentName($response['transaction']['payment_type']) + ] + ]; + + if (!empty($this->helper->getSession('isSubscriptionOrder'))) { + $insertData['additionalDetails']['subscription'] = $paymentdata; + } + + if ($response['transaction']['status'] === 'CONFIRMED' && !empty($response['transaction']['amount'])) { + $paymentStatus = 'PAID'; + $insertData['paidAmount'] = $response['transaction']['amount']; + } + + if ($response['transaction']['status'] === 'CONFIRMED' && $response['transaction']['amount'] == 0 && (in_array($response['transaction']['payment_type'], ['PREPAYMENT', 'INVOICE']) || (in_array($response['transaction']['payment_type'], ['CREDITCARD', 'DIRECT_DEBIT_SEPA', 'GOOGLEPAY', 'APPLEPAY']) && (!empty($paymentdata['booking_details']['payment_action']) && $paymentdata['booking_details']['payment_action'] != 'zero_amount')))) { + $paymentStatus = 'PAID'; + if (! empty($response['transaction']['amount'])) { + $insertData['paidAmount'] = $response['transaction']['amount']; + } + + } elseif ($response['transaction']['status'] == 'CONFIRMED' && $response['transaction']['amount'] == 0 && $response['transaction']['payment_type'] == 'DIRECT_DEBIT_ACH') { + $paymentStatus = 'PAID'; + } elseif ($response['transaction']['status'] === 'PENDING') { + $paymentStatus = 'PENDING'; + } elseif ((($response['transaction']['status'] === 'ON_HOLD') || ($response['transaction']['status'] === 'CONFIRMED' && $response['transaction']['amount'] == 0 && !in_array($response['transaction']['payment_type'], ['PREPAYMENT']))) && !in_array($response['transaction']['payment_type'], ['INVOICE', 'PAYPAL'])) { + $paymentStatus = 'AUTHORIZED'; + } + + if ($response['transaction']['amount'] == 0) { + $insertData['additionalDetails']['novalnetRequestParameters'] = $this->helper->getSession('novalnetRequestParameters'); + } + + if (! empty($response['transaction']['bank_details'])) { + $insertData['additionalDetails']['bankDetails'] = $response['transaction']['bank_details']; + } + if (!empty($response['transaction']['payment_data']['token'])) { + $insertData['tokenInfo'] = $response['transaction']['payment_data']['token']; + } elseif(!empty($paymentdata['booking_details']['payment_ref']['token'])) { + $insertData['tokenInfo'] = $paymentdata['booking_details']['payment_ref']['token']; + } + + if (! empty($response['instalment']['cycles_executed'])) { + $insertData['additionalDetails']['InstalmentDetails']= $this->transactionHelper->getInstalmentInformation($response, $this->helper->getLocaleCodeFromContext($salesChannelContext->getContext(), true, $transaction != null ? $transaction->getOrder()->getLanguageId() : null)); + } + + if (!empty($response['customer']['birth_date'])) { + $insertData ['additionalDetails'] ['dob'] = date('Y-m-d', strtotime($response['customer']['birth_date'])); + } + + $insertData['additionalDetails'] = $this->helper->serializeData($insertData['additionalDetails']); + + $transactionData = $this->transactionHelper->fetchNovalnetTransactionData((string) $response['transaction']['order_no'], $salesChannelContext->getContext()); + + if (!empty($transactionData)) { + $insertData['id'] = $transactionData->getId(); + } + + // Insert (or) Update data into novalnet_transaction_details.repository + $this->helper->updateTransactionData($insertData, $salesChannelContext->getContext()); + + $orderComments = ''; + //novalnet order comments + $orderComments = $this->helper->formBankDetails($response, $salesChannelContext->getContext(), $transaction != null ? $transaction->getOrder()->getLanguageId() : null); + $orderComments .= !empty($orderTransaction->getCustomFields()['novalnet_comments']) ? '&&' .$orderTransaction->getCustomFields()['novalnet_comments'] : ''; + + $customFields = [ + 'novalnet_comments' => $orderComments, + ]; + + $this->orderTransactionRepository->upsert([[ + 'id' => $orderTransaction->getId(), + 'customFields' => $customFields + ]], $salesChannelContext->getContext()); + + if (!empty($paymentStatus)) { + if ($paymentStatus == 'PAID') { + // Payment completed, set transaction status to "PAID" + $this->orderTransactionStateHandler->paid($orderTransaction->getId(), $salesChannelContext->getContext()); + } elseif ($paymentStatus == 'AUTHORIZED') { + $this->orderTransactionStateHandler->authorize($orderTransaction->getId(), $salesChannelContext->getContext()); + } elseif (empty($response['custom']['inputval4'])) { + $this->orderTransactionStateHandler->process($orderTransaction->getId(), $salesChannelContext->getContext()); + } + } + + // Send order email with Novalnet transaction comments. + if ((in_array($response['transaction']['payment_type'], ['INVOICE','GUARANTEED_INVOICE','GUARANTEED_DIRECT_DEBIT_SEPA', 'INSTALMENT_INVOICE', 'INSTALMENT_DIRECT_DEBIT_SEPA','PREPAYMENT','CASHPAYMENT', 'MULTIBANCO'])) && in_array($response['transaction']['status'], ['CONFIRMED', 'ON_HOLD', 'PENDING']) && !empty($transaction)) { + $this->transactionHelper->prepareMailContent($transaction->getOrder(), $salesChannelContext, $orderComments); + } + } catch (\Exception $e) { + echo 'Caught exception: ', $e->getMessage(), "\n"; + } + + $this->unsetSession(); + return; + } + + /** + * Handle transaction failure process + * + * @param OrderTransactionEntity $orderTransaction + * @param array $response + * @param SalesChannelContext $salesChannelContext + * + * throws CustomerCanceledAsyncPaymentException + */ + public function transactionFailure(OrderTransactionEntity $orderTransaction, array $response, SalesChannelContext $salesChannelContext, $transaction = null, string $isExpress = null): ?CustomerCanceledAsyncPaymentException + { + $errorMessage = $this->helper->getResponseText($response); + $requestParameter = $this->helper->getSession('novalnetRequestParameters'); + $this->helper->setSession('novalnetErrorMessage', $errorMessage); + $paymentdata = $this->helper->getSession('novalnetPaymentdata'); + + $insertData = [ + 'id' => Uuid::randomHex(), + 'paymentType' => $response['transaction']['payment_type'], + 'paidAmount' => 0, + 'tid' => (int) $response['transaction']['tid'], + 'gatewayStatus' => !empty($response['transaction']['status']) ? $response['transaction']['status'] : $response['result']['status'], + 'additionalDetails' => [ + 'payment_name' => !empty($paymentdata['payment_details']['name']) ? $paymentdata['payment_details']['name'] : $this->helper->getUpdatedPaymentName($response['transaction']['payment_type']) + ] + ]; + + foreach ([ + 'amount' => 'amount', + 'orderNo' => 'order_no', + 'currency' => 'currency', + 'customerNo' => 'customer_no' + ] as $key => $value) { + if ($key == 'customerNo') { + $insertData[$key] = !empty($response['customer'][$value]) ? $response['customer'][$value] : (!empty($requestParameter['customer'][$value]) ? $requestParameter['customer'][$value] : 0); + } else { + $insertData[$key] = !empty($response['transaction'][$value]) ? $response['transaction'][$value] : (!empty($requestParameter['transaction'][$value]) ? $requestParameter['transaction'][$value] : 0); + } + } + + if (!empty($this->helper->getSession('isSubscriptionOrder'))) { + $insertData['additionalDetails']['subscription'] = $paymentdata; + } + + $insertData['additionalDetails'] = $this->helper->serializeData($insertData['additionalDetails']); + + if (!empty($response['transaction']['order_no'])) + { + $transactionData = $this->transactionHelper->fetchNovalnetTransactionData((string) $response['transaction']['order_no'], $salesChannelContext->getContext()); + + if (!empty($transactionData)) { + $insertData['id'] = $transactionData->getId(); + } + } + + // Insert (or) Update data into novalnet_transaction_details.repository + $this->helper->updateTransactionData($insertData, $salesChannelContext->getContext()); + + $this->unsetSession(); + $orderComments = $this->helper->formBankDetails($response, $salesChannelContext->getContext(), $transaction != null ? $transaction->getOrder()->getLanguageId() : null); + + $orderComments .= !empty($orderTransaction->getCustomFields()['novalnet_comments']) ? '&&' .$orderTransaction->getCustomFields()['novalnet_comments'] : ''; + + $customFields = [ + 'novalnet_comments' => $orderComments, + ]; + + // Update Novalnet comments in Order transaction Repository. + $this->orderTransactionRepository->upsert([[ + 'id' => $orderTransaction->getId(), + 'customFields' => $customFields + ]], $salesChannelContext->getContext()); + + if (!empty($transaction) && empty($isExpress)) { + throw new CustomerCanceledAsyncPaymentException($orderTransaction->getId(), $errorMessage); + } else { + // Payment cancelled, set transaction status to "CANCEL" + $this->orderTransactionStateHandler->cancel($orderTransaction->getId(), $salesChannelContext->getContext()); + return null; + } + } + + /** + * Form payment comments. + * + * @param Request $request + * + * @return array + */ + public function formatQuerystring(Request $request): array + { + $data = []; + foreach ([ + 'tid' => 'transaction', + 'payment_type' => 'transaction', + 'status' => 'result', + 'status_text' => 'result', + ] as $parameter => $category) { + $data[ $category ][ $parameter ] = $request->query->get($parameter); + } + return $data; + } + + + /** + * Unset Novalnet session + * + */ + public function unsetSession(): void + { + foreach ([ + 'novalnetResponse', + 'novalnetPaymentdata', + 'novalnetTxnSecret', + 'novalnetpaymentFormData', + 'novalnetRequestParameters', + 'isSubscriptionOrder' + ] as $sessionKey) { + if ($this->helper->hasSession($sessionKey)) { + $this->helper->removeSession($sessionKey); + } + } + } +} diff --git a/src/Subscriber/Administration/OrderEventSubscriber.php b/src/Subscriber/Administration/OrderEventSubscriber.php new file mode 100755 index 0000000..2193fdb --- /dev/null +++ b/src/Subscriber/Administration/OrderEventSubscriber.php @@ -0,0 +1,145 @@ +helper = $helper; + $this->salesChannelContextFactory = $salesChannelContextFactory; + $this->paymentProcessor = $paymentProcessor; + $this->router = $router; + } + + /** + * Get subscribed events + * + * return array + */ + public static function getSubscribedEvents(): array + { + return [ + CheckoutOrderPlacedEvent::class => 'orderPlaced', + ]; + } + + /** + * Get order Placed + * + * @param CheckoutOrderPlacedEvent $event + * + */ + + public function orderPlaced(CheckoutOrderPlacedEvent $event) + { + + $requestUrl =!empty($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : ''; + + if (!empty($requestUrl) && strpos($requestUrl, '/api/_proxy-order') !== false && (strpos($requestUrl, '/novalnet-subscription') == false)) { + $order = $event->getOrder(); + $transaction = $order->getTransactions()->last(); + $paymentMethod = $transaction->getPaymentMethod(); + $payment = strpos($paymentMethod->getHandlerIdentifier(), 'NovalnetPayment'); + + if (strpos($paymentMethod->getHandlerIdentifier(), 'NovalnetPayment') == true) { + $orderId = $order->getId(); + + $salesChannelContext = $this->salesChannelContextFactory->create(Uuid::randomHex(), $order->getSalesChannelId(), [ + SalesChannelContextService::CUSTOMER_ID => $order->getOrderCustomer()->getCustomerId(), + SalesChannelContextService::CURRENCY_ID => $order->getCurrencyId() ?? $order->getCurrency()->getId(), + SalesChannelContextService::PAYMENT_METHOD_ID => $paymentMethod->getId() + ]); + + $finishUrl = $this->router->generate('frontend.checkout.finish.page', ['orderId' => $orderId]); + $errorUrl = $this->router->generate('frontend.account.edit-order.page', ['orderId' => $orderId]); + $dataBag = new RequestDataBag(); + $dataBag->set('isBackendOrderCreation', true); + + $paymentData = $this->helper->getCustomerDetails($order->getOrderCustomer()->getCustomerId()); + $paymentDatas = !empty($paymentData['novalnetOrderBackendParameters']) ? $paymentData['novalnetOrderBackendParameters']: []; + + $dataBag->set('BackendPaymentDetails', $paymentDatas); + + try { + $this->paymentProcessor->process($orderId, $dataBag, $salesChannelContext, $finishUrl, $errorUrl); + } catch (PaymentProcessException $e) { + } + } + } + } +} diff --git a/src/Subscriber/Core/FrameEventSubscriber.php b/src/Subscriber/Core/FrameEventSubscriber.php new file mode 100755 index 0000000..593f8b4 --- /dev/null +++ b/src/Subscriber/Core/FrameEventSubscriber.php @@ -0,0 +1,62 @@ + 'setCustomXFrameOptions', + ]; + } + + /** + * set Custom XFrame Options + * + * @param ResponseEvent $event + * + */ + + public function setCustomXFrameOptions(ResponseEvent $event) + { + $response = $event->getResponse(); + $response->headers->set('X-Frame-Options', 'same-origin'); + } +} diff --git a/src/Subscriber/Storefront/NovalnetOrderFinishLoadedEvent.php b/src/Subscriber/Storefront/NovalnetOrderFinishLoadedEvent.php new file mode 100755 index 0000000..88da643 --- /dev/null +++ b/src/Subscriber/Storefront/NovalnetOrderFinishLoadedEvent.php @@ -0,0 +1,69 @@ +helper = $helper; + } + + /** + * Register subscribed events + * + * return array + */ + public static function getSubscribedEvents(): array + { + return [ + + CheckoutFinishPageLoadedEvent::class => 'onFinshPage' + ]; + } + + public function onFinshPage(CheckoutFinishPageLoadedEvent $event) + { + if ($this->helper->hasSession('novalnetPaymentResponse')) { + $this->helper->removeSession('novalnetPaymentResponse'); + } + } +} diff --git a/src/Subscriber/Storefront/PaymentEventSubscriber.php b/src/Subscriber/Storefront/PaymentEventSubscriber.php new file mode 100755 index 0000000..278c34e --- /dev/null +++ b/src/Subscriber/Storefront/PaymentEventSubscriber.php @@ -0,0 +1,92 @@ +getCurrentRequest())) { + $this->helper = $helper; + $this->request = $requestStack->getCurrentRequest(); + } + } + + /** + * Get subscribed events + * + * return array + */ + public static function getSubscribedEvents(): array + { + return [ + PaymentEvents::PAYMENT_METHOD_LOADED_EVENT => 'afterPaymentMethodLoaded' + ]; + } + + /** + * Store the needed values in session after payment selection + * + * @params EntityLoadedEvent $event + */ + public function afterPaymentMethodLoaded(EntityLoadedEvent $event): void + { + $paymentData = []; + + if (!empty($this->request) && !empty($this->request->get('paymentMethodId')) && !empty($this->request->get('novalnetpaymentFormData'))) { + $this->helper->setSession('novalnetpaymentFormData', $this->request->get('novalnetpaymentFormData')); + } + } +} diff --git a/src/Twig/Filter/NovalnetFilter.php b/src/Twig/Filter/NovalnetFilter.php new file mode 100755 index 0000000..f4002b9 --- /dev/null +++ b/src/Twig/Filter/NovalnetFilter.php @@ -0,0 +1,169 @@ +helper = $helper; + $this->paymentMethodRoute = $paymentMethodRoute; + $this->transactionHelper = $transactionHelper; + } + + public function getFilters() + { + return [ + new TwigFilter('novalnetPaymentHandler', [$this, 'novalnetPaymentHandler']), + new TwigFilter('getNovalnetComments', [$this, 'getNovalnetComments']), + new TwigFilter('cashPaymentResponse', [$this, 'cashPaymentResponse']), + new TwigFilter('getFinishNovalnetComments', [$this->transactionHelper, 'getFinishNovalnetComments']), + new TwigFilter('getPaymentMethodName', [$this->helper, 'getPaymentMethodName']), + new TwigFilter('novalnetPayment', [$this->helper, 'getNovalnetIframeUrl']), + new TwigFilter('shopVersion', [$this->helper, 'getShopVersion']), + new TwigFilter('getNovalnetInstalmentInfo', [$this, 'getNovalnetInstalmentInfo']), + new TwigFilter('getPaymentMethodNovalnetName', [$this, 'getPaymentMethodNovalnetName']), + new TwigFilter('getPaymentName', [$this->transactionHelper, 'getPaymentName']), + new TwigFilter('getChangedPaymentName', [$this->transactionHelper, 'getChangedPaymentName']), + new TwigFilter('getNovalnetErrorMessage', [$this->helper, 'getNovalnetErrorMessage']), + ]; + } + + /** + * Return the novalnet instalment information. + * + * @param SalesChannelContext $salesChannelContext + * @param string $orderNumber + * + * @return array + */ + public function getNovalnetInstalmentInfo(SalesChannelContext $salesChannelContext, $orderNumber): array + { + $transactionData = $this->transactionHelper->fetchNovalnetTransactionData((string) $orderNumber, $salesChannelContext->getContext()); + if (!empty($transactionData) && $transactionData->getGatewayStatus() === 'CONFIRMED') { + return $this->helper->unserializeData($transactionData->getAdditionalDetails()); + } + return []; + } + + /** + * Return the novalnet instalment information. + * + * @param SalesChannelContext $salesChannelContext + * @param string $paymentHandler + * + * @return string + */ + public function novalnetPaymentHandler(SalesChannelContext $salesChannelContext, $paymentHandler): string + { + if (!empty($paymentHandler)) { + $paymentMethod = preg_match('/\w+$/', $paymentHandler, $match); + $match = $match[0]; + return $match; + } + return ''; + } + + /* + * Get Payment Method Novalnet payment + * + * @param SalesChannelContext $salesChannelContext + * @param string|null $orderNumber + * + * @return string + */ + public function getPaymentMethodNovalnetName(SalesChannelContext $salesChannelContext, string $orderNumber): ?string + { + $transactionData = $this->transactionHelper->fetchNovalnetTransactionData((string) $orderNumber, $salesChannelContext->getContext()); + + return !empty($transactionData) ? $this->helper->getUpdatedPaymentType($transactionData->getPaymentType()) :'' ; + } + + /* + * Get Novalnet Comments + * + * @param string|null $comments + * + * @return string + */ + public function getNovalnetComments(string $comments) : ?string + { + if (!empty($comments)) { + $novalnetComments = str_replace("&&", '
Comments:
'.PHP_EOL, $comments); + } + return !empty($novalnetComments) ? $novalnetComments : $comments; + } + + /* + * Get Novalnet Cash Payment Resopnse + * + * @param SalesChannelContext $salesChannelContext + * + * @return array + */ + public function cashPaymentResponse(SalesChannelContext $salesChannelContext) : ?array + { + $paymentdata = $this->helper->getSession('novalnetPaymentResponse'); + return !empty($paymentdata) ? $paymentdata : []; + } +}