Skip to main content

This site requires you to update your browser. Your browsing experience maybe affected by not having the most up to date version.

E-Commerce Modules /

Discuss about the various e-commerce modules available:
Ecommerce, SS Shop, SilverCart and SwipeStripe
Alternatively, have a look the shared mailinglist.

Moderators: martimiz, Nicolaas, Sean, frankmullenger, biapar, Willr, Ingo, Jedateach, swaiba, simon_w

Fixes for ecommerce 0.8.*


Reply


7 Posts   1246 Views

Avatar
inCharge

Community Member, 102 Posts

9 May 2011 at 11:42pm

Edited: 10/05/2011 8:26am

This is a fix for 0.8.0, 0.8.1 and (as of now) the current BurnBright version:

Using the FlatTaxModifier, I'm getting the following error when it is the second of two modifiers. The same problem probably also happens with other modifiers that iterate through all the modifiers. (It needs to do that to calculate tax on shipping etc)

Debug::fatalHandler(256,Uncaught Exception: Object->__call(): the method 'total' does not exist on 'DataObjectSet' in ...\sapphire\core\Object.php,724,Array)
exceptionHandler(exception 'Exception' with message 'Object->__call(): the method 'total' does not exist on 'DataObjectSet'' in ...sapphire\core\Object.php:724
Stack trace:
#0 ...\model\Order.php(609): Object->__call('Total', Array)
#1 ...\model\Order.php(609): DataObjectSet->Total()
#2 ...\modifiers\FlatTaxModifier.php(104): Order->ModifiersSubTotal('FlatTaxModifier')
#3 ...\modifiers\FlatTaxModifier.php(93): FlatTaxModifier->TaxableAmount()
...etc...

The cause is in Order.php, in the createModifiers function.
To fix it, change from...

return $write ? $this->modifiersFromDatabase() : new DataObjectSet($modifiers);

...to...

return $write ? $this->modifiersFromDatabase() : $modifiers;

...because $modifiers is already a DataObjectSet, so the old code creates a nested DataObjectSet. When the result is returned, and the caller tries to interate through the modifiers, it finds the nested DataObjectSet instead of a Modifier, which is why the error message says 'total' does not exist on 'DataObjectSet'.

I haven't tested older versions, but in version 8.0, ShoppingCart::get_modifiers() changed to return a dataset instead of an array, so looks like it affects all versions since then.

Avatar
inCharge

Community Member, 102 Posts

10 May 2011 at 12:28am

Edited: 27/05/2011 8:26pm

When a ModifierForm is submitted, it goes to 404 Page Not Found: "Sorry, it seems you were trying to access a page that doesn't exist."

The cause in CheckoutPage.php, in initVirtualMethods. To fix it, add the call to self::uninherited_static.

   protected function initVirtualMethods() {
      if($forms = $this->ModifierForms()) {
         foreach($forms as $form) {
            $this->addWrapperMethod($form->Name(), 'getOrderModifierForm');
            self::$allowed_actions[] = $form->Name(); // add all these forms to the list of allowed actions also
         }

         // Force this controller class to update its cache of allowed_actions
         self::uninherited_static('CheckoutPage_Controller', 'allowed_actions', true);
      }
   }

Why? Because actions are added to the allowed_actions array AFTER it has been read and cached by Object::uninherited_static, so the request handler doesn't see the dynamically added action. The solution is to call Object::uninherited_static again with the parameter 'uncached' as 'true', which forces the cache to be updated.

This code has been there since at least version 0.6, so either nobody has ever used ModifierForms, which is possible as I can't see any shipped examples. Or maybe the cacheing mechanism was introduced after the code was written, although I just checked SilverStripe 2.7 and it has the same cacheing code.

Avatar
Jedateach

Forum Moderator, 233 Posts

11 May 2011 at 2:34pm

hi inCharge, thanks for sharing your problems / solutions here.

In a nutshell what this code is trying to achieve is to allow any modifier form to be processed when they are submitted on the checkout page. Because your selection of modifiers is customizable, the initVirtualMethods function is needed to add each modifier form to the CheckoutPage_Controller. Normally you would add MyModiferForm to the ChecoutPage_Controller class, and this also becomes an action you can submit the form to.
The second part of adding an action to a controller is to allow it to be called, so that's why we need to update the allowed_actions static array.

Historically, I'm not sure modifier forms have ever worked / been used. I've revisited this code in trunk recently, when I finally needed to create a modifier with a form (for entering discount coupons). The coupon module isn't finished, but the modifier forms processing probably does. One change was to move the initVirtualMethods code to a unique controller... with the intention of allowing a modifier form to be added to / processed from any part of the site you want to add it on.

Anyway, thanks again, hope this helps. You're most welcome to test out the trunk code, we're currently trying to get it stable for a release.

Avatar
inCharge

Community Member, 102 Posts

14 May 2011 at 1:31am

I'm using a modifier form to allow the cutomer to select a shipping/delivery service - i.e. Standard/Express etc. It works fine once the cacheing issue mentioned above is fixed.

One aspect of the modifier form that I find strange is that each modifier form has its own <form> tags and Submit button. I don't think the customer expects to see more than one Submit button. Wouldn't it be better to have all the fields in one form? Maybe Ajax is the answer.

> You're most welcome to test out the trunk code, we're currently trying to get it stable for a release.

I was hoping to use that code for this project, but it wasn't ready, so I used 8.1. Hope to be upgrading before long. It's good to see those nightly test-run emails coming through to the Google group.

Thanks,
Jules

Avatar
inCharge

Community Member, 102 Posts

27 May 2011 at 8:30pm

This is another part of the CheckOut page fix detailed above.

It seems that the allowed_actions array must be declared for the Modifier Form actions to be added dynamically.

class CheckoutPage_Controller extends Page_Controller {

   static $allowed_actions = array(
      'OrderForm'
   );

Avatar
inCharge

Community Member, 102 Posts

27 May 2011 at 8:38pm

Edited: 27/05/2011 9:02pm

Sometimes you want to leave the variation label blank (e.g. Size), and just display the variation description and price. At the moment, if the variation label is empty, there's an unwanted colon

Also, sometimes the variation value is empty e.g. if there are multiple variation types, but one type is not applicable for some variations.

e.g. If the variation label is empty, it shows...

:85x200 cms, :
or
:85x200 cms, :Gold artwork
or
:, :Gold artwork

...but I want to show...

85x200 cms
or
85x200 cms, Gold artwork
or
Gold artwork

So in ProductVariation.php, I changed the getTitle function to...

   function getTitle(){
      $values = $this->AttributeValues();
      if($values->exists()){
         $labelvalues = array();
         foreach($values as $value){
            $l = $value->Type()->Label;
            $v = $value->Value;
            if ( $l && $v )
               $labelvalues[] = $l . ':' . $v;
            else if ( $v )
               $labelvalues[] = $v;
            }
         return implode(', ',$labelvalues);
      }
      return $this->InternalItemID;
   }

This change should be backwardly compatible, because I can't think why the leading colon would ever be desirable.

Avatar
inCharge

Community Member, 102 Posts

27 May 2011 at 8:59pm

Edited: 27/05/2011 9:09pm

This isn't a fix as such.

Objects typically have a debug() method, which is really useful for ...er... debugging. In the .ss file, just add $debug to see the properties of the object in the current context.

The Product object has a debug method, but it doesn't show all the properties. To see all properies, in product.php, change debug to...

   public function debug() {
      $Title = $this->Title;
      $Price = $this->Price;
      $Weight = $this->Weight;
      $Model = $this->Model;
      $FeaturedProduct = $this->FeaturedProduct;
      $AllowPurchase = $this->AllowPurchase;
      $InternalItemID = $this->InternalItemID;
      $NumberSold = $this->NumberSold;

      $html = parent::debug() .<<<HTML
         <h3>Product class details</h3>
         <p>
            <b>Title : </b>$Title<br/>
            <b>Price : </b>$Price<br/>
            <b>Weight : </b>$Weight<br/>
            <b>Model : </b>$Model<br/>
            <b>FeaturedProduct : </b>$FeaturedProduct<br/>
            <b>AllowPurchase : </b>$AllowPurchase<br/>
            <b>InternalItemID : </b>$InternalItemID<br/>
            <b>NumberSold : </b>$NumberSold<br/>
         </p>
HTML;

      return $html;
   }

By the way, also in Product.php, the Product_OrderItem class also has a debug function, which includes the line...

      $this->extend('updateDebug',$html);


...but I don't see how this can ever work, because the extension can't return anything, can it?