SUPEE-9767 Patch/CE 1.9.3.3 - One Page Checkout - Customer Registration issue

Ok here's the real bug fix I came up with.

Edit /skin/frontend/base/default/js/opcheckout.js and edit the setMethod() method by replacing:

setMethod: function(){
    if ($('login:guest') && $('login:guest').checked) {
        this.method = 'guest';
        new Ajax.Request(
            this.saveMethodUrl,
            {method: 'post', onFailure: this.ajaxFailure.bind(this), parameters: {method:'guest'}}
        );
        Element.hide('register-customer-password');
        this.gotoSection('billing', true);
    }
    else if($('login:register') && ($('login:register').checked || $('login:register').type == 'hidden')) {
        this.method = 'register';
        new Ajax.Request(
            this.saveMethodUrl,
            {method: 'post', onFailure: this.ajaxFailure.bind(this), parameters: {method:'register'}}
        );
        Element.show('register-customer-password');
        this.gotoSection('billing', true);
    }
    else{
        alert(Translator.translate('Please choose to register or to checkout as a guest').stripTags());
        return false;
    }
    document.body.fire('login:setMethod', {method : this.method});
},

With:

setMethod: function(){
    var formKey = $('checkout-step-login').select('[name=form_key]')[0].value;
    if ($('login:guest') && $('login:guest').checked) {
        this.method = 'guest';
        new Ajax.Request(
            this.saveMethodUrl,
            {method: 'post', onFailure: this.ajaxFailure.bind(this), parameters: {method:'guest', form_key:formKey}}
        );
        Element.hide('register-customer-password');
        this.gotoSection('billing', true);
    }
    else if($('login:register') && ($('login:register').checked || $('login:register').type == 'hidden')) {
        this.method = 'register';
        new Ajax.Request(
            this.saveMethodUrl,
            {method: 'post', onFailure: this.ajaxFailure.bind(this), parameters: {method:'register', form_key:formKey}}
        );
        Element.show('register-customer-password');
        this.gotoSection('billing', true);
    }
    else{
        alert(Translator.translate('Please choose to register or to checkout as a guest').stripTags());
        return false;
    }
    document.body.fire('login:setMethod', {method : this.method});
},

That'll do it while we're waiting for the v2 of the patch


When you select register and continue, the JS script calls checkout.setMethod(), which is located in skin/frontend/base/default/js/opcheckout.js. From there we can see it makes an AJAX POST request to this.saveMethodUrl, but the only paramter it passes is method. If we look at Mage_Checkout_OnepageController::saveMethodAction, which is the target of that AJAX request, we can see that the patch added:

if ($this->isFormkeyValidationOnCheckoutEnabled() && !$this->_validateFormKey()) {
        return;
}

Since _validateFormKey looks for a form_key parameter in the request, and since the JS setMethod request didn't send this when it made the AJAX request, it's simply returning early and doing nothing. Back to the setMethod function and we can see that since it doesn't attempt to do anything with a return value, nothing else happens and the JS continues. At this point the JS has set this.method = 'register' but the quote hasn't been updated, so checkout_method is the default 'guest'.

Since the JS knows the customer selected register, it displays the password fields, so on the face of it, it looks like you're registering. But as far as the PHP side is concerned, it's a guest checkout, so it doesn't create the customer when checkout is complete.

Edit: the simplest fix is to comment out those three lines from saveMethodAction. The more correct/complex solution is that setMethod should be grabbing the form_key from the page and sending it with the AJAX request.


Full credits go to Peter for the solution! I would like to point out step by step instruction what to change.

Go to app/code/core/Mage/Checkout/controllers/OnepageController.php

Locate:

 public function saveMethodAction()
{
    if ($this->_expireAjax()) {
        return;
    }

    if ($this->isFormkeyValidationOnCheckoutEnabled() && !$this->_validateFormKey()) {
        return;
    }

Comment out the line with /* */ tags.

 public function saveMethodAction()
{
    if ($this->_expireAjax()) {
        return;
    }

    /*if ($this->isFormkeyValidationOnCheckoutEnabled() && !$this->_validateFormKey()) {
        return;
    }*/