I'm trying to write some custom logic for browsing and searching in a Magento store.
So I figured I'd overwrite getProductCollection for both Mage_Catalog_Model_Layer and Mage_CatalogSearch_Model_Layer.
I'm trying to make decisions based on what the value of certain Attributes are for some of the products in the collection, but I can't seem to get the text value of all attributes.
The function as I've overwritten is:
public function getProductCollection()
{
if (isset($this->_productCollections[$this->getCurrentCategory()->getId()])) {
$collection = $this->_productCollections[$this->getCurrentCategory()->getId()];
} else {
$collection = $this->getCurrentCategory()->getProductCollection();
$this->prepareProductCollection($collection);
$this->_productCollections[$this->getCurrentCategory()->getId()] = $collection;
}
//ben
$collection->addAttributeToSelect('parent_sku');
$collection->addAttributeToSelect('door_color');
foreach($collection as $product) {
echo "\nSKU: ".$product->getSku()."\n";
$product_data = $product->getData();
if(isset($product_data['parent_sku']) && ($product_data['parent_sku'] != '')) {
echo "GETDATA PARENT: ".$product_data['parent_sku']."\n";
}
if($product->getAttributeText('parent_sku') != '') {
echo "ATTR TEXT PARENT: ".$product->getAttributeText('parent_sku')."\n";
}
if($product->getAttributeText('door_color') != '') {
echo "ATTR TEXT COLOR: ".$product->getAttributeText('door_color')."\n";
}
}
//end ben
return $collection;
}
This produces output like:
SKU: TEST_SKU_1
GETDATA PARENT: TEST_SKU_2
ATTR TEXT COLOR: Black
Notice:
I add both 'parent_sku' and 'door_color' as attributes to select.
I can access door_color using $product->getAttributeText()
I cannot access parent_sku using $product->getAttributeText()
I can access parent_sku through $product->getData()
Any time I call $product->getAttributeText('parent_sku') it returns false.
I assumed that this was a caching problem, but I flushed the cache and that didn't seem to help.
Does anyone have a clue why I can't access the value of 'parent_sku' through getAttributeText()?
Is parent_sku implemented as a dropdown box? My understanding is that getAttributeText loaded dropdown options and mapped them from and ID to text for you.
Related
I'm creating a product on prestashop, I enter the amount with this function:
echo "1";
StockAvailable::setQuantity($id_prod, 0, $quantity,1);
echo "2";
the result is:
1fatal error
going on the backend, the product is and the amount set correctly.
How can I avoid the "fatal error"?
Report me error here: classes/Product.php in line 2582: if (!$id_cart && !isset($context->employee)) die(Tools::displayError());
This code is in the function "getPriceStatic". It is normal that it is pulled to perform "StockAvailable::setQuantity"?
I have not changed classes and I do not override
Usually I use this snippet (adapt it to your needs):
$shop_is_feature_active = Shop::isFeatureActive();
$shops = Shop::getContextListShopID();
if ($shop_is_feature_active) {
foreach ($shops as $shop) {
StockAvailable::setQuantity((int)$product->id, 0, (int)$product->quantity, (int)$shop);
}
} else {
StockAvailable::setQuantity((int)$product->id, 0, (int)$product->quantity, (int)$this->context->shop->id);
}
However, I always suggest to check if the product is in that shop.
It is important to check if
Context::getContext()->employee
is not empty, otherwise enter:
$psContext = Context::getContext();
if (!$psContext->employee) {
$psContext->employee = new Employee(PS_DEFAULT_EMPLOYEE);
}
How to avoid decreasing of a product quantity when it's still in the "Process" and update when the order was shipped or delivered?
I've edited this part of code in orderdetail.php and add this $id_order_state != Configuration::get('PS_OS_PREPARATION') in the if statement. Yes, the quantity doesn't decrease when it's processed but when shipped it also doesn't decrease. please help I'm stuck in here.
protected function checkProductStock($product, $id_order_state)
{
if ($id_order_state != Configuration::get('PS_OS_CANCELED') && $id_order_state != Configuration::get('PS_OS_ERROR') && $id_order_state != Configuration::get('PS_OS_PREPARATION')) {
$update_quantity = true;
if (!StockAvailable::dependsOnStock($product['id_product'])) {
$update_quantity = StockAvailable::updateQuantity($product['id_product'], $product['id_product_attribute'], -(int)$product['cart_quantity']);
}
if ($update_quantity) {
$product['stock_quantity'] -= $product['cart_quantity'];
}
if ($product['stock_quantity'] < 0 && Configuration::get('PS_STOCK_MANAGEMENT')) {
$this->outOfStock = true;
}
Product::updateDefaultAttribute($product['id_product']);
}
}
An OrderDetail object is only created once for each Order and will not be updated after that even when you change the Order State. So when your OrderDetail object is created, with your modification it will not update the stock because it doesn't have the right state. And when you later change the Order State the method checkProductStock will never be called again.
You can create a custom module hooked on actionOrderStatusPostUpdate (witch is triggered inside changeIdOrderState() method of class OrderHistory(). In your module you will copy the checkProductStock() method and call it from the hook if the state is "shipped".
EDIT
If you want to add it directly in core:
Edit classes/order/OrderHistory.php
In method changeIdOrderState() change the last lines:
// executes hook
Hook::exec('actionOrderStatusPostUpdate', array('newOrderStatus' => $new_os, 'id_order' => (int)$order->id, ), null, false, true, false, $order->id_shop);
// Here change 4 to the desired id_order_state
if ($new_order_state == 4)
{
$virtual_products = $order->getVirtualProducts();
foreach ($virtual_products as $virtual_product)
{
$this->checkProductStock($virtual_product['product_id'], $new_order_state);
}
}
ShopUrl::resetMainDomainCache();
}
After that add a new method in this class:
protected function checkProductStock($product, $id_order_state)
{
$update_quantity = true;
if (!StockAvailable::dependsOnStock($product['product_id']))
{
StockAvailable::updateQuantity($product['product_id'], $product['product_attribute_id'], -(int)$product['product_quantity']);
}
Product::updateDefaultAttribute($product['product_id']);
}
This code has not been tested.
I advise you to do it in an override:
Create a new file in /overrides/classes/order/OrderHistory.php witch contains those two methods and change the class definition to class OrderHistory extends OrderHistoryCore {, you will have to delete /cache/class_index.php after adding this file.
Does anyone know how to modify the stage of a DataList in Silverstripe 3.2? I want to modify a DataList in my grid field component to change based on the ?_GET['stage'] parameter.
I solved this like so below.
class GridFieldChangeStage implements GridField_DataManipulator {
/*
* Modifies the DataList stage accordingly
*/
public function getManipulatedData(GridField $gridField, SS_List $dataList)
{
$isShowingLiveData = (isset($_GET['stage']) && $_GET['stage'] == 'Live');
if ($isShowingLiveData) {
$dataList = $dataList->alterDataQuery(function($dataQuery) {
$dataQuery->setQueryParam('Versioned.mode', 'stage');
$dataQuery->setQueryParam('Versioned.stage', 'Live');
});
}
return $dataList;
}
}
I'm trying to make an interface where I can edit some of the metadata attached to a lineitem. I've tried using update_post_meta() on the line item itself, however that returns bool(false). How can I update the line item meta data manually?
Thanks!
so I managed to figure it out. I wrote a small function that's below. So, all you need to do is load up the order using the API, parse through each line item and you can call wc_update_order_item_meta. The only thing is, you need to know the variation ID of the item being sold if you only want to update a specific item.
function update_order_item_meta($orderID, $variationID, $metaID, $metaValue) {
$order = returnWC_API()->get_order($orderID)->{'order'};
if(!$order) {
return false;
}
if($variationID == "all") {
foreach ($order->{'line_items'} as $line_item) {
if(!wc_update_order_item_meta($line_item->{'id'}, $metaID, $metaValue)) {
return false;
}
}
return true;
}
foreach ($order->{'line_items'} as $line_item) {
if($line_item->{'product_id'} == $variationID) {
return wc_update_order_item_meta($line_item->{'id'}, $metaID, $metaValue);
}
}
}
I have a product table which is linked to a product_image table in a one-to-many relations
. On the same table I also have a i18n behavior. Which means another table, product_i18n with the same type of relation, one-to-many. I'm using PropelORMPlugin (Propel 1.6). By default it generates the folowing doSave method in my BaseProduct.php file.
protected function doSave(PropelPDO $con)
{
$affectedRows = 0; // initialize var to track total num of affected rows
if (!$this->alreadyInSave) {
$this->alreadyInSave = true;
// We call the save method on the following object(s) if they
// were passed to this object by their coresponding set
// method. This object relates to these object(s) by a
// foreign key reference.
if ($this->aCategory !== null) {
if ($this->aCategory->isModified() || $this->aCategory->isNew()) {
$affectedRows += $this->aCategory->save($con);
}
$this->setCategory($this->aCategory);
}
if ($this->isNew() || $this->isModified()) {
// persist changes
if ($this->isNew()) {
$this->doInsert($con);
} else {
$this->doUpdate($con);
}
$affectedRows += 1;
$this->resetModified();
}
if ($this->productImagesScheduledForDeletion !== null) {
if (!$this->productImagesScheduledForDeletion->isEmpty()) {
ProductImageQuery::create()
->filterByPrimaryKeys($this->productImagesScheduledForDeletion->getPrimaryKeys(false))
->delete($con);
$this->productImagesScheduledForDeletion = null;
}
}
if ($this->collProductImages !== null) {
foreach ($this->collProductImages as $referrerFK) {
if (!$referrerFK->isDeleted()) {
$affectedRows += $referrerFK->save($con);
}
}
}
if ($this->productI18nsScheduledForDeletion !== null) {
if (!$this->productI18nsScheduledForDeletion->isEmpty()) {
ProductI18nQuery::create()
->filterByPrimaryKeys($this->productI18nsScheduledForDeletion->getPrimaryKeys(false))
->delete($con);
$this->productI18nsScheduledForDeletion = null;
}
}
if ($this->collProductI18ns !== null) {
foreach ($this->collProductI18ns as $referrerFK) {
if (!$referrerFK->isDeleted()) {
$affectedRows += $referrerFK->save($con);
}
}
}
$this->alreadyInSave = false;
}
return $affectedRows;
}
I need to access a property of the ProductI18n object when saving the in ProductImage objects table (when saving a Product). The problem is that ProductI18n objects are saved after the ProductImage objects. Meaning that the property is empty when the Product is new (because that property is populated when saving a ProductI18n object based on some other properties). Is there any way to change how Propel generates the order of the saving of the related objects? Is there any other way to make this work without rewriting the doSave method?
While there may be a trick to getting this to work by reordering the foreign-key entries in your schema file, this could be fragile (if someone reorders it again, your code breaks). It may be simpler (if not efficient) to use a postInsert hook on the ProductImage class and access it's relevant ProductI18n entry to get the slug (if it doesn't have it already) and then save the ProductImage again.
class ProductImage extends BaseProductImage {
...
public function postInsert(PropelPDO $con = null) {
if (!$this->getSlug()) {
// get the slug from ProductI18n and update $this, then call ->save();
}
}
...
}