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 
00229     public function isEnabled()
00230     {
00231         return !oxUtils::getInstance()->isSearchEngine();
00232     }
00233 
00243     protected function _changeBasketItemKey($sOldKey, $sNewKey, $value = null)
00244     {
00245         reset($this->_aBasketContents);
00246         $iOldKeyPlace = 0;
00247         while (key($this->_aBasketContents) != $sOldKey && next($this->_aBasketContents)) {
00248             ++$iOldKeyPlace;
00249         }
00250         $aNewCopy = array_merge(
00251             array_slice($this->_aBasketContents, 0, $iOldKeyPlace, true),
00252             array($sNewKey => $value),
00253             array_slice($this->_aBasketContents, $iOldKeyPlace+1, count($this->_aBasketContents)-$iOldKeyPlace, true)
00254         );
00255         $this->_aBasketContents = $aNewCopy;
00256     }
00257 
00273     public function addToBasket( $sProductID, $dAmount, $aSel = null, $aPersParam = null, $blOverride = false, $blBundle = false, $sOldBasketItemId = null )
00274     {
00275         // enabled ?
00276         if ( !$this->isEnabled() )
00277             return null;
00278 
00279         // basket exclude
00280         if ( $this->getConfig()->getConfigParam( 'blBasketExcludeEnabled' ) ) {
00281             if ( !$this->canAddProductToBasket( $sProductID ) ) {
00282                 $this->setCatChangeWarningState( true );
00283                 return null;
00284             } else {
00285                 $this->setCatChangeWarningState( false );
00286             }
00287         }
00288 
00289         $sItemId = $this->getItemKey( $sProductID, $aSel, $aPersParam, $blBundle );
00290         if ( $sOldBasketItemId && ( strcmp( $sOldBasketItemId, $sItemId ) != 0 ) ) {
00291             if ( isset( $this->_aBasketContents[$sItemId] ) ) {
00292                 // we are merging, so params will just go to the new key
00293                 unset( $this->_aBasketContents[$sOldBasketItemId] );
00294                 // do not override stock
00295                 $blOverride = false;
00296             } else {
00297                 // value is null - means isset will fail and real values will be filled
00298                 $this->_changeBasketItemKey( $sOldBasketItemId, $sItemId );
00299             }
00300         }
00301 
00302         // after some checks item must be removed from basket
00303         $blRemoveItem = false;
00304 
00305         // initialting exception storage
00306         $oEx = null;
00307 
00308         if ( isset( $this->_aBasketContents[$sItemId] ) ) {
00309 
00310             //updating existing
00311             try {
00312                 // setting stock check status
00313                 $this->_aBasketContents[$sItemId]->setStockCheckStatus( $this->getStockCheckMode() );
00314                 //validate amount
00315                 //possibly throws exception
00316                 $this->_aBasketContents[$sItemId]->setAmount( $dAmount, $blOverride, $sItemId );
00317             } catch( oxOutOfStockException $oEx ) {
00318                 // rethrow later
00319             }
00320 
00321         } else {
00322             //inserting new
00323             $oBasketItem = oxNew( 'oxbasketitem' );
00324             try {
00325                 $oBasketItem->setStockCheckStatus( $this->getStockCheckMode() );
00326                 $oBasketItem->init( $sProductID, $dAmount, $aSel, $aPersParam, $blBundle );
00327             } catch( oxNoArticleException $oEx ) {
00328                 // in this case that the article does not exist remove the item from the basket by setting its amount to 0
00329                 //$oBasketItem->dAmount = 0;
00330                 $blRemoveItem = true;
00331 
00332             } catch( oxOutOfStockException $oEx ) {
00333                 // rethrow later
00334             } catch ( oxArticleInputException $oEx ) {
00335                 // rethrow later
00336                 $blRemoveItem = true;
00337             }
00338 
00339             $this->_aBasketContents[$sItemId] = $oBasketItem;
00340         }
00341 
00342         //in case amount is 0 removing item
00343         if ( $this->_aBasketContents[$sItemId]->getAmount() == 0 || $blRemoveItem ) {
00344             $this->removeItem( $sItemId );
00345         } elseif ( $blBundle ) {
00346             //marking bundles
00347             $this->_aBasketContents[$sItemId]->setBundle( true );
00348         }
00349 
00350         //calling update method
00351         $this->onUpdate();
00352 
00353         if ( $oEx ) {
00354             throw $oEx;
00355         }
00356         return $this->_aBasketContents[$sItemId];
00357     }
00358 
00366     public function addOrderArticleToBasket( $oOrderArticle )
00367     {
00368         // adding only if amount > 0
00369         if ( $oOrderArticle->oxorderarticles__oxamount->value > 0 ) {
00370             $sItemId = $oOrderArticle->getId();
00371 
00372             //inserting new
00373             $this->_aBasketContents[$sItemId] = oxNew( 'oxbasketitem' );
00374             $this->_aBasketContents[$sItemId]->initFromOrderArticle( $oOrderArticle );
00375             $this->_aBasketContents[$sItemId]->setWrapping( $oOrderArticle->oxorderarticles__oxwrapid->value );
00376 
00377             //calling update method
00378             $this->onUpdate();
00379 
00380             return $this->_aBasketContents[$sItemId];
00381         }
00382     }
00383 
00391     public function setStockCheckMode( $blCheck )
00392     {
00393         $this->_blCheckStock = $blCheck;
00394     }
00395 
00401     public function getStockCheckMode()
00402     {
00403         return $this->_blCheckStock;
00404     }
00405 
00418     public function getItemKey( $sProductId, $aSel = null, $aPersParam = null, $blBundle = false, $sAdditionalParam = '' )
00419     {
00420         $aSel = ( $aSel != null) ? $aSel : array (0=>'0');
00421 
00422         $sItemKey = md5( $sProductId.'|'.serialize( $aSel ).'|'.serialize( $aPersParam ).'|'.( int ) $blBundle . '|' . serialize( $sAdditionalParam ) );
00423 
00424         return $sItemKey;
00425     }
00426 
00427 
00435     public function removeItem( $sItemKey )
00436     {
00437         if ($this->getConfig()->getConfigParam( 'blPsBasketReservationEnabled' )) {
00438             if (isset($this->_aBasketContents[$sItemKey])) {
00439                 $sArticleId = $this->_aBasketContents[$sItemKey]->getProductId();
00440                 if ($sArticleId) {
00441                     $this->getSession()
00442                             ->getBasketReservations()
00443                             ->discardArticleReservation($sArticleId);
00444                 }
00445             }
00446         }
00447         unset( $this->_aBasketContents[$sItemKey] );
00448 
00449         // basket exclude
00450         if ( !count($this->_aBasketContents) && $this->getConfig()->getConfigParam( 'blBasketExcludeEnabled' ) ) {
00451             $this->setBasketRootCatId(null);
00452         }
00453     }
00454 
00460     protected function _clearBundles()
00461     {
00462         reset( $this->_aBasketContents );
00463         while ( list( $sItemKey, $oBasketItem ) = each( $this->_aBasketContents ) ) {
00464             if ( $oBasketItem->isBundle() ) {
00465                 $this->removeItem( $sItemKey );
00466             }
00467         }
00468     }
00469 
00477     protected function _getArticleBundles( $oBasketItem )
00478     {
00479         $aBundles = array();
00480 
00481         if ( $oBasketItem->isBundle() ) {
00482             return $aBundles;
00483         }
00484 
00485         $oArticle = $oBasketItem->getArticle();
00486         if ( $oArticle && $oArticle->oxarticles__oxbundleid->value ) {
00487             $aBundles[$oArticle->oxarticles__oxbundleid->value] = 1;
00488         }
00489 
00490         return $aBundles;
00491     }
00492 
00500     protected function _getItemBundles( $oBasketItem )
00501     {
00502         if ( $oBasketItem->isBundle() ) {
00503             return array();
00504         }
00505 
00506         $aBundles = array();
00507 
00508         // does this object still exists ?
00509         if ( $oArticle = $oBasketItem->getArticle() ) {
00510             $aDiscounts = oxDiscountList::getInstance()->getBasketItemBundleDiscounts( $oArticle, $this, $this->getBasketUser() );
00511 
00512             foreach ( $aDiscounts as $oDiscount ) {
00513 
00514                 $iAmnt = $oDiscount->getBundleAmount( $oBasketItem->getAmount() );
00515                 if ( $iAmnt ) {
00516                     //init array element
00517                     if ( !isset( $aBundles[$oDiscount->oxdiscount__oxitmartid->value] ) ) {
00518                         $aBundles[$oDiscount->oxdiscount__oxitmartid->value] = 0;
00519                     }
00520 
00521                     $aBundles[$oDiscount->oxdiscount__oxitmartid->value] += $iAmnt;
00522                 }
00523             }
00524         }
00525 
00526         return $aBundles;
00527     }
00528 
00534     protected function _getBasketBundles()
00535     {
00536         $aBundles = array();
00537         $aDiscounts = oxDiscountList::getInstance()->getBasketBundleDiscounts( $this, $this->getBasketUser() );
00538 
00539         // calculating amount of non bundled/discount items
00540         $dAmount = 0;
00541         foreach ( $this->_aBasketContents as $oBasketItem ) {
00542             if ( !( $oBasketItem->isBundle() || $oBasketItem->isDiscountArticle() ) ) {
00543                 $dAmount += $oBasketItem->getAmount();
00544             }
00545         }
00546 
00547         foreach ( $aDiscounts as $oDiscount ) {
00548             if ($oDiscount->oxdiscount__oxitmartid->value) {
00549                 if ( !isset( $aBundles[$oDiscount->oxdiscount__oxitmartid->value] ) ) {
00550                     $aBundles[$oDiscount->oxdiscount__oxitmartid->value] = 0;
00551                 }
00552 
00553                 $aBundles[$oDiscount->oxdiscount__oxitmartid->value] += $oDiscount->getBundleAmount( $dAmount );
00554             }
00555         }
00556 
00557         return $aBundles;
00558     }
00559 
00566     protected function _addBundles()
00567     {
00568         // iterating through articles and binding bundles
00569         foreach ( $this->_aBasketContents as $key => $oBasketItem ) {
00570             try {
00571                 // adding discount type bundles
00572                 if ( !$oBasketItem->isDiscountArticle() && !$oBasketItem->isBundle() ) {
00573                     $aBundles = $this->_getItemBundles( $oBasketItem );
00574                 } else {
00575                     continue;
00576                 }
00577 
00578                 $this->_addBundlesToBasket( $aBundles );
00579 
00580                     // adding item type bundles
00581                     $aBundles = $this->_getArticleBundles( $oBasketItem );
00582 
00583                     // adding bundles to basket
00584                     $this->_addBundlesToBasket( $aBundles );
00585             } catch ( oxNoArticleException $oEx ) {
00586                 $this->removeItem( $key );
00587                 oxUtilsView::getInstance()->addErrorToDisplay( $oEx );
00588             } catch( oxArticleInputException $oEx ) {
00589                 $this->removeItem( $key );
00590                 oxUtilsView::getInstance()->addErrorToDisplay( $oEx );
00591             }
00592         }
00593 
00594         // adding global basket bundles
00595         if ( $aBundles = $this->_getBasketBundles() ) {
00596             $this->_addBundlesToBasket( $aBundles );
00597         }
00598 
00599     }
00600 
00608     protected function _addBundlesToBasket( $aBundles )
00609     {
00610         foreach ( $aBundles as $sBundleId => $dAmount ) {
00611             if ( $dAmount ) {
00612                 try {
00613                     if ( $oBundleItem = $this->addToBasket( $sBundleId, $dAmount, null, null, false, true ) ) {
00614                         $oBundleItem->setAsDiscountArticle( true );
00615                     }
00616                 } catch(oxArticleException $oEx) {
00617                     // caught and ignored
00618                 }
00619             }
00620         }
00621 
00622     }
00623 
00629     protected function _calcItemsPrice()
00630     {
00631         // resetting
00632         $this->setSkipDiscounts( false );
00633         $this->_iProductsCnt = 0; // count different types
00634         $this->_dItemsCnt    = 0; // count of item units
00635         $this->_dWeight      = 0; // basket weight
00636 
00637         // resetting
00638         $this->_aItemDiscounts = array();
00639 
00640         $this->_oProductsPriceList = oxNew( 'oxpricelist' );
00641         $this->_oDiscountProductsPriceList = oxNew( 'oxpricelist' );
00642         $this->_oNotDiscountedProductsPriceList = oxNew( 'oxpricelist' );
00643 
00644         $oDiscountList = oxDiscountList::getInstance();
00645 
00646         foreach ( $this->_aBasketContents as $oBasketItem ) {
00647             $this->_iProductsCnt++;
00648             $this->_dItemsCnt += $oBasketItem->getAmount();
00649             $this->_dWeight   += $oBasketItem->getWeight();
00650 
00651             if ( !$oBasketItem->isDiscountArticle() && ( $oArticle = $oBasketItem->getArticle() ) ) {
00652                 $oBasketPrice = $oArticle->getBasketPrice( $oBasketItem->getAmount(), $oBasketItem->getSelList(), $this );
00653                 $oBasketItem->setPrice( $oBasketPrice );
00654                 //P adding product price
00655                 $this->_oProductsPriceList->addToPriceList( $oBasketItem->getPrice() );
00656 
00657                 $oBasketPrice->setBruttoPriceMode();
00658                 if ( !$oArticle->skipDiscounts() && $this->canCalcDiscounts() ) {
00659                     // apply basket type discounts
00660                     $aItemDiscounts = $oDiscountList->applyBasketDiscounts( $oBasketPrice, $oDiscountList->getBasketItemDiscounts( $oArticle, $this, $this->getBasketUser() ), $oBasketItem->getAmount() );
00661                     if ( is_array($this->_aItemDiscounts) && is_array($aItemDiscounts) ) {
00662                         $this->_aItemDiscounts = $this->_mergeDiscounts( $this->_aItemDiscounts, $aItemDiscounts);
00663                     }
00664                 } else {
00665                     $oBasketItem->setSkipDiscounts( true );
00666                     $this->setSkipDiscounts( true );
00667                 }
00668                 $oBasketPrice->multiply( $oBasketItem->getAmount() );
00669 
00670                 //P collect discount values for basket items which are discountable
00671                 if ( !$oArticle->skipDiscounts() ) {
00672                     $this->_oDiscountProductsPriceList->addToPriceList( $oBasketPrice );
00673                 } else {
00674                     $this->_oNotDiscountedProductsPriceList->addToPriceList( $oBasketPrice );
00675                     $oBasketItem->setSkipDiscounts( true );
00676                     $this->setSkipDiscounts( true );
00677                 }
00678             } elseif ( $oBasketItem->isBundle() ) {
00679                 // if bundles price is set to zero
00680                 $oPrice = oxNew( "oxprice");
00681                 $oBasketItem->setPrice( $oPrice );
00682             }
00683         }
00684     }
00685 
00693     public function setDiscountCalcMode( $blCalcDiscounts )
00694     {
00695         $this->_blCalcDiscounts = $blCalcDiscounts;
00696     }
00697 
00703     public function canCalcDiscounts()
00704     {
00705         return $this->_blCalcDiscounts;
00706     }
00707 
00717     protected function _mergeDiscounts( $aDiscounts, $aItemDiscounts)
00718     {
00719         foreach ( $aItemDiscounts as $sKey => $oDiscount ) {
00720             // add prices of the same discounts
00721             if ( array_key_exists ($sKey, $aDiscounts) ) {
00722                 $aDiscounts[$sKey]->dDiscount += $oDiscount->dDiscount;
00723             } else {
00724                 $aDiscounts[$sKey] = $oDiscount;
00725             }
00726         }
00727         return $aDiscounts;
00728     }
00729 
00735     protected function _calcDeliveryCost()
00736     {
00737         if ( $this->_oDeliveryPrice !== null ) {
00738             return $this->_oDeliveryPrice;
00739         }
00740         $myConfig  = $this->getConfig();
00741         $oDeliveryPrice = oxNew( 'oxprice' );
00742         $oDeliveryPrice->setBruttoPriceMode();
00743 
00744         // don't calculate if not logged in
00745         $oUser = $this->getBasketUser();
00746 
00747         if ( !$oUser && !$myConfig->getConfigParam( 'blCalculateDelCostIfNotLoggedIn' ) ) {
00748             return $oDeliveryPrice;
00749         }
00750 
00751         // VAT for delivery ?
00752         $fDelVATPercent = 0;
00753         if ( $myConfig->getConfigParam( 'blCalcVATForDelivery' ) ) {
00754             $fDelVATPercent = $this->getMostUsedVatPercent();
00755             $oDeliveryPrice->setVat( $fDelVATPercent );
00756         }
00757 
00758         // list of active delivery costs
00759         if ( $myConfig->getConfigParam('bl_perfLoadDelivery') ) {
00760             $aDeliveryList = oxDeliveryList::getInstance()->getDeliveryList( $this,
00761                                         $oUser,
00762                                         $this->_findDelivCountry(),
00763                                         $this->getShippingId()
00764                                     );
00765 
00766             if ( count( $aDeliveryList ) > 0 ) {
00767                 foreach ( $aDeliveryList as $oDelivery ) {
00768                     //debug trace
00769                     if ( $myConfig->getConfigParam( 'iDebug' ) == 5 ) {
00770                         echo( "DelCost : ".$oDelivery->oxdelivery__oxtitle->value."<br>" );
00771                     }
00772                     $oDeliveryPrice->addPrice( $oDelivery->getDeliveryPrice( $fDelVATPercent ) );
00773                 }
00774             }
00775         }
00776 
00777         return $oDeliveryPrice;
00778     }
00779 
00785     public function getBasketUser()
00786     {
00787         if ( $this->_oUser == null ) {
00788             return $this->getUser();
00789         }
00790 
00791         return $this->_oUser;
00792     }
00793 
00801     public function setBasketUser( $oUser )
00802     {
00803         $this->_oUser = $oUser;
00804     }
00805 
00806     //P
00812     public function getMostUsedVatPercent()
00813     {
00814         return $this->_oProductsPriceList->getMostUsedVatPercent();
00815     }
00816 
00817     //P
00824     protected function _calcTotalPrice()
00825     {
00826         // 1. add products price
00827         $dprice = $this->_oProductsPriceList->getBruttoSum();
00828         $this->_oPrice->setPrice( $dprice );
00829 
00830         // 2. substract discounts
00831         if ( $dprice ) {
00832 
00833             // 2.1 applying basket item discounts
00834             foreach ( $this->_aItemDiscounts as $oDiscount ) {
00835 
00836                 // skipping bundle discounts
00837                 if ( $oDiscount->sType == 'itm' ) {
00838                     continue;
00839                 }
00840                 $this->_oPrice->subtract( $oDiscount->dDiscount );
00841             }
00842 
00843             // 2.2 applying basket discounts
00844             $this->_oPrice->subtract( $this->_oTotalDiscount->getBruttoPrice() );
00845 
00846             // 2.3 applying voucher discounts
00847             if ($oVoucherDisc = $this->getVoucherDiscount()) {
00848                 $this->_oPrice->subtract( $oVoucherDisc->getBruttoPrice() );
00849             }
00850         }
00851 
00852         // 2.3 add delivery cost
00853         if ( isset( $this->_aCosts['oxdelivery'] ) ) {
00854             $this->_oPrice->add( $this->_aCosts['oxdelivery']->getBruttoPrice() );
00855         }
00856 
00857         // 2.4 add wrapping price
00858         if ( isset( $this->_aCosts['oxwrapping'] ) ) {
00859             $this->_oPrice->add( $this->_aCosts['oxwrapping']->getBruttoPrice() );
00860         }
00861 
00862         // 2.5 add payment price
00863         if ( isset( $this->_aCosts['oxpayment'] ) ) {
00864             $this->_oPrice->add( $this->_aCosts['oxpayment']->getBruttoPrice() );
00865         }
00866 
00867         // 2.6 add TS protection price
00868         if ( isset( $this->_aCosts['oxtsprotection'] ) ) {
00869             $this->_oPrice->add( $this->_aCosts['oxtsprotection']->getBruttoPrice() );
00870         }
00871 
00872     }
00873 
00881     public function setVoucherDiscount( $dDiscount )
00882     {
00883         $this->_oVoucherDiscount = oxNew( 'oxPrice' );
00884         $this->_oVoucherDiscount->setBruttoPriceMode();
00885         $this->_oVoucherDiscount->add( $dDiscount );
00886     }
00887 
00893     protected function _calcVoucherDiscount()
00894     {
00895         if ( $this->getConfig()->getConfigParam( 'bl_showVouchers' ) && ($this->_oVoucherDiscount === null || ( $this->_blUpdateNeeded && !$this->isAdmin() ) ) ) {
00896 
00897             $this->_oVoucherDiscount = oxNew( 'oxPrice' );
00898             $this->_oVoucherDiscount->setBruttoPriceMode();
00899 
00900 
00901             // calculating price to apply discount
00902             $dPrice = $this->_oDiscountProductsPriceList->getBruttoSum() - $this->_oTotalDiscount->getBruttoPrice();
00903 
00904             // recalculating
00905             if ( count( $this->_aVouchers ) ) {
00906                 $oLang = oxLang::getInstance();
00907                 foreach ( $this->_aVouchers as $sVoucherId => $oStdVoucher ) {
00908                     $oVoucher = oxNew( 'oxvoucher' );
00909                     try { // checking
00910                         $oVoucher->load( $oStdVoucher->sVoucherId );
00911 
00912                         if ( !$this->_blSkipVouchersAvailabilityChecking ) {
00913                             $oVoucher->checkBasketVoucherAvailability( $this->_aVouchers, $dPrice );
00914                             $oVoucher->checkUserAvailability( $this->getBasketUser() );
00915                         }
00916 
00917                         // assigning real voucher discount value as this is the only place where real value is calculated
00918                         $dVoucherdiscount = $oVoucher->getDiscountValue( $dPrice );
00919 
00920                         // acumulating discount value
00921                         $this->_oVoucherDiscount->add( $dVoucherdiscount );
00922 
00923                         // collecting formatted for preview
00924                         $oStdVoucher->fVoucherdiscount = $oLang->formatCurrency( $dVoucherdiscount, $this->getBasketCurrency() );
00925                         $oStdVoucher->dVoucherdiscount = $dVoucherdiscount;
00926 
00927                         // substracting voucher discount
00928                         $dPrice -= $dVoucherdiscount;
00929                     } catch ( oxVoucherException $oEx ) {
00930 
00931                         // removing voucher on error
00932                         $oVoucher->unMarkAsReserved();
00933                         unset( $this->_aVouchers[$sVoucherId] );
00934 
00935                         // storing voucher error info
00936                         oxUtilsView::getInstance()->addErrorToDisplay($oEx, false, true);
00937                     }
00938                 }
00939             }
00940         }
00941     }
00942 
00943     //V
00950     protected function _applyDiscounts()
00951     {
00952         $dBruttoPrice = 0;
00953         $this->_aDiscountedVats = array();
00954         if ( $oPriceList = $this->getDiscountProductsPrice() ) {
00955             $dBruttoPrice = $oPriceList->getBruttoSum();
00956             $this->_aDiscountedVats = $oPriceList->getVatInfo();
00957         }
00958 
00959         //apply discounts for brutto price
00960         $dDiscountedBruttoPrice = $this->getDiscountedProductsBruttoPrice();
00961         $oTotalDiscount   = $this->getTotalDiscount();
00962         $oVoucherDiscount = $this->getVoucherDiscount();
00963 
00964         //apply discount for VATs
00965         if ( $dBruttoPrice &&
00966              ( ( $oTotalDiscount && $oTotalDiscount->getBruttoPrice() ) ||
00967                ( $oVoucherDiscount && $oVoucherDiscount->getBruttoPrice() )
00968              )
00969            ) {
00970             $dPercent = ( $dDiscountedBruttoPrice / $dBruttoPrice) * 100;
00971             foreach ( $this->_aDiscountedVats as $sKey => $dVat ) {
00972                 $this->_aDiscountedVats[$sKey] = oxPrice::percent( $dVat, $dPercent);
00973             }
00974         }
00975 
00976         $oUtils = oxUtils::getInstance();
00977         $dDiscVatSum = 0;
00978         foreach ( $this->_aDiscountedVats as $dVat ) {
00979             $dDiscVatSum += $oUtils->fRound( -$dVat, $this->_oCurrency);
00980         }
00981         //calculate netto price with discounts
00982         $this->_dDiscountedProductNettoPrice = $dDiscountedBruttoPrice + $dDiscVatSum;
00983     }
00984 
00990     protected function _calcBasketDiscount()
00991     {
00992         // resetting
00993         $this->_aDiscounts = array();
00994 
00995         // P using prices sum which has discount, not sum of skipped discounts
00996         $dOldprice = $this->_oDiscountProductsPriceList->getBruttoSum();
00997 
00998         // add basket discounts
00999         $aDiscounts = oxDiscountList::getInstance()->getBasketDiscounts( $this, $this->getBasketUser() );
01000 
01001         foreach ( $aDiscounts as $oDiscount ) {
01002 
01003             // storing applied discounts
01004             $oStdDiscount = $oDiscount->getSimpleDiscount();
01005 
01006             // skipping bundle discounts
01007             if ( $oDiscount->oxdiscount__oxaddsumtype->value == 'itm' ) {
01008                 continue;
01009             }
01010 
01011             // saving discount info
01012             $oStdDiscount->dDiscount = $oDiscount->getAbsValue( $dOldprice );
01013             if ($dOldprice < $oStdDiscount->dDiscount) {
01014                 $oStdDiscount->dDiscount = $dOldprice;
01015             }
01016 
01017             if ($oStdDiscount->dDiscount != 0) {
01018                 $this->_aDiscounts[$oDiscount->getId()] = $oStdDiscount;
01019                 // substracting product price after discount
01020                 $dOldprice = $dOldprice - $oStdDiscount->dDiscount;
01021             }
01022         }
01023     }
01024 
01030     protected function _calcBasketTotalDiscount()
01031     {
01032         if ( $this->_oTotalDiscount === null || ( $this->_blUpdateNeeded && !$this->isAdmin() ) ) {
01033             $this->_oTotalDiscount = oxNew( 'oxPrice' );
01034             $this->_oTotalDiscount->setBruttoPriceMode();
01035 
01036             if ( is_array($this->_aDiscounts) ) {
01037                 foreach ( $this->_aDiscounts as $oDiscount ) {
01038 
01039                     // skipping bundle discounts
01040                     if ( $oDiscount->sType == 'itm' ) {
01041                         continue;
01042                     }
01043 
01044                     // add discount value to total basket discount
01045                     $this->_oTotalDiscount->add( $oDiscount->dDiscount );
01046                 }
01047             }
01048         }
01049     }
01050 
01060     protected function _calcBasketWrapping()
01061     {
01062         $myConfig = $this->getConfig();
01063         $oWrappingPrice = oxNew( 'oxPrice' );
01064         $oWrappingPrice->setBruttoPriceMode();
01065 
01066         // wrapping VAT
01067         if ( $myConfig->getConfigParam( 'blCalcVatForWrapping' ) ) {
01068             $oWrappingPrice->setVat( $this->getMostUsedVatPercent() );
01069         }
01070 
01071         // calculating basket items wrapping
01072         foreach ( $this->_aBasketContents as $oBasketItem ) {
01073 
01074             if ( ( $oWrapping = $oBasketItem->getWrapping() ) ) {
01075                 $oWrapPrice = $oWrapping->getWrappingPrice( $oBasketItem->getAmount() );
01076                 $oWrappingPrice->add( $oWrapPrice->getBruttoPrice() );
01077             }
01078         }
01079 
01080         // gift card price calculation
01081         if ( ( $oCard = $this->getCard() ) ) {
01082             $oCardPrice = $oCard->getWrappingPrice();
01083             $oWrappingPrice->add( $oCardPrice->getBruttoPrice() );
01084         }
01085 
01086         return $oWrappingPrice;
01087     }
01088 
01095     protected function _calcPaymentCost()
01096     {
01097         // resetting values
01098         $oPaymentPrice = oxNew( 'oxPrice' );
01099         $oPaymentPrice->setBruttoPriceMode();
01100 
01101         // payment
01102         if ( ( $this->_sPaymentId = $this->getPaymentId() ) ) {
01103 
01104             $oPayment = oxNew( 'oxpayment' );
01105             $oPayment->load( $this->_sPaymentId );
01106 
01107             $oPaymentPrice = $oPayment->getPaymentPrice( $this );
01108         }
01109 
01110         return $oPaymentPrice;
01111     }
01112 
01119     protected function _calcTsProtectionCost()
01120     {
01121         // resetting values
01122         $oProtectionPrice = oxNew( 'oxPrice' );
01123         $oProtectionPrice->setBruttoPriceMode();
01124 
01125         // payment
01126         if ( ( $this->_sTsProductId = $this->getTsProductId() ) ) {
01127 
01128             $oTsProtection = oxNew('oxtsprotection');
01129             $oTsProduct = $oTsProtection->getTsProduct( $this->_sTsProductId );
01130 
01131             $oProtectionPrice = $oTsProduct->oPrice;
01132         }
01133         return $oProtectionPrice;
01134     }
01135 
01144     public function setCost( $sCostName, $oPrice = null )
01145     {
01146         $this->_aCosts[$sCostName] = $oPrice;
01147     }
01148 
01157     public function calculateBasket( $blForceUpdate = false )
01158     {
01159         if ( !$this->isEnabled() ) {
01160             return;
01161         }
01162 
01163         if ( !$this->_blUpdateNeeded && !$blForceUpdate ) {
01164             return;
01165         }
01166 
01167         $this->_aCosts = array();
01168 
01169         $this->_oPrice = oxNew( 'oxprice' );
01170         $this->_oPrice->setBruttoPriceMode();
01171 
01172         //  1. saving basket to the database
01173         $this->_save();
01174 
01175         //  2. remove all bundles
01176         $this->_clearBundles();
01177 
01178         //  3. generate bundle items
01179         $this->_addBundles();
01180 
01181         // reserve active basket
01182         if ($this->getConfig()->getConfigParam( 'blPsBasketReservationEnabled' )) {
01183             $this->getSession()->getBasketReservations()->reserveBasket($this);
01184         }
01185 
01186         //  4. calculating item prices
01187         $this->_calcItemsPrice();
01188 
01189         //  5. calculating/applying discounts
01190         $this->_calcBasketDiscount();
01191 
01192         //  6. calculating basket total discount
01193         $this->_calcBasketTotalDiscount();
01194 
01195         //  7. check for vouchers
01196         $this->_calcVoucherDiscount();
01197 
01198         //  8. applies all discounts to pricelist
01199         $this->_applyDiscounts();
01200 
01201         //  9. calculating additional costs:
01202         //  9.1: delivery
01203         $this->setCost( 'oxdelivery', $this->_calcDeliveryCost() );
01204 
01205         //  9.2: adding wrapping costs
01206         $this->setCost( 'oxwrapping', $this->_calcBasketWrapping() );
01207 
01208         //  9.3: adding payment cost
01209         $this->setCost( 'oxpayment', $this->_calcPaymentCost() );
01210 
01211         //  9.4: adding TS protection cost
01212         $this->setCost( 'oxtsprotection', $this->_calcTsProtectionCost() );
01213 
01214         //  10. calculate total price
01215         $this->_calcTotalPrice();
01216 
01217         //  11. setting deprecated values
01218         $this->_setDeprecatedValues();
01219 
01220         //  12.setting to up-to-date status
01221         $this->afterUpdate();
01222     }
01223 
01229     public function onUpdate()
01230     {
01231         $this->_blUpdateNeeded = true;
01232     }
01233 
01239     public function afterUpdate()
01240     {
01241         $this->_blUpdateNeeded = false;
01242     }
01243 
01251     public function getBasketSummary()
01252     {
01253         if ( $this->_blUpdateNeeded || $this->_aBasketSummary === null ) {
01254             $this->_aBasketSummary = new Oxstdclass();
01255             $this->_aBasketSummary->aArticles = array();
01256             $this->_aBasketSummary->aCategories = array();
01257             $this->_aBasketSummary->iArticleCount = 0;
01258             $this->_aBasketSummary->dArticlePrice = 0;
01259             $this->_aBasketSummary->dArticleDiscountablePrice = 0;
01260         }
01261 
01262         if ( !$this->isEnabled() ) {
01263             return $this->_aBasketSummary;
01264         }
01265 
01266         $myConfig = $this->getConfig();
01267         foreach ( $this->_aBasketContents as $oBasketItem ) {
01268             if ( !$oBasketItem->isBundle() && $oArticle = $oBasketItem->getArticle(false) ) {
01269                 $aCatIds = $oArticle->getCategoryIds();
01270                 //#M530 if price is not loaded for articles
01271                 $dPrice = 0;
01272                 $dDiscountablePrice = 0;
01273                 if ( ( $oPrice = $oArticle->getPrice( $oBasketItem->getAmount() ) ) ) {
01274                     $dPrice = $oPrice->getBruttoPrice();
01275                     if ( !$oArticle->skipDiscounts() ) {
01276                         $dDiscountablePrice = $dPrice;
01277                     }
01278                 }
01279 
01280                 foreach ( $aCatIds as $sCatId ) {
01281                     if ( !isset( $this->_aBasketSummary->aCategories[$sCatId] ) ) {
01282                         $this->_aBasketSummary->aCategories[$sCatId] = new Oxstdclass();
01283                     }
01284 
01285                     $this->_aBasketSummary->aCategories[$sCatId]->dPrice  += $dPrice * $oBasketItem->getAmount();
01286                     $this->_aBasketSummary->aCategories[$sCatId]->dDiscountablePrice += $dDiscountablePrice * $oBasketItem->getAmount();
01287                     $this->_aBasketSummary->aCategories[$sCatId]->dAmount += $oBasketItem->getAmount();
01288                     $this->_aBasketSummary->aCategories[$sCatId]->iCount++;
01289                 }
01290 
01291                 // variant handling
01292                 if ( ($sParentId = $oArticle->getProductParentId()) && $myConfig->getConfigParam( 'blVariantParentBuyable' ) ) {
01293                     if ( !isset( $this->_aBasketSummary->aArticles[$sParentId] ) ) {
01294                         $this->_aBasketSummary->aArticles[$sParentId] = 0;
01295                     }
01296                     $this->_aBasketSummary->aArticles[$sParentId] += $oBasketItem->getAmount();
01297                 }
01298 
01299                 if ( !isset( $this->_aBasketSummary->aArticles[$oBasketItem->getProductId()] ) ) {
01300                     $this->_aBasketSummary->aArticles[$oBasketItem->getProductId()] = 0;
01301                 }
01302 
01303                 $this->_aBasketSummary->aArticles[$oBasketItem->getProductId()] += $oBasketItem->getAmount();
01304                 $this->_aBasketSummary->iArticleCount += $oBasketItem->getAmount();
01305                 $this->_aBasketSummary->dArticlePrice += $dPrice * $oBasketItem->getAmount();
01306                 $this->_aBasketSummary->dArticleDiscountablePrice += $dDiscountablePrice * $oBasketItem->getAmount();
01307             }
01308         }
01309         return $this->_aBasketSummary;
01310     }
01311 
01323     public function addVoucher( $sVoucherId )
01324     {
01325         // calculating price to check
01326         // P using prices sum which has discount, not sum of skipped discounts
01327         $dPrice = 0;
01328         if ( $this->_oDiscountProductsPriceList ) {
01329             $dPrice = $this->_oDiscountProductsPriceList->getBruttoSum();
01330         }
01331 
01332         try { // trying to load voucher and apply it
01333 
01334             $oVoucher = oxNew( 'oxvoucher' );
01335 
01336             if ( !$this->_blSkipVouchersAvailabilityChecking ) {
01337                 $oVoucher->getVoucherByNr( $sVoucherId, $this->_aVouchers, true );
01338                 $oVoucher->checkVoucherAvailability( $this->_aVouchers, $dPrice );
01339                 $oVoucher->checkUserAvailability( $this->getBasketUser() );
01340                 $oVoucher->markAsReserved();
01341             } else {
01342                 $oVoucher->load( $sVoucherId );
01343             }
01344 
01345             // saving voucher info
01346             $this->_aVouchers[$oVoucher->oxvouchers__oxid->value] = $oVoucher->getSimpleVoucher();
01347         } catch ( oxVoucherException $oEx ) {
01348 
01349             // problems adding voucher
01350             oxUtilsView::getInstance()->addErrorToDisplay( $oEx, false, true );
01351         }
01352 
01353         $this->onUpdate();
01354     }
01355 
01363     public function removeVoucher( $sVoucherId )
01364     {
01365         // removing if it exists
01366         if ( isset( $this->_aVouchers[$sVoucherId] ) ) {
01367 
01368             $oVoucher = oxNew( 'oxvoucher' );
01369             $oVoucher->load( $sVoucherId );
01370 
01371             $oVoucher->unMarkAsReserved();
01372 
01373             // unsetting it if exists this voucher in DB or not
01374             unset( $this->_aVouchers[$sVoucherId] );
01375             $this->onUpdate();
01376         }
01377 
01378     }
01379 
01385     public function resetUserInfo()
01386     {
01387         $this->setPayment( null );
01388         $this->setShipping( null );
01389     }
01390 
01398     protected function _setDeprecatedValues()
01399     {
01400         $this->dproductsprice    = $this->_oProductsPriceList->getBruttoSum(); // products brutto price
01401         $this->dproductsnetprice = $this->getDiscountedNettoPrice();  // products netto price();
01402 
01403         //P sum vat values
01404         $this->dVAT = array_sum( $this->_oProductsPriceList->getVatInfo() );
01405         $oLang = oxLang::getInstance();
01406 
01407         // formatting final values
01408         $this->fproductsprice    = $this->getFProductsPrice();
01409         $this->fproductsnetprice = $this->getProductsNetPrice();
01410         $this->fVAT = $oLang->formatCurrency( $this->dVAT, $this->getBasketCurrency());
01411 
01412         // delivery costs
01413         if ( $oDeliveryCost = $this->getCosts( 'oxdelivery' ) ) {
01414 
01415             $this->ddeliverycost    = $oDeliveryCost->getBruttoPrice();
01416             $this->ddeliverynetcost = $oDeliveryCost->getNettoPrice();
01417             $this->dDelVAT          = $oDeliveryCost->getVatValue();
01418             $this->fDelVATPercent   = $oDeliveryCost->getVat() / 100; // needed to divide, because in template value is multyplied by 100
01419 
01420             // formating values
01421             $this->fdeliverycost    = $oLang->formatCurrency( $this->ddeliverycost, $this->getBasketCurrency() );
01422             $this->fdeliverynetcost = $oLang->formatCurrency( $this->ddeliverynetcost, $this->getBasketCurrency() );
01423             $this->fDelVAT          = $this->getDelCostVat();
01424         }
01425 
01426         //P
01427         // wrapping costs
01428         if ( $oWrappingCost = $this->getCosts( 'oxwrapping' ) ) {
01429 
01430             $this->dWrappingPrice = $oWrappingCost->getBruttoPrice();
01431             $this->dWrappingNetto = $oWrappingCost->getNettoPrice();
01432             $this->dWrappingVAT   = $oWrappingCost->getVatValue();
01433 
01434             //formating values
01435             $this->fWrappingPrice      = $oLang->formatCurrency( $this->dWrappingPrice, $this->getBasketCurrency() );
01436             $this->fWrappingNetto      = $this->getWrappCostNet();
01437             $this->fWrappingVAT        = $this->getWrappCostVat();
01438             $this->fWrappingVATPercent = $this->getWrappCostVatPercent();
01439         }
01440 
01441         //P
01442         // payment costs
01443         if ( $oPaymentCost = $this->getCosts( 'oxpayment' ) ) {
01444 
01445             $this->dAddPaymentSum    = $this->getPaymentCosts();
01446             $this->dAddPaymentSumVAT = $oPaymentCost->getVatValue();
01447 
01448             //formating values
01449             $this->fAddPaymentSum    = $oLang->formatCurrency( $this->dAddPaymentSum, $this->getBasketCurrency() );
01450             $this->fAddPaymentSumVAT = $this->getPayCostVat();
01451             $this->fAddPaymentSumVATPercent = $this->getPayCostVatPercent();
01452             $this->fAddPaymentNetSum = $this->getPayCostNet();
01453         }
01454 
01455         //P
01456         // basket total prices
01457         $this->dprice = $this->_oPrice->getBruttoPrice();
01458         $this->fprice = $oLang->formatCurrency( $this->dprice, $this->getBasketCurrency() );
01459 
01460         // product info
01461         $this->iCntProducts = $this->getProductsCount();
01462         $this->dCntItems    = $this->getItemsCount();
01463         $this->aVATs        = $this->getProductVats();
01464         $this->aBasketContents = $this->getContents();
01465 
01466         // setting gift card information
01467         $this->giftmessage = $this->getCardMessage();
01468         $this->chosencard  = $this->getCardId();
01469 
01470         $this->oCard = $this->getCard();
01471 
01472         // discount information
01473         // formating discount value
01474         $this->aDiscounts = $this->getDiscounts();
01475         if ( count($this->aDiscounts) > 0 ) {
01476             foreach ($this->aDiscounts as $oDiscount) {
01477                 $oDiscount->fDiscount = $oLang->formatCurrency( $oDiscount->dDiscount, $this->getBasketCurrency() );
01478             }
01479         }
01480         $this->dDiscount  = $this->getTotalDiscount()->getBruttoPrice();
01481 
01482         // voucher info
01483         $this->aVouchers = $this->getVouchers();
01484         $this->dVoucherDiscount = $this->getVoucherDiscValue();
01485         $this->fVoucherDiscount = $oLang->formatCurrency( $this->dVoucherDiscount, $this->getBasketCurrency() );
01486         $this->dSkippedDiscount = $this->hasSkipedDiscount();
01487 
01488     }
01489 
01490 
01496     protected function _canSaveBasket()
01497     {
01498         $blCanSave = !$this->getConfig()->getConfigParam( 'blPerfNoBasketSaving' );
01499         return $blCanSave;
01500     }
01501 
01507     public function load()
01508     {
01509         $oUser = $this->getBasketUser();
01510         if ( !$oUser ) {
01511             return;
01512         }
01513 
01514         $oBasket = $oUser->getBasket( 'savedbasket' );
01515 
01516         // restoring from saved history
01517         $aSavedItems = $oBasket->getItems();
01518         foreach ( $aSavedItems as $oItem ) {
01519             try {
01520                 $oSelList = $oItem->getSelList();
01521 
01522                 $this->addToBasket( $oItem->oxuserbasketitems__oxartid->value, $oItem->oxuserbasketitems__oxamount->value, $oSelList, $oItem->getPersParams(), true );
01523             } catch( oxArticleException $oEx ) {
01524                 // caught and ignored
01525             }
01526         }
01527     }
01528 
01534     protected function _save()
01535     {
01536         if ( $this->_canSaveBasket() ) {
01537 
01538             if ( $oUser = $this->getBasketUser() ) {
01539                 //first delete all contents
01540                 //#2039
01541                 $oSavedBasket = $oUser->getBasket( 'savedbasket' );
01542                 $oSavedBasket->delete();
01543 
01544                 //then save
01545                 foreach ( $this->_aBasketContents as $oBasketItem ) {
01546                     $oSavedBasket->addItemToBasket( $oBasketItem->getProductId(), $oBasketItem->getAmount(), $oBasketItem->getSelList(), true, $oBasketItem->getPersParams() );
01547                 }
01548             }
01549         }
01550     }
01551 
01563     /*
01564     protected function _addItemToSavedBasket( $sProductId , $dAmount, $aSel, $blOverride = false, $aPersParam = null )
01565     {
01566         // updating basket history
01567         if ( $oUser = $this->getBasketUser() ) {
01568             $oUser->getBasket( 'savedbasket' )->addItemToBasket( $sProductId, $dAmount, $aSel, $blOverride, $aPersParam );
01569         }
01570     }*/
01571 
01579     protected function _deleteSavedBasket()
01580     {
01581         // deleting basket if session user available
01582         if ( $oUser = $this->getBasketUser() ) {
01583             $oUser->getBasket( 'savedbasket' )->delete();
01584         }
01585 
01586         // basket exclude
01587         if ( $this->getConfig()->getConfigParam( 'blBasketExcludeEnabled' )) {
01588             $this->setBasketRootCatId(null);
01589         }
01590     }
01591 
01597     protected function _findDelivCountry()
01598     {
01599         $myConfig = $this->getConfig();
01600         $oUser    = $this->getBasketUser();
01601 
01602         $sDelivCountry = null;
01603 
01604         if ( !$oUser ) {
01605             // don't calculate if not logged in unless specified otherwise
01606             $aHomeCountry = $myConfig->getConfigParam( 'aHomeCountry' );
01607             if ( $myConfig->getConfigParam( 'blCalculateDelCostIfNotLoggedIn' ) && is_array( $aHomeCountry ) ) {
01608                 $sDelivCountry = current( $aHomeCountry );
01609             }
01610         } else {
01611 
01612             // ok, logged in
01613             if ( $sCountryId = $myConfig->getGlobalParameter( 'delcountryid' ) ) {
01614                 $sDelivCountry = $sCountryId;
01615             } elseif ( $sAddressId = oxConfig::getParameter( 'deladrid' ) ) {
01616 
01617                 $oDelAdress = oxNew( 'oxaddress' );
01618                 if ( $oDelAdress->load( $sAddressId ) ) {
01619                     $sDelivCountry = $oDelAdress->oxaddress__oxcountryid->value;
01620                 }
01621             }
01622 
01623             // still not found ?
01624             if ( !$sDelivCountry ) {
01625                 $sDelivCountry = $oUser->oxuser__oxcountryid->value;
01626             }
01627         }
01628 
01629         return $sDelivCountry;
01630     }
01631 
01637     public function deleteBasket()
01638     {
01639         $this->_aBasketContents = array();
01640         $this->getSession()->delBasket();
01641 
01642         if ($this->getConfig()->getConfigParam( 'blPsBasketReservationEnabled' )) {
01643             $this->getSession()->getBasketReservations()->discardReservations();
01644         }
01645 
01646         // merging basket history
01647         if ( !$this->getConfig()->getConfigParam( 'blPerfNoBasketSaving' ) ) {
01648             $this->_deleteSavedBasket();
01649         }
01650     }
01651 
01659     public function setPayment( $sPaymentId = null )
01660     {
01661         $this->_sPaymentId = $sPaymentId;
01662     }
01663 
01669     public function getPaymentId()
01670     {
01671         if ( !$this->_sPaymentId ) {
01672              $this->_sPaymentId = oxConfig::getParameter( 'paymentid' );
01673         }
01674         return $this->_sPaymentId;
01675     }
01676 
01684     public function setShipping( $sShippingSetId = null )
01685     {
01686         $this->_sShippingSetId = $sShippingSetId;
01687         oxSession::setVar( 'sShipSet', $sShippingSetId );
01688     }
01689 
01697     public function setDeliveryPrice( $oShippingPrice = null )
01698     {
01699         $this->_oDeliveryPrice = $oShippingPrice;
01700     }
01701 
01707     public function getShippingId()
01708     {
01709         if ( !$this->_sShippingSetId ) {
01710              $this->_sShippingSetId = oxConfig::getParameter( 'sShipSet' );
01711         }
01712 
01713         $sActPaymentId = $this->getPaymentId();
01714         // setting default if none is set
01715         if ( !$this->_sShippingSetId && $sActPaymentId != 'oxempty' ) {
01716             $oUser = $this->getUser();
01717 
01718             // choosing first preferred delivery set
01719             list( , $sActShipSet ) = oxDeliverySetList::getInstance()->getDeliverySetData( null, $oUser, $this );
01720             // in case nothing was found and no user set - choosing default
01721             $this->_sShippingSetId = $sActShipSet ? $sActShipSet : ( $oUser ? null : 'oxidstandard' );
01722         } elseif ( !$this->isAdmin() && $sActPaymentId == 'oxempty' ) {
01723             // in case 'oxempty' is payment id - delivery set must be reset
01724             $this->_sShippingSetId = null;
01725         }
01726 
01727         return $this->_sShippingSetId;
01728     }
01729 
01735     public function getBasketArticles()
01736     {
01737         $aBasketArticles = array();
01738 
01739         foreach ( $this->_aBasketContents as $sItemKey => $oBasketItem ) {
01740             try {
01741                 $oProduct = $oBasketItem->getArticle();
01742 
01743                 if ( $this->getConfig()->getConfigParam( 'bl_perfLoadSelectLists' ) ) {
01744                     // marking chosen select list
01745                     $aSelList = $oBasketItem->getSelList();
01746                     if ( is_array( $aSelList ) && ( $aSelectlist = $oProduct->getSelectLists( $sItemKey ) ) ) {
01747                         reset( $aSelList );
01748                         while ( list( $conkey, $iSel ) = each( $aSelList ) ) {
01749                             $aSelectlist[$conkey][$iSel]->selected = 1;
01750                         }
01751                         $oProduct->setSelectlist( $aSelectlist );
01752                     }
01753                 }
01754             } catch ( oxNoArticleException $oEx ) {
01755                 oxUtilsView::getInstance()->addErrorToDisplay( $oEx );
01756                 $this->removeItem( $sItemKey );
01757                 $this->calculateBasket( true );
01758                 continue;
01759             } catch ( oxArticleInputException $oEx ) {
01760                 oxUtilsView::getInstance()->addErrorToDisplay( $oEx );
01761                 $this->removeItem( $sItemKey );
01762                 $this->calculateBasket( true );
01763                 continue;
01764             }
01765 
01766             $aBasketArticles[$sItemKey] = $oProduct;
01767         }
01768         return $aBasketArticles;
01769     }
01770 
01776     public function getDiscountProductsPrice()
01777     {
01778         return $this->_oDiscountProductsPriceList;
01779     }
01780 
01786     public function getProductsPrice()
01787     {
01788         if ( is_null($this->_oProductsPriceList) ) {
01789             $this->_oProductsPriceList = oxNew( 'oxPriceList' );
01790         }
01791 
01792         return $this->_oProductsPriceList;
01793     }
01794 
01800     public function getPrice()
01801     {
01802         if ( is_null($this->_oPrice) ) {
01803             $this->_oPrice = oxNew( 'oxprice' );
01804         }
01805 
01806         return $this->_oPrice;
01807     }
01808 
01815     public function getOrderId()
01816     {
01817         return $this->_sOrderId;
01818     }
01819 
01827     public function setOrderId( $sId )
01828     {
01829         $this->_sOrderId = $sId;
01830     }
01831 
01840     public function getCosts( $sId = null )
01841     {
01842         // if user want some specific cost - return it
01843         if ( $sId ) {
01844             return isset( $this->_aCosts[$sId] )?$this->_aCosts[$sId]:null;
01845         }
01846         return $this->_aCosts;
01847     }
01848 
01854     public function getVouchers()
01855     {
01856         return $this->_aVouchers;
01857     }
01858 
01864     public function getProductsCount()
01865     {
01866         return $this->_iProductsCnt;
01867     }
01868 
01874     public function getItemsCount()
01875     {
01876         return $this->_dItemsCnt;
01877     }
01878 
01884     public function getWeight()
01885     {
01886         return $this->_dWeight;
01887     }
01888 
01894     public function getContents()
01895     {
01896         return $this->_aBasketContents;
01897     }
01898 
01906     public function getProductVats( $blFormatCurrency = true)
01907     {
01908         if ( !$this->_oNotDiscountedProductsPriceList ) {
01909             return array();
01910         }
01911 
01912         $aVats = $this->_oNotDiscountedProductsPriceList->getVatInfo();
01913 
01914         $oUtils = oxUtils::getInstance();
01915         foreach ( $this->_aDiscountedVats as $sKey => $dVat ) {
01916             // add prices of the same discounts
01917             $aVats[$sKey] += $oUtils->fRound( $dVat, $this->_oCurrency);
01918         }
01919 
01920         if ( $blFormatCurrency ) {
01921             $oLang = oxLang::getInstance();
01922             foreach ( $aVats as $sKey => $dVat ) {
01923                 $aVats[$sKey] = $oLang->formatCurrency( $dVat, $this->getBasketCurrency() );
01924             }
01925         }
01926 
01927         return $aVats;
01928     }
01929 
01935     public function getDiscountedNettoPrice()
01936     {
01937         if ( $this->_oNotDiscountedProductsPriceList ) {
01938             return $this->_dDiscountedProductNettoPrice + $this->_oNotDiscountedProductsPriceList->getNettoSum();
01939         }
01940         return false;
01941     }
01942 
01950     public function setCardMessage( $sMessage )
01951     {
01952         $this->_sCardMessage = $sMessage;
01953     }
01954 
01960     public function getCardMessage()
01961     {
01962         return $this->_sCardMessage;
01963     }
01964 
01972     public function setCardId( $sCardId )
01973     {
01974         $this->_sCardId = $sCardId;
01975     }
01976 
01982     public function getCardId()
01983     {
01984         return $this->_sCardId;
01985     }
01986 
01992     public function getCard()
01993     {
01994         $oCard = null;
01995         if ( $sCardId = $this->getCardId() ) {
01996             $oCard = oxNew( 'oxwrapping' );
01997             $oCard->load( $sCardId );
01998         }
01999         return $oCard;
02000     }
02001 
02007     public function getTotalDiscount()
02008     {
02009         return $this->_oTotalDiscount;
02010     }
02011 
02017     public function getDiscounts()
02018     {
02019         if ( $this->getTotalDiscount() && $this->getTotalDiscount()->getBruttoPrice() == 0 && count($this->_aItemDiscounts) == 0) {
02020             return null;
02021         }
02022 
02023         return array_merge($this->_aItemDiscounts, $this->_aDiscounts);
02024     }
02025 
02031     public function getVoucherDiscount()
02032     {
02033         if ($this->getConfig()->getConfigParam( 'bl_showVouchers' )) {
02034             return $this->_oVoucherDiscount;
02035         }
02036         return null;
02037     }
02038 
02046     public function setBasketCurrency( $oCurrency )
02047     {
02048         $this->_oCurrency = $oCurrency;
02049     }
02050 
02056     public function getBasketCurrency()
02057     {
02058         if ( $this->_oCurrency === null ) {
02059             $this->_oCurrency = $this->getConfig()->getActShopCurrencyObject();
02060         }
02061 
02062         return $this->_oCurrency;
02063     }
02064 
02072     public function setSkipVouchersChecking( $blSkipChecking = null )
02073     {
02074         $this->_blSkipVouchersAvailabilityChecking = $blSkipChecking;
02075     }
02076 
02082     public function hasSkipedDiscount()
02083     {
02084         return $this->_blSkipDiscounts;
02085     }
02086 
02094     public function setSkipDiscounts( $blSkip )
02095     {
02096         $this->_blSkipDiscounts = $blSkip;
02097     }
02098 
02104     public function getProductsNetPrice()
02105     {
02106         return oxLang::getInstance()->formatCurrency( $this->getDiscountedNettoPrice(), $this->getBasketCurrency() );
02107     }
02108 
02114     public function getFProductsPrice()
02115     {
02116         if ( $this->_oProductsPriceList ) {
02117             return oxLang::getInstance()->formatCurrency( $this->_oProductsPriceList->getBruttoSum(), $this->getBasketCurrency() );
02118         }
02119         return null;
02120     }
02121 
02127     public function getDelCostVatPercent()
02128     {
02129         return $this->getCosts( 'oxdelivery' )->getVat();
02130     }
02131 
02137     public function getDelCostVat()
02138     {
02139         $dDelVAT = $this->getCosts( 'oxdelivery' )->getVatValue();
02140         if ( $dDelVAT > 0 ) {
02141             return oxLang::getInstance()->formatCurrency( $dDelVAT, $this->getBasketCurrency() );
02142         }
02143         return false;
02144     }
02145 
02151     public function getDelCostNet()
02152     {
02153         if ( $this->getBasketUser() || $this->getConfig()->getConfigParam( 'blCalculateDelCostIfNotLoggedIn' ) ) {
02154             return oxLang::getInstance()->formatCurrency( $this->getCosts( 'oxdelivery' )->getNettoPrice(), $this->getBasketCurrency() );
02155         }
02156         return false;
02157     }
02158 
02164     public function getPayCostVatPercent()
02165     {
02166         return $this->getCosts( 'oxpayment' )->getVat();
02167     }
02168 
02174     public function getPayCostVat()
02175     {
02176         $dPayVAT = $this->getCosts( 'oxpayment' )->getVatValue();
02177         if ( $dPayVAT > 0 ) {
02178             return oxLang::getInstance()->formatCurrency( $dPayVAT, $this->getBasketCurrency() );
02179         }
02180         return false;
02181     }
02182 
02188     public function getPayCostNet()
02189     {
02190         return oxLang::getInstance()->formatCurrency( $this->getCosts( 'oxpayment' )->getNettoPrice(), $this->getBasketCurrency() );
02191     }
02192 
02198     public function getPaymentCosts()
02199     {
02200         return $this->getCosts( 'oxpayment' )->getBruttoPrice();
02201     }
02202 
02208     public function getFPaymentCosts()
02209     {
02210         $oPaymentCost = $this->getCosts( 'oxpayment' );
02211 
02212         if ( $oPaymentCost && $oPaymentCost->getBruttoPrice() ) {
02213             return oxLang::getInstance()->formatCurrency( $oPaymentCost->getBruttoPrice(), $this->getBasketCurrency() );
02214         }
02215         return false;
02216     }
02217 
02223     public function getVoucherDiscValue()
02224     {
02225         if ( $this->getVoucherDiscount() ) {
02226             return $this->getVoucherDiscount()->getBruttoPrice();
02227         }
02228         return false;
02229     }
02230 
02236     public function getWrappCostVatPercent()
02237     {
02238         return $this->getCosts( 'oxwrapping' )->getVat();
02239     }
02240 
02246     public function getWrappCostVat()
02247     {
02248         $dWrappVAT = $this->getCosts( 'oxwrapping' )->getVatValue();
02249         if ( $dWrappVAT > 0 ) {
02250             return oxLang::getInstance()->formatCurrency( $dWrappVAT, $this->getBasketCurrency() );
02251         }
02252         return false;
02253 
02254     }
02255 
02261     public function getWrappCostNet()
02262     {
02263         $dWrappNet = $this->getCosts( 'oxwrapping' )->getNettoPrice();
02264         if ( $dWrappNet > 0 ) {
02265             return  oxLang::getInstance()->formatCurrency( $dWrappNet, $this->getBasketCurrency() );
02266         }
02267         return false;
02268     }
02269 
02275     public function getFWrappingCosts()
02276     {
02277         $oWrappingCost = $this->getCosts( 'oxwrapping' );
02278         if ( $oWrappingCost && $oWrappingCost->getBruttoPrice() ) {
02279             return oxLang::getInstance()->formatCurrency( $oWrappingCost->getBruttoPrice(), $this->getBasketCurrency() );
02280         }
02281         return false;
02282     }
02283 
02289     public function getFPrice()
02290     {
02291         return oxLang::getInstance()->formatCurrency( $this->getPrice()->getBruttoPrice(), $this->getBasketCurrency() );
02292     }
02293 
02299     public function getFDeliveryCosts()
02300     {
02301         $oDeliveryCost = $this->getCosts( 'oxdelivery' );
02302         if ( $oDeliveryCost && $oDeliveryCost->getBruttoPrice()) {
02303             return oxLang::getInstance()->formatCurrency( $oDeliveryCost->getBruttoPrice(), $this->getBasketCurrency() );
02304         }
02305         return false;
02306     }
02307 
02313     public function getDeliveryCosts()
02314     {
02315         if ( $oDeliveryCost = $this->getCosts( 'oxdelivery' ) ) {
02316             return $oDeliveryCost->getBruttoPrice();
02317         }
02318         return false;
02319     }
02320 
02328     public function setTotalDiscount( $dDiscount )
02329     {
02330         $this->_oTotalDiscount = oxNew( 'oxPrice' );
02331         $this->_oTotalDiscount->setBruttoPriceMode();
02332         $this->_oTotalDiscount->add( $dDiscount );
02333     }
02334 
02341     public function getPriceForPayment()
02342     {
02343         $dPrice = $this->getDiscountedProductsBruttoPrice();
02344         //#1905 not discounted products should be included in payment amount calculation
02345         if ( $oPriceList = $this->getNotDiscountProductsPrice() ) {
02346             $dPrice += $oPriceList->getBruttoSum();
02347         }
02348 
02349         // adding delivery price to final price
02350         if ( $oDeliveryPrice = $this->_aCosts['oxdelivery'] ) {
02351             $dPrice += $oDeliveryPrice->getBruttoPrice();
02352         }
02353 
02354         return $dPrice;
02355     }
02356 
02362     public function getDiscountedProductsBruttoPrice()
02363     {
02364         if ( $oProductsPrice = $this->getDiscountProductsPrice() ) {
02365             $dPrice = $oProductsPrice->getBruttoSum();
02366         }
02367 
02368         // substracting total discount
02369         if ( $oPrice = $this->getTotalDiscount() ) {
02370             $dPrice -= $oPrice->getBruttoPrice();
02371         }
02372 
02373         if ( $oVoucherPrice = $this->getVoucherDiscount() ) {
02374             $dPrice -= $oVoucherPrice->getBruttoPrice();
02375         }
02376 
02377         return $dPrice;
02378     }
02379 
02385     public function isBelowMinOrderPrice()
02386     {
02387         $blIsBelowMinOrderPrice = false;
02388         $sConfValue = $this->getConfig()->getConfigParam( 'iMinOrderPrice' );
02389         if ( is_numeric($sConfValue) && $this->getProductsCount() ) {
02390             $dMinOrderPrice = oxPrice::getPriceInActCurrency( ( int ) $sConfValue );
02391             $blIsBelowMinOrderPrice = ($dMinOrderPrice > $this->getDiscountedProductsBruttoPrice());
02392         }
02393 
02394         return $blIsBelowMinOrderPrice;
02395 
02396     }
02397 
02406     public function getArtStockInBasket( $sArtId, $sExpiredArtId = null )
02407     {
02408         $dArtStock = 0;
02409         foreach ( $this->_aBasketContents as $sItemKey => $oOrderArticle ) {
02410             if ( $oOrderArticle && ( $sExpiredArtId == null || $sExpiredArtId != $sItemKey ) ) {
02411                 if ( $oOrderArticle->getArticle()->getId() == $sArtId ) {
02412                     $dArtStock += $oOrderArticle->getAmount();
02413                 }
02414             }
02415         }
02416 
02417         return $dArtStock;
02418     }
02419 
02427     public function canAddProductToBasket( $sProductId )
02428     {
02429         $blCanAdd = null;
02430 
02431         // if basket category is not set..
02432         if ( $this->_sBasketCategoryId === null ) {
02433             $oCat = null;
02434 
02435             // request category
02436             if ( $oView = $this->getConfig()->getActiveView() ) {
02437                 if ( $oCat = $oView->getActCategory() ) {
02438                     if ( !$this->_isProductInRootCategory( $sProductId, $oCat->oxcategories__oxrootid->value ) ) {
02439                         $oCat = null;
02440                     } else {
02441                         $blCanAdd = true;
02442                     }
02443                 }
02444             }
02445 
02446             // product main category
02447             if ( !$oCat ) {
02448                 $oProduct = oxNew( "oxarticle" );
02449                 if ( $oProduct->load( $sProductId ) ) {
02450                     $oCat = $oProduct->getCategory();
02451                 }
02452             }
02453 
02454             // root category id
02455             if ( $oCat ) {
02456                 $this->setBasketRootCatId($oCat->oxcategories__oxrootid->value);
02457             }
02458         }
02459 
02460         // avoiding double check..
02461         if ( $blCanAdd === null ) {
02462             $blCanAdd = $this->_sBasketCategoryId ? $this->_isProductInRootCategory( $sProductId, $this->getBasketRootCatId() ) : true;
02463         }
02464 
02465         return $blCanAdd;
02466     }
02467 
02476     protected function _isProductInRootCategory( $sProductId, $sRootCatId )
02477     {
02478         $sO2CTable = getViewName( 'oxobject2category' );
02479         $sCatTable = getViewName( 'oxcategories' );
02480 
02481         $oDb = oxDb::getDb();
02482         $sParentId  = $oDb->getOne( "select oxparentid from oxarticles where oxid = ".$oDb->quote( $sProductId ) );
02483         $sProductId = $sParentId ? $sParentId : $sProductId;
02484 
02485         $sQ = "select 1 from {$sO2CTable}
02486                  left join {$sCatTable} on {$sCatTable}.oxid = {$sO2CTable}.oxcatnid
02487                  where {$sO2CTable}.oxobjectid = ".$oDb->quote( $sProductId )." and
02488                        {$sCatTable}.oxrootid = ".$oDb->quote( $sRootCatId );
02489 
02490         return (bool) $oDb->getOne( $sQ );
02491     }
02492 
02500     public function setBasketRootCatId($sRoot)
02501     {
02502         $this->_sBasketCategoryId = $sRoot;
02503     }
02504 
02510     public function getBasketRootCatId()
02511     {
02512         return $this->_sBasketCategoryId;
02513     }
02514 
02522     public function setCatChangeWarningState( $blShow )
02523     {
02524         $this->_blShowCatChangeWarning = $blShow;
02525     }
02526 
02532     public function showCatChangeWarning()
02533     {
02534         return $this->_blShowCatChangeWarning;
02535     }
02536 
02544     public function setTsProductId( $sProductId )
02545     {
02546         $this->_sTsProductId = $sProductId;
02547     }
02548 
02554     public function getTsProductId()
02555     {
02556         return $this->_sTsProductId;
02557     }
02558 
02564     public function getFTsProtectionCosts()
02565     {
02566         $oProtectionCost = $this->getCosts( 'oxtsprotection' );
02567         if ( $oProtectionCost && $oProtectionCost->getBruttoPrice() ) {
02568             return oxLang::getInstance()->formatCurrency( $oProtectionCost->getBruttoPrice(), $this->getBasketCurrency() );
02569         }
02570         return false;
02571     }
02572 
02578     public function getTsProtectionVatPercent()
02579     {
02580         return $this->getCosts( 'oxtsprotection' )->getVat();
02581     }
02582 
02588     public function getTsProtectionVat()
02589     {
02590         $dProtectionVAT = $this->getCosts( 'oxtsprotection' )->getVatValue();
02591         if ( $dProtectionVAT > 0 ) {
02592             return oxLang::getInstance()->formatCurrency( $dProtectionVAT, $this->getBasketCurrency() );
02593         }
02594         return false;
02595     }
02596 
02602     public function getTsProtectionNet()
02603     {
02604         return oxLang::getInstance()->formatCurrency( $this->getCosts( 'oxtsprotection' )->getNettoPrice(), $this->getBasketCurrency() );
02605     }
02606 
02612     public function getTsProtectionCosts()
02613     {
02614         $oProtection = $this->getCosts( 'oxtsprotection' );
02615         if ( $oProtection ) {
02616             return $oProtection->getBruttoPrice();
02617         }
02618         return false;
02619     }
02620 
02626     public function getNotDiscountProductsPrice()
02627     {
02628         return $this->_oNotDiscountedProductsPriceList;
02629     }
02630 
02631 }