Custom Reports with Table Wizard and Ubercart

I've had a few people request custom reports that Ubercart does not have built in. Fortunately, thanks to the Table Wizard module, it's not hard to create them!

Required Modules:

  • Ubercart
  • Table Wizard
  • Views
  • Schema (required by Table Wizard)
  • Views Bonus (for Excel output)
  • Views Calc (to do calculations on views)

Step 1
Install and enable the required modules. If you're not familiar with how to do this, you should probably start with some more basic Drupal tutorials.

Step 2 - Setting up our Tables
In this example we will create a "sales by country" report. The first thing we need to do is go to the Table Wizard page and let it know which tables we want to work with. The table wizard page is at admin/content/tw

Click "Add Existing Tables" and add uc_orders and uc_countries. Now views will be able to see these two tables.

However, we do need to create a "relationship" between these two tables. So click on "analyze" next to uc_orders and scroll down to billing_country field and select "available key" checkbox. Save it. Now we can use the billing_country as a relationship.

Go to content management -> table wizard -> relationships. Add a relationship between uc_orders.billing_country and uc_countries.country_id and click "add"

Step 3 - Creating the View
Now we're ready to add a view. Go to site building -> views and add new view. From the view type, select uc_orders. You can name it sales_by_country or whatever you like.

Select country_name and order_total as the fields. Add a filter for uc_orders.order_status to complete.

Now, finally, select the style and select Views Calc table. Check "display calculation" for order total. Select "sum". Select "country" as the grouping field.

That's it! You're done. you've created a custom report for ubercart!

Lazy programmers do it inline

If there's one thing I've learned from writing a lot of jQuery, it's that you can write a whole lot of code without pressing the enter key. Between all the method chaining and inline functions, you can do quite a bit with a small amount of code.

One thing I never really bothered to realize before recently is that you can write inline functions anywhere you want in just about any programming language. In this example, I'll show you ActionScript 3. Remember, just because you can, doesn't mean you should: the point of a function is to be reusable. If you write a function inline, you can not use it in other places. The example I'm going to give is a good use of an inline function because the contents of the function are probably only used in this specific case.

Quick and Dirty Alert Confirmations

	Alert.show("Are you sure you want to do that?","Confirmation", Alert.YES|Alert.NO,this,
   (function(event:CloseEvent):void{
	if(event.detail == Alert.YES) dispatchEvent(new Event("SomeEvent"));
   }),null,Alert.NO);

A lot of times, we want to warn a user before they do something they will regret. This code, in the end, simply dispatches an event of type "SomeEvent" only if the user hit "yes". If they hit "no", nothing else will happen.

Another good example of this would be my aforementioned use of callLater. Anywhere a function is passed, you can do it inline. If you want to.

Alternative

	Alert.show("Are you sure you want to do that?","Confirmation", Alert.YES|Alert.NO,this,onConfirm,null,Alert.NO);

   private function onConfirm(event:CloseEvent):void{
	if(event.detail == Alert.YES) dispatchEvent(new Event("SomeEvent"));
   }

There's hardly any difference between the two except that the second one is reusable. Some developers cringe when they see stuff like this written inline and some think it is efficient. It's largely up to your style. If I've got more than a line or two of logic, I tend to write it out in its own function rather than inline.

callLater vs. validateNow

For years, many Flex developers have known the secret to fixing many a UI problem was using either callLater() or validateNow() methods. Much to my surprise, some of these developers do not understand WHY these fix problems, what the difference is, and which method to use.

The Problem

So why do we need these functions? Well, in short, the flex framework doesn't do anything in the order you tell it and it doesn't do what you tell it to do when you tell it to. If you set a text's width and a text's style, they may not be applied in that order. And they will probably not be applied until a bunch of other stuff has happened either. When a programmer thinks something is done synchronously (one after the other) when they're actually being done according to the component when it "validates". It is important to note that this is not an issue with ActionScript 3, so much as an issue with the Flex Framework.

callLater vs. validateNow

callLater accepts two parameters. A function and some arguments for the function. This "function" gets queued to be called again at a later frame, hopefully after everything else has finished processing. I blogged about this before but I failed to mention the real difference between this solution and validateNow.

validateNow accepts no parameters and basically tells your component to just do its processing RIGHT NOW! So the difference is, instead of waiting and executing, like callLater, it just executes right now. From a programmer's perspective, this is a lot easier to do, however, it is not faster. It forces Flex to reprocess a bunch of stuff, whereas callLater just executes the code you wanted to execute anyway at a later time. If you want to use validateNow, consider that there are some more specific functions such as validateSize, validateProperties, and validateDisplayList. All 3 of these functions are called by validateNow.

Code vs. Code

The situation is that you want the width of some rendered text. After setting the text, you can not get the measuredwidth property because it will still be 0 until the component has validated.

CallLater Solution

var someText:Text = new Text();
someText.text="testing";
addChild(someText);
trace("before: " + someText.measuredWidth);
callLater(getWidth);
public function getWidth():void{
     trace("after: " + someText.measuredWidth);
}

validateNow Solution

var someText:Text = new Text();
someText.text="testing";
addChild(someText);
trace("before: " + someText.measuredWidth);
someText.validateNow(); //you should actually use validateSize() if you just want the measured width
trace("after: " + someText.measuredWidth);

Hopefully this makes sense. In my opinion, it is generally better to use callLater as it won't cause any unneeded computation.

Addendum: invalidate functions

Unless you are writing your own component you won't need to worry about invalidateSize, invalidateDisplayList, and invalidateProperties. These are basically "make dirty" functions that tell flex "this component needs to run a validate function." If for some reason, a component (perhaps a custom component?) is failing to calculate or display something, these functions are an efficient way to tell the component it needs to do some processing. The Flex framework uses these functions internally to avoid unnecessary executions of the validate functions mentioned above.

Making a case against using your theme for functionality

As I'm teaching some friends the basics of Drupal I see a common mistake, putting too much functionality into the theme. The real problem with this is simple: the site's look and feel may change with or without the site's functionality. If you're using a custom theme, it's tempting to throw functionality right into page.tpl.php and call it a day. But you're setting yourself up for headaches. Trust me, I know from experience.

Once upon a time, I embedded views directly into my page template. It was simple, easy to do, and gave me the result I wanted. But when the designer handed me a brand new design it meant I had to manually move all of the views logic into the new theme... maybe that's not such a big deal but it felt ugly. If I had just put those views into blocks and created a region for it, I would have saved time.

Use Regions!

Most themes have 4 or 5 basic regions. Header, footer, left, right, content. But there's no limit to how many you can have. You can have one called "banana" if you want. All you need to do is put the region definition in your theme's .info file and

<?php print $banana; ?>

anywhere in your page.tpl.php file and you're done! Now you can assign blocks to that region and keep your code modular.

Use modules!

Modules are great! How many times did I look at the Google Analytics module and thing "man, that's stupid... why wouldn't I just put the JS in my page.tpl.php and forget about it?" Well, when your design changes and you forget to move that Google Analytics code you'll know that you should have just used the module. In addition, that module also gives you more integrated tracking and drupal specific features.

Drupal 7, Fusion, and new projects

I installed the latest build of Drupal 7, and I must say, it is going to rock! Many complaints against usability have been addressed.

This site is running on D6 and I just installed the Fusion base theme and I'm playing around with it. I'm really excited to use Prosper on an upcoming project. Those guys and gals over at TopNotchThemes know what they're doing.

FlexMonkey - MonkeyAgent doesn't work with references to Application

If you've got an app and are hoping to test it using FlexMonkey, be careful that you don't have any references to Application.application. This would normally return you a nice reference to your main app MXML file, but since MonkeyAgent is doing the loading, it will return you a reference to MonkeyAgent instead. Rather than change your code, I'd recommend using MonkeyLink. You need to include a bunch of stuff, but at least it works.

Another gotcha, compile your own MonkeyAgent and MonkeyLink projects because you can't run an app compiled with 3.4 in a MonkeyAgent compiled in 3.1. You will get incompatible override errors.

mod_speling CheckSpelling On, case insensitive drupal doesn't work with CleanURLS

If you're trying to do case-insensitive files with Drupal, forget about it! Unless you redo the whole mod rewrite stuff. basically when you request a file, the mod_rewrite shoots it through Drupal first as a query param. Even if you turn on CheckSpelling in apache, it won't work. I don't have a solution, except not to use mod rewrite or clean URLs. OR... not use CheckSpelling which is what most security experts recommend anyway. Make your choice!

new RW launched

Launched a new version of Raderwerks last night on top of a Drupal/Ubercart platform. Go get yourself some wheels!

Write your own jQuery accordions in 7 lines of code.

A lot of times, people want very specific functionality out of a jquery menu. There are at least 5 or 6 decent jQuery accordion menu plugins out there. But they're all overkill in my opinion.

A jQuery accordion can be as little as 3 lines of code. Here's one in 7 lines of code. And if you do some chaining, probably even less.

$('#accordion li ul').hide();
$('#accordion li a').click(function(){
	$(this).parent().addClass('selected');
	$(this).parent().children('ul').show('fast');
	$(this).parent().siblings().children('ul').hide('fast');
	$(this).parent().siblings().removeClass('selected');	
});

So how does this work? The first command hides all the sub-menus. Then you add a click listener to the item itself. When you click it, you add a "selected" class to its parent list element. That way you can style it appropriately if it is selected. Then you show the sub menu on the next line. Finally, hide all the siblings and remove their selected classes. Now, assuming you've got the CSS, XHTML structure in place... that's it. You are done my friend.

<ul id="accordion">
    <li><a>Item</a>
        <ul>
			<li><a href="#">sub item</a></li>
			<li><a href="#">sub item 2</a></li>
			<li><a href="#">sub item 3</a></li>
		</ul>
    </li>
	<li><a>Item 2</a>
        <ul>
			<li><a href="#">sub item</a></li>
			<li><a href="#">sub item 2</a></li>
			<li><a href="#">sub item 3</a></li>
		</ul>
    </li>
	<li><a>Item 3</a>
        <ul>
			<li><a href="#">sub item</a></li>
			<li><a href="#">sub item 2</a></li>
			<li><a href="#">sub item 3</a></li>
		</ul>
    </li>
</ul>

Very basic nested list elements.

Now let's add some CSS.

#accordion li a{cursor:pointer;text-decoration:none;}
#accordion li.selected {font-weight:bold;}

Here's a demo.

new site done

They're still adding content, so it's kind of bare at the moment, but I just launched a new site for DubAudi. This is a good example of PNG sprites.

Syndicate content