As we send shippment emails to customers, in this shippment email, we get tracking number from track.phtml and now the subject part of the email is like, order number and shippment number. I would like to change the subject of the email in which we are senidng as shippment emails. The subject has to be with tracking number. For order number we can get with "order.increment_id", But I dont know how to get the tracking number. SO how can I display tracking number in subject of email?
This cannot be done only by using a variable name like "order.increment_id" in the email template. You have to send the tracking data to the email template processor to achieve this with an example in 4 steps.
Step1>> Add Module configuration
In app/etc/modules/Eglobe_Sales.xml
<?xml version="1.0"?>
<config>
<modules>
<Eglobe_Sales>
<active>true</active>
<codePool>local</codePool>
</Eglobe_Sales>
</modules>
</config>
Step2>> Add config.xml(app/code/local/Eglobe/Sales/etc/config.xml)
<?xml version="1.0"?>
<config>
<modules>
<Eglobe_Sales>
<version>0.1.0</version>
</Eglobe_Sales>
</modules>
<global>
<models>
<sales>
<rewrite>
<order_shipment>Eglobe_Sales_Model_Order_Shipment</order_shipment>
</rewrite>
</sales>
</models>
</global>
</config>
Step3>> Override Mage_Sales_Model_Order_Shipment::sendEmail()
<?php
class Eglobe_Sales_Model_Order_Shipment extends Mage_Sales_Model_Order_Shipment {
/**
* Send email with shipment data
*
* #param boolean $notifyCustomer
* #param string $comment
* #return Mage_Sales_Model_Order_Shipment
*/
public function sendEmail($notifyCustomer = true, $comment = '')
{
$order = $this->getOrder();
$storeId = $order->getStore()->getId();
if (!Mage::helper('sales')->canSendNewShipmentEmail($storeId)) {
return $this;
}
// Get the destination email addresses to send copies to
$copyTo = $this->_getEmails(self::XML_PATH_EMAIL_COPY_TO);
$copyMethod = Mage::getStoreConfig(self::XML_PATH_EMAIL_COPY_METHOD, $storeId);
// Check if at least one recepient is found
if (!$notifyCustomer && !$copyTo) {
return $this;
}
// Start store emulation process
$appEmulation = Mage::getSingleton('core/app_emulation');
$initialEnvironmentInfo = $appEmulation->startEnvironmentEmulation($storeId);
try {
// Retrieve specified view block from appropriate design package (depends on emulated store)
$paymentBlock = Mage::helper('payment')->getInfoBlock($order->getPayment())
->setIsSecureMode(true);
$paymentBlock->getMethod()->setStore($storeId);
$paymentBlockHtml = $paymentBlock->toHtml();
} catch (Exception $exception) {
// Stop store emulation process
$appEmulation->stopEnvironmentEmulation($initialEnvironmentInfo);
throw $exception;
}
// Stop store emulation process
$appEmulation->stopEnvironmentEmulation($initialEnvironmentInfo);
// Retrieve corresponding email template id and customer name
if ($order->getCustomerIsGuest()) {
$templateId = Mage::getStoreConfig(self::XML_PATH_EMAIL_GUEST_TEMPLATE, $storeId);
$customerName = $order->getBillingAddress()->getName();
} else {
$templateId = Mage::getStoreConfig(self::XML_PATH_EMAIL_TEMPLATE, $storeId);
$customerName = $order->getCustomerName();
}
$mailer = Mage::getModel('core/email_template_mailer');
if ($notifyCustomer) {
$emailInfo = Mage::getModel('core/email_info');
$emailInfo->addTo($order->getCustomerEmail(), $customerName);
if ($copyTo && $copyMethod == 'bcc') {
// Add bcc to customer email
foreach ($copyTo as $email) {
$emailInfo->addBcc($email);
}
}
$mailer->addEmailInfo($emailInfo);
}
// Email copies are sent as separated emails if their copy method is 'copy' or a customer should not be notified
if ($copyTo && ($copyMethod == 'copy' || !$notifyCustomer)) {
foreach ($copyTo as $email) {
$emailInfo = Mage::getModel('core/email_info');
$emailInfo->addTo($email);
$mailer->addEmailInfo($emailInfo);
}
}
// Set all required params and send emails
$mailer->setSender(Mage::getStoreConfig(self::XML_PATH_EMAIL_IDENTITY, $storeId));
$mailer->setStoreId($storeId);
$mailer->setTemplateId($templateId);
$mailer->setTemplateParams(array(
'order' => $order,
'shipment' => $this,
'comment' => $comment,
'billing' => $order->getBillingAddress(),
'payment_html' => $paymentBlockHtml,
//setting the `track number here, A shihpment can have more than one track numbers so seperating by comma`
'tracks' => new Varien_Object(array('tracking_number' => implode(',', $this->getTrackingNumbers())))
)
);
$mailer->send();
return $this;
}
//Creating track number array
public function getTrackingNumbers()
{
$tracks = $this->getAllTracks();
$trackingNumbers = array();
if (count($tracks)) {
foreach ($tracks as $track) {
$trackingNumbers[] = $track->getNumber();
}
}
return $trackingNumbers;
}
}
Step4>> Modify your shipment email tempate subject by adding {{var tracks.track_number}}
Related
Is it possible to send two email in magento on order with different template, please tell how, or any extension available?
Sorry, my solution not very clear sometimes.
For test purposes I created new template, based on existing 'New order' in System / Email Templates.
Then create system.xml file where we can add new fields with template selectors:
<?xml version="1.0"?>
<config>
<sections>
<sales_email>
<groups>
<order>
<fields>
<template2>
<label>222 New Order Confirmation Template</label>
<frontend_type>select</frontend_type>
<source_model>adminhtml/system_config_source_email_template</source_model>
<sort_order>3</sort_order>
<show_in_default>1</show_in_default>
<show_in_website>1</show_in_website>
<show_in_store>1</show_in_store>
</template2>
<guest_template2 translate="label">
<label>222 New Order Confirmation Template for Guest</label>
<frontend_type>select</frontend_type>
<source_model>adminhtml/system_config_source_email_template</source_model>
<sort_order>4</sort_order>
<show_in_default>1</show_in_default>
<show_in_website>1</show_in_website>
<show_in_store>1</show_in_store>
</guest_template2>
</fields>
</order>
</groups>
</sales_email>
</sections>
</config>
As you can see we created two new fields template2 and guest_template2.
Then create your own new model, which extends !!!NOT REWRITES!!! Mage_Sales_Model_Order
Add there two new constants
class Vendor_Somemodule_Model_Order extends Mage_Sales_Model_Order
{
const XML_PATH_EMAIL_TEMPLATE = 'sales_email/order/template2';
const XML_PATH_EMAIL_GUEST_TEMPLATE = 'sales_email/order/guest_template2';
and copy-paste method sendNewOrderEmail(). In this method remove two rows at the bottom
$this->setEmailSent(true);
$this->_getResource()->saveAttribute($this, 'email_sent');
And your result will be:
public function sendNewOrderEmail()
{
$storeId = $this->getStore()->getId();
if (!Mage::helper('sales')->canSendNewOrderEmail($storeId)) {
return $this;
}
$emailSentAttributeValue = $this->load($this->getId())->getData('email_sent');
$this->setEmailSent((bool)$emailSentAttributeValue);
if ($this->getEmailSent()) {
return $this;
}
// Get the destination email addresses to send copies to
$copyTo = $this->_getEmails(self::XML_PATH_EMAIL_COPY_TO);
$copyMethod = Mage::getStoreConfig(self::XML_PATH_EMAIL_COPY_METHOD, $storeId);
// Start store emulation process
$appEmulation = Mage::getSingleton('core/app_emulation');
$initialEnvironmentInfo = $appEmulation->startEnvironmentEmulation($storeId);
try {
// Retrieve specified view block from appropriate design package (depends on emulated store)
$paymentBlock = Mage::helper('payment')->getInfoBlock($this->getPayment())
->setIsSecureMode(true);
$paymentBlock->getMethod()->setStore($storeId);
$paymentBlockHtml = $paymentBlock->toHtml();
} catch (Exception $exception) {
// Stop store emulation process
$appEmulation->stopEnvironmentEmulation($initialEnvironmentInfo);
throw $exception;
}
// Stop store emulation process
$appEmulation->stopEnvironmentEmulation($initialEnvironmentInfo);
// Retrieve corresponding email template id and customer name
if ($this->getCustomerIsGuest()) {
$templateId = Mage::getStoreConfig(self::XML_PATH_EMAIL_GUEST_TEMPLATE, $storeId);
$customerName = $this->getBillingAddress()->getName();
} else {
$templateId = Mage::getStoreConfig(self::XML_PATH_EMAIL_TEMPLATE, $storeId);
$customerName = $this->getCustomerName();
}
$mailer = Mage::getModel('core/email_template_mailer');
$emailInfo = Mage::getModel('core/email_info');
$emailInfo->addTo($this->getCustomerEmail(), $customerName);
if ($copyTo && $copyMethod == 'bcc') {
// Add bcc to customer email
foreach ($copyTo as $email) {
$emailInfo->addBcc($email);
}
}
$mailer->addEmailInfo($emailInfo);
// Email copies are sent as separated emails if their copy method is 'copy'
if ($copyTo && $copyMethod == 'copy') {
foreach ($copyTo as $email) {
$emailInfo = Mage::getModel('core/email_info');
$emailInfo->addTo($email);
$mailer->addEmailInfo($emailInfo);
}
}
// Set all required params and send emails
$mailer->setSender(Mage::getStoreConfig(self::XML_PATH_EMAIL_IDENTITY, $storeId));
$mailer->setStoreId($storeId);
$mailer->setTemplateId($templateId);
$mailer->setTemplateParams(array(
'order' => $this,
'billing' => $this->getBillingAddress(),
'payment_html' => $paymentBlockHtml
)
);
$mailer->send();
return $this;
}
Then you just need to call this method before magento call this method itself after order placed.
put in config.xml following:
<global>
<models>
<somemodule>
<class>Vendor_Somemodule_Model</class>
</somemodule>
</models>
<events>
<checkout_type_onepage_save_order_after>
<observers>
<send_duplicate_email>
<type>singleton</type>
<class>somemodule/observer</class>
<method>saveDuplicateEmail</method>
</send_duplicate_email>
</observers>
</checkout_type_onepage_save_order_after>
</events>
</global>
and create necessary observer:
class Vendor_Somemodule_Model_Observer
{
public function saveDuplicateEmail($observer)
{
$orderId = $observer->getOrder()->getId();
$order = Mage::getModel('somemodule/order')->load($orderId);
$order->sendNewOrderEmail();
}
}
Hi friends i am not expert in magento but i have some good knowledge of its themng but i dont have a very good knowledge of modules , i need to create a
custom registration form with contact info and company info
details ,
i need to create this on my own custom page , i need the magento
default registration page also
, i have check the
app\code\core\Mage\Customer\controllers/AccountController
in which i got the
public function createPostAction()
{
$session = $this->_getSession();
if ($session->isLoggedIn()) {
$this->_redirect('*/*/');
return;
}
$session->setEscapeMessages(true); // prevent XSS injection in user input
if ($this->getRequest()->isPost()) {
$errors = array();
if (!$customer = Mage::registry('current_customer')) {
$customer = Mage::getModel('customer/customer')->setId(null);
}
/* #var $customerForm Mage_Customer_Model_Form */
$customerForm = Mage::getModel('customer/form');
$customerForm->setFormCode('customer_account_create')
->setEntity($customer);
$customerData = $customerForm->extractData($this->getRequest());
if ($this->getRequest()->getParam('is_subscribed', false)) {
$customer->setIsSubscribed(1);
}
/**
* Initialize customer group id
*/
$customer->getGroupId();
if ($this->getRequest()->getPost('create_address')) {
/* #var $address Mage_Customer_Model_Address */
$address = Mage::getModel('customer/address');
/* #var $addressForm Mage_Customer_Model_Form */
$addressForm = Mage::getModel('customer/form');
$addressForm->setFormCode('customer_register_address')
->setEntity($address);
$addressData = $addressForm->extractData($this->getRequest(), 'address', false);
$addressErrors = $addressForm->validateData($addressData);
if ($addressErrors === true) {
$address->setId(null)
->setIsDefaultBilling($this->getRequest()->getParam('default_billing', false))
->setIsDefaultShipping($this->getRequest()->getParam('default_shipping', false));
$addressForm->compactData($addressData);
$customer->addAddress($address);
$addressErrors = $address->validate();
if (is_array($addressErrors)) {
$errors = array_merge($errors, $addressErrors);
}
} else {
$errors = array_merge($errors, $addressErrors);
}
}
try {
$customerErrors = $customerForm->validateData($customerData);
if ($customerErrors !== true) {
$errors = array_merge($customerErrors, $errors);
} else {
$customerForm->compactData($customerData);
$customer->setPassword($this->getRequest()->getPost('password'));
$customer->setConfirmation($this->getRequest()->getPost('confirmation'));
$customerErrors = $customer->validate();
if (is_array($customerErrors)) {
$errors = array_merge($customerErrors, $errors);
}
}
$validationResult = count($errors) == 0;
if (true === $validationResult) {
$customer->save();
Mage::dispatchEvent('customer_register_success',
array('account_controller' => $this, 'customer' => $customer)
);
if ($customer->isConfirmationRequired()) {
$customer->sendNewAccountEmail(
'confirmation',
$session->getBeforeAuthUrl(),
Mage::app()->getStore()->getId()
);
$session->addSuccess($this->__('Account confirmation is required. Please, check your email for the confirmation link. To resend the confirmation email please click here.', Mage::helper('customer')->getEmailConfirmationUrl($customer->getEmail())));
$this->_redirectSuccess(Mage::getUrl('*/*/index', array('_secure'=>true)));
return;
} else {
$session->setCustomerAsLoggedIn($customer);
$url = $this->_welcomeCustomer($customer);
$this->_redirectSuccess($url);
return;
}
} else {
$session->setCustomerFormData($this->getRequest()->getPost());
if (is_array($errors)) {
foreach ($errors as $errorMessage) {
$session->addError($errorMessage);
}
} else {
$session->addError($this->__('Invalid customer data'));
}
}
} catch (Mage_Core_Exception $e) {
$session->setCustomerFormData($this->getRequest()->getPost());
if ($e->getCode() === Mage_Customer_Model_Customer::EXCEPTION_EMAIL_EXISTS) {
$url = Mage::getUrl('customer/account/forgotpassword');
$message = $this->__('There is already an account with this email address. If you are sure that it is your email address, click here to get your password and access your account.', $url);
$session->setEscapeMessages(false);
} else {
$message = $e->getMessage();
}
$session->addError($message);
} catch (Exception $e) {
$session->setCustomerFormData($this->getRequest()->getPost())
->addException($e, $this->__('Cannot save the customer.'));
}
}
$this->_redirectError(Mage::getUrl('*/*/create', array('_secure' => true)));
}
which is for creating new account
,
but i don't want to edit this function because i need the magento
default registration page als
o , so please suggest me how can i create a new function from where i can make the customer provide there information and can register and i can store that in database , basically i need to store the contact info and company info in address tables so that the information can be shown in admin
Your custom module should contain something similar:
Package/Module/etc/config.xml
Package/Module/controllers/contactController.php
Package/Module/sql/modulename_setup/mysql4-install-1.0.0.php
app/design/frontend/default/default/layout/customercontact.xml
config.xml:
<config>
...
<modules>
<Package_Module>
<version>1.0.0</version>
</Package_Module>
</modules>
<frontend>
<!--configure your controllers-->
<routers>
<modulename>
<use>standard</use>
<args>
<module>Package_Module</module>
<frontName>modulename</frontName>
</args>
</modulename>
</routers>
<layout>
<updates>
<modulename>
<file>customercontact.xml</file>
</modulename>
</updates>
</layout>
</frontend>
<global>
<blocks></blocks><!--you can read some blogs etc-->
<models></models><!--you can read some blogs etc-->
<helpers></helpers><!--you can read some blogs etc-->
<resources>
<modulename_setup>
<setup>
<module>Package_Module</module>
</setup>
<connection>
<use>core_setup</use>
</connection>
</modulename_setup>
<modulename_write>
<connection>
<use>core_write</use>
</connection>
</modulename_write>
<modulename_read>
<connection>
<use>core_read</use>
</connection>
</modulename_read>
</resources>
</global>
...
</config>
ContactController.php
public function customerDetailsAction(){
/*render your form
Use layout handle to set your own blocks
*/
}
public function customerDetailsPostAction(){
/*borrow some logic from AccountController or Build your own
get posted data, validate and set to model & save
*/
}
mysql4-install-1.0.0.php
Used below script in few of my similar tasks:
$installer = $this;
$installer->startSetup();
$setup = Mage::getModel('customer/entity_setup', 'core_setup');//invoke customer entity setup class
// add your attribute to customer entity
$setup->addAttribute(
'customer',
'attribute_code',
array(
'type' => 'varchar',
'input' => 'text',
'label' => 'Company name',
'global' => 1,
'visible' => 1,
'required' => 0,
'user_defined' => 1,
'visible_on_front' => 1,
)
);
if (version_compare(Mage::getVersion(), '1.6.0', '<='))
{
$customer = Mage::getModel('customer/customer');
$attrSetId = $customer->getResource()->getEntityType()->getDefaultAttributeSetId();
$setup->addAttributeToSet('customer', $attrSetId, 'General', 'attribute_code');
}
if (version_compare(Mage::getVersion(), '1.4.2', '>='))
{
/*
* To get new attribute listed for customer/form various models, example checl line 275 to 277 AccountController.php
*/
Mage::getSingleton('eav/config')
->getAttribute('customer', 'attribute_code')
->setData(
'used_in_forms',
array(
'adminhtml_customer',//will make new attribute appear in admin
'customer_account_create',//will make new attribute appear on registration
'customer_account_edit',//will make new attribute appear in account dashboard
'checkout_register'// on checkout page
)
)
->save();
}
customercontact.xml
<layout>
...
<modulename_contact_customerDetails>
<update handle="customer_account_create"/><!--if only some additional fields are needed-->
<referene name="customer_form_register"><!--set your template based on customer/form/register.phtml-->
<action method="setTemplate">path to your template</action>
</reference>
</modulename_contact_customerDetails>
...
</layout>
Hope this gives an idea of what needed to be done !
The seemingly easiest path ahead for you would be to create a custom module, with a frontend controller, a single table model and an admin grid if you wish to present the data collected by the contact form to the admin users in the way other magento modules show the data.
Creating magento extensions is quite easy if right set of tools are used, you can use this module creator to create an extension quite instantly.
How do I make the telephone field not required on shipping but have it required on billing in onepage checkout?
I have followed many forums that point to the below method but this disables the required element on both billing and shipping?
http://swarminglabs.com/magento-making-the-telephone-field-not-required-at-checkout/#comment-2687
I do not know any extension that would allow this. If you want to make it work you should work with Mage_Customer_Model_Form. During checkout process magento calls validateData() method of this model. This method is defined in Mage_Eav_Model_Form. You need to rewrite another model, namely Mage_Sales_Model_Quote_Address as its parent Mage_Customer_Model_Address_Abstract has a valid() method that checks if telephone is not emtpy. So, assuming you have removed is_required and validation_rules for this attribute
in a module etc/config.xml
<config>
<global>
<models>
<customer>
<rewrite>
<form>YourNamespace_YourModule_Model_Customer_Form</form>
</rewrite>
</customer>
<sales>
<rewrite>
<quote_address>YourNamespace_YourModule_Model_Quote_Address</quote_address>
</rewrite>
</sales>
</models>
</global>
</config>
in YourNamespace/YourModule/Model/Customer/Form.php
class YourNamespace_YourModule_Model_Customer_Form extends Mage_Customer_Model_Form {
public function validateData(array $data) {
//perform parent validation
$result = parent::validateData($data);
//checking billing address; perform additional validation
if ($this->getEntity()->getAddressType() == Mage_Sales_Model_Quote_Address::TYPE_BILLING) {
$valid = $this->_validatePhoneForBilling($data);
if ($result !== true && $valid !== true) {
$result[] = $valid;
}
elseif ($result === true && $valid !== true) {
$result = $valid;
}
}
return $result;
}
protected function _validatePhoneForBilling($data) {
$errors = array();
if (empty($data['telephone'])) {
$attribute = $this->getAttribute('telephone');
$label = Mage::helper('eav')->__($attribute->getStoreLabel());
$errors[] = Mage::helper('eav')->__('"%s" is a required value.', $label);
}
if (empty($errors)) {
return true;
}
return $errors;
}
}
in YourNamespace/YourModule/Model/Quote/Address.php
class YourNamespace_YourModule_Model_Quote_Address extends Mage_Sales_Model_Quote_Address {
public function validate() {
if ($this->getAddressType() == self::TYPE_SHIPPING) {
$result = parent::validate();
$errorMsg = Mage::helper('customer')->__('Please enter the telephone number.');
if (is_array($result) && in_array($errorMsg, $result)) {
$result = array_diff($result, array($errorMsg));
}
if (empty($result)) {
return true;
}
return $result;
}
else {
return parent::validate();
}
}
}
Hello The Great Developers,
I want to customize the sales order Grid.
currently several product options are added when ever the product is added to the cart.
and they are showing up in the Order detail page in the admin panel.
but i want to make it show up in the Sales order grid.
and if i made a join query to show the product options from the sales_flat_order_item table, it is showing php array string in the serialized form which is unreadable. looks like json string.
I have been working on this issue from the past 2 days but haven't got any proper solution for this.
Your help will be fully appreciated.
Create a custom module...
read more http://tutorials.slcdev.com/2012/04/magento-extend-order-grid/ or http://inchoo.net/ecommerce/magento/how-to-extend-magento-order-grid/
In app/code/local/RWS/OrderGridOptions/etc/config.xml
<global>
<blocks>
<adminhtml>
<rewrite>
<sales_order_grid>RWS_OrderGridOptions_Block_Adminhtml_Sales_Order_Grid</sales_order_grid>
</rewrite>
</adminhtml>
</blocks>
</global>
Create in app/code/local/RWS/OrderGridOptions/Block/Adminhtml/Sales/Order/Grid.php
(see app/code/core/Mage/Adminhtml/Block/Sales/Order/Grid.php)
create function _prepareColumns()
$this->addColumn('product_options', array(
'header' => Mage::helper('order')->__('Options'),
'width' => '150',
'index' => 'product_options'
'renderer' = new RWS_OrderGridOptions_Block_Adminhtml_Renderer_Data() // added this line
));
Read more # http://www.magentocommerce.com/boards/viewthread/192232/#t239222
in app/code/local/RWS/OrderGridOptions/Block/Adminhtml/Renderer/Data.php
class RWS_OrderGridOptions_Block_Adminhtml_Renderer_Data extends Mage_Adminhtml_Block_Widget_Grid_Column_Renderer_Action
{
public function render(Varien_Object $row)
{
return $this->_getValue($row);
}
public function _getValue(Varien_Object $row)
{
$val = $row->getData($this->getColumn()->getIndex()); // row value
$array = unserialize($val);
//loop thru the $array and create a format string
//
$format_val = $array['xyx'] . ' ' . $array['abc'];
return $format_val;
}
}
I followed the code #R.S s with the following modifications to the renderer out more user friendly:
public function render(Varien_Object $row)
{
return $this->_getValue($row);
}
public function _getValue(Varien_Object $row)
{
$codeIndex = $row->getData($this->getColumn()->getIndex()); // row value
$prodOpUns = unserialize($codeIndex);
$dataOpt = $prodOpUns['options'];
$returnHtml = '<dl class="item-options">';
for ($i=0; $i<count($dataOpt); $i++){
$value = str_replace(array("<", ">"), array("<", ">"), htmlspecialchars($dataOpt[$i]['print_value'], ENT_COMPAT, "UTF-8", false));
$returnHtml .= '<dt>'.strtolower($dataOpt[$i]['label']) .'</dt>' . '<dd>' . $value . '</dd>';
}
$returnHtml .= '</dl>';
return $returnHtml;
}
Is there a simple way to add the username of the person who is making the comment in the admin history to the comment thread on the order?
-- edit --
Another way of asking this would be how do I add an additional field to the comment history model so that I can override the appropriate models and templates inserting that data into the data structure.
If you want to add the username who is currently logged in and making change in order or commenting on order. you need to add an attribute to magento.
Create a Module say Audit
app / etc / modules / Namespace_Audit.xml
<?xml version="1.0"?>
<config>
<modules>
<Namespace_Audit>
<active>true</active>
<codePool>local</codePool>
<depends>
<Mage_Sales/>
</depends>
</Namespace_Audit>
</modules>
</config>
then Create a folder Audit in you namespace and create the config file. purpose of this is to rewrite the core class and extending for modified method
app / code / local / Namespace / Audit / etc / config.xml
`<?xml version="1.0"?>
<config>
<modules>
<Namespace_Audit>
<version>0.1.0</version>
</Namespace_Audit>
</modules>
<global>
<blocks>
<adminhtml>
<rewrite>
<sales_order_view_tab_history before="Mage_Adminhtml_Block">Namespace_Audit_Block_Sales_Order_View_Tab_History<sales_order_view_tab_history>
</rewrite>
</adminhtml>
</blocks>
<global>
<models>
<audit>
<class>Bigadda_Audit_Model</class>
</audit>
</models>
<resources>
<audit_setup>
<setup>
<module>Bigadda_Audit</module>
</setup>
<connection>
<use>core_setup</use>
</connection>
</audit_setup>
<audit_write>
<connection>
<use>core_write</use>
</connection>
</audit_write>
<audit_read>
<connection>
<use>core_read</use>
</connection>
</audit_read>
</resources>
</global>
</global>
</config>`
create a setup to make a new attribute in database
local / Namespace / Audit / sql / audit_setup / mysql4-install-0.1.0.php
`
<?php
$installer = $this;
$installer->startSetup();
$setup = new Mage_Eav_Model_Entity_Setup('core_setup');
$setup->addAttribute('order_status_history', 'track_user', array('type' => 'varchar'));
$installer->endSetup();
`
Now extending the existing class . create a class file History.php
Namespace/Audit/Block/Sales/Order/View/Tab/History
and copy the functions in that
`
public function getFullHistory()
{
$order = $this->getOrder();
$history = array();
foreach ($order->getAllStatusHistory() as $orderComment){
$history[$orderComment->getEntityId()] = $this->_prepareHistoryItem(
$orderComment->getStatusLabel(),
$orderComment->getIsCustomerNotified(),
$orderComment->getCreatedAtDate(),
$orderComment->getComment(),
$orderComment->getTrackUser(),
$orderComment->getTrackUserName()
);
}
foreach ($order->getCreditmemosCollection() as $_memo){
$history[$_memo->getEntityId()] =
$this->_prepareHistoryItem($this->__('Credit Memo #%s created', $_memo->getIncrementId()),
$_memo->getEmailSent(), $_memo->getCreatedAtDate());
foreach ($_memo->getCommentsCollection() as $_comment){
$history[$_comment->getEntityId()] =
$this->_prepareHistoryItem($this->__('Credit Memo #%s comment added', $_memo->getIncrementId()),
$_comment->getIsCustomerNotified(), $_comment->getCreatedAtDate(), $_comment->getComment(),$_comment->getTrackUser(),$_comment->getTrackUserName());
}
}
foreach ($order->getShipmentsCollection() as $_shipment){
$history[$_shipment->getEntityId()] =
$this->_prepareHistoryItem($this->__('Shipment #%s created', $_shipment->getIncrementId()),
$_shipment->getEmailSent(), $_shipment->getCreatedAtDate());
foreach ($_shipment->getCommentsCollection() as $_comment){
$history[$_comment->getEntityId()] =
$this->_prepareHistoryItem($this->__('Shipment #%s comment added', $_shipment->getIncrementId()),
$_comment->getIsCustomerNotified(), $_comment->getCreatedAtDate(), $_comment->getComment(),$_comment->getTrackUser(),$_comment->getTrackUserName());
}
}
foreach ($order->getInvoiceCollection() as $_invoice){
$history[$_invoice->getEntityId()] =
$this->_prepareHistoryItem($this->__('Invoice #%s created', $_invoice->getIncrementId()),
$_invoice->getEmailSent(), $_invoice->getCreatedAtDate());
foreach ($_invoice->getCommentsCollection() as $_comment){
$history[$_comment->getEntityId()] =
$this->_prepareHistoryItem($this->__('Invoice #%s comment added', $_invoice->getIncrementId()),
$_comment->getIsCustomerNotified(), $_comment->getCreatedAtDate(), $_comment->getComment(),$_comment->getTrackUser(),$_comment->getTrackUserName());
}
}
foreach ($order->getTracksCollection() as $_track){
$history[$_track->getEntityId()] =
$this->_prepareHistoryItem($this->__('Tracking number %s for %s assigned', $_track->getNumber(), $_track->getTitle()),
false, $_track->getCreatedAtDate());
}
krsort($history);
return $history;
}`
protected function _prepareHistoryItem($label, $notified, $created, $comment = '' , $trackUser = '' , $trackUserName ='')
{
return array(
'title' => $label,
'notified' => $notified,
'track_user' => $trackUser,
'track_user_name' => $trackUserName,
'comment' => $comment,
'created_at' => $created
);
}
extend the class order.php and add this method to set the comment to update the database.
app / code / local / Mynamespace / Sales / Model / Order.php
public function addStatusHistoryComment($comment, $status = false)
{
if (false === $status) {
$status = $this->getStatus();
} elseif (true === $status) {
$status = $this->getConfig()->getStateDefaultStatus($this->getState());
} else {
$this->setStatus($status);
}
$UserInfo = Mage::getSingleton('admin/session')->getUser();
$UserName='';
$UserName=$UserInfo->getUsername();
$history = Mage::getModel('sales/order_status_history')
->setStatus($status)
->setComment($comment)
->setTrackUser($UserName); //added by vipul dadhich to add audits in the
$this->addStatusHistory($history);
return $history;
}
finally updating the phtml files.
app / design / adminhtml / default / default / template / sales / order / view / history.phtml
place this code wherever u want to show the username
<?php if ($_item->getTrackUser()): ?>
<br/><?php echo "<b>Updated By ( User ) :- </b>".$this->htmlEscape($_item->getTrackUser(), array('b','br','strong','i','u')) ?>
<?php endif; ?>
app / design / adminhtml / default / default / template / sales / order / view / tab / history.phtml
<?php if ($_comment = $this->getItemTrackUser($_item)): ?>
<br/><?php echo "<b>Updated By (User) :- </b>".$_comment ?>
<?php endif; ?>
Thats All folks..
Vipul Dadhich
A different take by observing the event *sales_order_status_history_save_before*
Define the setup and observer in your config:
<config>
<modules>
<Name_Module>
<version>0.0.1</version>
</Name_Module>
</modules>
<global>
<resources>
<module_setup>
<setup>
<module>Name_Module</module>
</setup>
<connection>
<use>core_setup</use>
</connection>
</module_setup>
</resources>
<events>
<sales_order_status_history_save_before>
<observers>
<sales_order_status_history_save_before_observer>
<type>singleton</type>
<class>Name_Module_Model_Observer</class>
<method>orderStatusHistorySaveBefore</method>
</sales_order_status_history_save_before_observer>
</observers>
</sales_order_status_history_save_before>
</events>
<!-- and so on ->
In your module_setup file app\code\local\Name\Module\sql\module_setup\install-0.0.1.php
$installer = $this;
$installer->startSetup();
$table = $installer->getTable('sales/order_status_history');
$installer->getConnection()
->addColumn($table, 'username', array(
'type' => Varien_Db_Ddl_Table::TYPE_TEXT,
'length' => 40,
'nullable' => true,
'comment' => 'Admin user name'
));
$installer->getConnection()
->addColumn($table, 'userrole', array(
'type' => Varien_Db_Ddl_Table::TYPE_TEXT,
'length' => 50,
'nullable' => true,
'comment' => 'Admin user role'
));
$installer->endSetup();
Then in Name_Module_Model_Observer:
public function orderStatusHistorySaveBefore($observer)
{
$session = Mage::getSingleton('admin/session');
if ($session->isLoggedIn()) { //only for login admin user
$user = $session->getUser();
$history = $observer->getEvent()->getStatusHistory();
if (!$history->getId()) { //only for new entry
$history->setData('username', $user->getUsername());
$role = $user->getRole(); //if you have the column userrole
$history->setData('userrole', $role->getRoleName()); //you can save it too
}
}
}
In Magento 2
You need to override the AddComment.php file in vendor/magento/module-sales
If you want to edit the core file AddComment.php then you can add the following code to your AddComment.php file
$username = $this->authSession->getUser()->getUsername();
$append = " (by ".$username.")";
$history = $order->addStatusHistoryComment($data['comment'].$append, $data['status']);
But this is not a good practice to modify core files directly. You need to make your new module and override
Vendor/Module/etc/di.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<preference for="Magento\Sales\Controller\Adminhtml\Order\AddComment" type="Vendor\Module\Controller\Adminhtml\Order\AddComment" />
</config>
Vendor\Module\Controller\Adminhtml\Order\AddComment.php
<?php
namespace Vendor\Module\Controller\Adminhtml\Order;
use Magento\Backend\App\Action;
use Magento\Sales\Model\Order\Email\Sender\OrderCommentSender;
use Magento\Sales\Api\OrderManagementInterface;
use Magento\Sales\Api\OrderRepositoryInterface;
use Magento\Framework\Exception\NoSuchEntityException;
use Magento\Framework\Exception\InputException;
use Psr\Log\LoggerInterface;
class AddComment extends \Magento\Sales\Controller\Adminhtml\Order
{
/**
* Authorization level of a basic admin session
*
* #see _isAllowed()
*/
const ADMIN_RESOURCE = 'Magento_Sales::comment';
/**
* Core registry
*
* #var \Magento\Framework\Registry
*/
protected $_coreRegistry = null;
/**
* #var \Magento\Framework\App\Response\Http\FileFactory
*/
protected $_fileFactory;
/**
* #var \Magento\Framework\Translate\InlineInterface
*/
protected $_translateInline;
/**
* #var \Magento\Framework\View\Result\PageFactory
*/
protected $resultPageFactory;
/**
* #var \Magento\Framework\Controller\Result\JsonFactory
*/
protected $resultJsonFactory;
/**
* #var \Magento\Framework\View\Result\LayoutFactory
*/
protected $resultLayoutFactory;
/**
* #var \Magento\Framework\Controller\Result\RawFactory
*/
protected $resultRawFactory;
/**
* #var OrderManagementInterface
*/
protected $orderManagement;
/**
* #var OrderRepositoryInterface
*/
protected $orderRepository;
/**
* #var LoggerInterface
*/
protected $logger;
protected $authSession;
public function __construct(
Action\Context $context,
\Magento\Framework\Registry $coreRegistry,
\Magento\Framework\App\Response\Http\FileFactory $fileFactory,
\Magento\Framework\Translate\InlineInterface $translateInline,
\Magento\Framework\View\Result\PageFactory $resultPageFactory,
\Magento\Framework\Controller\Result\JsonFactory $resultJsonFactory,
\Magento\Framework\View\Result\LayoutFactory $resultLayoutFactory,
\Magento\Framework\Controller\Result\RawFactory $resultRawFactory,
OrderManagementInterface $orderManagement,
OrderRepositoryInterface $orderRepository,
LoggerInterface $logger,
\Magento\Backend\Model\Auth\Session $authSession
) {
$this->authSession = $authSession;
parent::__construct($context, $coreRegistry,$fileFactory,$translateInline,$resultPageFactory,$resultJsonFactory,$resultLayoutFactory,$resultRawFactory,$orderManagement,$orderRepository,$logger);
}
/**
* Add order comment action
*
* #return \Magento\Framework\Controller\ResultInterface
*/
public function execute()
{
$order = $this->_initOrder();
if ($order) {
try {
$data = $this->getRequest()->getPost('history');
if (empty($data['comment']) && $data['status'] == $order->getDataByKey('status')) {
throw new \Magento\Framework\Exception\LocalizedException(__('Please enter a comment.'));
}
$notify = isset($data['is_customer_notified']) ? $data['is_customer_notified'] : false;
$visible = isset($data['is_visible_on_front']) ? $data['is_visible_on_front'] : false;
$username = $this->authSession->getUser()->getUsername();
$append = " (by ".$username.")";
$history = $order->addStatusHistoryComment($data['comment'].$append, $data['status']);
$history->setIsVisibleOnFront($visible);
$history->setIsCustomerNotified($notify);
$history->save();
$comment = trim(strip_tags($data['comment']));
$order->save();
/** #var OrderCommentSender $orderCommentSender */
$orderCommentSender = $this->_objectManager
->create(\Magento\Sales\Model\Order\Email\Sender\OrderCommentSender::class);
$orderCommentSender->send($order, $notify, $comment);
return $this->resultPageFactory->create();
} catch (\Magento\Framework\Exception\LocalizedException $e) {
$response = ['error' => true, 'message' => $e->getMessage()];
} catch (\Exception $e) {
$response = ['error' => true, 'message' => __('We cannot add order history.')];
}
if (is_array($response)) {
$resultJson = $this->resultJsonFactory->create();
$resultJson->setData($response);
return $resultJson;
}
}
return $this->resultRedirectFactory->create()->setPath('sales/*/');
}
}