Magento – Programatic Quote, Order, Invoices

<?php
 
require_once 'app/Mage.php';
 
Mage::app('default');
 
$store = Mage::app()->getStore('default');
 
$customer = Mage::getModel('customer/customer');
$customer->setStore($store);
$customer->loadByEmail('email_address@gmail.com');
 
$quote = Mage::getModel('sales/quote');
$quote->setStore($store);
$quote->assignCustomer($customer);
 
$product1 = Mage::getModel('catalog/product')->load(166); /* HTC Touch Diamond */
$buyInfo1 = array('qty' => 1);
 
$product2 = Mage::getModel('catalog/product')->load(18); /* Sony Ericsson W810i */
$buyInfo2 = array('qty' => 3);
 
$quote->addProduct($product1, new Varien_Object($buyInfo1));
$quote->addProduct($product2, new Varien_Object($buyInfo2));
 
$billingAddress = $quote->getBillingAddress()->addData($customer->getPrimaryBillingAddress());
$shippingAddress = $quote->getShippingAddress()->addData($customer->getPrimaryShippingAddress());
 
$shippingAddress->setCollectShippingRates(true)->collectShippingRates()
                ->setShippingMethod('flatrate_flatrate')
                ->setPaymentMethod('checkmo');
 
$quote->getPayment()->importData(array('method' => 'checkmo'));
 
$quote->collectTotals()->save();
 
$service = Mage::getModel('sales/service_quote', $quote);
$service->submitAll();
$order = $service->getOrder();
 
$invoice = Mage::getModel('sales/service_order', $order)->prepareInvoice();
$invoice->setRequestedCaptureCase(Mage_Sales_Model_Order_Invoice::CAPTURE_ONLINE);
$invoice->register();
 
$transaction = Mage::getModel('core/resource_transaction')
                    ->addObject($invoice)
                    ->addObject($invoice->getOrder());
 
$transaction->save();
  • The $invoice->register() calls pay() in the Mage_Sales_Model_Order_Invoice class. This fires the event sales_order_invoice_pay which is useful for hooking into after an invoice has been paid for; E.g. automatically sending the invoice email upon creation:
   public function sendEmail(Varien_Event_Observer $observer)
    {
        $event = $observer->getEvent();
        /** @var Mage_Sales_Model_Order_Invoice $invoice */
        $invoice = $event->getInvoice();
        if(!$invoice->getEmailSent()){
            $invoice->sendEmail(true);
        }
    }

Emails in Magento: A Guide

Emails in Magento can be incredibly tricky. Firstly, you’ll want to define a field in system config for the template itself; the location of this field dictates the structure of the default node it uses to retrieve available templates and children.

<config>
    <tabs>
        <rayware translate="label" module="rayware">
            <label>Rayware</label>
        </rayware>
    </tabs>
    <sections>
        <rayware translate="label" module="rayware">
            <label>General</label>
            <tab>rayware</tab>
            <groups>
                <reg_email translate="label">
                    <label>Registration Email</label>
                    <fields>
                        <email_template translate="label description" module="rayware">
                            <show_in_default>1</show_in_default>
                            <show_in_website>1</show_in_website>
                            <show_in_store>1</show_in_store>
                            <label>Email Template</label>
                            <source_model>adminhtml/system_config_source_email_template</source_model>
                            <sort_order>10</sort_order>
                            <frontend_type>select</frontend_type>
                            <description>The template used to send new user reqistrations to rayware</description>
                        </email_template>
                    </fields>
                </reg_email>
            </groups>
        </rayware>
    </sections>
</config>

The class adminhtml/system_config_source_email_template finds its default using its own node structure by converting its slashes to underscores, and then looking in global/defaults/template/email so it’ll look here:

<global>
    <template>
        <email>
            <rayware_reg_email_email_template translate="label" module="rayware">
                <label>[Rayware] New Customer Email</label>
                <file>rayware/new-customer.phtml</file>
                <type>html</type>
            </rayware_reg_email_email_template>
        </email>
    </template>
</global>

So: The location of system config setting for the email template dictates where the actual template should live in global/template/email node.

Defaults

The structure of the system config node above dictates where the default should be located. In this instance, it’ll be the following – and the contents of the node should refer to the node name in global/template/email/ above

<default>
	<rayware>
		<reg_email>
			<email_template>rayware_reg_email_email_template</email_template>
		</reg_email>
	</rayware>
</default>

Sending Emails

$mailTemplate = Mage::getModel('core/email_template');
$mailTemplate->setDesignConfig(array(
	'area' => 'frontend',
	 'store' => Mage::app()->getStore()->getId()
));

$mailTemplate->sendTransactional($templateId, $senderName, $toEmail, $toName, $bind = array(), $storeId = null);
  • Templateid can either be a string or a number, if it’s retrieved from the config then it’ll be worked out automatically if the value has been saved. For the current example, Mage::getStoreConfig(‘rayware/reg_email/email_template’); would be used
  • Sender Name – this refers to one of the transactional sender names in the admin. The name entered here is used to look up a config path in Mage::getStoreConfig(‘trans_email/ident_’ . $sender . ‘/name’);
  • toEmail – the email to send to, this can be an array of email addresses
  • toName – the name of the person to send the email to – this can be an array of names
    bind – array of variables which can be used in the email (See directives)

Templates

Define what variables are available in the email using comments at the top of each email file. The subject is also defined in this way.

logo_url and logo_alt are populated from the admin area. The purpose of variables is to allow easy inserting of them from the admin area – this would appear to be their only purpose. The part after the colon is the part which will be shown in the dropdown in the admin (the user friendly name).

<!--@subject Your Quote #{{htmlescape var=$quotation.quote_id}}@-->
<!--@vars
{"store url=\"\"":"Store Url",
"var logo_url":"Email Logo Image Url",
"var logo_alt":"Email Logo Image Alt"}
@-->

Email template files live in app/locale/<<country_CODE>>/template/email/ where country code is the code of the country set in the admin area.
The templates can also be placed in en_US, which is the last level of fallback.

Email templates in the database live in the core_email_template table.

Any of the vars can be placed in the subject field using the above, E.g:

<!--@subject {{var title}}@-->

Directives

Var

Used to pull out any variables which are passed in to the template via the ‘bind’ parameter. Methods can also be called on passed in variables on the email objects:

{{var subscriber.getConfirmationLink()}}
{{var passedInVariable.horse}}
$bind = array(
    'passedInVariable'  => array(
        'horse' => ‘Moose’
    }
);

Block

Creates the block, and sets the parameters on them (or calls the methods). If type is not set as a parameter

{{block type=‘cms/block’ customVar=‘1’ methodToCall=‘test’}} 

Protocol

{{protocol}} -current protocol http or https
{{protocol url="www.domain.com/"}} domain URL with current protocol
{{protocol http="http://url" https="https://url"} - also allow additional parameter "store"

Config

{{config path="path/to/config}}

CustomVar

{{customvar code="custom_var_code"}}

Inlinecss

{{inlinecss file="path/to/file.css"}}

Layout

Loads the layout handle specified and sets all variables on each of the blocks in the layout handle. Methods can also be called on the blocks in the layout handle using this method, if they exist. “area” can also be set as a parameter but will default to the current area if not. Most likely this will be ‘frontend’.

{{layout handle="my_custom_layout_handle_to_be_used" variable="test" method="moose"}}

Skin

Embeds the url to a skin asset.

{{skin url="path/to/asset.ext"}}

Media

Embeds a media url.

{{media url="path/to/media/asset.ext"}}

Store

Get the URL for the store. If the url doesn’t end in a suffix, then ‘URL’ can be used, otherwise, direct_url should be used instead. Parameters can also be passed into the url using the syntax _query_paramName=”paramValue”.

{{store url="contacts"}} // http://dave.magento.store/contacts/
{{store direct_url="html_file.html"}} // http://dave.magento.store/html_file.html
{{store direct_url="goosey.html" _query_param="horseparam"}} // http://dave.magento-test-2.iweb/goosey.html?param=horseparam

htmlescape

Escapes the variable which is passed in from the bind array. certain tags can also be ignored using the allowed_tags parameter

{{htmlescape var="<b>Moose</b>" allowed_tags="b"}} // This would output the moose and keep the bold tags unescaped. See the var directive above for referencing bind params in the same way for htmlescape.

Email (& Static Block) Directives

Var

Used to pull out any variables which are passed in to the template via the ‘bind’ parameter. Methods can also be called on passed in variables on the email objects:

{{var subscriber.getConfirmationLink()}}
{{var passedInVariable.horse}}
<?php
$bind = array(
	'passedInVariable'  => array(
		'horse' => 'Moose’
	}
);

Block

Creates the block, and sets the parameters on them (or calls the methods). If type is not set as a parameter

{{block type='cms/block’ customVar='1’ methodToCall='test’}} 

Protocol

{{protocol}} - current protocol http or https
{{protocol url="www.domain.com/"}} domain URL with current protocol
{{protocol http="http://url" https="https://url"}

Config

Puts a system config setting into the email

{{config path="path/to/config"}}

CustomVar

{{customvar code="custom_var_code"}}

InlineCss

This is used in Magento’s new email styling method. Styles from the CSS file specified are “Emogrified” and placed into style tags on the corresponding elements.

{{inlinecss file="path/to/file.css"}}

Layout

Loads the layout handle specified and sets all variables on each of the blocks in the layout handle. Methods can also be called on the blocks in the layout handle using this method, if they exist. “area” can also be set as a parameter but will default to the current area if not. Most likely this will be ‘frontend’

{{layout handle="my_custom_layout_handle_to_be_used" variable="test" method="moose"}}

Skin

Embeds the url to a skin asset, _secure can be used if required.

{{skin url="path/to/asset.ext" _secure="true"}}

Media

Embeds a media URL, _secure can be used if required

{{media url="path/to/media/asset.ext" _secure="true"}}

Store

Get the URL for the store. If the url doesn’t end in a suffix, then ‘URL’ can be used, otherwise, direct_url should be used instead. Parameters can also be passed into the url using the syntax _query_paramName=”paramValue”

{{store url="contacts"}} // http://dave.magento.store/contacts/
{{store direct_url="html_file.html"}} // http://dave.magento.store/html_file.html
{{store direct_url="goosey.html" _query_param="horseparam"}} // http://dave.magento-test-2.iweb/goosey.html?param=horseparam

Depends

Allows the contents of the depends to be omitted if the clause doesn’t hold true.

{{depend order.getIsNotVirtual()}}
<!-- Statemement -->
{{/depend}}

If

Allows the contents of the if to be omitted if the clause doesn’t hold true. Like depends, but allows the use of an else clause

{{if order.getIsNotVirtual()}}
<!-- Statemement One -->
{{else}}
<!-- Statemement Two -->
{{/if}}

Template

Allows templates to be inserted via a config path. The config paths in the example are from System > Config > Design > Transactional Emails

{{template config_path="design/email/header"}}
{{template config_path="design/email/footer"}}