I have created a 'Companyname' attribute which gets added up in my Customer's Account information and is a required field.
It gets filled up on registration, form and edit pages fine and gets displayed on Customer's Grid in the back-end too.
However I am not able to display the Company name in any of my order email templates.
I believe this is because there is neither any column called 'companyname' in my order tables nor do I have any custom variable which I can pass to order/invoice/shipment templates to display Company name right next to the line after Customer's name.
Can any one point out the file where I can create this custom variable containing my custom 'companyname' attribute and pass it to all types of sales email templates
Thanks
After a little bit of searching I found the right file to make the changes. Since I already had 'companyname' as one of my attributes I retrieved the value of this field and passed it as a param in the following function
app/code/core/Mage/Sales/Model/Order.php
public function sendNewOrderEmail()
{
/*Existing Code*/
if ($this->getCustomerIsGuest()) {
$templateId = Mage::getStoreConfig(self::XML_PATH_EMAIL_GUEST_TEMPLATE, $storeId);
$customerId = Mage::getModel('customer/customer')->load($this->getCustomerId());
$companyname = $customerId->getCompanyname();
$customerName = $this->getBillingAddress()->getName();
} else {
$templateId = Mage::getStoreConfig(self::XML_PATH_EMAIL_TEMPLATE, $storeId);
$customerId = Mage::getModel('customer/customer')->load($this->getCustomerId());
$companyname = $customerId->getCompanyname();
$customerName = $this->getCustomerName();
}
/*Existing Code*/
$mailer->setTemplateParams(array(
'order' => $this,
'billing' => $this->getBillingAddress(),
'payment_html' => $paymentBlockHtml,
'companyname' => $companyname
));
/*Rest of the code remains the same*/
}
After making this change. I edited my Transactional Email to include this param. Since I wanted to display inside Shipping Address, I placed my variable just before this line in
System > Transactional Emails > New Order Email
{{ var companyname }}
{{var order.getShippingAddress.format('html')}}
If your companyname is getting saved as a part of Customer Information then this would get displayed in your Order Email in 'Shipping Address' Information right at the Start.
You can do the same for Invoice and Shipment Emails.
Hope this helps someone !!! :-)
Related
I have seen this question come up here and there, but it has not been fully answered. I know how to get the WC_Order_Item_Shipping information from an order, but how can I get a WC_Shipping_Method object from the orders shipping method item?
I have stored some custom options through a custom field in the admin setting page for the WooCommerce shipping methods. I want to get this field from an order. Right now I am doing this, and I can get to my information:
foreach ($order->get_shipping_methods() as $shipping_method) {
$options = get_option('woocommerce_' . $shipping_method->get_method_id() . '_' . $shipping_method->get_instance_id() . '_settings');
}
But this does not feel future proof. If the structure of the saved data changes, then everything will break. I'd rather use the getter from WC_Shipping_Method get_instance_option(). The problem is that I am not allowed to instantiate such an object, and there does not seem to be a wc_get_shipping_method() function I can use to get the method based on it's instance ID, such as with orders and products.
I could go the long route and save this info to order meta after payment is made, but that also does not seem like an optimized way of doing it. I want to get the information as it is saved in the present moment, not as it was saved to an order when the order was made.
Is the way that I am doing it now the only way, or is there a better way?
EDIT:
This is the code that adds the custom field:
function shipping_instance_form_add_extra_fields($settings)
{
$settings['custom_shipping_id'] = [
'title' => 'Custom Shipping ID',
'type' => 'number',
'description' => '',
];
return $settings;
}
function shipping_instance_form_fields_filters()
{
$shipping_methods = WC()->shipping->get_shipping_methods();
foreach ($shipping_methods as $shipping_method) {
add_filter('woocommerce_shipping_instance_form_fields_' . $shipping_method->id, 'shipping_instance_form_add_extra_fields');
}
}
add_action('woocommerce_init', 'shipping_instance_form_fields_filters');
If you already have shipping method instance id you can simply create instance of class WC_Shipping_Method giving it instance id as constructor parameter like $method = new WC_Shipping_Method($instance_id). After that you can use method get_instance_option to get value of that option like $custom_shipping_id = $method->get_instance_option('custom_shipping_id');
I am currently trying to use swiftmailer in my project. I am currently working on Sonata Admin and I wanted to know how I could retrieve the object displayed in a list to be able to retrieve the associated mail addresses and thus send an e-mail to all the addresses contained in this list. I want to go through the list displayed by sonata because their filter system works very well and I would use it to choose the people I want to send an email to. I saw on the symfony documentation that it was possible to send mail to an address table in this form:
$to = array('one#example.com', 'two#example.com', 'three#example.com');
$message = (new \Swift_Message('Hello Email'))
->setFrom('send#example.com')
->setTo(array($to))
->setBody('html content goes here', 'text/html');
$mailer->send($message);
But i don't know how to take back the object form the list.
From this grid.
Can you help me thanks ?
Ps :
I just think putting a button down the list to send an email to all the people displayed in the list.
Thanks a lot.
Edit :
I'm still searching and i found that the sql request was like 't0.id' and 'c0.id'. t0 and c0 are the name of the object ? Is it always that ? What is the difference between t0 and c0 ?
You can do this by adding an action to your admin list.
To do so, first create a new class in YourAdminBundle\Controller folder, extending Sonata\AdminBundle\Controller\CRUDController.
Your custom action could look like this for instance :
/** #property YourAdminClass $admin */
public function batchActionSendMail(ProxyQueryInterface $selectedModelQuery ,$type = 'sendMails') {
if (false === $this->admin->isGranted('EDIT')) {
throw new AccessDeniedException();
}
/* selected objects in your list !! */
$selectedModels = $selectedModelQuery->execute();
try{
foreach ($selectedModels as $selectedModel){
// your code to retrieve objects mails here (for instance)
}
//code to send your mails
}
catch(\Exception $e)
{
$this->addFlash('sonata_flash_error', "error");
}
$this->addFlash('sonata_flash_success', 'mails sent')
return new RedirectResponse($this->admin->generateUrl('list'));
}
To make this custom CRUD controller active, go to services.yml, get to your class admin block, and complete the third param of arguments property by referencing your custom CRUD controller:
arguments: [null, YourBundle\Entity\YourEntity,YourAdminBundle:CustomCRUD]
Finally, to allow you to use your custom action, go to your Admin Class and add this function :
public function getBatchActions()
{
if ($this->hasRoute('edit')) {
$actions['sendMails'] = array(
'label' => $this->trans('batch.sendMails.action'),
'ask_confirmation' => true, // by default always true
);
}
return $actions;
}
The action will be available in the dropdown list at the bottom of your admin list, next to the "Select all" checkbox.
When creating an invoice with SugarCRM, in the invoice detail there's number of unit and unit price. I would like to populate the field line price automatically, which is simply the product of those two fields above.
Here is what I added in the custom/modules/C_Inc_Invoice_Detail directory :
logic_hook.php
<?php
$hook_version = 1;
$hook_array = array();
$hook_array['after_save'] = array();
$hook_array['after_save'][] = array(
1,
'Auto Fill Line price',
'custom/modules/C_Inv_Invoice_Detail/autofilllineprice.php',
'AutoFillLinePrice',
'autofilllineprice'
);
?>
and the autofilllineprice.php :
<?php
//prevents directly accessing this file from a web browser
if
(!defined('sugarEntry') ||!sugarEntry) die('Not A Valid Entry Point');
class AutoFillLinePrice {
function autofilllineprice($bean, $event, $arguments){
$line_price = $bean->unit_price * $bean->number_units;
}
}
?>
Could you advise ?
This post does not answer this question directly, but it documents the steps involved in accomplishing a similar requirement. The Accounts module in SugarCE-6.5.22 has a field Annual Revenue and it's displayed in the DetailView as shown below.
The following are the steps involved in adding a new field that displays the value of this field converted to some other currency.
The first step is to create a non-db field that will hold the value of this new currency. For this, we need to create two files, one that defines the field("custom_fields.php") and the other that defines a language specific dispplay value for this field("en_us_custom_fields.php"). These two files are to be created in the below mentioned location. Please create the required directory structure if not present already.
custom\Extension\modules\Accounts\Ext\Vardefs\custom_fields.php
<?php
if (!defined('sugarEntry') ||!sugarEntry) die('Not A Valid Entry Point');
$dictionary['Account']['fields']['annual_revenue_inr'] = array(
'name' => 'annual_revenue_inr',
'vname' => 'LBL_ANNUAL_REVENUE_INR',
'label'=>'LBL_ANNUAL_REVENUE_INR',
'type' => 'name',
'module' => 'Accounts',
'source' => 'non-db',
'studio' => array('detailview'=>true),
'default_value' => '',
'help' => 'Annual Revenue(INR)',
'comment' => 'Annual Revenue(INR)',
'reportable' => true,
'audited' => false,
'duplicate_merge' => false,
'importable' => 'true',
);
?>
custom\Extension\modules\Accounts\Ext\Language\en_us_custom_fields.php
<?php
if (!defined('sugarEntry') ||!sugarEntry) die('Not A Valid Entry Point');
$mod_strings['LBL_ANNUAL_REVENUE_INR'] = 'Annual Revenue(INR)';
?>
After adding these two files, we need to run Admin-->Repair-->Quick Repair and Rebuild. After it's complete, if we open Admin-->Studio and expand Accounts-->Layouts-->DetailView, we should see our newly created field available there. We can drag and drop it inside the layout wherever we want it to appear and click Save & Deploy.
Now, this new field should be visible in the detail view of the account.
The next task is to populate the value for this new currency. This can be achieved using logic hooks provided by SugarCRM. We need to compute the value for this field everytime after an account data is retrieved from database. The after_retrieve event can be used for this. First, let's create a php file("annual_revenue_hook.php") with code that computes the value of this new currency field in the following location.
custom\Extension\modules\Accounts\Ext\hooks\annual_revenue_hook.php
<?php
if (!defined('sugarEntry') ||!sugarEntry) die('Not A Valid Entry Point');
class AnnualRevenue {
function computeAnnualRevenueINR($bean, $event, $arguments){
$bean->annual_revenue_inr = $bean->annual_revenue * 100;
}
}
?>
To register the above hook, we need to edit the logic_hooks.php file of the module and add the following lines:
custom\modules\Accounts\logic_hooks.php
//Create a new array that holds after_retrieve event hooks if not present already
$hook_array['after_retrieve'] = Array();
//Register our annual revenue hook for computing new currency value
$hook_array['after_retrieve'][]= Array(1, 'Compute Annual Revenue in INR', 'custom/Extension/modules/Accounts/Ext/hooks/annual_revenue_hook.php','AnnualRevenue', 'computeAnnualRevenueINR');
After completing these steps, we should see the value of the new currency populated in the detail view as shown below:
It's also possible to get data from associated modules. For example, let's say we need to calculate the sum of all Opportunities associated with this Account and add to our new field. The following are the steps to accomplish it:
The first step is to get the relationship information between the modules, in this case between Accounts and Opportunities. We need to open the file modules\Accounts\vardefs.php and search for Opportunities. It should give us the following information.
'opportunities' =>
array (
'name' => 'opportunities',
'type' => 'link',
'relationship' => 'accounts_opportunities',
'module'=>'Opportunities',
'bean_name'=>'Opportunity',
'source'=>'non-db',
'vname'=>'LBL_OPPORTUNITY',
),
Then, we can open Admin-->Studio, expand Accounts-->Relationships and find the type of relationship as shown below:
Now that we have identified the relationship information, we can edit our existing hook as shown below:
custom\Extension\modules\Accounts\Ext\hooks\annual_revenue_hook.php
<?php
if (!defined('sugarEntry') ||!sugarEntry) die('Not A Valid Entry Point');
class AnnualRevenue {
function computeAnnualRevenueINR($bean, $event, $arguments){
$bean->annual_revenue_inr = $bean->annual_revenue * 100;
$bean->load_relationship('opportunities');
$opportunities = $bean->opportunities->getBeans();
//Every account has multiple opportunities i.e array of Opportunity
foreach($opportunities as $opportunity){
$bean->annual_revenue_inr = $bean->annual_revenue_inr + $opportunity->amount;
}
}
}
?>
The above code should now multiply annual_revenue by 100 and also sum up all the associated Opportunities with it to calculate the value of annual_revenue_inr.
From the beginning I want to apologize for my poor English! I have a task to make the proper storage of information in the customer session in Magento on the page checkout. When i try to save billing address of a guest user i had rewrite billing model and all ok. But when user is logged in and has several address in his address book i saw interesting thing.... I had rewrite billing model more to save a customer address id and save selected address but when user select an option in select "New address", form data save in quote and when i try to get it with getQuote()->getBillingAddress() i took the default user address (when user not logged in all work good) How i can do this task ?? I need help because this important task for me ... A lot of thx !!!
If I am parsing your question correctly, are you saying that getQuote()->getBillingAddress() is getting the customer's default billing address instead of the new address the customer has entered in the order?
I have this problem in Magento 1.4.0.1 as well, I worked around it by getting all the addresses from the customer and comparing every attribute with the address specified in the order to find out the real entity ID of the address.
I copied this from my code with some parts of custom business logic removed, so consider it untested, but you get the idea:
(The code is only tested on Magento 1.4.0.1 and might not apply to Magento 1.5)
$currentCustomer = Mage::getModel('customer/customer')->load($order['customer_id']);
$attributesToCompare = array('firstname', 'lastname', 'country_id', 'region', 'region_id', 'city', 'telephone', 'postcode', 'company', 'fax', 'prefix', 'middlename', 'suffix', 'street');
$orderAddresses = array(
'billing' => $order->getBillingAddress()->getData(),
'shipping' => $order->getShippingAddress()->getData()
);
$foundExistingCustomerAddressEntityId = array(
'billing' => false,
'shipping' => false
);
$billingSameAsShipping = false;
$currentCustomerAddresses = $currentCustomer->getAddressesCollection();
// is the billing/shipping address currently found in the customer's address book?
foreach ($orderAddresses as $orderAddressKey => $orderAddress) {
//var_dump($orderAddress);
foreach ($currentCustomerAddresses as $currentCustomerAddressObj) {
$currentCustomerAddress = $currentCustomerAddressObj->getData();
$attributesMatchCount = 0;
foreach ($attributesToCompare as $attributeToCompare) {
if (empty($currentCustomerAddress[$attributeToCompare])) {
$currentCustomerAddress[$attributeToCompare] = false;
}
$attributesMatchCount += ($orderAddress[$attributeToCompare] == $currentCustomerAddress[$attributeToCompare])?1:0;
//echo 'attributesMatchCount: '.$attributesMatchCount." {$orderAddress[$attributeToCompare]} {$currentCustomerAddress[$attributeToCompare]}\n";
}
if ($attributesMatchCount == count($attributesToCompare)) {
$foundExistingCustomerAddressEntityId[$orderAddressKey] = $currentCustomerAddress['entity_id'];
//echo 'foundExistingCustomerAddressEntityId['.$orderAddressKey.']: '.$foundExistingCustomerAddressEntityId[$orderAddressKey]."\n\n";
break;
}
}
}
$billingShippingExactMatchCount = 0;
foreach ($attributesToCompare as $attributeToCompare) {
$billingShippingExactMatchCount += ($orderAddresses['billing'][$attributeToCompare] == $orderAddresses['shipping'][$attributeToCompare])?1:0;
}
if ($billingShippingExactMatchCount == count($attributesToCompare)) {
$billingSameAsShipping = true;
}
When the user is sent to the "thank you page" (cart/checkout/complete) I need to get some info about the order to send it to a 3rd party tracking API. Problem is that in this point there is no info about the order, either in session nor in any other place that I know of. As a workaround I tried querying the last order for the currently connected user but this fails when the user is unregistered as Ubercart registers an account on the fly and leaves the user unlogged.
So my question is, is there a way to get the Order object at this point (cart/checkout/complete) from the page-cart.tpl.php template ?
My solution so far:
Grab the $_SESSION['cart_order'] variable at cart/checkout/review , assign it to $_SESSION['faux_order'] and use faux_order in my script at cart/checkout/complete ... which feels as ugly as seeing a giraffe choke to death.
WARNING! DO NOT USE THE ANSWER ABOVE. See my comment for explanation.
Instead of the answer submitted above (which you should NEVER! use) create a custom Ubercart conditional action (CA) and add it to the section "Trigger: Customer completes checkout" in your Ubercart CA workflow, found in https://dev.betternow.org/admin/store/ca/overview
Here I am defining a custom CA
function my_module_ca_action() {
$order_arg = array(
'#entity' => 'uc_order',
'#title' => t('Order'),
);
$actions['my_module_status_update'] = array(
'#title' => t('Some Title'),
'#category' => t('Custom UC AC'),
'#callback' => 'my_module_some_function_name',
'#arguments' => array(
'order' => $order_arg,
),
);
return $actions;
}
Now I can use the order id in my own callback function defined in my module:
function my_module_some_function_name(&$order, $settings) {
echo "This is the order id: " . $order->order_id;
}
I use this approach myself to show a "Thank You" page to users with a link to the product they just purchased.
$_SESSION['cart_order'] is available on the order review page.
So ...
Create a cookie representing the order ID like this:
<?php setcookie('orderID', '$_SESSION['cart_order']'); ?>
Then, on the order confirmation page, you can call the saved cookie like this:
<?php
if (isset($_COOKIE['orderID'])):
$theOrder = $_COOKIE['orderID'));
echo 'The order ID is: ' . $theOrder;
endif;
?>
If the user then goes back and creates a new order, the cookie will be updated whenever they reach the order review page.