Description

If a discount has been applied to an order the "My Shipping information is the same as my Billing information" fails to work, the AJAX call returns a 500 server error.

The problem appears to be triggered by the validation function commerce_customer_profile_copy_validate() which does quite a bit of refreshing and saving of the order object. This calls the commerce_discount module's commerce_discount_commerce_cart_order_refresh() function, which deletes and re-creates discount lines. A little later in the AJAX callback code the original order is used, but this refers to the now-deleted discount line item, and so it fails with EntityMetadataWrapperException: Unable to get the data property commerce_unit_price as the parent data structure is not set.

Original Description, for posterity

I have an occasional random failure for the Shipping Address to appear, when the "My Shipping information is the same as my Billing information" checkbox is deselected.

Has been noticed on Apple Mac with Safari, and Windows 8.1 with Firefox. So it doesn't seem to be an OS or browser-specific problem.

Typically when I ask the user for more details, they report that the function is now working for them.

I've tried, and failed, to reproduce the problem on my machine with all the browsers I have.

When I asked about the rotating arrows, one user reported that they didn't see those: they deselected the checkbox and nothing happened at all.

So it seems to be:

  • a random issue that doesn't happen very often (race condition somewhere?)
  • not browser-specific
  • perhaps an early client-side JavaScript error, before the AJAX call is made to fetch the new fields
  • possibly a problem for new site visitors only?
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

rszrama’s picture

Version: 7.x-1.10 » 7.x-1.x-dev
Category: Bug report » Support request
Status: Active » Postponed (maintainer needs more info)

No clue... I haven't personally seen the issue, so we'll just leave this open until we can get some steps to reproduce. It very well could be some other JavaScript on the page causing an error before the Ajax request runs. Can you share the link or does it need to remain private?

fonant’s picture

It's a tricky one!

The Commerce store is at http://www.thehealthybackbag.co.uk - it should be possible to reproduce the problem by adding one item to the basket and then going to the checkout page. But I haven't managed to reproduce it here, and others say everything is working for them too.

As I hear from other people who've seen the problem I'll post more info here.

rszrama’s picture

Wow, that site looks awesome! Great work. : )

fwiw, I tested Add to Cart / the profile copy checkbox and it worked as expected. I'll keep an eye out and try making it fail in other browsers if possible.

fonant’s picture

Useful new symptom information: the problem occurs if a coupon code is added using commerce_discount/commerce_coupon.

I can now reproduce the problem. Changing "My Shipping information is the same as my Billing information" now results in a 500 server error from the AJAX call.

So not random, it's a problem caused by commerce_discount/commerce_coupon!

The error message is:

EntityMetadataWrapperException: Unable to get the data property
commerce_unit_price as the parent data structure is not set. in
EntityStructureWrapper->getPropertyValue() (line 438 of
/var/www/shared/drupal7/sites/all/modules/entity/includes/entity.wrapper.inc).

Since a "Free Shipping" discount works fine, I suspect it's something to do with the additional line item that the discount/coupon module adds to the order.

I'll try to diagnose the cause further when I get a spare moment.

fonant’s picture

Title: Random failure if shipping is not same as billing » Shipping is not same as billing fails, if discount is applied
Category: Support request » Bug report
Status: Postponed (maintainer needs more info) » Active
rszrama’s picture

Project: Commerce Core » Commerce Coupon
Component: User experience » Code

Thanks for the update! Moving to the Coupon project (but feel free to move it to the Discount project if it turns out to be an issue inthere).

fonant’s picture

Three hours more research (this is hard to debug, there are so many function and method calls going on!):

Additional symptoms:

* Error occurs if a Discount Coupon has been applied to the order.
* If you re-apply the Discount Coupon a second time (resulting in "The coupon you have entered has already been applied to your order") then everything works fine.

The error is triggered by the AJAX call which in turn calls commerce_customer_profile_copy_validate() to validate the commerce_customer_profile_copy field in the checkout form. This validation function saves the order, and at some point during the commerce_order_save() an exception is caused and it all stops with a 500 error.

fonant’s picture

OK, more info.

The problem seems to be that while validating the "The coupon you have entered has already been applied to your order" field the order is saved and refreshed and generally manipulated a great deal. Not sure why this is needed: there's an awful lot of code being run!

For some reason during this process the existing discount line item is being deleted and replaced with a duplicate one with a new ID, but the order in some places still refers to the original line item that is deleted so has no data.

fonant’s picture

The problem seems to stem from commerce_discount_commerce_cart_order_refresh() deleting and re-creating order discount line items. In the context of this particular AJAX call this results in the order becoming corrupted because it refers to the original discount line item which has been deleted.

dpolant’s picture

Status: Active » Fixed

I believe I fixed this by adding an empty check on the discount line items.

Discount module has a habit of churning through line items, so you always have to be super careful not to assume they actually exist while doing stuff in a cart refresh hook.

Check the latest dev branch.

fonant’s picture

Priority: Normal » Major
Status: Fixed » Active

Nope, still fails here.

Using:

  • commerce_coupon 7.x-2.0-beta4+4-dev
  • commerce_discount 7.x-1.0-alpha4+4-dev

If I apply a discount code to the order, using "My Shipping information is the same as my Billing information" causes a 500 error on the AJAX call, meaning customers cannot enter a separate shipping address.

The problem occurs if you:

  1. Go to checkout.
  2. Apply a discount code.
  3. Choose to have a separate shipping address.

The problem does not occur if you:

  1. Go to checkout.
  2. Apply a discount code.
  3. Apply the same discount code again (ignoring warning).
  4. Choose to have a separate shipping address.
fonant’s picture

Project: Commerce Coupon » Commerce Discount

Moving to commerce_discount, as this problem still occurs with a very simple discount and with commerce_coupon disabled.

Demonstration with simple site:

  1. Go to http://www.fonant.com/node/53
  2. Add one to cart.
  3. Go to checkout, where a fixed 10% order discount is applied.
  4. Try to enter a different shipping address: AJAX fails with a 500 error.

Running with:

  • commerce 7.x-1.10
  • commerce_shipping 7.x-2.1
  • commerce_discount 7.x-1.0-alpha4+4-dev
fonant’s picture

Issue summary: View changes
fonant’s picture

Issue summary: View changes
joelpittet’s picture

Status: Active » Postponed (maintainer needs more info)
Issue tags: +sprint

Thanks for the demo @fonant! Is there any chance you can post what the PHP error log is spitting out from that 500 error?

Also is this still happening on the latest -dev?

If so I think we can likely create a test for this now that the automated tests seem to be working today.

fonant’s picture

With:

  • commerce 7.x-1.11
  • commerce_discount 7.x-1.0-alpha5

I got:

EntityMetadataWrapperException: Unable to get the data property commerce_unit_price as the parent data structure is not set. in EntityStructureWrapper->getPropertyValue() (line 438 of /var/www/shared/drupal7/sites/all/modules/entity/includes/entity.wrapper.inc).

but with commerce_discount 7.x-1.x-dev (7.x-1.0-alpha6+2-dev) the error has gone!

Thank you for fixing this :)

joelpittet’s picture

Status: Postponed (maintainer needs more info) » Fixed

Oh great news!

fonant’s picture

Status: Fixed » Needs work

Hmmm.. not quite. On my simple demo site the bug has gone away, but on a more complex site the bug still persists a little.

There still seems to be an initialisation problem, just the first time you want a different shipping address:

  1. Add products to basket.
  2. Add discount code at checkout.
  3. Untick "My Shipping information is the same as my Billing information." => 500 ERROR!
  4. Tick "My Shipping information is the same as my Billing information." => OK :)
  5. Untick "My Shipping information is the same as my Billing information." => OK :)
  6. From then on the shipping address toggle works fine, but if you refresh the checkout page (or go to the next page and then back again) the problem returns.

joelpittet’s picture

Is the discount code a using the coupon module? And what is the PHP error for the 500 error?

fonant’s picture

OK, I've updated my demo site to use coupon code for the discount, and the error is reproducible.

  1. Go to http://www.fonant.com/node/53
  2. Add one to cart.
  3. Go to checkout, where shipping toggle works fine.
  4. Enter "DISCOUNT" coupon code: a 10% order discount is applied.
  5. Try to enter a different shipping address: AJAX fails with a 500 error.
  6. Toggle the shipping address twice more, and it all works again.
  • commerce 7.x-1.11
  • commerce_discount 7.x-1.0-alpha5
  • commerce_coupon 7.x-2.0-rc2

The error is slightly different now:

EntityMetadataWrapperException: Unable to get the data property type as the parent data structure is not set. in EntityStructureWrapper->getPropertyValue() (line 438 of /var/www/shared/drupal7/sites/all/modules/entity/includes/entity.wrapper.inc).

fonant’s picture

More testing shows that the bug remains even with commerce_coupon 7.x-2.0-rc2+2-dev

joelpittet’s picture

Can you use the -dev version instead of alpha5? alpha6 i better but the dev version has nice fix here for the wrapper cache issues #2540234: Order Wrapper updating on refresh creates stale EMW cache

What version of the coupon module are you using?

fonant’s picture

Sorry, I was, gave the wrong version numbers above. My demo site has:

  • commerce 7.x-1.11
  • commerce_discount 7.x-1.0-alpha6+2-dev
  • commerce_coupon 7.x-2.0-rc2+2-dev

It's a lot better than it was: with a coupon code entered you still get a 500 error when trying to enter a different shipping address, but if you try again it works.

joelpittet’s picture

Ah thank you, it would be good to know where that error is originating. Could you add backtrace info to that exception?

includes/entity.wrapper.inc

$backtrace = debug_backtrace();
$debug = '<pre>' . json_encode($backtrace, JSON_PRETTY_PRINT) . '</pre>';
throw new EntityMetadataWrapperException('Unable to get the data property ' . check_plain($name) . ' as the parent data structure is not set. ' . $debug);

Then we can find out what function is being called that is losing that property info.

It looks like 'type' is being checked on a non-object. And likely should be getBundle() call on a EMW but that won't resolve the issue.

fonant’s picture

Here's the backtrace - there's a lot!

joelpittet’s picture

Awesome, that callstack doesn't have any commerce_discount functions in it. It looks like there may be an issue in commerce_donate from first glance.

joelpittet’s picture

@fonant I think it's suffering from stale cache as well in the entity_metadata_wrapper, we were looking in to a fix here https://www.drupal.org/node/1343196#comment-10152572 though i think it would great to just remove that cache all together like they suggest.

I wonder though if you apply that patch that it may resolve the issue. Give it a try...

fonant’s picture

FileSize
1.73 MB

Thanks for the ideas :)

Oddly although commerce_donate was once installed, it is no longer enabled and has been uninstalled. I'll check for remnants.

The patch linked to for entity_metadata_wrapper sadly doesn't help.

Here's a print_r($this, TRUE) from where the exception is raised.

joelpittet’s picture

@fonant in self-interest but it "may" help, try this patch #2538812: When discounts are deleted on existing carts it's EMW related for commerce_discount.

joelpittet’s picture

@fonant regarding commerce_donate, it was in the traceback/callstack you provided so it's being triggered. If you remove it and still get the error, can you post another traceback?

maxollerenshaw’s picture

Hi,

I can replicate this issue every time when an order discount is applied, I've not tried with a coupon. I thought i'd add a comment here to describe the issue I've found but If I need to raise as a new bug let me know as it's separate to the coupon issue described above.

I created an order discount when the total amount is greater than 49.99 then to add a free product to the bag. When you uncheck the box to change shipping information I get the http status 500 error every time. When I disabled this discount unchecking the box worked fine.

My versions differ slightly:

Commerce Discount - 7.x-1.0-alpha4
Commerce Coupon - 7.x-1.0-beta7

Unfortunately my php knowledge isn't good enough to develop a solution so hopefully the info I've provided will help track down the issue quicker, I'd be more than happy to test out any patches should somebody write one.

Many Thanks
Max

joelpittet’s picture

@maxollerenshaw please try to upgrade to the latest versions of discount and coupon and open a new issue if this problem persists.

There has been quite a few fixes since that release so it doesn't help us much to debug old alpha releases. Please try with the latest -dev release.

mglaman’s picture

Status: Needs work » Postponed (maintainer needs more info)

I can't replicate, it seems this is an issue with Commerce Coupon. It's happening with 2.x and 1.x versions in the comments. Marking needs more info for solid testing steps without Commerce Coupon. Otherwise I think we can mark "cannot reproduce" or kick over to that queue.

joelpittet’s picture

Status: Postponed (maintainer needs more info) » Closed (cannot reproduce)

Closing to triage the issue queue, reopen if you feel this still needs to be addressed. Assuming #33 is correct