diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..0b68a78
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,6 @@
+ps_root_dir/
+vendor/
+
+composer.lock
+.php-cs-fixer.php
+.php-cs-fixer.cache
\ No newline at end of file
diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php
new file mode 100644
index 0000000..819ca8c
--- /dev/null
+++ b/.php-cs-fixer.dist.php
@@ -0,0 +1,25 @@
+in([
+ __DIR__,
+ ])
+ ->exclude([
+ 'vendor',
+ 'ps_root_dir',
+ ]);
+
+$config = new PhpCsFixer\Config();
+
+return $config
+ ->setRules([
+ '@PER-CS2.0' => true,
+ 'declare_strict_types' => true,
+ 'strict_param' => true,
+ 'concat_space' => ['spacing' => 'one'],
+ 'protected_to_private' => true,
+ 'nullable_type_declaration_for_default_null_value' => true,
+ 'final_class' => true,
+ ])
+ ->setRiskyAllowed(true)
+ ->setFinder($finder);
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..f6f9be4
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2024 SimPay.pl
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..eeed923
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,7 @@
+fixer:
+ vendor/bin/php-cs-fixer fix
+
+phpstan:
+ vendor/bin/phpstan analyse
+
+sa: fixer phpstan
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..7d1e8b0
--- /dev/null
+++ b/README.md
@@ -0,0 +1 @@
+# Simpay Prestashop
diff --git a/composer.json b/composer.json
new file mode 100644
index 0000000..cabe8a7
--- /dev/null
+++ b/composer.json
@@ -0,0 +1,35 @@
+{
+ "license": "MIT",
+ "name": "simpaypl/prestashop",
+ "type": "prestashop-module",
+ "description": "Module for integration with SimPay payment gateway",
+ "keywords": [
+ "simpay",
+ "prestashop",
+ "payment",
+ "gateway"
+ ],
+ "authors": [
+ {
+ "name": "SimPay Core Team"
+ }
+ ],
+ "autoload": {
+ "psr-4": {
+ "SimPaypl\\PrestaShop\\": "src/"
+ }
+ },
+ "require": {
+ "php": "^8.1",
+ "simpaypl/simpay": "^3.0"
+ },
+ "require-dev": {
+ "phpstan/phpstan": "^1.10",
+ "prestashop/php-dev-tools": "^4.3"
+ },
+ "config": {
+ "preferred-install": "dist",
+ "prepend-autoloader": false,
+ "sort-packages": true
+ }
+}
diff --git a/config.xml b/config.xml
new file mode 100644
index 0000000..a1f1c7d
--- /dev/null
+++ b/config.xml
@@ -0,0 +1,12 @@
+
+
+ simpay
+
+
+
+
+
+
+ 1
+ 1
+
\ No newline at end of file
diff --git a/config/admin/index.php b/config/admin/index.php
new file mode 100644
index 0000000..232bfba
--- /dev/null
+++ b/config/admin/index.php
@@ -0,0 +1,11 @@
+setTemplate('module:simpay/views/templates/front/failed.tpl');
+ }
+}
diff --git a/controllers/front/index.php b/controllers/front/index.php
new file mode 100644
index 0000000..232bfba
--- /dev/null
+++ b/controllers/front/index.php
@@ -0,0 +1,11 @@
+ 'error', 'message' => 'Invalid payload, expected JSON']));
+ }
+
+ /** @var array{
+ * id: string,
+ * service_id: string,
+ * status: string,
+ * amount: array{
+ * value: float,
+ * currency: string,
+ * commission: float,
+ * },
+ * control: string,
+ * channel: string,
+ * environment: string,
+ * signature: string
+ * }|bool|null $payload
+ */
+ $payload = json_decode($jsonPayload, true);
+
+ if (!is_array($payload)) {
+ http_response_code(400);
+ header('Content-Type: application/json');
+ die(json_encode(['status' => 'error', 'message' => 'Invalid payload, expected JSON']));
+ }
+
+ $signatureValues = [];
+ array_walk_recursive($payload, function (mixed $item, string $key) use (&$signatureValues) {
+ if ($key === 'signature') {
+ return;
+ }
+
+ $signatureValues[] = (string) $item;
+ });
+
+ $signatureValues[] = Configuration::get('SIMPAY_SERVICE_IPN_SIGNATURE_KEY');
+ $signatureValues = implode('|', $signatureValues);
+ $signatureHash = hash('sha256', $signatureValues);
+
+ if ($payload['signature'] !== $signatureHash) {
+ http_response_code(400);
+ header('Content-Type: application/json');
+ die(json_encode(['status' => 'error', 'message' => 'Invalid signature']));
+ }
+
+ $order = Order::getByCartId((int) $payload['control']);
+
+ if (null === $order) {
+ http_response_code(400);
+ header('Content-Type: application/json');
+ die(json_encode(['status' => 'error', 'message' => 'Order not found']));
+ }
+
+ if ((int) Configuration::get(Simpay::CONFIG_OS_AWAITING) === $order->getCurrentState()) {
+
+ $orderStatusId = (int) match($payload['status']) {
+ 'transaction_paid' => Configuration::get('PS_OS_PAYMENT'),
+ default => Configuration::get('PS_OS_ERROR'),
+ };
+
+ $orderHistory = new OrderHistory();
+ $orderHistory->id_order = (int) $order->id;
+ $orderHistory->changeIdOrderState($orderStatusId, (int) $order->id, true);
+ $orderHistory->save();
+ }
+
+
+ http_response_code(200);
+ header('Content-Type: application/json');
+ die(json_encode(['status' => 'ok']));
+ }
+}
diff --git a/controllers/front/validate.php b/controllers/front/validate.php
new file mode 100644
index 0000000..d776e3d
--- /dev/null
+++ b/controllers/front/validate.php
@@ -0,0 +1,175 @@
+assertModuleIsActive();
+
+ if (!$this->checkIfContextIsValid()) {
+ $this->redirectToOrder();
+
+ return;
+ }
+
+ if (!$this->checkIfPaymentOptionIsAvailable()) {
+ $this->redirectToOrder();
+
+ return;
+ }
+
+ /** @var Cart $cart */
+ $cart = $this->context->cart;
+ /** @var Currency $currency */
+ $currency = $this->context->currency;
+
+ $customer = new Customer($cart->id_customer);
+ if (false === Validate::isLoadedObject($customer)) {
+ $this->redirectToOrder();
+
+ return;
+ }
+
+ /** @var PaymentInterface $paymentClient */
+ $paymentClient = $this->get('prestashop.module.simpay.front.payment_client');
+
+ /** @var string $serviceIdString */
+ $serviceIdString = Configuration::get(SimpayDataConfiguration::SERVICE_ID);
+ $response = $paymentClient->paymentTransactionCreate(
+ new ServiceId($serviceIdString),
+ $this->createPaymentRequest($cart, $customer->secure_key),
+ );
+
+ $this->module->validateOrder(
+ (int) $cart->id,
+ (int) Configuration::get(Simpay::CONFIG_OS_AWAITING),
+ $cart->getOrderTotal(),
+ $this->trans('SimPay', [], 'Modules.Simpay.Shop'),
+ null,
+ [
+ 'transaction_id' => $response->transactionId,
+ ],
+ $currency->id,
+ false,
+ $customer->secure_key,
+ );
+
+ $this->setTemplate('module:simpay/views/templates/front/validate.tpl');
+ $this->context->smarty?->assign([
+ 'action' => $response->redirectUrl,
+ ]);
+
+ }
+ private function assertModuleIsActive(): void
+ {
+ if (!Module::isEnabled($this->module->name)) {
+ die($this->trans('This payment method is not available.', [], 'Modules.Simpay.Shop'));
+ }
+
+ if (!$this->module->active) {
+ die($this->trans('SimPay module module isn\'t active.', [], 'Modules.Simpay.Shop'));
+ }
+ }
+
+ private function checkIfContextIsValid(): bool
+ {
+ if (null === $this->context->cart) {
+ return false;
+ }
+
+ if (null === $this->context->currency) {
+ return false;
+ }
+
+ return Validate::isLoadedObject($this->context->cart)
+ && Validate::isUnsignedInt($this->context->cart->id_customer)
+ && Validate::isUnsignedInt($this->context->cart->id_address_delivery)
+ && Validate::isUnsignedInt($this->context->cart->id_address_invoice);
+ }
+
+ private function checkIfPaymentOptionIsAvailable(): bool
+ {
+ $modules = Module::getPaymentModules();
+
+ if (empty($modules)) {
+ return false;
+ }
+
+ foreach ($modules as $module) {
+ if (isset($module['name']) && $this->module->name === $module['name']) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private function redirectToOrder(): void
+ {
+ /** @var Link $link */
+ $link = $this->context->link;
+
+ Tools::redirect($link->getPageLink(
+ 'order',
+ true,
+ (int) $this->context->language?->id,
+ [
+ 'step' => 1,
+ ]
+ ));
+ }
+
+ private function createPaymentRequest(Cart $cart, string $customerSecureKey): CreatePayment
+ {
+ $amount = (float) $cart->getOrderTotal();
+
+ /** @var Link $link */
+ $link = $this->context->link;
+
+ $successReturnUrl = $link->getPageLink(
+ 'order-confirmation',
+ true,
+ $this->context->language?->id,
+ [
+ 'id_cart' => (int) $cart->id,
+ 'id_module' => (int) $this->module->id,
+ 'id_order' => $this->module->currentOrder,
+ 'key' => $customerSecureKey
+ ]
+ );
+
+ $failureReturnUrl = $link->getModuleLink(
+ 'simpay',
+ 'failed',
+ [],
+ true,
+ $this->context->language?->id,
+ );
+
+ return new CreatePayment(
+ new Amount($amount),
+ [],
+ null,
+ new SimpayCurrency('PLN'),
+ null,
+ new Control((string) $cart->id),
+ null,
+ null,
+ null,
+ new CallbackReturnUrl($successReturnUrl, $failureReturnUrl),
+ );
+ }
+}
diff --git a/controllers/index.php b/controllers/index.php
new file mode 100644
index 0000000..232bfba
--- /dev/null
+++ b/controllers/index.php
@@ -0,0 +1,11 @@
+
+
+
+ {payment}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+ |
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Hi {firstname} {lastname},
+
+ |
+
+
+
+
+ Thank you for shopping with {shop_name}!
+
+ |
+
+
+
+ |
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Order ID {order_name} - Pending payment
+
+ |
+
+ |
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Your order with the reference {order_name} has been placed successfully. You can expect delivery as soon as your payment is received.
+
+ |
+
+ |
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Payment method: {payment}
+
+ |
+
+ |
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ You have decided to pay via SimPay.
+
+ |
+
+
+
+
+ Amount:
+ {total_paid}
+
+ |
+
+
+ |
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Follow your order and download your invoice on our shop, go to the Order history and details section of your customer account.
+
+ |
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ If you have a guest account, you can follow your order via the Guest Tracking section on our shop.
+
+ |
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mails/en/awaiting_simpay_payment.txt b/mails/en/awaiting_simpay_payment.txt
new file mode 100644
index 0000000..aa7ab6a
--- /dev/null
+++ b/mails/en/awaiting_simpay_payment.txt
@@ -0,0 +1,23 @@
+{shop_url}
+
+Hi {firstname} {lastname},
+
+Thank you for shopping with {shop_name}!
+
+Order ID {order_name} - Pending payment
+
+Your order with the reference {order_name} has been placed successfully. You can expect delivery as soon as your payment is received.
+
+Payment method: {payment}
+
+You have decided to pay via SimPay.
+
+Amount: {total_paid}
+
+Follow your order and download your invoice on our shop, go to the [Order history and details]({history_url}) section of your customer account.
+
+If you have a guest account, you can follow your order via the [Guest Tracking]({guest_tracking_url}) section on our shop.
+
+[{shop_name}]({shop_url})
+
+Powered by [PrestaShop](https://www.prestashop.com/?utm_source=marchandprestashop&utm_medium=e-mail=utm_campaign=footer_1-7)
\ No newline at end of file
diff --git a/mails/en/index.php b/mails/en/index.php
new file mode 100644
index 0000000..232bfba
--- /dev/null
+++ b/mails/en/index.php
@@ -0,0 +1,11 @@
+ 'SimpayConfigurationAdminParentController',
+ 'name' => 'SimPay Module',
+ 'parent_class_name' => 'AdminParentModulesSf',
+ 'visible' => false,
+ ],
+ [
+ 'class_name' => 'SimpayConfigurationAdminController',
+ 'route_name' => 'simpay_configuration',
+ 'name' => 'Configuration',
+ 'parent_class_name' => 'SimpayConfigurationAdminParentController',
+ 'visible' => false,
+ ],
+ ];
+
+ private const HOOKS = [
+ 'paymentOptions',
+ ];
+
+ public function __construct()
+ {
+ $this->name = 'simpay';
+ $this->tab = 'payments_gateways';
+ $this->version = '0.1.0';
+ $this->author = 'Payments Solution Sp. z o.o.';
+ $this->ps_versions_compliancy = [
+ 'min' => '8.0.0',
+ 'max' => '8.99.99',
+ ];
+ $this->controllers = ['failed', 'notify', 'validate'];
+
+ $this->bootstrap = true;
+ parent::__construct();
+
+ $this->displayName = $this->trans('SimPay', [], 'Modules.Simpay.Admin');
+ $this->description = $this->trans('Connect your shop directly with SimPay gateway', [], 'Modules.Simpay.Admin');
+ $this->confirmUninstall = $this->trans('Are you sure you want to uninstall?', [], 'Modules.Simpay.Admin');
+ }
+
+ public function install(): bool
+ {
+ if (!parent::install()) {
+ return false;
+ }
+
+ if (!$this->registerHook(self::HOOKS)) {
+ return false;
+ }
+
+ if (!$this->createOrderState(
+ self::CONFIG_OS_AWAITING,
+ [
+ 'en' => 'Awaiting SimPay payment',
+ ],
+ '#34209e',
+ true,
+ false,
+ false,
+ false,
+ false,
+ false,
+ false,
+ false,
+ 'awaiting_simpay_payment'
+ )) {
+ return false;
+ }
+
+ if (!$this->installTabs()) {
+ return false;
+ }
+
+ return true;
+ }
+
+ public function uninstall(): bool
+ {
+ if (!parent::uninstall()) {
+ return false;
+ }
+
+ if (!$this->deleteOrderState()) {
+ return false;
+ }
+
+ if (!$this->uninstallTabs()) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * @param array{cart: Cart} $params
+ * @return array
+ */
+ public function hookPaymentOptions(array $params): array
+ {
+ $cart = $params['cart'];
+
+ if (false === Validate::isLoadedObject($cart)) {
+ return [];
+ }
+
+ if (false === $this->checkCurrency($cart)) {
+ return [];
+ }
+
+ if ($cart->isVirtualCart()) {
+ return [];
+ }
+
+ if (!isset($this->context->link)) {
+ return [];
+ }
+
+ $logoPath = Media::getMediaPath(_PS_MODULE_DIR_ . $this->name . '/views/img/option/simpay.png');
+
+ $simpayPaymentOption = (new PaymentOption())
+ ->setModuleName((string) $this->name)
+ ->setCallToActionText('Pay with Simpay')
+ ->setAction($this->context->link->getModuleLink((string) $this->name, 'validate', [], true))
+ ->setInputs([
+ 'token' => [
+ 'name' => 'token',
+ 'type' => 'hidden',
+ 'value' => '[5cbfniD+(gEV<59lYbG/,3VmHiEsetLogo($logoPath);
+ }
+
+ return [$simpayPaymentOption];
+ }
+
+ public function getContent(): void
+ {
+ /** @var Router $router */
+ $router = $this->get('router');
+ Tools::redirectAdmin($router->generate('simpay_configuration'));
+ }
+
+ private function installTabs(): bool
+ {
+ foreach (self::MODULE_ADMIN_CONTROLLERS as $controller) {
+ if (Tab::getIdFromClassName($controller['class_name'])) {
+ continue;
+ }
+
+ $tab = new Tab();
+ $tab->class_name = $controller['class_name'];
+ $tab->active = $controller['visible'];
+
+ /** @var array,
+ * }> $languages
+ */
+ $languages = Language::getLanguages(false);
+ foreach ($languages as $lang) {
+ $tab->name[$lang['id_lang']] = $this->trans($controller['name'], [], 'Modules.Simpay.Admin', $lang['locale']);
+ }
+ $tab->id_parent = Tab::getIdFromClassName($controller['parent_class_name']);
+ $tab->module = 'simpay';
+ if (!$tab->add()) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private function uninstallTabs(): bool
+ {
+ foreach (self::MODULE_ADMIN_CONTROLLERS as $controller) {
+ $id_tab = (int) Tab::getIdFromClassName($controller['class_name']);
+ $tab = new Tab($id_tab);
+ if (Validate::isLoadedObject($tab)) {
+ if (!$tab->delete()) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ /** @param array $nameByLangIsoCode */
+ private function createOrderState(
+ string $configurationKey,
+ array $nameByLangIsoCode,
+ string $color,
+ bool $isLogable = false,
+ bool $isPaid = false,
+ bool $isInvoice = false,
+ bool $isShipped = false,
+ bool $isDelivery = false,
+ bool $isPdfDelivery = false,
+ bool $isPdfInvoice = false,
+ bool $isSendEmail = false,
+ string $template = '',
+ bool $isHidden = false,
+ bool $isUnremovable = true,
+ bool $isDeleted = false,
+ ): bool {
+ $tabNameByLangId = [];
+
+ foreach ($nameByLangIsoCode as $langIsoCode => $name) {
+ /** @var array> $languages */
+ $languages = Language::getLanguages(false);
+ foreach ($languages as $language) {
+ if (Tools::strtolower($language['iso_code']) === $langIsoCode) {
+ $tabNameByLangId[(int) $language['id_lang']] = $name;
+ } elseif (isset($nameByLangIsoCode['en'])) {
+ $tabNameByLangId[(int) $language['id_lang']] = $nameByLangIsoCode['en'];
+ }
+ }
+ }
+
+ $orderState = new OrderState();
+ $orderState->module_name = $this->name;
+ $orderState->name = $tabNameByLangId;
+ $orderState->color = $color;
+ $orderState->logable = $isLogable;
+ $orderState->paid = $isPaid;
+ $orderState->invoice = $isInvoice;
+ $orderState->shipped = $isShipped;
+ $orderState->delivery = $isDelivery;
+ $orderState->pdf_delivery = $isPdfDelivery;
+ $orderState->pdf_invoice = $isPdfInvoice;
+ $orderState->send_email = $isSendEmail;
+ $orderState->hidden = $isHidden;
+ $orderState->unremovable = $isUnremovable;
+ $orderState->template = $template;
+ $orderState->deleted = $isDeleted;
+
+ if (false === $orderState->add()) {
+ $this->_errors[] = sprintf(
+ 'Failed to create OrderState %s',
+ $configurationKey
+ );
+
+ return false;
+ }
+
+ if (false === Configuration::updateGlobalValue($configurationKey, (int) $orderState->id)) {
+ $this->_errors[] = sprintf(
+ 'Failed to save OrderState %s to Configuration',
+ $configurationKey
+ );
+
+ return false;
+ }
+
+ $orderStateImgPath = $this->getLocalPath() . 'views/img/orderstate/' . $configurationKey . '.png';
+ if (false === Tools::file_exists_cache($orderStateImgPath)) {
+ $this->_errors[] = sprintf(
+ 'Failed to find icon file of OrderState %s',
+ $configurationKey
+ );
+
+ return false;
+ }
+
+ if (false === Tools::copy($orderStateImgPath, _PS_ORDER_STATE_IMG_DIR_ . $orderState->id . '.gif')) {
+ $this->_errors[] = sprintf(
+ 'Failed to copy icon of OrderState %s',
+ $configurationKey
+ );
+
+ return false;
+ }
+
+ return true;
+ }
+
+ private function deleteOrderState(): bool
+ {
+ $result = true;
+
+ $orderStateCollection = new PrestaShopCollection('OrderState');
+ $orderStateCollection->where('module_name', '=', $this->name);
+ /** @var OrderState[] $orderStates */
+ $orderStates = $orderStateCollection->getAll();
+
+ foreach ($orderStates as $orderState) {
+ $orderState->deleted = true;
+ if (!$orderState->save()) {
+ $result = false;
+ }
+ }
+
+ return $result;
+ }
+
+ private function checkCurrency(Cart $cart): bool
+ {
+ $currencyOrder = new Currency($cart->id_currency);
+
+ return 'PLN' === $currencyOrder->iso_code;
+ }
+}
diff --git a/src/Controller/SimpayConfigurationAdminController.php b/src/Controller/SimpayConfigurationAdminController.php
new file mode 100644
index 0000000..ddaa42d
--- /dev/null
+++ b/src/Controller/SimpayConfigurationAdminController.php
@@ -0,0 +1,42 @@
+simpayFormDataHandler = $simpayFormDataHandler;
+ }
+ public function configureAction(Request $request): Response
+ {
+ $configurationForm = $this->simpayFormDataHandler->getForm();
+ $configurationForm->handleRequest($request);
+
+ if ($configurationForm->isSubmitted() && $configurationForm->isValid()) {
+ /** @var array $data */
+ $data = $configurationForm->getData();
+ $errors = $this->simpayFormDataHandler->save($data);
+
+ if (empty($errors)) {
+ $this->addFlash('success', $this->trans('Successful update.', 'Admin.Notifications.Success'));
+
+ return $this->redirectToRoute('simpay_configuration');
+ }
+
+ $this->flashErrors($errors);
+ }
+
+ return $this->render('@Modules/simpay/views/templates/admin/configuration.html.twig', [
+ 'configurationForm' => $configurationForm->createView(),
+ ]);
+ }
+}
diff --git a/src/Controller/index.php b/src/Controller/index.php
new file mode 100644
index 0000000..232bfba
--- /dev/null
+++ b/src/Controller/index.php
@@ -0,0 +1,11 @@
+configuration = $configuration;
+ }
+
+ /** @return array{api_key: string, api_password: string, service_id: string, service_ipn_signature_key: string} */
+ public function getConfiguration(): array
+ {
+ return [
+ 'api_key' => (string) $this->configuration->get(self::API_KEY),
+ 'api_password' => (string) $this->configuration->get(self::API_PASSWORD),
+ 'service_id' => (string) $this->configuration->get(self::SERVICE_ID),
+ 'service_ipn_signature_key' => (string) $this->configuration->get(self::SERVICE_IPN_SIGNATURE_KEY),
+ ];
+ }
+
+ /**
+ * @param array{api_key: string, api_password: string, service_id: string, service_ipn_signature_key: string} $configuration
+ * @return array
+ */
+ public function updateConfiguration(array $configuration)
+ {
+ if (!$this->validateConfiguration($configuration)) {
+ return ['Invalid configuration'];
+ }
+
+ $this->configuration->set(self::API_KEY, $configuration['api_key']);
+ $this->configuration->set(self::API_PASSWORD, $configuration['api_password']);
+ $this->configuration->set(self::SERVICE_ID, $configuration['service_id']);
+ $this->configuration->set(self::SERVICE_IPN_SIGNATURE_KEY, $configuration['service_ipn_signature_key']);
+
+
+
+ return [];
+ }
+
+ /**
+ * @param array $configuration
+ */
+ public function validateConfiguration(array $configuration): bool
+ {
+ return isset($configuration['api_key'])
+ && isset($configuration['api_password'])
+ && isset($configuration['service_id'])
+ && isset($configuration['service_ipn_signature_key']);
+ }
+}
diff --git a/src/Form/SimpayFormDataProvider.php b/src/Form/SimpayFormDataProvider.php
new file mode 100644
index 0000000..19795a4
--- /dev/null
+++ b/src/Form/SimpayFormDataProvider.php
@@ -0,0 +1,33 @@
+simpayDataConfiguration = $simpayDataConfiguration;
+ }
+
+ /** @return array{api_key: string, api_password: string, service_id: string, service_ipn_signature_key: string} */
+ public function getData(): array
+ {
+ return $this->simpayDataConfiguration->getConfiguration();
+
+ }
+
+ /**
+ * @param array{api_key: string, api_password: string, service_id: string, service_ipn_signature_key: string} $data
+ * @return array
+ */
+ public function setData(array $data): array
+ {
+ return $this->simpayDataConfiguration->updateConfiguration($data);
+ }
+}
diff --git a/src/Form/SimpayFormType.php b/src/Form/SimpayFormType.php
new file mode 100644
index 0000000..86f809f
--- /dev/null
+++ b/src/Form/SimpayFormType.php
@@ -0,0 +1,63 @@
+add('api_key', TextType::class, [
+ 'label' => $this->trans('API Key', 'Modules.Simpay.Admin'),
+ 'help' => $this->trans('Konto Klienta -> API -> Szczegoly -> Klucz', 'Modules.Simpay.Admin'),
+ 'constraints' => [
+ new NotBlank(),
+ ],
+ ])
+
+ ->add('api_password', TextType::class, [
+ 'label' => $this->trans('API Password', 'Modules.Simpay.Admin'),
+ 'help' => $this->trans('Konto Klienta -> API -> Szczegoly -> Hasło / Bearer Token ', 'Modules.Simpay.Admin'),
+ 'constraints' => [
+ new NotBlank(),
+ ],
+ ])
+
+ ->add('service_id', TextType::class, [
+ 'label' => $this->trans('Service ID', 'Modules.Simpay.Admin'),
+ 'help' => $this->trans('Platnosci online -> Uslugi -> Szczegoly -> ID', 'Modules.Simpay.Admin'),
+ 'constraints' => [
+ new NotBlank(),
+ ],
+ ])
+
+ ->add('service_ipn_signature_key', TextType::class, [
+ 'label' => $this->trans('Service IPN Signature Key', 'Modules.Simpay.Admin'),
+ 'help' => $this->trans('Platnosci online -> Uslugi -> Szczegoly -> Ustawienia -> Klucz do sygnatury IPN', 'Modules.Simpay.Admin'),
+ 'constraints' => [
+ new NotBlank(),
+ ],
+ ])
+
+ ->add('service_ipn_notify_url', UrlType::class, [
+ 'label' => $this->trans('Service IPN Notify URL', 'Modules.Simpay.Admin'),
+ 'help' => $this->trans('Platnosci online -> Uslugi -> Szczegoly -> Ustawienia -> Adres url do powiadomień IPN', 'Modules.Simpay.Admin'),
+ 'required' => false,
+ 'mapped' => false,
+ 'disabled' => true,
+ 'data' => (new Link())->getModuleLink('simpay', 'notify', [], true),
+ ])
+ ;
+ }
+
+}
diff --git a/src/Form/index.php b/src/Form/index.php
new file mode 100644
index 0000000..232bfba
--- /dev/null
+++ b/src/Form/index.php
@@ -0,0 +1,11 @@
+configuration = $configuration;
+ }
+ public function __invoke(): PaymentInterface
+ {
+ return new PaymentApi(
+ new HttpClientFactory(
+ new SimpayConfiguration(
+ $this->configuration->get('SIMPAY_API_KEY'),
+ $this->configuration->get('SIMPAY_API_PASSWORD'),
+ 'en',
+ )
+ )
+ );
+ }
+}
diff --git a/src/index.php b/src/index.php
new file mode 100644
index 0000000..232bfba
--- /dev/null
+++ b/src/index.php
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+ {{ form_widget(configurationForm) }}
+
+
+
+
+
+
+
+ {{ form_end(configurationForm) }}
+{% endblock %}
\ No newline at end of file
diff --git a/views/templates/admin/index.php b/views/templates/admin/index.php
new file mode 100644
index 0000000..232bfba
--- /dev/null
+++ b/views/templates/admin/index.php
@@ -0,0 +1,11 @@
+
+
+
+ There was an error during the payment process
+
+
+{/block}
+
+{block name="link_rewrite"}
+ simpay-payment-error
+{/block}
\ No newline at end of file
diff --git a/views/templates/front/index.php b/views/templates/front/index.php
new file mode 100644
index 0000000..232bfba
--- /dev/null
+++ b/views/templates/front/index.php
@@ -0,0 +1,11 @@
+
+ {l s='You will be redirected to SimPay payment gateway. Please wait...' mod='simpay'}
+ {l s='If you are not redirected automatically' mod='simpay'}
+
+
+{/block}
+
+{*{block name='javascript_bottom'}*}
+{* {include file="_partials/javascript.tpl" javascript=$javascript.bottom}*}
+{* *}
+{*{/block}*}
\ No newline at end of file