Multiple Origin Zip Codes in Magento Checkout - magento

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

Related

How to change the weight before sending to fedex magento?

In magento checkout page, after giving billing information and shipping information, i understand that these details are sending to fedex then the shipping rates are populating in chekout page, before sending theses details to fedex, i want to change the weight of the product, i Want to add additional weights for each products,
suppose user adding a product with weight of 2 pounds, i want to send
these weight to 2*5 = 10pounds, how can i do that in magento? please
help.
Not sure to understand what you want exactly but I'll give a try.
I think you can override Mage_Checkout_OnepageController::savePaymentAction method in your local pool and in your local method, dispatch your own new event 'save_payment_action_before' and pass your objects as parameters.
In your fedex module, create an observer, get your object and change the order weight before it's sent to fedex.
To create your custom event, check this post
Finally i find out that it is happening in the sales/quote/item.php file, there is a function called setProduct, here we need to add addititonal info while setting data.
public function setProduct($product)
{
$batchQty = Mage::getModel('catalog/product')->load($product->getId())->getBatchQty();
$roleId = Mage::getSingleton('customer/session')->getCustomerGroupId();
$userrole = Mage::getSingleton('customer/group')->load($roleId)->getData('customer_group_code');
$userrole = strtolower($userrole);
if ($this->getQuote()) {
$product->setStoreId($this->getQuote()->getStoreId());
$product->setCustomerGroupId($this->getQuote()->getCustomerGroupId());
}
if($userrole=="retailer" && $batchQty>0 ){
$this->setData('product', $product)
->setProductId($product->getId())
->setProductType($product->getTypeId())
->setSku($this->getProduct()->getSku())
->setName($product->getName())
->setWeight($this->getProduct()->getWeight()*$batchQty)
->setTaxClassId($product->getTaxClassId())
->setBaseCost($product->getCost())
->setIsRecurring($product->getIsRecurring());
} else {
$this->setData('product', $product)
->setProductId($product->getId())
->setProductType($product->getTypeId())
->setSku($this->getProduct()->getSku())
->setName($product->getName())
->setWeight($this->getProduct()->getWeight())
->setTaxClassId($product->getTaxClassId())
->setBaseCost($product->getCost())
->setIsRecurring($product->getIsRecurring());
}
if ($product->getStockItem()) {
$this->setIsQtyDecimal($product->getStockItem()->getIsQtyDecimal());
}
Mage::dispatchEvent('sales_quote_item_set_product', array(
'product' => $product,
'quote_item' => $this
));
return $this;
}

Magento OnePage modification, need to skip a step

I am completely new to Magento and we are using version 1.4 currently. The steps on the OnePage checkout are:
Checkout Method (Guest or sign-in)
Billing Information
Shipping Information
Delivery Information
Payment Information
Order Review
I want to skip Delivery Information. To do this I have done two things:
1. Changed (actually extended) the core Checkout class to not include #4 Delivery Information ('shipping_information'),
2. in the Controller, call the Checkout class method saveShippingMethodAction( ) inside of saveShippingAction( ) (since there is never a submission of shipping method by user), with a data value passed manually.
Everything works as expected, and the step is skipped, however inside Checkout::saveShippingMethodAction( ) there are these two lines:
Mage::dispatchEvent('checkout_controller_onepage_save_shipping_method', array('request'=>$this->getRequest(), 'quote'=>$this->getOnepage()->getQuote()));
$this->getResponse()->setBody(Mage::helper('core')->jsonEncode($result));
The problem is in the usage of 'request'=>$this->getRequest(). The actual request is not shipping_method but rather shipping, so the output (i.e. the HTML form string that should be passed to step #5, Payment information) is not loaded, and so step #5 is blank.
My first instict is how can I simulate a request, but there is probably a "Magento Way" to do this. Can anyone tell me what that might be, or how I can prep getRequest( ) and maybe getResponse( ) as if I'd submitted that specific form? Thanks!
I understood what you want to do but i didn't understood what you did.
Ok, i will explain you something here.If you are talking about magento default onepage checkout than the thing you are talking about Delivery Information it is actually the shipping method.
You also were asking about something
Mage::dispatchEvent('checkout_controller_onepage_save_shipping_method', array('request'=>$this->getRequest(), 'quote'=>$this->getOnepage()->getQuote()));
$this->getResponse()->setBody(Mage::helper('core')->jsonEncode($result));
It actually don't have anything to do with your code because it is the place to insert your event, Its like a hook.
Now the real problem and its solution.I haven't tried it yet but this should work.
If you see the
app/code/core/Mage/checkout/controllers/OnepageController.php
file.You need to make changes in this file. First override this controller to your own module, this is the preferred way but you can test in core files too.
Now in this file you will see two function
public function saveShippingAction()
{
//This function saves the shipping information of customer
}
and
public function saveShippingMethodAction()
{
//this function saves the shipping method
}
In the first function you will see some code like this
if (!isset($result['error'])) {
$result['goto_section'] = 'shipping_method';
$result['update_section'] = array(
'name' => 'shipping-method',
'html' => $this->_getShippingMethodsHtml()
);
}
this redirects to shipping method.If you want to by pass the shipping method steps(in your case delivery information) then replace the above code by
if (!isset($result['error'])) {
$result['goto_section'] = 'payment';
$result['update_section'] = array(
'name' => 'payment-method',
'html' => $this->_getPaymentMethodsHtml()
);
}
This will complete your redirection part from controller side now remove the block that displays the shipping method block from the layout file. and that's it.
Hope this helps.

Add checkbox to Magento checkout?

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.

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.

How to toggle Shipping Methods Based on Products?

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.

Resources