I want to be able to toggle what shipping method is used based upon the items that are in the cart. Where is the best place to "check" this and grab the right shipping method?
The way it will work is that there will be a standard shipping method that is used, and then, if there are certain items in the cart another method will override that other method.
I think I could do this by hacking around in the individual shipping modules, but I'd like to do this the "right" way.
shipping methods have built in method in Mage_Shipping_Model_Carrier_Abstract that they all extend:
public function isActive();
extend your shipping methods and add your logic to that method and don't forget to call parent::isActive(); first
Try and Try as I did to implement a custom override, I was only able to find success when I copied the entire Tablerates.php file to local/Mage/Shipping/Model/Carrier/Tablerates.php
isActive() was still not "the way" at that point. I had to introduce some code in the collectRates() function like so:
// check the store
if (Mage::app()->getStore()->getId() == 2){
// check for free shipping
$packageValue = $request->getPackageValueWithDiscount();
$freeShipping = ($request->getFreeShipping()) || ($packageValue >= Mage::getStoreConfig("carriers/freeshipping/free_shipping_subtotal", $this->getStore()));
if($freeShipping)
return false;
$foundFlag = false;
foreach ($request->getAllItems() as $item) {
$org_product = Mage::getModel('catalog/product')->load($item->getProductId());
if($org_product->getDeliveryFlag() == "workstationmats")
{
$foundFlag = true;
}
}
if ($foundFlag == false)
return false;
}
// end shpping mod
This was placed right at the beginning of the collectRates function.
Related
My Problem:
I want to use observer before checkout onepage page begins, in that, based on products in the cart, I want to disable shipping if it doesn't match certain conditions.
I am using [controller_action_predispatch_checkout_onepage_index] event observer, this basically call before checkout page starts loading...I am able to get all products and quote info but didn't found any method to disable shipping.
What I am looking for,
from the observer, is it possible to disable shipping by calling certain magento methods or any other solutions?
Overriding collectRates()
After getting few replies, I am trying to override collectRates() method using code given below
$method = Mage::getModel('shipping/rate_result_method');
$method->setCarrier('flatrate');
$method->setCarrierTitle($this->getConfigData('title'));
$method->setMethod('flatrate');
$method->setMethodTitle($this->getConfigData('name'));
if ($request->getFreeShipping() === true || $request->getPackageQty() == $this->getFreeBoxes()) {
$shippingPrice = '0.00';
}
$method->setPrice($shippingPrice);
$method->setCost($shippingPrice);
$result->append($method);
Although, I dont want to enable flatrate shipping method either. I just want to disable shipping, or optionally return with reply something like
Free shipping $0.00
User can select that to continue to next step. Please help me from here..
What should I use in $method->setCarrier('??????');
or what changes I do need to do in above code?
I think it might be better to either override or subclass the individual Carrier models.
All carriers implement a method "Mage_Shipping_Model_Carrier_Abstract::collectRates()" to return results.
It is possible to get information about the current quote to modify the returned rates/options from within this method.
That said, if there is a way to do it with an observer, it would probably be cleaner/easier.
Finally I have override shipping method, its a two step code but you can reduce it to one step if you wish. Here is my two step solution.
Before we start our shipping class needs to extend and implement
extends Mage_Shipping_Model_Carrier_Abstract
implements Mage_Shipping_Model_Carrier_Interface
Now, We create a protected method
protected function _createMethod($request, $method_code, $title, $price, $cost)
{
$method = Mage::getModel('shipping/rate_result_method');
$method->setCarrier('australiapost'); // in my case its australia post, it can be any other whatever you are using
$method->setCarrierTitle($this->getConfigData('title'));
$method->setMethod($method_code);
$method->setMethodTitle($title);
$method->setPrice($this->getFinalPriceWithHandlingFee($price));
$method->setCost($cost);
return $method;
}
Now just use code below to create new method with free shipping and bypass existing shipping calculator, this code will go inside collectRates(Mage_Shipping_Model_Rate_Request $request) method
// PROCESS WILL RETURN FREE SHIPPING
if ($request->getFreeShipping() === true || $request->getPackageQty() == $this->getFreeBoxes()) {
$shippingPrice = '0.00';
}
$shipping_method = 'Free Shipping';
$method = $this->_createMethod($request, $shipping_method, 'Shipping Disabled', '0.00', '0.00');
$result->append($method);
return $result;
By Doing this, you can get result like below in checkout and user can easily click continue to next step.
Shipping Disabled $0.00
I've been searching, trying, and failing alot here. What I want is to add a checkbox, on the Shipping page of Onepage checkout, the standard magento checkout.
I want to create a checkbox so that customers can check it if they want their products to be placed on their address without a signature.
I've been messing around with some old "Accept Terms" checkboxes, but with no luck.
I'm hoping that somebody might have had to make the same kind of customization.
What you can do is save the preference in the checkout/session via an observer. First, add the checkbox to the shipping section and give it the property of name=shipping[no_signature]. Then, create a new module and hook into the event controller_action_postdispatch_checkout_onepage_saveShipping and then use this code:
public function controller_action_postdispatch_checkout_onepage_saveShipping($observer)
{
$params = (Mage::app()->getRequest()->getParams()) ? Mage::app()->getRequest()->getParams() : array();
if (isset($params['shipping']['no_signature']) && $params['shipping']['no_signature']) {
Mage::getSingleton('checkout/session')->setNoSignature(true);
} else {
Mage::getSingleton('checkout/session')->setNoSignature(false);
}
return $this;
}
Then, when the order is about to be placed, hook into the event sales_order_place_before you can add a comment to the order like this:
public function sales_order_place_before($observer)
{
$order = $observer->getOrder();
if (Mage::getSingleton('checkout/session')->getNoSignature()) {
$order->setCustomerNote('No signature required.');
} else {
$order->setCustomerNote(null);
}
return $this;
}
When you go to Sales > Orders, you should see a comment on the order regarding if the customer requires a signature or not. This is under the assumption that no other module or custom code is injecting anything into the customer_note field on the order object.
I followed the steps in creating a payment method in this tutorial (http://www.magentocommerce.com/wiki/5_-_modules_and_development/payment/create-payment-method-module) everything works fine, but i need an additional functionality.
additional 6% charge to the total if the payment method is selected.
I also use this module - http://www.magentocommerce.com/magento-connect/payment-method-charge-4050.html but I need 2 condition. That is why I created new payment method.
1st payment method - 6% charge
2nd payment method - 2% charge
Thanks in advance.
More than likely your going to want to just create an observer to do what your are needing:
You'll need to look around for the proper observer event to hook into, however here is an example observer method:
public function updateShippingAmount( $observer )
{
$MyPaymentMethod = Mage::getSingleton('namespace/mypaymentmethod');
$order = $observer->getEvent()->getOrder();
$payment = $order->getPayment()->getData();
if( $payment['method'] == $MyPaymentMethod->getCode() )
{
$shipping_amount = $order->getShippingAmount();
$order->setShippingAmount( $shipping_amount + $MyPaymentMethod->getPostHandlingCost() );
}
}
Taken from this article:
http://www.candesprojects.com/magento/add-payment-method-handling-cost/
More reading on how to create an observer:
http://www.magentocommerce.com/wiki/5_-_modules_and_development/0_-_module_development_in_magento/customizing_magento_using_event-observer_method
Recently I have the same requirement and I fixed by implementing event-observer method.
In fact you can add any additional shipping cost to any shipping method for any condition by implementing event called sales_quote_collect_totals_before
And the observer model method(dummy code though) looks like:
public function salesQuoteCollectTotalsBefore(Varien_Event_Observer $observer)
{
/**#var Mage_Sales_Model_Quote $quote */
$quote = $observer->getQuote();
$someConditions = true; //this can be any condition based on your requirements
$newHandlingFee = 15;
$store = Mage::app()>getStore($quote>getStoreId());
$carriers = Mage::getStoreConfig('carriers', $store);
foreach ($carriers as $carrierCode => $carrierConfig) {
if($carrierCode == 'fedex'){
if($someConditions){
Mage::log('Handling Fee(Before):' . $store->getConfig("carriers/{$carrierCode}/handling_fee"), null, 'shipping-price.log');
$store->setConfig("carriers/{$carrierCode}/handling_type", 'F'); #F - Fixed, P - Percentage
$store->setConfig("carriers/{$carrierCode}/handling_fee", $newHandlingFee);
###If you want to set the price instead of handling fee you can simply use as:
#$store->setConfig("carriers/{$carrierCode}/price", $newPrice);
Mage::log('Handling Fee(After):' . $store->getConfig("carriers/{$carrierCode}/handling_fee"), null, 'shipping-price.log');
}
}
}
}
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.
I'm working on a Magento storefront for a client. They use dropshippers, so a single zip code doesn't do us much help. We do have it set for the most common zip code from which the client ships, so, in many cases, it's ok.
However, in some cases, there is a different origin zip code that needs to be used. In more rare cases, we will have multiple origin zip codes. When there is a zip that differs from the main one, we have stored this in an attribute called 'origin zip' (creative, huh?)
Where should I be looking to make the modifications? We're only using the UPS shipping method, and what I'm looking to do is, before calculating shipping, to grab whatever origin zips may be in the cart (I think we've got this part), but then, depending on the results, I may need to iterate through the shipping calculation and add the values together - i.e. in the case they order one product with an origin zip code, and another product without an origin zip code, it would have to calculate the first, then the second, and then add them together.
If someone could point us in the correct direction of which php files or classes we'll need to modify, I would greatly appreciate it.
First of all you need to add your custom attributed to list of attributes that will be used in shopping cart.
Follow these answer on stackoverflow:
How to add custom uploaded images to cart in magento 1.4.1.1?
Then you need to create your custom shipping method, maybe extended from yours one. It should walk through items it receives from shipping request and check for different zip origin, then calculate rate for them separately.
I hope for you it will not be a problem to create a module that will extend existing shipping method functionality.
Cheers!
UPDATE
For adding your attribute to product that is loaded in the cart item use such configuration:
<config>
<global>
<sales>
<quote>
<item>
<product_attributes>
<origin_zip />
</product_attributes>
</item>
</quote>
</sales>
</global>
</config>
Then in shipping method model use something like this (used USPS as example):
public function collectRates(Mage_Shipping_Model_Rate_Request $request)
{
if (!$this->getConfigFlag('active')) {
return false;
}
$defaultOriginZip = Mage::getStoreConfig('shipping/origin/postcode', $this->getStore());
$requestDataByOriginZip = array();
// Walking through quote items
foreach ($request->getAllItems() as $quoteItem) {
// If virtual or not shippable separately, it should be skipped
if ($quoteItem->isVirtual() || $quoteItem->isDummy(true)) {
continue;
}
// Retrieving origin zip code
if ($quoteItem->getProduct()->getOriginZip()) {
$zipCodeForCalculation = $quoteItem->getProduct()->getOriginZip();
} else {
$zipCodeForCalculation = $defaultOriginZip;
}
if (!isset($requestDataByOriginZip[$zipCodeForCalculation])) {
// Default values initialization for this zip code
$requestDataByOriginZip[$zipCodeForCalculation] = array(
'orig_postcode' => $zipCodeForCalculation,
'package_weight' => 0,
'package_value' => 0,
// etc...
);
}
$requestDataByOriginZip[$zipCodeForCalculation]['package_weight'] += $quoteItem->getRowWeight();
$requestDataByOriginZip[$zipCodeForCalculation]['package_value'] += $quoteItem->getBaseRowTotal();
// Etc...
}
$results = array();
foreach ($requestDataByOriginZip as $requestData) {
$requestByZip = clone $request; // Cloning to prevent changing logic in other shipment methods.
$requestByZip->addData($requestData);
$this->setRequest($requestByZip);
// Returns rate result for current request
$results[] = $this->_getQuotes();
}
$yourMergedResult = Mage::getModel('shipping/rate_result');
foreach ($results as $result) {
// Logic for merging the rate prices....
}
return $yourMergedResult;
}
The class usa/shipping_ups is what handles these requests, and specifically the method setRequest seems to have what you need:
if ($request->getOrigPostcode()) {
$r->setOrigPostal($request->getOrigPostcode());
} else {
$r->setOrigPostal(Mage::getStoreConfig('shipping/origin/postcode', $this->getStore()));
}
If you can add the orig_postcode to the shipping request, UPS will return a quote based on that origin.
One approach to this would be to override Mage_Shipping_Model_Rate_Request and add a method called getOrigPostcode. By virtue of being a real method, this would override the default Magento getter/setter behavior. Have this method query the contents of the request to find out which zip needs to be used.
Hope that helps!
Thanks,
Joe