src/ShopBundle/objects/db/TShopArticle.class.php
public function UpdateStock($dNewStockValue, $bNewAmountIsDelta = false, $bUpdateSaleCounter = false, $bForceUpdate = false)
    {
        if ($this->HasVariants()) {
            return false;
        }
        $oldStock = $this->getAvailableStock();
        // NOTE the below comparison always has true as result (compares int to double); see https://github.com/chameleon-system/chameleon-system/issues/120
        $stockIsChanging = ($bNewAmountIsDelta || $oldStock !== $dNewStockValue);
        if (false === $stockIsChanging && false === $bUpdateSaleCounter && false === $bForceUpdate) {
            return false;
        }

        if ($bNewAmountIsDelta) {
            $this->getInventoryService()->addStock($this->id, $dNewStockValue);
        } else {
            $this->getInventoryService()->setStock($this->id, $dNewStockValue);
        }

        if ($bUpdateSaleCounter && $bNewAmountIsDelta) {
            $dSaleAmount = -1 * $dNewStockValue;
            $this->getProductStatsService()->add($this->id, ProductStatisticsServiceInterface::TYPE_SALES, $dSaleAmount);
        }

        $newStock = $this->getAvailableStock();

        $bActive = $this->CheckActivateOrDeactivate($newStock);
        $this->setIsActive(1 === $bActive);

        // check if the article is part of a bundle... if it is, make sure the bundle article does not exceed the total number of single items
        $query = 'SELECT shop_article.*,
                     shop_bundle_article.amount AS ItemsPerBundle,
                     (shop_bundle_article.amount * shop_article_stock.amount) AS required_stock
                FROM shop_article
          INNER JOIN shop_bundle_article ON shop_article.id = shop_bundle_article.shop_article_id
           LEFT JOIN shop_article_stock ON shop_article.id = shop_article_stock.shop_article_id
               WHERE shop_bundle_article.bundle_article_id = :articleId
                 AND (shop_bundle_article.amount * shop_article_stock.amount) > :newStock
               ';
        $aBundleChangeList = $this->getDatabaseConnection()->fetchAll($query, array('articleId' => $this->id, 'newStock' => $newStock), array('articleId' => \PDO::PARAM_STR, 'newStock' => \PDO::PARAM_INT));
        foreach ($aBundleChangeList as $aBundleChange) {
            $iAllowedStock = floor($newStock / $aBundleChange['ItemsPerBundle']);
            $oBundleArticle = TdbShopArticle::GetNewInstance();
            $oBundleArticle->LoadFromRow($aBundleChange);
            $oBundleArticle->UpdateStock($iAllowedStock, false, false);
        }

        if ($oldStock !== $newStock || true === $bForceUpdate) {
            $this->StockWasUpdatedHook($oldStock, $newStock);
            $this->getEventDispatcher()->dispatch(ShopEvents::UPDATE_PRODUCT_STOCK, new UpdateProductStockEvent($this->id, $newStock, $oldStock));
        }

        return $oldStock !== $newStock;
    }
public function UpdateStock($dNewStockValue, $bNewAmountIsDelta = false, $bUpdateSaleCounter = false, $bForceUpdate = false)
    {
        if ($this->HasVariants()) {
            return false;
        }
        $oldStock = $this->getAvailableStock();
        // NOTE the below comparison always has true as result (compares int to double); see https://github.com/chameleon-system/chameleon-system/issues/120
        $stockIsChanging = ($bNewAmountIsDelta || $oldStock !== $dNewStockValue);
        if (false === $stockIsChanging && false === $bUpdateSaleCounter && false === $bForceUpdate) {
            return false;
        }

        if ($bNewAmountIsDelta) {
            $this->getInventoryService()->addStock($this->id, $dNewStockValue);
        } else {
            $this->getInventoryService()->setStock($this->id, $dNewStockValue);
        }

        if ($bUpdateSaleCounter && $bNewAmountIsDelta) {
            $dSaleAmount = -1 * $dNewStockValue;
            $this->getProductStatsService()->add($this->id, ProductStatisticsServiceInterface::TYPE_SALES, $dSaleAmount);
        }

        $newStock = $this->getAvailableStock();

        $bActive = $this->CheckActivateOrDeactivate($newStock);
        $this->setIsActive(1 === $bActive);

        // check if the article is part of a bundle... if it is, make sure the bundle article does not exceed the total number of single items
        $query = 'SELECT shop_article.*,
                     shop_bundle_article.amount AS ItemsPerBundle,
                     (shop_bundle_article.amount * shop_article_stock.amount) AS required_stock
                FROM shop_article
          INNER JOIN shop_bundle_article ON shop_article.id = shop_bundle_article.shop_article_id
           LEFT JOIN shop_article_stock ON shop_article.id = shop_article_stock.shop_article_id
               WHERE shop_bundle_article.bundle_article_id = :articleId
                 AND (shop_bundle_article.amount * shop_article_stock.amount) > :newStock
               ';
        $aBundleChangeList = $this->getDatabaseConnection()->fetchAll($query, array('articleId' => $this->id, 'newStock' => $newStock), array('articleId' => \PDO::PARAM_STR, 'newStock' => \PDO::PARAM_INT));
        foreach ($aBundleChangeList as $aBundleChange) {
            $iAllowedStock = floor($newStock / $aBundleChange['ItemsPerBundle']);
            $oBundleArticle = TdbShopArticle::GetNewInstance();
            $oBundleArticle->LoadFromRow($aBundleChange);
            $oBundleArticle->UpdateStock($iAllowedStock, false, false);
        }

        if ($oldStock !== $newStock || true === $bForceUpdate) {
            $this->StockWasUpdatedHook($oldStock, $newStock);
            $this->getEventDispatcher()->dispatch(ShopEvents::UPDATE_PRODUCT_STOCK, new UpdateProductStockEvent($this->id, $newStock, $oldStock));
        }

        return $oldStock !== $newStock;
    }
public function UpdateStock ( $ dNewStockValue , $ bNewAmountIsDelta = false , $ bUpdateSaleCounter = false , $ bForceUpdate = false ) { if ( $ this -> HasVariants ( ) ) { return false ; } $ oldStock = $ this -> getAvailableStock ( ) ; // NOTE the below comparison always has true as result (compares int to double); see https://github.com/chameleon-system/chameleon-system/issues/120 $ stockIsChanging = ( $ bNewAmountIsDelta || $ oldStock !== $ dNewStockValue ) ; if ( false === $ stockIsChanging && false === $ bUpdateSaleCounter && false === $ bForceUpdate ) { return false ; } if ( $ bNewAmountIsDelta ) { $ this -> getInventoryService ( ) -> addStock ( $ this -> id , $ dNewStockValue ) ; } else { $ this -> getInventoryService ( ) -> setStock ( $ this -> id , $ dNewStockValue ) ; } if ( $ bUpdateSaleCounter && $ bNewAmountIsDelta ) { $ dSaleAmount = - 1 * $ dNewStockValue ; $ this -> getProductStatsService ( ) -> add ( $ this -> id , ProductStatisticsServiceInterface :: TYPE_SALES , $ dSaleAmount ) ; } $ newStock = $ this -> getAvailableStock ( ) ; $ bActive = $ this -> CheckActivateOrDeactivate ( $ newStock ) ; $ this -> setIsActive ( 1 === $ bActive ) ; // check if the article is part of a bundle... if it is, make sure the bundle article does not exceed the total number of single items $ query = 'SELECT shop_article.*,
                     shop_bundle_article.amount AS ItemsPerBundle,
                     (shop_bundle_article.amount * shop_article_stock.amount) AS required_stock
                FROM shop_article
          INNER JOIN shop_bundle_article ON shop_article.id = shop_bundle_article.shop_article_id
           LEFT JOIN shop_article_stock ON shop_article.id = shop_article_stock.shop_article_id
               WHERE shop_bundle_article.bundle_article_id = :articleId
                 AND (shop_bundle_article.amount * shop_article_stock.amount) > :newStock
               ' ; $ aBundleChangeList = $ this -> getDatabaseConnection ( ) -> fetchAll ( $ query , array ( 'articleId' => $ this -> id , 'newStock' => $ newStock ) , array ( 'articleId' => \ PDO :: PARAM_STR , 'newStock' => \ PDO :: PARAM_INT ) ) ; foreach ( $ aBundleChangeList as $ aBundleChange ) { $ iAllowedStock = floor ( $ newStock / $ aBundleChange [ 'ItemsPerBundle' ] ) ; $ oBundleArticle = TdbShopArticle :: GetNewInstance ( ) ; $ oBundleArticle -> LoadFromRow ( $ aBundleChange ) ; $ oBundleArticle -> UpdateStock ( $ iAllowedStock , false , false ) ; } if ( $ oldStock !== $ newStock || true === $ bForceUpdate ) { $ this -> StockWasUpdatedHook ( $ oldStock , $ newStock ) ; $ this -> getEventDispatcher ( ) -> dispatch ( ShopEvents :: UPDATE_PRODUCT_STOCK , new UpdateProductStockEvent ( $ this -> id , $ newStock , $ oldStock ) ) ; } return $ oldStock !== $ newStock ; }
the methods recalculates the total available stock for a base article based on
the articles variants. You can call this either on the primary article or on
a variant - both calls will result in an update to the parent article.

@param float $dNewStockValue     - optional: you can update the stock of the current article to this new value
@param bool  $bNewAmountIsDelta  - set to true if you want to increase or decrease the amount by some quantity
@param bool  $bUpdateSaleCounter - set to true if you also want to update the sales counter (IMPORTANT: changes the sales counter ONLY if $bNewAmountIsDelta is also set to true)
@param bool  $bForceUpdate       - set to true, if you want to trigger update action, even if nothing changed (needed for example, if an article is changed via the table editor)

@return bool - return true if some data was changed
the methods recalculates the total available stock for a base article based on the articles variants . You can call this either on the primary article or on a variant - both calls will result in an update to the parent article .