How can i create partial create memo? i.e. if total order value is £50 and I want to create a credit memo of £10. I am using the below code to create credit memo:
function createCreditMemo($orderId) {
$order = Mage::getModel('sales/order')->load($orderId, 'increment_id');
if (!$order->getId()) {
print_r('order_not_exists');
}
if (!$order->canCreditmemo()) {
Mage::log('cannot_create_creditmemo', null, 'product.txt');
print_r('cannot_create_creditmemo');
}
$data = array();
$refundToStoreCreditAmount = '10.22';
$service = Mage::getModel('sales/service_order', $order);
$creditmemo = $service->prepareCreditmemo($data);
// refund to Store Credit
if ($refundToStoreCreditAmount) {
// check if refund to Store Credit is available
if ($order->getCustomerIsGuest()) {
print_r('cannot_refund_to_storecredit');
}
$refundToStoreCreditAmount = max(
0,
min($creditmemo->getBaseCustomerBalanceReturnMax(), $refundToStoreCreditAmount)
);
if ($refundToStoreCreditAmount) {
$refundToStoreCreditAmount = $creditmemo->getStore()->roundPrice($refundToStoreCreditAmount);
$creditmemo->setBaseCustomerBalanceTotalRefunded($refundToStoreCreditAmount);
$refundToStoreCreditAmount = $creditmemo->getStore()->roundPrice(
$refundToStoreCreditAmount*$order->getStoreToOrderRate()
);
// this field can be used by customer balance observer
$creditmemo->setBsCustomerBalTotalRefunded($refundToStoreCreditAmount);
// setting flag to make actual refund to customer balance after credit memo save
$creditmemo->setCustomerBalanceRefundFlag(true);
print_r($refundToStoreCreditAmount.'<br/>');
//die('2');
}
}
//Mage::log($creditmemo, null, 'product.txt');
$creditmemo->setPaymentRefundDisallowed(true);
$creditmemo->register();
$orderCreditMemoStatusCode = Mage_Sales_Model_Order::STATE_CLOSED;
$orderCreditMemoStatusComment = 'Order Refunded.';
$saveTransaction = Mage::getModel('core/resource_transaction')->addObject ($creditmemo )->addObject ( $order )->save ();
$order->addStatusToHistory ( $orderCreditMemoStatusCode, $orderCreditMemoStatusComment, true );
$notifyCustomer = true;
$comment = 'testing refund';
$includeComment = true;
$creditmemo->setEmailSent(true);
// add comment to creditmemo
if (!empty($comment)) {
$creditmemo->addComment($comment, $notifyCustomer);
}
try {
Mage::getModel('core/resource_transaction')
->addObject($creditmemo)
->addObject($order)
->save();
// send email notification
$creditmemo->sendEmail($notifyCustomer, ($includeComment ? $comment : ''));
} catch (Mage_Core_Exception $e) {
print_r('data_invalid', $e->getMessage());
}
echo $creditmemo->getIncrementId();
}
In the below code, even if I set the $refundToStoreCreditAmount = 10; it still refunds the full amount. Any idea how to refund partially?
Related
My products have variable sizes which affect weight and I need to put weight logic in the cart to more accurately calculate shipping costs. I've moved a copy of app/code/core/Mage/Sales/Model/Quote/Item.php to the local code pool. I've been able to grab the associated product's base weight, however, I am not able to get the custom option (text field) value to do the math calculation before updating the cart. I'm doing this in the public function, setProduct. Here's what I have so far:
public function setProduct($product)
{
if ($this->getQuote()) {
$product->setStoreId($this->getQuote()->getStoreId());
$product->setCustomerGroupId($this->getQuote()->getCustomerGroupId());
}
//Get the Weight per UOM
$sku = $product->getSku();
$item = Mage::getModel('catalog/product')->loadByAttribute('sku',$sku);
$wpuom = $item->getResource()->getAttribute('weight_per_uom')->getFrontend()->getValue($item);
//Get the Length
$params = Mage::app()->getRequest()->getParams();
/** #var Mage_Catalog_Model_Product $product */
$info = new Varien_Object($params);
// Don't throw an exception if required options are missing
$processMode = Mage_Catalog_Model_Product_Type_Abstract::PROCESS_MODE_LITE;
$options = array();
foreach ($product->getOptions() as $option) {
/* #var $option Mage_Catalog_Model_Product_Option */
$group = $option->groupFactory($option->getType())
->setOption($option)
->setProduct($product)
->setRequest($info)
->setProcessMode($processMode)
->validateUserValue($info->getOptions());
$optionValue = $info->getData('options/' . $option->getId());
$options[] = array(
'label' => $option->getTitle(),
'value' => $group->getFormattedOptionValue($optionValue),
'value2' => $option->getValues(),
'option_id' => $option->getId(),
'option_type' => $option->getType()
);
//<<<This is Where I Cannot Get the Value for the Custom Option>>>
if($options[0]['label'] == 'Length') {
//print_r($options[0]['value']);
}
}
//Update Weight
$baseWeight = $item->getWeight();
$uom = $item->getResource()->getAttribute('uom')->getFrontend()->getValue($item);
if((($uom == 'Meters') && ($length >= 76)) || (($uom == 'Feet') && ($length >= 250))) { $spoolWeight = 3; }
else { $spoolWeight = 0; }
$finalWeight = ($baseWeight + ($length * $wpuom) + $spoolWeight);
$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;
}
When I try adding print_r($options[0]);, I get everything except value, it's not even an array. What am I missing in order to get the value?
You're likely going to run into issues with the wishlist and other functionality if you display the product price in various spots on your site such as category pages, wishlist and other areas on the site.
That being said, I made some modifications to your code and updated it below. I took a slightly different approach to get the end result. First, get all the cart items for the current session. If the product type is configurable, do some logic, if not, do other logic. Inside the logic, I am gathering the items, associated attribute values, custom options, and custom option values. I also added some functionality to add the length and the unit of measure to the sku. Then I went ahead and showed examples of how you can use direct mySQL queries to update the database with your new pricing, skus, weight, and other details.
public function setProduct($product)
{
if ($this->getQuote()) {
$product->setStoreId($this->getQuote()->getStoreId());
$product->setCustomerGroupId($this->getQuote()->getCustomerGroupId());
}
$quote = Mage::getSingleton('checkout/session')->getQuote();
foreach ($quote->getAllVisibleItems() as $itm){
$sku = $product->getSku();
$item = Mage::getModel('catalog/product')->loadByAttribute('sku',$sku);
$assocProd = Mage::getModel('catalog/product')->loadByAttribute('sku',$itm->getSku());
if($product->getTypeId() == 'configurable') { //configurable product
foreach ($product->getOptions() as $o) {
if($o->getTitle() == "YOUR CUSTOM OPTION LABEL" && $o->getType() == "field"){
$optionId = $o->getOptionId();
$opz = $itm->getOptionByCode('info_buyRequest');
$buyRequest = new Varien_Object($opz ? unserialize($opz->getValue()) : null);
foreach($buyRequest['options'] as $key => $value){
if($key == $optionId) {
$length = $value;
//here is your length... do with it what you please
}
//example of how to update the database
$itemId = $itm->getId();
$query = 'UPDATE `sales_flat_quote_item` SET `weight` = "'.$finalWeight.'", `display_sku` = "'.$displaySku.'" WHERE `item_id` = "'.$itemId.'"';
$resource = Mage::getSingleton('core/resource');
$writeConnection = $resource->getConnection('core_write');
$writeConnection->query($query);
}
}
}
}
}
else { //simple product
if($product->getOptions()) { //has options
foreach ($product->getOptions() as $o) {
if($o->getTitle() == "YOUR OPTION LABEL" && $o->getType() == "field"){
$optionId = $o->getOptionId();
$opz = $itm->getOptionByCode('info_buyRequest');
$buyRequest = new Varien_Object($opz ? unserialize($opz->getValue()) : null);
foreach($buyRequest['options'] as $key => $value){
$finalWeight = '';
if($key == $optionId) {
$length = $value;
//here's your length value for simple products
}
//to update the database
$itemId = $itm->getId();
$query = 'UPDATE `sales_flat_quote_item` SET `weight` = "'.$finalWeight.'", `display_sku` = "'.$displaySku.'" WHERE `item_id` = "'.$itemId.'"';
$resource = Mage::getSingleton('core/resource');
$writeConnection = $resource->getConnection('core_write');
$writeConnection->query($query);
}
}
}
}
}
else { //doesn't have options
//this would be your logic for a simple product with no options
}
}
I hope this helps and feel free to let me know if you have any questions!
I am generating orders from a custom web service called from a mobile app. However when the order is finally generated, I get "Original Price" as Rs0.00 . This is creating a problem since we have third party integrations for invoicing and Shipping.
However in the normal course of action when order is generated from website, the Original Price is correct.
I inspected the sales_flat_order_item table for both these orders, the original_price is indeed 0.00 in the first order, Hence I must be missing something in my code which is not setting the original_price for the orderItem.
Here is the code where the quote is converted to order.
public function placeorder($custid, $Jproduct, $store, $address, $couponCode, $is_create_quote, $transid, $payment_code, $shipping_code, $currency, $message)
{
$res = array();
$quantity_error = array();
try {
$quote_data = $this->prepareQuote($custid, $Jproduct, $store, $address, $shipping_code, $couponCode, $currency, 1, 0);
if ($quote_data["status"] == "error") {
return $quote_data;
}
$quote = Mage::getModel('sales/quote')->load($quote_data['quote_id']);
$quote = $this->setQuoteGiftMessage($quote, $message, $custid);
$quote = $this->setQuotePayment($quote, $payment_code, $transid);
$convertQuote = Mage::getSingleton('sales/convert_quote');
try {
$order = $convertQuote->addressToOrder($quote->getShippingAddress());
}
catch (Exception $Exc) {
echo $Exc->getMessage();
}
$items = $quote->getAllItems();
foreach ($items as $item) {
$orderItem = $convertQuote->itemToOrderItem($item);
$order->addItem($orderItem);
}
try {
$decode_address = json_decode(base64_decode($address));
$order->setCustomer_email($decode_address->billing->email);
$order->setCustomerFirstname($decode_address->billing->firstname)->setCustomerLastname($decode_address->billing->lastname);
}
catch (Exception $e) {
}
$order->setBillingAddress($convertQuote->addressToOrderAddress($quote->getBillingAddress()));
$order->setShippingAddress($convertQuote->addressToOrderAddress($quote->getShippingAddress()));
$order->setPayment($convertQuote->paymentToOrderPayment($quote->getPayment()));
$order->save();
$quantity_error = $this->updateQuantityAfterOrder($Jproduct);
$res["status"] = 1;
$res["id"] = $order->getId();
$res["orderid"] = $order->getIncrementId();
$res["transid"] = $order->getPayment()->getTransactionId();
$res["shipping_method"] = $shipping_code;
$res["payment_method"] = $payment_code;
$res["quantity_error"] = $quantity_error;
$order->addStatusHistoryComment("Order was placed using Mobile App")->setIsVisibleOnFront(false)->setIsCustomerNotified(false);
if ($res["orderid"] > 0 && ($payment_code == "cashondelivery" || $payment_code == "banktransfer" || $payment_code == "free")) {
$this->ws_sendorderemail($res["orderid"]);
$order->setState(Mage_Sales_Model_Order::STATE_NEW, true)->save();
$res["order_status"] = "PENDING_PAYMENT";
} else {
$order->setState(Mage_Sales_Model_Order::STATE_PENDING_PAYMENT, true)->save();
$res["order_status"] = "PENDING_PAYMENT";
}
}catch (Exception $except) {
$res["status"] = 0;
$res["shipping_method"] = $shipping_code;
$res["payment_method"] = $payment_code;
}
return $res;
}
It would be very helpful if someone points out what I missed. I will edit if any other info is required.
Missing original_price indicates that you didn't run collectTotals() on the quote yet, try the following:
$quote->collectTotals()->save();
$order->save();
I have an order that looks like this:
I want to create a shipment for the following on this order (not for everything):
2 x VCF001
1 x SBA364
To achieve this, I found the following info on the shipment api: http://bit.ly/17rpuwj
Based on this documentation of the API, I came up with the following code. When I tried to execute it, I got the following error Cannot create an empty shipment:
$order_number = '300000002';
$order = Mage::getModel('sales/order')->loadByIncrementId($order_number);
$allocations = array(
array('sku' => 'VCF001', 'allocated_qty' => 2),
array('sku' => 'SBA364', 'allocated_qty' => 1)
);
function GetOrderItemId($order_items, $sku) {
foreach ($order_items as $order_item) {
if ($order_item->getSku() == $sku) {
return $order_item->getItemId();
}
}
return 0;
}
function CreateShipment($order, $allocations)
{
// Get Order Items
$order_items = $order->getItemsCollection();
// Parepare Item Qtys For Shipment
$item_qtys = array();
foreach ($allocations as $allocation) {
$item_qtys[] = array(GetOrderItemId($order_items,
$allocation['sku']) => $allocation['allocated_qty']);
}
// Anticipate Errors
try
{
// Create Shipment
$shipment = new Mage_Sales_Model_Order_Shipment_Api();
$shipmentId = $shipment->create($order->getIncrementId(),
$item_qtys, 'Pick #123 Sent to Warehouse');
// Done
echo 'Shipment Created - ID #'. $shipmentId;
}
catch (Exception $e)
{
print_r($e);
}
}
CreateShipment($order, $allocations);
Any idea why this isn't working as intended? See the full exception log here : http://pastebin.com/raw.php?i=GMN4WCAE
Try it like this instead :
protected function _createShipment($order, $qtysForProducts)
{
$shipment = $order->prepareShipment($qtysForProducts);
if ($shipment) {
$shipment->register();
$shipment->sendEmail(true)
->setEmailSent(true)
->save();
$order->setIsInProcess(true);
$transactionSave = Mage::getModel('core/resource_transaction')
->addObject($shipment)
->addObject($shipment->getOrder())
->save();
}
return $shipment;
}
I've been struggling with this for a while, should be pretty straight forward but...
I'm trying to apply coupon to order using magento cart.coupon.add api.
The product is Virtual
here is my code ( and I've tried everything i could find on google before I came here ):
protected function _applyCoupon($quoteId, $couponCode, $store = null)
{
$coupon = Mage::getModel('salesrule/coupon');
$coupon->loadByCode($couponCode);
Mage::log('_applyCoupon('.$couponCode.')');
$quote = $this->_getQuote($quoteId, $store);
if (!$quote->getItemsCount()) {
// $this->_fault('quote_is_empty');
}
$oldCouponCode = $quote->getCouponCode();
if (!strlen($couponCode) && !strlen($oldCouponCode)) {
return false;
}
try {
//$quote->getShippingAddress()->setCollectShippingRates(true);
$quote->setCouponCode($couponCode);
$quote->setTotalsCollectedFlag(false)->collectTotals();
$quote->collectTotals();
$quote->save();
Mage::getModel("checkout/session")->setData("coupon_code",$couponCode);
Mage::getModel('checkout/cart')->getQuote()->setCouponCode($couponCode)->save();
Mage::getModel('checkout/cart')->getQuote()->collectTotals();
Mage::getModel('checkout/cart')->getQuote()->save();
Mage::log("_applyCoupon : Set coupon to quote:".$quote->getCouponCode());
} catch (Exception $e) {
$this->_fault("cannot_apply_coupon_code", $e->getMessage());
}
Mage::log('3');
if ($couponCode) {
Mage::log("Coupon applied");
if (!$couponCode == $quote->getCouponCode()) {
Mage::log('3.2');
$this->_fault('coupon_code_is_not_valid');
}
}
return true;
}
I've also tried applying coupon to address:
protected function applyDiscountToAddress($address,$quote)
{
Mage::log('applyDiscountToProduct ...');
$coupon = Mage::getModel('salesrule/coupon');
Mage::log("checkoutprocess: checkout/session:".Mage::getModel("checkout/session")->getData("coupon_code"));
$coupon->loadByCode(Mage::getModel("checkout/session")->getData("coupon_code"));
$rule = Mage::getModel('salesrule/rule');
$rule->load($coupon->getRuleId());
$discountamount = $rule->getDiscountAmount();
$dbldiscount = 0.00 + $discountamount;
$grandTotal = Mage::getModel('checkout/cart')->getQuote()->getGrandTotal();
$subTotal = Mage::getModel('checkout/cart')->getQuote()->getSubtotal();
Mage::log('applyDiscountToProduct $grandTotal:'.$grandTotal);
Mage::log('applyDiscountToProduct $subTotal:'.$subTotal);
$gTotal = $grandTotal - $dbldiscount;
$address->setDiscountAmount($dbldiscount)
->setBaseDiscountAmount($dbldiscount)
->setGrandTotal($gTotal)
->setBaseGrandTotal($gTotal);
$grandTotal = $address->getGrandTotal();
$baseGrandTotal = $address->getBaseGrandTotal();
Mage::log('applyDiscountToProduct Address:$grandTotal:'.$grandTotal);
Mage::log('applyDiscountToProduct Address:$baseGrandTotal:'.$baseGrandTotal);
$totals = array_sum($address->getAllTotalAmounts());
$baseTotals = array_sum($address->getAllBaseTotalAmounts());
$address->setGrandTotal($grandTotal+$totals);
$address->setBaseGrandTotal($baseGrandTotal+$baseTotals);
}
the coupon is valid but after the order being placed in the Magento admin I see that the discount amount = 0.0 and the user was charged full amount to his credit card.
Anyone....? Help...?
Finally found an answer
I needed to call setCouponCode() before adding any items to quote.
$quote= Mage::getModel('sales/quote')->setCouponCode($couponCode);
I have a tricky shipping issue that I'm trying to work out. I have a custom extension that calculates the table rates for all of the domestic shipping. But for international, one type of product(category A) is a flat $35/product shipping fee and the rest of the products (categories B and C) are calculated by UPS and USPS. The only way I've been able to figure out how to properly calculate shipping if a customer purchases both types of products is to create a table rate for Category A, then pass it along to UPS/USPS as a handling fee. Is there a variable/method I can use for this process? I haven't yet found one.
As requested, here's my function:
public function collectRates(Mage_Shipping_Model_Rate_Request $request)
{
// Cut out code where it adds up the categories and the number of items in each category
$rates = $this->getRates($request, $_categories);
if (!empty($rates))
{
$rateTypes = array();
foreach($rates as $rate)
{
$rateTypes[] = $rate['method_name'];
}
$rateTypes = array_unique($rateTypes);
$i=0;
// Create array to pass along to UPS/USPS, if needed
$tempCategories = $_categories;
foreach($rateTypes as $rateType)
{
$groupPrice = 0;
foreach($_categories as $category=>$catQty)
{
$rateExists = false;
$standardRate = 0;
foreach($rates as $rate)
{
$rateCats = explode(',',$rate['category_list']);
if(in_array($category,$rateCats) && $rate['method_name'] == $rateType )
{
$rateExists = true;
if($rate['condition_type'] == 'I'){
$ratePrice = $rate['price'] * $catQty;
}
else if ($rate['condition_type'] == 'O') {
$ratePrice = $rate['price'];
}
unset($tempCategories[$category]);
}
else if(in_array($category,$rateCats) && $rate['method_name'] == "Standard" && $rateType != "Standard")
{
if($rate['condition_type'] == 'I'){
$standardRate += $rate['price'] * $catQty;
}
else if ($rate['condition_type'] == 'O') {
$standardRate += $rate['price'];
}
unset($tempCategories[$category]);
}
}
if($rateExists == false)
{
$groupPrice += $standardRate;
}
else
$groupPrice += $ratePrice;
}
if(count($tempCategories) > 0)
{
// Figure out how to pass the $groupPrice to other shipping methods here
}
else {
$method = Mage::getModel('shipping/rate_result_method');
$method->setCarrier('shippingcodes');
$method->setCarrierTitle($this->getConfigData('title'));
$method->setMethod('shippingcodes_'.$rateType);
$method->setMethodTitle($rateType);
$method->setPrice($groupPrice);
$result->append($method);
}
}
}
else
return false;
return $result;
}