Checking If Order is Being Edited By Admin? - magento

My custom shipping module was failing because it couldn't get a sales quote when an order was being edited on the backend. This was the code I was using:
class Mymodule_Model_Mycarrier_Customrate
extends Mage_Shipping_Model_Carrier_Abstract
implements Mage_Shipping_Model_Carrier_Interface
{
public function collectRates(Mage_Shipping_Model_Rate_Request $request)
{
$quote = Mage::getSingleton('checkout/type_onepage')->getQuote();
I need to get the current quote so I have access to the address information. I am making an API request that requires a street address.
Now if the order was being edited on the backend, this would obviously result in an error because the checkout singleton is no longer relevant. Instead I get the quote like this:
$quote = Mage::getSingleton('adminhtml/session_quote')->getQuote();
In my collectRates() method I need to determine which singleton to load. First I want to ask if this is the proper way of doing things, and also if my check for the backend is sufficient:
$quote = Mage::getSingleton('checkout/type_onepage')->getQuote();
// If admin is editing an order, find the quote by admin session.
if(Mage::getSingleton('admin/session')->isLoggedIn()){
$quote = Mage::getSingleton('adminhtml/session_quote')->getQuote();
}
I don't want this to potentially cause problems later. I also get the feeling that I may be using the collectRates() method wrong if I have to create a workaround like this.

The Mage_Shipping_Model_Rate_Request object already has access to the address via $request->getDestStreet(), etc...

Related

Magento returning incorrect customer data on frontend pages

isn't this the right method to get Name of logged in customer?
<?php echo Mage::helper('customer')->getCustomer()->getName(); ?>
I have a website with live chat functionality. Yesterday I have been asked to pass email address and the name of the logged into the user into the Javascript Tracking variable code placed in the head section of the website. So that the operators could see who is on the website and whom are they talking to without any need to ask about their information.
So I passed the information from Magento into the Javascript code but now I see this very strange thing happening. For example,
If I am logged in with credentials Name = John Email =
john12#yahoo.com
Then This name and email variable values are changing with the change of pages. For example if I click on any product page the variable values which I am passing changes to some other user's information.
Name becomes Ricky Email becomes ricky23#gmail.com
this variable values are kept on changing back to john and from john to something else with the change of pages. So operator does not have any idea whom are they talking because the values are kept on changing. Also, user ricky or who ever it changes to also exist in the database. so it is picking up random person from the database.
This is what i did to pass the code to javascript. Please let me know if that is not the right code to pass the information. Please check the php code I am using to fetch information from Magento. Roughly, I receive incorrect value once in 5 times. Please provide some assistance. Thanks in advance.
<?php
$customer = Mage::getSingleton('customer/session')->getCustomer();
$email = $customer->getEmail();
$firstname = $customer->getFirstname();
$lastname= $customer->getLastname();
$name = $firstname . ' ' . $lastname;
?>
<script type="text/javascript">
if (typeof(lpMTagConfig) == "undefined"){ lpMTagConfig = {};}
if (typeof(lpMTagConfig.visitorVar) == "undefined"){ lpMTagConfig.visitorVar = [];}
lpMTagConfig.visitorVar[lpMTagConfig.visitorVar.length] = 'Email=<?php echo $email; ?>';
lpMTagConfig.visitorVar[lpMTagConfig.visitorVar.length] = 'Name=<?php echo $name; ?>';
</script>
I'm also attaching a snap shot
I'd be interested to hear how you're adding this code to the page? Is it in it's own block, or are you adding it to footer.phtml, or similar? If your adding to an existing block be sure to check the block caching settings of that template.
To confirm the caching hypothesis I'd ask the following:
Do you get the same name, all the time, on the same page? When you refresh the page, do you get the same name and email in the Javascript?
Does the problem persist with caching disabled?
This doesn't sound like a singleton problem at all. Each execution of the PHP script is isolated from the others, serving one page request. There's no chance of another customer's object moving between invokations of the script.
It is a matter of understanding the singleton pattern. If you call your code twice:
$customer_1 = Mage::helper('customer')->getCustomer()->getName();
$customer_2 = Mage::helper('customer')->getCustomer()->getName();
you get two different instances of the object. But... if one of them has already implemented a singleton pattern in its constructor or has implemented a singleton getInstance then both objects will actually point to the same thing.
Looking at the customer/helper/Data.php code you can see the function
public function getCustomer()
{
if (empty($this->_customer)) {
$this->_customer = Mage::getSingleton('customer/session')->getCustomer();
}
return $this->_customer;
}
That means that in one of the cases singleton is already implemented/called and in other one - not as the property is already set.
The correct way to work with quote/customer/cart in order to get always the correct data is always to use the singleton pattern.
So using this:
$customer = Mage::getSingleton('customer/session')->getCustomer();
always guarantee that you get the correct customer in that session. And as may be you know singleton pattern is based on registry pattern in app/Mage.php:
public static function getSingleton($modelClass='', array $arguments=array())
{
$registryKey = '_singleton/'.$modelClass;
if (!self::registry($registryKey)) {
self::register($registryKey, self::getModel($modelClass, $arguments));
}
return self::registry($registryKey);
}
and looking at app/Mage.php:
public static function register($key, $value, $graceful = false)
{
if (isset(self::$_registry[$key])) {
if ($graceful) {
return;
}
self::throwException('Mage registry key "'.$key.'" already exists');
}
self::$_registry[$key] = $value;
}
...
public static function registry($key)
{
if (isset(self::$_registry[$key])) {
return self::$_registry[$key];
}
return null;
}
you can see that Magento checks is it is already set. If so, Magento will either throw an Exception, which is the default behavior or return null.
Hope this will help you to understand the issue you face.
I have sorted this out. I have moved the code from footer.phtml to head.phtml and it's working fine now.Values are not changing anymore. If anyone know the logic behind please post and I will change my answer. So far this is working.

Codeigniter: Routing and URI Segments

I'm having an issue with routing in codeigniter.
Lets say I have a controller named Pages, with a method named product that does the following:
public function product() {
$this->load->model('pages_model');
$productid = $this->uri->segment(3);
$data['product'] = $this->pages_model->getProduct($productid);
// ...load view, etc.
}
To access a particular product, my url will be www.example.com/pages/product/ID.
I want to setup a custom route so I can access the product by going to www.example.com/name-of-product.
However, putting
$route['name-of-product'] = 'pages/product/ID';
does not work. It will load the product view, but the product data will not be loaded. If I say
$route['name-of-product/:any/ID'] = 'pages/product/ID';
it works as it should, but I would rather not have the two additional segments at the end of the url.
You don't need 2 additional segments. One should be sufficient.
$route['PRODUCT_NAME/PRODUCT_ID'] = 'pages/product/PRODUCT_ID';
However, if I were you I would make the URL to have the first segment to be the id of the product instead.
$route['PRODUCT_ID/PRODUCT_NAME'] = 'pages/product/PRODUCT_ID';
That way, if I only know the product id, I wouldn't have to type example.com//123 which might cause some problem. If I'm not mistaken, if you do that, CI will try to load a controller named 123.

Magento - Dynamically disable payment method based on criteria

I have an extremely simple module that allows a customer to "Purchase On Account". The module doesn't do anything special really (it was simply modified from a Cash On Delivery module.)
The problem is I only want to offer this payment method to logged in customers.
So far my module looks like this:
BuyOnAccount/
etc/
config.xml
system.xml
Model/
PaymentMethod.php
The content of PaymentMethod.php is:
class MyCompany_BuyOnAccount_Model_PaymentMethod extends Mage_Payment_Model_Method_Abstract
{
protected $_code = 'buyonaccount';
protected $_isInitializeNeeded = true;
protected $_canUseInternal = false;
protected $_canUseForMultishipping = false;
}
The config and system xml files contain the usual sort of thing (please let me know if you would like to see the code and i'll edit)
So bascically I need to disable the module if the user is not logged in (but obviously only for the current customer session!)
Any ideas?
Thanks
You can just add a method to your payment model called isAvailable(Mage_Sales_Model_Quote $quote) that returns a bool. For example, in your situation you could add something like:
public function isAvailable($quote = null) {
$isLoggedIn = Mage::helper('customer')->isLoggedIn();
return parent::isAvailable($quote) && $isLoggedIn;
}
The Mage_Payment_Model_Method_Free payment method that ships with Magento is an example of a payment method that employs this -- it'll only show if the basket total is zero.

How do order statuses/states work in Magento 1.4.x

As far as I understand Magento have various order statuses under global/sales/order/statuses which can be altered by either copying app/code/core/Mage/Sales/etc/config.xml to local scope or overriding it with your custom module.
There are also global/sales/order/states defined in the same file and as far as I understand states are something like statuses groups. Only states (not statuses) can be set at the order status in magento and statuses are something like states subdivisions. So in administrator interface you can change statuses of a placed order but you can't change state from the order status drop-down (you can change it by either invoicing the client or canceling the order).
As far as I understand you can easily add a new status to your Magento but can't add new state as states are somehow hardcoded with the rest or Magento order processing logic. I really hope that I'm wrong.
Please correct me if I'm wrong in any point as these are just my thoughts and it might be quite far from real Magento 1.4.x flow.
I'm quite sure that 'state' is free data, it can be set to ANY value using the setData option on an order instance. So if you write a custom module that can load an order, set data to one of your new 'states' and test with what ever custom logic you require.
$order = Mage::getModel('sales/order')->load(1);
$order->setData('state','myCustomState');
$order->setData('status','onCustomState');
echo $order->getState()
// Returns myCustomState
its worth bearing in mine that CLOSED/CANCELLED are protected states, so trying to use $order->setState('my_state') will fail on those order, but shouldn't fail on setData so you can overwrite a closed or cancelled order with this method.
if you were to overwrite the order model with a custom one you could add your own logic such as isOnCustomState() and allow the order to be handled in any way just by loading by id.
To add 'custom logic' to your order you could do something copy app\code\core\Mage\Sales\Model\Order.php into your local folder, then you can add functions into that model,
public function isActive(){ if($this->getState() == 'active'){ return true; } else { return false; }
public function isInActive(){ if($this->getState() == 'deactivated'){ return true; } else { return false; }
public function activate(){
if(!$this->isActive()){
$this->setData('state','active');
$this->setData('status','Active Subscription');
// some custom code to start a recuring payment
return $this;
}
}
public function deactiveate(){
if(!$this->isInActive()){
$this->setData('state','deactivated');
$this->sendOrderUpdateEmail(true,'Your subscription has been deactivated.');
// some custom code to stop a recuring payment
return $this;
}
}
now you can load an order and set activate or deactivate on that order to fire your custom code,
$order = Mage::getModel('sales/order')->load(1)->activate();
this code is all untested and just an example of somethings you could try, please don't just dump this code in your model and expect it to work perfectly. in code\core\Mage\Sales\etc\config.xml in the nodes sales/order/states add
<activated translate="label">
<label>Active Subscription</label>
<statuses>
<pending default="1"/>
</statuses>
<visible_on_front/>
</activated>
Magento Order is a finite state machine.
Therefore when you define status it would automatically try to define its state. Altering state directly is not recommended.
When you define status it checks various flags for shipment and invoices and depending in all those it would get the right state. Once order is in approved state however you can easily change status regardless of if there is invoice or any flag etc.

Customer session is different in different parts of a Magento website

I have a function inside of a Helper in Magento that returns whether or not a customer attribute equals one.
Here is my Helper class
class Nie_Nie_Helper_Data extends Mage_Core_Helper_Abstract {
public function isNieAdmin() {
if(Mage::getSingleton('customer/session')->getCustomer()->getNieAdmin() == 1) {
return true;
} else {
return false;
}
}
}
Now when I call this function from a class that extends Mage_Core_Block_Template, everything seems to work fine. However when I try to use this inside one of my controllers, it does not work. In fact when I do Mage::getSingleton('customer/session')->getCustomer()->debug() the only variable that is returned is the website_id.
Does anyone know what I have to do in order to get this to work?
At the time of the controller the session objects are not yet initialised (although the session variable must be) so it returns a blank model. My guess is the website_id is deliberately set in the creation of a customer object to act as a default.
You could access $_SESSION['customer'] directly to find what you need, but that is messy. An alternative would be to do what you want in an event that occurs later.
I hope someone can come up with a better answer than mine.
Ok it looks like I had to load up the session myself. I had to put the following in my functions:
Mage::getSingleton('core/session', array('name' => 'frontend'));
Hope this helps.

Resources