【问题标题】:How to perform an action just before submitting a payment in PrestaShop?如何在 PrestaShop 中提交付款之前执行操作?
【发布时间】:2019-06-18 16:57:33
【问题描述】:

我目前正在为 PrestaShop 1.6 开发欺诈检测模块。在这个模块中,我需要在客户按下按钮确认订单之后,但在提交付款之前调用一个 API,无论支付网关如何。

起初,在浏览了1.6中所有可用的钩子之后,我想到了使用actionValidateOrder钩子来做这件事,问题是这个钩子是在支付网关提交/处理付款后立即执行的,即不是我要找的。​​p>

我还考虑过使用 javascript 来拦截执行,然后调用验证控制器来执行,但是对于每个网关来说它变得过于具体,并且 prestashop 对象/ajax/javascript 之间的数据流似乎可以变成有问题。

我知道你可以创建自定义挂钩,但我在互联网上看到的每个示例都是关于显示挂钩的,没有一个显示如何创建自定义操作挂钩。

这就是我在 actionValidateOrder 挂钩中使用的内容

public function hookActionValidateOrder($params)
{
    include_once(_PS_MODULE_DIR_.'bayonet/sdk/Paymethods.php');

    $this->order = $params['order'];
    $cart = $this->context->cart;
    $address_delivery = new Address((int)$cart->id_address_delivery);
    $address_invoice = new Address((int)$cart->id_address_invoice);
    $state_delivery = new State((int)$address_delivery->id_state);
    $country_delivery = new Country((int)$address_delivery->id_country);
    $state_invoice = new State((int)$address_invoice->id_state);
    $country_invoice = new Country((int)$address_invoice->id_country);
    $customer = $this->context->customer;
    $currency = $this->context->currency;

    $products = $cart->getProducts();
    $product_list = array();

    foreach($products as $product)
    {
        $products_list[] = [
            "product_id" => $product['id_product'],
            "product_name" => $product['name'],
            "product_price" => $product['price'],
            "product_category" => $product['category']
        ];
    }

    $request = [
        'channel' => 'ecommerce',
        'consumer_name' => $customer->firstname.' '.$customer->lastname,
        "consumer_internal_id" => $customer->id,
        "transaction_amount" => $cart->getOrderTotal(),
        "currency_code" => $currency->iso_code,
        "telephone" => $address_invoice->phone,
        "email" => $customer->email,
        "payment_gateway" => $this->order->module,
        "shipping_address" => [
          "line_1" => $address_delivery->address1,
          "line_2" => $address_delivery->address2,
          "city" => $address_delivery->city,
          "state" => $state_delivery->name,
          "country" => convert_country_code($country_delivery->iso_code),
          "zip_code" => $address_delivery->postcode
        ],
        "billing_address" => [
          "line_1" => $address_invoice->address1,
          "line_2" => $address_invoice->address2,
          "city" => $address_invoice->city,
          "state" => $state_invoice->name,
          "country" => convert_country_code($country_invoice->iso_code),
          "zip_code" => $address_invoice->postcode
        ],
        "products" => $products_list,
        "order_id" => (int)$this->order->id
    ];

    foreach ($paymentMethods as $key => $value) {
        if ($this->order->module == $key)
        {
            $request['payment_method'] = $value;
            if ($this->order->module == 'paypalmx')
                $request['payment_gateway'] = 'paypal';  
        }
    }

    if (Configuration::get('BAYONET_API_MODE') == 0)
    {
        $this->bayonet = new BayonetClient([
                'api_key' => Configuration::get('BAYONET_API_TEST_KEY'),
                'version' => Configuration::get('BAYONET_API_VERSION')
            ]);
    }
    else if (Configuration::get('BAYONET_API_MODE') == 1)
    {
        $this->bayonet = new BayonetClient([
                'api_key' => Configuration::get('BAYONET_API_LIVE_KEY_KEY'),
                'version' => Configuration::get('BAYONET_API_VERSION')
            ]);
    }

    $this->bayonet->consulting([
        'body' => $request,
        'on_success' => function($response) {
            $this->dataToInsert = array(
                'id_cart' => $this->context->cart->id,
                'order_no' => $this->order->id,
                'status' => $response->decision,
                'bayonet_tracking_id' => $response->bayonet_tracking_id,
                'consulting_api' => 1,
                'consulting_api_response' => json_encode(array(
                    'reason_code' => $response->reason_code,
                    'tracking_id' => $response->bayonet_tracking_id
                )),
                'is_executed' => 1,
            );

            Db::getInstance()->insert('bayonet', $this->dataToInsert);

            if ($response->decision == 'decline')
            {
                $this->module = Module::getInstanceByName('bayonet');
                Tools::redirect($this->context->link->getModuleLink($this->module->name,'rejected', array()));
            }
        },
        'on_failure' => function($response) {

            $this->dataToInsert = array(
                'id_cart' => $this->context->cart->id,
                'order_no' => $this->order->id,
                'status' => $response->decision,
                'bayonet_tracking_id' => $response->bayonet_tracking_id,
                'consulting_api' => 0,
                'consulting_api_response' => json_encode(array(
                    'reason_code' => $response->reason_code,
                )),
                'is_executed' => 1,
            );

            Db::getInstance()->insert('bayonet', $this->dataToInsert);
            }
    ]);
}

在检测到钩子的问题后,这是我用 JavaScript 尝试的,它使用 ajax 调用验证页面,该页面的代码与钩子中的代码几乎相同

$('#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;
                }
            }
        });
    }   
});

我仍然认为使用钩子是最好的选择,但在所有可用的钩子中,没有一个能满足我的需求。现在,我真的不知道还有什么可以尝试的,这就是为什么我需要你的帮助来解决这种情况,任何想法都是受欢迎的,我们将不胜感激。谢谢。

【问题讨论】:

    标签: php module prestashop payment


    【解决方案1】:

    您可以使用在创建订单付款之前执行的钩子

    public function hookActionObjectOrderPaymentAddBefore($params)
    {
        /** OrderPayment $orderPayment */
        $orderPayment = $params['object'];
        $cart = $this->context->cart;
    
        // to stop order payment creation you need to redirect from this hook 
    }
    

    或在创建订单之前

    public function hookActionObjectOrderAddBefore($params)
    {
        /** Order $order */
        $order = $params['object'];
        $cart = $this->context->cart;
    
        // to stop order creation you need to redirect from this hook 
    }
    

    【讨论】:

    • 我尝试使用这些钩子,问题是支付模块已经调用了支付验证。检查网关自己的仪表板,此时支付已经注册,这将导致数据库表冲突,并且某些网关的行为方式不同。我选择在订单创建后进行验证,我认为这样可以更好地保持订单流程完整。
    猜你喜欢
    • 1970-01-01
    • 2020-03-13
    • 2022-06-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-16
    • 2014-03-14
    • 1970-01-01
    相关资源
    最近更新 更多