How can to cancel particular item of an order not complete order in custom module
I found a solution for how to cancel a particular item from whole order for that set setQtyCanceled() for a particular order item :
$orderDetail = $this->_objectManager->create('Magento\Sales\Model\Order')->load(1);
if ($orderDetail->canCancel()) {
$orderItems = $orderDetail->getAllItems();
foreach ($orderItems as $value) {
if($value['product_id']==122))
{
$value->setQtyCanceled($value['qty_ordered']);
$value->save();
}
else
{
continue;
}
}
$orderDetail->save();
}
Here i want to cancel an order item of order no 1 and whose product id is 122.
This works for me
Related
Trying to set the available inventory for a large amount of products within multiple locations.
The problem I am running into is there is just so many products that I need to find their inventory_item_id in order to utilize the inventoryActivate mutation.
How can I grab a list of ALL of my 9,000 products inventory_item_id without going one-by-one?
Use Case:
10 Locations used in Shopify
9,000 Products in Shopify
ERP creates and holds the physical inventory of each
Need to update the Inventory of each Product at its respective location every hour or so
I am looking at the docs found here.
You can export inventory in bulk and get your needed inventory item IDs, current quantities and location. Using that file (JSON) you can then loop through those and activate your inventory items.
I have found that we can utilize the bulkOperationRunQuery following the docs here.
I first ran the following to create the bulk operation with sku and inventoryItem:
mutation {
bulkOperationRunQuery(
query: """
{
products {
edges {
node {
id
variants(first: 5)
{
edges {
node {
id
sku
inventoryItem {
id #this is the inventory_item_id
}
}
}
}
}
}
}
}
"""
) {
bulkOperation {
id
status
}
userErrors {
field
message
}
}
}
After completed I then grabbed the Url returned from the Bulk Operation:
query {
node(id: "gid://shopify/BulkOperation/123456789") {
... on BulkOperation {
url
partialDataUrl
}
}
}
When we go to the URL we get a downloadable .jsonl file. I parsed it with PHP to grab only the sku and InventoryItem id:
print '<table>';
$file = #fopen("bulk.json", "r");
while (!feof($file)){
$line = fgets($file);
$obj = json_decode($line);
$sku = $obj->sku;
$inv_id = $obj->inventoryItem->id;
$inv_id = str_replace("gid://shopify/InventoryItem/", "", $inv_id);
if($inv_id != ''){
print "<tr>
<td>$sku</td>";
print "<td>$inv_id</td>
</tr>";
}
}
print '</table>';
This provided me with all 9,000 Products Inventory Item IDs to be used on any subsequent Inventory Updates we need to call with GraphQL.
How do I filter an observable using values from another observable, like an inner join in SQL?
class Item {
constructor(public name: string public category: string) {
}
}
class NavItem {
constructor(public key: string public isSelected: boolean = false) {
}
}
// Build a list of items
let items = of(new Item('Test', 'Cat1'), new Item('Test2', 'Cat2'))
.pipe(toArray());
// Determine the unique categories present in all the items
let navItems = from(items)
.pipe(mergeAll(),
distinct((i:item) => i.category),
map(i=>new NavItem(i.category)),
toArray());
I'm building a faceted search so let's say that in the UI, the "Cat1" NavItem is selected, so I want to produce an observable of all the items that have that category. After filtering down to the selected NavItem, I'm not sure how to bring in the Items, filter them down and spit out only those Items that mach a selected category. Here's what I have:
let filteredItems = navItems.pipe(
mergeAll(),
filter(n => n.isSelected))
// join to items?
// emit only items that match a selected category?
Expected result would be
[{name: 'Test', category: 'Cat1'}]
If I understand correctly, you want to select a certain navItem representing a certain category and then select all the items which have such category.
If this is true, than you can consider to create a function or method such as this
selectedItems(categoryId) {
return items.pipe(filter(item => item.category === categoryId));
}
Once you click the navItem then you raise an event which references the navItem and therefore the category id you are interested. You have then to call selectedItems function and pass the category id you selected. This will return an Observable which emits all the items of the category you have selected.
I finally got back around to looking at this and I figured out how to solve this. I needed to use switchMap to join the observables together in the same context. Then I can use map to emit all relevant items:
let filteredItems = from(items)
.pipe(mergeAll(),
switchMap((i) => navItems
// Get only navItems that are selected
.pipe(filter(ni => ni.isSelected),
// Convert back to array so I can if there are any selected items
// if zero, then show all items
toArray(),
map((nav) => {
if(nav.lengh > 0) {
// If the item's category matches, return it
return nav.some(x => x.key == i.category) ? i : null;
}
// If no categories were selected, then show all
return i;
})
}),
// Filter out the irrelevant items
filter(x => x !== null),
toArray()
);
I am able to retrieve items and its details from the database but what i want to do is, when i get an item, i compare its quantity to a certain number.
Controller
$item = Item::all();
if($item->quantity = 5)
{
return $response;
}
else
{
//
}
What is happening here is, it actually sets 5 to the item's quantity but instead i want to get the quantity of the item selected and compare if it is equal to 5. How do i do this?
You are assigning the value with a single '=' since it's an assignment operator.
Instead, compare the values with '=='
$item = Item::all();
if($item->quantity == 5)
{
return $response;
}
else
{
//
}
I am trying to use magmi to import group and tier pricing for the not logged in group and am not sure what the format is for my csv headers or where to find it.
I have successfully used group and tier price imports with magmi on all (sku,price,tier_price:_all_), none (sku,group_price:None,tier_price:None) and other custom groups I have. A (sku,group_price:A,tier_price:A), B (sku,group_price:B,tier_price:B) and so on.
It is just the formatting for not logged in I can't figure out and I can't seem to find anything on it in the documentation.
Here is what I have tried so far.
sku,group_price:NOT LOGGED IN,tier_price:NOT LOGGED IN
sku,group_price:'NOT LOGGED IN',tier_price:'NOT LOGGED IN'
sku,group_price:_not_,tier_price:_not_
sku,group_price:General,tier_price:General
Any ideas?
yes it is works.. create directory /var/www/html/../magmi/plugins/extra/itemprocessors/groupprice
put this grouppriceprocessor.php on this directory ,
select this profile in magmi .. group_price:NOT LOGGED IN
this is header in csv file put value for this and it works ..
code of grouppriceprocessor.php
<?php
/**
* Class Tier price processor
* #author dweeves
*
* This imports tier prices for columns names called "group_price:"
*/
class GrouppriceProcessor extends Magmi_ItemProcessor
{
protected $_tpcol=array();
protected $_singlestore=0;
protected $__pricescope=2;
public function getPluginInfo()
{
return array(
"name" => "Group price importer",
"author" => "Dweeves,bepixeld,Jason",
"version" => "0.0.1",
);
}
/**
* you can add/remove columns for the item passed since it is passed by reference
* #param Magmi_Engine $mmi : reference to magmi engine instance (convenient to perform database operations)
* #param unknown_type $item : modifiable reference to item before import
* the $item is a key/value array with column names as keys and values as read from csv file.
* #return bool :
* true if you want the item to be imported after your custom processing
* false if you want to skip item import after your processing
*/
public function processItemAfterId(&$item,$params=null)
{
$pid=$params["product_id"];
$tpn=$this->tablename("catalog_product_entity_group_price");
$tpcol=array_intersect(array_keys($this->_tpcol),array_keys($item));
//do nothing if item has no group price info or has not change
if(count($tpcol)==0 )
{
return true;
}
else
{
//it seems that magento does not handle "per website" tier price on single store deployments , so force it to "default"
//so we test wether we have single store deployment or not.
//bepixeld patch : check pricescope from general config
if($this->_singlestore==0 && $this->_pricescope!=0)
{
$wsids=$this->getItemWebsites($item);
}
else
{
$wsids=array(0);
}
$wsstr=$this->arr2values($wsids);
//clear all existing tier price info for existing customer groups in csv
$cgids=array();
foreach($tpcol as $k)
{
$tpinf=$this->_tpcol[$k];
if($tpinf["id"]!=null)
{
$cgids[]=$tpinf["id"];
}
else
{
$cgids=array();
break;
}
}
//if we have specific customer groups
if(count($cgids)>0)
{
//delete only for thos customer groups
$instr=$this->arr2values($cgids);
//clear tier prices for selected tier price columns
$sql="DELETE FROM $tpn WHERE entity_id=? AND customer_group_id IN ($instr) AND website_id IN ($wsstr)";
$this->delete($sql,array_merge(array($pid),$cgids,$wsids));
}
else
{
//delete for all customer groups
$sql="DELETE FROM $tpn WHERE entity_id=? AND website_id IN ($wsstr)";
$this->delete($sql,array_merge(array($pid),$wsids));
}
}
foreach($tpcol as $k)
{
//get tier price column info
$tpinf=$this->_tpcol[$k];
//now we've got a customer group id
$cgid=$tpinf["id"];
//add tier price
$sql="INSERT INTO $tpn
(entity_id,all_groups,customer_group_id,value,website_id) VALUES ";
$inserts=array();
$data=array();
if($item[$k]=="")
{
continue;
}
$tpvals=explode(";",$item[$k]);
foreach($wsids as $wsid)
{
//for each tier price value definition
foreach($tpvals as $tpval)
{
$tpprice=str_replace(",",".",$tpval);
if($tpprice=="")
{
continue;
}
if(substr($tpprice,-1)=="%")
{
//if no reference price,skip % tier price
if(!isset($item["price"]))
{
$this->warning("No price define, cannot apply % on group price");
continue;
}
$fp=(float)(str_replace(",",".",$item["price"]));
$pc=(float)(substr($tpprice,0,-1));
$m=($pc<0?(100+$pc):$pc);
$tpprice=strval(($fp*($m))/100.0);
}
$inserts[]="(?,?,?,?,?)";
$data[]=$pid;
//if all , set all_groups flag
$data[]=(isset($cgid)?0:1);
$data[]=(isset($cgid)?$cgid:0);
$data[]=$tpprice;
$data[]=$wsid;
}
}
if(count($inserts)>0)
{
$sql.=implode(",",$inserts);
$sql.=" ON DUPLICATE KEY UPDATE `value`=VALUES(`value`)";
$this->insert($sql,$data);
}
}
return true;
}
public function processColumnList(&$cols,$params=null)
{
//inspect column list for getting tier price columns info
foreach($cols as $col)
{
if(preg_match("|group_price:(.*)|",$col,$matches))
{
$tpinf=array("name"=>$matches[1],"id"=>null);
//if specific tier price
if($tpinf["name"]!=="_all_")
{
//get tier price customer group id
$sql="SELECT customer_group_id from ".$this->tablename("customer_group")." WHERE customer_group_code=?";
$cgid=$this->selectone($sql,$tpinf["name"],"customer_group_id");
$tpinf["id"]=$cgid;
}
else
{
$tpinf["id"]=null;
}
$this->_tpcol[$col]=$tpinf;
}
}
return true;
}
public function initialize($params)
{
$sql="SELECT COUNT(store_id) as cnt FROM ".$this->tablename("core_store")." WHERE store_id!=0";
$ns=$this->selectOne($sql,array(),"cnt");
if($ns==1)
{
$this->_singlestore=1;
}
//bepixeld patch : check pricescope from general config
$sql = "SELECT value FROM ". $this->tablename('core_config_data') ." WHERE path=?";
$this->_pricescope = intval($this->selectone($sql, array('catalog/price/scope'), 'value')); //0=global, 1=website
}
}
thanks
I found out from further testing that the tier pricing magmi plugin worked just fine with the above csv format. the original plugin I got to work with some code change but then decided to check for an update.
While searching I found an alternate magmi plugin for the group price importer and it worked.
Replace the current file in the magmi/plugins/extra/itemprocessors/groupprice folder with this one.
Here is the website found at if you would like to see more info.
I have a magento site I'm building (1.6) my site has a bunch of configurable options with 6 or so attributes set as dropdowns for the customer to pick from. After saving a configurable product the order of the attributes changes. I've been able to find what I think is happening, it is reordering them according to the attribute id not the order I have them set up in the attribute set. I need to find a way to get magento to keep the order of the attributes the same as they are in the attribute set. Any help is greatly appreciated.
Trick is pretty simple.
Just drag'n'drop them in product->edit->associatedProduct tab ;)
The order of attributes from this page is saved to catalog_product_super_attribute table.
I was also looking for the same and finally i found this and it works for me hope it will work for others too.
From Admin Panel > Catalog > Attributes > Manage Attributes select the one like if you want to make it like for the capacity 4GB > 8GB > 16GB and so on then do this small changes.
Select Manage Label / Options > Manage Options (values of your attribute) and if you already created the variables just add the position manually, like:
4GB - 1
8GB - 2
16GB - 3
Save and flush the cache.
That's it, now it should show the attributes as per the position that you assign.
It is an old question but I have found a solution right now having the same problem.
If you are still interesting in changing the order of the configurable attribute you may want to look into this method:
Mage_Catalog_Model_Product_Type_Configurable::getConfigurableAttributes()
getConfigurableAttributes() load the collection of attributes.
The first time the collection is loaded, before saving the configurable, there is no position value, so I think the attribute ID rules on the display order.
If you want to alter this order you can only add a sort for attribute_id after the ->orderByPosition() and revert the order ( this will preserve the position functionality )
For example, here I have added ->setOrder('attribute_id','DESC')
public function getConfigurableAttributes($product = null)
{
Varien_Profiler::start('CONFIGURABLE:'.__METHOD__);
if (!$this->getProduct($product)->hasData($this->_configurableAttributes)) {
$configurableAttributes = $this->getConfigurableAttributeCollection($product)
->orderByPosition()
->setOrder('attribute_id','DESC')
->load();
$this->getProduct($product)->setData($this->_configurableAttributes, $configurableAttributes);
}
Varien_Profiler::stop('CONFIGURABLE:'.__METHOD__);
return $this->getProduct($product)->getData($this->_configurableAttributes);
}
OR
In case you want to modify the order in more radical way, you can also act on this method:
Mage_Adminhtml_Block_Catalog_Product_Edit_Tab_Super_Config::getAttributesJson()
This is basically calling the getConfigurableAttributes().
To understand if this is the first configurable load, you can check all the attributes in the array $attributes to see if they all have a position ==0 and then proceed with a manual reorder )
Example
I'm omitting all the module creation and the rewrite part.
Here an example modifying getAttributesJson() in order to have the color attribute always on the top.
public function getAttributesJson()
{
$attributes = $this->_getProduct()->getTypeInstance(true)
->getConfigurableAttributesAsArray($this->_getProduct());
if (!$attributes) {
return '[]';
} else {
// == START ==
// checking if I can re-order
if ($this->isNoSavedPosition($attributes)) {
$attributes = $this->attributeReorder($attributes);
}
// == END ==
// Hide price if needed
foreach ($attributes as &$attribute) {
if (isset($attribute['values']) && is_array($attribute['values'])) {
foreach ($attribute['values'] as &$attributeValue) {
if (!$this->getCanReadPrice()) {
$attributeValue['pricing_value'] = '';
$attributeValue['is_percent'] = 0;
}
$attributeValue['can_edit_price'] = $this->getCanEditPrice();
$attributeValue['can_read_price'] = $this->getCanReadPrice();
}
}
}
}
return Mage::helper('core')->jsonEncode($attributes);
}
public function isNoSavedPosition($attributes)
{
foreach ($attributes as $attribute) {
if (isset($attribute['position']) && $attribute['position'] != 0) {
return false;
}
}
// there is no position saved
// - this is the first time the configurable is loaded
// - (the position is saved on second save action)
return true;
}
public function attributeReorder($attributes)
{
// we want the Color attribute to be always on the top
$newAttributesOrderArray = array();
foreach ($attributes as $key => $attribute) {
if (isset($attribute['label']) && $attribute['label'] == 'Color') {
$newAttributesOrderArray[] = $attribute;
unset($attributes[$key]);
}
}
$newAttributesOrderArray = array_merge($newAttributesOrderArray,$attributes);
return $newAttributesOrderArray;
}