oxbasket.php

Go to the documentation of this file.
00001 <?php
00002 
00005 class oxBasket extends oxSuperCfg
00006 {
00012     protected $_aBasketContents = array();
00013 
00019     protected $_iProductsCnt = 0;
00020 
00026     protected $_dItemsCnt = 0.0;
00027 
00033     protected $_dWeight = 0.0;
00034 
00040     protected $_oPrice = null;
00041 
00047     protected $_oProductsPriceList = null;
00048 
00054     protected $_aDiscounts = array();
00055 
00061     protected $_aItemDiscounts = array();
00062 
00068     protected $_sOrderId = null;
00069 
00075     protected $_aVouchers = array();
00076 
00082     protected $_aCosts = array();
00083 
00089     protected $_oDiscountProductsPriceList = null;
00090 
00096     protected $_oNotDiscountedProductsPriceList = null;
00097 
00103     protected $_blUpdateNeeded = true;
00104 
00110     protected $_aBasketSummary = null;
00111 
00117     protected $_sPaymentId = null;
00118 
00124     protected $_sShippingSetId = null;
00125 
00131     protected $_oUser = null;
00132 
00138     protected $_oTotalDiscount = null;
00139 
00145     protected $_oVoucherDiscount = null;
00146 
00152     protected $_oCurrency = null;
00153 
00159     protected $_blSkipVouchersAvailabilityChecking = null;
00160 
00166     protected $_dDiscountedProductNettoPrice = null;
00167 
00173     protected $_aDiscountedVats = null;
00174 
00180     protected $_blSkipDiscounts = false;
00181 
00187     protected $_oDeliveryPrice = null;
00188 
00194      protected $_blCheckStock = true;
00195 
00201     protected $_blCalcDiscounts = true;
00202 
00208     protected $_sBasketCategoryId = null;
00209 
00215     protected $_blShowCatChangeWarning = false;
00216 
00222     protected $_sTsProductId = null;
00223 
00228     protected $_blNewITemAdded = null;
00229 
00234     protected $_blDownloadableProducts = null;
00235 
00241     public function isEnabled()
00242     {
00243         return !oxUtils::getInstance()->isSearchEngine();
00244     }
00245 
00255     protected function _changeBasketItemKey($sOldKey, $sNewKey, $value = null)
00256     {
00257         reset($this->_aBasketContents);
00258         $iOldKeyPlace = 0;
00259         while (key($this->_aBasketContents) != $sOldKey && next($this->_aBasketContents)) {
00260             ++$iOldKeyPlace;
00261         }
00262         $aNewCopy = array_merge(
00263             array_slice($this->_aBasketContents, 0, $iOldKeyPlace, true),
00264             array($sNewKey => $value),
00265             array_slice($this->_aBasketContents, $iOldKeyPlace+1, count($this->_aBasketContents)-$iOldKeyPlace, true)
00266         );
00267         $this->_aBasketContents = $aNewCopy;
00268     }
00269 
00285     public function addToBasket( $sProductID, $dAmount, $aSel = null, $aPersParam = null, $blOverride = false, $blBundle = false, $sOldBasketItemId = null )
00286     {
00287         // enabled ?
00288         if ( !$this->isEnabled() )
00289             return null;
00290 
00291         // basket exclude
00292         if ( $this->getConfig()->getConfigParam( 'blBasketExcludeEnabled' ) ) {
00293             if ( !$this->canAddProductToBasket( $sProductID ) ) {
00294                 $this->setCatChangeWarningState( true );
00295                 return null;
00296             } else {
00297                 $this->setCatChangeWarningState( false );
00298             }
00299         }
00300 
00301         $sItemId = $this->getItemKey( $sProductID, $aSel, $aPersParam, $blBundle );
00302         if ( $sOldBasketItemId && ( strcmp( $sOldBasketItemId, $sItemId ) != 0 ) ) {
00303             if ( isset( $this->_aBasketContents[$sItemId] ) ) {
00304                 // we are merging, so params will just go to the new key
00305                 unset( $this->_aBasketContents[$sOldBasketItemId] );
00306                 // do not override stock
00307                 $blOverride = false;
00308             } else {
00309                 // value is null - means isset will fail and real values will be filled
00310                 $this->_changeBasketItemKey( $sOldBasketItemId, $sItemId );
00311             }
00312         }
00313 
00314         // after some checks item must be removed from basket
00315         $blRemoveItem = false;
00316 
00317         // initialting exception storage
00318         $oEx = null;
00319 
00320         if ( isset( $this->_aBasketContents[$sItemId] ) ) {
00321 
00322             //updating existing
00323             try {
00324                 // setting stock check status
00325                 $this->_aBasketContents[$sItemId]->setStockCheckStatus( $this->getStockCheckMode() );
00326                 //validate amount
00327                 //possibly throws exception
00328                 $this->_aBasketContents[$sItemId]->setAmount( $dAmount, $blOverride, $sItemId );
00329             } catch( oxOutOfStockException $oEx ) {
00330                 // rethrow later
00331             }
00332 
00333         } else {
00334             //inserting new
00335             $oBasketItem = oxNew( 'oxbasketitem' );
00336             try {
00337                 $oBasketItem->setStockCheckStatus( $this->getStockCheckMode() );
00338                 $oBasketItem->init( $sProductID, $dAmount, $aSel, $aPersParam, $blBundle );
00339             } catch( oxNoArticleException $oEx ) {
00340                 // in this case that the article does not exist remove the item from the basket by setting its amount to 0
00341                 //$oBasketItem->dAmount = 0;
00342                 $blRemoveItem = true;
00343 
00344             } catch( oxOutOfStockException $oEx ) {
00345                 // rethrow later
00346             } catch ( oxArticleInputException $oEx ) {
00347                 // rethrow later
00348                 $blRemoveItem = true;
00349             }
00350 
00351             $this->_aBasketContents[$sItemId] = $oBasketItem;
00352         }
00353 
00354         //in case amount is 0 removing item
00355         if ( $this->_aBasketContents[$sItemId]->getAmount() == 0 || $blRemoveItem ) {
00356             $this->removeItem( $sItemId );
00357         } elseif ( $blBundle ) {
00358             //marking bundles
00359             $this->_aBasketContents[$sItemId]->setBundle( true );
00360         }
00361 
00362         //calling update method
00363         $this->onUpdate();
00364 
00365         if ( $oEx ) {
00366             throw $oEx;
00367         }
00368 
00369         // notifying that new basket item was added
00370         $this->_addedNewItem( $sProductID, $dAmount, $aSel, $aPersParam, $blOverride, $blBundle, $sOldBasketItemId );
00371 
00372         // returning basket item object
00373         return $this->_aBasketContents[$sItemId];
00374     }
00375 
00383     public function addOrderArticleToBasket( $oOrderArticle )
00384     {
00385         // adding only if amount > 0
00386         if ( $oOrderArticle->oxorderarticles__oxamount->value > 0 && !$oOrderArticle->isBundle() ) {
00387             $sItemId = $oOrderArticle->getId();
00388 
00389             //inserting new
00390             $this->_aBasketContents[$sItemId] = oxNew( 'oxbasketitem' );
00391             $this->_aBasketContents[$sItemId]->initFromOrderArticle( $oOrderArticle );
00392             $this->_aBasketContents[$sItemId]->setWrapping( $oOrderArticle->oxorderarticles__oxwrapid->value );
00393             $this->_aBasketContents[$sItemId]->setBundle( $oOrderArticle->isBundle() );
00394 
00395             //calling update method
00396             $this->onUpdate();
00397 
00398             return $this->_aBasketContents[$sItemId];
00399         } elseif ( $oOrderArticle->isBundle() ) {
00400             // deleting bundles, they are handled automatically
00401             $oOrderArticle->delete();
00402         }
00403     }
00404 
00412     public function setStockCheckMode( $blCheck )
00413     {
00414         $this->_blCheckStock = $blCheck;
00415     }
00416 
00422     public function getStockCheckMode()
00423     {
00424         return $this->_blCheckStock;
00425     }
00426 
00439     public function getItemKey( $sProductId, $aSel = null, $aPersParam = null, $blBundle = false, $sAdditionalParam = '' )
00440     {
00441         $aSel = ( $aSel != null) ? $aSel : array (0=>'0');
00442 
00443         $sItemKey = md5( $sProductId.'|'.serialize( $aSel ).'|'.serialize( $aPersParam ).'|'.( int ) $blBundle . '|' . serialize( $sAdditionalParam ) );
00444 
00445         return $sItemKey;
00446     }
00447 
00448 
00456     public function removeItem( $sItemKey )
00457     {
00458         if ($this->getConfig()->getConfigParam( 'blPsBasketReservationEnabled' )) {
00459             if (isset($this->_aBasketContents[$sItemKey])) {
00460                 $sArticleId = $this->_aBasketContents[$sItemKey]->getProductId();
00461                 if ($sArticleId) {
00462                     $this->getSession()
00463                             ->getBasketReservations()
00464                             ->discardArticleReservation($sArticleId);
00465                 }
00466             }
00467         }
00468         unset( $this->_aBasketContents[$sItemKey] );
00469 
00470         // basket exclude
00471         if ( !count($this->_aBasketContents) && $this->getConfig()->getConfigParam( 'blBasketExcludeEnabled' ) ) {
00472             $this->setBasketRootCatId(null);
00473         }
00474     }
00475 
00481     protected function _clearBundles()
00482     {
00483         reset( $this->_aBasketContents );
00484         while ( list( $sItemKey, $oBasketItem ) = each( $this->_aBasketContents ) ) {
00485             if ( $oBasketItem->isBundle() ) {
00486                 $this->removeItem( $sItemKey );
00487             }
00488         }
00489     }
00490 
00498     protected function _getArticleBundles( $oBasketItem )
00499     {
00500         $aBundles = array();
00501 
00502         if ( $oBasketItem->isBundle() ) {
00503             return $aBundles;
00504         }
00505 
00506         $oArticle = $oBasketItem->getArticle();
00507         if ( $oArticle && $oArticle->oxarticles__oxbundleid->value ) {
00508             $aBundles[$oArticle->oxarticles__oxbundleid->value] = 1;
00509         }
00510 
00511         return $aBundles;
00512     }
00513 
00522     protected function _getItemBundles( $oBasketItem, $aBundles = array() )
00523     {
00524         if ( $oBasketItem->isBundle() ) {
00525             return array();
00526         }
00527 
00528         // does this object still exists ?
00529         if ( $oArticle = $oBasketItem->getArticle() ) {
00530             $aDiscounts = oxDiscountList::getInstance()->getBasketItemBundleDiscounts( $oArticle, $this, $this->getBasketUser() );
00531 
00532             foreach ( $aDiscounts as $oDiscount ) {
00533 
00534                 $iAmnt = $oDiscount->getBundleAmount( $oBasketItem->getAmount() );
00535                 if ( $iAmnt ) {
00536                     //init array element
00537                     if ( !isset( $aBundles[$oDiscount->oxdiscount__oxitmartid->value] ) ) {
00538                         $aBundles[$oDiscount->oxdiscount__oxitmartid->value] = 0;
00539                     }
00540 
00541                     if ($oDiscount->oxdiscount__oxitmmultiple->value) {
00542                         $aBundles[$oDiscount->oxdiscount__oxitmartid->value] += $iAmnt;
00543                     } else {
00544                         $aBundles[$oDiscount->oxdiscount__oxitmartid->value] = $iAmnt;
00545                     }
00546                 }
00547             }
00548         }
00549 
00550         return $aBundles;
00551     }
00552 
00560     protected function _getBasketBundles( $aBundles = array() )
00561     {
00562         $aDiscounts = oxDiscountList::getInstance()->getBasketBundleDiscounts( $this, $this->getBasketUser() );
00563 
00564         // calculating amount of non bundled/discount items
00565         $dAmount = 0;
00566         foreach ( $this->_aBasketContents as $oBasketItem ) {
00567             if ( !( $oBasketItem->isBundle() || $oBasketItem->isDiscountArticle() ) ) {
00568                 $dAmount += $oBasketItem->getAmount();
00569             }
00570         }
00571 
00572         foreach ( $aDiscounts as $oDiscount ) {
00573             if ($oDiscount->oxdiscount__oxitmartid->value) {
00574                 if ( !isset( $aBundles[$oDiscount->oxdiscount__oxitmartid->value] ) ) {
00575                     $aBundles[$oDiscount->oxdiscount__oxitmartid->value] = 0;
00576                 }
00577 
00578                 $aBundles[$oDiscount->oxdiscount__oxitmartid->value] += $oDiscount->getBundleAmount( $dAmount );
00579             }
00580         }
00581 
00582         return $aBundles;
00583     }
00584 
00591     protected function _addBundles()
00592     {
00593         $aBundles = array();
00594         // iterating through articles and binding bundles
00595         foreach ( $this->_aBasketContents as $key => $oBasketItem ) {
00596             try {
00597                 // adding discount type bundles
00598                 if ( !$oBasketItem->isDiscountArticle() && !$oBasketItem->isBundle() ) {
00599                     $aBundles = $this->_getItemBundles( $oBasketItem, $aBundles );
00600                 } else {
00601                     continue;
00602                 }
00603 
00604                     // adding item type bundles
00605                     $aArtBundles = $this->_getArticleBundles( $oBasketItem );
00606 
00607                     // adding bundles to basket
00608                     $this->_addBundlesToBasket( $aArtBundles );
00609             } catch ( oxNoArticleException $oEx ) {
00610                 $this->removeItem( $key );
00611                 oxUtilsView::getInstance()->addErrorToDisplay( $oEx );
00612             } catch( oxArticleInputException $oEx ) {
00613                 $this->removeItem( $key );
00614                 oxUtilsView::getInstance()->addErrorToDisplay( $oEx );
00615             }
00616         }
00617 
00618         // adding global basket bundles
00619         $aBundles = $this->_getBasketBundles( $aBundles );
00620 
00621         // adding all bundles to basket
00622         if ( $aBundles ) {
00623             $this->_addBundlesToBasket( $aBundles );
00624         }
00625     }
00626 
00634     protected function _addBundlesToBasket( $aBundles )
00635     {
00636         foreach ( $aBundles as $sBundleId => $dAmount ) {
00637             if ( $dAmount ) {
00638                 try {
00639                     if ( $oBundleItem = $this->addToBasket( $sBundleId, $dAmount, null, null, false, true ) ) {
00640                         $oBundleItem->setAsDiscountArticle( true );
00641                     }
00642                 } catch(oxArticleException $oEx) {
00643                     // caught and ignored
00644                 }
00645             }
00646         }
00647 
00648     }
00649 
00655     protected function _calcItemsPrice()
00656     {
00657         // resetting
00658         $this->setSkipDiscounts( false );
00659         $this->_iProductsCnt = 0; // count different types
00660         $this->_dItemsCnt    = 0; // count of item units
00661         $this->_dWeight      = 0; // basket weight
00662 
00663         // resetting
00664         $this->_aItemDiscounts = array();
00665 
00666         $this->_oProductsPriceList = oxNew( 'oxpricelist' );
00667         $this->_oDiscountProductsPriceList = oxNew( 'oxpricelist' );
00668         $this->_oNotDiscountedProductsPriceList = oxNew( 'oxpricelist' );
00669 
00670         $oDiscountList = oxDiscountList::getInstance();
00671 
00672         foreach ( $this->_aBasketContents as $oBasketItem ) {
00673             $this->_iProductsCnt++;
00674             $this->_dItemsCnt += $oBasketItem->getAmount();
00675             $this->_dWeight   += $oBasketItem->getWeight();
00676 
00677             if ( !$oBasketItem->isDiscountArticle() && ( $oArticle = $oBasketItem->getArticle() ) ) {
00678                 $oBasketPrice = $oArticle->getBasketPrice( $oBasketItem->getAmount(), $oBasketItem->getSelList(), $this );
00679                 $oBasketItem->setPrice( $oBasketPrice );
00680                 //P adding product price
00681                 $this->_oProductsPriceList->addToPriceList( $oBasketItem->getPrice() );
00682 
00683                 $oBasketPrice->setBruttoPriceMode();
00684                 if ( !$oArticle->skipDiscounts() && $this->canCalcDiscounts() ) {
00685                     // apply basket type discounts
00686                     //#3857 added clone in order not to influence the price
00687                     $aItemDiscounts = $oDiscountList->applyBasketDiscounts( clone $oBasketPrice, $oDiscountList->getBasketItemDiscounts( $oArticle, $this, $this->getBasketUser() ), $oBasketItem->getAmount() );
00688                     if ( is_array($this->_aItemDiscounts) && is_array($aItemDiscounts) ) {
00689                         $this->_aItemDiscounts = $this->_mergeDiscounts( $this->_aItemDiscounts, $aItemDiscounts);
00690                     }
00691                 } else {
00692                     $oBasketItem->setSkipDiscounts( true );
00693                     $this->setSkipDiscounts( true );
00694                 }
00695                 $oBasketPrice->multiply( $oBasketItem->getAmount() );
00696 
00697                 //P collect discount values for basket items which are discountable
00698                 if ( !$oArticle->skipDiscounts() ) {
00699                     $this->_oDiscountProductsPriceList->addToPriceList( $oBasketPrice );
00700                 } else {
00701                     $this->_oNotDiscountedProductsPriceList->addToPriceList( $oBasketPrice );
00702                     $oBasketItem->setSkipDiscounts( true );
00703                     $this->setSkipDiscounts( true );
00704                 }
00705             } elseif ( $oBasketItem->isBundle() ) {
00706                 // if bundles price is set to zero
00707                 $oPrice = oxNew( "oxprice");
00708                 $oBasketItem->setPrice( $oPrice );
00709             }
00710         }
00711     }
00712 
00720     public function setDiscountCalcMode( $blCalcDiscounts )
00721     {
00722         $this->_blCalcDiscounts = $blCalcDiscounts;
00723     }
00724 
00730     public function canCalcDiscounts()
00731     {
00732         return $this->_blCalcDiscounts;
00733     }
00734 
00744     protected function _mergeDiscounts( $aDiscounts, $aItemDiscounts)
00745     {
00746         foreach ( $aItemDiscounts as $sKey => $oDiscount ) {
00747             // add prices of the same discounts
00748             if ( array_key_exists ($sKey, $aDiscounts) ) {
00749                 $aDiscounts[$sKey]->dDiscount += $oDiscount->dDiscount;
00750             } else {
00751                 $aDiscounts[$sKey] = $oDiscount;
00752             }
00753         }
00754         return $aDiscounts;
00755     }
00756 
00762     protected function _calcDeliveryCost()
00763     {
00764         if ( $this->_oDeliveryPrice !== null ) {
00765             return $this->_oDeliveryPrice;
00766         }
00767         $myConfig  = $this->getConfig();
00768         $oDeliveryPrice = oxNew( 'oxprice' );
00769         $oDeliveryPrice->setBruttoPriceMode();
00770 
00771         // don't calculate if not logged in
00772         $oUser = $this->getBasketUser();
00773 
00774         if ( !$oUser && !$myConfig->getConfigParam( 'blCalculateDelCostIfNotLoggedIn' ) ) {
00775             return $oDeliveryPrice;
00776         }
00777 
00778         // VAT for delivery will be calculated always (#3757)
00779         // blCalcVATForDelivery option is @deprecated since 2012-03-23 in version 4.6
00780         // the option blShowVATForDelivery will be used only for displaying
00781         $fDelVATPercent = 0;
00782         $fDelVATPercent = $this->getMostUsedVatPercent();
00783         $oDeliveryPrice->setVat( $fDelVATPercent );
00784 
00785         // list of active delivery costs
00786         if ( $myConfig->getConfigParam('bl_perfLoadDelivery') ) {
00787             $aDeliveryList = oxDeliveryList::getInstance()->getDeliveryList( $this,
00788                                         $oUser,
00789                                         $this->_findDelivCountry(),
00790                                         $this->getShippingId()
00791                                     );
00792 
00793             if ( count( $aDeliveryList ) > 0 ) {
00794                 foreach ( $aDeliveryList as $oDelivery ) {
00795                     //debug trace
00796                     if ( $myConfig->getConfigParam( 'iDebug' ) == 5 ) {
00797                         echo( "DelCost : ".$oDelivery->oxdelivery__oxtitle->value."<br>" );
00798                     }
00799                     $oDeliveryPrice->addPrice( $oDelivery->getDeliveryPrice( $fDelVATPercent ) );
00800                 }
00801             }
00802         }
00803 
00804         return $oDeliveryPrice;
00805     }
00806 
00812     public function getBasketUser()
00813     {
00814         if ( $this->_oUser == null ) {
00815             return $this->getUser();
00816         }
00817 
00818         return $this->_oUser;
00819     }
00820 
00828     public function setBasketUser( $oUser )
00829     {
00830         $this->_oUser = $oUser;
00831     }
00832 
00833     //P
00839     public function getMostUsedVatPercent()
00840     {
00841         return $this->_oProductsPriceList->getMostUsedVatPercent();
00842     }
00843 
00844     //P
00851     protected function _calcTotalPrice()
00852     {
00853         // 1. add products price
00854         $dprice = $this->_oProductsPriceList->getBruttoSum();
00855         $this->_oPrice->setPrice( $dprice );
00856 
00857         // 2. substract discounts
00858         if ( $dprice ) {
00859 
00860             /*
00861             //#3857 this section is not needed as $this->_aItemDiscounts is part of $this->_aDiscounts
00862             // 2.1 applying basket item discounts
00863             foreach ( $this->_aItemDiscounts as $oDiscount ) {
00864 
00865                 // skipping bundle discounts
00866                 if ( $oDiscount->sType == 'itm' ) {
00867                     continue;
00868                 }
00869                 $this->_oPrice->subtract( $oDiscount->dDiscount );
00870             }*/
00871 
00872             // 2.2 applying basket discounts
00873             $this->_oPrice->subtract( $this->_oTotalDiscount->getBruttoPrice() );
00874 
00875             // 2.3 applying voucher discounts
00876             if ($oVoucherDisc = $this->getVoucherDiscount()) {
00877                 $this->_oPrice->subtract( $oVoucherDisc->getBruttoPrice() );
00878             }
00879         }
00880 
00881         // 2.3 add delivery cost
00882         if ( isset( $this->_aCosts['oxdelivery'] ) ) {
00883             $this->_oPrice->add( $this->_aCosts['oxdelivery']->getBruttoPrice() );
00884         }
00885 
00886         // 2.4 add wrapping price
00887         if ( isset( $this->_aCosts['oxwrapping'] ) ) {
00888             $this->_oPrice->add( $this->_aCosts['oxwrapping']->getBruttoPrice() );
00889         }
00890 
00891         // 2.5 add payment price
00892         if ( isset( $this->_aCosts['oxpayment'] ) ) {
00893             $this->_oPrice->add( $this->_aCosts['oxpayment']->getBruttoPrice() );
00894         }
00895 
00896         // 2.6 add TS protection price
00897         if ( isset( $this->_aCosts['oxtsprotection'] ) ) {
00898             $this->_oPrice->add( $this->_aCosts['oxtsprotection']->getBruttoPrice() );
00899         }
00900 
00901     }
00902 
00910     public function setVoucherDiscount( $dDiscount )
00911     {
00912         $this->_oVoucherDiscount = oxNew( 'oxPrice' );
00913         $this->_oVoucherDiscount->setBruttoPriceMode();
00914         $this->_oVoucherDiscount->add( $dDiscount );
00915     }
00916 
00922     protected function _calcVoucherDiscount()
00923     {
00924         if ( $this->getConfig()->getConfigParam( 'bl_showVouchers' ) && ($this->_oVoucherDiscount === null || ( $this->_blUpdateNeeded && !$this->isAdmin() ) ) ) {
00925 
00926             $this->_oVoucherDiscount = oxNew( 'oxPrice' );
00927             $this->_oVoucherDiscount->setBruttoPriceMode();
00928 
00929 
00930             // calculating price to apply discount
00931             $dPrice = $this->_oDiscountProductsPriceList->getBruttoSum() - $this->_oTotalDiscount->getBruttoPrice();
00932 
00933             // recalculating
00934             if ( count( $this->_aVouchers ) ) {
00935                 $oLang = oxLang::getInstance();
00936                 foreach ( $this->_aVouchers as $sVoucherId => $oStdVoucher ) {
00937                     $oVoucher = oxNew( 'oxvoucher' );
00938                     try { // checking
00939                         $oVoucher->load( $oStdVoucher->sVoucherId );
00940 
00941                         if ( !$this->_blSkipVouchersAvailabilityChecking ) {
00942                             $oVoucher->checkBasketVoucherAvailability( $this->_aVouchers, $dPrice );
00943                             $oVoucher->checkUserAvailability( $this->getBasketUser() );
00944                         }
00945 
00946                         // assigning real voucher discount value as this is the only place where real value is calculated
00947                         $dVoucherdiscount = $oVoucher->getDiscountValue( $dPrice );
00948 
00949                         // acumulating discount value
00950                         $this->_oVoucherDiscount->add( $dVoucherdiscount );
00951 
00952                         // collecting formatted for preview
00953                         $oStdVoucher->fVoucherdiscount = $oLang->formatCurrency( $dVoucherdiscount, $this->getBasketCurrency() );
00954                         $oStdVoucher->dVoucherdiscount = $dVoucherdiscount;
00955 
00956                         // substracting voucher discount
00957                         $dPrice -= $dVoucherdiscount;
00958                     } catch ( oxVoucherException $oEx ) {
00959 
00960                         // removing voucher on error
00961                         $oVoucher->unMarkAsReserved();
00962                         unset( $this->_aVouchers[$sVoucherId] );
00963 
00964                         // storing voucher error info
00965                         oxUtilsView::getInstance()->addErrorToDisplay($oEx, false, true);
00966                     }
00967                 }
00968             }
00969         }
00970     }
00971 
00972     //V
00979     protected function _applyDiscounts()
00980     {
00981         $dBruttoPrice = 0;
00982         $this->_aDiscountedVats = array();
00983         if ( $oPriceList = $this->getDiscountProductsPrice() ) {
00984             $dBruttoPrice = $oPriceList->getBruttoSum();
00985             $this->_aDiscountedVats = $oPriceList->getVatInfo();
00986         }
00987 
00988         //apply discounts for brutto price
00989         $dDiscountedBruttoPrice = $this->getDiscountedProductsBruttoPrice();
00990         $oTotalDiscount   = $this->getTotalDiscount();
00991         $oVoucherDiscount = $this->getVoucherDiscount();
00992 
00993         //apply discount for VATs
00994         if ( $dBruttoPrice &&
00995              ( ( $oTotalDiscount && $oTotalDiscount->getBruttoPrice() ) ||
00996                ( $oVoucherDiscount && $oVoucherDiscount->getBruttoPrice() )
00997              )
00998            ) {
00999             $dPercent = ( $dDiscountedBruttoPrice / $dBruttoPrice) * 100;
01000             foreach ( $this->_aDiscountedVats as $sKey => $dVat ) {
01001                 $this->_aDiscountedVats[$sKey] = oxPrice::percent( $dVat, $dPercent);
01002             }
01003         }
01004 
01005         $oUtils = oxUtils::getInstance();
01006         $dDiscVatSum = 0;
01007         foreach ( $this->_aDiscountedVats as $dVat ) {
01008             $dDiscVatSum += $oUtils->fRound( -$dVat, $this->_oCurrency);
01009         }
01010         //calculate netto price with discounts
01011         $this->_dDiscountedProductNettoPrice = $dDiscountedBruttoPrice + $dDiscVatSum;
01012     }
01013 
01019     protected function _calcBasketDiscount()
01020     {
01021         // resetting
01022         $this->_aDiscounts = array();
01023 
01024         // P using prices sum which has discount, not sum of skipped discounts
01025         $dOldprice = $this->_oDiscountProductsPriceList->getBruttoSum();
01026 
01027         // add basket discounts
01028         $aDiscounts = oxDiscountList::getInstance()->getBasketDiscounts( $this, $this->getBasketUser() );
01029 
01030         foreach ( $aDiscounts as $oDiscount ) {
01031 
01032             // storing applied discounts
01033             $oStdDiscount = $oDiscount->getSimpleDiscount();
01034 
01035             // skipping bundle discounts
01036             if ( $oDiscount->oxdiscount__oxaddsumtype->value == 'itm' ) {
01037                 continue;
01038             }
01039 
01040             // saving discount info
01041             $oStdDiscount->dDiscount = $oDiscount->getAbsValue( $dOldprice );
01042             if ($dOldprice < $oStdDiscount->dDiscount) {
01043                 $oStdDiscount->dDiscount = $dOldprice;
01044             }
01045 
01046             if ($oStdDiscount->dDiscount != 0) {
01047                 $this->_aDiscounts[$oDiscount->getId()] = $oStdDiscount;
01048                 // substracting product price after discount
01049                 $dOldprice = $dOldprice - $oStdDiscount->dDiscount;
01050             }
01051         }
01052     }
01053 
01059     protected function _calcBasketTotalDiscount()
01060     {
01061         if ( $this->_oTotalDiscount === null || ( !$this->isAdmin() ) ) {
01062 
01063 
01064             $this->_oTotalDiscount = oxNew( 'oxPrice' );
01065             $this->_oTotalDiscount->setBruttoPriceMode();
01066 
01067             //#3857 merging item discounts to aDiscounts and later to oTotalDiscount
01068             $this->_aDiscounts = array_merge($this->_aItemDiscounts, $this->_aDiscounts);
01069 
01070             if ( is_array($this->_aDiscounts) ) {
01071                 foreach ( $this->_aDiscounts as $oDiscount ) {
01072 
01073                     // skipping bundle discounts
01074                     if ( $oDiscount->sType == 'itm' ) {
01075                         continue;
01076                     }
01077 
01078                     // add discount value to total basket discount
01079                     $this->_oTotalDiscount->add( $oDiscount->dDiscount );
01080                 }
01081             }
01082         }
01083     }
01084 
01094     protected function _calcBasketWrapping()
01095     {
01096         $myConfig = $this->getConfig();
01097         $oWrappingPrice = oxNew( 'oxPrice' );
01098         $oWrappingPrice->setBruttoPriceMode();
01099 
01100         // wrapping VAT will be always calculated (#3757)
01101         // blCalcVatForWrapping option is @deprecated since 2012-03-23 in version 4.6
01102         // blShowVATForWrapping option will be used only for displaying
01103         $dWrappingVATPercent = $this->getMostUsedVatPercent();
01104         $oWrappingPrice->setVat( $dWrappingVATPercent );
01105 
01106         // calculating basket items wrapping
01107         foreach ( $this->_aBasketContents as $oBasketItem ) {
01108 
01109             if ( ( $oWrapping = $oBasketItem->getWrapping() ) ) {
01110                 if ($dWrappingVATPercent !== null) {
01111                     $oWrapping->setWrappingVat($dWrappingVATPercent);
01112                 }
01113                 $oWrappingPrice->addPrice( $oWrapping->getWrappingPrice( $oBasketItem->getAmount() ) );
01114             }
01115         }
01116 
01117         // gift card price calculation
01118         if ( ( $oCard = $this->getCard() ) ) {
01119             if ($dWrappingVATPercent !== null) {
01120                 $oCard->setWrappingVat($dWrappingVATPercent);
01121             }
01122             $oWrappingPrice->addPrice( $oCard->getWrappingPrice() );
01123         }
01124 
01125         return $oWrappingPrice;
01126     }
01127 
01134     protected function _calcPaymentCost()
01135     {
01136         // resetting values
01137         $oPaymentPrice = oxNew( 'oxPrice' );
01138         $oPaymentPrice->setBruttoPriceMode();
01139 
01140         // payment
01141         if ( ( $this->_sPaymentId = $this->getPaymentId() ) ) {
01142 
01143             $oPayment = oxNew( 'oxpayment' );
01144             $oPayment->load( $this->_sPaymentId );
01145 
01146             $oPaymentPrice = $oPayment->getPaymentPrice( $this );
01147         }
01148 
01149         return $oPaymentPrice;
01150     }
01151 
01158     protected function _calcTsProtectionCost()
01159     {
01160         // resetting values
01161         $oProtectionPrice = oxNew( 'oxPrice' );
01162         $oProtectionPrice->setBruttoPriceMode();
01163 
01164         // payment
01165         if ( ( $this->_sTsProductId = $this->getTsProductId() ) ) {
01166 
01167             $oTsProtection = oxNew('oxtsprotection');
01168             $oTsProduct = $oTsProtection->getTsProduct( $this->_sTsProductId );
01169 
01170             $oProtectionPrice = $oTsProduct->getPrice();
01171         }
01172         return $oProtectionPrice;
01173     }
01174 
01183     public function setCost( $sCostName, $oPrice = null )
01184     {
01185         $this->_aCosts[$sCostName] = $oPrice;
01186     }
01187 
01196     public function calculateBasket( $blForceUpdate = false )
01197     {
01198         /*
01199         //would be good to perform the reset of previous calculation
01200         //at least you can use it for the debug
01201         $this->_aDiscounts = array();
01202         $this->_aItemDiscounts = array();
01203         $this->_oTotalDiscount = null;
01204         $this->_dDiscountedProductNettoPrice = 0;
01205         $this->_aDiscountedVats = array();
01206         $this->_oPrice = null;
01207         $this->_oNotDiscountedProductsPriceList = null;
01208         $this->_oProductsPriceList = null;
01209         $this->_oDiscountProductsPriceList = null;*/
01210 
01211 
01212         if ( !$this->isEnabled() ) {
01213             return;
01214         }
01215 
01216         if ( !$this->_blUpdateNeeded && !$blForceUpdate ) {
01217             return;
01218         }
01219 
01220         $this->_aCosts = array();
01221 
01222         $this->_oPrice = oxNew( 'oxprice' );
01223         $this->_oPrice->setBruttoPriceMode();
01224 
01225         //  1. saving basket to the database
01226         $this->_save();
01227 
01228         //  2. remove all bundles
01229         $this->_clearBundles();
01230 
01231         //  3. generate bundle items
01232         $this->_addBundles();
01233 
01234         // reserve active basket
01235         if ($this->getConfig()->getConfigParam( 'blPsBasketReservationEnabled' )) {
01236             $this->getSession()->getBasketReservations()->reserveBasket($this);
01237         }
01238 
01239         //  4. calculating item prices
01240         $this->_calcItemsPrice();
01241 
01242         //  5. calculating/applying discounts
01243         $this->_calcBasketDiscount();
01244 
01245         //  6. calculating basket total discount
01246         $this->_calcBasketTotalDiscount();
01247 
01248         //  7. check for vouchers
01249         $this->_calcVoucherDiscount();
01250 
01251         //  8. applies all discounts to pricelist
01252         $this->_applyDiscounts();
01253 
01254         //  9. calculating additional costs:
01255         //  9.1: delivery
01256         $this->setCost( 'oxdelivery', $this->_calcDeliveryCost() );
01257 
01258         //  9.2: adding wrapping costs
01259         $this->setCost( 'oxwrapping', $this->_calcBasketWrapping() );
01260 
01261         //  9.3: adding payment cost
01262         $this->setCost( 'oxpayment', $this->_calcPaymentCost() );
01263 
01264         //  9.4: adding TS protection cost
01265         $this->setCost( 'oxtsprotection', $this->_calcTsProtectionCost() );
01266 
01267         //  10. calculate total price
01268         $this->_calcTotalPrice();
01269 
01270         //  11. setting deprecated values
01271         $this->_setDeprecatedValues();
01272 
01273         //  12.setting to up-to-date status
01274         $this->afterUpdate();
01275     }
01276 
01282     public function onUpdate()
01283     {
01284         $this->_blUpdateNeeded = true;
01285     }
01286 
01292     public function afterUpdate()
01293     {
01294         $this->_blUpdateNeeded = false;
01295     }
01296 
01304     public function getBasketSummary()
01305     {
01306         if ( $this->_blUpdateNeeded || $this->_aBasketSummary === null ) {
01307             $this->_aBasketSummary = new Oxstdclass();
01308             $this->_aBasketSummary->aArticles = array();
01309             $this->_aBasketSummary->aCategories = array();
01310             $this->_aBasketSummary->iArticleCount = 0;
01311             $this->_aBasketSummary->dArticlePrice = 0;
01312             $this->_aBasketSummary->dArticleDiscountablePrice = 0;
01313         }
01314 
01315         if ( !$this->isEnabled() ) {
01316             return $this->_aBasketSummary;
01317         }
01318 
01319         $myConfig = $this->getConfig();
01320         foreach ( $this->_aBasketContents as $oBasketItem ) {
01321             if ( !$oBasketItem->isBundle() && $oArticle = $oBasketItem->getArticle(false) ) {
01322                 $aCatIds = $oArticle->getCategoryIds();
01323                 //#M530 if price is not loaded for articles
01324                 $dPrice = 0;
01325                 $dDiscountablePrice = 0;
01326                 if ( ( $oPrice = $oArticle->getPrice( $oBasketItem->getAmount() ) ) ) {
01327                     $dPrice = $oPrice->getBruttoPrice();
01328                     if ( !$oArticle->skipDiscounts() ) {
01329                         $dDiscountablePrice = $dPrice;
01330                     }
01331                 }
01332 
01333                 foreach ( $aCatIds as $sCatId ) {
01334                     if ( !isset( $this->_aBasketSummary->aCategories[$sCatId] ) ) {
01335                         $this->_aBasketSummary->aCategories[$sCatId] = new Oxstdclass();
01336                     }
01337 
01338                     $this->_aBasketSummary->aCategories[$sCatId]->dPrice  += $dPrice * $oBasketItem->getAmount();
01339                     $this->_aBasketSummary->aCategories[$sCatId]->dDiscountablePrice += $dDiscountablePrice * $oBasketItem->getAmount();
01340                     $this->_aBasketSummary->aCategories[$sCatId]->dAmount += $oBasketItem->getAmount();
01341                     $this->_aBasketSummary->aCategories[$sCatId]->iCount++;
01342                 }
01343 
01344                 // variant handling
01345                 if ( ($sParentId = $oArticle->getProductParentId()) && $myConfig->getConfigParam( 'blVariantParentBuyable' ) ) {
01346                     if ( !isset( $this->_aBasketSummary->aArticles[$sParentId] ) ) {
01347                         $this->_aBasketSummary->aArticles[$sParentId] = 0;
01348                     }
01349                     $this->_aBasketSummary->aArticles[$sParentId] += $oBasketItem->getAmount();
01350                 }
01351 
01352                 if ( !isset( $this->_aBasketSummary->aArticles[$oBasketItem->getProductId()] ) ) {
01353                     $this->_aBasketSummary->aArticles[$oBasketItem->getProductId()] = 0;
01354                 }
01355 
01356                 $this->_aBasketSummary->aArticles[$oBasketItem->getProductId()] += $oBasketItem->getAmount();
01357                 $this->_aBasketSummary->iArticleCount += $oBasketItem->getAmount();
01358                 $this->_aBasketSummary->dArticlePrice += $dPrice * $oBasketItem->getAmount();
01359                 $this->_aBasketSummary->dArticleDiscountablePrice += $dDiscountablePrice * $oBasketItem->getAmount();
01360             }
01361         }
01362         return $this->_aBasketSummary;
01363     }
01364 
01376     public function addVoucher( $sVoucherId )
01377     {
01378         // calculating price to check
01379         // P using prices sum which has discount, not sum of skipped discounts
01380         $dPrice = 0;
01381         if ( $this->_oDiscountProductsPriceList ) {
01382             $dPrice = $this->_oDiscountProductsPriceList->getBruttoSum();
01383         }
01384 
01385         try { // trying to load voucher and apply it
01386 
01387             $oVoucher = oxNew( 'oxvoucher' );
01388 
01389             if ( !$this->_blSkipVouchersAvailabilityChecking ) {
01390                 $oVoucher->getVoucherByNr( $sVoucherId, $this->_aVouchers, true );
01391                 $oVoucher->checkVoucherAvailability( $this->_aVouchers, $dPrice );
01392                 $oVoucher->checkUserAvailability( $this->getBasketUser() );
01393                 $oVoucher->markAsReserved();
01394             } else {
01395                 $oVoucher->load( $sVoucherId );
01396             }
01397 
01398             // saving voucher info
01399             $this->_aVouchers[$oVoucher->oxvouchers__oxid->value] = $oVoucher->getSimpleVoucher();
01400         } catch ( oxVoucherException $oEx ) {
01401 
01402             // problems adding voucher
01403             oxUtilsView::getInstance()->addErrorToDisplay( $oEx, false, true );
01404         }
01405 
01406         $this->onUpdate();
01407     }
01408 
01416     public function removeVoucher( $sVoucherId )
01417     {
01418         // removing if it exists
01419         if ( isset( $this->_aVouchers[$sVoucherId] ) ) {
01420 
01421             $oVoucher = oxNew( 'oxvoucher' );
01422             $oVoucher->load( $sVoucherId );
01423 
01424             $oVoucher->unMarkAsReserved();
01425 
01426             // unsetting it if exists this voucher in DB or not
01427             unset( $this->_aVouchers[$sVoucherId] );
01428             $this->onUpdate();
01429         }
01430 
01431     }
01432 
01438     public function resetUserInfo()
01439     {
01440         $this->setPayment( null );
01441         $this->setShipping( null );
01442     }
01443 
01451     protected function _setDeprecatedValues()
01452     {
01453         // discount information
01454         // formating discount value
01455         $this->aDiscounts = $this->getDiscounts();
01456         if ( count($this->aDiscounts) > 0 ) {
01457             $oLang = oxLang::getInstance();
01458             foreach ($this->aDiscounts as $oDiscount) {
01459                 $oDiscount->fDiscount = $oLang->formatCurrency( $oDiscount->dDiscount, $this->getBasketCurrency() );
01460             }
01461         }
01462     }
01463 
01464 
01470     protected function _canSaveBasket()
01471     {
01472         $blCanSave = !$this->getConfig()->getConfigParam( 'blPerfNoBasketSaving' );
01473         return $blCanSave;
01474     }
01475 
01481     public function load()
01482     {
01483         $oUser = $this->getBasketUser();
01484         if ( !$oUser ) {
01485             return;
01486         }
01487 
01488         $oBasket = $oUser->getBasket( 'savedbasket' );
01489 
01490         // restoring from saved history
01491         $aSavedItems = $oBasket->getItems();
01492         foreach ( $aSavedItems as $oItem ) {
01493             try {
01494                 $oSelList = $oItem->getSelList();
01495 
01496                 $this->addToBasket( $oItem->oxuserbasketitems__oxartid->value, $oItem->oxuserbasketitems__oxamount->value, $oSelList, $oItem->getPersParams(), true );
01497             } catch( oxArticleException $oEx ) {
01498                 // caught and ignored
01499             }
01500         }
01501     }
01502 
01508     protected function _save()
01509     {
01510         if ( $this->_canSaveBasket() ) {
01511 
01512             if ( $oUser = $this->getBasketUser() ) {
01513                 //first delete all contents
01514                 //#2039
01515                 $oSavedBasket = $oUser->getBasket( 'savedbasket' );
01516                 $oSavedBasket->delete();
01517 
01518                 //then save
01519                 foreach ( $this->_aBasketContents as $oBasketItem ) {
01520                     // discount or bundled products will be added automatically if available
01521                     if ( !$oBasketItem->isBundle() && !$oBasketItem->isDiscountArticle() ) {
01522                        $oSavedBasket->addItemToBasket( $oBasketItem->getProductId(), $oBasketItem->getAmount(), $oBasketItem->getSelList(), true, $oBasketItem->getPersParams() );
01523                     }
01524                 }
01525             }
01526         }
01527     }
01528 
01540     /*
01541     protected function _addItemToSavedBasket( $sProductId , $dAmount, $aSel, $blOverride = false, $aPersParam = null )
01542     {
01543         // updating basket history
01544         if ( $oUser = $this->getBasketUser() ) {
01545             $oUser->getBasket( 'savedbasket' )->addItemToBasket( $sProductId, $dAmount, $aSel, $blOverride, $aPersParam );
01546         }
01547     }*/
01548 
01556     protected function _deleteSavedBasket()
01557     {
01558         // deleting basket if session user available
01559         if ( $oUser = $this->getBasketUser() ) {
01560             $oUser->getBasket( 'savedbasket' )->delete();
01561         }
01562 
01563         // basket exclude
01564         if ( $this->getConfig()->getConfigParam( 'blBasketExcludeEnabled' )) {
01565             $this->setBasketRootCatId(null);
01566         }
01567     }
01568 
01574     protected function _findDelivCountry()
01575     {
01576         $myConfig = $this->getConfig();
01577         $oUser    = $this->getBasketUser();
01578 
01579         $sDelivCountry = null;
01580 
01581         if ( !$oUser ) {
01582             // don't calculate if not logged in unless specified otherwise
01583             $aHomeCountry = $myConfig->getConfigParam( 'aHomeCountry' );
01584             if ( $myConfig->getConfigParam( 'blCalculateDelCostIfNotLoggedIn' ) && is_array( $aHomeCountry ) ) {
01585                 $sDelivCountry = current( $aHomeCountry );
01586             }
01587         } else {
01588 
01589             // ok, logged in
01590             if ( $sCountryId = $myConfig->getGlobalParameter( 'delcountryid' ) ) {
01591                 $sDelivCountry = $sCountryId;
01592             } elseif ( $sAddressId = oxSession::getVar( 'deladrid' ) ) {
01593 
01594                 $oDelAdress = oxNew( 'oxaddress' );
01595                 if ( $oDelAdress->load( $sAddressId ) ) {
01596                     $sDelivCountry = $oDelAdress->oxaddress__oxcountryid->value;
01597                 }
01598             }
01599 
01600             // still not found ?
01601             if ( !$sDelivCountry ) {
01602                 $sDelivCountry = $oUser->oxuser__oxcountryid->value;
01603             }
01604         }
01605 
01606         return $sDelivCountry;
01607     }
01608 
01614     public function deleteBasket()
01615     {
01616         $this->_aBasketContents = array();
01617         $this->getSession()->delBasket();
01618 
01619         if ($this->getConfig()->getConfigParam( 'blPsBasketReservationEnabled' )) {
01620             $this->getSession()->getBasketReservations()->discardReservations();
01621         }
01622 
01623         // merging basket history
01624         $this->_deleteSavedBasket();
01625     }
01626 
01634     public function setPayment( $sPaymentId = null )
01635     {
01636         $this->_sPaymentId = $sPaymentId;
01637     }
01638 
01644     public function getPaymentId()
01645     {
01646         if ( !$this->_sPaymentId ) {
01647              $this->_sPaymentId = oxSession::getVar( 'paymentid' );
01648         }
01649         return $this->_sPaymentId;
01650     }
01651 
01659     public function setShipping( $sShippingSetId = null )
01660     {
01661         $this->_sShippingSetId = $sShippingSetId;
01662         oxSession::setVar( 'sShipSet', $sShippingSetId );
01663     }
01664 
01672     public function setDeliveryPrice( $oShippingPrice = null )
01673     {
01674         $this->_oDeliveryPrice = $oShippingPrice;
01675     }
01676 
01682     public function getShippingId()
01683     {
01684         if ( !$this->_sShippingSetId ) {
01685              $this->_sShippingSetId = oxSession::getVar( 'sShipSet' );
01686         }
01687 
01688         $sActPaymentId = $this->getPaymentId();
01689         // setting default if none is set
01690         if ( !$this->_sShippingSetId && $sActPaymentId != 'oxempty' ) {
01691             $oUser = $this->getUser();
01692 
01693             // choosing first preferred delivery set
01694             list( , $sActShipSet ) = oxDeliverySetList::getInstance()->getDeliverySetData( null, $oUser, $this );
01695             // in case nothing was found and no user set - choosing default
01696             $this->_sShippingSetId = $sActShipSet ? $sActShipSet : ( $oUser ? null : 'oxidstandard' );
01697         } elseif ( !$this->isAdmin() && $sActPaymentId == 'oxempty' ) {
01698             // in case 'oxempty' is payment id - delivery set must be reset
01699             $this->_sShippingSetId = null;
01700         }
01701 
01702         return $this->_sShippingSetId;
01703     }
01704 
01710     public function getBasketArticles()
01711     {
01712         $aBasketArticles = array();
01713 
01714         foreach ( $this->_aBasketContents as $sItemKey => $oBasketItem ) {
01715             try {
01716                 $oProduct = $oBasketItem->getArticle();
01717 
01718                 if ( $this->getConfig()->getConfigParam( 'bl_perfLoadSelectLists' ) ) {
01719                     // marking chosen select list
01720                     $aSelList = $oBasketItem->getSelList();
01721                     if ( is_array( $aSelList ) && ( $aSelectlist = $oProduct->getSelectLists( $sItemKey ) ) ) {
01722                         reset( $aSelList );
01723                         while ( list( $conkey, $iSel ) = each( $aSelList ) ) {
01724                             $aSelectlist[$conkey][$iSel] = $aSelectlist[$conkey][$iSel];
01725                             $aSelectlist[$conkey][$iSel]->selected = 1;
01726                         }
01727                         $oProduct->setSelectlist( $aSelectlist );
01728                     }
01729                 }
01730             } catch ( oxNoArticleException $oEx ) {
01731                 oxUtilsView::getInstance()->addErrorToDisplay( $oEx );
01732                 $this->removeItem( $sItemKey );
01733                 $this->calculateBasket( true );
01734                 continue;
01735             } catch ( oxArticleInputException $oEx ) {
01736                 oxUtilsView::getInstance()->addErrorToDisplay( $oEx );
01737                 $this->removeItem( $sItemKey );
01738                 $this->calculateBasket( true );
01739                 continue;
01740             }
01741 
01742             $aBasketArticles[$sItemKey] = $oProduct;
01743         }
01744         return $aBasketArticles;
01745     }
01746 
01752     public function getDiscountProductsPrice()
01753     {
01754         return $this->_oDiscountProductsPriceList;
01755     }
01756 
01762     public function getProductsPrice()
01763     {
01764         if ( is_null($this->_oProductsPriceList) ) {
01765             $this->_oProductsPriceList = oxNew( 'oxPriceList' );
01766         }
01767 
01768         return $this->_oProductsPriceList;
01769     }
01770 
01776     public function getPrice()
01777     {
01778         if ( is_null($this->_oPrice) ) {
01779             $this->_oPrice = oxNew( 'oxprice' );
01780         }
01781 
01782         return $this->_oPrice;
01783     }
01784 
01791     public function getOrderId()
01792     {
01793         return $this->_sOrderId;
01794     }
01795 
01803     public function setOrderId( $sId )
01804     {
01805         $this->_sOrderId = $sId;
01806     }
01807 
01816     public function getCosts( $sId = null )
01817     {
01818         // if user want some specific cost - return it
01819         if ( $sId ) {
01820             return isset( $this->_aCosts[$sId] )?$this->_aCosts[$sId]:null;
01821         }
01822         return $this->_aCosts;
01823     }
01824 
01830     public function getVouchers()
01831     {
01832         return $this->_aVouchers;
01833     }
01834 
01840     public function getProductsCount()
01841     {
01842         return $this->_iProductsCnt;
01843     }
01844 
01850     public function getItemsCount()
01851     {
01852         return $this->_dItemsCnt;
01853     }
01854 
01860     public function getWeight()
01861     {
01862         return $this->_dWeight;
01863     }
01864 
01870     public function getContents()
01871     {
01872         return $this->_aBasketContents;
01873     }
01874 
01882     public function getProductVats( $blFormatCurrency = true)
01883     {
01884         if ( !$this->_oNotDiscountedProductsPriceList ) {
01885             return array();
01886         }
01887 
01888         $aVats = $this->_oNotDiscountedProductsPriceList->getVatInfo();
01889 
01890         $oUtils = oxUtils::getInstance();
01891         foreach ( $this->_aDiscountedVats as $sKey => $dVat ) {
01892             if ( !isset( $aVats[$sKey] ) ) {
01893                 $aVats[$sKey] = 0;
01894             }
01895             // add prices of the same discounts
01896             $aVats[$sKey] += $oUtils->fRound( $dVat, $this->_oCurrency );
01897         }
01898 
01899         if ( $blFormatCurrency ) {
01900             $oLang = oxLang::getInstance();
01901             foreach ( $aVats as $sKey => $dVat ) {
01902                 $aVats[$sKey] = $oLang->formatCurrency( $dVat, $this->getBasketCurrency() );
01903             }
01904         }
01905 
01906         return $aVats;
01907     }
01908 
01914     public function getDiscountedNettoPrice()
01915     {
01916         if ( $this->_oNotDiscountedProductsPriceList ) {
01917             return $this->_dDiscountedProductNettoPrice + $this->_oNotDiscountedProductsPriceList->getNettoSum();
01918         }
01919         return false;
01920     }
01921 
01929     public function setCardMessage( $sMessage )
01930     {
01931         $this->_sCardMessage = $sMessage;
01932     }
01933 
01939     public function getCardMessage()
01940     {
01941         return $this->_sCardMessage;
01942     }
01943 
01951     public function setCardId( $sCardId )
01952     {
01953         $this->_sCardId = $sCardId;
01954     }
01955 
01961     public function getCardId()
01962     {
01963         return $this->_sCardId;
01964     }
01965 
01971     public function getCard()
01972     {
01973         $oCard = null;
01974         if ( $sCardId = $this->getCardId() ) {
01975             $oCard = oxNew( 'oxwrapping' );
01976             $oCard->load( $sCardId );
01977         }
01978         return $oCard;
01979     }
01980 
01986     public function getTotalDiscount()
01987     {
01988         return $this->_oTotalDiscount;
01989     }
01990 
01996     public function getDiscounts()
01997     {
01998         if ( $this->getTotalDiscount() && $this->getTotalDiscount()->getBruttoPrice() == 0 && count($this->_aItemDiscounts) == 0) {
01999             return null;
02000         }
02001 
02002         //#3857 this section is not needed as $this->_aItemDiscounts is part of $this->_aDiscounts already
02003         //return array_merge($this->_aItemDiscounts, $this->_aDiscounts);
02004         return $this->_aDiscounts;
02005     }
02006 
02012     public function getVoucherDiscount()
02013     {
02014         if ($this->getConfig()->getConfigParam( 'bl_showVouchers' )) {
02015             return $this->_oVoucherDiscount;
02016         }
02017         return null;
02018     }
02019 
02027     public function setBasketCurrency( $oCurrency )
02028     {
02029         $this->_oCurrency = $oCurrency;
02030     }
02031 
02037     public function getBasketCurrency()
02038     {
02039         if ( $this->_oCurrency === null ) {
02040             $this->_oCurrency = $this->getConfig()->getActShopCurrencyObject();
02041         }
02042 
02043         return $this->_oCurrency;
02044     }
02045 
02053     public function setSkipVouchersChecking( $blSkipChecking = null )
02054     {
02055         $this->_blSkipVouchersAvailabilityChecking = $blSkipChecking;
02056     }
02057 
02063     public function hasSkipedDiscount()
02064     {
02065         return $this->_blSkipDiscounts;
02066     }
02067 
02075     public function setSkipDiscounts( $blSkip )
02076     {
02077         $this->_blSkipDiscounts = $blSkip;
02078     }
02079 
02085     public function getProductsNetPrice()
02086     {
02087         return oxLang::getInstance()->formatCurrency( $this->getDiscountedNettoPrice(), $this->getBasketCurrency() );
02088     }
02089 
02095     public function getFProductsPrice()
02096     {
02097         if ( $this->_oProductsPriceList ) {
02098             return oxLang::getInstance()->formatCurrency( $this->_oProductsPriceList->getBruttoSum(), $this->getBasketCurrency() );
02099         }
02100         return null;
02101     }
02102 
02108     public function getDelCostVatPercent()
02109     {
02110         return $this->getCosts( 'oxdelivery' )->getVat();
02111     }
02112 
02118     public function getDelCostVat()
02119     {
02120         $dDelVAT = $this->getCosts( 'oxdelivery' )->getVatValue();
02121 
02122         // blShowVATForDelivery option will be used, only for displaying, but not calculation
02123         if ( $dDelVAT > 0 && $this->getConfig()->getConfigParam( 'blShowVATForDelivery' )) {
02124             return oxLang::getInstance()->formatCurrency( $dDelVAT, $this->getBasketCurrency() );
02125         }
02126         return false;
02127     }
02128 
02134     public function getDelCostNet()
02135     {
02136         $oConfig = $this->getConfig();
02137 
02138         // blShowVATForDelivery option will be used, only for displaying, but not calculation
02139         if ( $oConfig->getConfigParam( 'blShowVATForDelivery' ) && ( $this->getBasketUser() || $oConfig->getConfigParam( 'blCalculateDelCostIfNotLoggedIn' ) ) ) {
02140             $dNetPrice = $this->getCosts( 'oxdelivery' )->getNettoPrice();
02141             if ( $dNetPrice > 0 ) {
02142                 return oxLang::getInstance()->formatCurrency( $dNetPrice, $this->getBasketCurrency() );
02143             }
02144         }
02145         return false;
02146     }
02147 
02153     public function getPayCostVatPercent()
02154     {
02155         return $this->getCosts( 'oxpayment' )->getVat();
02156     }
02157 
02163     public function getPayCostVat()
02164     {
02165         $dPayVAT = $this->getCosts( 'oxpayment' )->getVatValue();
02166 
02167         // blShowVATForPayCharge option will be used, only for displaying, but not calculation
02168         if ( $dPayVAT > 0 && $this->getConfig()->getConfigParam( 'blShowVATForPayCharge' ) ) {
02169             return oxLang::getInstance()->formatCurrency( $dPayVAT, $this->getBasketCurrency() );
02170         }
02171         return false;
02172     }
02173 
02179     public function getPayCostNet()
02180     {
02181         // blShowVATForPayCharge option will be used, only for displaying, but not calculation
02182         if ( $this->getConfig()->getConfigParam( 'blShowVATForPayCharge' ) ) {
02183             $dNetPrice = $this->getCosts( 'oxpayment' )->getNettoPrice();
02184             if ($dNetPrice) {
02185                 return oxLang::getInstance()->formatCurrency( $dNetPrice, $this->getBasketCurrency() );
02186             }
02187         }
02188         return false;
02189     }
02190 
02196     public function getPaymentCosts()
02197     {
02198         return $this->getCosts( 'oxpayment' )->getBruttoPrice();
02199     }
02200 
02206     public function getFPaymentCosts()
02207     {
02208         $oPaymentCost = $this->getCosts( 'oxpayment' );
02209 
02210         if ( $oPaymentCost && $oPaymentCost->getBruttoPrice() ) {
02211             return oxLang::getInstance()->formatCurrency( $oPaymentCost->getBruttoPrice(), $this->getBasketCurrency() );
02212         }
02213         return false;
02214     }
02215 
02221     public function getVoucherDiscValue()
02222     {
02223         if ( $this->getVoucherDiscount() ) {
02224             return $this->getVoucherDiscount()->getBruttoPrice();
02225         }
02226         return false;
02227     }
02228 
02234     public function getFVoucherDiscountValue()
02235     {
02236         if ( $oVoucherDiscount = $this->getVoucherDiscount() ) {
02237             if ( $oVoucherDiscount->getBruttoPrice() ) {
02238                 return oxLang::getInstance()->formatCurrency( $oVoucherDiscount->getBruttoPrice(), $this->getBasketCurrency() );
02239             }
02240         }
02241         return false;
02242     }
02243 
02244 
02250     public function getWrappCostVatPercent()
02251     {
02252         return $this->getCosts( 'oxwrapping' )->getVat();
02253     }
02254 
02260     public function getWrappCostVat()
02261     {
02262         $dWrappVAT = $this->getCosts( 'oxwrapping' )->getVatValue();
02263         // blShowVATForWrapping option will be used, only for displaying, but not calculation
02264         if ( $dWrappVAT > 0 && $this->getConfig()->getConfigParam( 'blShowVATForWrapping' ) ) {
02265             return oxLang::getInstance()->formatCurrency( $dWrappVAT, $this->getBasketCurrency() );
02266         }
02267         return false;
02268 
02269     }
02270 
02276     public function getWrappCostNet()
02277     {
02278         $dWrappNet = $this->getCosts( 'oxwrapping' )->getNettoPrice();
02279         // blShowVATForWrapping option will be used, only for displaying, but not calculation
02280         if ( $dWrappNet > 0 && $this->getConfig()->getConfigParam( 'blShowVATForWrapping' ) ) {
02281             return  oxLang::getInstance()->formatCurrency( $dWrappNet, $this->getBasketCurrency() );
02282         }
02283         return false;
02284     }
02285 
02291     public function getFWrappingCosts()
02292     {
02293         $oWrappingCost = $this->getCosts( 'oxwrapping' );
02294         if ( $oWrappingCost && $oWrappingCost->getBruttoPrice() ) {
02295             return oxLang::getInstance()->formatCurrency( $oWrappingCost->getBruttoPrice(), $this->getBasketCurrency() );
02296         }
02297         return false;
02298     }
02299 
02305     public function getFPrice()
02306     {
02307         return oxLang::getInstance()->formatCurrency( $this->getPrice()->getBruttoPrice(), $this->getBasketCurrency() );
02308     }
02309 
02315     public function getFDeliveryCosts()
02316     {
02317         $oDeliveryCost = $this->getCosts( 'oxdelivery' );
02318         if ( $oDeliveryCost && ( $this->getBasketUser() || $this->getConfig()->getConfigParam( 'blCalculateDelCostIfNotLoggedIn' ) ) ) {
02319             return oxLang::getInstance()->formatCurrency( $oDeliveryCost->getBruttoPrice(), $this->getBasketCurrency() );
02320         }
02321         return false;
02322     }
02323 
02329     public function getDeliveryCosts()
02330     {
02331         if ( $oDeliveryCost = $this->getCosts( 'oxdelivery' ) ) {
02332             return $oDeliveryCost->getBruttoPrice();
02333         }
02334         return false;
02335     }
02336 
02344     public function setTotalDiscount( $dDiscount )
02345     {
02346         $this->_oTotalDiscount = oxNew( 'oxPrice' );
02347         $this->_oTotalDiscount->setBruttoPriceMode();
02348         $this->_oTotalDiscount->add( $dDiscount );
02349     }
02350 
02357     public function getPriceForPayment()
02358     {
02359         $dPrice = $this->getDiscountedProductsBruttoPrice();
02360         //#1905 not discounted products should be included in payment amount calculation
02361         if ( $oPriceList = $this->getNotDiscountProductsPrice() ) {
02362             $dPrice += $oPriceList->getBruttoSum();
02363         }
02364 
02365         // adding delivery price to final price
02366         if ( $oDeliveryPrice = $this->_aCosts['oxdelivery'] ) {
02367             $dPrice += $oDeliveryPrice->getBruttoPrice();
02368         }
02369 
02370         return $dPrice;
02371     }
02372 
02378     public function getDiscountedProductsBruttoPrice()
02379     {
02380         if ( $oProductsPrice = $this->getDiscountProductsPrice() ) {
02381             $dPrice = $oProductsPrice->getBruttoSum();
02382         }
02383 
02384         // substracting total discount
02385         if ( $oPrice = $this->getTotalDiscount() ) {
02386             $dPrice -= $oPrice->getBruttoPrice();
02387         }
02388 
02389         if ( $oVoucherPrice = $this->getVoucherDiscount() ) {
02390             $dPrice -= $oVoucherPrice->getBruttoPrice();
02391         }
02392 
02393         return $dPrice;
02394     }
02395 
02401     public function isBelowMinOrderPrice()
02402     {
02403         $blIsBelowMinOrderPrice = false;
02404         $sConfValue = $this->getConfig()->getConfigParam( 'iMinOrderPrice' );
02405         if ( is_numeric($sConfValue) && $this->getProductsCount() ) {
02406             $dMinOrderPrice = oxPrice::getPriceInActCurrency( ( int ) $sConfValue );
02407             $dNotDiscountedProductPrice = 0;
02408             if ( $oPrice = $this->getNotDiscountProductsPrice() ) {
02409                 $dNotDiscountedProductPrice = $oPrice->getBruttoSum();
02410             }
02411             $blIsBelowMinOrderPrice = ($dMinOrderPrice > ($this->getDiscountedProductsBruttoPrice() + $dNotDiscountedProductPrice));
02412         }
02413 
02414         return $blIsBelowMinOrderPrice;
02415 
02416     }
02417 
02426     public function getArtStockInBasket( $sArtId, $sExpiredArtId = null )
02427     {
02428         $dArtStock = 0;
02429         foreach ( $this->_aBasketContents as $sItemKey => $oOrderArticle ) {
02430             if ( $oOrderArticle && ( $sExpiredArtId == null || $sExpiredArtId != $sItemKey ) ) {
02431                 if ( $oOrderArticle->getArticle()->getId() == $sArtId ) {
02432                     $dArtStock += $oOrderArticle->getAmount();
02433                 }
02434             }
02435         }
02436 
02437         return $dArtStock;
02438     }
02439 
02447     public function canAddProductToBasket( $sProductId )
02448     {
02449         $blCanAdd = null;
02450 
02451         // if basket category is not set..
02452         if ( $this->_sBasketCategoryId === null ) {
02453             $oCat = null;
02454 
02455             // request category
02456             if ( $oView = $this->getConfig()->getActiveView() ) {
02457                 if ( $oCat = $oView->getActCategory() ) {
02458                     if ( !$this->_isProductInRootCategory( $sProductId, $oCat->oxcategories__oxrootid->value ) ) {
02459                         $oCat = null;
02460                     } else {
02461                         $blCanAdd = true;
02462                     }
02463                 }
02464             }
02465 
02466             // product main category
02467             if ( !$oCat ) {
02468                 $oProduct = oxNew( "oxarticle" );
02469                 if ( $oProduct->load( $sProductId ) ) {
02470                     $oCat = $oProduct->getCategory();
02471                 }
02472             }
02473 
02474             // root category id
02475             if ( $oCat ) {
02476                 $this->setBasketRootCatId($oCat->oxcategories__oxrootid->value);
02477             }
02478         }
02479 
02480         // avoiding double check..
02481         if ( $blCanAdd === null ) {
02482             $blCanAdd = $this->_sBasketCategoryId ? $this->_isProductInRootCategory( $sProductId, $this->getBasketRootCatId() ) : true;
02483         }
02484 
02485         return $blCanAdd;
02486     }
02487 
02496     protected function _isProductInRootCategory( $sProductId, $sRootCatId )
02497     {
02498         $sO2CTable = getViewName( 'oxobject2category' );
02499         $sCatTable = getViewName( 'oxcategories' );
02500 
02501         $oDb = oxDb::getDb();
02502         $sParentId  = $oDb->getOne( "select oxparentid from oxarticles where oxid = ".$oDb->quote( $sProductId ) );
02503         $sProductId = $sParentId ? $sParentId : $sProductId;
02504 
02505         $sQ = "select 1 from {$sO2CTable}
02506                  left join {$sCatTable} on {$sCatTable}.oxid = {$sO2CTable}.oxcatnid
02507                  where {$sO2CTable}.oxobjectid = ".$oDb->quote( $sProductId )." and
02508                        {$sCatTable}.oxrootid = ".$oDb->quote( $sRootCatId );
02509 
02510         return (bool) $oDb->getOne( $sQ );
02511     }
02512 
02520     public function setBasketRootCatId($sRoot)
02521     {
02522         $this->_sBasketCategoryId = $sRoot;
02523     }
02524 
02530     public function getBasketRootCatId()
02531     {
02532         return $this->_sBasketCategoryId;
02533     }
02534 
02542     public function setCatChangeWarningState( $blShow )
02543     {
02544         $this->_blShowCatChangeWarning = $blShow;
02545     }
02546 
02552     public function showCatChangeWarning()
02553     {
02554         return $this->_blShowCatChangeWarning;
02555     }
02556 
02564     public function setTsProductId( $sProductId )
02565     {
02566         $this->_sTsProductId = $sProductId;
02567     }
02568 
02574     public function getTsProductId()
02575     {
02576         return $this->_sTsProductId;
02577     }
02578 
02584     public function getFTsProtectionCosts()
02585     {
02586         $oProtectionCost = $this->getCosts( 'oxtsprotection' );
02587         if ( $oProtectionCost && $oProtectionCost->getBruttoPrice() ) {
02588             return oxLang::getInstance()->formatCurrency( $oProtectionCost->getBruttoPrice(), $this->getBasketCurrency() );
02589         }
02590         return false;
02591     }
02592 
02598     public function getTsProtectionVatPercent()
02599     {
02600         return $this->getCosts( 'oxtsprotection' )->getVat();
02601     }
02602 
02608     public function getTsProtectionVat()
02609     {
02610         $dProtectionVAT = $this->getCosts( 'oxtsprotection' )->getVatValue();
02611         // blShowVATForPayCharge option will be used, only for displaying, but not calculation
02612         if ( $dProtectionVAT > 0 && $this->getConfig()->getConfigParam( 'blShowVATForPayCharge' ) ) {
02613             return oxLang::getInstance()->formatCurrency( $dProtectionVAT, $this->getBasketCurrency() );
02614         }
02615         return false;
02616     }
02617 
02623     public function getTsProtectionNet()
02624     {
02625         // blShowVATForPayCharge option will be used, only for displaying, but not calculation
02626         if ( $this->getConfig()->getConfigParam( 'blShowVATForPayCharge' ) ) {
02627             return oxLang::getInstance()->formatCurrency( $this->getCosts( 'oxtsprotection' )->getNettoPrice(), $this->getBasketCurrency() );
02628         }
02629         return false;
02630     }
02631 
02637     public function getTsProtectionCosts()
02638     {
02639         $oProtection = $this->getCosts( 'oxtsprotection' );
02640         if ( $oProtection ) {
02641             return $oProtection->getBruttoPrice();
02642         }
02643         return false;
02644     }
02645 
02651     public function getNotDiscountProductsPrice()
02652     {
02653         return $this->_oNotDiscountedProductsPriceList;
02654     }
02655 
02669     protected function _addedNewItem( $sProductID, $dAmount, $aSel, $aPersParam, $blOverride, $blBundle, $sOldBasketItemId )
02670     {
02671         if ( !$blOverride ) {
02672             $this->_blNewITemAdded = null;
02673             oxSession::setVar( "blAddedNewItem", true );
02674         }
02675     }
02676 
02682     public function __wakeUp()
02683     {
02684         $this->_blNewITemAdded = null;
02685     }
02686 
02692     public function isNewItemAdded()
02693     {
02694         if ( $this->_blNewITemAdded == null ) {
02695             $this->_blNewITemAdded = (bool) oxSession::getVar( "blAddedNewItem" );
02696             oxSession::deleteVar( "blAddedNewItem" );
02697         }
02698         return $this->_blNewITemAdded;
02699     }
02700 
02706     public function hasDownloadableProducts()
02707     {
02708         $this->_blDownloadableProducts = false;
02709         foreach ( $this->_aBasketContents as $sItemKey => $oOrderArticle ) {
02710             if ( $oOrderArticle->getArticle()->isDownloadable() ) {
02711                 $this->_blDownloadableProducts = true;
02712                 break;
02713             }
02714         }
02715 
02716         return $this->_blDownloadableProducts;
02717     }
02718 
02719 }