Keeping it short. After I got Crackspace to turn on SOAP (yeah I know how, but we pay for these peep to do this for us!) we got some serious NO WORKY.
Mostly 500 errors, occasional 404 (mod_rewrite was dropping page not found error).
Hit the forums, over and over. Some seriously WACKED solutions and things going on. Nothing was working. Until I hit this post:
http://www.magentocommerce.com/boards/viewthread/42062/
In short Magento programmers FAILED hard core. Besides not testing, they are not even using intelligent IDE’s? (meaning my KoMoDo IDE picked up on the error instantly.
About the change, in the file /app/code/core/Mage/Api/Model/Server/Adapter/Soap.php at line 144 (approx) is this original code:
}else {
$this->fault('0', 'Unable to load Soap extension on the server');
return $this;
}
Where a “}” was missing:
else {
$this->fault('0', 'Unable to load Soap extension on the server');
} // <--- This one is missing, line 135
return $this;
}
Ouch.
So, on to getting this stuff working – fast version:
$proxy = new SoapClient('http://YourSite/api/soap/?wsdl');
$sessionId = $proxy->login('apiuser', 'apipassword');
// ****** Gets core info based on Sku
$products = $proxy->call($sessionId, 'catalog_product.info', 'productsku');
var_dump($products);
The above code will return an array / dump of the product info based on sku via a SOAP call.
You will need to get the api user and password as well as the role dialed in on the admin.
Good Luck.
Addendum : Need images, this will dump and array for the sku with image information:
var_dump($proxy->call($sessionId, 'product_media.list', 'productsku'));
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/
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…
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;