title: How to perform an action just before submitting a payment in PrestaShop?
body: <p>I'm currently developing a fraud detection module for PrestaShop 1.6. In this module, I need to make a call to an API just after the customer presses the button to confirm their order, but before the payment is submitted, regardless of payment gateway.</p>
  
  <p>At first, after looking through all the available hooks in 1.6, I thought about using the actionValidateOrder hook to do this, the problem is that this hook is executed right after the payment is submitted/processed by the payment gateway, which is not what I'm looking for.</p>
  
  <p>I also thought about using javascript to intercept the execution and then calling to a validation controller to perform, but it becomes way too specific for each gateway and the data flow between prestashop objects/ajax/javascript seems like it could turn out to be problematic.</p>
  
  <p>I know you can create a custom hook, but every example I see on internet is about display hooks, none of it shows how to create a custom action hook.</p>
  
  <p>This is what I was using in the actionValidateOrder hook</p>
  
  <pre class="lang-php prettyprint-override"><code>public function hookActionValidateOrder($params)
  {
      include_once(_PS_MODULE_DIR_.'bayonet/sdk/Paymethods.php');
  
      $this-&gt;order = $params['order'];
      $cart = $this-&gt;context-&gt;cart;
      $address_delivery = new Address((int)$cart-&gt;id_address_delivery);
      $address_invoice = new Address((int)$cart-&gt;id_address_invoice);
      $state_delivery = new State((int)$address_delivery-&gt;id_state);
      $country_delivery = new Country((int)$address_delivery-&gt;id_country);
      $state_invoice = new State((int)$address_invoice-&gt;id_state);
      $country_invoice = new Country((int)$address_invoice-&gt;id_country);
      $customer = $this-&gt;context-&gt;customer;
      $currency = $this-&gt;context-&gt;currency;
  
      $products = $cart-&gt;getProducts();
      $product_list = array();
  
      foreach($products as $product)
      {
          $products_list[] = [
              "product_id" =&gt; $product['id_product'],
              "product_name" =&gt; $product['name'],
              "product_price" =&gt; $product['price'],
              "product_category" =&gt; $product['category']
          ];
      }
  
      $request = [
          'channel' =&gt; 'ecommerce',
          'consumer_name' =&gt; $customer-&gt;firstname.' '.$customer-&gt;lastname,
          "consumer_internal_id" =&gt; $customer-&gt;id,
          "transaction_amount" =&gt; $cart-&gt;getOrderTotal(),
          "currency_code" =&gt; $currency-&gt;iso_code,
          "telephone" =&gt; $address_invoice-&gt;phone,
          "email" =&gt; $customer-&gt;email,
          "payment_gateway" =&gt; $this-&gt;order-&gt;module,
          "shipping_address" =&gt; [
            "line_1" =&gt; $address_delivery-&gt;address1,
            "line_2" =&gt; $address_delivery-&gt;address2,
            "city" =&gt; $address_delivery-&gt;city,
            "state" =&gt; $state_delivery-&gt;name,
            "country" =&gt; convert_country_code($country_delivery-&gt;iso_code),
            "zip_code" =&gt; $address_delivery-&gt;postcode
          ],
          "billing_address" =&gt; [
            "line_1" =&gt; $address_invoice-&gt;address1,
            "line_2" =&gt; $address_invoice-&gt;address2,
            "city" =&gt; $address_invoice-&gt;city,
            "state" =&gt; $state_invoice-&gt;name,
            "country" =&gt; convert_country_code($country_invoice-&gt;iso_code),
            "zip_code" =&gt; $address_invoice-&gt;postcode
          ],
          "products" =&gt; $products_list,
          "order_id" =&gt; (int)$this-&gt;order-&gt;id
      ];
  
      foreach ($paymentMethods as $key =&gt; $value) {
          if ($this-&gt;order-&gt;module == $key)
          {
              $request['payment_method'] = $value;
              if ($this-&gt;order-&gt;module == 'paypalmx')
                  $request['payment_gateway'] = 'paypal';  
          }
      }
  
      if (Configuration::get('BAYONET_API_MODE') == 0)
      {
          $this-&gt;bayonet = new BayonetClient([
                  'api_key' =&gt; Configuration::get('BAYONET_API_TEST_KEY'),
                  'version' =&gt; Configuration::get('BAYONET_API_VERSION')
              ]);
      }
      else if (Configuration::get('BAYONET_API_MODE') == 1)
      {
          $this-&gt;bayonet = new BayonetClient([
                  'api_key' =&gt; Configuration::get('BAYONET_API_LIVE_KEY_KEY'),
                  'version' =&gt; Configuration::get('BAYONET_API_VERSION')
              ]);
      }
  
      $this-&gt;bayonet-&gt;consulting([
          'body' =&gt; $request,
          'on_success' =&gt; function($response) {
              $this-&gt;dataToInsert = array(
                  'id_cart' =&gt; $this-&gt;context-&gt;cart-&gt;id,
                  'order_no' =&gt; $this-&gt;order-&gt;id,
                  'status' =&gt; $response-&gt;decision,
                  'bayonet_tracking_id' =&gt; $response-&gt;bayonet_tracking_id,
                  'consulting_api' =&gt; 1,
                  'consulting_api_response' =&gt; json_encode(array(
                      'reason_code' =&gt; $response-&gt;reason_code,
                      'tracking_id' =&gt; $response-&gt;bayonet_tracking_id
                  )),
                  'is_executed' =&gt; 1,
              );
  
              Db::getInstance()-&gt;insert('bayonet', $this-&gt;dataToInsert);
  
              if ($response-&gt;decision == 'decline')
              {
                  $this-&gt;module = Module::getInstanceByName('bayonet');
                  Tools::redirect($this-&gt;context-&gt;link-&gt;getModuleLink($this-&gt;module-&gt;name,'rejected', array()));
              }
          },
          'on_failure' =&gt; function($response) {
  
              $this-&gt;dataToInsert = array(
                  'id_cart' =&gt; $this-&gt;context-&gt;cart-&gt;id,
                  'order_no' =&gt; $this-&gt;order-&gt;id,
                  'status' =&gt; $response-&gt;decision,
                  'bayonet_tracking_id' =&gt; $response-&gt;bayonet_tracking_id,
                  'consulting_api' =&gt; 0,
                  'consulting_api_response' =&gt; json_encode(array(
                      'reason_code' =&gt; $response-&gt;reason_code,
                  )),
                  'is_executed' =&gt; 1,
              );
  
              Db::getInstance()-&gt;insert('bayonet', $this-&gt;dataToInsert);
              }
      ]);
  }
  </code></pre>
  
  <p>And after detecting the issue with the hook, this is what I tried with JavaScript, which calls a validation page using ajax, this page has almost the same code as what it was in the hook</p>
  
  <pre><code>$('#form-pagar-mp').submit(function(event) {
      if (lock == 1) {
          params = {};
          $.ajax({
              url: url,
              type: 'post',
              data: params,
              dataType: 'json',
              processData: false,
              success: function(data) {
                  if (data.error == 0) {
                      lock = 0;
                  }
                  else {
                      window.location.href = data.url;
                  }
              }
          });
      }   
  });
  </code></pre>
  
  <p>I still think using a hook is the best option, but out of all available hooks, none of them meets my needs. Right now, I don't really know that else to try, that's why I need your help in how to approach this situation, any ideas are welcome and will be highly appreciated. Thank you.</p>