Increase product stock on sale - magento

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 :)

Related

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!

Magento mass-assign products to category

As the title says,i need to mass-assign products to a category and from the admin i can only edit one product at a time; i dont know why it just doesnt work to mass add them from the "category products" tab in the category page.
Thats why i need another method that's fast,like using phpMyAdmin or something alike.
Any help?
Thanks in advance!
I created a simple script to do this outside of Magento. Be sure to test this first on a single product and make sure it looks as you'd expect.
// Load Magento
require_once 'path/to/app/Mage.php';
Mage::app();
// $productIds is an array of the products you want to modify.
// Create it however you want, I did it like this...
$productsIds = Mage::getModel('catalog/product')->getCollection()
->addAttributeToFilter('sku', array('like' => 'something'))
->getAllIds();
// Array of category_ids to add.
$newCategories = array(20);
foreach ($productIds as $id) {
$product = Mage::getModel('catalog/product')->load($id);
$product->setCategoryIds(
array_merge($product->getCategoryIds(), $newCategories)
);
$product->save();
}
If you wish to overwrite a product's existing categories, change array_merge(...) to just $newCategories.
I would shy away from tackling this problem from the database side of things. If you do go that direction make sure and take lots of backups and do it during low usage.
The following thread on the Magento forum identifies the very same problem. One poster recommends a raw sql approach with example. Again, I would be careful - make sure you take backups.
The answer I like best from the thread (posted by Magento MVP):
Go into the category you don’t want them in, find the product list.
Click the check boxes on the products you want to remove and select
delete from the little dropdown.
Now go into the category where you
do want them, go to the product list. Select the NO dropdown so it
shows items not in the category. You might have to do a selective
search to limit stuff and do it in a couple iterations. Click the
check boxes and tell it to add stuff.
You may as well do this using the magento API
This is the script I use for mass adding products. sku.txt contains one sku per line.
<?php
$wsdlUrl = "magento-root/index.php/api/soap/?wsdl";
$proxy = new SoapClient($wsdlUrl);
$sessionId = $proxy->login('apiuser', 'apipasswd');
$listOfDiscountedSKUFile = "sku.txt";
function readinFile($filePath)
{
$fp = fopen($filePath,'r') or exit("Unable to open file!");
$dataItems = array();
while(!feof($fp))
{
$dataItems[] = trim(fgets($fp));
}
fclose($fp);
var_dump($dataItems);
return $dataItems;
}
function addToCategory($sku,$categoryId)
{
global $proxy,$sessionId;
$proxy->call($sessionId, 'category.assignProduct', array($categoryId, $sku));
}
function IsNullOrEmptyString($question){
return (!isset($question) || trim($question)==='');
}
$categoryId = 82;//e.g.
$listOfSKU = readinFile($listOfDiscountedSKUFile);
foreach($listOfSKU as $sku)
{
addToCategory($sku,$category);
}
?>
I managed to resolve the problem with the following code :
$write = Mage::getSingleton('core/resource')->getConnection('core_write');
$x = 1171;
$y = 2000;
$categoryID = 4;
$productPosition = 0;
while($x <= $y) {
$write->query("REPLACE INTO `catalog_category_product` (`category_id`, `product_id`, `position`) VALUES ($categoryID, $x++, $productPosition)");
}
echo "The job is done";
?>
I hope the code is clear for everyone,if it's not,reply and i'll try to explain it.
#nachito : here it is.

Duplicating a product with Code in Magento

I am trying to write a custom module which is capable of duplicating a product into multiple products with only varying SKU. I have tried using function duplicate() under /app/code/core/Mage/Catalog/Model/Product.php in my custom module. But its not working.
I am using the below code in my custom Obesrever.php file to duplicate, but duplication is not occuring
$product = $observer->getEvent()->getProduct();
$newProduct = $product->duplicate();
can anyone suggest me any links to do this or any code format would be helpful.
Thanks
It would be great if you can post the complete function that you are trying to debug or create duplicate products and config.xml (where you are trying to call the event).
Below code works for me in CE 1.9.2.2 without any problems. This function does the following tasks:
Creates duplicate of the original product
Sets the stock to "In Stock" and Qty to "100" (hard coded for now)
Automates reindexing
public function indexAction() //change the function name
{
$productId = $observer->getEvent()->getProduct()->getId();
$productObject = Mage::getModel('catalog/product');
$_product = $productObject->load($productId);
$newProduct = $_product->duplicate();
//new product status is disabled - to view in the frontend you will need to set the status as enabled
$newProduct->setStatus(1);
$newProduct->setName('Duplicate-' . $_product->getName());
$newProduct->setSku('value-' . $productId);
$newProduct->setWebsiteIds($_product->getWebsiteIds());
//set the product stock and qty to display product in the frontend
//while creating duplicate product, it will update the new product to have qty 0 and out of stock
$stockItem = Mage::getModel('cataloginventory/stock_item')->loadByProduct($newProduct->getId());
if ($stockItem->getId() > 0 && $stockItem->getManageStock())
{
$qty = 100;
$stockItem->setQty($qty);
$stockItem->setIsInStock((int)($qty > 0));
$stockItem->save();
}
$newProduct->getResource()->save($newProduct);
//automate reindexing - to display the product in the frontend
$indexers = Mage::getSingleton('index/indexer')->getProcessesCollection();
foreach ($indexers as $indexer)
{
$indexer->reindexEverything();
}
}
Hope this helps.
Happy Coding...

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

Magento - module is not updating prices on a per-website basis

I am having trouble with a module that is supposed to update prices on a per-website basis.
At the top of my module I have :
Mage::app()->setCurrentStore(Mage_Core_Model_App::ADMIN_STORE_ID);
This should mean that when I call the module (the module has a frontend) I am able to update prices etc as 'admin'. However, this just isn't happening. Currently I have gone on a few desperate efforts to get it working - seeing if number formats trip it up or indexes not reindexed, cache problems and anything else.
The following snippet actually produces the right numbers but it just is not saving to the database. Any ideas?
$product = Mage::getModel('catalog/product')->
setStoreId($storeId)->setWebsiteId($websites[$store])->
loadByAttribute('sku',$price['SKU']);
$oldprice=(float)str_replace(",","",$product->getPrice());
if($newprice!=$oldprice) {
Mage::log($product->getPrice());
$product->setPrice(number_format($newprice,4,".",""));
Mage::log($product->getPrice());
$product->getResource()->saveAttribute($product, 'price');
$product->save();
Mage::log($product->getPrice());
unset($product);
}
Let's assume that you are updating the prices of products using a method in your module's class, with the following sample code:-
public function updateProductPrices ($sku, $newPrice) {
Mage::app()->setCurrentStore(Mage_Core_Model_App::ADMIN_STORE_ID);
$websites = Mage::app()->getWebsites();
$product = Mage::getModel('catalog/product')
$productId = $product->getIdBySku($sku);
foreach ($websites as $_eachWebsite) {
$_websiteId = $_eachWebsite->getWebsiteId();
$websiteObj = new Mage_Core_Model_Website();
$websiteObj->load($_websiteId);
$storeIds = $websiteObj->getStoreIds();
if (count($storeIds)) {
foreach ($storeIds as $_eachStoreId) {
$product->setStoreId($_eachStoreId)
->load($productId);
$oldPrice = $product->getPrice();
if ($oldPrice != $newPrice) {
$product->setPrice($newPrice);
$product->save();
}
}
}
unset($storeIds, $websiteObj, $_websiteId);
}
unset($product);
}
Hope it helps.
Try:
$product->setPrice($newprice)->save();
I am having similar issue and I think there is a bug in the answer from Knowledge Craving. The code will actually not update on a per website basis but rather update one unique price to each and every website
The bug I am talking about actually happened to me with similar code and is that other product attributes will be unlinked from default (at least, it is what happened to me).
Below is a suggestion based on Knowledge Craving's solution, I just amended a bit
public function updateProductPrices ($sku, $newPrice, $websiteId) {
Mage::app()->setCurrentStore(Mage_Core_Model_App::ADMIN_STORE_ID);
$product = Mage::getModel('catalog/product')
$productId = $product->getIdBySku($sku);
$websiteObj = new Mage_Core_Model_Website();
$websiteObj->load($websiteId);
$storeIds = $websiteObj->getStoreIds();
if (count($storeIds)) {
foreach ($storeIds as $_eachStoreId) { //Does it need to do for each storeview, price being anyway website scope?
$product->load($productId);
$oldPrice = $product->getPrice();
if ($oldPrice != $newPrice) { //actually, this if would not be necessary as you anyway want to update, right?
$product->setStoreId($_eachStoreId)
->setPrice($newPrice)
->save();
}
}
}
unset($productId, $storeIds, $websiteObj, $product);
}

Resources