Jump to content

[PS 1.6.1.15] Multishop combinations - Default attribute SQL error


bdesprez

Recommended Posts

Recently I discovered a problem with combinations in multishop context.

First of all, the error : 

Duplicate entry '339-1' for key 'product_default'

UPDATE ps_product_attribute a
				 INNER JOIN ps_product_attribute_shop product_attribute_shop
		ON (product_attribute_shop.id_product_attribute = a.id_product_attribute AND product_attribute_shop.id_shop = 2)
				SET a.default_on = '1', product_attribute_shop.default_on = '1' WHERE a.id_product_attribute = 932

 

Now, I will explain how I did it :

Prerequisites :

  • Multishop option activated 
  • At least 2 shops
  • Combinations enabled

 

Steps to producing error again :

  1. Context : All shops
  2. Create a product
  3. Context : a specific shop
  4. Associate the product to a shop's category
  5. Add a combination for this product
  6. This combination is now the default one
  7. Context : another specific shop
  8. Associate the product to a shop's category
  9. Add another combination
  10. Doh! ERROR! Indeed, the product already has a default attribute but it does not exist in the actual context.

 

Code side now :

In ProductCose class (Product.php), the error is raised when «checkDefaultAttributes» is called. 

  1. Searching default attribute in associated shop table. If it exists it's ok, the method return TRUE.
  2. If product does not have attributes, ok, it's returning FALSE.
  3. «ObjectModel::updateMultishopTable» is called but there is an index «product_default» in the DB table «product_attribute». It's impossible to have two different default attribute for a product attribute.
  4. It sounds like we cannot have different combinations for the same product in different shops. If it is the wanted purpose, I am wondering why the «product_attribute» table has an associated shop table… If it is not, the index «product default» may be on the «product_attribute_shop» table. Oh! wait, there is an index  called «id_product» ( cols: id_product, id_shop, default_on).
Link to comment
Share on other sites

  • 3 months later...
  • 3 years later...

I do some hardcode to fix it myself. 

In file classes/Combination.php , edit the add function and update function. line 131 

public function add($autodate = true, $null_values = false)
    {
        $lokijDefaultOn = $this->default_on;
        if ($this->default_on) {
            $this->default_on = 1;
        } else {
            $this->default_on = null;
        }

        if (!parent::add($autodate, $null_values)) {
            return false;
        }
        if(!$lokijDefaultOn){
            Db::getInstance()->executeS('UPDATE `xxx_main`.`ps_product_attribute` SET `default_on` = NULL WHERE `id_product_attribute` = '.$this->id);
        }
        
        $product = new Product((int)$this->id_product);
        if ($product->getType() == Product::PTYPE_VIRTUAL) {
            StockAvailable::setProductOutOfStock((int)$this->id_product, 1, null, (int)$this->id);
        } else {
            StockAvailable::setProductOutOfStock((int)$this->id_product, StockAvailable::outOfStock((int)$this->id_product), null, $this->id);
        }

        SpecificPriceRule::applyAllRules(array((int)$this->id_product));

        Product::updateDefaultAttribute($this->id_product);
        if(!$lokijDefaultOn){
            Db::getInstance()->executeS('UPDATE `xxx_main`.`ps_product_attribute_shop` SET `default_on` = NULL WHERE `id_product_attribute` = '.$this->id);
        }
        return true;
    }

public function update($null_values = false)
    {
        $lokijDefaultOn = $this->default_on;
        if ($this->default_on) {
            $this->default_on = 1;
        } else {
            $this->default_on = null;
        }

        $return = parent::update($null_values);
        if(!$lokijDefaultOn){
            Db::getInstance()->executeS('UPDATE `xxx_main`.`ps_product_attribute` SET `default_on` = NULL WHERE `id_product_attribute` = '.$this->id);
        }
        
        Product::updateDefaultAttribute($this->id_product);
        if(!$lokijDefaultOn){
            Db::getInstance()->executeS('UPDATE `xxx_main`.`ps_product_attribute_shop` SET `default_on` = NULL WHERE `id_product_attribute` = '.$this->id);
        }
        return $return;
    }

 

See the table 'product_attribute' ,the expected value of default_on is null or 1 , but it actually got 0 or 1 after insert data into database. and it cause the error "Duplicate entry 'xxx' for key 'product_default' " .

product_default is a unique indexes of table 'product_attribute' .  product_default( id_product, default_on ) . if the default_on's value can only be 0 or 1 , then a product can only create two combination .

I don't find any code logic error in it .  the code try to set the default_on value to null but fail.  I think maybe it was cause by php setting or database setting or ObjectModel.php .

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...