craftcms / commerce-paypal-checkout

PayPal Checkout gateway for Craft Commerce.
https://plugins.craftcms.com/commerce-paypal-checkout
MIT License
5 stars 10 forks source link

Error: Trying to get property 'fullName' of non-object #48

Closed clarknelson closed 2 years ago

clarknelson commented 2 years ago

Description Describe what the problem is.

<form method="post">
    {{ csrfInput() }}
    {{ actionInput('commerce/payments/pay') }}
    {{ hiddenInput('cancelUrl', '/commerce/checkout/payment'|hash) }}
    {{ cart.gateway.getPaymentFormHtml({
        currency: cart.paymentCurrency
    }) | raw }}
</form>

I have included the paypal buttons like so. But after clicking the yellow checkout button after the popup appears I see an alert "Error: Trying to get property 'fullName' of non-object"

I also get the following console error message: Screenshot from 2021-12-02 12-06-36

Additional info

I have tried both testing and non-testing in the gateway settings!

clarknelson commented 2 years ago

I have been playing around with it, now I see the following error message:

"Error: Invalid payment or order. Please review."

This is the error message in the js console:

Error: Expected an order id to be passed
    at https://www.sandbox.paypal.com/smart/buttons?style.layout=vertical&style.color=gold&style.shape=rect&style.tagline=false&components.0=buttons&locale.country=US&locale.lang=en&sdkMeta=eyJ1cmwiOiJodHRwczovL3d3dy5wYXlwYWwuY29tL3Nkay9qcz9jbGllbnQtaWQ9QWZxZVRMelFjSEVmY3FXMnZMMEQtekdKbjQwUm12eVphTURjMkZkSUpqQy1RZXJIMm1RcVBTXzZsRVRMczhhaUo1elowdkowamdOSlFDR2cmaW50ZW50PWNhcHR1cmUmY3VycmVuY3k9VVNEIiwiYXR0cnMiOnsiZGF0YS11aWQiOiJ1aWRfd2F6cnllcWNodHFra2t6cmZsZHp0Ynp0bWdpa256In19&clientID=AfqeTLzQcHEfcqW2vL0D-zGJn40RmvyZaMDc2FdIJjC-QerH2mQqPS_6lETLs8aiJ5zZ0vJ0jgNJQCGg&sdkCorrelationID=aa825f5b9eeab&storageID=uid_66a70263fa_mtk6ndi6ndu&sessionID=uid_8b2cc3b920_mtg6mdy6mjq&buttonSessionID=uid_392da2d517_mtg6mje6mzc&env=sandbox&fundingEligibility=eyJwYXlwYWwiOnsiZWxpZ2libGUiOnRydWUsInZhdWx0YWJsZSI6dHJ1ZX0sInBheWxhdGVyIjp7ImVsaWdpYmxlIjpmYWxzZSwibWVyY2hhbnRDb25maWdIYXNoIjoiIiwicHJvZHVjdHMiOnsicGF5SW40Ijp7ImVsaWdpYmxlIjpmYWxzZSwidmFyaWFudCI6bnVsbH0sInBheWxhdGVyIjp7ImVsaWdpYmxlIjpmYWxzZSwidmFyaWFudCI6bnVsbH19fSwiY2FyZCI6eyJlbGlnaWJsZSI6dHJ1ZSwiYnJhbmRlZCI6dHJ1ZSwiaW5zdGFsbG1lbnRzIjpmYWxzZSwidmVuZG9ycyI6eyJ2aXNhIjp7ImVsaWdpYmxlIjp0cnVlLCJ2YXVsdGFibGUiOnRydWV9LCJtYXN0ZXJjYXJkIjp7ImVsaWdpYmxlIjp0cnVlLCJ2YXVsdGFibGUiOnRydWV9LCJhbWV4Ijp7ImVsaWdpYmxlIjp0cnVlLCJ2YXVsdGFibGUiOnRydWV9LCJkaXNjb3ZlciI6eyJlbGlnaWJsZSI6dHJ1ZSwidmF1bHRhYmxlIjp0cnVlfSwiaGlwZXIiOnsiZWxpZ2libGUiOmZhbHNlLCJ2YXVsdGFibGUiOmZhbHNlfSwiZWxvIjp7ImVsaWdpYmxlIjpmYWxzZSwidmF1bHRhYmxlIjp0cnVlfSwiamNiIjp7ImVsaWdpYmxlIjpmYWxzZSwidmF1bHRhYmxlIjp0cnVlfX0sImd1ZXN0RW5hYmxlZCI6ZmFsc2V9LCJ2ZW5tbyI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJpdGF1Ijp7ImVsaWdpYmxlIjpmYWxzZX0sImNyZWRpdCI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJhcHBsZXBheSI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJzZXBhIjp7ImVsaWdpYmxlIjpmYWxzZX0sImlkZWFsIjp7ImVsaWdpYmxlIjpmYWxzZX0sImJhbmNvbnRhY3QiOnsiZWxpZ2libGUiOmZhbHNlfSwiZ2lyb3BheSI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJlcHMiOnsiZWxpZ2libGUiOmZhbHNlfSwic29mb3J0Ijp7ImVsaWdpYmxlIjpmYWxzZX0sIm15YmFuayI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJwMjQiOnsiZWxpZ2libGUiOmZhbHNlfSwiemltcGxlciI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJ3ZWNoYXRwYXkiOnsiZWxpZ2libGUiOmZhbHNlfSwicGF5dSI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJibGlrIjp7ImVsaWdpYmxlIjpmYWxzZX0sInRydXN0bHkiOnsiZWxpZ2libGUiOmZhbHNlfSwib3h4byI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJtYXhpbWEiOnsiZWxpZ2libGUiOmZhbHNlfSwiYm9sZXRvIjp7ImVsaWdpYmxlIjpmYWxzZX0sIm1lcmNhZG9wYWdvIjp7ImVsaWdpYmxlIjpmYWxzZX19&platform=desktop&experiment.enableVenmo=false&experiment.disablePaylater=false&flow=purchase&currency=USD&intent=capture&commit=true&vault=false&renderedButtons.0=paypal&renderedButtons.1=card&debug=false&applePaySupport=false&supportsPopups=true&supportedNativeBrowser=false&allowBillingPayments=true:1337:113414
clarknelson commented 2 years ago

Screenshot from 2021-12-08 13-15-40

clarknelson commented 2 years ago

My template looks something like this, maybe there is a problem with how I am including the gateway checkout...

{% for id,name in craft.commerce.gateways.allCustomerEnabledGateways %}
        {% if name == 'PayPal Checkout' %}
            <form method="post">
                {{ csrfInput() }}
                {{ actionInput('commerce/payments/pay') }}
                {{ name.getPaymentFormHtml({
                    currency: cart.paymentCurrency
                }) | raw }}
            </form>
        {% endif %}
{% endfor %}
nfourtythree commented 2 years ago

Hi @clarknelson

Thank you for bringing this to our attention.

This looks like the issue was caused when you are not providing a billing address during the checkout process.

We were initially under the impression that PayPal requires the payer object during API calls, however, having consulted the PayPal Checkout docs it seems like that is an optional property. An update has been pushed up that now means it is possible to not provide a billing address and therefore prevent this error (the update will be included in the next release of the plugin).

It is worth noting that, at the moment, this plugin does not do any syncing of data from the PayPal side of things back to Commerce. This means although you do not have to have the customer provide any shipping or billing address information on the site, this information will then only be available on the PayPal dashboard. Obviously, you do have an option to write some custom code in a module/plugin if you want to fetch that data.

We are looking into the future of this plugin/integration with PayPal to see how we can tie them closer together.

Thanks!

clarknelson commented 2 years ago

Thanks for taking the time to respond and write an update. I thought I had a billing address on the order, but when I set a default billing address for the customer I no longer see the fullName error message.

Unfortunatly I am seeing another error: "Error: Argument 1 passed to craft\helpers\UrlHelper::siteUrl() must be of the type string, null given, called in /app/vendor/craftcms/commerce-paypal-checkout/src/gateways/Gateway.php on line 514"

I fixed this by making sure the returnUrl and cancelUrl are set within the form:

<form method="post">
        {{ csrfInput() }}
        {{ actionInput('commerce/payments/pay') }}
        {{ redirectInput('/store/checkout/confirm?number=' ~ cart.number) }}
        <input type="hidden" name="cancelUrl" value="{{ '/store/checkout/payment'|hash }}"/>
        {{ name.getPaymentFormHtml({
            currency: cart.paymentCurrency
        }) | raw }}
</form>

Notice the added {{ redirectInput }} and . Another issue I ran into is making sure that the correct gateway is set for the order / cart. If you are trying to set up say stripe + paypal you will want to make sure the correct gateway is set before the popup is opened. This is an issue I am going to have to try and resolve because I have both Paypal and stripe forms displayed on the same page.

It may be useful to add an example form to the README because I don't think these required form parameters are clearly stated. Hopefully this github issue may help users in the future though.

nfourtythree commented 2 years ago

Hi @clarknelson

Thank you for your reply, we can certainly look into the documentation side of this.

For future note, the fields are shown in the example templates (https://github.com/craftcms/commerce/blob/develop/example-templates/dist/shop/checkout/payment.twig#L58-L65) which is a good resource for looking at some structure.

As for your point about having two gateways on the page. This is possible as the commerce/payments/pay action does accept a gatewayId so this can be passed at the same time.

As mentioned in the docs you could loop over all the available gateways and output their forms separately, making sure to include the ID.

That would look something like the following:

<h1>Gateways</h1>
{% for gateway in craft.commerce.gateways.getAllCustomerEnabledGateways %}
    <h2>{{ gateway.name }}</h2>
    <form id="paymentForm" method="post" action="">
        {{ csrfInput() }}
        {{ actionInput('commerce/payments/pay') }}
        {{ redirectInput(siteUrl('/shop/customer/order', {
            number: cart.number,
            success: 'true'
        })) }}
        {{ hiddenInput('cancelUrl', siteUrl('/shop/checkout/payment')|hash) }}
        {{ hiddenInput('orderEmail', cart.email) }}
        {{ hiddenInput('gatewayId', gateway.id) }}
        {% set params = {} %}

        {% if className(cart.gateway) == 'craft\\commerce\\paypalcheckout\\gateways\\Gateway' %}
            {% set params = { currency: cart.paymentCurrency } %}
        {% endif %}

        <div>
            {{ gateway.getPaymentFormHtml(params)|raw }}
        </div>

        <div>
            {% if className(gateway) not in [
                'craft\\commerce\\paypalcheckout\\gateways\\Gateway',
            ] %}
                {{ tag('button', {
                    type: 'submit',
                    text: 'Pay'|t
                }) }}
            {% endif %}
        </div>
    </form>
{% endfor %}

Hope this helps!

clarknelson commented 2 years ago

Thank you so much, this is very very helpful!

I used these example forms, which apparently still have the cancel url and redirect url set... https://craftcms.com/docs/commerce/3.x/making-payments.html#full-payment-at-checkout

It's clearly just an understanding bit on my end, probably more of craft's job to have it on their documentation that these are required.

Thanks again and happy holidays!