hikashop Error: 0 Call to a member function getName() on null

  • Posts: 3
  • Thank you received: 0
2 years 9 months ago #339171

Hi

I get the following error: hikashop Error: 0 Call to a member function getName() on null, when I attempt to create an order using the cart id like so:

$cartClass = hikashop_get('class.cart');
$orderClass = hikashop_get('class.order');

$cart = $cartClass->getFullCart();

$cart_id = $cart->cart_id;
$order = $orderClass->createFromCart($cart_id);

This is being done in a custom component.

Any help would be greatly appreciated.

Please Log in or Create an account to join the conversation.

  • Posts: 82863
  • Thank you received: 13372
  • MODERATOR
2 years 9 months ago #339172

Hi,

Hard do say like that.
Please activate the "debug system" setting of the Joomla configuration and try again.
It will display the error message with more information on where the error is happening.

Please Log in or Create an account to join the conversation.

  • Posts: 3
  • Thank you received: 0
2 years 9 months ago #339223

The debug option did not expand the error we recieve with the reponse.

To give you the full picture we are trying to create a stripe plugin, to confirm the payment request we send an AJAX call to a custom component which includes stripe and hikashop helpers. The stripe end of things successfully completes, but we then need to create and then confirm the order with hikashop.

However when trying to create an order from cart it falls over with the error, even thought getFullCart() and cart_id works.

/plugins/hikashoppayment/example/example.php: This sends the AJAX

<?php
/*
 * A payment plugin called "example". This is the main file of the plugin.
 */
defined('_JEXEC') or die('Restricted access');

require $_SERVER['DOCUMENT_ROOT'] . '/vendor/autoload.php';

// You need to extend from the hikashopPaymentPlugin class which already define lots of functions in order to simplify your work
class plgHikashoppaymentExample extends hikashopPaymentPlugin
{

    //Payment plugin name (the name of the PHP file)
    var $accepted_currencies = array('USD', 'GBP', 'EUR', 'JPY', 'CAD', 'AUD');
    var $multiple = true;
    var $name = 'example';

    var $pluginConfig = array(
        'login' => array('HIKA_USERNAME', 'input'),
        'password' => array('HIKA_PASSWORD', 'input'),
        'signature' => array('SIGNATURE', 'input'),
        'environnement' => array('ENVIRONNEMENT', 'list', array(
            'production' => 'HIKA_PRODUCTION',
            'sandbox' => 'HIKA_SANDBOX',
            'beta-sandbox' => 'Beta-Sandbox'
        )),
        'instant_capture' => array('Instant Capture', 'boolean', '0'),
        'ask_ccv' => array('Ask CCV', 'boolean', '1'),
        'details' => array('SEND_DETAILS_OF_ORDER', 'boolean', '1'),
        'send_order_id' => array('Send order id', 'boolean', '0'),
        'send_notification' => array('ORDER_NOTIFICATION', 'boolean', '0'),
        'debug' => array('DEBUG', 'boolean', '0'),
        'cancel_url' => array('CANCEL_URL', 'input'),
        'return_url' => array('RETURN_URL', 'input'),
        'verified_status' => array('VERIFIED_STATUS', 'orderstatus')
    );

    function needCC(&$method)
    {

            $method->custom_html = '
            <script src="https://js.stripe.com/v3/"></script>
            <input type="hidden" id="hiddencontainer" name="hiddencontainer"/>

            <div id="payment-request-button">
              <!-- A Stripe Element will be inserted here. -->
            </div>
            <script>
                
                const stripe = Stripe("secretkeygoeshere", {
                    apiVersion: "2020-08-27",
                });
                
                console.log("amount in basket: ", document.getElementsByClassName("hikashop-count")[0].innerHTML);                
                
                let amount = 3495 * document.getElementsByClassName("hikashop-count")[0].innerHTML;
                let label = "ellaOne x" + document.getElementsByClassName("hikashop-count")[0].innerHTML + "tablet";
                
                const paymentRequest = stripe.paymentRequest({
                    country: "GB",
                    currency: "gbp",
                    total: {
                        label: label,
                        amount:amount,
                    },
                });
                const elements = stripe.elements();
                const prButton = elements.create("paymentRequestButton", {
                  paymentRequest,
                });
                
                (async () => {
                // Check the availability of the Payment Request API first.
                const result = await paymentRequest.canMakePayment();
                    if (result) {
                        prButton.mount("#payment-request-button");
                    } else {
                        document.getElementById("payment-request-button").style.display = "none";
                    }
                })();
                
                async function handleServerResponse(response, complete) {
                    if (response.error) {
                        complete("fail");
                    } else if (response.requires_action) {
                        complete("success");
                        await handleAction(response);
                    } else {
                        complete("success");
                        console.log("MISHA");
            
                        let myhidden = document.getElementById("hiddencontainer");
                        myhidden.value = 1;
            
                    }
                }
            
                async function handleAction(response) {
                    const {
                        error: errorAction,
                        paymentIntent
                    } = await stripe.handleCardAction(
                        response.payment_intent_client_secret
                    );
            
                    if (errorAction) {
                        // Show error from Stripe.js in payment form
                    } else {
                        const response = await fetch(
                            "/plugins/hikashoppayment/example/confirm_payment.php", {
                                method: "POST",
                                headers: {
                                    "Content-Type": "application/json"
                                },
                                body: JSON.stringify({
                                    payment_intent_id: paymentIntent.id
                                })
                            }
                        );
            
                        // Step 3: handle server response
                        handleServerResponse(await response.json());
                    }
                }
                    
                paymentRequest.on("paymentmethod",
                  async ({paymentMethod, complete}) => {
                    // Send paymentMethod to server
                    const response = await fetch(
                        "index.php?option=com_helloworld&format=ajax&lang=en&view=helloworld&task=getArticles&tmpl=component", {
                        method: "POST",
                        headers: {
                          "Content-Type": "application/json"
                        },
                        body: JSON.stringify({
                          payment_method_id: paymentMethod.id
                        })
                      }
                    )
                
                    // Step 3: handle server response
                    await handleServerResponse(await response.json(), complete);
                });
            </script>
            ';

            return true;
    }
}
?>

/components/com_helloworld/views/helloworld: This recieves the ajax and fails on createFromCart()
<?php
# vendor using composer


require $_SERVER['DOCUMENT_ROOT'] . '/vendor/autoload.php';

defined('_JEXEC') or die;

//ini_set('display_errors', 1);
//ini_set('display_startup_errors', 1);
//error_reporting(E_ALL);

\Stripe\Stripe::setApiKey('secretkeygoeshere');

header('Content-Type: application/json');

class HelloWorldViewHelloWorld extends JViewLegacy
{

    function display($tpl = null)
    {

        $app = JFactory::getApplication();
        $user = JFactory::getUser();
        $userId = $user->get('id');

        $task = JRequest::getString('task');

        switch ($task) {

            case "getArticles":

                $this->_getArticles();

                break;

        }
        parent::display($tpl);

        jexit();

    }


    public function _getArticles()
    {

# retrieve json from POST body
        $json_str = file_get_contents('php://input');
        $json_obj = json_decode($json_str);

        $intent = null;
        try {
            if (isset($json_obj->payment_method_id)) {
                # Create the PaymentIntent
                $intent = \Stripe\PaymentIntent::create([
                    'payment_method' => $json_obj->payment_method_id,
                    'amount' => 3495,
                    'currency' => 'gbp',
                    'confirmation_method' => 'manual',
                    'confirm' => true,
                ]);
            }
            if (isset($json_obj->payment_intent_id)) {
                $intent = \Stripe\PaymentIntent::retrieve(
                    $json_obj->payment_intent_id
                );
                $intent->confirm();
            }
            $this->generateResponse($intent);
        } catch (\Stripe\Exception\ApiErrorException $e) {
            # Display error on client
            echo json_encode([
                'error' => $e->getMessage()
            ]);
        }
    }


    function generateResponse($intent)
    {
        # Note that if your API version is before 2019-02-11, 'requires_action'
        # appears as 'requires_source_action'.
        if ($intent->status == 'requires_action' &&
            $intent->next_action->type == 'use_stripe_sdk') {
            # Tell the client to handle the action
            echo json_encode([
                'requires_action' => true,
                'payment_intent_client_secret' => $intent->client_secret
            ]);
        } else if ($intent->status == 'succeeded') {
            # The payment didn’t need any additional actions and completed!
            # Handle post-payment fulfillment
            echo json_encode([
                "success" => true,
            ]);

            $hikashopHelper = rtrim(JPATH_ADMINISTRATOR, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'components' . DIRECTORY_SEPARATOR . 'com_hikashop' . DIRECTORY_SEPARATOR . 'helpers' . DIRECTORY_SEPARATOR . 'helper.php';

            if (!file_exists($hikashopHelper) || !include_once($hikashopHelper)) {
                echo "HIKA NOT WORKING";
                return;
            }

            $cartClass = hikashop_get('class.cart');
            $orderClass = hikashop_get('class.order');

            $cart = $cartClass->getFullCart();

            $cart_id = $cart->cart_id;
            
            //Error here
            $order = $orderClass->createFromCart($cart_id);

            

//            $orderClass = hikashop_get('class.cart');
//        $orderClass->createFromCart(0);
        } else {
            # Invalid status
            http_response_code(500);
            echo json_encode(['error' => 'Invalid PaymentIntent status']);
        }
    }

}

We have been stuck on this for days and at least a nudge in the right direction would be appreciated. Many thanks for your time.

Please Log in or Create an account to join the conversation.

  • Posts: 82863
  • Thank you received: 13372
  • MODERATOR
2 years 9 months ago #339229

Hi,

We have around a 100 calls to getName functions in the code of HikaShop.
There are basically two types of calls:
- the ones with $this->getName(); in view files or $view-getName() in code dealing with views to get the name of the current view. I don't see this failing in your case.
- the ones to get the name of shipping methods and payment methods to be displayed in the invoices, order information, emails, etc.
It's likely to come from this. This would indicate that the order_payment_id or order_payment_method or the order_shipping_id or order_shipping_method of the order is for a shipping plugin which doesn't exist or at least which couldn't be loaded.
I suppose it is because of the second one.
To be sure, if you can't get the full error message on screen, you can check in your PHP error log. It will contain the full fatal error message with the line number and file path where the error happened.
Supposing that I'm correct, then I would recommend checking these columns in the hikashop_order table for the order created in your database and check with the id of the payment/shipping methods you have configured in your backend and their folder name. There is probably some discrepency, or if it's correctly, maybe it's linked to the fact that the plugin's access is not "public" or something like that. For example, if you limit your payment method's access to "super adminstrator", then you can see and select it on the checkout as you're logged in as a super admin, but when Stripe contacts your /components/com_helloworld/views/helloworld code, the Stripe server is not logged in and thus is a guest. And supposing that you did that for your tests, I would rather recommend that you do it differently. For example, you could just add a few lines of PHP at the beginning of your payment plugin file to check the user group of the current user or URL parameters to check that it is stripe contacting you and return if it's not super admin. That way, the payment method won't appear for others on the checkout but it will still be loaded when the createFromCart function is used and the getName function is called on the payment plugin class.
Now that's just guesses over guesses so I might be wrong...

Please Log in or Create an account to join the conversation.

Time to create page: 0.059 seconds
Powered by Kunena Forum