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 $_blBasketMerged = false;
00118 
00124     protected $_sPaymentId = null;
00125 
00131     protected $_sShippingSetId = null;
00132 
00138     protected $_oUser = null;
00139 
00145     protected $_oTotalDiscount = null;
00146 
00152     protected $_oVoucherDiscount = null;
00153 
00159     protected $_oCurrency = null;
00160 
00166     protected $_blSkipVouchersAvailabilityChecking = null;
00167 
00173     protected $_dDiscountedProductNettoPrice = null;
00174 
00180     protected $_aDiscountedVats = null;
00181 
00187     protected $_blSkipDiscounts = false;
00188 
00194     protected $_oDeliveryPrice = null;
00195 
00201      protected $_blCheckStock = true;
00202 
00208     protected $_blCalcDiscounts = true;
00209 
00215     protected $_sBasketCategoryId = null;
00216 
00222     protected $_blShowCatChangeWarning = false;
00223 
00229     protected $_sTsProductId = null;
00230 
00236     public function isEnabled()
00237     {
00238         return !oxUtils::getInstance()->isSearchEngine();
00239     }
00240 
00250     protected function _changeBasketItemKey($sOldKey, $sNewKey, $value = null)
00251     {
00252         reset($this->_aBasketContents);
00253         $iOldKeyPlace = 0;
00254         while (key($this->_aBasketContents) != $sOldKey && next($this->_aBasketContents)) {
00255             ++$iOldKeyPlace;
00256         }
00257         $aNewCopy = array_merge(
00258             array_slice($this->_aBasketContents, 0, $iOldKeyPlace, true),
00259             array($sNewKey => $value),
00260             array_slice($this->_aBasketContents, $iOldKeyPlace+1, count($this->_aBasketContents)-$iOldKeyPlace, true)
00261         );
00262         $this->_aBasketContents = $aNewCopy;
00263     }
00264 
00280     public function addToBasket( $sProductID, $dAmount, $aSel = null, $aPersParam = null, $blOverride = false, $blBundle = false, $sOldBasketItemId = null )
00281     {
00282         // enabled ?
00283         if ( !$this->isEnabled() )
00284             return null;
00285 
00286         // basket exclude
00287         if ( $this->getConfig()->getConfigParam( 'blBasketExcludeEnabled' ) ) {
00288             if ( !$this->canAddProductToBasket( $sProductID ) ) {
00289                 $this->setCatChangeWarningState( true );
00290                 return null;
00291             } else {
00292                 $this->setCatChangeWarningState( false );
00293             }
00294         }
00295 
00296         $sItemId = $this->getItemKey( $sProductID, $aSel, $aPersParam, $blBundle );
00297         if ( $sOldBasketItemId && ( strcmp( $sOldBasketItemId, $sItemId ) != 0 ) ) {
00298             if ( isset( $this->_aBasketContents[$sItemId] ) ) {
00299                 // we are merging, so params will just go to the new key
00300                 unset( $this->_aBasketContents[$sOldBasketItemId] );
00301                 // do not override stock
00302                 $blOverride = false;
00303             } else {
00304                 // value is null - means isset will fail and real values will be filled
00305                 $this->_changeBasketItemKey( $sOldBasketItemId, $sItemId );
00306             }
00307         }
00308 
00309         // after some checks item must be removed from basket
00310         $blRemoveItem = false;
00311 
00312         // initialting exception storage
00313         $oEx = null;
00314 
00315         if ( isset( $this->_aBasketContents[$sItemId] ) ) {
00316 
00317             //updating existing
00318             try {
00319                 // setting stock check status
00320                 $this->_aBasketContents[$sItemId]->setStockCheckStatus( $this->getStockCheckMode() );
00321                 //validate amount
00322                 //possibly throws exception
00323                 $this->_aBasketContents[$sItemId]->setAmount( $dAmount, $blOverride, $sItemId );
00324             } catch( oxOutOfStockException $oEx ) {
00325                 // rethrow later
00326             }
00327 
00328         } else {
00329             //inserting new
00330             $oBasketItem = oxNew( 'oxbasketitem' );
00331             try {
00332                 $oBasketItem->setStockCheckStatus( $this->getStockCheckMode() );
00333                 $oBasketItem->init( $sProductID, $dAmount, $aSel, $aPersParam, $blBundle );
00334             } catch( oxNoArticleException $oEx ) {
00335                 // in this case that the article does not exist remove the item from the basket by setting its amount to 0
00336                 //$oBasketItem->dAmount = 0;
00337                 $blRemoveItem = true;
00338 
00339             } catch( oxOutOfStockException $oEx ) {
00340                 // rethrow later
00341             } catch ( oxArticleInputException $oEx ) {
00342                 // rethrow later
00343                 $blRemoveItem = true;
00344             }
00345 
00346             $this->_aBasketContents[$sItemId] = $oBasketItem;
00347         }
00348 
00349         //in case amount is 0 removing item
00350         if ( $this->_aBasketContents[$sItemId]->getAmount() == 0 || $blRemoveItem ) {
00351             $this->removeItem( $sItemId );
00352         } elseif ( $blBundle ) {
00353             //marking bundles
00354             $this->_aBasketContents[$sItemId]->setBundle( true );
00355         }
00356 
00357         //calling update method
00358         $this->onUpdate();
00359 
00360         // updating basket history
00361         if ( !$blBundle ) {
00362             $this->_addItemToSavedBasket( $sProductID, $dAmount, $aSel, $blOverride );
00363         }
00364 
00365         if ( $oEx ) {
00366             throw $oEx;
00367         }
00368         return $this->_aBasketContents[$sItemId];
00369     }
00370 
00378     public function addOrderArticleToBasket( $oOrderArticle )
00379     {
00380         // adding only if amount > 0
00381         if ( $oOrderArticle->oxorderarticles__oxamount->value > 0 ) {
00382             $sItemId = $oOrderArticle->getId();
00383 
00384             //inserting new
00385             $this->_aBasketContents[$sItemId] = oxNew( 'oxbasketitem' );
00386             $this->_aBasketContents[$sItemId]->initFromOrderArticle( $oOrderArticle );
00387             $this->_aBasketContents[$sItemId]->setWrapping( $oOrderArticle->oxorderarticles__oxwrapid->value );
00388 
00389             //calling update method
00390             $this->onUpdate();
00391 
00392             return $this->_aBasketContents[$sItemId];
00393         }
00394     }
00395 
00403     public function setStockCheckMode( $blCheck )
00404     {
00405         $this->_blCheckStock = $blCheck;
00406     }
00407 
00413     public function getStockCheckMode()
00414     {
00415         return $this->_blCheckStock;
00416     }
00417 
00430     public function getItemKey( $sProductId, $aSel = null, $aPersParam = null, $blBundle = false, $sAdditionalParam = '' )
00431     {
00432         $aSel = ( $aSel != null) ? $aSel : array (0=>'0');
00433 
00434         $sItemKey = md5( $sProductId.'|'.serialize( $aSel ).'|'.serialize( $aPersParam ).'|'.( int ) $blBundle . '|' . serialize( $sAdditionalParam ) );
00435 
00436         return $sItemKey;
00437     }
00438 
00439 
00447     public function removeItem( $sItemKey )
00448     {
00449         if ($this->getConfig()->getConfigParam( 'blPsBasketReservationEnabled' )) {
00450             if (isset($this->_aBasketContents[$sItemKey])) {
00451                 $sArticleId = $this->_aBasketContents[$sItemKey]->getProductId();
00452                 if ($sArticleId) {
00453                     $this->getSession()
00454                             ->getBasketReservations()
00455                             ->discardArticleReservation($sArticleId);
00456                 }
00457             }
00458         }
00459         unset( $this->_aBasketContents[$sItemKey] );
00460 
00461         // basket exclude
00462         if ( !count($this->_aBasketContents) && $this->getConfig()->getConfigParam( 'blBasketExcludeEnabled' ) ) {
00463             $this->setBasketRootCatId(null);
00464         }
00465     }
00466 
00472     protected function _clearBundles()
00473     {
00474         reset( $this->_aBasketContents );
00475         while ( list( $sItemKey, $oBasketItem ) = each( $this->_aBasketContents ) ) {
00476             if ( $oBasketItem->isBundle() ) {
00477                 $this->removeItem( $sItemKey );
00478             }
00479         }
00480     }
00481 
00489     protected function _getArticleBundles( $oBasketItem )
00490     {
00491         $aBundles = array();
00492 
00493         if ( $oBasketItem->isBundle() ) {
00494             return $aBundles;
00495         }
00496 
00497         $oArticle = $oBasketItem->getArticle();
00498         if ( $oArticle && $oArticle->oxarticles__oxbundleid->value ) {
00499             $aBundles[$oArticle->oxarticles__oxbundleid->value] = 1;
00500         }
00501 
00502         return $aBundles;
00503     }
00504 
00512     protected function _getItemBundles( $oBasketItem )
00513     {
00514         if ( $oBasketItem->isBundle() ) {
00515             return array();
00516         }
00517 
00518         $aBundles = array();
00519 
00520         // does this object still exists ?
00521         if ( $oArticle = $oBasketItem->getArticle() ) {
00522             $aDiscounts = oxDiscountList::getInstance()->getBasketItemBundleDiscounts( $oArticle, $this, $this->getBasketUser() );
00523 
00524             foreach ( $aDiscounts as $oDiscount ) {
00525 
00526                 //init array element
00527                 if ( !isset( $aBundles[$oDiscount->oxdiscount__oxitmartid->value] ) ) {
00528                     $aBundles[$oDiscount->oxdiscount__oxitmartid->value] = 0;
00529                 }
00530 
00531                 $aBundles[$oDiscount->oxdiscount__oxitmartid->value] += $oDiscount->getBundleAmount( $oBasketItem->getAmount() );
00532 
00533             }
00534         }
00535 
00536         return $aBundles;
00537     }
00538 
00544     protected function _getBasketBundles()
00545     {
00546         $aBundles = array();
00547         $aDiscounts = oxDiscountList::getInstance()->getBasketBundleDiscounts( $this, $this->getBasketUser() );
00548 
00549         // calculating amount of non bundled/discount items
00550         $dAmount = 0;
00551         foreach ( $this->_aBasketContents as $oBasketItem ) {
00552             if ( !( $oBasketItem->isBundle() || $oBasketItem->isDiscountArticle() ) ) {
00553                 $dAmount += $oBasketItem->getAmount();
00554             }
00555         }
00556 
00557         foreach ( $aDiscounts as $oDiscount ) {
00558             if ($oDiscount->oxdiscount__oxitmartid->value) {
00559                 if ( !isset( $aBundles[$oDiscount->oxdiscount__oxitmartid->value] ) ) {
00560                     $aBundles[$oDiscount->oxdiscount__oxitmartid->value] = 0;
00561                 }
00562 
00563                 $aBundles[$oDiscount->oxdiscount__oxitmartid->value] += $oDiscount->getBundleAmount( $dAmount );
00564             }
00565         }
00566 
00567         return $aBundles;
00568     }
00569 
00576     protected function _addBundles()
00577     {
00578         // iterating through articles and binding bundles
00579         foreach ( $this->_aBasketContents as $key => $oBasketItem ) {
00580             try {
00581                 // adding discount type bundles
00582                 if ( !$oBasketItem->isDiscountArticle() && !$oBasketItem->isBundle() ) {
00583                     $aBundles = $this->_getItemBundles( $oBasketItem );
00584                 } else {
00585                     continue;
00586                 }
00587 
00588                 $this->_addBundlesToBasket( $aBundles );
00589 
00590                     // adding item type bundles
00591                     $aBundles = $this->_getArticleBundles( $oBasketItem );
00592 
00593                     // adding bundles to basket
00594                     $this->_addBundlesToBasket( $aBundles );
00595             } catch ( oxNoArticleException $oEx ) {
00596                 $this->removeItem( $key );
00597                 oxUtilsView::getInstance()->addErrorToDisplay( $oEx );
00598             } catch( oxArticleInputException $oEx ) {
00599                 $this->removeItem( $key );
00600                 oxUtilsView::getInstance()->addErrorToDisplay( $oEx );
00601             }
00602         }
00603 
00604         // adding global basket bundles
00605         if ( $aBundles = $this->_getBasketBundles() ) {
00606             $this->_addBundlesToBasket( $aBundles );
00607         }
00608 
00609     }
00610 
00618     protected function _addBundlesToBasket( $aBundles )
00619     {
00620         foreach ( $aBundles as $sBundleId => $dAmount ) {
00621             try {
00622                 if ( $oBundleItem = $this->addToBasket( $sBundleId, $dAmount, null, null, true, true ) ) {
00623                     $oBundleItem->setAsDiscountArticle( true );
00624                 }
00625             } catch(oxArticleException $oEx) {
00626                 // caught and ignored
00627             }
00628         }
00629 
00630     }
00631 
00637     protected function _calcItemsPrice()
00638     {
00639         // resetting
00640         $this->setSkipDiscounts( false );
00641         $this->_iProductsCnt = 0; // count different types
00642         $this->_dItemsCnt    = 0; // count of item units
00643         $this->_dWeight      = 0; // basket weight
00644 
00645         // resetting
00646         $this->_aItemDiscounts = array();
00647 
00648         $this->_oProductsPriceList = oxNew( 'oxpricelist' );
00649         $this->_oDiscountProductsPriceList = oxNew( 'oxpricelist' );
00650         $this->_oNotDiscountedProductsPriceList = oxNew( 'oxpricelist' );
00651 
00652         $oDiscountList = oxDiscountList::getInstance();
00653 
00654         foreach ( $this->_aBasketContents as $oBasketItem ) {
00655             $this->_iProductsCnt++;
00656             $this->_dItemsCnt += $oBasketItem->getAmount();
00657             $this->_dWeight   += $oBasketItem->getWeight();
00658 
00659             if ( !$oBasketItem->isDiscountArticle() && ( $oArticle = $oBasketItem->getArticle() ) ) {
00660                 $oBasketPrice = $oArticle->getBasketPrice( $oBasketItem->getAmount(), $oBasketItem->getSelList(), $this );
00661                 $oBasketItem->setPrice( $oBasketPrice );
00662                 //P adding product price
00663                 $this->_oProductsPriceList->addToPriceList( $oBasketItem->getPrice() );
00664 
00665                 $oBasketPrice->setBruttoPriceMode();
00666                 if ( !$oArticle->skipDiscounts() && $this->canCalcDiscounts() ) {
00667                     // apply basket type discounts
00668                     $aItemDiscounts = $oDiscountList->applyBasketDiscounts( $oBasketPrice, $oDiscountList->getBasketItemDiscounts( $oArticle, $this, $this->getBasketUser() ), $oBasketItem->getAmount() );
00669                     if ( is_array($this->_aItemDiscounts) && is_array($aItemDiscounts) ) {
00670                         $this->_aItemDiscounts = $this->_mergeDiscounts( $this->_aItemDiscounts, $aItemDiscounts);
00671                     }
00672                 } else {
00673                     $oBasketItem->setSkipDiscounts( true );
00674                     $this->setSkipDiscounts( true );
00675                 }
00676                 $oBasketPrice->multiply( $oBasketItem->getAmount() );
00677 
00678                 //P collect discount values for basket items which are discountable
00679                 if ( !$oArticle->skipDiscounts() ) {
00680                     $this->_oDiscountProductsPriceList->addToPriceList( $oBasketPrice );
00681                 } else {
00682                     $this->_oNotDiscountedProductsPriceList->addToPriceList( $oBasketPrice );
00683                     $oBasketItem->setSkipDiscounts( true );
00684                     $this->setSkipDiscounts( true );
00685                 }
00686             } elseif ( $oBasketItem->isBundle() ) {
00687                 // if bundles price is set to zero
00688                 $oPrice = oxNew( "oxprice");
00689                 $oBasketItem->setPrice( $oPrice );
00690             }
00691         }
00692     }
00693 
00701     public function setDiscountCalcMode( $blCalcDiscounts )
00702     {
00703         $this->_blCalcDiscounts = $blCalcDiscounts;
00704     }
00705 
00711     public function canCalcDiscounts()
00712     {
00713         return $this->_blCalcDiscounts;
00714     }
00715 
00725     protected function _mergeDiscounts( $aDiscounts, $aItemDiscounts)
00726     {
00727         foreach ( $aItemDiscounts as $sKey => $oDiscount ) {
00728             // add prices of the same discounts
00729             if ( array_key_exists ($sKey, $aDiscounts) ) {
00730                 $aDiscounts[$sKey]->dDiscount += $oDiscount->dDiscount;
00731             } else {
00732                 $aDiscounts[$sKey] = $oDiscount;
00733             }
00734         }
00735         return $aDiscounts;
00736     }
00737 
00743     protected function _calcDeliveryCost()
00744     {
00745         if ( $this->_oDeliveryPrice !== null ) {
00746             return $this->_oDeliveryPrice;
00747         }
00748         $myConfig  = $this->getConfig();
00749         $oDeliveryPrice = oxNew( 'oxprice' );
00750         $oDeliveryPrice->setBruttoPriceMode();
00751 
00752         // don't calculate if not logged in
00753         $oUser = $this->getBasketUser();
00754 
00755         if ( !$oUser && !$myConfig->getConfigParam( 'blCalculateDelCostIfNotLoggedIn' ) ) {
00756             return $oDeliveryPrice;
00757         }
00758 
00759         // VAT for delivery ?
00760         $fDelVATPercent = 0;
00761         if ( $myConfig->getConfigParam( 'blCalcVATForDelivery' ) ) {
00762             $fDelVATPercent = $this->getMostUsedVatPercent();
00763             $oDeliveryPrice->setVat( $fDelVATPercent );
00764         }
00765 
00766         // list of active delivery costs
00767         if ( $myConfig->getConfigParam('bl_perfLoadDelivery') ) {
00768             $aDeliveryList = oxDeliveryList::getInstance()->getDeliveryList( $this,
00769                                         $oUser,
00770                                         $this->_findDelivCountry(),
00771                                         $this->getShippingId()
00772                                     );
00773 
00774             if ( count( $aDeliveryList ) > 0 ) {
00775                 foreach ( $aDeliveryList as $oDelivery ) {
00776                     //debug trace
00777                     if ( $myConfig->getConfigParam( 'iDebug' ) == 5 ) {
00778                         echo( "DelCost : ".$oDelivery->oxdelivery__oxtitle->value."<br>" );
00779                     }
00780                     $oDeliveryPrice->addPrice( $oDelivery->getDeliveryPrice( $fDelVATPercent ) );
00781                 }
00782             }
00783         }
00784 
00785         return $oDeliveryPrice;
00786     }
00787 
00793     public function getBasketUser()
00794     {
00795         if ( $this->_oUser == null ) {
00796             return $this->getUser();
00797         }
00798 
00799         return $this->_oUser;
00800     }
00801 
00809     public function setBasketUser( $oUser )
00810     {
00811         $this->_oUser = $oUser;
00812     }
00813 
00814     //P
00820     public function getMostUsedVatPercent()
00821     {
00822         return $this->_oProductsPriceList->getMostUsedVatPercent();
00823     }
00824 
00825     //P
00832     protected function _calcTotalPrice()
00833     {
00834         // 1. add products price
00835         $dprice = $this->_oProductsPriceList->getBruttoSum();
00836         $this->_oPrice->setPrice( $dprice );
00837 
00838         // 2. substract discounts
00839         if ( $dprice ) {
00840 
00841             // 2.1 applying basket item discounts
00842             foreach ( $this->_aItemDiscounts as $oDiscount ) {
00843 
00844                 // skipping bundle discounts
00845                 if ( $oDiscount->sType == 'itm' ) {
00846                     continue;
00847                 }
00848                 $this->_oPrice->subtract( $oDiscount->dDiscount );
00849             }
00850 
00851             // 2.2 applying basket discounts
00852             $this->_oPrice->subtract( $this->_oTotalDiscount->getBruttoPrice() );
00853 
00854             // 2.3 applying voucher discounts
00855             if ($oVoucherDisc = $this->getVoucherDiscount()) {
00856                 $this->_oPrice->subtract( $oVoucherDisc->getBruttoPrice() );
00857             }
00858         }
00859 
00860         // 2.3 add delivery cost
00861         if ( isset( $this->_aCosts['oxdelivery'] ) ) {
00862             $this->_oPrice->add( $this->_aCosts['oxdelivery']->getBruttoPrice() );
00863         }
00864 
00865         // 2.4 add wrapping price
00866         if ( isset( $this->_aCosts['oxwrapping'] ) ) {
00867             $this->_oPrice->add( $this->_aCosts['oxwrapping']->getBruttoPrice() );
00868         }
00869 
00870         // 2.5 add payment price
00871         if ( isset( $this->_aCosts['oxpayment'] ) ) {
00872             $this->_oPrice->add( $this->_aCosts['oxpayment']->getBruttoPrice() );
00873         }
00874 
00875         // 2.6 add TS protection price
00876         if ( isset( $this->_aCosts['oxtsprotection'] ) ) {
00877             $this->_oPrice->add( $this->_aCosts['oxtsprotection']->getBruttoPrice() );
00878         }
00879 
00880     }
00881 
00889     public function setVoucherDiscount( $dDiscount )
00890     {
00891         $this->_oVoucherDiscount = oxNew( 'oxPrice' );
00892         $this->_oVoucherDiscount->setBruttoPriceMode();
00893         $this->_oVoucherDiscount->add( $dDiscount );
00894     }
00895 
00901     protected function _calcVoucherDiscount()
00902     {
00903         if ( $this->getConfig()->getConfigParam( 'bl_showVouchers' ) && ($this->_oVoucherDiscount === null || ( $this->_blUpdateNeeded && !$this->isAdmin() ) ) ) {
00904 
00905             $this->_oVoucherDiscount = oxNew( 'oxPrice' );
00906             $this->_oVoucherDiscount->setBruttoPriceMode();
00907 
00908 
00909             // calculating price to apply discount
00910             $dPrice = $this->_oDiscountProductsPriceList->getBruttoSum() - $this->_oTotalDiscount->getBruttoPrice();
00911 
00912             // recalculating
00913             if ( count( $this->_aVouchers ) ) {
00914                 $oLang = oxLang::getInstance();
00915                 foreach ( $this->_aVouchers as $sVoucherId => $oStdVoucher ) {
00916                     $oVoucher = oxNew( 'oxvoucher' );
00917                     try { // checking
00918                         $oVoucher->load( $oStdVoucher->sVoucherId );
00919 
00920                         if ( !$this->_blSkipVouchersAvailabilityChecking ) {
00921                             $oVoucher->checkBasketVoucherAvailability( $this->_aVouchers, $dPrice );
00922                             $oVoucher->checkUserAvailability( $this->getBasketUser() );
00923                         }
00924 
00925                         // assigning real voucher discount value as this is the only place where real value is calculated
00926                         $dVoucherdiscount = $oVoucher->getDiscountValue( $dPrice );
00927 
00928                         // acumulating discount value
00929                         $this->_oVoucherDiscount->add( $dVoucherdiscount );
00930 
00931                         // collecting formatted for preview
00932                         $oStdVoucher->fVoucherdiscount = $oLang->formatCurrency( $dVoucherdiscount, $this->getBasketCurrency() );
00933                         $oStdVoucher->dVoucherdiscount = $dVoucherdiscount;
00934 
00935                         // substracting voucher discount
00936                         $dPrice -= $dVoucherdiscount;
00937                     } catch ( oxVoucherException $oEx ) {
00938 
00939                         // removing voucher on error
00940                         $oVoucher->unMarkAsReserved();
00941                         unset( $this->_aVouchers[$sVoucherId] );
00942 
00943                         // storing voucher error info
00944                         oxUtilsView::getInstance()->addErrorToDisplay($oEx, false, true);
00945                     }
00946                 }
00947             }
00948         }
00949     }
00950 
00951     //V
00958     protected function _applyDiscounts()
00959     {
00960         $dBruttoPrice = 0;
00961         $this->_aDiscountedVats = array();
00962         if ( $oPriceList = $this->getDiscountProductsPrice() ) {
00963             $dBruttoPrice = $oPriceList->getBruttoSum();
00964             $this->_aDiscountedVats = $oPriceList->getVatInfo();
00965         }
00966 
00967         //apply discounts for brutto price
00968         $dDiscountedBruttoPrice = $this->getDiscountedProductsBruttoPrice();
00969         $oTotalDiscount   = $this->getTotalDiscount();
00970         $oVoucherDiscount = $this->getVoucherDiscount();
00971 
00972         //apply discount for VATs
00973         if ( $dBruttoPrice &&
00974              ( ( $oTotalDiscount && $oTotalDiscount->getBruttoPrice() ) ||
00975                ( $oVoucherDiscount && $oVoucherDiscount->getBruttoPrice() )
00976              )
00977            ) {
00978             $dPercent = ( $dDiscountedBruttoPrice / $dBruttoPrice) * 100;
00979             foreach ( $this->_aDiscountedVats as $sKey => $dVat ) {
00980                 $this->_aDiscountedVats[$sKey] = oxPrice::percent( $dVat, $dPercent);
00981             }
00982         }
00983 
00984         $oUtils = oxUtils::getInstance();
00985         $dDiscVatSum = 0;
00986         foreach ( $this->_aDiscountedVats as $dVat ) {
00987             $dDiscVatSum += $oUtils->fRound( -$dVat, $this->_oCurrency);
00988         }
00989         //calculate netto price with discounts
00990         $this->_dDiscountedProductNettoPrice = $dDiscountedBruttoPrice + $dDiscVatSum;
00991     }
00992 
00998     protected function _calcBasketDiscount()
00999     {
01000         // resetting
01001         $this->_aDiscounts = array();
01002 
01003         // P using prices sum which has discount, not sum of skipped discounts
01004         $dOldprice = $this->_oDiscountProductsPriceList->getBruttoSum();
01005 
01006         // add basket discounts
01007         $aDiscounts = oxDiscountList::getInstance()->getBasketDiscounts( $this, $this->getBasketUser() );
01008 
01009         foreach ( $aDiscounts as $oDiscount ) {
01010 
01011             // storing applied discounts
01012             $oStdDiscount = $oDiscount->getSimpleDiscount();
01013 
01014             // skipping bundle discounts
01015             if ( $oDiscount->oxdiscount__oxaddsumtype->value == 'itm' ) {
01016                 continue;
01017             }
01018 
01019             // saving discount info
01020             $oStdDiscount->dDiscount = $oDiscount->getAbsValue( $dOldprice );
01021             if ($dOldprice < $oStdDiscount->dDiscount) {
01022                 $oStdDiscount->dDiscount = $dOldprice;
01023             }
01024 
01025             if ($oStdDiscount->dDiscount != 0) {
01026                 $this->_aDiscounts[$oDiscount->getId()] = $oStdDiscount;
01027                 // substracting product price after discount
01028                 $dOldprice = $dOldprice - $oStdDiscount->dDiscount;
01029             }
01030         }
01031     }
01032 
01038     protected function _calcBasketTotalDiscount()
01039     {
01040         if ( $this->_oTotalDiscount === null || ( $this->_blUpdateNeeded && !$this->isAdmin() ) ) {
01041             $this->_oTotalDiscount = oxNew( 'oxPrice' );
01042             $this->_oTotalDiscount->setBruttoPriceMode();
01043 
01044             if ( is_array($this->_aDiscounts) ) {
01045                 foreach ( $this->_aDiscounts as $oDiscount ) {
01046 
01047                     // skipping bundle discounts
01048                     if ( $oDiscount->sType == 'itm' ) {
01049                         continue;
01050                     }
01051 
01052                     // add discount value to total basket discount
01053                     $this->_oTotalDiscount->add( $oDiscount->dDiscount );
01054                 }
01055             }
01056         }
01057     }
01058 
01068     protected function _calcBasketWrapping()
01069     {
01070         $myConfig = $this->getConfig();
01071         $oWrappingPrice = oxNew( 'oxPrice' );
01072         $oWrappingPrice->setBruttoPriceMode();
01073 
01074         // wrapping VAT
01075         if ( $myConfig->getConfigParam( 'blCalcVatForWrapping' ) ) {
01076             $oWrappingPrice->setVat( $this->getMostUsedVatPercent() );
01077         }
01078 
01079         // calculating basket items wrapping
01080         foreach ( $this->_aBasketContents as $oBasketItem ) {
01081 
01082             if ( ( $oWrapping = $oBasketItem->getWrapping() ) ) {
01083                 $oWrapPrice = $oWrapping->getWrappingPrice( $oBasketItem->getAmount() );
01084                 $oWrappingPrice->add( $oWrapPrice->getBruttoPrice() );
01085             }
01086         }
01087 
01088         // gift card price calculation
01089         if ( ( $oCard = $this->getCard() ) ) {
01090             $oCardPrice = $oCard->getWrappingPrice();
01091             $oWrappingPrice->add( $oCardPrice->getBruttoPrice() );
01092         }
01093 
01094         return $oWrappingPrice;
01095     }
01096 
01103     protected function _calcPaymentCost()
01104     {
01105         // resetting values
01106         $oPaymentPrice = oxNew( 'oxPrice' );
01107         $oPaymentPrice->setBruttoPriceMode();
01108 
01109         // payment
01110         if ( ( $this->_sPaymentId = $this->getPaymentId() ) ) {
01111 
01112             $oPayment = oxNew( 'oxpayment' );
01113             $oPayment->load( $this->_sPaymentId );
01114 
01115             $oPaymentPrice = $oPayment->getPaymentPrice( $this );
01116         }
01117 
01118         return $oPaymentPrice;
01119     }
01120 
01127     protected function _calcTsProtectionCost()
01128     {
01129         // resetting values
01130         $oProtectionPrice = oxNew( 'oxPrice' );
01131         $oProtectionPrice->setBruttoPriceMode();
01132 
01133         // payment
01134         if ( ( $this->_sTsProductId = $this->getTsProductId() ) ) {
01135 
01136             $oTsProtection = oxNew('oxtsprotection');
01137             $oTsProduct = $oTsProtection->getTsProduct( $this->_sTsProductId );
01138 
01139             $oProtectionPrice = $oTsProduct->oPrice;
01140         }
01141         return $oProtectionPrice;
01142     }
01143 
01152     public function setCost( $sCostName, $oPrice = null )
01153     {
01154         $this->_aCosts[$sCostName] = $oPrice;
01155     }
01156 
01165     public function calculateBasket( $blForceUpdate = false )
01166     {
01167         if ( !$this->isEnabled() ) {
01168             return;
01169         }
01170 
01171         if ( !$this->_blUpdateNeeded && !$blForceUpdate ) {
01172             return;
01173         }
01174 
01175         $this->_aCosts = array();
01176 
01177         $this->_oPrice = oxNew( 'oxprice' );
01178         $this->_oPrice->setBruttoPriceMode();
01179 
01180         //  1. merging basket history
01181         $this->_mergeSavedBasket();
01182 
01183         //  2. remove all bundles
01184         $this->_clearBundles();
01185 
01186         //  3. generate bundle items
01187         $this->_addBundles();
01188 
01189         // reserve active basket
01190         if ($this->getConfig()->getConfigParam( 'blPsBasketReservationEnabled' )) {
01191             $this->getSession()->getBasketReservations()->reserveBasket($this);
01192         }
01193 
01194         //  4. calculating item prices
01195         $this->_calcItemsPrice();
01196 
01197         //  5. calculating/applying discounts
01198         $this->_calcBasketDiscount();
01199 
01200         //  6. calculating basket total discount
01201         $this->_calcBasketTotalDiscount();
01202 
01203         //  7. check for vouchers
01204         $this->_calcVoucherDiscount();
01205 
01206         //  8. applies all discounts to pricelist
01207         $this->_applyDiscounts();
01208 
01209         //  9. calculating additional costs:
01210         //  9.1: delivery
01211         $this->setCost( 'oxdelivery', $this->_calcDeliveryCost() );
01212 
01213         //  9.2: adding wrapping costs
01214         $this->setCost( 'oxwrapping', $this->_calcBasketWrapping() );
01215 
01216         //  9.3: adding payment cost
01217         $this->setCost( 'oxpayment', $this->_calcPaymentCost() );
01218 
01219         //  9.4: adding TS protection cost
01220         $this->setCost( 'oxtsprotection', $this->_calcTsProtectionCost() );
01221 
01222         //  10. calculate total price
01223         $this->_calcTotalPrice();
01224 
01225         //  11. setting deprecated values
01226         $this->_setDeprecatedValues();
01227 
01228         //  12.setting to up-to-date status
01229         $this->afterUpdate();
01230     }
01231 
01237     public function onUpdate()
01238     {
01239         $this->_blUpdateNeeded = true;
01240     }
01241 
01247     public function afterUpdate()
01248     {
01249         $this->_blUpdateNeeded = false;
01250     }
01251 
01259     public function getBasketSummary()
01260     {
01261         if ( $this->_blUpdateNeeded || $this->_aBasketSummary === null ) {
01262             $this->_aBasketSummary = new Oxstdclass();
01263             $this->_aBasketSummary->aArticles = array();
01264             $this->_aBasketSummary->aCategories = array();
01265             $this->_aBasketSummary->iArticleCount = 0;
01266             $this->_aBasketSummary->dArticlePrice = 0;
01267             $this->_aBasketSummary->dArticleDiscountablePrice = 0;
01268         }
01269 
01270         if ( !$this->isEnabled() ) {
01271             return $this->_aBasketSummary;
01272         }
01273 
01274         $myConfig = $this->getConfig();
01275         foreach ( $this->_aBasketContents as $oBasketItem ) {
01276             if ( !$oBasketItem->isBundle() && $oArticle = $oBasketItem->getArticle(false) ) {
01277                 $aCatIds = $oArticle->getCategoryIds();
01278                 //#M530 if price is not loaded for articles
01279                 $dPrice = 0;
01280                 $dDiscountablePrice = 0;
01281                 if ( ( $oPrice = $oArticle->getPrice( $oBasketItem->getAmount() ) ) ) {
01282                     $dPrice = $oPrice->getBruttoPrice();
01283                     if ( !$oArticle->skipDiscounts() ) {
01284                         $dDiscountablePrice = $dPrice;
01285                     }
01286                 }
01287 
01288                 foreach ( $aCatIds as $sCatId ) {
01289                     if ( !isset( $this->_aBasketSummary->aCategories[$sCatId] ) ) {
01290                         $this->_aBasketSummary->aCategories[$sCatId] = new Oxstdclass();
01291                     }
01292 
01293                     $this->_aBasketSummary->aCategories[$sCatId]->dPrice  += $dPrice * $oBasketItem->getAmount();
01294                     $this->_aBasketSummary->aCategories[$sCatId]->dDiscountablePrice += $dDiscountablePrice * $oBasketItem->getAmount();
01295                     $this->_aBasketSummary->aCategories[$sCatId]->dAmount += $oBasketItem->getAmount();
01296                     $this->_aBasketSummary->aCategories[$sCatId]->iCount++;
01297                 }
01298 
01299                 // variant handling
01300                 if ( ($sParentId = $oArticle->getProductParentId()) && $myConfig->getConfigParam( 'blVariantParentBuyable' ) ) {
01301                     if ( !isset( $this->_aBasketSummary->aArticles[$sParentId] ) ) {
01302                         $this->_aBasketSummary->aArticles[$sParentId] = 0;
01303                     }
01304                     $this->_aBasketSummary->aArticles[$sParentId] += $oBasketItem->getAmount();
01305                 }
01306 
01307                 if ( !isset( $this->_aBasketSummary->aArticles[$oBasketItem->getProductId()] ) ) {
01308                     $this->_aBasketSummary->aArticles[$oBasketItem->getProductId()] = 0;
01309                 }
01310 
01311                 $this->_aBasketSummary->aArticles[$oBasketItem->getProductId()] += $oBasketItem->getAmount();
01312                 $this->_aBasketSummary->iArticleCount += $oBasketItem->getAmount();
01313                 $this->_aBasketSummary->dArticlePrice += $dPrice * $oBasketItem->getAmount();
01314                 $this->_aBasketSummary->dArticleDiscountablePrice += $dDiscountablePrice * $oBasketItem->getAmount();
01315             }
01316         }
01317         return $this->_aBasketSummary;
01318     }
01319 
01331     public function addVoucher( $sVoucherId )
01332     {
01333         // calculating price to check
01334         // P using prices sum which has discount, not sum of skipped discounts
01335         $dPrice = 0;
01336         if ( $this->_oDiscountProductsPriceList ) {
01337             $dPrice = $this->_oDiscountProductsPriceList->getBruttoSum();
01338         }
01339 
01340         try { // trying to load voucher and apply it
01341 
01342             $oVoucher = oxNew( 'oxvoucher' );
01343 
01344             if ( !$this->_blSkipVouchersAvailabilityChecking ) {
01345                 $oVoucher->getVoucherByNr( $sVoucherId, $this->_aVouchers, true );
01346                 $oVoucher->checkVoucherAvailability( $this->_aVouchers, $dPrice );
01347                 $oVoucher->checkUserAvailability( $this->getBasketUser() );
01348                 $oVoucher->markAsReserved();
01349             } else {
01350                 $oVoucher->load( $sVoucherId );
01351             }
01352 
01353             // saving voucher info
01354             $this->_aVouchers[$oVoucher->oxvouchers__oxid->value] = $oVoucher->getSimpleVoucher();
01355         } catch ( oxVoucherException $oEx ) {
01356 
01357             // problems adding voucher
01358             oxUtilsView::getInstance()->addErrorToDisplay( $oEx, false, true );
01359         }
01360 
01361         $this->onUpdate();
01362     }
01363 
01371     public function removeVoucher( $sVoucherId )
01372     {
01373         // removing if it exists
01374         if ( isset( $this->_aVouchers[$sVoucherId] ) ) {
01375 
01376             $oVoucher = oxNew( 'oxvoucher' );
01377             $oVoucher->load( $sVoucherId );
01378 
01379             $oVoucher->unMarkAsReserved();
01380 
01381             // unsetting it if exists this voucher in DB or not
01382             unset( $this->_aVouchers[$sVoucherId] );
01383             $this->onUpdate();
01384         }
01385 
01386     }
01387 
01393     public function resetUserInfo()
01394     {
01395         $this->setPayment( null );
01396         $this->setShipping( null );
01397     }
01398 
01406     protected function _setDeprecatedValues()
01407     {
01408         $this->dproductsprice    = $this->_oProductsPriceList->getBruttoSum(); // products brutto price
01409         $this->dproductsnetprice = $this->getDiscountedNettoPrice();  // products netto price();
01410 
01411         //P sum vat values
01412         $this->dVAT = array_sum( $this->_oProductsPriceList->getVatInfo() );
01413         $oLang = oxLang::getInstance();
01414 
01415         // formatting final values
01416         $this->fproductsprice    = $this->getFProductsPrice();
01417         $this->fproductsnetprice = $this->getProductsNetPrice();
01418         $this->fVAT = $oLang->formatCurrency( $this->dVAT, $this->getBasketCurrency());
01419 
01420         // delivery costs
01421         if ( $oDeliveryCost = $this->getCosts( 'oxdelivery' ) ) {
01422 
01423             $this->ddeliverycost    = $oDeliveryCost->getBruttoPrice();
01424             $this->ddeliverynetcost = $oDeliveryCost->getNettoPrice();
01425             $this->dDelVAT          = $oDeliveryCost->getVatValue();
01426             $this->fDelVATPercent   = $oDeliveryCost->getVat() / 100; // needed to divide, because in template value is multyplied by 100
01427 
01428             // formating values
01429             $this->fdeliverycost    = $oLang->formatCurrency( $this->ddeliverycost, $this->getBasketCurrency() );
01430             $this->fdeliverynetcost = $oLang->formatCurrency( $this->ddeliverynetcost, $this->getBasketCurrency() );
01431             $this->fDelVAT          = $this->getDelCostVat();
01432         }
01433 
01434         //P
01435         // wrapping costs
01436         if ( $oWrappingCost = $this->getCosts( 'oxwrapping' ) ) {
01437 
01438             $this->dWrappingPrice = $oWrappingCost->getBruttoPrice();
01439             $this->dWrappingNetto = $oWrappingCost->getNettoPrice();
01440             $this->dWrappingVAT   = $oWrappingCost->getVatValue();
01441 
01442             //formating values
01443             $this->fWrappingPrice      = $oLang->formatCurrency( $this->dWrappingPrice, $this->getBasketCurrency() );
01444             $this->fWrappingNetto      = $this->getWrappCostNet();
01445             $this->fWrappingVAT        = $this->getWrappCostVat();
01446             $this->fWrappingVATPercent = $this->getWrappCostVatPercent();
01447         }
01448 
01449         //P
01450         // payment costs
01451         if ( $oPaymentCost = $this->getCosts( 'oxpayment' ) ) {
01452 
01453             $this->dAddPaymentSum    = $this->getPaymentCosts();
01454             $this->dAddPaymentSumVAT = $oPaymentCost->getVatValue();
01455 
01456             //formating values
01457             $this->fAddPaymentSum    = $oLang->formatCurrency( $this->dAddPaymentSum, $this->getBasketCurrency() );
01458             $this->fAddPaymentSumVAT = $this->getPayCostVat();
01459             $this->fAddPaymentSumVATPercent = $this->getPayCostVatPercent();
01460             $this->fAddPaymentNetSum = $this->getPayCostNet();
01461         }
01462 
01463         //P
01464         // basket total prices
01465         $this->dprice = $this->_oPrice->getBruttoPrice();
01466         $this->fprice = $oLang->formatCurrency( $this->dprice, $this->getBasketCurrency() );
01467 
01468         // product info
01469         $this->iCntProducts = $this->getProductsCount();
01470         $this->dCntItems    = $this->getItemsCount();
01471         $this->aVATs        = $this->getProductVats();
01472         $this->aBasketContents = $this->getContents();
01473 
01474         // setting gift card information
01475         $this->giftmessage = $this->getCardMessage();
01476         $this->chosencard  = $this->getCardId();
01477 
01478         $this->oCard = $this->getCard();
01479 
01480         // discount information
01481         // formating discount value
01482         $this->aDiscounts = $this->getDiscounts();
01483         if ( count($this->aDiscounts) > 0 ) {
01484             foreach ($this->aDiscounts as $oDiscount) {
01485                 $oDiscount->fDiscount = $oLang->formatCurrency( $oDiscount->dDiscount, $this->getBasketCurrency() );
01486             }
01487         }
01488         $this->dDiscount  = $this->getTotalDiscount()->getBruttoPrice();
01489 
01490         // voucher info
01491         $this->aVouchers = $this->getVouchers();
01492         $this->dVoucherDiscount = $this->getVoucherDiscValue();
01493         $this->fVoucherDiscount = $oLang->formatCurrency( $this->dVoucherDiscount, $this->getBasketCurrency() );
01494         $this->dSkippedDiscount = $this->hasSkipedDiscount();
01495 
01496     }
01497 
01498 
01504     protected function _canMergeBasket()
01505     {
01506         $blCan = true;
01507         if ( $this->getConfig()->getConfigParam( 'blPerfNoBasketSaving' ) ||
01508              $this->_blBasketMerged || $this->isAdmin() ) {
01509             $blCan = false;
01510         }
01511         return $blCan;
01512     }
01513 
01520     protected function _mergeSavedBasket()
01521     {
01522         if ( $this->_canMergeBasket() ) {
01523 
01524             $oUser = $this->getBasketUser();
01525             if ( !$oUser ) {
01526                 $this->_blBasketMerged = false;
01527                 return;
01528             }
01529 
01530             $oBasket = $oUser->getBasket( 'savedbasket' );
01531 
01532             // restoring from saved history
01533             $aSavedItems = $oBasket->getItems();
01534             foreach ( $aSavedItems as $oItem ) {
01535                 try {
01536                     $this->addToBasket( $oItem->oxuserbasketitems__oxartid->value, $oItem->oxuserbasketitems__oxamount->value, $oItem->getSelList(), null, true );
01537                 } catch( oxArticleException $oEx ) {
01538                     // caught and ignored
01539                 }
01540             }
01541 
01542             // refreshing history
01543             foreach ( $this->_aBasketContents as $oBasketItem ) {
01544                 $oBasket->addItemToBasket( $oBasketItem->getProductId(), $oBasketItem->getAmount(), $oBasketItem->getSelList(), true );
01545             }
01546 
01547             // marking basked as saved
01548             $this->_blBasketMerged = true;
01549         }
01550     }
01551 
01562     protected function _addItemToSavedBasket( $sProductId , $dAmount, $aSel, $blOverride = false )
01563     {
01564         // updating basket history
01565         if ( $oUser = $this->getBasketUser() ) {
01566             $oUser->getBasket( 'savedbasket' )->addItemToBasket( $sProductId, $dAmount, $aSel, $blOverride );
01567         }
01568     }
01569 
01577     protected function _deleteSavedBasket()
01578     {
01579         // deleting basket if session user available
01580         if ( $oUser = $this->getBasketUser() ) {
01581             $oUser->getBasket( 'savedbasket' )->delete();
01582         }
01583 
01584         // basket exclude
01585         if ( $this->getConfig()->getConfigParam( 'blBasketExcludeEnabled' )) {
01586             $this->setBasketRootCatId(null);
01587         }
01588     }
01589 
01595     protected function _findDelivCountry()
01596     {
01597         $myConfig = $this->getConfig();
01598         $oUser    = $this->getBasketUser();
01599 
01600         $sDelivCountry = null;
01601 
01602         if ( !$oUser ) {
01603             // don't calculate if not logged in unless specified otherwise
01604             $aHomeCountry = $myConfig->getConfigParam( 'aHomeCountry' );
01605             if ( $myConfig->getConfigParam( 'blCalculateDelCostIfNotLoggedIn' ) && is_array( $aHomeCountry ) ) {
01606                 $sDelivCountry = current( $aHomeCountry );
01607             }
01608         } else {
01609 
01610             // ok, logged in
01611             if ( $sCountryId = $myConfig->getGlobalParameter( 'delcountryid' ) ) {
01612                 $sDelivCountry = $sCountryId;
01613             } elseif ( $sAddressId = oxConfig::getParameter( 'deladrid' ) ) {
01614 
01615                 $oDelAdress = oxNew( 'oxaddress' );
01616                 if ( $oDelAdress->load( $sAddressId ) ) {
01617                     $sDelivCountry = $oDelAdress->oxaddress__oxcountryid->value;
01618                 }
01619             }
01620 
01621             // still not found ?
01622             if ( !$sDelivCountry ) {
01623                 $sDelivCountry = $oUser->oxuser__oxcountryid->value;
01624             }
01625         }
01626 
01627         return $sDelivCountry;
01628     }
01629 
01635     public function deleteBasket()
01636     {
01637         $this->_aBasketContents = array();
01638         $this->getSession()->delBasket();
01639 
01640         if ($this->getConfig()->getConfigParam( 'blPsBasketReservationEnabled' )) {
01641             $this->getSession()->getBasketReservations()->discardReservations();
01642         }
01643 
01644         // merging basket history
01645         if ( !$this->getConfig()->getConfigParam( 'blPerfNoBasketSaving' ) ) {
01646             $this->_deleteSavedBasket();
01647         }
01648     }
01649 
01657     public function setPayment( $sPaymentId = null )
01658     {
01659         $this->_sPaymentId = $sPaymentId;
01660     }
01661 
01667     public function getPaymentId()
01668     {
01669         if ( !$this->_sPaymentId ) {
01670              $this->_sPaymentId = oxConfig::getParameter( 'paymentid' );
01671         }
01672         return $this->_sPaymentId;
01673     }
01674 
01682     public function setShipping( $sShippingSetId = null )
01683     {
01684         $this->_sShippingSetId = $sShippingSetId;
01685         oxSession::setVar( 'sShipSet', $sShippingSetId );
01686     }
01687 
01695     public function setDeliveryPrice( $oShippingPrice = null )
01696     {
01697         $this->_oDeliveryPrice = $oShippingPrice;
01698     }
01699 
01705     public function getShippingId()
01706     {
01707         if ( !$this->_sShippingSetId ) {
01708              $this->_sShippingSetId = oxConfig::getParameter( 'sShipSet' );
01709         }
01710 
01711         $sActPaymentId = $this->getPaymentId();
01712         // setting default if none is set
01713         if ( !$this->_sShippingSetId && $sActPaymentId != 'oxempty' ) {
01714             $oUser = $this->getUser();
01715 
01716             // choosing first preferred delivery set
01717             list( , $sActShipSet ) = oxDeliverySetList::getInstance()->getDeliverySetData( null, $oUser, $this );
01718             // in case nothing was found and no user set - choosing default
01719             $this->_sShippingSetId = $sActShipSet ? $sActShipSet : ( $oUser ? null : 'oxidstandard' );
01720         } elseif ( !$this->isAdmin() && $sActPaymentId == 'oxempty' ) {
01721             // in case 'oxempty' is payment id - delivery set must be reset
01722             $this->_sShippingSetId = null;
01723         }
01724 
01725         return $this->_sShippingSetId;
01726     }
01727 
01733     public function getBasketArticles()
01734     {
01735         $aBasketArticles = array();
01736 
01737         foreach ( $this->_aBasketContents as $sItemKey => $oBasketItem ) {
01738             try {
01739                 $oProduct = $oBasketItem->getArticle();
01740 
01741                 if ( $this->getConfig()->getConfigParam( 'bl_perfLoadSelectLists' ) ) {
01742                     // marking chosen select list
01743                     $aSelList = $oBasketItem->getSelList();
01744                     if ( is_array( $aSelList ) && ( $aSelectlist = $oProduct->getSelectLists( $sItemKey ) ) ) {
01745                         reset( $aSelList );
01746                         while ( list( $conkey, $iSel ) = each( $aSelList ) ) {
01747                             $aSelectlist[$conkey][$iSel]->selected = 1;
01748                         }
01749                         $oProduct->setSelectlist( $aSelectlist );
01750                     }
01751                 }
01752             } catch ( oxNoArticleException $oEx ) {
01753                 oxUtilsView::getInstance()->addErrorToDisplay( $oEx );
01754                 $this->removeItem( $sItemKey );
01755                 $this->calculateBasket( true );
01756                 continue;
01757             } catch ( oxArticleInputException $oEx ) {
01758                 oxUtilsView::getInstance()->addErrorToDisplay( $oEx );
01759                 $this->removeItem( $sItemKey );
01760                 $this->calculateBasket( true );
01761                 continue;
01762             }
01763 
01764             $aBasketArticles[$sItemKey] = $oProduct;
01765         }
01766         return $aBasketArticles;
01767     }
01768 
01774     public function getDiscountProductsPrice()
01775     {
01776         return $this->_oDiscountProductsPriceList;
01777     }
01778 
01784     public function getProductsPrice()
01785     {
01786         if ( is_null($this->_oProductsPriceList) ) {
01787             $this->_oProductsPriceList = oxNew( 'oxPriceList' );
01788         }
01789 
01790         return $this->_oProductsPriceList;
01791     }
01792 
01798     public function getPrice()
01799     {
01800         if ( is_null($this->_oPrice) ) {
01801             $this->_oPrice = oxNew( 'oxprice' );
01802         }
01803 
01804         return $this->_oPrice;
01805     }
01806 
01813     public function getOrderId()
01814     {
01815         return $this->_sOrderId;
01816     }
01817 
01825     public function setOrderId( $sId )
01826     {
01827         $this->_sOrderId = $sId;
01828     }
01829 
01838     public function getCosts( $sId = null )
01839     {
01840         // if user want some specific cost - return it
01841         if ( $sId ) {
01842             return isset( $this->_aCosts[$sId] )?$this->_aCosts[$sId]:null;
01843         }
01844         return $this->_aCosts;
01845     }
01846 
01852     public function getVouchers()
01853     {
01854         return $this->_aVouchers;
01855     }
01856 
01862     public function getProductsCount()
01863     {
01864         return $this->_iProductsCnt;
01865     }
01866 
01872     public function getItemsCount()
01873     {
01874         return $this->_dItemsCnt;
01875     }
01876 
01882     public function getWeight()
01883     {
01884         return $this->_dWeight;
01885     }
01886 
01892     public function getContents()
01893     {
01894         return $this->_aBasketContents;
01895     }
01896 
01904     public function getProductVats( $blFormatCurrency = true)
01905     {
01906         if ( !$this->_oNotDiscountedProductsPriceList ) {
01907             return array();
01908         }
01909 
01910         $aVats = $this->_oNotDiscountedProductsPriceList->getVatInfo();
01911 
01912         $oUtils = oxUtils::getInstance();
01913         foreach ( $this->_aDiscountedVats as $sKey => $dVat ) {
01914             // add prices of the same discounts
01915             $aVats[$sKey] += $oUtils->fRound( $dVat, $this->_oCurrency);
01916         }
01917 
01918         if ( $blFormatCurrency ) {
01919             $oLang = oxLang::getInstance();
01920             foreach ( $aVats as $sKey => $dVat ) {
01921                 $aVats[$sKey] = $oLang->formatCurrency( $dVat, $this->getBasketCurrency() );
01922             }
01923         }
01924 
01925         return $aVats;
01926     }
01927 
01933     public function getDiscountedNettoPrice()
01934     {
01935         if ( $this->_oNotDiscountedProductsPriceList ) {
01936             return $this->_dDiscountedProductNettoPrice + $this->_oNotDiscountedProductsPriceList->getNettoSum();
01937         }
01938         return false;
01939     }
01940 
01948     public function setCardMessage( $sMessage )
01949     {
01950         $this->_sCardMessage = $sMessage;
01951     }
01952 
01958     public function getCardMessage()
01959     {
01960         return $this->_sCardMessage;
01961     }
01962 
01970     public function setCardId( $sCardId )
01971     {
01972         $this->_sCardId = $sCardId;
01973     }
01974 
01980     public function getCardId()
01981     {
01982         return $this->_sCardId;
01983     }
01984 
01990     public function getCard()
01991     {
01992         $oCard = null;
01993         if ( $sCardId = $this->getCardId() ) {
01994             $oCard = oxNew( 'oxwrapping' );
01995             $oCard->load( $sCardId );
01996         }
01997         return $oCard;
01998     }
01999 
02005     public function getTotalDiscount()
02006     {
02007         return $this->_oTotalDiscount;
02008     }
02009 
02015     public function getDiscounts()
02016     {
02017         if ( $this->getTotalDiscount() && $this->getTotalDiscount()->getBruttoPrice() == 0 && count($this->_aItemDiscounts) == 0) {
02018             return null;
02019         }
02020 
02021         return array_merge($this->_aItemDiscounts, $this->_aDiscounts);
02022     }
02023 
02029     public function getVoucherDiscount()
02030     {
02031         if ($this->getConfig()->getConfigParam( 'bl_showVouchers' )) {
02032             return $this->_oVoucherDiscount;
02033         }
02034         return null;
02035     }
02036 
02044     public function setBasketCurrency( $oCurrency )
02045     {
02046         $this->_oCurrency = $oCurrency;
02047     }
02048 
02054     public function getBasketCurrency()
02055     {
02056         if ( $this->_oCurrency === null ) {
02057             $this->_oCurrency = $this->getConfig()->getActShopCurrencyObject();
02058         }
02059 
02060         return $this->_oCurrency;
02061     }
02062 
02070     public function setSkipVouchersChecking( $blSkipChecking = null )
02071     {
02072         $this->_blSkipVouchersAvailabilityChecking = $blSkipChecking;
02073     }
02074 
02080     public function hasSkipedDiscount()
02081     {
02082         return $this->_blSkipDiscounts;
02083     }
02084 
02092     public function setSkipDiscounts( $blSkip )
02093     {
02094         $this->_blSkipDiscounts = $blSkip;
02095     }
02096 
02102     public function getProductsNetPrice()
02103     {
02104         return oxLang::getInstance()->formatCurrency( $this->getDiscountedNettoPrice(), $this->getBasketCurrency() );
02105     }
02106 
02112     public function getFProductsPrice()
02113     {
02114         if ( $this->_oProductsPriceList ) {
02115             return oxLang::getInstance()->formatCurrency( $this->_oProductsPriceList->getBruttoSum(), $this->getBasketCurrency() );
02116         }
02117         return null;
02118     }
02119 
02125     public function getDelCostVatPercent()
02126     {
02127         return $this->getCosts( 'oxdelivery' )->getVat();
02128     }
02129 
02135     public function getDelCostVat()
02136     {
02137         $dDelVAT = $this->getCosts( 'oxdelivery' )->getVatValue();
02138         if ( $dDelVAT > 0 ) {
02139             return oxLang::getInstance()->formatCurrency( $dDelVAT, $this->getBasketCurrency() );
02140         }
02141         return false;
02142     }
02143 
02149     public function getDelCostNet()
02150     {
02151         if ( $this->getBasketUser() || $this->getConfig()->getConfigParam( 'blCalculateDelCostIfNotLoggedIn' ) ) {
02152             return oxLang::getInstance()->formatCurrency( $this->getCosts( 'oxdelivery' )->getNettoPrice(), $this->getBasketCurrency() );
02153         }
02154         return false;
02155     }
02156 
02162     public function getPayCostVatPercent()
02163     {
02164         return $this->getCosts( 'oxpayment' )->getVat();
02165     }
02166 
02172     public function getPayCostVat()
02173     {
02174         $dPayVAT = $this->getCosts( 'oxpayment' )->getVatValue();
02175         if ( $dPayVAT > 0 ) {
02176             return oxLang::getInstance()->formatCurrency( $dPayVAT, $this->getBasketCurrency() );
02177         }
02178         return false;
02179     }
02180 
02186     public function getPayCostNet()
02187     {
02188         return oxLang::getInstance()->formatCurrency( $this->getCosts( 'oxpayment' )->getNettoPrice(), $this->getBasketCurrency() );
02189     }
02190 
02196     public function getPaymentCosts()
02197     {
02198         return $this->getCosts( 'oxpayment' )->getBruttoPrice();
02199     }
02200 
02206     public function getFPaymentCosts()
02207     {
02208         $oPaymentCost = $this->getCosts( 'oxpayment' );
02209 
02210         if ( $oPaymentCost && $oPaymentCost->getBruttoPrice() ) {
02211             return oxLang::getInstance()->formatCurrency( $oPaymentCost->getBruttoPrice(), $this->getBasketCurrency() );
02212         }
02213         return false;
02214     }
02215 
02221     public function getVoucherDiscValue()
02222     {
02223         if ( $this->getVoucherDiscount() ) {
02224             return $this->getVoucherDiscount()->getBruttoPrice();
02225         }
02226         return false;
02227     }
02228 
02234     public function getWrappCostVatPercent()
02235     {
02236         return $this->getCosts( 'oxwrapping' )->getVat();
02237     }
02238 
02244     public function getWrappCostVat()
02245     {
02246         $dWrappVAT = $this->getCosts( 'oxwrapping' )->getVatValue();
02247         if ( $dWrappVAT > 0 ) {
02248             return oxLang::getInstance()->formatCurrency( $dWrappVAT, $this->getBasketCurrency() );
02249         }
02250         return false;
02251 
02252     }
02253 
02259     public function getWrappCostNet()
02260     {
02261         $dWrappNet = $this->getCosts( 'oxwrapping' )->getNettoPrice();
02262         if ( $dWrappNet > 0 ) {
02263             return  oxLang::getInstance()->formatCurrency( $dWrappNet, $this->getBasketCurrency() );
02264         }
02265         return false;
02266     }
02267 
02273     public function getFWrappingCosts()
02274     {
02275         $oWrappingCost = $this->getCosts( 'oxwrapping' );
02276         if ( $oWrappingCost && $oWrappingCost->getBruttoPrice() ) {
02277             return oxLang::getInstance()->formatCurrency( $oWrappingCost->getBruttoPrice(), $this->getBasketCurrency() );
02278         }
02279         return false;
02280     }
02281 
02287     public function getFPrice()
02288     {
02289         return oxLang::getInstance()->formatCurrency( $this->getPrice()->getBruttoPrice(), $this->getBasketCurrency() );
02290     }
02291 
02297     public function getFDeliveryCosts()
02298     {
02299         $oDeliveryCost = $this->getCosts( 'oxdelivery' );
02300         if ( $oDeliveryCost && $oDeliveryCost->getBruttoPrice()) {
02301             return oxLang::getInstance()->formatCurrency( $oDeliveryCost->getBruttoPrice(), $this->getBasketCurrency() );
02302         }
02303         return false;
02304     }
02305 
02311     public function getDeliveryCosts()
02312     {
02313         if ( $oDeliveryCost = $this->getCosts( 'oxdelivery' ) ) {
02314             return $oDeliveryCost->getBruttoPrice();
02315         }
02316         return false;
02317     }
02318 
02326     public function setTotalDiscount( $dDiscount )
02327     {
02328         $this->_oTotalDiscount = oxNew( 'oxPrice' );
02329         $this->_oTotalDiscount->setBruttoPriceMode();
02330         $this->_oTotalDiscount->add( $dDiscount );
02331     }
02332 
02339     public function getPriceForPayment()
02340     {
02341         $dPrice = $this->getDiscountedProductsBruttoPrice();
02342         //#1905 not discounted products should be included in payment amount calculation
02343         if ( $oPriceList = $this->getNotDiscountProductsPrice() ) {
02344             $dPrice += $oPriceList->getBruttoSum();
02345         }
02346 
02347         // adding delivery price to final price
02348         if ( $oDeliveryPrice = $this->_aCosts['oxdelivery'] ) {
02349             $dPrice += $oDeliveryPrice->getBruttoPrice();
02350         }
02351 
02352         return $dPrice;
02353     }
02354 
02360     public function getDiscountedProductsBruttoPrice()
02361     {
02362         if ( $oProductsPrice = $this->getDiscountProductsPrice() ) {
02363             $dPrice = $oProductsPrice->getBruttoSum();
02364         }
02365 
02366         // substracting total discount
02367         if ( $oPrice = $this->getTotalDiscount() ) {
02368             $dPrice -= $oPrice->getBruttoPrice();
02369         }
02370 
02371         if ( $oVoucherPrice = $this->getVoucherDiscount() ) {
02372             $dPrice -= $oVoucherPrice->getBruttoPrice();
02373         }
02374 
02375         return $dPrice;
02376     }
02377 
02383     public function isBelowMinOrderPrice()
02384     {
02385         $blIsBelowMinOrderPrice = false;
02386         $sConfValue = $this->getConfig()->getConfigParam( 'iMinOrderPrice' );
02387         if ( is_numeric($sConfValue) && $this->getProductsCount() ) {
02388             $dMinOrderPrice = oxPrice::getPriceInActCurrency( ( int ) $sConfValue );
02389             $blIsBelowMinOrderPrice = ($dMinOrderPrice > $this->getDiscountedProductsBruttoPrice());
02390         }
02391 
02392         return $blIsBelowMinOrderPrice;
02393 
02394     }
02395 
02404     public function getArtStockInBasket( $sArtId, $sExpiredArtId = null )
02405     {
02406         $dArtStock = 0;
02407         foreach ( $this->_aBasketContents as $sItemKey => $oOrderArticle ) {
02408             if ( $oOrderArticle && ( $sExpiredArtId == null || $sExpiredArtId != $sItemKey ) ) {
02409                 if ( $oOrderArticle->getArticle()->getId() == $sArtId ) {
02410                     $dArtStock += $oOrderArticle->getAmount();
02411                 }
02412             }
02413         }
02414 
02415         return $dArtStock;
02416     }
02417 
02425     public function canAddProductToBasket( $sProductId )
02426     {
02427         $blCanAdd = null;
02428 
02429         // if basket category is not set..
02430         if ( $this->_sBasketCategoryId === null ) {
02431             $oCat = null;
02432 
02433             // request category
02434             if ( $oView = $this->getConfig()->getActiveView() ) {
02435                 if ( $oCat = $oView->getActCategory() ) {
02436                     if ( !$this->_isProductInRootCategory( $sProductId, $oCat->oxcategories__oxrootid->value ) ) {
02437                         $oCat = null;
02438                     } else {
02439                         $blCanAdd = true;
02440                     }
02441                 }
02442             }
02443 
02444             // product main category
02445             if ( !$oCat ) {
02446                 $oProduct = oxNew( "oxarticle" );
02447                 if ( $oProduct->load( $sProductId ) ) {
02448                     $oCat = $oProduct->getCategory();
02449                 }
02450             }
02451 
02452             // root category id
02453             if ( $oCat ) {
02454                 $this->setBasketRootCatId($oCat->oxcategories__oxrootid->value);
02455             }
02456         }
02457 
02458         // avoiding double check..
02459         if ( $blCanAdd === null ) {
02460             $blCanAdd = $this->_sBasketCategoryId ? $this->_isProductInRootCategory( $sProductId, $this->getBasketRootCatId() ) : true;
02461         }
02462 
02463         return $blCanAdd;
02464     }
02465 
02474     protected function _isProductInRootCategory( $sProductId, $sRootCatId )
02475     {
02476         $sO2CTable = getViewName( 'oxobject2category' );
02477         $sCatTable = getViewName( 'oxcategories' );
02478 
02479         $oDb = oxDb::getDb();
02480         $sParentId  = $oDb->getOne( "select oxparentid from oxarticles where oxid = ".$oDb->quote( $sProductId ) );
02481         $sProductId = $sParentId ? $sParentId : $sProductId;
02482 
02483         $sQ = "select 1 from {$sO2CTable}
02484                  left join {$sCatTable} on {$sCatTable}.oxid = {$sO2CTable}.oxcatnid
02485                  where {$sO2CTable}.oxobjectid = ".$oDb->quote( $sProductId )." and
02486                        {$sCatTable}.oxrootid = ".$oDb->quote( $sRootCatId );
02487 
02488         return (bool) $oDb->getOne( $sQ );
02489     }
02490 
02498     public function setBasketRootCatId($sRoot)
02499     {
02500         $this->_sBasketCategoryId = $sRoot;
02501     }
02502 
02508     public function getBasketRootCatId()
02509     {
02510         return $this->_sBasketCategoryId;
02511     }
02512 
02520     public function setCatChangeWarningState( $blShow )
02521     {
02522         $this->_blShowCatChangeWarning = $blShow;
02523     }
02524 
02530     public function showCatChangeWarning()
02531     {
02532         return $this->_blShowCatChangeWarning;
02533     }
02534 
02542     public function setTsProductId( $sProductId )
02543     {
02544         $this->_sTsProductId = $sProductId;
02545     }
02546 
02552     public function getTsProductId()
02553     {
02554         return $this->_sTsProductId;
02555     }
02556 
02562     public function getFTsProtectionCosts()
02563     {
02564         $oProtectionCost = $this->getCosts( 'oxtsprotection' );
02565         if ( $oProtectionCost && $oProtectionCost->getBruttoPrice() ) {
02566             return oxLang::getInstance()->formatCurrency( $oProtectionCost->getBruttoPrice(), $this->getBasketCurrency() );
02567         }
02568         return false;
02569     }
02570 
02576     public function getTsProtectionVatPercent()
02577     {
02578         return $this->getCosts( 'oxtsprotection' )->getVat();
02579     }
02580 
02586     public function getTsProtectionVat()
02587     {
02588         $dProtectionVAT = $this->getCosts( 'oxtsprotection' )->getVatValue();
02589         if ( $dProtectionVAT > 0 ) {
02590             return oxLang::getInstance()->formatCurrency( $dProtectionVAT, $this->getBasketCurrency() );
02591         }
02592         return false;
02593     }
02594 
02600     public function getTsProtectionNet()
02601     {
02602         return oxLang::getInstance()->formatCurrency( $this->getCosts( 'oxtsprotection' )->getNettoPrice(), $this->getBasketCurrency() );
02603     }
02604 
02610     public function getTsProtectionCosts()
02611     {
02612         $oProtection = $this->getCosts( 'oxtsprotection' );
02613         if ( $oProtection ) {
02614             return $oProtection->getBruttoPrice();
02615         }
02616         return false;
02617     }
02618 
02624     public function getNotDiscountProductsPrice()
02625     {
02626         return $this->_oNotDiscountedProductsPriceList;
02627     }
02628 
02629 }