Posted on Leave a comment

Installing Composer With Magento

To install Composer with Magento, you will need to have access to the ssh on your web hosting, if you don’t have this option, the suggestion is to create a virtual environment for your UAT environment that you can install prior to deployment to the production.

In this example, I was using “Turnkey Magento”, you can download the VM in the following link

https://www.turnkeylinux.org/magento

Follow the instruction to install and configure it. Then login to the root account. In this example I will be installing the “Fontis Australia Post” extension.

First things first, I will copy the composer.json file to the root of magento installation.

The content of the composer.json is as below

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
  "name":"fontis/australia",
  "type":"magento-module",
  "license":"OSL-3.0",
"description":"Provides essential functionality for Australian stores",
"homepage":"https://www.fontis.com.au/australia-magento-extension",
  "require":{
    "magento-hackathon/magento-composer-installer": "*",
    "fontis/auspost-api-php": "1.x",
    "fontis/composer-autoloader" : "*"  
  }
  "extra":{
    "magento-root-dir":"/var/www/magento"
  }
}

The composer.json file can be created manually in the location /var/www/magento

Once the composer.json configuration file is created, all that needs to be done is install composer (curl –O http://getcomposer.org/composer.phar) and run it:

    php composer.phar install

And that’s all. The listed packages and all their dependencies will be installed in the project.

The place where composer installs the libraries is a directory called vendor.

Should the contents of the composer.json file ever be changed, run

    php composer.phar update

and the new configuration will be applied.

That is also how you uninstall a package: you remove it from the require list in the composer.json and run composer.phar update.

Directory layout

Before we wrap up, there is one more thing that should be talked about. As mentioned before, composer installs libraries (and Magneto modules) into a vendor directory.

So this directory needs to be integrated somehow into the project.

When placed directly in a Magento root directory we would end up with a structure like this:

1
2
3
4
5
6
7
8
9
10
11
12
var/www/magento/
 ├── .git/
 ├── composer.json
 ├── composer.lock
 ├── index.php
 ├── app/
 ├── js/
 ├── lib/
 ├── media/
 ├── skin/
 ├── var/
 └── vendor/

This works, but you need to make sure that the vendor directory, and also the compser.json and composer.lock files aren’t accessable from a web browser.

Once this is done, you can then ftp the vendor directory out from your UAT environment (in this case the turnkey magento virtual machine) and put it into your production environment.

And last but not the least, the one file that is being modified by composer is Mage.php file located in

/var/www/magento/app/Mage.php

make a backup of the same file in your production environment, and ftp this file to your production folder

/magento/app 

Once this is done, you can go to the Magento System -> Configuration and configure the Fontis Australia Post extension.

Posted on Leave a comment

Custom shipping method in Magento

In this article, I will demonstrate how to write custom shipping in Magento, or to be more precise, two of them: standard shipping and express shipping, which is only available if none of your cart items exceeds specified weight threshold. Lets start by explaining how Magento handles shipping, and what would be needed to achieve our goal.


When looking for available shipping methods, Magento first gathers all available carriers. A “Carrier” represents a shipping carrier, just like in real world (ex. FedEx). Each carrier is represented with the class that extends Mage_Shipping_Model_Carrier_Abstract.

After list of carriers has been received, shipping information(implemented as Mage_Shipping_Model_Rate_Request) is sent to carrier in order to retrieve all available rates provided by given carrier, represented as Mage_Shipping_Model_Rate_Result.

This process happens in Mage_Shipping_Model_Shipping::collectRates() as seen in code below:

...
$carriers = Mage::getStoreConfig('carriers', $storeId);
 
foreach ($carriers as $carrierCode => $carrierConfig) {
    $this->collectCarrierRates($carrierCode, $request);
}
...

Function collectCarrierRates() is responsible for checking carrier availability (is carrier enabled in admin, is it available for requested country, etc.), and eventually triggers collectRates() function of your class, which we will implement later.

And that is general outline of what is going on behind the scenes. We are now ready to write some code that will fit nicely into everything explained above. First thing you will need to do, is create new module which depends on Mage_Shipping. Besides standard module configuration, you will have following inside your config.xml:

<config>
    ...
    <default>
        ...
        <carriers>
            <inchoo_shipping>
                <active>1</active>
                <model>inchoo_shipping/carrier</model>
                <title>Inchoo Shipping Carrier</title>
                <sort_order>10</sort_order>
                <sallowspecific>0</sallowspecific>
                <express_max_weight>1</express_max_weight>
            </inchoo_shipping>
        </carriers>
        ...
    </default>
    ...
</config>

Entries active, sallowspecific and express_max_items are config entries which will be used and explained later. We will start with model entry. You can see that our carrier will be represented with Inchoo_Shipping_Model_Carrier, so lets implement that class. As previously said, carrier needs to extend Mage_Shipping_Model_Carrier_Abstract and implement Mage_Shipping_Model_Carrier_Interface in order to ensure Magento can work with it. We will start by doing just that:

class Inchoo_Shipping_Model_Carrier
    extends Mage_Shipping_Model_Carrier_Abstract
    implements Mage_Shipping_Model_Carrier_Interface
{
    protected $_code = 'inchoo_shipping';

Next, our interface requires us to implement getAllowedMethods() which returns array of key-value pairs of all available methods, so let’s do that:

public function getAllowedMethods()
{
    return array(
        'standard'    =>  'Standard delivery',
        'express'     =>  'Express delivery',
    );
}

Finally, we said that rates are collected by calling collectRates(). This function takes shipping information as parameter, and returns all available rates. It is also responsible for determining which rate is available for given request:

public function collectRates(Mage_Shipping_Model_Rate_Request $request)
{
	/** @var Mage_Shipping_Model_Rate_Result $result */
	$result = Mage::getModel('shipping/rate_result');
 
	/** @var Inchoo_Shipping_Helper_Data $expressMaxProducts */
	$expressMaxWeight = Mage::helper('inchoo_shipping')->getExpressMaxWeight();
 
	$expressAvailable = true;
	foreach ($request->getAllItems() as $item) {
	    if ($item->getWeight() > $expressMaxWeight) {
		$expressAvailable = false;
	    }
	}
 
	if ($expressAvailable) {
	    $result->append($this->_getExpressRate());
	}
	$result->append($this->_getStandardRate());
 
	return $result;
}

As you can see, code is pretty straight forward: Weight of all products in cart are compared to value stored in config, which determines availability of our ‘express‘ rate. Our ‘standard‘ rate is always available. Each rate is added by passing Mage_Shipping_Model_Rate_Result_Method object to append() of our result object. And we get those rate objects by calling _getExpressRate() and _getStandardRate(), which are implemented as following:

protected function _getStandardRate()
{
    /** @var Mage_Shipping_Model_Rate_Result_Method $rate */
    $rate = Mage::getModel('shipping/rate_result_method');
 
    $rate->setCarrier($this->_code);
    $rate->setCarrierTitle($this->getConfigData('title'));
    $rate->setMethod('large');
    $rate->setMethodTitle('Standard delivery');
    $rate->setPrice(1.23);
    $rate->setCost(0);
 
    return $rate;
}

And that’s all that our class needs in order to work. We will finish up by adding admin configuration through system.xml. Here is an shortened version:

<config>
    <sections>
        <carriers>
            <groups>
                <inchoo_shipping translate="label">
                    ...
                    <fields>
                        <active translate="label">
                            ...
                        </active>
                        <title translate="label">
                            ...
                        </title>
                        <sallowspecific translate="label">
                            ...
                            <frontend_type>select</frontend_type>
                            <frontend_class>shipping-applicable-country</frontend_class>
                            <source_model>adminhtml/system_config_source_shipping_allspecificcountries</source_model>
                            ...
                        </sallowspecific>
                        <specificcountry translate="label">
                            ...
                            <frontend_type>multiselect</frontend_type>
                            <source_model>adminhtml/system_config_source_country</source_model>
                            ...
                        </specificcountry>
                        <express_max_weight translate="label">
                            ...
                        </express_max_weight>
                    </fields>
                </inchoo_shipping>
            </groups>
        </carriers>
    </sections>
</config>

What is important to note here, is that active, title, sallowspecific and specificcountry are handled automatically by Magento, so besides adding this to admin, you aren’t required to do anything else. With others being self explanatory, there are only two options being interesting here. First one, sallowspecific, tells Magento should carrier be available for all countries, or only for once that are specified in specificcountry.

And that is all work required for our shipping method to appear on checkout step. This module has been written as an example for Magento CE 1.9.0.1.

Posted on Leave a comment

Configuring Magento for Australian Store

I stumble across the following instruction to setup the Australian store for Magento 1.xx

Running Magento stores in Australia differs very little from any other country, but there are a few things that you need to do for compliance with ATO requirements and to ensure that Magento calculates taxes correctly. The following is an outline of the necessary configuration and settings you may need to consider when setting up Magento for an Australian store.

First, the basic information for the store must be configured for Australia:

System → Configuration → General
Countries options

  • Default country = Australia
  • Allow countries = ensure Australia is selected

Locale options

  • Timezone = AUS Eastern Standard Time (Australia/Sydney) (as appropriate)
  • Locale = English (Australia)

Next, the currency must be configured for Australian Dollars:

System → Configuration → Currency Setup
Currency Options

  • Base currency = Australian Dollar
  • Default display currency = Australian Dollar
  • Allowed currencies = ensure Australian Dollar is selected

Shipping settings are important for shipping, and also for tax calculation. You should enter information appropriate for your shipping location, which must be in Australia for shipping and tax calculations to work correctly.

System → Configuration → Shipping Settings
Origin

  • Country = Australia

To set tax correctly for Australia (prices shown include GST) and to apply discounts correctly, the following should be set:

System → Configuration → Tax
Tax Classes

  • Tax Class for Shipping = Shipping

Calculation Settings

  • Tax Based On = Shipping Address
  • Catalog prices include tax = Yes
  • Shipping prices include tax = Yes
  • Apply Tax After Discount = Yes
  • Apply Discount On Prices Including Tax = Yes
  • Apply Tax On = Custom price if available

Default Tax Destination Calculation

  • Default Country = Australia

Display

  • Display Cart/Order Prices = Including tax
  • Display full tax summary = No
  • Display Shipping Prices = Including tax
  • Display Product Prices = Including tax

These settings will instruct Magento that all prices entered into the system already include GST (which is most common for Australian retailers) and that prices displayed to the customer should be displayed including tax. You may need to adjust the settings for shipping appropriately, depending on whether your chosen shipping method should include GST or not.

Please note that the upcoming release has some changes to these settings. For Community Edition 1.4 (and Enterprise Edition 1.6), use the following instead:

System → Configuration → Tax
Tax Classes

  • Tax Class for Shipping = Shipping

Calculation Settings

  • Tax Calculation Method Based On = Total
  • Tax Calculation Based On = Shipping Address
  • Catalog prices = Including tax
  • Shipping prices = Including tax
  • Apply Customer Tax = After Discount
  • Apply Discount On Prices = Including tax
  • Apply Tax On = Custom price if available

Default Tax Destination Calculation

  • Default Country = Australia

Price Display Settings

  • Display Product Prices In Catalog = Including tax

Shopping Cart Display Settings

  • Display Prices = Including tax
  • Display Subtotal = Including tax
  • Display Shipping Amount = Including tax
  • Include Tax in Grand Total = No

Order, Invoices, Creditmemos Display Settings

  • Display Prices = Including tax
  • Display Subtotal = Including tax
  • Display Shipping Amount = Including tax
  • Include Tax in Grand Total = No

The easiest way to meet the ATO requirements for ABN and contact number on invoices is to add these details to your address information:

System → Configuration → Sales
Invoice and Packing Slip Design

  • Address = your address + ABN and phone number

You might also choose to add this information to the transactional email template for invoices. If you want to use the PDF invoices however you will need to alter the address above or modify the PDF rendering, which we may cover in another post.

To set up the 10% GST to be applied on products and shipping, Magento requires the addition of an appropriate tax rate and rule:

Sales → Tax → Manage Tax Zones & Rates
Here we add a tax rate for GST so that Magento will know how much tax to calculate.

To add a rate, click Add New Tax Rate in the top right and fill out the following information:

  • Tax Identifier = GST
  • Country = Australia
  • State = *
  • Zip/Post Code = *
  • Rate = 10.00

Save the rate and proceed to set up a rule for GST.

Sales → Tax → Manage Tax Rules

Tax rules determines when rates should be applied. In this case we want to set it up to apply GST anywhere in Australia.

Click Add New Tax Rule in the top right and fill out the following information:

  • Name = GST
  • Customer Tax Class = Retail Customer
  • Product Tax Class = Taxable Goods | Shipping
  • Tax Rate = GST

Save the rule and GST will be completely set up. It’s a good idea to remove any other tax rules that are present by default, unless they will also be relevant for you.

Rename Tax to GST

Something that is often overlooked is that you must include a line in your invoices specifically indicating the amount of GST that has been applied. This can be done in a few ways but a simple method is to use the translation files included as part of the locale. This allows for easy replication across websites by copying the files from one site to another.

To modify the translation, creating an app/locale/en_AU directory and copy the Mage_Sales.csv file from the en_USlocale into it. Open this file as a spreadsheet (such as in Excel or OpenOffice.org) and find the line with the word “Tax”. Modify the value in the right column to be “GST”. This will appropriately change the text that is displayed to the customer.

Rename Invoice to Tax Invoice

Similar to the above, you can edit the translation files to change the text “Invoice” to “Tax Invoice”. This is left as an exercise for the reader.

Posted on Leave a comment

WordPress site stuck in maintenance mode

When you are doing some maintenance, e.g.: updating the plugin on your wordpress site, it will automatically set the maintenance page. This is done by setting the .maintenance file in your root directory of the wordpress site. If the update timeout or if you accidentally goes out from the admin page while the update is still going, your site will be stuck in maintenance mode. And showing the following message:

Briefly unavailable for scheduled maintenance. Check back in minute

To fix this issue you can delete the .maintenance file from the root directory of your wordpress via ftp into your wordpress site.

jetpack update issue

If you are in the middle of updating the “jetpack” plugin, there are chances that the site will not work after deleting the .maintenance file. To fix this second issue, delete the jetpack folder in your wordpress plugin directory. This is usually located in

  • wp-content
    • plugins -jetpack