My experience with a 50 hour hackathon and why you should attend one too

My experience with a 50 hour hackathon and why you should attend one too

Few months ago I decided to attend a hackathon because it’s something I have been wanting to do for a long time. Like any other first experience, I didn’t know what to expect. Just the term hackathon can sound scary and intimidating. Let me share my story and then you can decide what a hackathon actually implies. Here are some hints in case I’ve already scared you: a fun, relaxed event with amazing people and cool technology.

For my first hackathon ever, I’ve decided to attend MegaHack, which took place in Cluj-Napoca.

At this event, there were listed challenges from different fields and, fortunately for me, one of them was a challenge on Magento. The main reason I took it is because I like working with the Magento platform and I wanted to see if I could complete the challenge in that given time.

In each challenge there was a team with no more than 5 members. I initially registered as an individual, thinking I would have the opportunity to meet new people that had already been working with Magento or people who wanted to know more about it. In the end, 2 other members joined me and we formed a team called MagentoCrew. Because the Magento community is quite small in Cluj-Napoca, those 2 members also happen to be my friends. So we were off to a good start already.

The final team members were:

After we created our team and set up our laptops, we discussed the requirements with the challenge owner. Here are the Magento challenge steps as described by the owner:

In Romania, the National Agency for Fiscal Administration (NAFA) has to organize public auctions in order to decide upon a company that offers shipping, tracking and courier delivery services. These kinds of auctions involve a lot of bureaucracy and usually take a lot of time. In order to simplify the process, we want to create a warehouse system where buyers can book and pick up their products from.

Challenge steps:

  • Develop a Magento module (1.9.2.4 or 1.9.3.1 if it launches before) to do the following: multi-warehouse inventory tracking at the product level
  • Display product page warehouses where the product is available
  • Filter category page products by particular warehouse location
  • Display in checkout delivery method "Lifting the deposit" mentioning the deposit (or deposits) where the products are located
  • (Bonus) display in order confirmation email deposit for each product
  • (Bonus) create a shipment only with products from a particular warehouse (thus, the staff will make a shipment with goods only from warehouse Galati and send them by mail to prepare products)

The module must be done with modman and include a readme.md file. Any resources (static blocks, attributes, etc.) that are required must be created through SQL scripts / install mode. The module should include translations ro_RO and en_US.”

Long story short, we had to create a warehouse module that would use modman (Magento module manager) in order to manage multiple warehouses and add stock to products. In the end, this is how we decided to implement our solution.

We first wrote the main module functionalities that we had to complete:

  • CRUD operations with warehouse on administration page
  • Warehouse filter on product listing
  • Warehouse information on product page
  • Warehouse information on products from shopping cart
  • Warehouse selection on the admin shipment process

After we assigned the module functionalities to each one of our team members, we discussed the technical approach.

The important module data was stored in DB with the following structure:

  • A DB table for the warehouse details with fields like:
    • Warehouse ID
    • Warehouse name
    • Warehouse email
    • Warehouse address
    • Warehouse code
  • A DB table for product link to warehouse with fields like:
    • The internal DB product ID from Magento product table
    • The internal DB warehouse ID from the above warehouse table
    • The stock quantity for a product in warehouse
  • Alter table sales shipment to contain a link to warehouse ID

We decided to implement a warehouse filter model on product listing page by using a separate table to store the product link to warehouse. In Magento, you can use a product attribute as a filterable data without needing to code, but we wanted to see how a new type of filter could be integrated in the layer navigation model.

The warehouse filter on product listing was my responsibility and I will explain the solution later on in this article.

The next part was the module creation. Before working on our individual tasks, we created the basic module with the main module directory structure, an installer for those 2 new tables and Magento models for warehouse and product warehouse link.

We used the last Magento Community version 1.9.3.0 with the latest PHP version 5.6 and MySQL 5.6. We worked on the following machine configurations:

  • Windows XAMPP
  • VM Linux setup with Vagrant using Nginx server
  • VM Linux setup with Docker using Nginx server

While CRUD operations were implemented, we made a sample SQL data with dummy warehouse information and product link to warehouse.

The CRUD operations on warehouse contained:

  • Adding a new admin controller using the “admin” router.
  • Extended classes as Widget type for Grid, Form, Tabs and Menu. Those classes are used for creating new administrative pages using the default admin theme.
  • Adding a tab where the product listing grid was displayed, in order to see the selected products or add new products and stock quantities for that warehouse. The implementation was using the same logic as the one used for the product related tab in the product edit administrative page.

The product stock can be updated in two ways:

  • By accessing Product edit page from admin interface.
  • By accessing Warehouse edit page from admin interface.

In the warehouse edit page, there is a section called "Manage Products". A product that is associated with a warehouse has an input for the available stock. When you add a stock in that input, the value will be added to the product’s general stock. The available warehouse stock will decrease when you ship a product from that warehouse.

In the shipment creation page, we added a warehouse selection possibility at the product level. A new layout XML file for the administrative section was used to set a new block class. Using this class we acquired the available warehouses of the item used in the order. For the purpose of having shipments per warehouse, we also implemented a new admin controller to process this selection made on shipment creation page.

As for the filter implementation, we created a new filter used only for the warehouse. Because we decided not to use the attribute filter model, we learned a lot on how a new filter will be created in Magento.

The implementation used by Magento for the layer navigation is not decoupling the filter block classes in a way that they can be easily added or removed. That’s why we were forced to add a new frontend layout XML file that allowed us to extend the current navigation block class with our block class. This was not the only class we were forced to overwrite. During my experience with Magento, I have seen Magento modules that use a rewrite method for navigation block classes in order to add features to this part and avoid default layout modifications. We didn't like this approach because we consider that the layout page needs to adapt in custom implementations, more precisely when adding a new feature.

This new filter implementation was integrated on product listing page and on the search results page. The layout configuration for filters page looks like this:

   
       
       
           
               
           
       
   
  
   
       
       
           
               
           
       
   

The next Magento block classes were extended in order to add support to our new filter:

  • Mage_Catalog_Block_Layer_View class - because the 4 types of filters are declared here and there is no way to add a new type of filter besides extending the class.
  • Mage_CatalogSearch_Block_Layer class - even if this extends the Mage_Catalog_Block_Layer_View class, we cannot extend to our new block class because, in that case, we need to copy the implementation from Magento to the new block class. So we chose to add the implementation for adding the new filter in this class also. At that moment that was our decision, but this can be avoided by using duplicated code in another class.

We were forced to remove the current block name used on the default layout in order to add our block filter class. This change causes custom themes or custom filter layout modules to not work with our module. If someone adds new catalog filter navigation modules, there will be conflicts at the code level.

The new Magento filters need to have the following classes in order to be integrated with the current layer filter:

  • a block class that will extend the Mage_Catalog_Block_Layer_Filter_Abstract class;
  • a model class that will extend the Mage_Catalog_Model_Layer_Filter_Abstract class.

Our block class MagentoCrew_Warehouse_Block_Catalog_Layer_Filter_Warehouse only has the filter model instantiation to our filter model class in the class constructor:

class MagentoCrew_Warehouse_Block_Catalog_Layer_Filter_Warehouse
   extends Mage_Catalog_Block_Layer_Filter_Abstract
{
   /**
    * Initialize filter model object
    */
   public function __construct()
   {
       parent::__construct();
       $this->_filterModelName = 'mc_warehouse/catalog_layer_filter_warehouse';
   }
}

The model class MagentoCrew_Warehouse_Model_Catalog_Layer_Filter_Warehouse used as warehouse filter on product collection will have:

  • The _requestVar property, which will be set with the value from the name of the URL parameter name used for selection of warehouse:
   /**
    * Set request filter variable
    */
   public function __construct()
   {
       parent::__construct();
       $this->_requestVar = 'warehouse';
   }
  • The name of the filter used on product page when you see the possible filters on the product listing page:
   /**
    * Get filter name
    * @return string
    */
   public function getName()
   {
       return Mage::helper('mc_warehouse')->__('Warehouse');
   }

Next, we applied warehouse filter to the current product listing collection based on the warehouse from the filters section of the page. When you choose a filter, a parameter with the name/id of the filter and the selected value will be sent in the URL using the HTTP GET method and will be submitted to the layer model. This is done by overriding the Mage_Catalog_Model_Layer_Filter_Abstract::apply method:

   /**
    * Apply category filter to layer
    * @param   Zend_Controller_Request_Abstract $request
    * @param   Mage_Core_Block_Abstract $filterBlock
    * @return  MagentoCrew_Warehouse_Model_Catalog_Layer_Filter_Warehouse
    */
   public function apply(Zend_Controller_Request_Abstract $request, $filterBlock)
   {
        $filter = (int) $request->getParam($this->getRequestVar());
        if (!$filter) {
            return $this;
        }
        $this->_warehouseId = $filter;
        $warehouse = $this->getWarehouse();
        if (is_null($warehouse)) {
            return $this;
        }
        Mage::register('current_warehouse_filter', $warehouse, true);
        $warehouse->addWarehouseFilterLayerNavigation($this->getLayer());
        $this->getLayer()->getState()->addFilter(
            $this->_createItem($warehouse->getName(), $filter)
        );
        return $this;
    }

Then, we got the current warehouses’ names used for current product listing. This is done by overriding the Mage_Catalog_Model_Layer_Filter_Abstract::_getItemsData method:

   /**
    * Get data array for building warehouse filter items
    * @return array
    */
   protected function _getItemsData()
   {
        $key = $this->getLayer()->getStateKey().'_WAREHOUSE';
        $data = $this->getLayer()->getAggregator()->getCacheData($key);
        if (!is_null($data)) {
            return $data;
        }
        $data = array();
        if (is_null($this->getWarehouse())) {
            $warehouseCollection = Mage::getModel('mc_warehouse/warehouse')
                    ->getCollection()
                    ->getWarehousesFromProductCollection(
                            $this->getLayer()->getProductCollection());
            $data = array();
            foreach ($warehouseCollection as $warehouse) {
                $data[] = array(
                    'label' => Mage::helper('core')->escapeHtml($warehouse->getName()),
                    'value' => $warehouse->getId(),
                    'count' => $warehouse->getProductCount(),
                );
            } 
        }
        $tags = $this->getLayer()->getStateTags();
        $this->getLayer()->getAggregator()->saveCacheData($data, $key, $tags);
        return $data;
    }

Based on this approach, multiple types of filters can be added in the same way. When the filter blocks are decoupled from the main view layer block class, we can only add the 2 classes above. Instead, we have added 5 classes and a layout XML configuration.

As for future improvements, we would like to implement the following functionalities:

  • Warehouse information on order email
  • Multiple warehouse stock rules on products
  • Add warehouse in product administration page

Our module can be found on https://github.com/razvanpojar1/megahack-magento.. We made it available for everyone in case somebody needs a basic free warehouse module in Magento. We think this code can be used as an example and we also wanted to share this solution.

So, was it worth it? Hell, yeah!

Not only did I learn a lot more about Magento, but most importantly I learned so much on how to collaborate with other developers in a totally new environment. The great thing about my team is that we worked incredibly well together. We all have different strengths and we capitalized on them by always being supportive, communicating and of course thinking positively.

If there is something I can recommend to all programmers who want to improve their skills, I would encourage them to join such competitions and to dive right in. And, by the way, it’s incredible how quickly time flies when you are surrounded by ambitious and equally caffeinated people :)


NO COMMENTS

Tell us what you think

Fields marked with " * " are mandatory.

We use cookies to offer you the best experience on our website. Learn more

Got it