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 
00235     public function isEnabled()
00236     {
00237         return !oxUtils::getInstance()->isSearchEngine();
00238     }
00239 
00249     protected function _changeBasketItemKey($sOldKey, $sNewKey, $value = null)
00250     {
00251         reset($this->_aBasketContents);
00252         $iOldKeyPlace = 0;
00253         while (key($this->_aBasketContents) != $sOldKey && next($this->_aBasketContents)) {
00254             ++$iOldKeyPlace;
00255         }
00256         $aNewCopy = array_merge(
00257             array_slice($this->_aBasketContents, 0, $iOldKeyPlace, true),
00258             array($sNewKey => $value),
00259             array_slice($this->_aBasketContents, $iOldKeyPlace+1, count($this->_aBasketContents)-$iOldKeyPlace, true)
00260         );
00261         $this->_aBasketContents = $aNewCopy;
00262     }
00263 
00279     public function addToBasket( $sProductID, $dAmount, $aSel = null, $aPersParam = null, $blOverride = false, $blBundle = false, $sOldBasketItemId = null )
00280     {
00281         // enabled ?
00282         if ( !$this->isEnabled() )
00283             return null;
00284 
00285         // basket exclude
00286         if ( $this->getConfig()->getConfigParam( 'blBasketExcludeEnabled' ) ) {
00287             if ( !$this->canAddProductToBasket( $sProductID ) ) {
00288                 $this->setCatChangeWarningState( true );
00289                 return null;
00290             } else {
00291                 $this->setCatChangeWarningState( false );
00292             }
00293         }
00294 
00295         $sItemId = $this->getItemKey( $sProductID, $aSel, $aPersParam, $blBundle );
00296         if ( $sOldBasketItemId && ( strcmp( $sOldBasketItemId, $sItemId ) != 0 ) ) {
00297             if ( isset( $this->_aBasketContents[$sItemId] ) ) {
00298                 // we are merging, so params will just go to the new key
00299                 unset( $this->_aBasketContents[$sOldBasketItemId] );
00300                 // do not override stock
00301                 $blOverride = false;
00302             } else {
00303                 // value is null - means isset will fail and real values will be filled
00304                 $this->_changeBasketItemKey( $sOldBasketItemId, $sItemId );
00305             }
00306         }
00307 
00308         // after some checks item must be removed from basket
00309         $blRemoveItem = false;
00310 
00311         // initialting exception storage
00312         $oEx = null;
00313 
00314         if ( isset( $this->_aBasketContents[$sItemId] ) ) {
00315 
00316             //updating existing
00317             try {
00318                 // setting stock check status
00319                 $this->_aBasketContents[$sItemId]->setStockCheckStatus( $this->getStockCheckMode() );
00320                 //validate amount
00321                 //possibly throws exception
00322                 $this->_aBasketContents[$sItemId]->setAmount( $dAmount, $blOverride, $sItemId );
00323             } catch( oxOutOfStockException $oEx ) {
00324                 // rethrow later
00325             }
00326 
00327         } else {
00328             //inserting new
00329             $oBasketItem = oxNew( 'oxbasketitem' );
00330             try {
00331                 $oBasketItem->setStockCheckStatus( $this->getStockCheckMode() );
00332                 $oBasketItem->init( $sProductID, $dAmount, $aSel, $aPersParam, $blBundle );
00333             } catch( oxNoArticleException $oEx ) {
00334                 // in this case that the article does not exist remove the item from the basket by setting its amount to 0
00335                 //$oBasketItem->dAmount = 0;
00336                 $blRemoveItem = true;
00337 
00338             } catch( oxOutOfStockException $oEx ) {
00339                 // rethrow later
00340             } catch ( oxArticleInputException $oEx ) {
00341                 // rethrow later
00342                 $blRemoveItem = true;
00343             }
00344 
00345             $this->_aBasketContents[$sItemId] = $oBasketItem;
00346         }
00347 
00348         //in case amount is 0 removing item
00349         if ( $this->_aBasketContents[$sItemId]->getAmount() == 0 || $blRemoveItem ) {
00350             $this->removeItem( $sItemId );
00351         } elseif ( $blBundle ) {
00352             //marking bundles
00353             $this->_aBasketContents[$sItemId]->setBundle( true );
00354         }
00355 
00356         //calling update method
00357         $this->onUpdate();
00358 
00359         if ( $oEx ) {
00360             throw $oEx;
00361         }
00362 
00363         // notifying that new basket item was added
00364         $this->_addedNewItem( $sProductID, $dAmount, $aSel, $aPersParam, $blOverride, $blBundle, $sOldBasketItemId );
00365 
00366         // returning basket item object
00367         return $this->_aBasketContents[$sItemId];
00368     }
00369 
00377     public function addOrderArticleToBasket( $oOrderArticle )
00378     {
00379         // adding only if amount > 0
00380         if ( $oOrderArticle->oxorderarticles__oxamount->value > 0 && !$oOrderArticle->isBundle() ) {
00381             $sItemId = $oOrderArticle->getId();
00382 
00383             //inserting new
00384             $this->_aBasketContents[$sItemId] = oxNew( 'oxbasketitem' );
00385             $this->_aBasketContents[$sItemId]->initFromOrderArticle( $oOrderArticle );
00386             $this->_aBasketContents[$sItemId]->setWrapping( $oOrderArticle->oxorderarticles__oxwrapid->value );
00387             $this->_aBasketContents[$sItemId]->setBundle( $oOrderArticle->isBundle() );
00388 
00389             //calling update method
00390             $this->onUpdate();
00391 
00392             return $this->_aBasketContents[$sItemId];
00393         } elseif ( $oOrderArticle->isBundle() ) {
00394             // deleting bundles, they are handled automatically
00395             $oOrderArticle->delete();
00396         }
00397     }
00398 
00406     public function setStockCheckMode( $blCheck )
00407     {
00408         $this->_blCheckStock = $blCheck;
00409     }
00410 
00416     public function getStockCheckMode()
00417     {
00418         return $this->_blCheckStock;
00419     }
00420 
00433     public function getItemKey( $sProductId, $aSel = null, $aPersParam = null, $blBundle = false, $sAdditionalParam = '' )
00434     {
00435         $aSel = ( $aSel != null) ? $aSel : array (0=>'0');
00436 
00437         $sItemKey = md5( $sProductId.'|'.serialize( $aSel ).'|'.serialize( $aPersParam ).'|'.( int ) $blBundle . '|' . serialize( $sAdditionalParam ) );
00438 
00439         return $sItemKey;
00440     }
00441 
00442 
00450     public function removeItem( $sItemKey )
00451     {
00452         if ($this->getConfig()->getConfigParam( 'blPsBasketReservationEnabled' )) {
00453             if (isset($this->_aBasketContents[$sItemKey])) {
00454                 $sArticleId = $this->_aBasketContents[$sItemKey]->getProductId();
00455                 if ($sArticleId) {
00456                     $this->getSession()
00457                             ->getBasketReservations()
00458                             ->discardArticleReservation($sArticleId);
00459                 }
00460             }
00461         }
00462         unset( $this->_aBasketContents[$sItemKey] );
00463 
00464         // basket exclude
00465         if ( !count($this->_aBasketContents) && $this->getConfig()->getConfigParam( 'blBasketExcludeEnabled' ) ) {
00466             $this->setBasketRootCatId(null);
00467         }
00468     }
00469 
00475     protected function _clearBundles()
00476     {
00477         reset( $this->_aBasketContents );
00478         while ( list( $sItemKey, $oBasketItem ) = each( $this->_aBasketContents ) ) {
00479             if ( $oBasketItem->isBundle() ) {
00480                 $this->removeItem( $sItemKey );
00481             }
00482         }
00483     }
00484 
00492     protected function _getArticleBundles( $oBasketItem )
00493     {
00494         $aBundles = array();
00495 
00496         if ( $oBasketItem->isBundle() ) {
00497             return $aBundles;
00498         }
00499 
00500         $oArticle = $oBasketItem->getArticle();
00501         if ( $oArticle && $oArticle->oxarticles__oxbundleid->value ) {
00502             $aBundles[$oArticle->oxarticles__oxbundleid->value] = 1;
00503         }
00504 
00505         return $aBundles;
00506     }
00507 
00516     protected function _getItemBundles( $oBasketItem, $aBundles = array() )
00517     {
00518         if ( $oBasketItem->isBundle() ) {
00519             return array();
00520         }
00521 
00522         // does this object still exists ?
00523         if ( $oArticle = $oBasketItem->getArticle() ) {
00524             $aDiscounts = oxDiscountList::getInstance()->getBasketItemBundleDiscounts( $oArticle, $this, $this->getBasketUser() );
00525 
00526             foreach ( $aDiscounts as $oDiscount ) {
00527 
00528                 $iAmnt = $oDiscount->getBundleAmount( $oBasketItem->getAmount() );
00529                 if ( $iAmnt ) {
00530                     //init array element
00531                     if ( !isset( $aBundles[$oDiscount->oxdiscount__oxitmartid->value] ) ) {
00532                         $aBundles[$oDiscount->oxdiscount__oxitmartid->value] = 0;
00533                     }
00534 
00535                     if ($oDiscount->oxdiscount__oxitmmultiple->value) {
00536                         $aBundles[$oDiscount->oxdiscount__oxitmartid->value] += $iAmnt;
00537                     } else {
00538                         $aBundles[$oDiscount->oxdiscount__oxitmartid->value] = $iAmnt;
00539                     }
00540                 }
00541             }
00542         }
00543 
00544         return $aBundles;
00545     }
00546 
00554     protected function _getBasketBundles( $aBundles = array() )
00555     {
00556         $aDiscounts = oxDiscountList::getInstance()->getBasketBundleDiscounts( $this, $this->getBasketUser() );
00557 
00558         // calculating amount of non bundled/discount items
00559         $dAmount = 0;
00560         foreach ( $this->_aBasketContents as $oBasketItem ) {
00561             if ( !( $oBasketItem->isBundle() || $oBasketItem->isDiscountArticle() ) ) {
00562                 $dAmount += $oBasketItem->getAmount();
00563             }
00564         }
00565 
00566         foreach ( $aDiscounts as $oDiscount ) {
00567             if ($oDiscount->oxdiscount__oxitmartid->value) {
00568                 if ( !isset( $aBundles[$oDiscount->oxdiscount__oxitmartid->value] ) ) {
00569                     $aBundles[$oDiscount->oxdiscount__oxitmartid->value] = 0;
00570                 }
00571 
00572                 $aBundles[$oDiscount->oxdiscount__oxitmartid->value] += $oDiscount->getBundleAmount( $dAmount );
00573             }
00574         }
00575 
00576         return $aBundles;
00577     }
00578 
00585     protected function _addBundles()
00586     {
00587         $aBundles = array();
00588         // iterating through articles and binding bundles
00589         foreach ( $this->_aBasketContents as $key => $oBasketItem ) {
00590             try {
00591                 // adding discount type bundles
00592                 if ( !$oBasketItem->isDiscountArticle() && !$oBasketItem->isBundle() ) {
00593                     $aBundles = $this->_getItemBundles( $oBasketItem, $aBundles );
00594                 } else {
00595                     continue;
00596                 }
00597 
00598                     // adding item type bundles
00599                     $aArtBundles = $this->_getArticleBundles( $oBasketItem );
00600 
00601                     // adding bundles to basket
00602                     $this->_addBundlesToBasket( $aArtBundles );
00603             } catch ( oxNoArticleException $oEx ) {
00604                 $this->removeItem( $key );
00605                 oxUtilsView::getInstance()->addErrorToDisplay( $oEx );
00606             } catch( oxArticleInputException $oEx ) {
00607                 $this->removeItem( $key );
00608                 oxUtilsView::getInstance()->addErrorToDisplay( $oEx );
00609             }
00610         }
00611 
00612         // adding global basket bundles
00613         $aBundles = $this->_getBasketBundles( $aBundles );
00614 
00615         // adding all bundles to basket
00616         if ( $aBundles ) {
00617             $this->_addBundlesToBasket( $aBundles );
00618         }
00619     }
00620 
00628     protected function _addBundlesToBasket( $aBundles )
00629     {
00630         foreach ( $aBundles as $sBundleId => $dAmount ) {
00631             if ( $dAmount ) {
00632                 try {
00633                     if ( $oBundleItem = $this->addToBasket( $sBundleId, $dAmount, null, null, false, true ) ) {
00634                         $oBundleItem->setAsDiscountArticle( true );
00635                     }
00636                 } catch(oxArticleException $oEx) {
00637                     // caught and ignored
00638                 }
00639             }
00640         }
00641 
00642     }
00643 
00649     protected function _calcItemsPrice()
00650     {
00651         // resetting
00652         $this->setSkipDiscounts( false );
00653         $this->_iProductsCnt = 0; // count different types
00654         $this->_dItemsCnt    = 0; // count of item units
00655         $this->_dWeight      = 0; // basket weight
00656 
00657         // resetting
00658         $this->_aItemDiscounts = array();
00659 
00660         $this->_oProductsPriceList = oxNew( 'oxpricelist' );
00661         $this->_oDiscountProductsPriceList = oxNew( 'oxpricelist' );
00662         $this->_oNotDiscountedProductsPriceList = oxNew( 'oxpricelist' );
00663 
00664         $oDiscountList = oxDiscountList::getInstance();
00665 
00666         foreach ( $this->_aBasketContents as $oBasketItem ) {
00667             $this->_iProductsCnt++;
00668             $this->_dItemsCnt += $oBasketItem->getAmount();
00669             $this->_dWeight   += $oBasketItem->getWeight();
00670 
00671             if ( !$oBasketItem->isDiscountArticle() && ( $oArticle = $oBasketItem->getArticle() ) ) {
00672                 $oBasketPrice = $oArticle->getBasketPrice( $oBasketItem->getAmount(), $oBasketItem->getSelList(), $this );
00673                 $oBasketItem->setPrice( $oBasketPrice );
00674                 //P adding product price
00675                 $this->_oProductsPriceList->addToPriceList( $oBasketItem->getPrice() );
00676 
00677                 $oBasketPrice->setBruttoPriceMode();
00678                 if ( !$oArticle->skipDiscounts() && $this->canCalcDiscounts() ) {
00679                     // apply basket type discounts
00680                     //#3857 added clone in order not to influence the price
00681                     $aItemDiscounts = $oDiscountList->applyBasketDiscounts( clone $oBasketPrice, $oDiscountList->getBasketItemDiscounts( $oArticle, $this, $this->getBasketUser() ), $oBasketItem->getAmount() );
00682 
00683                     if ( is_array($this->_aItemDiscounts) && is_array($aItemDiscounts) ) {
00684                         $this->_aItemDiscounts = $this->_mergeDiscounts( $this->_aItemDiscounts, $aItemDiscounts);
00685                     }
00686                 } else {
00687                     $oBasketItem->setSkipDiscounts( true );
00688                     $this->setSkipDiscounts( true );
00689                 }
00690                 $oBasketPrice->multiply( $oBasketItem->getAmount() );
00691 
00692                 //P collect discount values for basket items which are discountable
00693                 if ( !$oArticle->skipDiscounts() ) {
00694                     $this->_oDiscountProductsPriceList->addToPriceList( $oBasketPrice );
00695                 } else {
00696                     $this->_oNotDiscountedProductsPriceList->addToPriceList( $oBasketPrice );
00697                     $oBasketItem->setSkipDiscounts( true );
00698                     $this->setSkipDiscounts( true );
00699                 }
00700             } elseif ( $oBasketItem->isBundle() ) {
00701                 // if bundles price is set to zero
00702                 $oPrice = oxNew( "oxprice");
00703                 $oBasketItem->setPrice( $oPrice );
00704             }
00705         }
00706     }
00707 
00715     public function setDiscountCalcMode( $blCalcDiscounts )
00716     {
00717         $this->_blCalcDiscounts = $blCalcDiscounts;
00718     }
00719 
00725     public function canCalcDiscounts()
00726     {
00727         return $this->_blCalcDiscounts;
00728     }
00729 
00739     protected function _mergeDiscounts( $aDiscounts, $aItemDiscounts)
00740     {
00741         foreach ( $aItemDiscounts as $sKey => $oDiscount ) {
00742             // add prices of the same discounts
00743             if ( array_key_exists ($sKey, $aDiscounts) ) {
00744                 $aDiscounts[$sKey]->dDiscount += $oDiscount->dDiscount;
00745             } else {
00746                 $aDiscounts[$sKey] = $oDiscount;
00747             }
00748         }
00749         return $aDiscounts;
00750     }
00751 
00757     protected function _calcDeliveryCost()
00758     {
00759         if ( $this->_oDeliveryPrice !== null ) {
00760             return $this->_oDeliveryPrice;
00761         }
00762         $myConfig  = $this->getConfig();
00763         $oDeliveryPrice = oxNew( 'oxprice' );
00764         $oDeliveryPrice->setBruttoPriceMode();
00765 
00766         // don't calculate if not logged in
00767         $oUser = $this->getBasketUser();
00768 
00769         if ( !$oUser && !$myConfig->getConfigParam( 'blCalculateDelCostIfNotLoggedIn' ) ) {
00770             return $oDeliveryPrice;
00771         }
00772 
00773         // VAT for delivery ?
00774         $fDelVATPercent = 0;
00775         if ( $myConfig->getConfigParam( 'blCalcVATForDelivery' ) ) {
00776             $fDelVATPercent = $this->getMostUsedVatPercent();
00777             $oDeliveryPrice->setVat( $fDelVATPercent );
00778         }
00779 
00780         // list of active delivery costs
00781         if ( $myConfig->getConfigParam('bl_perfLoadDelivery') ) {
00782             $aDeliveryList = oxDeliveryList::getInstance()->getDeliveryList( $this,
00783                                         $oUser,
00784                                         $this->_findDelivCountry(),
00785                                         $this->getShippingId()
00786                                     );
00787 
00788             if ( count( $aDeliveryList ) > 0 ) {
00789                 foreach ( $aDeliveryList as $oDelivery ) {
00790                     //debug trace
00791                     if ( $myConfig->getConfigParam( 'iDebug' ) == 5 ) {
00792                         echo( "DelCost : ".$oDelivery->oxdelivery__oxtitle->value."<br>" );
00793                     }
00794                     $oDeliveryPrice->addPrice( $oDelivery->getDeliveryPrice( $fDelVATPercent ) );
00795                 }
00796             }
00797         }
00798 
00799         return $oDeliveryPrice;
00800     }
00801 
00807     public function getBasketUser()
00808     {
00809         if ( $this->_oUser == null ) {
00810             return $this->getUser();
00811         }
00812 
00813         return $this->_oUser;
00814     }
00815 
00823     public function setBasketUser( $oUser )
00824     {
00825         $this->_oUser = $oUser;
00826     }
00827 
00828     //P
00834     public function getMostUsedVatPercent()
00835     {
00836         return $this->_oProductsPriceList->getMostUsedVatPercent();
00837     }
00838 
00839     //P
00846     protected function _calcTotalPrice()
00847     {
00848         // 1. add products price
00849         $dprice = $this->_oProductsPriceList->getBruttoSum();
00850         $this->_oPrice->setPrice( $dprice );
00851 
00852         // 2. substract discounts
00853         if ( $dprice ) {
00854 
00855             /*
00856             //#3857 this section is not needed as $this->_aItemDiscounts is part of $this->_aDiscounts
00857             // 2.1 applying basket item discounts
00858             foreach ( $this->_aItemDiscounts as $oDiscount ) {
00859 
00860                 // skipping bundle discounts
00861                 if ( $oDiscount->sType == 'itm' ) {
00862                     continue;
00863                 }
00864                 $this->_oPrice->subtract( $oDiscount->dDiscount );
00865             }*/
00866 
00867             // 2.2 applying basket discounts
00868             $this->_oPrice->subtract( $this->_oTotalDiscount->getBruttoPrice() );
00869 
00870             // 2.3 applying voucher discounts
00871             if ($oVoucherDisc = $this->getVoucherDiscount()) {
00872                 $this->_oPrice->subtract( $oVoucherDisc->getBruttoPrice() );
00873             }
00874         }
00875 
00876         // 2.3 add delivery cost
00877         if ( isset( $this->_aCosts['oxdelivery'] ) ) {
00878             $this->_oPrice->add( $this->_aCosts['oxdelivery']->getBruttoPrice() );
00879         }
00880 
00881         // 2.4 add wrapping price
00882         if ( isset( $this->_aCosts['oxwrapping'] ) ) {
00883             $this->_oPrice->add( $this->_aCosts['oxwrapping']->getBruttoPrice() );
00884         }
00885 
00886         // 2.5 add payment price
00887         if ( isset( $this->_aCosts['oxpayment'] ) ) {
00888             $this->_oPrice->add( $this->_aCosts['oxpayment']->getBruttoPrice() );
00889         }
00890 
00891         // 2.6 add TS protection price
00892         if ( isset( $this->_aCosts['oxtsprotection'] ) ) {
00893             $this->_oPrice->add( $this->_aCosts['oxtsprotection']->getBruttoPrice() );
00894         }
00895 
00896     }
00897 
00905     public function setVoucherDiscount( $dDiscount )
00906     {
00907         $this->_oVoucherDiscount = oxNew( 'oxPrice' );
00908         $this->_oVoucherDiscount->setBruttoPriceMode();
00909         $this->_oVoucherDiscount->add( $dDiscount );
00910     }
00911 
00917     protected function _calcVoucherDiscount()
00918     {
00919         if ( $this->getConfig()->getConfigParam( 'bl_showVouchers' ) && ($this->_oVoucherDiscount === null || ( $this->_blUpdateNeeded && !$this->isAdmin() ) ) ) {
00920 
00921             $this->_oVoucherDiscount = oxNew( 'oxPrice' );
00922             $this->_oVoucherDiscount->setBruttoPriceMode();
00923 
00924 
00925             // calculating price to apply discount
00926             $dPrice = $this->_oDiscountProductsPriceList->getBruttoSum() - $this->_oTotalDiscount->getBruttoPrice();
00927 
00928             // recalculating
00929             if ( count( $this->_aVouchers ) ) {
00930                 $oLang = oxLang::getInstance();
00931                 foreach ( $this->_aVouchers as $sVoucherId => $oStdVoucher ) {
00932                     $oVoucher = oxNew( 'oxvoucher' );
00933                     try { // checking
00934                         $oVoucher->load( $oStdVoucher->sVoucherId );
00935 
00936                         if ( !$this->_blSkipVouchersAvailabilityChecking ) {
00937                             $oVoucher->checkBasketVoucherAvailability( $this->_aVouchers, $dPrice );
00938                             $oVoucher->checkUserAvailability( $this->getBasketUser() );
00939                         }
00940 
00941                         // assigning real voucher discount value as this is the only place where real value is calculated
00942                         $dVoucherdiscount = $oVoucher->getDiscountValue( $dPrice );
00943 
00944                         // acumulating discount value
00945                         $this->_oVoucherDiscount->add( $dVoucherdiscount );
00946 
00947                         // collecting formatted for preview
00948                         $oStdVoucher->fVoucherdiscount = $oLang->formatCurrency( $dVoucherdiscount, $this->getBasketCurrency() );
00949                         $oStdVoucher->dVoucherdiscount = $dVoucherdiscount;
00950 
00951                         // substracting voucher discount
00952                         $dPrice -= $dVoucherdiscount;
00953                     } catch ( oxVoucherException $oEx ) {
00954 
00955                         // removing voucher on error
00956                         $oVoucher->unMarkAsReserved();
00957                         unset( $this->_aVouchers[$sVoucherId] );
00958 
00959                         // storing voucher error info
00960                         oxUtilsView::getInstance()->addErrorToDisplay($oEx, false, true);
00961                     }
00962                 }
00963             }
00964         }
00965     }
00966 
00967     //V
00974     protected function _applyDiscounts()
00975     {
00976         $dBruttoPrice = 0;
00977         $this->_aDiscountedVats = array();
00978         if ( $oPriceList = $this->getDiscountProductsPrice() ) {
00979             $dBruttoPrice = $oPriceList->getBruttoSum();
00980             $this->_aDiscountedVats = $oPriceList->getVatInfo();
00981         }
00982 
00983         //apply discounts for brutto price
00984         $dDiscountedBruttoPrice = $this->getDiscountedProductsBruttoPrice();
00985         $oTotalDiscount   = $this->getTotalDiscount();
00986         $oVoucherDiscount = $this->getVoucherDiscount();
00987 
00988         //apply discount for VATs
00989         if ( $dBruttoPrice &&
00990              ( ( $oTotalDiscount && $oTotalDiscount->getBruttoPrice() ) ||
00991                ( $oVoucherDiscount && $oVoucherDiscount->getBruttoPrice() )
00992              )
00993            ) {
00994             $dPercent = ( $dDiscountedBruttoPrice / $dBruttoPrice) * 100;
00995             foreach ( $this->_aDiscountedVats as $sKey => $dVat ) {
00996                 $this->_aDiscountedVats[$sKey] = oxPrice::percent( $dVat, $dPercent);
00997             }
00998         }
00999 
01000         $oUtils = oxUtils::getInstance();
01001         $dDiscVatSum = 0;
01002         foreach ( $this->_aDiscountedVats as $dVat ) {
01003             $dDiscVatSum += $oUtils->fRound( -$dVat, $this->_oCurrency);
01004         }
01005         //calculate netto price with discounts
01006         $this->_dDiscountedProductNettoPrice = $dDiscountedBruttoPrice + $dDiscVatSum;
01007     }
01008 
01014     protected function _calcBasketDiscount()
01015     {
01016         // resetting
01017         $this->_aDiscounts = array();
01018 
01019         // P using prices sum which has discount, not sum of skipped discounts
01020         $dOldprice = $this->_oDiscountProductsPriceList->getBruttoSum();
01021 
01022         // add basket discounts
01023         $aDiscounts = oxDiscountList::getInstance()->getBasketDiscounts( $this, $this->getBasketUser() );
01024 
01025         foreach ( $aDiscounts as $oDiscount ) {
01026 
01027             // storing applied discounts
01028             $oStdDiscount = $oDiscount->getSimpleDiscount();
01029 
01030             // skipping bundle discounts
01031             if ( $oDiscount->oxdiscount__oxaddsumtype->value == 'itm' ) {
01032                 continue;
01033             }
01034 
01035             // saving discount info
01036             $oStdDiscount->dDiscount = $oDiscount->getAbsValue( $dOldprice );
01037             if ($dOldprice < $oStdDiscount->dDiscount) {
01038                 $oStdDiscount->dDiscount = $dOldprice;
01039             }
01040 
01041             if ($oStdDiscount->dDiscount != 0) {
01042                 $this->_aDiscounts[$oDiscount->getId()] = $oStdDiscount;
01043                 // substracting product price after discount
01044                 $dOldprice = $dOldprice - $oStdDiscount->dDiscount;
01045             }
01046         }
01047     }
01048 
01054     protected function _calcBasketTotalDiscount()
01055     {
01056         if ( $this->_oTotalDiscount === null || ( $this->_blUpdateNeeded && !$this->isAdmin() ) ) {
01057             $this->_oTotalDiscount = oxNew( 'oxPrice' );
01058             $this->_oTotalDiscount->setBruttoPriceMode();
01059 
01060             //#3857 merging item discounts to aDiscounts and later to oTotalDiscount
01061             $this->_aDiscounts = array_merge($this->_aItemDiscounts, $this->_aDiscounts);
01062 
01063             if ( is_array($this->_aDiscounts) ) {
01064                 foreach ( $this->_aDiscounts as $oDiscount ) {
01065 
01066                     // skipping bundle discounts
01067                     if ( $oDiscount->sType == 'itm' ) {
01068                         continue;
01069                     }
01070 
01071                     // add discount value to total basket discount
01072                     $this->_oTotalDiscount->add( $oDiscount->dDiscount );
01073                 }
01074             }
01075         }
01076     }
01077 
01087     protected function _calcBasketWrapping()
01088     {
01089         $myConfig = $this->getConfig();
01090         $oWrappingPrice = oxNew( 'oxPrice' );
01091         $oWrappingPrice->setBruttoPriceMode();
01092 
01093         // wrapping VAT
01094         if ( $myConfig->getConfigParam( 'blCalcVatForWrapping' ) ) {
01095             $oWrappingPrice->setVat( $this->getMostUsedVatPercent() );
01096         }
01097 
01098         // calculating basket items wrapping
01099         foreach ( $this->_aBasketContents as $oBasketItem ) {
01100 
01101             if ( ( $oWrapping = $oBasketItem->getWrapping() ) ) {
01102                 $oWrapPrice = $oWrapping->getWrappingPrice( $oBasketItem->getAmount() );
01103                 $oWrappingPrice->add( $oWrapPrice->getBruttoPrice() );
01104             }
01105         }
01106 
01107         // gift card price calculation
01108         if ( ( $oCard = $this->getCard() ) ) {
01109             $oCardPrice = $oCard->getWrappingPrice();
01110             $oWrappingPrice->add( $oCardPrice->getBruttoPrice() );
01111         }
01112 
01113         return $oWrappingPrice;
01114     }
01115 
01122     protected function _calcPaymentCost()
01123     {
01124         // resetting values
01125         $oPaymentPrice = oxNew( 'oxPrice' );
01126         $oPaymentPrice->setBruttoPriceMode();
01127 
01128         // payment
01129         if ( ( $this->_sPaymentId = $this->getPaymentId() ) ) {
01130 
01131             $oPayment = oxNew( 'oxpayment' );
01132             $oPayment->load( $this->_sPaymentId );
01133 
01134             $oPaymentPrice = $oPayment->getPaymentPrice( $this );
01135         }
01136 
01137         return $oPaymentPrice;
01138     }
01139 
01146     protected function _calcTsProtectionCost()
01147     {
01148         // resetting values
01149         $oProtectionPrice = oxNew( 'oxPrice' );
01150         $oProtectionPrice->setBruttoPriceMode();
01151 
01152         // payment
01153         if ( ( $this->_sTsProductId = $this->getTsProductId() ) ) {
01154 
01155             $oTsProtection = oxNew('oxtsprotection');
01156             $oTsProduct = $oTsProtection->getTsProduct( $this->_sTsProductId );
01157 
01158             $oProtectionPrice = $oTsProduct->getPrice();
01159         }
01160         return $oProtectionPrice;
01161     }
01162 
01171     public function setCost( $sCostName, $oPrice = null )
01172     {
01173         $this->_aCosts[$sCostName] = $oPrice;
01174     }
01175 
01184     public function calculateBasket( $blForceUpdate = false )
01185     {
01186         if ( !$this->isEnabled() ) {
01187             return;
01188         }
01189 
01190         if ( !$this->_blUpdateNeeded && !$blForceUpdate ) {
01191             return;
01192         }
01193 
01194         $this->_aCosts = array();
01195 
01196         $this->_oPrice = oxNew( 'oxprice' );
01197         $this->_oPrice->setBruttoPriceMode();
01198 
01199         //  1. saving basket to the database
01200         $this->_save();
01201 
01202         //  2. remove all bundles
01203         $this->_clearBundles();
01204 
01205         //  3. generate bundle items
01206         $this->_addBundles();
01207 
01208         // reserve active basket
01209         if ($this->getConfig()->getConfigParam( 'blPsBasketReservationEnabled' )) {
01210             $this->getSession()->getBasketReservations()->reserveBasket($this);
01211         }
01212 
01213         //  4. calculating item prices
01214         $this->_calcItemsPrice();
01215 
01216         //  5. calculating/applying discounts
01217         $this->_calcBasketDiscount();
01218 
01219         //  6. calculating basket total discount
01220         $this->_calcBasketTotalDiscount();
01221 
01222         //  7. check for vouchers
01223         $this->_calcVoucherDiscount();
01224 
01225         //  8. applies all discounts to pricelist
01226         $this->_applyDiscounts();
01227 
01228         //  9. calculating additional costs:
01229         //  9.1: delivery
01230         $this->setCost( 'oxdelivery', $this->_calcDeliveryCost() );
01231 
01232         //  9.2: adding wrapping costs
01233         $this->setCost( 'oxwrapping', $this->_calcBasketWrapping() );
01234 
01235         //  9.3: adding payment cost
01236         $this->setCost( 'oxpayment', $this->_calcPaymentCost() );
01237 
01238         //  9.4: adding TS protection cost
01239         $this->setCost( 'oxtsprotection', $this->_calcTsProtectionCost() );
01240 
01241         //  10. calculate total price
01242         $this->_calcTotalPrice();
01243 
01244         //  11. setting deprecated values
01245         $this->_setDeprecatedValues();
01246 
01247         //  12.setting to up-to-date status
01248         $this->afterUpdate();
01249     }
01250 
01256     public function onUpdate()
01257     {
01258         $this->_blUpdateNeeded = true;
01259     }
01260 
01266     public function afterUpdate()
01267     {
01268         $this->_blUpdateNeeded = false;
01269     }
01270 
01278     public function getBasketSummary()
01279     {
01280         if ( $this->_blUpdateNeeded || $this->_aBasketSummary === null ) {
01281             $this->_aBasketSummary = new Oxstdclass();
01282             $this->_aBasketSummary->aArticles = array();
01283             $this->_aBasketSummary->aCategories = array();
01284             $this->_aBasketSummary->iArticleCount = 0;
01285             $this->_aBasketSummary->dArticlePrice = 0;
01286             $this->_aBasketSummary->dArticleDiscountablePrice = 0;
01287         }
01288 
01289         if ( !$this->isEnabled() ) {
01290             return $this->_aBasketSummary;
01291         }
01292 
01293         $myConfig = $this->getConfig();
01294         foreach ( $this->_aBasketContents as $oBasketItem ) {
01295             if ( !$oBasketItem->isBundle() && $oArticle = $oBasketItem->getArticle(false) ) {
01296                 $aCatIds = $oArticle->getCategoryIds();
01297                 //#M530 if price is not loaded for articles
01298                 $dPrice = 0;
01299                 $dDiscountablePrice = 0;
01300                 if ( ( $oPrice = $oArticle->getPrice( $oBasketItem->getAmount() ) ) ) {
01301                     $dPrice = $oPrice->getBruttoPrice();
01302                     if ( !$oArticle->skipDiscounts() ) {
01303                         $dDiscountablePrice = $dPrice;
01304                     }
01305                 }
01306 
01307                 foreach ( $aCatIds as $sCatId ) {
01308                     if ( !isset( $this->_aBasketSummary->aCategories[$sCatId] ) ) {
01309                         $this->_aBasketSummary->aCategories[$sCatId] = new Oxstdclass();
01310                     }
01311 
01312                     $this->_aBasketSummary->aCategories[$sCatId]->dPrice  += $dPrice * $oBasketItem->getAmount();
01313                     $this->_aBasketSummary->aCategories[$sCatId]->dDiscountablePrice += $dDiscountablePrice * $oBasketItem->getAmount();
01314                     $this->_aBasketSummary->aCategories[$sCatId]->dAmount += $oBasketItem->getAmount();
01315                     $this->_aBasketSummary->aCategories[$sCatId]->iCount++;
01316                 }
01317 
01318                 // variant handling
01319                 if ( ($sParentId = $oArticle->getProductParentId()) && $myConfig->getConfigParam( 'blVariantParentBuyable' ) ) {
01320                     if ( !isset( $this->_aBasketSummary->aArticles[$sParentId] ) ) {
01321                         $this->_aBasketSummary->aArticles[$sParentId] = 0;
01322                     }
01323                     $this->_aBasketSummary->aArticles[$sParentId] += $oBasketItem->getAmount();
01324                 }
01325 
01326                 if ( !isset( $this->_aBasketSummary->aArticles[$oBasketItem->getProductId()] ) ) {
01327                     $this->_aBasketSummary->aArticles[$oBasketItem->getProductId()] = 0;
01328                 }
01329 
01330                 $this->_aBasketSummary->aArticles[$oBasketItem->getProductId()] += $oBasketItem->getAmount();
01331                 $this->_aBasketSummary->iArticleCount += $oBasketItem->getAmount();
01332                 $this->_aBasketSummary->dArticlePrice += $dPrice * $oBasketItem->getAmount();
01333                 $this->_aBasketSummary->dArticleDiscountablePrice += $dDiscountablePrice * $oBasketItem->getAmount();
01334             }
01335         }
01336         return $this->_aBasketSummary;
01337     }
01338 
01350     public function addVoucher( $sVoucherId )
01351     {
01352         // calculating price to check
01353         // P using prices sum which has discount, not sum of skipped discounts
01354         $dPrice = 0;
01355         if ( $this->_oDiscountProductsPriceList ) {
01356             $dPrice = $this->_oDiscountProductsPriceList->getBruttoSum();
01357         }
01358 
01359         try { // trying to load voucher and apply it
01360 
01361             $oVoucher = oxNew( 'oxvoucher' );
01362 
01363             if ( !$this->_blSkipVouchersAvailabilityChecking ) {
01364                 $oVoucher->getVoucherByNr( $sVoucherId, $this->_aVouchers, true );
01365                 $oVoucher->checkVoucherAvailability( $this->_aVouchers, $dPrice );
01366                 $oVoucher->checkUserAvailability( $this->getBasketUser() );
01367                 $oVoucher->markAsReserved();
01368             } else {
01369                 $oVoucher->load( $sVoucherId );
01370             }
01371 
01372             // saving voucher info
01373             $this->_aVouchers[$oVoucher->oxvouchers__oxid->value] = $oVoucher->getSimpleVoucher();
01374         } catch ( oxVoucherException $oEx ) {
01375 
01376             // problems adding voucher
01377             oxUtilsView::getInstance()->addErrorToDisplay( $oEx, false, true );
01378         }
01379 
01380         $this->onUpdate();
01381     }
01382 
01390     public function removeVoucher( $sVoucherId )
01391     {
01392         // removing if it exists
01393         if ( isset( $this->_aVouchers[$sVoucherId] ) ) {
01394 
01395             $oVoucher = oxNew( 'oxvoucher' );
01396             $oVoucher->load( $sVoucherId );
01397 
01398             $oVoucher->unMarkAsReserved();
01399 
01400             // unsetting it if exists this voucher in DB or not
01401             unset( $this->_aVouchers[$sVoucherId] );
01402             $this->onUpdate();
01403         }
01404 
01405     }
01406 
01412     public function resetUserInfo()
01413     {
01414         $this->setPayment( null );
01415         $this->setShipping( null );
01416     }
01417 
01425     protected function _setDeprecatedValues()
01426     {
01427         // discount information
01428         // formating discount value
01429         $this->aDiscounts = $this->getDiscounts();
01430         if ( count($this->aDiscounts) > 0 ) {
01431             $oLang = oxLang::getInstance();
01432             foreach ($this->aDiscounts as $oDiscount) {
01433                 $oDiscount->fDiscount = $oLang->formatCurrency( $oDiscount->dDiscount, $this->getBasketCurrency() );
01434             }
01435         }
01436     }
01437 
01438 
01444     protected function _canSaveBasket()
01445     {
01446         $blCanSave = !$this->getConfig()->getConfigParam( 'blPerfNoBasketSaving' );
01447         return $blCanSave;
01448     }
01449 
01455     public function load()
01456     {
01457         $oUser = $this->getBasketUser();
01458         if ( !$oUser ) {
01459             return;
01460         }
01461 
01462         $oBasket = $oUser->getBasket( 'savedbasket' );
01463 
01464         // restoring from saved history
01465         $aSavedItems = $oBasket->getItems();
01466         foreach ( $aSavedItems as $oItem ) {
01467             try {
01468                 $oSelList = $oItem->getSelList();
01469 
01470                 $this->addToBasket( $oItem->oxuserbasketitems__oxartid->value, $oItem->oxuserbasketitems__oxamount->value, $oSelList, $oItem->getPersParams(), true );
01471             } catch( oxArticleException $oEx ) {
01472                 // caught and ignored
01473             }
01474         }
01475     }
01476 
01482     protected function _save()
01483     {
01484         if ( $this->_canSaveBasket() ) {
01485 
01486             if ( $oUser = $this->getBasketUser() ) {
01487                 //first delete all contents
01488                 //#2039
01489                 $oSavedBasket = $oUser->getBasket( 'savedbasket' );
01490                 $oSavedBasket->delete();
01491 
01492                 //then save
01493                 foreach ( $this->_aBasketContents as $oBasketItem ) {
01494                     // discount or bundled products will be added automatically if available
01495                     if ( !$oBasketItem->isBundle() && !$oBasketItem->isDiscountArticle() ) {
01496                        $oSavedBasket->addItemToBasket( $oBasketItem->getProductId(), $oBasketItem->getAmount(), $oBasketItem->getSelList(), true, $oBasketItem->getPersParams() );
01497                     }
01498                 }
01499             }
01500         }
01501     }
01502 
01514     /*
01515     protected function _addItemToSavedBasket( $sProductId , $dAmount, $aSel, $blOverride = false, $aPersParam = null )
01516     {
01517         // updating basket history
01518         if ( $oUser = $this->getBasketUser() ) {
01519             $oUser->getBasket( 'savedbasket' )->addItemToBasket( $sProductId, $dAmount, $aSel, $blOverride, $aPersParam );
01520         }
01521     }*/
01522 
01530     protected function _deleteSavedBasket()
01531     {
01532         // deleting basket if session user available
01533         if ( $oUser = $this->getBasketUser() ) {
01534             $oUser->getBasket( 'savedbasket' )->delete();
01535         }
01536 
01537         // basket exclude
01538         if ( $this->getConfig()->getConfigParam( 'blBasketExcludeEnabled' )) {
01539             $this->setBasketRootCatId(null);
01540         }
01541     }
01542 
01548     protected function _findDelivCountry()
01549     {
01550         $myConfig = $this->getConfig();
01551         $oUser    = $this->getBasketUser();
01552 
01553         $sDelivCountry = null;
01554 
01555         if ( !$oUser ) {
01556             // don't calculate if not logged in unless specified otherwise
01557             $aHomeCountry = $myConfig->getConfigParam( 'aHomeCountry' );
01558             if ( $myConfig->getConfigParam( 'blCalculateDelCostIfNotLoggedIn' ) && is_array( $aHomeCountry ) ) {
01559                 $sDelivCountry = current( $aHomeCountry );
01560             }
01561         } else {
01562 
01563             // ok, logged in
01564             if ( $sCountryId = $myConfig->getGlobalParameter( 'delcountryid' ) ) {
01565                 $sDelivCountry = $sCountryId;
01566             } elseif ( $sAddressId = oxSession::getVar( 'deladrid' ) ) {
01567 
01568                 $oDelAdress = oxNew( 'oxaddress' );
01569                 if ( $oDelAdress->load( $sAddressId ) ) {
01570                     $sDelivCountry = $oDelAdress->oxaddress__oxcountryid->value;
01571                 }
01572             }
01573 
01574             // still not found ?
01575             if ( !$sDelivCountry ) {
01576                 $sDelivCountry = $oUser->oxuser__oxcountryid->value;
01577             }
01578         }
01579 
01580         return $sDelivCountry;
01581     }
01582 
01588     public function deleteBasket()
01589     {
01590         $this->_aBasketContents = array();
01591         $this->getSession()->delBasket();
01592 
01593         if ($this->getConfig()->getConfigParam( 'blPsBasketReservationEnabled' )) {
01594             $this->getSession()->getBasketReservations()->discardReservations();
01595         }
01596 
01597         // merging basket history
01598         $this->_deleteSavedBasket();
01599     }
01600 
01608     public function setPayment( $sPaymentId = null )
01609     {
01610         $this->_sPaymentId = $sPaymentId;
01611     }
01612 
01618     public function getPaymentId()
01619     {
01620         if ( !$this->_sPaymentId ) {
01621              $this->_sPaymentId = oxSession::getVar( 'paymentid' );
01622         }
01623         return $this->_sPaymentId;
01624     }
01625 
01633     public function setShipping( $sShippingSetId = null )
01634     {
01635         $this->_sShippingSetId = $sShippingSetId;
01636         oxSession::setVar( 'sShipSet', $sShippingSetId );
01637     }
01638 
01646     public function setDeliveryPrice( $oShippingPrice = null )
01647     {
01648         $this->_oDeliveryPrice = $oShippingPrice;
01649     }
01650 
01656     public function getShippingId()
01657     {
01658         if ( !$this->_sShippingSetId ) {
01659              $this->_sShippingSetId = oxSession::getVar( 'sShipSet' );
01660         }
01661 
01662         $sActPaymentId = $this->getPaymentId();
01663         // setting default if none is set
01664         if ( !$this->_sShippingSetId && $sActPaymentId != 'oxempty' ) {
01665             $oUser = $this->getUser();
01666 
01667             // choosing first preferred delivery set
01668             list( , $sActShipSet ) = oxDeliverySetList::getInstance()->getDeliverySetData( null, $oUser, $this );
01669             // in case nothing was found and no user set - choosing default
01670             $this->_sShippingSetId = $sActShipSet ? $sActShipSet : ( $oUser ? null : 'oxidstandard' );
01671         } elseif ( !$this->isAdmin() && $sActPaymentId == 'oxempty' ) {
01672             // in case 'oxempty' is payment id - delivery set must be reset
01673             $this->_sShippingSetId = null;
01674         }
01675 
01676         return $this->_sShippingSetId;
01677     }
01678 
01684     public function getBasketArticles()
01685     {
01686         $aBasketArticles = array();
01687 
01688         foreach ( $this->_aBasketContents as $sItemKey => $oBasketItem ) {
01689             try {
01690                 $oProduct = $oBasketItem->getArticle();
01691 
01692                 if ( $this->getConfig()->getConfigParam( 'bl_perfLoadSelectLists' ) ) {
01693                     // marking chosen select list
01694                     $aSelList = $oBasketItem->getSelList();
01695                     if ( is_array( $aSelList ) && ( $aSelectlist = $oProduct->getSelectLists( $sItemKey ) ) ) {
01696                         reset( $aSelList );
01697                         while ( list( $conkey, $iSel ) = each( $aSelList ) ) {
01698                             $aSelectlist[$conkey][$iSel] = $aSelectlist[$conkey][$iSel];
01699                             $aSelectlist[$conkey][$iSel]->selected = 1;
01700                         }
01701                         $oProduct->setSelectlist( $aSelectlist );
01702                     }
01703                 }
01704             } catch ( oxNoArticleException $oEx ) {
01705                 oxUtilsView::getInstance()->addErrorToDisplay( $oEx );
01706                 $this->removeItem( $sItemKey );
01707                 $this->calculateBasket( true );
01708                 continue;
01709             } catch ( oxArticleInputException $oEx ) {
01710                 oxUtilsView::getInstance()->addErrorToDisplay( $oEx );
01711                 $this->removeItem( $sItemKey );
01712                 $this->calculateBasket( true );
01713                 continue;
01714             }
01715 
01716             $aBasketArticles[$sItemKey] = $oProduct;
01717         }
01718         return $aBasketArticles;
01719     }
01720 
01726     public function getDiscountProductsPrice()
01727     {
01728         return $this->_oDiscountProductsPriceList;
01729     }
01730 
01736     public function getProductsPrice()
01737     {
01738         if ( is_null($this->_oProductsPriceList) ) {
01739             $this->_oProductsPriceList = oxNew( 'oxPriceList' );
01740         }
01741 
01742         return $this->_oProductsPriceList;
01743     }
01744 
01750     public function getPrice()
01751     {
01752         if ( is_null($this->_oPrice) ) {
01753             $this->_oPrice = oxNew( 'oxprice' );
01754         }
01755 
01756         return $this->_oPrice;
01757     }
01758 
01765     public function getOrderId()
01766     {
01767         return $this->_sOrderId;
01768     }
01769 
01777     public function setOrderId( $sId )
01778     {
01779         $this->_sOrderId = $sId;
01780     }
01781 
01790     public function getCosts( $sId = null )
01791     {
01792         // if user want some specific cost - return it
01793         if ( $sId ) {
01794             return isset( $this->_aCosts[$sId] )?$this->_aCosts[$sId]:null;
01795         }
01796         return $this->_aCosts;
01797     }
01798 
01804     public function getVouchers()
01805     {
01806         return $this->_aVouchers;
01807     }
01808 
01814     public function getProductsCount()
01815     {
01816         return $this->_iProductsCnt;
01817     }
01818 
01824     public function getItemsCount()
01825     {
01826         return $this->_dItemsCnt;
01827     }
01828 
01834     public function getWeight()
01835     {
01836         return $this->_dWeight;
01837     }
01838 
01844     public function getContents()
01845     {
01846         return $this->_aBasketContents;
01847     }
01848 
01856     public function getProductVats( $blFormatCurrency = true)
01857     {
01858         if ( !$this->_oNotDiscountedProductsPriceList ) {
01859             return array();
01860         }
01861 
01862         $aVats = $this->_oNotDiscountedProductsPriceList->getVatInfo();
01863 
01864         $oUtils = oxUtils::getInstance();
01865         foreach ( $this->_aDiscountedVats as $sKey => $dVat ) {
01866             if ( !isset( $aVats[$sKey] ) ) {
01867                 $aVats[$sKey] = 0;
01868             }
01869             // add prices of the same discounts
01870             $aVats[$sKey] += $oUtils->fRound( $dVat, $this->_oCurrency );
01871         }
01872 
01873         if ( $blFormatCurrency ) {
01874             $oLang = oxLang::getInstance();
01875             foreach ( $aVats as $sKey => $dVat ) {
01876                 $aVats[$sKey] = $oLang->formatCurrency( $dVat, $this->getBasketCurrency() );
01877             }
01878         }
01879 
01880         return $aVats;
01881     }
01882 
01888     public function getDiscountedNettoPrice()
01889     {
01890         if ( $this->_oNotDiscountedProductsPriceList ) {
01891             return $this->_dDiscountedProductNettoPrice + $this->_oNotDiscountedProductsPriceList->getNettoSum();
01892         }
01893         return false;
01894     }
01895 
01903     public function setCardMessage( $sMessage )
01904     {
01905         $this->_sCardMessage = $sMessage;
01906     }
01907 
01913     public function getCardMessage()
01914     {
01915         return $this->_sCardMessage;
01916     }
01917 
01925     public function setCardId( $sCardId )
01926     {
01927         $this->_sCardId = $sCardId;
01928     }
01929 
01935     public function getCardId()
01936     {
01937         return $this->_sCardId;
01938     }
01939 
01945     public function getCard()
01946     {
01947         $oCard = null;
01948         if ( $sCardId = $this->getCardId() ) {
01949             $oCard = oxNew( 'oxwrapping' );
01950             $oCard->load( $sCardId );
01951         }
01952         return $oCard;
01953     }
01954 
01960     public function getTotalDiscount()
01961     {
01962         return $this->_oTotalDiscount;
01963     }
01964 
01970     public function getDiscounts()
01971     {
01972         if ( $this->getTotalDiscount() && $this->getTotalDiscount()->getBruttoPrice() == 0 && count($this->_aItemDiscounts) == 0) {
01973             return null;
01974         }
01975 
01976         //#3857 this section is not needed as $this->_aItemDiscounts is part of $this->_aDiscounts already
01977         //return array_merge($this->_aItemDiscounts, $this->_aDiscounts);
01978         return $this->_aDiscounts;
01979     }
01980 
01986     public function getVoucherDiscount()
01987     {
01988         if ($this->getConfig()->getConfigParam( 'bl_showVouchers' )) {
01989             return $this->_oVoucherDiscount;
01990         }
01991         return null;
01992     }
01993 
02001     public function setBasketCurrency( $oCurrency )
02002     {
02003         $this->_oCurrency = $oCurrency;
02004     }
02005 
02011     public function getBasketCurrency()
02012     {
02013         if ( $this->_oCurrency === null ) {
02014             $this->_oCurrency = $this->getConfig()->getActShopCurrencyObject();
02015         }
02016 
02017         return $this->_oCurrency;
02018     }
02019 
02027     public function setSkipVouchersChecking( $blSkipChecking = null )
02028     {
02029         $this->_blSkipVouchersAvailabilityChecking = $blSkipChecking;
02030     }
02031 
02037     public function hasSkipedDiscount()
02038     {
02039         return $this->_blSkipDiscounts;
02040     }
02041 
02049     public function setSkipDiscounts( $blSkip )
02050     {
02051         $this->_blSkipDiscounts = $blSkip;
02052     }
02053 
02059     public function getProductsNetPrice()
02060     {
02061         return oxLang::getInstance()->formatCurrency( $this->getDiscountedNettoPrice(), $this->getBasketCurrency() );
02062     }
02063 
02069     public function getFProductsPrice()
02070     {
02071         if ( $this->_oProductsPriceList ) {
02072             return oxLang::getInstance()->formatCurrency( $this->_oProductsPriceList->getBruttoSum(), $this->getBasketCurrency() );
02073         }
02074         return null;
02075     }
02076 
02082     public function getDelCostVatPercent()
02083     {
02084         return $this->getCosts( 'oxdelivery' )->getVat();
02085     }
02086 
02092     public function getDelCostVat()
02093     {
02094         $dDelVAT = $this->getCosts( 'oxdelivery' )->getVatValue();
02095 
02096         if ( $dDelVAT > 0 ) {
02097             return oxLang::getInstance()->formatCurrency( $dDelVAT, $this->getBasketCurrency() );
02098         }
02099         return false;
02100     }
02101 
02107     public function getDelCostNet()
02108     {
02109         if ( $this->getBasketUser() || $this->getConfig()->getConfigParam( 'blCalculateDelCostIfNotLoggedIn' ) ) {
02110             return oxLang::getInstance()->formatCurrency( $this->getCosts( 'oxdelivery' )->getNettoPrice(), $this->getBasketCurrency() );
02111         }
02112         return false;
02113     }
02114 
02120     public function getPayCostVatPercent()
02121     {
02122         return $this->getCosts( 'oxpayment' )->getVat();
02123     }
02124 
02130     public function getPayCostVat()
02131     {
02132         $dPayVAT = $this->getCosts( 'oxpayment' )->getVatValue();
02133         if ( $dPayVAT > 0 ) {
02134             return oxLang::getInstance()->formatCurrency( $dPayVAT, $this->getBasketCurrency() );
02135         }
02136         return false;
02137     }
02138 
02144     public function getPayCostNet()
02145     {
02146         return oxLang::getInstance()->formatCurrency( $this->getCosts( 'oxpayment' )->getNettoPrice(), $this->getBasketCurrency() );
02147     }
02148 
02154     public function getPaymentCosts()
02155     {
02156         return $this->getCosts( 'oxpayment' )->getBruttoPrice();
02157     }
02158 
02164     public function getFPaymentCosts()
02165     {
02166         $oPaymentCost = $this->getCosts( 'oxpayment' );
02167 
02168         if ( $oPaymentCost && $oPaymentCost->getBruttoPrice() ) {
02169             return oxLang::getInstance()->formatCurrency( $oPaymentCost->getBruttoPrice(), $this->getBasketCurrency() );
02170         }
02171         return false;
02172     }
02173 
02179     public function getVoucherDiscValue()
02180     {
02181         if ( $this->getVoucherDiscount() ) {
02182             return $this->getVoucherDiscount()->getBruttoPrice();
02183         }
02184         return false;
02185     }
02186 
02192     public function getFVoucherDiscountValue()
02193     {
02194         if ( $oVoucherDiscount = $this->getVoucherDiscount() ) {
02195             if ( $oVoucherDiscount->getBruttoPrice() ) {
02196                 return oxLang::getInstance()->formatCurrency( $oVoucherDiscount->getBruttoPrice(), $this->getBasketCurrency() );
02197             }
02198         }
02199         return false;
02200     }
02201 
02202 
02208     public function getWrappCostVatPercent()
02209     {
02210         return $this->getCosts( 'oxwrapping' )->getVat();
02211     }
02212 
02218     public function getWrappCostVat()
02219     {
02220         $dWrappVAT = $this->getCosts( 'oxwrapping' )->getVatValue();
02221         if ( $dWrappVAT > 0 ) {
02222             return oxLang::getInstance()->formatCurrency( $dWrappVAT, $this->getBasketCurrency() );
02223         }
02224         return false;
02225 
02226     }
02227 
02233     public function getWrappCostNet()
02234     {
02235         $dWrappNet = $this->getCosts( 'oxwrapping' )->getNettoPrice();
02236         if ( $dWrappNet > 0 ) {
02237             return  oxLang::getInstance()->formatCurrency( $dWrappNet, $this->getBasketCurrency() );
02238         }
02239         return false;
02240     }
02241 
02247     public function getFWrappingCosts()
02248     {
02249         $oWrappingCost = $this->getCosts( 'oxwrapping' );
02250         if ( $oWrappingCost && $oWrappingCost->getBruttoPrice() ) {
02251             return oxLang::getInstance()->formatCurrency( $oWrappingCost->getBruttoPrice(), $this->getBasketCurrency() );
02252         }
02253         return false;
02254     }
02255 
02261     public function getFPrice()
02262     {
02263         return oxLang::getInstance()->formatCurrency( $this->getPrice()->getBruttoPrice(), $this->getBasketCurrency() );
02264     }
02265 
02271     public function getFDeliveryCosts()
02272     {
02273         $oDeliveryCost = $this->getCosts( 'oxdelivery' );
02274         if ( $oDeliveryCost ) {
02275             return oxLang::getInstance()->formatCurrency( $oDeliveryCost->getBruttoPrice(), $this->getBasketCurrency() );
02276         }
02277         return false;
02278     }
02279 
02285     public function getDeliveryCosts()
02286     {
02287         if ( $oDeliveryCost = $this->getCosts( 'oxdelivery' ) ) {
02288             return $oDeliveryCost->getBruttoPrice();
02289         }
02290         return false;
02291     }
02292 
02300     public function setTotalDiscount( $dDiscount )
02301     {
02302         $this->_oTotalDiscount = oxNew( 'oxPrice' );
02303         $this->_oTotalDiscount->setBruttoPriceMode();
02304         $this->_oTotalDiscount->add( $dDiscount );
02305     }
02306 
02313     public function getPriceForPayment()
02314     {
02315         $dPrice = $this->getDiscountedProductsBruttoPrice();
02316         //#1905 not discounted products should be included in payment amount calculation
02317         if ( $oPriceList = $this->getNotDiscountProductsPrice() ) {
02318             $dPrice += $oPriceList->getBruttoSum();
02319         }
02320 
02321         // adding delivery price to final price
02322         if ( $oDeliveryPrice = $this->_aCosts['oxdelivery'] ) {
02323             $dPrice += $oDeliveryPrice->getBruttoPrice();
02324         }
02325 
02326         return $dPrice;
02327     }
02328 
02334     public function getDiscountedProductsBruttoPrice()
02335     {
02336         if ( $oProductsPrice = $this->getDiscountProductsPrice() ) {
02337             $dPrice = $oProductsPrice->getBruttoSum();
02338         }
02339 
02340         // substracting total discount
02341         if ( $oPrice = $this->getTotalDiscount() ) {
02342             $dPrice -= $oPrice->getBruttoPrice();
02343         }
02344 
02345         if ( $oVoucherPrice = $this->getVoucherDiscount() ) {
02346             $dPrice -= $oVoucherPrice->getBruttoPrice();
02347         }
02348 
02349         return $dPrice;
02350     }
02351 
02357     public function isBelowMinOrderPrice()
02358     {
02359         $blIsBelowMinOrderPrice = false;
02360         $sConfValue = $this->getConfig()->getConfigParam( 'iMinOrderPrice' );
02361         if ( is_numeric($sConfValue) && $this->getProductsCount() ) {
02362             $dMinOrderPrice = oxPrice::getPriceInActCurrency( ( int ) $sConfValue );
02363             $dNotDiscountedProductPrice = 0;
02364             if ( $oPrice = $this->getNotDiscountProductsPrice() ) {
02365                 $dNotDiscountedProductPrice = $oPrice->getBruttoSum();
02366             }
02367             $blIsBelowMinOrderPrice = ($dMinOrderPrice > ($this->getDiscountedProductsBruttoPrice() + $dNotDiscountedProductPrice));
02368         }
02369 
02370         return $blIsBelowMinOrderPrice;
02371 
02372     }
02373 
02382     public function getArtStockInBasket( $sArtId, $sExpiredArtId = null )
02383     {
02384         $dArtStock = 0;
02385         foreach ( $this->_aBasketContents as $sItemKey => $oOrderArticle ) {
02386             if ( $oOrderArticle && ( $sExpiredArtId == null || $sExpiredArtId != $sItemKey ) ) {
02387                 if ( $oOrderArticle->getArticle()->getId() == $sArtId ) {
02388                     $dArtStock += $oOrderArticle->getAmount();
02389                 }
02390             }
02391         }
02392 
02393         return $dArtStock;
02394     }
02395 
02403     public function canAddProductToBasket( $sProductId )
02404     {
02405         $blCanAdd = null;
02406 
02407         // if basket category is not set..
02408         if ( $this->_sBasketCategoryId === null ) {
02409             $oCat = null;
02410 
02411             // request category
02412             if ( $oView = $this->getConfig()->getActiveView() ) {
02413                 if ( $oCat = $oView->getActCategory() ) {
02414                     if ( !$this->_isProductInRootCategory( $sProductId, $oCat->oxcategories__oxrootid->value ) ) {
02415                         $oCat = null;
02416                     } else {
02417                         $blCanAdd = true;
02418                     }
02419                 }
02420             }
02421 
02422             // product main category
02423             if ( !$oCat ) {
02424                 $oProduct = oxNew( "oxarticle" );
02425                 if ( $oProduct->load( $sProductId ) ) {
02426                     $oCat = $oProduct->getCategory();
02427                 }
02428             }
02429 
02430             // root category id
02431             if ( $oCat ) {
02432                 $this->setBasketRootCatId($oCat->oxcategories__oxrootid->value);
02433             }
02434         }
02435 
02436         // avoiding double check..
02437         if ( $blCanAdd === null ) {
02438             $blCanAdd = $this->_sBasketCategoryId ? $this->_isProductInRootCategory( $sProductId, $this->getBasketRootCatId() ) : true;
02439         }
02440 
02441         return $blCanAdd;
02442     }
02443 
02452     protected function _isProductInRootCategory( $sProductId, $sRootCatId )
02453     {
02454         $sO2CTable = getViewName( 'oxobject2category' );
02455         $sCatTable = getViewName( 'oxcategories' );
02456 
02457         $oDb = oxDb::getDb();
02458         $sParentId  = $oDb->getOne( "select oxparentid from oxarticles where oxid = ".$oDb->quote( $sProductId ) );
02459         $sProductId = $sParentId ? $sParentId : $sProductId;
02460 
02461         $sQ = "select 1 from {$sO2CTable}
02462                  left join {$sCatTable} on {$sCatTable}.oxid = {$sO2CTable}.oxcatnid
02463                  where {$sO2CTable}.oxobjectid = ".$oDb->quote( $sProductId )." and
02464                        {$sCatTable}.oxrootid = ".$oDb->quote( $sRootCatId );
02465 
02466         return (bool) $oDb->getOne( $sQ );
02467     }
02468 
02476     public function setBasketRootCatId($sRoot)
02477     {
02478         $this->_sBasketCategoryId = $sRoot;
02479     }
02480 
02486     public function getBasketRootCatId()
02487     {
02488         return $this->_sBasketCategoryId;
02489     }
02490 
02498     public function setCatChangeWarningState( $blShow )
02499     {
02500         $this->_blShowCatChangeWarning = $blShow;
02501     }
02502 
02508     public function showCatChangeWarning()
02509     {
02510         return $this->_blShowCatChangeWarning;
02511     }
02512 
02520     public function setTsProductId( $sProductId )
02521     {
02522         $this->_sTsProductId = $sProductId;
02523     }
02524 
02530     public function getTsProductId()
02531     {
02532         return $this->_sTsProductId;
02533     }
02534 
02540     public function getFTsProtectionCosts()
02541     {
02542         $oProtectionCost = $this->getCosts( 'oxtsprotection' );
02543         if ( $oProtectionCost && $oProtectionCost->getBruttoPrice() ) {
02544             return oxLang::getInstance()->formatCurrency( $oProtectionCost->getBruttoPrice(), $this->getBasketCurrency() );
02545         }
02546         return false;
02547     }
02548 
02554     public function getTsProtectionVatPercent()
02555     {
02556         return $this->getCosts( 'oxtsprotection' )->getVat();
02557     }
02558 
02564     public function getTsProtectionVat()
02565     {
02566         $dProtectionVAT = $this->getCosts( 'oxtsprotection' )->getVatValue();
02567         if ( $dProtectionVAT > 0 ) {
02568             return oxLang::getInstance()->formatCurrency( $dProtectionVAT, $this->getBasketCurrency() );
02569         }
02570         return false;
02571     }
02572 
02578     public function getTsProtectionNet()
02579     {
02580         return oxLang::getInstance()->formatCurrency( $this->getCosts( 'oxtsprotection' )->getNettoPrice(), $this->getBasketCurrency() );
02581     }
02582 
02588     public function getTsProtectionCosts()
02589     {
02590         $oProtection = $this->getCosts( 'oxtsprotection' );
02591         if ( $oProtection ) {
02592             return $oProtection->getBruttoPrice();
02593         }
02594         return false;
02595     }
02596 
02602     public function getNotDiscountProductsPrice()
02603     {
02604         return $this->_oNotDiscountedProductsPriceList;
02605     }
02606 
02620     protected function _addedNewItem( $sProductID, $dAmount, $aSel, $aPersParam, $blOverride, $blBundle, $sOldBasketItemId )
02621     {
02622         if ( !$blOverride ) {
02623             $this->_blNewITemAdded = null;
02624             oxSession::setVar( "blAddedNewItem", true );
02625         }
02626     }
02627 
02633     public function __wakeUp()
02634     {
02635         $this->_blNewITemAdded = null;
02636     }
02637 
02643     public function isNewItemAdded()
02644     {
02645         if ( $this->_blNewITemAdded == null ) {
02646             $this->_blNewITemAdded = (bool) oxSession::getVar( "blAddedNewItem" );
02647             oxSession::deleteVar( "blAddedNewItem" );
02648         }
02649         return $this->_blNewITemAdded;
02650     }
02651 }