diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..68729d6
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+.idea/
+.DS_Store
\ No newline at end of file
diff --git a/README.md b/README.md
index e69de29..7263c85 100644
--- a/README.md
+++ b/README.md
@@ -0,0 +1,68 @@
+# Craftgate Payment Orchestration Module for PrestaShop
+
+## Description
+
+The Craftgate Payment Orchestration module for PrestaShop provides a seamless integration with Craftgate's payment services. It allows your customers to make payments using various methods supported by Craftgate, including credit/debit cards and alternative payment methods.
+
+## Features
+
+- Easy integration with Craftgate payment services
+- Support for credit/debit card payments
+- Support for alternative payment methods
+- Customizable payment option title and description
+- Sandbox mode for testing
+- One-page checkout option
+
+## Compatibility
+
+This module is compatible with PrestaShop versions 1.7.x and 8.x.
+
+## Requirements
+
+- PHP 7.2 or higher
+- PrestaShop 1.7.x or 8.x
+
+## Installation
+
+There are two ways to install the Craftgate Payment Orchestration module:
+
+### Method 1: Manual Installation
+
+1. Download the latest release of the module from the GitHub repository.
+2. Unzip the downloaded file.
+3. Upload the `craftgate_payment_orchestration` folder to your PrestaShop's `/modules` directory.
+4. Log in to your PrestaShop admin panel.
+5. Navigate to "Modules" > "Module Manager".
+6. Search for "Craftgate Payment Orchestration" in the module list.
+7. Click on the "Install" button next to the module.
+8. After installation, click on "Configure" to set up your Craftgate API credentials and other settings.
+
+### Method 2: ZIP File Installation
+
+1. Download the ZIP file from the Github repository.
+2. Log in to your PrestaShop admin panel.
+3. Navigate to "Modules" > "Module Manager".
+4. Click on the "Upload a module" button at the top of the page.
+5. Select the downloaded ZIP file and upload it.
+6. PrestaShop will automatically install the module.
+7. After installation, click on "Configure" to set up your Craftgate API credentials and other settings.
+
+## Configuration
+
+1. In the module configuration page, enter your Craftgate API credentials (API Key and Secret Key) for both live and sandbox environments.
+2. Choose whether to enable sandbox mode for testing.
+3. Customize the payment option title and description if desired.
+4. Configure the one-page checkout option if you want to use it.
+5. Save your settings.
+
+## Usage
+
+Once installed and configured, the Craftgate payment option will appear on the checkout page for your customers. They can select this option to pay using Craftgate's services.
+
+## Support
+
+For any issues or questions, please contact Craftgate support via support@craftgate.io
+
+## License
+
+This module is released under the [MIT License](LICENSE).
\ No newline at end of file
diff --git a/classes/CraftgateClient.php b/classes/CraftgateClient.php
new file mode 100755
index 0000000..65a8786
--- /dev/null
+++ b/classes/CraftgateClient.php
@@ -0,0 +1,46 @@
+craftgate = new \Craftgate\Craftgate(array(
+ 'apiKey' => $api_key,
+ 'secretKey' => $secret_key,
+ 'baseUrl' => $api_url,
+ ));
+ }
+
+ public function initCheckoutForm($request)
+ {
+ $response = $this->craftgate->payment()->initCheckoutPayment($request);
+ return $this->buildResponse($response);
+ }
+
+ public function retrieveCheckoutFormResult($token)
+ {
+ $response = $this->craftgate->payment()->retrieveCheckoutPayment($token);
+ return $this->buildResponse($response);
+ }
+
+ private function buildResponse($response)
+ {
+ $response_json = json_decode($response);
+ return $response_json->data ?? $response_json;
+ }
+}
\ No newline at end of file
diff --git a/classes/CraftgatePayment.php b/classes/CraftgatePayment.php
new file mode 100644
index 0000000..ac8afb4
--- /dev/null
+++ b/classes/CraftgatePayment.php
@@ -0,0 +1,96 @@
+ 'craftgate_payments',
+ 'primary' => 'id_craftgate_payment',
+ 'fields' => [
+ 'payment_id' => ['type' => self::TYPE_INT, 'required' => true],
+ 'checkout_token' => ['type' => self::TYPE_STRING, 'validate' => 'isString', 'size' => 255],
+ 'meta_data' => ['type' => self::TYPE_STRING],
+ 'id_order' => ['type' => self::TYPE_INT, 'required' => true],
+ ],
+ ];
+
+ public static function getByOrderId(int $orderId)
+ {
+ $sql = 'SELECT `id_craftgate_payment`
+ FROM `' . _DB_PREFIX_ . 'craftgate_payments`
+ WHERE `id_order` = ' . $orderId;
+
+ $result = Db::getInstance()->getValue($sql);
+ return !empty($result) ? new self($result) : false;
+ }
+
+ public static function getByCheckoutToken(string $checkoutToken): false|CraftgatePayment
+ {
+ $sql = 'SELECT `id_craftgate_payment`
+ FROM `' . _DB_PREFIX_ . 'craftgate_payments`
+ WHERE `checkout_token` = \'' . pSQL($checkoutToken) . '\'';
+
+ $result = Db::getInstance()->getValue($sql);
+ return !empty($result) ? new self($result) : false;
+ }
+
+ public function getIdOrder()
+ {
+ return $this->id_order;
+ }
+
+ public function setIdOrder($id_order): void
+ {
+ $this->id_order = $id_order;
+ }
+
+ public function getPaymentId()
+ {
+ return $this->payment_id;
+ }
+
+ public function setPaymentId($payment_id): void
+ {
+ $this->payment_id = $payment_id;
+ }
+
+ public function getCheckoutToken()
+ {
+ return $this->checkout_token;
+ }
+
+ public function setCheckoutToken($checkout_token): void
+ {
+ $this->checkout_token = $checkout_token;
+ }
+
+ public function getIdCraftgatePayment(): string
+ {
+ return $this->id_craftgate_payment;
+ }
+
+ public function setIdCraftgatePayment(string $id_craftgate_payment): void
+ {
+ $this->id_craftgate_payment = $id_craftgate_payment;
+ }
+
+ public function getMetaData()
+ {
+ return json_decode($this->meta_data);
+ }
+
+ public function setMetaData($data): void
+ {
+ $this->meta_data = json_encode($data);
+ }
+}
diff --git a/classes/CraftgatePaymentDBManager.php b/classes/CraftgatePaymentDBManager.php
new file mode 100644
index 0000000..a29dd68
--- /dev/null
+++ b/classes/CraftgatePaymentDBManager.php
@@ -0,0 +1,24 @@
+execute($sql);
+ }
+}
+
+
diff --git a/classes/CraftgatePaymentErrorException.php b/classes/CraftgatePaymentErrorException.php
new file mode 100644
index 0000000..586f27f
--- /dev/null
+++ b/classes/CraftgatePaymentErrorException.php
@@ -0,0 +1,10 @@
+module = $module;
+ }
+
+ public function handleCheckoutPaymentCallbackResult(Cart $cart, Customer $customer, $checkoutToken): void
+ {
+ if (!$this->checkIfContextIsValid($cart, $customer)) {
+ throw new Exception("Context is not valid!");
+ }
+
+ $craftgatePayment = $this->retrieveCraftgatePayment($checkoutToken);
+ if ($craftgatePayment) {
+ $this->redirectOrderConfirmationPage($craftgatePayment, $customer);
+ exit();
+ }
+
+ $checkoutFormResult = self::craftgateClient()->retrieveCheckoutFormResult($checkoutToken);
+ $checkoutFormResult->checkoutToken = $checkoutToken;
+
+ if (!isset($checkoutFormResult->conversationId) || $checkoutFormResult->conversationId != $cart->id) {
+ PrestaShopLogger::addLog("Conversation ID is not matched cart id " . $cart->id . $checkoutFormResult->conversationId);
+ throw new Exception("Unknown error occurred!");
+ }
+
+ if (!isset($checkoutFormResult->paymentError) && $checkoutFormResult->paymentStatus === 'SUCCESS') {
+ $this->createOrder($cart, $customer, $checkoutFormResult);
+ } else {
+ throw new CraftgatePaymentErrorException($checkoutFormResult->paymentError->errorDescription);
+ }
+ }
+
+ public function handleCheckoutPaymentWebhookResult($checkoutToken): void
+ {
+ if ($this->retrieveCraftgatePayment($checkoutToken))
+ return;
+
+
+ $checkoutFormResult = self::craftgateClient()->retrieveCheckoutFormResult($checkoutToken);
+ $checkoutFormResult->checkoutToken = $checkoutToken;
+
+ $cartId = $checkoutFormResult->conversationId;
+ $cart = new Cart($cartId);
+ $customer = new Customer($cart->id_customer);
+
+ if ($this->checkIfContextIsValid($cart, $customer) && !isset($checkoutFormResult->paymentError) && $checkoutFormResult->paymentStatus === 'SUCCESS') {
+ $this->createOrder($cart, $customer, $checkoutFormResult);
+ }
+ }
+
+ private function createOrder(Cart $cart, Customer $customer, $checkoutFormResult): void
+ {
+ Context::getContext()->cookie->__unset(self::INSTALLMENT_FEE_COOKIE_NAME);
+ Context::getContext()->cookie->write();
+
+ if ($checkoutFormResult->installment > 1) {
+ Context::getContext()->cookie->__set(self::INSTALLMENT_FEE_COOKIE_NAME, $checkoutFormResult->paidPrice - $checkoutFormResult->price);
+ Context::getContext()->cookie->write();
+ }
+
+ $this->module->validateOrder(
+ (int)$cart->id,
+ (int)Configuration::get('PS_OS_PAYMENT'),
+ (float)$checkoutFormResult->price,
+ $this->module->displayName,
+ null,
+ ['transaction_id' => $checkoutFormResult->id],
+ null,
+ false,
+ $customer->secure_key,
+ );
+
+ $orderCore = Order::getByCartId($cart->id);
+ $craftgatePayment = new CraftgatePayment();
+ $craftgatePayment->setPaymentId($checkoutFormResult->id);
+ $craftgatePayment->setCheckoutToken($checkoutFormResult->checkoutToken);
+ $craftgatePayment->setIdOrder($orderCore->id);
+ $craftgatePayment->setMetaData([
+ 'paidPrice' => $checkoutFormResult->paidPrice,
+ 'installment' => $checkoutFormResult->installment,
+ 'installmentFee' => $checkoutFormResult->paidPrice - $checkoutFormResult->price,
+ 'orderId' => $checkoutFormResult->orderId,
+ 'environment' => Configuration::get(Craftgate_Payment_Orchestration::CONFIG_IS_SANDBOX_ACTIVE) ? "Sandbox" : "Production"
+ ]);
+
+ $craftgatePayment->save();
+
+ }
+
+ public function addInstallmentFee(Order $order): void
+ {
+ $installmentFee = Context::getContext()->cookie->__get(self::INSTALLMENT_FEE_COOKIE_NAME);
+ if (!$installmentFee) {
+ return;
+ }
+
+ Context::getContext()->cookie->__unset(self::INSTALLMENT_FEE_COOKIE_NAME);
+ Context::getContext()->cookie->write();
+
+ $installmentFee = (float)$installmentFee;
+
+ $orderDetail = new OrderDetail();
+ $orderDetail->id_order = $order->id;
+ $orderDetail->product_name = $this->module->l('Installment Fee');
+ $orderDetail->product_quantity = 1;
+ $orderDetail->product_price = $installmentFee;
+ $orderDetail->unit_price_tax_excl = $installmentFee;
+ $orderDetail->unit_price_tax_incl = $installmentFee;
+ $orderDetail->total_price_tax_incl = $installmentFee;
+ $orderDetail->total_price_tax_excl = $installmentFee;
+ $orderDetail->id_warehouse = 0;
+ $orderDetail->id_shop = $order->id_shop;
+ $orderDetail->add();
+
+ $orderPayment = $order->getOrderPayments()[0];
+ $orderPayment->amount += $installmentFee;
+ $orderPayment->save();
+
+ $order->total_paid_real += $installmentFee;
+ $order->total_paid += $installmentFee;
+ $order->total_paid_tax_incl += $installmentFee;
+ $order->total_paid_tax_excl += $installmentFee;
+ $order->update();
+ }
+
+ private function retrieveCraftgatePayment($checkoutToken): false|CraftgatePayment
+ {
+ return CraftgatePayment::getByCheckoutToken($checkoutToken);
+ }
+
+ private function checkIfContextIsValid($cart, $customer): bool
+ {
+ return true === Validate::isLoadedObject($cart)
+ && true === Validate::isLoadedObject($customer);
+ }
+
+ public static function craftgateClient(): CraftgateClient
+ {
+ $isSandboxActive = Configuration::get(Craftgate_Payment_Orchestration::CONFIG_IS_SANDBOX_ACTIVE);
+ if ($isSandboxActive) {
+ $apiKey = Configuration::get(Craftgate_Payment_Orchestration::CONFIG_SANDBOX_API_KEY);
+ $secretKey = Configuration::get(Craftgate_Payment_Orchestration::CONFIG_SANDBOX_SECRET_KEY);
+ return CraftgateClient::getInstance($apiKey, $secretKey, "https://sandbox-api.craftgate.io");
+ }
+
+ $apiKey = Configuration::get(Craftgate_Payment_Orchestration::CONFIG_LIVE_API_KEY);
+ $secretKey = Configuration::get(Craftgate_Payment_Orchestration::CONFIG_LIVE_SECRET_KEY);
+ return CraftgateClient::getInstance($apiKey, $secretKey, "https://api.craftgate.io");
+ }
+
+
+ public function redirectOrderConfirmationPage(CraftgatePayment $craftgatePayment, Customer $customer): void
+ {
+ $id_order = $craftgatePayment->getIdOrder();
+ $order = new Order($id_order);
+ $link = new Link();
+ $redirect_url = $link->getPageLink('order-confirmation', true, null, [
+ 'id_cart' => $order->id_cart,
+ 'id_module' => $this->module->id,
+ 'id_order' => $id_order,
+ 'key' => $customer->secure_key,
+ ]);
+ Tools::redirect($redirect_url);
+ }
+}
\ No newline at end of file
diff --git a/classes/CraftgateUtil.php b/classes/CraftgateUtil.php
new file mode 100644
index 0000000..43e0894
--- /dev/null
+++ b/classes/CraftgateUtil.php
@@ -0,0 +1,11 @@
+
+
+ craftgate_payment_orchestration
+
+
+
+
+
+ 1
+ 1
+
\ No newline at end of file
diff --git a/controllers/admin/AdminConfigureCraftgatePaymentOrchestrationController.php b/controllers/admin/AdminConfigureCraftgatePaymentOrchestrationController.php
new file mode 100755
index 0000000..f8286e8
--- /dev/null
+++ b/controllers/admin/AdminConfigureCraftgatePaymentOrchestrationController.php
@@ -0,0 +1,64 @@
+page_header_toolbar_title = 'Craftgate Payment Orchestration Module';
+ $this->bootstrap = true;
+ $this->className = 'Configuration';
+ $this->table = 'configuration';
+ parent::__construct();
+ }
+
+ public function renderForm()
+ {
+ $this->context->smarty->assign([
+ 'CRAFTGATE_MODULE_ENABLED' => Configuration::get(Craftgate_Payment_Orchestration::CONFIG_IS_MODULE_ENABLED),
+ 'CRAFTGATE_PAYMENT_OPTION_TITLE' => Configuration::get(Craftgate_Payment_Orchestration::CONFIG_PAYMENT_OPTION_TITLE),
+ 'CRAFTGATE_PAYMENT_OPTION_DESCRIPTION' => Configuration::get(Craftgate_Payment_Orchestration::CONFIG_PAYMENT_OPTION_DESCRIPTION),
+ 'CRAFTGATE_LIVE_API_KEY' => Configuration::get(Craftgate_Payment_Orchestration::CONFIG_LIVE_API_KEY),
+ 'CRAFTGATE_LIVE_SECRET_KEY' => Configuration::get(Craftgate_Payment_Orchestration::CONFIG_LIVE_SECRET_KEY),
+ 'CRAFTGATE_SANDBOX_API_KEY' => Configuration::get(Craftgate_Payment_Orchestration::CONFIG_SANDBOX_API_KEY),
+ 'CRAFTGATE_SANDBOX_SECRET_KEY' => Configuration::get(Craftgate_Payment_Orchestration::CONFIG_SANDBOX_SECRET_KEY),
+ 'CRAFTGATE_IS_SANDBOX_ACTIVE' => Configuration::get(Craftgate_Payment_Orchestration::CONFIG_IS_SANDBOX_ACTIVE),
+ 'CRAFTGATE_IFRAME_OPTIONS' => Configuration::get(Craftgate_Payment_Orchestration::CONFIG_IFRAME_OPTIONS),
+ 'CRAFTGATE_WEBHOOK_URL' => Configuration::get(Craftgate_Payment_Orchestration::CONFIG_WEBHOOK_URL),
+ 'CRAFTGATE_IS_ONE_PAGE_CHECKOUT_ACTIVE' => Configuration::get(Craftgate_Payment_Orchestration::CONFIG_IS_ONE_PAGE_CHECKOUT_ACTIVE),
+ ]);
+
+ return $this->context->smarty->fetch($this->getTemplatePath() . 'configure.tpl');
+ }
+
+ public function postProcess()
+ {
+ if (Tools::isSubmit('submitCraftgateModuleConfiguration')) {
+ Configuration::updateValue(Craftgate_Payment_Orchestration::CONFIG_IS_MODULE_ENABLED, Tools::getValue('CRAFTGATE_MODULE_ENABLED'));
+ Configuration::updateValue(Craftgate_Payment_Orchestration::CONFIG_PAYMENT_OPTION_TITLE, Tools::getValue('CRAFTGATE_PAYMENT_OPTION_TITLE'));
+ Configuration::updateValue(Craftgate_Payment_Orchestration::CONFIG_PAYMENT_OPTION_DESCRIPTION, Tools::getValue('CRAFTGATE_PAYMENT_OPTION_DESCRIPTION'));
+ Configuration::updateValue(Craftgate_Payment_Orchestration::CONFIG_IS_ONE_PAGE_CHECKOUT_ACTIVE, Tools::getValue('CRAFTGATE_IS_ONE_PAGE_CHECKOUT_ACTIVE'));
+ Configuration::updateValue(Craftgate_Payment_Orchestration::CONFIG_LIVE_API_KEY, Tools::getValue('CRAFTGATE_LIVE_API_KEY'));
+ Configuration::updateValue(Craftgate_Payment_Orchestration::CONFIG_LIVE_SECRET_KEY, Tools::getValue('CRAFTGATE_LIVE_SECRET_KEY'));
+ Configuration::updateValue(Craftgate_Payment_Orchestration::CONFIG_SANDBOX_API_KEY, Tools::getValue('CRAFTGATE_SANDBOX_API_KEY'));
+ Configuration::updateValue(Craftgate_Payment_Orchestration::CONFIG_SANDBOX_SECRET_KEY, Tools::getValue('CRAFTGATE_SANDBOX_SECRET_KEY'));
+ Configuration::updateValue(Craftgate_Payment_Orchestration::CONFIG_IS_SANDBOX_ACTIVE, Tools::getValue('CRAFTGATE_IS_SANDBOX_ACTIVE'));
+ Configuration::updateValue(Craftgate_Payment_Orchestration::CONFIG_IFRAME_OPTIONS, Tools::getValue('CRAFTGATE_IFRAME_OPTIONS'));
+
+ $this->confirmations[] = $this->l('Settings updated successfully.');
+ }
+
+ return parent::postProcess();
+ }
+
+ public function initContent()
+ {
+ parent::initContent();
+ $this->content .= $this->renderForm();
+ $this->context->smarty->assign('content', $this->content);
+ }
+
+ public function getTemplatePath()
+ {
+ return _PS_MODULE_DIR_ . $this->module->name . '/views/templates/admin/';
+ }
+}
diff --git a/controllers/admin/index.php b/controllers/admin/index.php
new file mode 100755
index 0000000..3b58b73
--- /dev/null
+++ b/controllers/admin/index.php
@@ -0,0 +1,10 @@
+context->cart->id_customer);
+ if (false === $this->checkIfContextIsValid() || false === $this->checkIfPaymentOptionIsAvailable() || false === Validate::isLoadedObject($customer)) {
+ $this->redirectToCheckoutPage();
+ }
+ }
+
+ public function initContent(): void
+ {
+ parent::initContent();
+ if (Tools::isSubmit("isOnePageCheckout")) {
+ $this->handleOnePageCheckout();
+ } else {
+ $this->handleCheckout();
+ }
+ }
+
+ public function handleOnePageCheckout(): void
+ {
+ header('Content-Type: application/json');
+ try {
+ $checkoutFormUrl = $this->initCheckoutForm();
+ $language = $this->context->language->iso_code;
+ $iframeOptions = Configuration::get(Craftgate_Payment_Orchestration::CONFIG_IFRAME_OPTIONS);
+ $response = ["checkoutFormUrl" => $checkoutFormUrl . "&iframe=true&lang=" . $language . "&" . $iframeOptions . "&hideSubmitButton=true"];
+ http_response_code(201);
+ exit(json_encode($response));
+ } catch (Exception $exception) {
+ http_response_code(422);
+ $response = ["errorMessage" => $this->module->l("We're currently unable to process this payment option. Please choose another method or try again later.")];
+ PrestaShopLogger::addLog("Error occurred while initializing checkout form. Error: " . $exception->getMessage(), 3);
+ exit(json_encode($response));
+ }
+ }
+
+ public function handleCheckout(): void
+ {
+ try {
+ $checkoutFormUrl = $this->initCheckoutForm();
+
+ $language = $this->context->language->iso_code;
+ $iframeOptions = Configuration::get(Craftgate_Payment_Orchestration::CONFIG_IFRAME_OPTIONS);
+
+ $this->context->smarty->assign([
+ 'checkoutFormUrl' => $checkoutFormUrl . "&iframe=true&lang=" . $language . "&" . $iframeOptions
+ ]);
+ } catch (Exception $exception) {
+ PrestaShopLogger::addLog("Error occurred while initializing checkout form. Error: " . $exception->getMessage(), 3);
+ $this->context->smarty->assign([
+ 'error' => $this->module->l("We're currently unable to process this payment option. Please choose another method or try again later.")
+ ]);
+ }
+
+ $this->setTemplate('module:' . $this->module->name . '/views/templates/front/checkoutForm.tpl');
+ }
+
+ private function initCheckoutForm()
+ {
+ $request = $this->buildInitCheckoutFormRequest();
+ $response = CraftgatePaymentService::craftgateClient()->initCheckoutForm($request);
+
+ if (isset($response->pageUrl)) {
+ return $response->pageUrl;
+ } elseif (isset($response->errors)) {
+ throw new Exception($response->errors->errorDescription, $response->errors->errorCode);
+ }
+ }
+
+ private function buildInitCheckoutFormRequest(): array
+ {
+ $cartId = $this->context->cart->id;
+ $orderTotal = $this->context->cart->getOrderTotal();
+
+ return [
+ 'price' => CraftgateUtil::format_price($orderTotal),
+ 'paidPrice' => CraftgateUtil::format_price($orderTotal),
+ 'currency' => $this->context->currency->iso_code,
+ 'paymentGroup' => \Craftgate\Model\PaymentGroup::LISTING_OR_SUBSCRIPTION,
+ 'conversationId' => $cartId,
+ 'callbackUrl' => $this->context->link->getModuleLink($this->module->name, 'checkoutFormCallbackHandler', ['cartId' => $cartId], true),
+ 'items' => $this->buildItems($this->context->cart)
+ ];
+ }
+
+ private function buildItems($cart)
+ {
+ $cart_products = $cart->getProducts();
+ $items = [];
+
+ if ($cart_products) {
+ foreach ($cart_products as $product) {
+ $items[] = [
+ 'externalId' => $product['id_product'],
+ 'name' => $product['name'],
+ 'price' => CraftgateUtil::format_price($product['total_wt']),
+ ];
+ }
+ }
+
+ $shipping_cost = (float)$cart->getOrderTotal(true, Cart::ONLY_SHIPPING);
+ if ($shipping_cost > 0) {
+ $items[] = [
+ 'externalId' => 'shipping-total',
+ 'name' => 'Shipping Total',
+ 'price' => CraftgateUtil::format_price($shipping_cost),
+ ];
+ }
+
+ return $items;
+ }
+
+ private function checkIfContextIsValid()
+ {
+ return true === Validate::isLoadedObject($this->context->cart)
+ && true === Validate::isUnsignedInt($this->context->cart->id_customer)
+ && true === Validate::isUnsignedInt($this->context->cart->id_address_delivery)
+ && true === Validate::isUnsignedInt($this->context->cart->id_address_invoice);
+ }
+
+
+ private function checkIfPaymentOptionIsAvailable(): bool
+ {
+ if (!Configuration::get(Craftgate_Payment_Orchestration::CONFIG_IS_MODULE_ENABLED)) {
+ return false;
+ }
+
+ $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;
+ }
+
+ public function redirectToCheckoutPage(): void
+ {
+ Tools::redirect($this->context->link->getPageLink('order', true, $this->context->language->id, ['step' => 1]));
+ }
+}
diff --git a/controllers/front/checkoutFormCallbackHandler.php b/controllers/front/checkoutFormCallbackHandler.php
new file mode 100755
index 0000000..afbb8b0
--- /dev/null
+++ b/controllers/front/checkoutFormCallbackHandler.php
@@ -0,0 +1,80 @@
+auth = false;
+ $this->craftgatePaymentService = new CraftgatePaymentService($this->module);
+ }
+
+ public function postProcess(): void
+ {
+ $checkoutToken = Tools::getValue("token");
+
+ if (!$checkoutToken) {
+ Tools::displayError("Error occurred");
+ exit();
+ }
+
+ if (Tools::getValue('source') != 'prestashop') {
+ $this->context->smarty->assign([
+ "checkoutToken" => $checkoutToken,
+ "cartId" => Tools::getValue("cartId")
+ ]);
+
+ $this->setTemplate('module:' . $this->module->name . '/views/templates/front/checkoutFormCallback.tpl');
+ } else {
+ $this->handleResult($checkoutToken);
+ }
+ }
+
+ public function handleResult(mixed $checkoutToken): void
+ {
+ $cartId = Tools::getValue("cartId");
+ $cart = new Cart($cartId);
+ $customer = new Customer($cart->id_customer);
+
+ try {
+ $this->craftgatePaymentService->handleCheckoutPaymentCallbackResult($cart, $customer, $checkoutToken);
+ } catch (CraftgatePaymentErrorException $e) {
+ PrestaShopLogger::addLog("Payment error occurred while creating order for cart $cartId" . $e->getMessage(), 2);
+ $this->redirectOrderCheckout($e->getMessage());
+ } catch (Exception $e) {
+ PrestaShopLogger::addLog("Unknown error occurred while creating order" . serialize($e), 3);
+ $this->redirectOrderCheckout();
+ }
+
+ $orderConfirmationPageLink = $this->buildOrderConfirmationLink($cart, $customer);
+ Tools::redirect($orderConfirmationPageLink);
+ }
+
+ public function redirectOrderCheckout($message = null): void
+ {
+ $redirectUrl = $this->context->link->getPageLink('order', true, $this->context->language->id, ['step' => 1]);
+ if (!isset($message)) {
+ Tools::redirect($redirectUrl);
+ } else {
+ $this->context->controller->errors[] = $message;
+ $this->context->controller->redirectWithNotifications($redirectUrl);
+ }
+ }
+
+ public function buildOrderConfirmationLink(Cart $cart, Customer $customer): string
+ {
+ return $this->context->link->getPageLink('order-confirmation', true, $this->context->language->id,
+ [
+ 'id_cart' => (int)$cart->id,
+ 'id_module' => (int)$this->module->id,
+ 'id_order' => (int)$this->module->currentOrder,
+ 'key' => $customer->secure_key,
+ ]
+ );
+ }
+}
diff --git a/controllers/front/checkoutFormWebhookHandler.php b/controllers/front/checkoutFormWebhookHandler.php
new file mode 100644
index 0000000..1d5997c
--- /dev/null
+++ b/controllers/front/checkoutFormWebhookHandler.php
@@ -0,0 +1,48 @@
+auth = false;
+ $this->craftgatePaymentService = new CraftgatePaymentService($this->module);
+ }
+
+ public function postProcess(): void
+ {
+ $webhook_data = json_decode(file_get_contents('php://input'), true);
+ if (!isset($webhook_data) || !$this->shouldProcessWebhookRequest($webhook_data)) {
+ exit();
+ }
+
+ try {
+ $this->craftgatePaymentService->handleCheckoutPaymentWebhookResult($webhook_data["payloadId"]);
+ exit();
+ } catch (Exception $e) {
+ Tools::displayError($e);
+ PrestaShopLogger::addLog("Unexpected error occurred while creating order" . serialize($e));
+ }
+ }
+
+ private function shouldProcessWebhookRequest($webhook_data): bool
+ {
+ if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
+ return false;
+ }
+
+ $event_type = $webhook_data['eventType'];
+ $status = $webhook_data['status'];
+ $checkout_token = $webhook_data['payloadId'];
+
+ if ($event_type !== 'CHECKOUTFORM_AUTH' || $status !== "SUCCESS" || !isset($checkout_token)) {
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/controllers/front/index.php b/controllers/front/index.php
new file mode 100755
index 0000000..3b58b73
--- /dev/null
+++ b/controllers/front/index.php
@@ -0,0 +1,10 @@
+name = 'craftgate_payment_orchestration';
+ $this->tab = 'payments_gateways';
+ $this->version = '1.0.0';
+ $this->author = 'Craftgate';
+ $this->currencies = true;
+ $this->currencies_mode = 'checkbox';
+ $this->ps_versions_compliancy = [
+ 'min' => '1.7',
+ 'max' => _PS_VERSION_,
+ ];
+
+ $this->controllers = [
+ 'cancel',
+ 'external',
+ 'validation',
+ ];
+
+ parent::__construct();
+
+ $this->displayName = $this->l('Craftgate Payment Orchestration');
+ $this->description = $this->l("Simple, Flexible, Accessible 'One-Stop Shop' Payment Orchestration");
+ $this->craftgatePaymentService = new CraftgatePaymentService($this);
+ }
+
+ public function install(): bool
+ {
+ return parent::install()
+ && CraftgatePaymentDBManager::install()
+ && $this->registerHook(static::HOOKS)
+ && $this->updateDefaultConfigurations();
+ }
+
+ public function uninstall(): bool
+ {
+ return parent::uninstall()
+ && Configuration::deleteByName(static::CONFIG_IS_MODULE_ENABLED);
+ }
+
+ public function getContent(): void
+ {
+ Tools::redirectAdmin($this->context->link->getAdminLink(static::MODULE_ADMIN_CONTROLLER));
+ }
+
+ public function hookActionValidateOrder($params)
+ {
+ $order = $params['order'];
+ $this->craftgatePaymentService->addInstallmentFee($order);
+ }
+
+ public function hookPaymentOptions(array $params): array
+ {
+ $cart = $params['cart'];
+
+ if (false === Validate::isLoadedObject($cart) || false === $this->isCurrencySupported($cart)) {
+ return [];
+ }
+
+ $paymentOptions = [];
+
+ if (Configuration::get(static::CONFIG_IS_MODULE_ENABLED)) {
+ $paymentOptions[] = Configuration::get(static::CONFIG_IS_ONE_PAGE_CHECKOUT_ACTIVE)
+ ? $this->getCraftgateOnePageCheckoutFormPaymentOption()
+ : $this->getCraftgateCheckoutFormPaymentOption();
+ }
+
+ return $paymentOptions;
+ }
+
+ public function hookDisplayHeader()
+ {
+ $this->context->controller->addCSS('modules/' . $this->name . '/views/css/style.css');
+ }
+
+ public function hookDisplayPaymentByBinaries(array $params)
+ {
+
+ $cart = $params['cart'];
+
+ if (false === Validate::isLoadedObject($cart) || false === $this->isCurrencySupported($cart) || false === Configuration::get(static::CONFIG_IS_ONE_PAGE_CHECKOUT_ACTIVE)) {
+ return '';
+ }
+
+ return $this->context->smarty->fetch('module:craftgate_payment_orchestration/views/templates/hook/embeddedCheckoutFormBinary.tpl');
+ }
+
+ public function hookDisplayAdminOrderLeft(array $params): string
+ {
+ return $this->hookDisplayAdminOrderMainBottom($params);
+ }
+
+
+ public function hookDisplayAdminOrderMainBottom(array $params): string
+ {
+ if (empty($params['id_order'])) {
+ return '';
+ }
+
+ $orderId = $params['id_order'];
+ $order = new Order((int)$orderId);
+ if (false === Validate::isLoadedObject($order) || $order->module !== $this->name) {
+ return '';
+ }
+
+ $craftgatePayment = CraftgatePayment::getByOrderId($orderId);
+
+ $this->context->smarty->assign([
+ 'currency' => $order->id_currency,
+ 'craftgatePayment' => $craftgatePayment,
+ 'moduleName' => $this->name,
+ 'moduleDisplayName' => $this->displayName,
+ 'moduleLogoSrc' => $this->getPathUri() . 'logo.png',
+ ]);
+
+ return $this->context->smarty->fetch('module:craftgate_payment_orchestration/views/templates/hook/displayAdminOrderMainBottom.tpl');
+ }
+
+
+ private function isCurrencySupported(Cart $cart): bool
+ {
+ $cartCurrency = new Currency($cart->id_currency);
+ $moduleCurrencies = $this->getCurrency($cart->id_currency);
+
+ if (empty($moduleCurrencies)) {
+ return false;
+ }
+
+ foreach ($moduleCurrencies as $currency_module) {
+ if ($cartCurrency->id == $currency_module['id_currency']) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private function getCraftgateCheckoutFormPaymentOption(): PaymentOption
+ {
+ $paymentOption = new PaymentOption();
+ $paymentOption->setModuleName($this->name);
+ $paymentOptionTitle = !empty(Configuration::get(Craftgate_Payment_Orchestration::CONFIG_PAYMENT_OPTION_TITLE))
+ ? Configuration::get(Craftgate_Payment_Orchestration::CONFIG_PAYMENT_OPTION_TITLE)
+ : $this->l('Pay with Debit/Credit Card and Alternative Payment Methods');
+
+ $paymentOptionDescription = !empty(Configuration::get(Craftgate_Payment_Orchestration::CONFIG_PAYMENT_OPTION_DESCRIPTION))
+ ? Configuration::get(Craftgate_Payment_Orchestration::CONFIG_PAYMENT_OPTION_DESCRIPTION)
+ : $this->l('You can pay with Debit and Credit Card');
+
+ $paymentOption->setCallToActionText($paymentOptionTitle);
+ $paymentOption->setAction($this->context->link->getModuleLink($this->name, 'checkoutForm', [], true));
+
+ $this->context->smarty->clearCompiledTemplate('module:craftgate_payment_orchestration/views/templates/front/checkoutFormPaymentOption.tpl');
+ $this->context->smarty->assign([
+ "description" => $paymentOptionDescription
+ ]);
+ $paymentOption->setAdditionalInformation($this->context->smarty->fetch('module:craftgate_payment_orchestration/views/templates/front/checkoutFormPaymentOption.tpl', 1, 2));
+ return $paymentOption;
+ }
+
+ private function getCraftgateOnePageCheckoutFormPaymentOption(): PaymentOption
+ {
+ $paymentOption = new PaymentOption();
+ $paymentOption->setModuleName($this->name);
+ $paymentOptionTitle = !empty(Configuration::get(Craftgate_Payment_Orchestration::CONFIG_PAYMENT_OPTION_TITLE))
+ ? Configuration::get(Craftgate_Payment_Orchestration::CONFIG_PAYMENT_OPTION_TITLE)
+ : $this->l('Pay with Debit/Credit Card and Alternative Payment Methods');
+
+ $paymentOption->setCallToActionText($paymentOptionTitle);
+ $paymentOption->setAction($this->context->link->getModuleLink($this->name, 'checkoutForm', [], true));
+
+ $this->context->smarty->clearCompiledTemplate('module:craftgate_payment_orchestration/views/templates/front/onePageCheckoutFormPaymentOption.tpl');
+ $paymentOption->setBinary(true);
+ $paymentOption->setAdditionalInformation($this->context->smarty->fetch('module:craftgate_payment_orchestration/views/templates/front/onePageCheckoutFormPaymentOption.tpl', 1, 2));
+ return $paymentOption;
+ }
+
+ private function updateDefaultConfigurations(): bool
+ {
+ $webhookUrl = $this->context->link->getModuleLink($this->name, 'checkoutFormWebhookHandler', [], true);
+ return Configuration::updateGlobalValue(Craftgate_Payment_Orchestration::CONFIG_IS_ONE_PAGE_CHECKOUT_ACTIVE, true)
+ && Configuration::updateGlobalValue(Craftgate_Payment_Orchestration::CONFIG_WEBHOOK_URL, $webhookUrl);
+ }
+}
diff --git a/index.php b/index.php
new file mode 100755
index 0000000..61ffa71
--- /dev/null
+++ b/index.php
@@ -0,0 +1,10 @@
+options = $options;
+ }
+
+ protected function httpGet($path)
+ {
+ $url = $this->prepareUrl($path);
+ $headers = $this->prepareHeaders($path);
+
+ return Curl::get($url, $headers);
+ }
+
+ protected function httpPost($path, $request)
+ {
+ $url = $this->prepareUrl($path);
+ $headers = $this->prepareHeaders($path, $request);
+
+ return Curl::post($url, $headers, $request);
+ }
+
+ protected function httpPut($path, $request)
+ {
+ $url = $this->prepareUrl($path);
+ $headers = $this->prepareHeaders($path, $request);
+
+ return Curl::put($url, $headers, $request);
+ }
+
+ protected function httpDelete($path)
+ {
+ $url = $this->prepareUrl($path);
+ $headers = $this->prepareHeaders($path);
+
+ return Curl::delete($url, $headers);
+ }
+
+ private function prepareHeaders($path, $request = null)
+ {
+ $headers = array(
+ 'accept: application/json',
+ 'content-type: application/json'
+ );
+
+ if (isset($GLOBALS["cg-lang-header"])) {
+ $headers[] = 'lang: ' . $GLOBALS["cg-lang-header"];
+ }
+
+ $headers[] = 'x-api-key: ' . $this->options->getApiKey();
+ $headers[] = 'x-rnd-key: ' . ($randomString = Guid::generate());
+ $headers[] = 'x-auth-version: v1';
+ $headers[] = 'x-signature: ' . Signature::generate(
+ $this->options, $path, $randomString, $request
+ );
+
+ return $headers;
+ }
+
+ private function prepareUrl($path)
+ {
+ return $this->options->getBaseUrl() . '/' . trim($path, '/');
+ }
+}
diff --git a/lib/craftgate/src/Adapter/PaymentAdapter.php b/lib/craftgate/src/Adapter/PaymentAdapter.php
new file mode 100755
index 0000000..31dd331
--- /dev/null
+++ b/lib/craftgate/src/Adapter/PaymentAdapter.php
@@ -0,0 +1,18 @@
+httpPost($path, $request);
+ }
+
+ public function retrieveCheckoutPayment($token)
+ {
+ $path = "/payment/v1/checkout-payments/" . $token;
+ return $this->httpGet($path);
+ }
+}
diff --git a/lib/craftgate/src/Craftgate.php b/lib/craftgate/src/Craftgate.php
new file mode 100755
index 0000000..236bc10
--- /dev/null
+++ b/lib/craftgate/src/Craftgate.php
@@ -0,0 +1,43 @@
+setOptions($options);
+ }
+
+ public function setOptions($options)
+ {
+ if (is_array($options)) {
+ $options = new CraftgateOptions($options);
+ }
+
+ if (!$options instanceof CraftgateOptions) {
+ throw new \Exception(sprintf(
+ 'Argument $options must be either instance of %s or an array, %s given',
+ 'Craftgate\CraftgateOptions', gettype($options)
+ ));
+ }
+
+ $this->options = $options;
+
+ return $this;
+ }
+
+ public function getOptions()
+ {
+ return $this->options;
+ }
+
+ public function payment()
+ {
+ return new PaymentAdapter($this->options);
+ }
+}
diff --git a/lib/craftgate/src/CraftgateOptions.php b/lib/craftgate/src/CraftgateOptions.php
new file mode 100755
index 0000000..9796d04
--- /dev/null
+++ b/lib/craftgate/src/CraftgateOptions.php
@@ -0,0 +1,67 @@
+apiKey = $options['apiKey'];
+ isset($options['secretKey']) && $this->secretKey = $options['secretKey'];
+ isset($options['baseUrl']) && $this->baseUrl = $options['baseUrl'];
+ }
+ }
+
+ public function __debugInfo()
+ {
+ // Hides sensitive data (properties) while dump calls,
+ // so toArray() method should be called for debugging.
+ }
+
+ public function setApiKey($apiKey)
+ {
+ $this->apiKey = $apiKey;
+ }
+
+ public function getApiKey()
+ {
+ return $this->apiKey;
+ }
+
+ public function setSecretKey($secretKey)
+ {
+ $this->secretKey = $secretKey;
+ }
+
+ public function getSecretKey()
+ {
+ return $this->secretKey;
+ }
+
+ public function setBaseUrl($baseUrl)
+ {
+ $this->baseUrl = $baseUrl;
+ }
+
+ public function getBaseUrl()
+ {
+ return $this->baseUrl;
+ }
+
+ public function toArray()
+ {
+ return array(
+ 'apiKey' => $this->apiKey,
+ 'secretKey' => $this->secretKey,
+ 'baseUrl' => $this->baseUrl,
+ );
+ }
+}
diff --git a/lib/craftgate/src/Model/Currency.php b/lib/craftgate/src/Model/Currency.php
new file mode 100755
index 0000000..8316a14
--- /dev/null
+++ b/lib/craftgate/src/Model/Currency.php
@@ -0,0 +1,11 @@
+ 'GET',
+ CURLOPT_CONNECTTIMEOUT => self::CONNECT_TIMEOUT,
+ CURLOPT_TIMEOUT => self::READ_TIMEOUT,
+ CURLOPT_RETURNTRANSFER => true,
+ CURLOPT_HTTPHEADER => $headers,
+ ));
+ }
+
+ public static function post($url, array $headers, $content)
+ {
+ return self::request($url, array(
+ CURLOPT_CUSTOMREQUEST => 'POST',
+ CURLOPT_CONNECTTIMEOUT => self::CONNECT_TIMEOUT,
+ CURLOPT_TIMEOUT => self::READ_TIMEOUT,
+ CURLOPT_RETURNTRANSFER => true,
+ CURLOPT_HTTPHEADER => $headers,
+ CURLOPT_POSTFIELDS => json_encode($content),
+ ));
+ }
+
+ public static function put($url, array $headers, $content)
+ {
+ return self::request($url, array(
+ CURLOPT_CUSTOMREQUEST => 'PUT',
+ CURLOPT_CONNECTTIMEOUT => self::CONNECT_TIMEOUT,
+ CURLOPT_TIMEOUT => self::READ_TIMEOUT,
+ CURLOPT_RETURNTRANSFER => true,
+ CURLOPT_HTTPHEADER => $headers,
+ CURLOPT_POSTFIELDS => json_encode($content),
+ ));
+ }
+
+ public static function delete($url, array $headers)
+ {
+ return self::request($url, array(
+ CURLOPT_CUSTOMREQUEST => 'DELETE',
+ CURLOPT_CONNECTTIMEOUT => self::CONNECT_TIMEOUT,
+ CURLOPT_TIMEOUT => self::READ_TIMEOUT,
+ CURLOPT_RETURNTRANSFER => true,
+ CURLOPT_HTTPHEADER => $headers,
+ ));
+ }
+
+ private static function request($url, $options)
+ {
+ $request = curl_init($url);
+
+ curl_setopt_array($request, $options);
+
+ $response = curl_exec($request);
+
+ if ($response === false) {
+ throw new \Exception(curl_error($request), curl_errno($request));
+ }
+
+ curl_close($request);
+ unset($request); // PHP 8.0
+
+ return $response;
+ }
+}
diff --git a/lib/craftgate/src/Util/Guid.php b/lib/craftgate/src/Util/Guid.php
new file mode 100755
index 0000000..15f188b
--- /dev/null
+++ b/lib/craftgate/src/Util/Guid.php
@@ -0,0 +1,21 @@
+getBaseUrl() . urldecode($path)
+ . $options->getApiKey() . $options->getSecretKey()
+ . $randomString . ($request ? json_encode($request) : '');
+
+ return base64_encode(hash('sha256', $hash, true));
+ }
+}
diff --git a/logo.png b/logo.png
new file mode 100755
index 0000000..986abfd
Binary files /dev/null and b/logo.png differ
diff --git a/translations/en.php b/translations/en.php
new file mode 100644
index 0000000..e817c26
--- /dev/null
+++ b/translations/en.php
@@ -0,0 +1,39 @@
+craftgate_payment_orchestration_3275c30b6355fca65139ddd0778ac7ec'] = 'Craftgate Payment Orchestration';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>craftgate_payment_orchestration_e083809d29c251972afd5b382a87ef37'] = 'Pay with Debit/Credit Card and Alternative Payment Methods';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>craftgate_payment_orchestration_b2c6367d0ae462370977f8fade784fe6'] = 'You can pay with Debit and Credit Card';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_e566fe9aef1502d69ccdbe28e1957535'] = 'Enable/Disable';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_93cba07454f06a4a960172bbd6e2a435'] = 'Yes';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_bafd7322c6e97d25b6299b5d6fe8920b'] = 'No';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_4c3128be0910f49baecd0497f1ddfdf8'] = 'Enable or disable the Craftgate payment option on the checkout page.';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_0fc904bf3841ae6d54ced36050fde67e'] = 'One Page Checkout';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_c4ec25a4cde1fdd1b2a9e3edc43f3b77'] = 'Enable or disable one-page checkout for the Craftgate payment option.';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_b78a3223503896721cca1303f776159b'] = 'Title';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_78aef61495e242bb4477a033f4cd6b00'] = 'This is the title of the payment option shown to the customer during checkout. To use default, keep this field empty.';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_b5a7adde1af5c87d7fd797b6245c2a39'] = 'Description';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_c5d26bb5054d169f7122d3868e62857a'] = 'Provide a brief description for the payment option that will appear on the checkout page. To use default, keep this field empty.';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_3d855a86c289a1fea2ee9b992ed58e2f'] = 'Live API Key';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_0393670cb9bd296b3528935e44d0d90e'] = 'Enter the live API key provided by Craftgate.';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_df2223649d627882b90c2db3ec8d4f2b'] = 'Live Secret Key';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_af4e8396a3198cc824517152a2414ab8'] = 'Enter the live secret key provided by Craftgate.';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_0f069af40ceaacc090c657429bf1397a'] = 'Sandbox API Key';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_a17404634f898e154928b3835408c3c3'] = 'Enter the sandbox API key for testing.';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_8c9952079f4bd6acb39f6bdf0425aa38'] = 'Sandbox Secret Key';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_da8d9d678dbf7f2c6af42aea161c8dfd'] = 'Enter the sandbox secret key for testing.';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_8eaf9dd80ecfbd6de7c83cf3b707232b'] = 'Sandbox Mode';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_f5bc7ee15452cb2038d174084618ad78'] = 'Enable or disable sandbox mode for testing the integration.';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_0763bcfe13fb05503dada612e8990fe4'] = 'Iframe Options';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_9dc258f2243861d1cf2bea3629675138'] = 'Example: hideFooter=true&hideHeader=true';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_c9cc8cce247e49bae79f15173ce97354'] = 'Save';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>displayadminordermainbottom_1e63d1811556fc2dad106dcbd4217a69'] = 'Payment ID';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>displayadminordermainbottom_f8510606e25047908d1f3e4633145576'] = 'Craftgate Order ID';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>displayadminordermainbottom_f97a7b6286078d057df359177e532b72'] = 'Paid Price';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>displayadminordermainbottom_459f93c30d7bc374abe95e0d8a1c66b0'] = 'Installment';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>displayadminordermainbottom_ab05c71727b84389efacb94cfe65a299'] = 'Installment Fee';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>displayadminordermainbottom_eb8abdd76e82b300cba4096d4c120122'] = 'Payment Detail URL';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>embeddedcheckoutformbinary_a128f329c5aeea633ced6bb9d7c56c74'] = 'Place Order';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>adminconfigurecraftgatepaymentorchestrationcontroller_8dd2f915acf4ec98006d11c9a4b0945b'] = 'Settings updated successfully.';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>craftgatepaymentservice_ab05c71727b84389efacb94cfe65a299'] = 'Installment Fee';
diff --git a/translations/es.php b/translations/es.php
new file mode 100644
index 0000000..00dcf09
--- /dev/null
+++ b/translations/es.php
@@ -0,0 +1,41 @@
+craftgate_payment_orchestration_3275c30b6355fca65139ddd0778ac7ec'] = 'Orquestación de Pagos de Craftgate';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>craftgate_payment_orchestration_e083809d29c251972afd5b382a87ef37'] = 'Pague con Tarjeta de Débito/Crédito y Métodos de Pago Alternativos';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>craftgate_payment_orchestration_b2c6367d0ae462370977f8fade784fe6'] = 'Puede pagar con Tarjeta de Débito y Crédito';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_e566fe9aef1502d69ccdbe28e1957535'] = 'Activar/Desactivar';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_93cba07454f06a4a960172bbd6e2a435'] = 'Sí';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_bafd7322c6e97d25b6299b5d6fe8920b'] = 'No';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_4c3128be0910f49baecd0497f1ddfdf8'] = 'Activar o desactivar la opción de pago de Craftgate en la página de pago.';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_0fc904bf3841ae6d54ced36050fde67e'] = 'Pago en Una Página';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_c4ec25a4cde1fdd1b2a9e3edc43f3b77'] = 'Activar o desactivar el pago en una página para la opción de pago de Craftgate.';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_b78a3223503896721cca1303f776159b'] = 'Título';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_78aef61495e242bb4477a033f4cd6b00'] = 'Este es el título de la opción de pago mostrado al cliente durante el proceso de pago. Para usar el predeterminado, deje este campo vacío.';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_b5a7adde1af5c87d7fd797b6245c2a39'] = 'Descripción';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_c5d26bb5054d169f7122d3868e62857a'] = 'Proporcione una breve descripción para la opción de pago que aparecerá en la página de pago. Para usar el predeterminado, deje este campo vacío.';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_3d855a86c289a1fea2ee9b992ed58e2f'] = 'Clave API en Vivo';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_0393670cb9bd296b3528935e44d0d90e'] = 'Ingrese la clave API en vivo proporcionada por Craftgate.';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_df2223649d627882b90c2db3ec8d4f2b'] = 'Clave Secreta en Vivo';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_af4e8396a3198cc824517152a2414ab8'] = 'Ingrese la clave secreta en vivo proporcionada por Craftgate.';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_0f069af40ceaacc090c657429bf1397a'] = 'Clave API de Sandbox';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_a17404634f898e154928b3835408c3c3'] = 'Ingrese la clave API de sandbox para realizar pruebas.';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_8c9952079f4bd6acb39f6bdf0425aa38'] = 'Clave Secreta de Sandbox';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_da8d9d678dbf7f2c6af42aea161c8dfd'] = 'Ingrese la clave secreta de sandbox para realizar pruebas.';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_8eaf9dd80ecfbd6de7c83cf3b707232b'] = 'Modo Sandbox';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_f5bc7ee15452cb2038d174084618ad78'] = 'Activar o desactivar el modo sandbox para probar la integración.';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_0763bcfe13fb05503dada612e8990fe4'] = 'Opciones de Iframe';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_9dc258f2243861d1cf2bea3629675138'] = 'Ejemplo: hideFooter=true&hideHeader=true';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_c9cc8cce247e49bae79f15173ce97354'] = 'Guardar';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>displayadminordermainbottom_accea76d09b0193c332cf51c646a205c'] = 'Detalles del Pago';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>displayadminordermainbottom_1e63d1811556fc2dad106dcbd4217a69'] = 'ID del Pago';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>displayadminordermainbottom_f8510606e25047908d1f3e4633145576'] = 'ID del Pedido de Craftgate';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>displayadminordermainbottom_f97a7b6286078d057df359177e532b72'] = 'Importe del Pago';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>displayadminordermainbottom_459f93c30d7bc374abe95e0d8a1c66b0'] = 'Cuota';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>displayadminordermainbottom_ab05c71727b84389efacb94cfe65a299'] = 'Cuota de Cuota';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>displayadminordermainbottom_eb8abdd76e82b300cba4096d4c120122'] = 'URL de los Detalles del Pago';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>embeddedcheckoutformbinary_a128f329c5aeea633ced6bb9d7c56c74'] = 'Realizar Pedido';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>adminconfigurecraftgatepaymentorchestrationcontroller_edfe300ca312067edea71abb9770e302'] = 'Módulo de Orquestación de Pagos Craftgate';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>adminconfigurecraftgatepaymentorchestrationcontroller_8dd2f915acf4ec98006d11c9a4b0945b'] = 'Ajustes actualizados correctamente.';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>craftgatepaymentservice_ab05c71727b84389efacb94cfe65a299'] = 'Cuota de Cuota';
diff --git a/translations/tr.php b/translations/tr.php
new file mode 100644
index 0000000..6baa29d
--- /dev/null
+++ b/translations/tr.php
@@ -0,0 +1,40 @@
+craftgate_payment_orchestration_3275c30b6355fca65139ddd0778ac7ec'] = 'Craftgate Ödeme Orkestrasyonu';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>craftgate_payment_orchestration_e083809d29c251972afd5b382a87ef37'] = 'Kredi/Banka Kartı veya Alternatif Ödeme Yöntemleri ile Öde';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>craftgate_payment_orchestration_b2c6367d0ae462370977f8fade784fe6'] = 'Kredi/Banka Kartı ile ödeme yapabilirsiniz';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_e566fe9aef1502d69ccdbe28e1957535'] = 'Açık / Kapalı';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_93cba07454f06a4a960172bbd6e2a435'] = 'Evet';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_bafd7322c6e97d25b6299b5d6fe8920b'] = 'Hayır';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_4c3128be0910f49baecd0497f1ddfdf8'] = 'Craftgate ödeme seçeneğini açın veya kapatın';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_0fc904bf3841ae6d54ced36050fde67e'] = 'One Page Checkout';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_c4ec25a4cde1fdd1b2a9e3edc43f3b77'] = 'One Page Checkout özelliğini açın veya kapatın';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_b78a3223503896721cca1303f776159b'] = 'Başlık';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_78aef61495e242bb4477a033f4cd6b00'] = 'Ödeme seçeneğinin ödeme sırasında müşteriye gösterilen başlığıdır. Varsayılanı kullanmak için bu alanı boş bırakın.';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_b5a7adde1af5c87d7fd797b6245c2a39'] = 'Açıklama';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_c5d26bb5054d169f7122d3868e62857a'] = 'Ödeme sayfasında görünecek olan ödeme seçeneği için kısa bir açıklama girin. Varsayılanı kullanmak için bu alanı boş bırakın.';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_3d855a86c289a1fea2ee9b992ed58e2f'] = 'Canlı API Anahtarı';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_0393670cb9bd296b3528935e44d0d90e'] = 'Craftgate tarafından sağlanan canlı API anahtarını girin.';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_df2223649d627882b90c2db3ec8d4f2b'] = 'Canlı Gizli Anahtarı';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_af4e8396a3198cc824517152a2414ab8'] = 'Craftgate tarafından sağlanan canlı gizli anahtarı girin.';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_0f069af40ceaacc090c657429bf1397a'] = 'Sandbox API Anahtarı';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_a17404634f898e154928b3835408c3c3'] = 'Craftgate tarafından sağlanan sandbox API anahtarını girin.';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_8c9952079f4bd6acb39f6bdf0425aa38'] = 'Sandbox Gizli Anahtarı';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_da8d9d678dbf7f2c6af42aea161c8dfd'] = 'Test için sandbox gizli anahtarını girin.';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_8eaf9dd80ecfbd6de7c83cf3b707232b'] = 'Sandbox Mod';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_f5bc7ee15452cb2038d174084618ad78'] = 'Entegrasyonu test etmek için sandbox modunu etkinleştirin veya devre dışı bırakın.';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_0763bcfe13fb05503dada612e8990fe4'] = 'Iframe Seçenekleri';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_9dc258f2243861d1cf2bea3629675138'] = 'Örnek: hideFooter=true&hideHeader=true';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>configure_c9cc8cce247e49bae79f15173ce97354'] = 'Kaydet';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>displayadminordermainbottom_accea76d09b0193c332cf51c646a205c'] = 'Ödeme Detayları';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>displayadminordermainbottom_1e63d1811556fc2dad106dcbd4217a69'] = 'Ödeme ID';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>displayadminordermainbottom_f8510606e25047908d1f3e4633145576'] = 'Craftgate Sipariş Numarası';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>displayadminordermainbottom_f97a7b6286078d057df359177e532b72'] = 'Toplam Tahsil Edilen Tutar';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>displayadminordermainbottom_459f93c30d7bc374abe95e0d8a1c66b0'] = 'Taksit';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>displayadminordermainbottom_ab05c71727b84389efacb94cfe65a299'] = 'Taksit Vade Farkı';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>displayadminordermainbottom_eb8abdd76e82b300cba4096d4c120122'] = 'Ödeme Detay Sayfası';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>embeddedcheckoutformbinary_a128f329c5aeea633ced6bb9d7c56c74'] = 'Sipariş Oluştur';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>adminconfigurecraftgatepaymentorchestrationcontroller_8dd2f915acf4ec98006d11c9a4b0945b'] = 'Ayarlar başarılı bir şekilde güncellendi.';
+$_MODULE['<{craftgate_payment_orchestration}prestashop>craftgatepaymentservice_ab05c71727b84389efacb94cfe65a299'] = 'Taksit Vade Farkı ';
diff --git a/vendor/.htaccess b/vendor/.htaccess
new file mode 100755
index 0000000..3de9e40
--- /dev/null
+++ b/vendor/.htaccess
@@ -0,0 +1,10 @@
+# Apache 2.2
+
+ Order deny,allow
+ Deny from all
+
+
+# Apache 2.4
+
+ Require all denied
+
diff --git a/views/css/style.css b/views/css/style.css
new file mode 100755
index 0000000..ca282e5
--- /dev/null
+++ b/views/css/style.css
@@ -0,0 +1,89 @@
+#craftgate-checkout-form-iframe-container {
+ min-height: 858px;
+}
+
+#craftgate-checkout-form-iframe-container iframe {
+ border: 0;
+ width: 100%;
+ height: 100%;
+}
+
+#craftgate-one-page-checkout-form-iframe-container {
+ min-height: 640px;
+}
+
+#craftgate-one-page-checkout-form-iframe-container iframe {
+ border: 0;
+ width: 100%;
+ height: 100%;
+}
+
+.disabled-by-craftgate {
+ cursor: not-allowed;
+ opacity: .6;
+}
+
+.disabled-by-craftgate .btn {
+ cursor: not-allowed;
+ opacity: .65;
+}
+
+[type=reset],
+#loading-spinner {
+ text-align: center;
+}
+
+.display-none {
+ display: none;
+}
+
+.lds-facebook {
+ color: #333fdd;
+}
+
+.lds-facebook,
+.lds-facebook div {
+ box-sizing: border-box;
+}
+
+.lds-facebook {
+ display: inline-block;
+ position: relative;
+ width: 80px;
+ height: 80px;
+}
+
+.lds-facebook div {
+ display: inline-block;
+ position: absolute;
+ left: 8px;
+ width: 16px;
+ background: currentColor;
+ animation: lds-facebook 1.2s cubic-bezier(0, 0.5, 0.5, 1) infinite;
+}
+
+.lds-facebook div:nth-child(1) {
+ left: 8px;
+ animation-delay: -0.24s;
+}
+
+.lds-facebook div:nth-child(2) {
+ left: 32px;
+ animation-delay: -0.12s;
+}
+
+.lds-facebook div:nth-child(3) {
+ left: 56px;
+ animation-delay: 0s;
+}
+
+@keyframes lds-facebook {
+ 0% {
+ top: 8px;
+ height: 64px;
+ }
+ 50%, 100% {
+ top: 24px;
+ height: 32px;
+ }
+}
diff --git a/views/img/cards/amex.svg b/views/img/cards/amex.svg
new file mode 100644
index 0000000..3fef956
--- /dev/null
+++ b/views/img/cards/amex.svg
@@ -0,0 +1,113 @@
+
+
+
diff --git a/views/img/cards/maestro.svg b/views/img/cards/maestro.svg
new file mode 100644
index 0000000..316d396
--- /dev/null
+++ b/views/img/cards/maestro.svg
@@ -0,0 +1,33 @@
+
+
+
diff --git a/views/img/cards/mastercard.svg b/views/img/cards/mastercard.svg
new file mode 100644
index 0000000..623f1fb
--- /dev/null
+++ b/views/img/cards/mastercard.svg
@@ -0,0 +1,91 @@
+
+
diff --git a/views/img/cards/troy.svg b/views/img/cards/troy.svg
new file mode 100644
index 0000000..6fe84fb
--- /dev/null
+++ b/views/img/cards/troy.svg
@@ -0,0 +1,22 @@
+
+
+
diff --git a/views/img/cards/visa-electron.svg b/views/img/cards/visa-electron.svg
new file mode 100644
index 0000000..9f31f62
--- /dev/null
+++ b/views/img/cards/visa-electron.svg
@@ -0,0 +1,130 @@
+
+
diff --git a/views/img/cards/visa.svg b/views/img/cards/visa.svg
new file mode 100644
index 0000000..e521bf8
--- /dev/null
+++ b/views/img/cards/visa.svg
@@ -0,0 +1,23 @@
+
+
+
diff --git a/views/img/index.php b/views/img/index.php
new file mode 100755
index 0000000..ad177a4
--- /dev/null
+++ b/views/img/index.php
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
{l s='Enable or disable the Craftgate payment option on the checkout page.' mod='craftgate_payment_orchestration'}
+
+
+
+
+
+
+
+
+
+
+
+
{l s='Enable or disable one-page checkout for the Craftgate payment option.' mod='craftgate_payment_orchestration'}
+
+
+
+
+
+
{l s='This is the title of the payment option shown to the customer during checkout. To use default, keep this field empty.' mod='craftgate_payment_orchestration'}
+
+
+
+
+
+
{l s='Provide a brief description for the payment option that will appear on the checkout page. To use default, keep this field empty.' mod='craftgate_payment_orchestration'}
+
+
+
+
+
+
+
+
{l s='Enter the live API key provided by Craftgate.' mod='craftgate_payment_orchestration'}
+
+
+
+
+
+
{l s='Enter the live secret key provided by Craftgate.' mod='craftgate_payment_orchestration'}
+
+
+
+
+
+
+
+
{l s='Enter the sandbox API key for testing.' mod='craftgate_payment_orchestration'}
+
+
+
+
+
+
{l s='Enter the sandbox secret key for testing.' mod='craftgate_payment_orchestration'}
+
+
+
+
+
+
+
+
+
+
+
+
+
{l s='Enable or disable sandbox mode for testing the integration.' mod='craftgate_payment_orchestration'}
{l s='The URL that payment results will be sent to on the server-side. You should enter this webhook address to Craftgate Merchant Panel to get webhook request.' mod='craftgate_payment_orchestration'}
+
+ {/if}
+{/block}
+
+{block name="footer"}
+
+{/block}
\ No newline at end of file
diff --git a/views/templates/front/checkoutFormCallback.tpl b/views/templates/front/checkoutFormCallback.tpl
new file mode 100755
index 0000000..f1b475c
--- /dev/null
+++ b/views/templates/front/checkoutFormCallback.tpl
@@ -0,0 +1,77 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/views/templates/front/checkoutFormPaymentOption.tpl b/views/templates/front/checkoutFormPaymentOption.tpl
new file mode 100755
index 0000000..dca8674
--- /dev/null
+++ b/views/templates/front/checkoutFormPaymentOption.tpl
@@ -0,0 +1,39 @@
+
+
+