Capture partial amount once order is placed - magento

I have created a link in Magento admin to create the invoice for individual product, But while calling the function $order->prepareInvoice($qtys) it will add all the product in invoice even I am passing only one item.
I am using below code.
$order = Mage::getModel('sales/order')->load($this->getRequest()->getParam('order_id'));
$count = $order->getTotalItemCount();
$qtys = Array
(
[370] => 1
);
$invoice = $order->prepareInvoice($qtys);
if (!$invoice->getTotalQty()) {
Mage::throwException(Mage::helper('core')->__('Cannot create an invoice without products.'));
}
$amount = $invoice->getGrandTotal();
$invoice->register()->pay();
$invoice->getOrder()->setIsInProcess(true);
$history = $invoice->getOrder()->addStatusHistoryComment('Partial amount of $'. $amount .' captured automatically.', false);
$history->setIsCustomerNotified(true);
$order->save();
Mage::getModel('core/resource_transaction')
->addObject($invoice)
->addObject($invoice->getOrder())
->save();
$invoice->save();
Any Suggestion ?

The logic found in Mage_Sales_Model_Service_Order::prepareInvoice, the method which you are ultimately calling to prepare the invoice, reveals what is at play here. The following loop is employed, and the inner else-if block is where the qty is set when an array of qtys is passed in:
foreach ($this->_order->getAllItems() as $orderItem) {
if (!$this->_canInvoiceItem($orderItem, array())) {
continue;
}
$item = $this->_convertor->itemToInvoiceItem($orderItem);
if ($orderItem->isDummy()) {
$qty = $orderItem->getQtyOrdered() ? $orderItem->getQtyOrdered() : 1;
} else if (!empty($qtys)) {
if (isset($qtys[$orderItem->getId()])) {
$qty = (float) $qtys[$orderItem->getId()];
}
} else {
$qty = $orderItem->getQtyToInvoice();
}
$totalQty += $qty;
$item->setQty($qty);
$invoice->addItem($item);
}
The $qtys variable is the array which you are passing in to the prepareInvoice call. In your case, you are only passing an index for the item you wish to add to the invoice. Per the documentation (and the above loop), this should work, except for one minor problem: the above loop is not resetting the value of $qty at the top of the loop to 0. This does not pose a problem when called from the core code which processes initialization of the invoice when created from the admin via the pre-existing form, as the form which is being submitted will always contain a value for each item on the order, and in the case of only 1 item being invoiced, all others will hold a 0 qty value thus working around the failure to reset the value of $qty.
To solve your problem, try setting your $qtys variable like so (I'm assuming 370 and 371 are the two order item entity ids):
$qtys = array(
370 => 1,
371 => 0,
);
An alternative which I might suggest would be to simply have your "Create Invoice" link set the appropriate values in the form to invoice the individual item and then submit the form directly. This way you'll be relying on the known-to-be-working core controller for the heavy lifting. This will, of course, only work if you are not doing anything fairly customized beyond invoicing the single item. :)

Related

Get the next order increment id during checkout?

I am developing a custom payment gateway. It uses OrderIncrementID to identify which Order was the payment made for. I have every functionality running after the Order has been placed, i.e. after checkout, except one in the checkout page itself.
In the checkout page, Order was not created, getting an OrderIncrementID seems very difficult. We have to overwrite the order creation in the checkout such that it will be created after the payment method selection which sounds very complicated and dangerous to overwrite the flow. An alternative is to use QuoteID, but the tradeoff is that I have to implement a convertion from QuoteID to OrderIncrementID.
What can I do in this case to get an OrderIncrementID in the checkout page? especially after the payment method selection
You actually already have a reserved order id on the quote.
You just have to do :
$quote = Mage::getSingleton('checkout/session')->getQuote();
$quote->getReservedOrderId(); // this will be your order_increment_id
I developed bellow code to get next increment ID
I am not sure this will give correct result always.
But, this can help you
Please bellow code in any resource model to call
For example : place code in Names_Test_Model_Resource_Test class
public function getNextIncrementId(){
$store = Mage::app()->getStore();
$resource = Mage::getSingleton('core/resource');
$readConnection = $resource->getConnection('core_read');
$entityStoreTable = $resource->getTableName('eav_entity_store');
$entityTypeTable = $resource->getTableName('eav_entity_type');
$selectEntity = $readConnection->select()->from($entityTypeTable, "*")
->where("entity_type_code = 'order'");
$entityTypeRow = $readConnection->fetchRow($selectEntity);
if(isset($entityTypeRow['entity_type_id']) && $entityTypeRow['entity_type_id'] > 0){
$orderEntityTypeId = $entityTypeRow['entity_type_id'];
$entityStoreSelect = $readConnection->select()->from($entityStoreTable, "*")
->where("store_id = ? AND entity_type_id = $orderEntityTypeId", $store->getId());
$row = $readConnection->fetchRow($entityStoreSelect);
$lastIncrementId = 0;
if(isset($row['increment_last_id'])){
$lastIncrementId = $row['increment_last_id'] + 1;
}
return $lastIncrementId;
}
return 0;
}
To call this function you can use
$nextIncrementId = Mage::getResourceModel('test/test')->getNextIncrementId();
We can also find last increment id from orders table
Please comment for better solutions

Increase product stock on sale

I'm trying to make something different with my Magento instance;
I want to increase product's stock (in a certain condition) when I'm selling a product. I've added a custom checkbox in the Magento Admin panel and when it's checked I expect to increase product's quantity.
I'm currently investigating the following method:
Mage_Sales_Model_Service_Quote:submitOrder()
Is it a good place to start looking at? Any tip on this problem?
I think I've achieved what I wanted.
I've added the following lines at Mage_Sales_Model_Service_Quote:submitOrder()
...
// $mySpecialCondition = form.checkbox
foreach ($quote->getAllItems() as $item) {
if($mySpecialCondition){
$item->setQty(0 - $item->getQty(), true);
}
...
and also changed the method Mage_Sales_Model_Quote_Item:_prepareQty to accept negative values:
protected function _prepareQty($qty, $ignoreValue = false)
{
$qty = Mage::app()->getLocale()->getNumber($qty);
if(!$ignoreValue){
$qty = ($qty > 0) ? $qty : 1;
}
return $qty;
}
Thanks anyway :)

codeigniter count_all_results

I'm working with the latest codeIgniter released, and i'm also working with jquery datatables from datatables.net
I've written this function: https://gist.github.com/4478424 which, as is works fine. Except when I filter by using the text box typing something in. The filter itself happens, but my count is completely off.
I tried to add in $res = $this->db->count_all_results() before my get, and it stops the get from working at all. What I need to accomplish, if ($data['sSearch'] != '') then to utilize the entire query without the limit to see how many total rows with the search filter exists.
If you need to see any other code other than whats in my gist, just ask and I will go ahead and post it.
$this->db->count_all_results() replaces $this->db->get() in a database call.
I.E. you can call either count_all_results() or get(), but not both.
You need to do two seperate active record calls. One to assign the results #, and one to get the actual results.
Something like this for the count:
$this->db->select('id');
$this->db->from('table');
$this->db->where($your_conditions);
$num_results = $this->db->count_all_results();
And for the actual query (which you should already have):
$this->db->select($your_columns);
$this->db->from('table');
$this->db->where($your_conditions);
$this->db->limit($limit);
$query = $this->db->get();
Have you read up on https://www.codeigniter.com/userguide2/database/active_record.html#caching ?
I see you are trying to do some pagination where you need the "real" total results and at the same time limiting.
This is my practice in most of my codes I do in CI.
$this->db->start_cache();
// All your conditions without limit
$this->db->from();
$this->db->where(); // and etc...
$this->db->stop_cache();
$total_rows = $this->db->count_all_results(); // This will get the real total rows
// Limit the rows now so to return per page result
$this->db->limit($per_page, $offset);
$result = $this->db->get();
return array(
'total_rows' => $total_rows,
'result' => $result,
); // Return this back to the controller.
I typed the codes above without testing but it should work something like this. I do this in all of my projects.
You dont actually have to have the from either, you can include the table name in the count_all_results like so.
$this->db->count_all_results('table_name');
Count first with no_reset_flag.
$this->db->count_all_results('', FALSE);
$rows = $this->db->get()->result_array();
system/database/DB_query_builder.php
public function count_all_results($table = '', $reset = TRUE) { ... }
The
$this->db->count_all_results();
actually replaces the:
$this->db->get();
So you can't actually have both.
If you want to do have both get and to calculate the num rows at the same query you can easily do this:
$this->db->from(....);
$this->db->where(....);
$db_results = $this->get();
$results = $db_results->result();
$num_rows = $db_results->num_rows();
Try this
/**
* #param $column_name : Use In Choosing Column name
* #param $where : Use In Condition Statement
* #param $table_name : Name of Database Table
* Description : Count all results
*/
function count_all_results($column_name = array(),$where=array(), $table_name = array())
{
$this->db->select($column_name);
// If Where is not NULL
if(!empty($where) && count($where) > 0 )
{
$this->db->where($where);
}
// Return Count Column
return $this->db->count_all_results($table_name[0]);//table_name array sub 0
}
Then Simple Call the Method
Like this
$this->my_model->count_all_results(['column_name'],['where'],['table name']);
If your queries contain a group by, using count_all_results fails. I wrote a simple method to work around this. The key to preventing writing your queries twice is to put them all inside a private method that can be called twice. Here is some sample code:
class Report extends CI_Model {
...
public function get($page=0){
$this->_complex_query();
$this->db->limit($this->results_per_page, $page*$this->results_per_page);
$sales = $this->db->get()->result(); //no table needed in get()
$this->_complex_query();
$num_results = $this->_count_results();
$num_pages = ceil($num_results/$this->results_per_page);
//return data to your controller
}
private function _complex_query(){
$this->db->where('a', $value);
$this->db->join('(subquery) as s', 's.id = table.s_id');
$this->db->group_by('table.column_a');
$this->db->from('table'); //crucial - we specify all tables here
}
private function _count_results(){
$query = $this->db->get_compiled_select();
$count_query = "SELECT count(*) as num_rows FROM (".$query.") count_wrap";
$r = $this->db->query($count_query)->row();
return $r->num_rows;
}
}

How to check if a Magento product is already added in cart or not?

I want to show popup when a product is first added to cart in Magento and don't want to show a popup if the product was added again or updated.In short, I want to know product which is going to be added in the cart is First occurence or not?
The answer largely depends on how you want to deal with parent/child type products (if you need to).
If you are only dealing only with simple products or you have parent/child type products and you need to test for child id's then:
$productId = 1;
$quote = Mage::getSingleton('checkout/session')->getQuote();
if (! $quote->hasProductId($productId)) {
// Product is not in the shopping cart so
// go head and show the popup.
}
Alternatively, if you are dealing with parent/child type products and you only want to test for the parent id then:
$productId = 1;
$quote = Mage::getSingleton('checkout/session')->getQuote();
$foundInCart = false;
foreach($quote->getAllVisibleItems() as $item) {
if ($item->getData('product_id') == $productId) {
$foundInCart = true;
break;
}
}
EDIT
The question was asked in a comment as to why setting a registry value in controller_action_predispatch_checkout_cart_add is not available to retrieve in cart.phtml.
Essentially registry value are only available through the life of a single request - you are posting to checkout/cart/add and then being redirected to checkout/cart/index - so your registry values are lost.
If you would like to persist a value across these then you can use the session instead:
In your observer:
Mage::getSingleton('core/session')->setData('your_var', 'your_value');
To retrieve the value
$yourVar = Mage::getSingleton('core/session')->getData('your_var', true);
The true flag being passed to getData will remove the value from the session for you.
In order check if the product is already in cart or not, you can simply use the following code:
$productId = $_product->getId(); //or however you want to get product id
$quote = Mage::getSingleton('checkout/session')->getQuote();
$items = $quote->getAllVisibleItems();
$isProductInCart = false;
foreach($items as $_item) {
if($_item->getProductId() == $productId){
$isProductInCart = true;
break;
}
}
var_dump($isProductInCart);
Hope this helps!

Programmatically change product attribute at store view level

I'm sorry if this question is trivial but I've been struggling to find what I am doing wrong here. I am trying to change the value of an attribute on a store view level but the default is also changed whereas it shouldn't be. Of course, this attribute is set up to be "store-view-scoped". To keep it simple, I've tried with the product name. No success.
Below are unsuccessful tests I've tried...
Do you see what I am doing wrong here?
Many thanks.
My tries :
$product = Mage::getModel('catalog/product')->load(PRODUCT_ID);
$product->setStoreId(STORE_ID)->setName('new_name')->save();
$product = Mage::getModel('catalog/product')->load(PRODUCT_ID);
$product->setStoreId(STORE_ID)->setStore(STORE_CODE)->setName('new_name')->save();
$product = Mage::getModel('catalog/product')->load(PRODUCT_ID);
$product->setStoreId(STORE_CODE)->setName('new_name')->save();
$product = Mage::getModel('catalog/product')->setStoreId(STORE_ID)->load(PRODUCT_ID);
$product->setName('new_name')->save();
$product = Mage::getModel('catalog/product')->setStoreId(STORE_ID)->load(PRODUCT_ID);
$product->setStoreId(STORE_ID)->setName('new_name')->save();
I even tried by adding the line below before the product model load...
Mage::app()->setCurrentStore(STORE_ID);
So here is the complete snippet to change attribute value for a specific product attribute on a specific store view. Example with the product name :
Mage::app()->setCurrentStore(Mage_Core_Model_App::ADMIN_STORE_ID);
$product = Mage::getModel('catalog/product')->load(PRODUCT_ID);
$product->setStoreId(STORE_ID)->setName('my_new_product_name')->save();
And as an additional answer, one could be interested in changing the attribute value to the default one. In this case, the argument 'false' must be passed to the setAttribute :
Mage::app()->setCurrentStore(Mage_Core_Model_App::ADMIN_STORE_ID);
$product = Mage::getModel('catalog/product')->load(PRODUCT_ID);
$product->setStoreId(STORE_ID)->setName(false)->save();
You need to set the current store to admin at the top of your code block:
Mage::app()->setCurrentStore(Mage_Core_Model_App::ADMIN_STORE_ID);
note when loading product with data for some store view, also default values get loaded. saving such product will save default values as store values (thus unset "Use Default Value" for fields)
i ended up with following function to clean-up product data from default values
public static function _removeDefaults($item) {
static $attributeCodes = null;
if($attributeCodes == null) {
$attributes = Mage::getSingleton('eav/config')
->getEntityType(Mage_Catalog_Model_Product::ENTITY)->getAttributeCollection();
$attributeCodes = array();
foreach($attributes as $attribute) {
$ac = $attribute->getAttributeCode();
if(in_array($ac, array('sku','has_options','required_options','created_at','updated_at','category_ids'))) {
continue;
}
$attributeCodes[] = $ac;
}
}
foreach($attributeCodes as $ac) {
if(false == $item->getExistsStoreValueFlag($ac)) {
$item->unsetData($ac);
}
}
}
remember to send only product loaded for some store view

Resources