10 September 2010

Get Tracking Information from Magento via Order Number

Pretty straight forward query to get the core shipping information out of  in magento for  v 1.4.1 (will not work pre 1.4x tables changed)

select  shp.number, shp.title, shp.carrier_code, shp.updated_at, flt.shipping_description
 from `magento_store`.`sales_flat_order` as flt
 left join `magento_store`.`sales_flat_shipment_track` as shp
 on (flt.entity_id = shp.order_id)
 where flt.increment_id = '$order_id';

I use a WordPress install to interface with the Magento DB to stress server less.

Don’t forget that the 1.4x shipping API for Magento is B-U-S-T-E-D as of this writing. Here is the link I found:

http://magebase.com/magento-tutorials/shipment-api-in-magento-1-4-1-broken/

28 May 2010

Advanced application of Options in Simple Products

I wanted to drop some notes in there to helpfully assist someone who might be doing weird stuff in Magento like I am.

As short as possible – a current project uses a custom design interface for our products (in Flash) for the final sell-able item.  Every item is a unique design on a “stock” product.

In the end of the design process the design is serialized (in the sense of being unique).  The problem was simple – how do you get the serial # in the cart with the item and pass through the product option phase (not directly to cart).

At first you say – No Problem! Use the

?option[##]=stuff

- not so simple.

After the design options need to be selected like material type or what ever.  So here is some of  my solution…

You can AJAX in your results if you want, but this jumps over the “options” phase of the product page.  Your ajax string looks like this (we can’t use .htaccess rewrites because of Flash – BOO!)

AJAX CALL PROTOTYPE : [code]/index.php/checkout/cart/add/product/113/?options[27]=17067[/code]

27 = option ID and 17067 is our generated serial#

Wrap and trigger that JS how you want.

Ultimately I had to inject a hidden input (dynamically) – the input looks like this:

$inputStr = '<input type="hidden" value="'.$_GET['serial'].'" name="options['.$ret.']">';

This input is printed inside the form here:

…./template/catalog/product/view.phtml

Where the $_GET['serial'] is the unique design instance appended to the product page (generated by a call to the PHP header() function using variables returned form our designer – buncha sick tight queries and code to do this!)

The $ret is the option # for the product. This is returned form a backwards query on the item/sku in Magento.

The basic function is:

// this is actually encapsulated in a class and I leave it as a public static function....
function get_option($product_id){
 $product_id = mysqlEscapeString($product_id);
 $write = Mage::getSingleton('core/resource')->getConnection('core_write');
 $readresult=$write->query("SELECT option_id FROM catalog_product_option WHERE product_id = $product_id AND sku = 'serial';");
 $row = $readresult->fetch();
 if (intval($row['option_id'])>1) {
 return mysqlEscapeString($row['option_id']);
 }else{
 return false;
 }
// there is a lot of room in this  do what you want!

mysqlEscapeString is a local function that preps data for use in MySQL – replace with your favorite one…

This function is fed the Magento product ID (easy to get that info) “serial” is the sku of the option in Magento (we use one sku for all of these product options making things simple)

One of the reasons why I am putting this post up is to warn people on some odd stuff and failures.  I am not about to worry too much on the how and why, instead let me tell you that they fail-xor.

The fail:

The AJAX call above works well BUT if you apply a “?option[##]=#### to the form action by appending to the

this->getAddToCartUrl($_product);

on the file

…./template/catalog/product/view.phtml

The /uenc/STUFF-HERE in the form action”THATLINK”will see extra garbage.

That garbage will cause failure when the form is submitted.  The “garbage”is totally weird and I stopped caring how/why. In short I was getting the standard UENC/STUFF with an underscore and other alpha-numeric info added. This would break the form submission.

So don”mess with the action URL!

I hope this helps, drop a note if you need more or clarification.  This was a long battle in creating a hybrid between a legacy system and Magento.

Closing note – you can not do this in Magento with the Wishlist.  Your expectation of the wishlist operating like a “holding area” that is a parallel dimension to the cart is wrong.  This “stamping” of the product instance with my required serial # is not possible in the wishlist. (**cough Hint Magento team**)

Until this is dialed in (if ever), I wired in our own custom design manager.  Now back to that work…

12 April 2010

GoDaddy 554 Error gone horribly wrong

Short and sweet, if and when I am found to be in error let me know so I can update.

Define the players:

  • Email thread between me and 2 other people me@somegodaddyhostedemail.com and person1@gmail.com and person2@hotmail.com
  • Also, there is a site referred to as referencedsite-inmessagebody.com – copied and pasted in the discussion.

Timeline, crude but true:

  1. Email string gets big, 10+ responses
  2. Suddenly email only yeilds massive 554 errors from GoDaddy – no option to avoid fail
  3. Email programs and (my) IP address changes with no effect on the final outcome.
  4. Call GoDaddy, they scan the issue email.
  5. Answer: referencedsite-inmessagebody.com has an associated PBL entry (http://www.spamhaus.org/pbl/) via the IP address associated with the domain.

We now stop and look at the problem.

The site referencedsite-inmessagebody.com is associated with an ip address that has a PBL listing.  In short it could be said that referencedsite-inmessagebody.com sent spam or had mail flagged as spam and made it on the naughty list.

Moving forward with the assumption that referencedsite-inmessagebody.com is not one of the real offenders of spam on the net. We have to ask WTF?

Well, the WTF turns out to be just plain evil wrapped in evil.

I drop a WhoIs on referencedsite-inmessagebody.com and find out they are on a large shared (virtual) host. We all use similar services.

I happen to know this host, I use them.  Generally I think the company runs 200+ clients per server.

What follows is a wild summary of the conversation I had with the tech at GoDaddy (he was cool and honest).

Any idiot on a virtual host can start spamming, get busted, loose account and flag the (shared) IP . That means  referencedsite-inmessagebody.com is  pretty much doomed along with any emails associated to that domain name, regardless of the location of the email server (as far as IP address goes).

Doomed to the point where (the actually broken GoDaddy protocol) is blocking my email because my message body has a “flagged” http address (with associated PBL flagged IP address).

Is there anything to be done – Nope. I asked they guy straight up, should I just move my emails off or is there something we can  do such as petitions.

His response was “don’t even try”.

My Solution is to move all these email accounts onto a leased server with dedicated IP address I can get unflagged if ever necessary and run no risk of colliding with “some idiot”.

Ever wonder why certain stuff will NEVER EVER make it from one email to another, this is a clear outline of a protocol that will (often silently) kill your communication.

Emergency Workarounds are available and cumbersome for the low-tech.  I suggest instant messaging and file sharing sites.  You can create a real time one-to-one connection with your target and provide information to get the data.

File sharing services (of the professional type) are also a good alternative for moving files, but this is not a solution for general text communication over email.

Let’s close out with a list of things you should not do:

  • Do not use shared hosting with out a dedicated IP
  • Do not use any service like GoDaddy who utilizes services like SpamHaus
  • Do not reference any website in your email or only write them as “domain[dot]com”

And one more important “beware“:

  • Beware the dynamic IP address. (Who knows how many IP’s we all share are flagged and/or associated with strange shit)

With that in mind email becomes a rather difficult form of communication.

I was taking no responses personally when they were dying or errored out. Going to have to meet people face to face  to talk.

OMG.

16 February 2010

CSS Compression with nothing more than your brain

Right now I am compressing some CSS into a slimmer package. This is only one of a few steps, but this little bit of planning and thought will save a lot of time in the end.  Especially when your CSS file is 2000+ lines and already formatted in line to decrease line count.

The original:

#iz_catnav {
    background: url(/add/images/left_nav_rpt.png) repeat;
    width:185px;
    padding:4px 0px 4px 0px;
    overflow:hidden;
}
#catNavCap {
    height:30px;
    width:185px;
    background: url(/add/images/left_nav_cap.png) no-repeat;
    margin:0px;
    padding:0px;
}
#catNavBase {
    height:30px;
    width:185px;
    background: url(/add/images/left_nav_base.png) no-repeat;
}

compacted:

#iz_catnav, #catNavCap, #catNavBase  {
    background: url(/add/images/left_nav_rpt.png) repeat;
    width:185px;
    padding:4px 0px;
}
#catNavCap, #catNavBase {
    height:30px;
    margin:0px;
    padding:0px;
}
#catNavCap, #catNavBase {
    background: url(/add/images/left_nav_cap.png) no-repeat;
}
#catNavBase {
    background: url(/add/images/left_nav_base.png) no-repeat;
}

So, minor gain, a 2 line reduction. From 18 lines to 16 lines. Just over 10% reduction.  Think about that on the scale of thousands of lines of CSS. Then compound that with “smart” design and setting up better patterns in your CSS including Object-Orientated CSS where standard attributes are wrapped up in a well defined document.

How many times are you Floating?  What if there was compressed style sheet with all your common needs defined in classes.  Nice huh? That is the idea behind OO-CSS – more reusable objects (classes).

8 February 2010

Magento E-Commerce bare as all hell navigation

Need to get the Product categories output for custom scripts (like I am doing).  Here is a basic prototype to begin:

// Nevermind - this will not make subcats, the children are all from the main
$obj = new Mage_Catalog_Block_Navigation();
$store_cats    = $obj->getStoreCategories();
$current_cat     = $obj->getCurrentCategory();
$current_cat    = (is_object($current_cat) ? $current_cat->getName() : '');

foreach ($store_cats as $cat) {
  echo '1- '.$obj->getCategoryUrl($cat).' 2- '.$cat->getName().' - -';
  foreach ($obj->getCurrentChildCategories() as $subcat) {
    echo 'A- '.$this->getCategoryUrl($subcat).' B- '.$subcat->getName();
  }
}

// author : @marwei / datamafia.com / interzonemultimedia.com
// Check this out! for one level deep cat menu that you can place anywhere

// get your object
$navobj = new Mage_Catalog_Block_Navigation();
$store_cats    = $navobj->getStoreCategories();

// open the list
$ret = '<ul id="corpDesMageNav">';
// parent cat loop
foreach ($store_cats as $cat) {
 $ret .= '<li>'.$cat->getRequestPath().' - '.$cat->getName().'</li>';
 $subcats = $cat->getChildren();
 // one deep subcategory
 $subCtr = 0; // for counting in the next foreach
 $closeUL = false;
 // reset the trigger // Child cat / one deep loop
 foreach($subcats as $kid){
 if ($subCtr==0) { // first itteration opens the (nested) <ul>
 $ret .= '<ul style="margin-left:20px;"><!-- Only a helper for the subcat -->';
 $closeUL = true;
 }
 $subCtr++;
 $ret .= '<li> [sub cat] '.$kid->getRequestPath().' + '.$kid->getName().'</li>';
 }
 if ($closeUL == true) { // close the ul based on event trigger
 $ret .= '</ul>';
 }
}
$ret .= '</ul>';
echo $ret;

Notes on the (revised) above content. Most (but not all???) of the methods from the Class work (Magento reference).  The above example provides you with the big pieces of information. The Cat Name and the Cat Link.

More importantly – this method allows you to use the menu system ANYWHERE! You are not working with $this->stuff, instead you are dropping isolated instances. My need arised because we are switching in important legacy information and programs in the middle of Magento.   Trust me when I say No ecommerce software was ready for what we are doing.

So I can drop in custom scripting in the content pane using a simple content controller and variable sniffer inside the Magento system and then drop menus and such with out head ache.

The example is FAR from your final output, but this is enough for a programmer with medium skill to get a custom navigation going.  My output has some “garbage” in there to help look at the category information. It should only take a minute to clean it up and check Strict.

And, as a friendly reminder, watch your “default category”.  Magento (at the time of this post) reads from the top level category, no exceptions.  There is plenty of documentation on this topic in the forums.

I hope this helps, let me know if you need more!

/*
 ONE FINAL EXAMPLE - 3 levels deep!!!!
 If anyone wants to write this into a fully recursive function/class let me know. I only need 3 deep
Adding another nested foreach is easier than a unit test on recursion.
*/

// get your object
$navobj = new Mage_Catalog_Block_Navigation();
$store_cats    = $navobj->getStoreCategories();

// open the list
$ret = '<ul id="corpDesMageNav">';
foreach ($store_cats as $cat) {
 $ret .= '<li>'.$cat->getRequestPath().' - '.$cat->getName().'</li>';
 $subcats = $cat->getChildren();
 // one deep subcategory
 $subCtr = 0; // for counting in the next foreach
 $closeUL = false;
 foreach($subcats as $kid){
 if ($subCtr==0) { // first itteration opens the (nested) <ul>
  $ret .= '<ul>';
  $closeUL = true;
 }
 $subCtr++;
 $ret .= '<li style="margin-left:10px;"> [sub cat] '.$kid->getRequestPath().' + '.$kid->getName().'</li>';
 // ome more deep - we got children?
 $subSubCtr = 0;
 $closeSubUL = false;
 if($kid->hasChildren()==1){
  $subSubCat = $kid->getChildren();
  foreach($subSubCat as $grandKid){
   if ($subSubCtr==0) { // itteration opens the (nested) <ul>
   $ret .= '<ul>';
   $closeSubUL = true;
  }         
  $ret .= '<li style="margin-left:20px;"> [sub sub cat] '.$grandKid->getRequestPath().' + '.$grandKid->getName().'</li>';
 }
 if ($closeSubUL == true) { // close the ul based on event trigger
  $ret .= '</ul>';
 }
}
}
 if ($closeUL == true) { // close the ul based on event trigger
 $ret .= '</ul>';
 }
}
$ret .= '</ul>';
echo $ret;
8 February 2010

Programmer begins to go crazy when coffee is too weak

Working on some application and I wrote this comment:

include $_SERVER['DOCUMENT_ROOT'].'/######.#####.php';
/* this file includes switching and error handles/ This has to be on the
root (or you will need to hire a song and dance man with a one trick
pony, a knife, 2 avocados, an icepick, and a pastry blender)

Comments are the programmers legacy.  Some people consider the program to be the legacy (Caprica even referenced this idea).  The comments are the communication to the piers.  The piers need to know where you stand.  Sometimes this standing is honesty in stating

/* I know this is a bad way to do things, but the pay was not
enough to do this correct. When the database catches on
fire tell the boss they should have found another $500 */

More to come, coffee on the way.

3 December 2009

No, really Rackspace is good.

My history with Rackspace is growing.  New work puts me on a new dedicated server and in direct connection with the “fanatical” support.  So my problem was with the .htaccess file and mod_rewrite (Apache) functionality.

After spending the evening looking up “Rackspace htaccess” searches most information comes in relating to the cloud hosting (also referred to as Mosso). Not the same thing. I have reached success and I wanted to put my $0.02 into the blog-o-sphere.
More On This

21 August 2009

Tables are Back?

Yes, one man (Guido van Rossum), greater than ALL the CSS layout people combined said:

http://twitter.com/gvanrossum/status/3454080762

To quote:

I’ve abandoned the “don’t use tables for layout” meme. The CSS contortions to replace it really aren’t worth it

What to say?

28 July 2009

I do not own much Sampson equipment, but this sure did catch my eye.
More On This

6 July 2009

Twitter is here to stay!

With my DNS service experiencing a fire and the control panel going down down down I am finally catching up on some overdue DNS settings.  The first thing is to point the domain onto the “pay-for” name servers. This requires a stop in the GoDaddy DCC (you know, the over ajax’ed control panel of lag). Well, look at what popped up today: More On This