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 && !$oOrderArticle->isBundle() ) {
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             $this->_aBasketContents[$sItemId]->setBundle( $oOrderArticle->isBundle() );
00377 
00378             //calling update method
00379             $this->onUpdate();
00380 
00381             return $this->_aBasketContents[$sItemId];
00382         } elseif ( $oOrderArticle->isBundle() ) {
00383             // deleting bundles, they are handled automatically
00384             $oOrderArticle->delete();
00385         }
00386     }
00387 
00395     public function setStockCheckMode( $blCheck )
00396     {
00397         $this->_blCheckStock = $blCheck;
00398     }
00399 
00405     public function getStockCheckMode()
00406     {
00407         return $this->_blCheckStock;
00408     }
00409 
00422     public function getItemKey( $sProductId, $aSel = null, $aPersParam = null, $blBundle = false, $sAdditionalParam = '' )
00423     {
00424         $aSel = ( $aSel != null) ? $aSel : array (0=>'0');
00425 
00426         $sItemKey = md5( $sProductId.'|'.serialize( $aSel ).'|'.serialize( $aPersParam ).'|'.( int ) $blBundle . '|' . serialize( $sAdditionalParam ) );
00427 
00428         return $sItemKey;
00429     }
00430 
00431 
00439     public function removeItem( $sItemKey )
00440     {
00441         if ($this->getConfig()->getConfigParam( 'blPsBasketReservationEnabled' )) {
00442             if (isset($this->_aBasketContents[$sItemKey])) {
00443                 $sArticleId = $this->_aBasketContents[$sItemKey]->getProductId();
00444                 if ($sArticleId) {
00445                     $this->getSession()
00446                             ->getBasketReservations()
00447                             ->discardArticleReservation($sArticleId);
00448                 }
00449             }
00450         }
00451         unset( $this->_aBasketContents[$sItemKey] );
00452 
00453         // basket exclude
00454         if ( !count($this->_aBasketContents) && $this->getConfig()->getConfigParam( 'blBasketExcludeEnabled' ) ) {
00455             $this->setBasketRootCatId(null);
00456         }
00457     }
00458 
00464     protected function _clearBundles()
00465     {
00466         reset( $this->_aBasketContents );
00467         while ( list( $sItemKey, $oBasketItem ) = each( $this->_aBasketContents ) ) {
00468             if ( $oBasketItem->isBundle() ) {
00469                 $this->removeItem( $sItemKey );
00470             }
00471         }
00472     }
00473 
00481     protected function _getArticleBundles( $oBasketItem )
00482     {
00483         $aBundles = array();
00484 
00485         if ( $oBasketItem->isBundle() ) {
00486             return $aBundles;
00487         }
00488 
00489         $oArticle = $oBasketItem->getArticle();
00490         if ( $oArticle && $oArticle->oxarticles__oxbundleid->value ) {
00491             $aBundles[$oArticle->oxarticles__oxbundleid->value] = 1;
00492         }
00493 
00494         return $aBundles;
00495     }
00496 
00504     protected function _getItemBundles( $oBasketItem )
00505     {
00506         if ( $oBasketItem->isBundle() ) {
00507             return array();
00508         }
00509 
00510         $aBundles = array();
00511 
00512         // does this object still exists ?
00513         if ( $oArticle = $oBasketItem->getArticle() ) {
00514             $aDiscounts = oxDiscountList::getInstance()->getBasketItemBundleDiscounts( $oArticle, $this, $this->getBasketUser() );
00515 
00516             foreach ( $aDiscounts as $oDiscount ) {
00517 
00518                 $iAmnt = $oDiscount->getBundleAmount( $oBasketItem->getAmount() );
00519                 if ( $iAmnt ) {
00520                     //init array element
00521                     if ( !isset( $aBundles[$oDiscount->oxdiscount__oxitmartid->value] ) ) {
00522                         $aBundles[$oDiscount->oxdiscount__oxitmartid->value] = 0;
00523                     }
00524 
00525                     $aBundles[$oDiscount->oxdiscount__oxitmartid->value] += $iAmnt;
00526                 }
00527             }
00528         }
00529 
00530         return $aBundles;
00531     }
00532 
00538     protected function _getBasketBundles()
00539     {
00540         $aBundles = array();
00541         $aDiscounts = oxDiscountList::getInstance()->getBasketBundleDiscounts( $this, $this->getBasketUser() );
00542 
00543         // calculating amount of non bundled/discount items
00544         $dAmount = 0;
00545         foreach ( $this->_aBasketContents as $oBasketItem ) {
00546             if ( !( $oBasketItem->isBundle() || $oBasketItem->isDiscountArticle() ) ) {
00547                 $dAmount += $oBasketItem->getAmount();
00548             }
00549         }
00550 
00551         foreach ( $aDiscounts as $oDiscount ) {
00552             if ($oDiscount->oxdiscount__oxitmartid->value) {
00553                 if ( !isset( $aBundles[$oDiscount->oxdiscount__oxitmartid->value] ) ) {
00554                     $aBundles[$oDiscount->oxdiscount__oxitmartid->value] = 0;
00555                 }
00556 
00557                 $aBundles[$oDiscount->oxdiscount__oxitmartid->value] += $oDiscount->getBundleAmount( $dAmount );
00558             }
00559         }
00560 
00561         return $aBundles;
00562     }
00563 
00570     protected function _addBundles()
00571     {
00572         // iterating through articles and binding bundles
00573         foreach ( $this->_aBasketContents as $key => $oBasketItem ) {
00574             try {
00575                 // adding discount type bundles
00576                 if ( !$oBasketItem->isDiscountArticle() && !$oBasketItem->isBundle() ) {
00577                     $aBundles = $this->_getItemBundles( $oBasketItem );
00578                 } else {
00579                     continue;
00580                 }
00581 
00582                 $this->_addBundlesToBasket( $aBundles );
00583 
00584                     // adding item type bundles
00585                     $aBundles = $this->_getArticleBundles( $oBasketItem );
00586 
00587                     // adding bundles to basket
00588                     $this->_addBundlesToBasket( $aBundles );
00589             } catch ( oxNoArticleException $oEx ) {
00590                 $this->removeItem( $key );
00591                 oxUtilsView::getInstance()->addErrorToDisplay( $oEx );
00592             } catch( oxArticleInputException $oEx ) {
00593                 $this->removeItem( $key );
00594                 oxUtilsView::getInstance()->addErrorToDisplay( $oEx );
00595             }
00596         }
00597 
00598         // adding global basket bundles
00599         if ( $aBundles = $this->_getBasketBundles() ) {
00600             $this->_addBundlesToBasket( $aBundles );
00601         }
00602 
00603     }
00604 
00612     protected function _addBundlesToBasket( $aBundles )
00613     {
00614         foreach ( $aBundles as $sBundleId => $dAmount ) {
00615             if ( $dAmount ) {
00616                 try {
00617                     if ( $oBundleItem = $this->addToBasket( $sBundleId, $dAmount, null, null, false, true ) ) {
00618                         $oBundleItem->setAsDiscountArticle( true );
00619                     }
00620                 } catch(oxArticleException $oEx) {
00621                     // caught and ignored
00622                 }
00623             }
00624         }
00625 
00626     }
00627 
00633     protected function _calcItemsPrice()
00634     {
00635         // resetting
00636         $this->setSkipDiscounts( false );
00637         $this->_iProductsCnt = 0; // count different types
00638         $this->_dItemsCnt    = 0; // count of item units
00639         $this->_dWeight      = 0; // basket weight
00640 
00641         // resetting
00642         $this->_aItemDiscounts = array();
00643 
00644         $this->_oProductsPriceList = oxNew( 'oxpricelist' );
00645         $this->_oDiscountProductsPriceList = oxNew( 'oxpricelist' );
00646         $this->_oNotDiscountedProductsPriceList = oxNew( 'oxpricelist' );
00647 
00648         $oDiscountList = oxDiscountList::getInstance();
00649 
00650         foreach ( $this->_aBasketContents as $oBasketItem ) {
00651             $this->_iProductsCnt++;
00652             $this->_dItemsCnt += $oBasketItem->getAmount();
00653             $this->_dWeight   += $oBasketItem->getWeight();
00654 
00655             if ( !$oBasketItem->isDiscountArticle() && ( $oArticle = $oBasketItem->getArticle() ) ) {
00656                 $oBasketPrice = $oArticle->getBasketPrice( $oBasketItem->getAmount(), $oBasketItem->getSelList(), $this );
00657                 $oBasketItem->setPrice( $oBasketPrice );
00658                 //P adding product price
00659                 $this->_oProductsPriceList->addToPriceList( $oBasketItem->getPrice() );
00660 
00661                 $oBasketPrice->setBruttoPriceMode();
00662                 if ( !$oArticle->skipDiscounts() && $this->canCalcDiscounts() ) {
00663                     // apply basket type discounts
00664                     $aItemDiscounts = $oDiscountList->applyBasketDiscounts( $oBasketPrice, $oDiscountList->getBasketItemDiscounts( $oArticle, $this, $this->getBasketUser() ), $oBasketItem->getAmount() );
00665                     if ( is_array($this->_aItemDiscounts) && is_array($aItemDiscounts) ) {
00666                         $this->_aItemDiscounts = $this->_mergeDiscounts( $this->_aItemDiscounts, $aItemDiscounts);
00667                     }
00668                 } else {
00669                     $oBasketItem->setSkipDiscounts( true );
00670                     $this->setSkipDiscounts( true );
00671                 }
00672                 $oBasketPrice->multiply( $oBasketItem->getAmount() );
00673 
00674                 //P collect discount values for basket items which are discountable
00675                 if ( !$oArticle->skipDiscounts() ) {
00676                     $this->_oDiscountProductsPriceList->addToPriceList( $oBasketPrice );
00677                 } else {
00678                     $this->_oNotDiscountedProductsPriceList->addToPriceList( $oBasketPrice );
00679                     $oBasketItem->setSkipDiscounts( true );
00680                     $this->setSkipDiscounts( true );
00681                 }
00682             } elseif ( $oBasketItem->isBundle() ) {
00683                 // if bundles price is set to zero
00684                 $oPrice = oxNew( "oxprice");
00685                 $oBasketItem->setPrice( $oPrice );
00686             }
00687         }
00688     }
00689 
00697     public function setDiscountCalcMode( $blCalcDiscounts )
00698     {
00699         $this->_blCalcDiscounts = $blCalcDiscounts;
00700     }
00701 
00707     public function canCalcDiscounts()
00708     {
00709         return $this->_blCalcDiscounts;
00710     }
00711 
00721     protected function _mergeDiscounts( $aDiscounts, $aItemDiscounts)
00722     {
00723         foreach ( $aItemDiscounts as $sKey => $oDiscount ) {
00724             // add prices of the same discounts
00725             if ( array_key_exists ($sKey, $aDiscounts) ) {
00726                 $aDiscounts[$sKey]->dDiscount += $oDiscount->dDiscount;
00727             } else {
00728                 $aDiscounts[$sKey] = $oDiscount;
00729             }
00730         }
00731         return $aDiscounts;
00732     }
00733 
00739     protected function _calcDeliveryCost()
00740     {
00741         if ( $this->_oDeliveryPrice !== null ) {
00742             return $this->_oDeliveryPrice;
00743         }
00744         $myConfig  = $this->getConfig();
00745         $oDeliveryPrice = oxNew( 'oxprice' );
00746         $oDeliveryPrice->setBruttoPriceMode();
00747 
00748         // don't calculate if not logged in
00749         $oUser = $this->getBasketUser();
00750 
00751         if ( !$oUser && !$myConfig->getConfigParam( 'blCalculateDelCostIfNotLoggedIn' ) ) {
00752             return $oDeliveryPrice;
00753         }
00754 
00755         // VAT for delivery ?
00756         $fDelVATPercent = 0;
00757         if ( $myConfig->getConfigParam( 'blCalcVATForDelivery' ) ) {
00758             $fDelVATPercent = $this->getMostUsedVatPercent();
00759             $oDeliveryPrice->setVat( $fDelVATPercent );
00760         }
00761 
00762         // list of active delivery costs
00763         if ( $myConfig->getConfigParam('bl_perfLoadDelivery') ) {
00764             $aDeliveryList = oxDeliveryList::getInstance()->getDeliveryList( $this,
00765                                         $oUser,
00766                                         $this->_findDelivCountry(),
00767                                         $this->getShippingId()
00768                                     );
00769 
00770             if ( count( $aDeliveryList ) > 0 ) {
00771                 foreach ( $aDeliveryList as $oDelivery ) {
00772                     //debug trace
00773                     if ( $myConfig->getConfigParam( 'iDebug' ) == 5 ) {
00774                         echo( "DelCost : ".$oDelivery->oxdelivery__oxtitle->value."<br>" );
00775                     }
00776                     $oDeliveryPrice->addPrice( $oDelivery->getDeliveryPrice( $fDelVATPercent ) );
00777                 }
00778             }
00779         }
00780 
00781         return $oDeliveryPrice;
00782     }
00783 
00789     public function getBasketUser()
00790     {
00791         if ( $this->_oUser == null ) {
00792             return $this->getUser();
00793         }
00794 
00795         return $this->_oUser;
00796     }
00797 
00805     public function setBasketUser( $oUser )
00806     {
00807         $this->_oUser = $oUser;
00808     }
00809 
00810     //P
00816     public function getMostUsedVatPercent()
00817     {
00818         return $this->_oProductsPriceList->getMostUsedVatPercent();
00819     }
00820 
00821     //P
00828     protected function _calcTotalPrice()
00829     {
00830         // 1. add products price
00831         $dprice = $this->_oProductsPriceList->getBruttoSum();
00832         $this->_oPrice->setPrice( $dprice );
00833 
00834         // 2. substract discounts
00835         if ( $dprice ) {
00836 
00837             // 2.1 applying basket item discounts
00838             foreach ( $this->_aItemDiscounts as $oDiscount ) {
00839 
00840                 // skipping bundle discounts
00841                 if ( $oDiscount->sType == 'itm' ) {
00842                     continue;
00843                 }
00844                 $this->_oPrice->subtract( $oDiscount->dDiscount );
00845             }
00846 
00847             // 2.2 applying basket discounts
00848             $this->_oPrice->subtract( $this->_oTotalDiscount->getBruttoPrice() );
00849 
00850             // 2.3 applying voucher discounts
00851             if ($oVoucherDisc = $this->getVoucherDiscount()) {
00852                 $this->_oPrice->subtract( $oVoucherDisc->getBruttoPrice() );
00853             }
00854         }
00855 
00856         // 2.3 add delivery cost
00857         if ( isset( $this->_aCosts['oxdelivery'] ) ) {
00858             $this->_oPrice->add( $this->_aCosts['oxdelivery']->getBruttoPrice() );
00859         }
00860 
00861         // 2.4 add wrapping price
00862         if ( isset( $this->_aCosts['oxwrapping'] ) ) {
00863             $this->_oPrice->add( $this->_aCosts['oxwrapping']->getBruttoPrice() );
00864         }
00865 
00866         // 2.5 add payment price
00867         if ( isset( $this->_aCosts['oxpayment'] ) ) {
00868             $this->_oPrice->add( $this->_aCosts['oxpayment']->getBruttoPrice() );
00869         }
00870 
00871         // 2.6 add TS protection price
00872         if ( isset( $this->_aCosts['oxtsprotection'] ) ) {
00873             $this->_oPrice->add( $this->_aCosts['oxtsprotection']->getBruttoPrice() );
00874         }
00875 
00876     }
00877 
00885     public function setVoucherDiscount( $dDiscount )
00886     {
00887         $this->_oVoucherDiscount = oxNew( 'oxPrice' );
00888         $this->_oVoucherDiscount->setBruttoPriceMode();
00889         $this->_oVoucherDiscount->add( $dDiscount );
00890     }
00891 
00897     protected function _calcVoucherDiscount()
00898     {
00899         if ( $this->getConfig()->getConfigParam( 'bl_showVouchers' ) && ($this->_oVoucherDiscount === null || ( $this->_blUpdateNeeded && !$this->isAdmin() ) ) ) {
00900 
00901             $this->_oVoucherDiscount = oxNew( 'oxPrice' );
00902             $this->_oVoucherDiscount->setBruttoPriceMode();
00903 
00904 
00905             // calculating price to apply discount
00906             $dPrice = $this->_oDiscountProductsPriceList->getBruttoSum() - $this->_oTotalDiscount->getBruttoPrice();
00907 
00908             // recalculating
00909             if ( count( $this->_aVouchers ) ) {
00910                 $oLang = oxLang::getInstance();
00911                 foreach ( $this->_aVouchers as $sVoucherId => $oStdVoucher ) {
00912                     $oVoucher = oxNew( 'oxvoucher' );
00913                     try { // checking
00914                         $oVoucher->load( $oStdVoucher->sVoucherId );
00915 
00916                         if ( !$this->_blSkipVouchersAvailabilityChecking ) {
00917                             $oVoucher->checkBasketVoucherAvailability( $this->_aVouchers, $dPrice );
00918                             $oVoucher->checkUserAvailability( $this->getBasketUser() );
00919                         }
00920 
00921                         // assigning real voucher discount value as this is the only place where real value is calculated
00922                         $dVoucherdiscount = $oVoucher->getDiscountValue( $dPrice );
00923 
00924                         // acumulating discount value
00925                         $this->_oVoucherDiscount->add( $dVoucherdiscount );
00926 
00927                         // collecting formatted for preview
00928                         $oStdVoucher->fVoucherdiscount = $oLang->formatCurrency( $dVoucherdiscount, $this->getBasketCurrency() );
00929                         $oStdVoucher->dVoucherdiscount = $dVoucherdiscount;
00930 
00931                         // substracting voucher discount
00932                         $dPrice -= $dVoucherdiscount;
00933                     } catch ( oxVoucherException $oEx ) {
00934 
00935                         // removing voucher on error
00936                         $oVoucher->unMarkAsReserved();
00937                         unset( $this->_aVouchers[$sVoucherId] );
00938 
00939                         // storing voucher error info
00940                         oxUtilsView::getInstance()->addErrorToDisplay($oEx, false, true);
00941                     }
00942                 }
00943             }
00944         }
00945     }
00946 
00947     //V
00954     protected function _applyDiscounts()
00955     {
00956         $dBruttoPrice = 0;
00957         $this->_aDiscountedVats = array();
00958         if ( $oPriceList = $this->getDiscountProductsPrice() ) {
00959             $dBruttoPrice = $oPriceList->getBruttoSum();
00960             $this->_aDiscountedVats = $oPriceList->getVatInfo();
00961         }
00962 
00963         //apply discounts for brutto price
00964         $dDiscountedBruttoPrice = $this->getDiscountedProductsBruttoPrice();
00965         $oTotalDiscount   = $this->getTotalDiscount();
00966         $oVoucherDiscount = $this->getVoucherDiscount();
00967 
00968         //apply discount for VATs
00969         if ( $dBruttoPrice &&
00970              ( ( $oTotalDiscount && $oTotalDiscount->getBruttoPrice() ) ||
00971                ( $oVoucherDiscount && $oVoucherDiscount->getBruttoPrice() )
00972              )
00973            ) {
00974             $dPercent = ( $dDiscountedBruttoPrice / $dBruttoPrice) * 100;
00975             foreach ( $this->_aDiscountedVats as $sKey => $dVat ) {
00976                 $this->_aDiscountedVats[$sKey] = oxPrice::percent( $dVat, $dPercent);
00977             }
00978         }
00979 
00980         $oUtils = oxUtils::getInstance();
00981         $dDiscVatSum = 0;
00982         foreach ( $this->_aDiscountedVats as $dVat ) {
00983             $dDiscVatSum += $oUtils->fRound( -$dVat, $this->_oCurrency);
00984         }
00985         //calculate netto price with discounts
00986         $this->_dDiscountedProductNettoPrice = $dDiscountedBruttoPrice + $dDiscVatSum;
00987     }
00988 
00994     protected function _calcBasketDiscount()
00995     {
00996         // resetting
00997         $this->_aDiscounts = array();
00998 
00999         // P using prices sum which has discount, not sum of skipped discounts
01000         $dOldprice = $this->_oDiscountProductsPriceList->getBruttoSum();
01001 
01002         // add basket discounts
01003         $aDiscounts = oxDiscountList::getInstance()->getBasketDiscounts( $this, $this->getBasketUser() );
01004 
01005         foreach ( $aDiscounts as $oDiscount ) {
01006 
01007             // storing applied discounts
01008             $oStdDiscount = $oDiscount->getSimpleDiscount();
01009 
01010             // skipping bundle discounts
01011             if ( $oDiscount->oxdiscount__oxaddsumtype->value == 'itm' ) {
01012                 continue;
01013             }
01014 
01015             // saving discount info
01016             $oStdDiscount->dDiscount = $oDiscount->getAbsValue( $dOldprice );
01017             if ($dOldprice < $oStdDiscount->dDiscount) {
01018                 $oStdDiscount->dDiscount = $dOldprice;
01019             }
01020 
01021             if ($oStdDiscount->dDiscount != 0) {
01022                 $this->_aDiscounts[$oDiscount->getId()] = $oStdDiscount;
01023                 // substracting product price after discount
01024                 $dOldprice = $dOldprice - $oStdDiscount->dDiscount;
01025             }
01026         }
01027     }
01028 
01034     protected function _calcBasketTotalDiscount()
01035     {
01036         if ( $this->_oTotalDiscount === null || ( $this->_blUpdateNeeded && !$this->isAdmin() ) ) {
01037             $this->_oTotalDiscount = oxNew( 'oxPrice' );
01038             $this->_oTotalDiscount->setBruttoPriceMode();
01039 
01040             if ( is_array($this->_aDiscounts) ) {
01041                 foreach ( $this->_aDiscounts as $oDiscount ) {
01042 
01043                     // skipping bundle discounts
01044                     if ( $oDiscount->sType == 'itm' ) {
01045                         continue;
01046                     }
01047 
01048                     // add discount value to total basket discount
01049                     $this->_oTotalDiscount->add( $oDiscount->dDiscount );
01050                 }
01051             }
01052         }
01053     }
01054 
01064     protected function _calcBasketWrapping()
01065     {
01066         $myConfig = $this->getConfig();
01067         $oWrappingPrice = oxNew( 'oxPrice' );
01068         $oWrappingPrice->setBruttoPriceMode();
01069 
01070         // wrapping VAT
01071         if ( $myConfig->getConfigParam( 'blCalcVatForWrapping' ) ) {
01072             $oWrappingPrice->setVat( $this->getMostUsedVatPercent() );
01073         }
01074 
01075         // calculating basket items wrapping
01076         foreach ( $this->_aBasketContents as $oBasketItem ) {
01077 
01078             if ( ( $oWrapping = $oBasketItem->getWrapping() ) ) {
01079                 $oWrapPrice = $oWrapping->getWrappingPrice( $oBasketItem->getAmount() );
01080                 $oWrappingPrice->add( $oWrapPrice->getBruttoPrice() );
01081             }
01082         }
01083 
01084         // gift card price calculation
01085         if ( ( $oCard = $this->getCard() ) ) {
01086             $oCardPrice = $oCard->getWrappingPrice();
01087             $oWrappingPrice->add( $oCardPrice->getBruttoPrice() );
01088         }
01089 
01090         return $oWrappingPrice;
01091     }
01092 
01099     protected function _calcPaymentCost()
01100     {
01101         // resetting values
01102         $oPaymentPrice = oxNew( 'oxPrice' );
01103         $oPaymentPrice->setBruttoPriceMode();
01104 
01105         // payment
01106         if ( ( $this->_sPaymentId = $this->getPaymentId() ) ) {
01107 
01108             $oPayment = oxNew( 'oxpayment' );
01109             $oPayment->load( $this->_sPaymentId );
01110 
01111             $oPaymentPrice = $oPayment->getPaymentPrice( $this );
01112         }
01113 
01114         return $oPaymentPrice;
01115     }
01116 
01123     protected function _calcTsProtectionCost()
01124     {
01125         // resetting values
01126         $oProtectionPrice = oxNew( 'oxPrice' );
01127         $oProtectionPrice->setBruttoPriceMode();
01128 
01129         // payment
01130         if ( ( $this->_sTsProductId = $this->getTsProductId() ) ) {
01131 
01132             $oTsProtection = oxNew('oxtsprotection');
01133             $oTsProduct = $oTsProtection->getTsProduct( $this->_sTsProductId );
01134 
01135             $oProtectionPrice = $oTsProduct->getPrice();
01136         }
01137         return $oProtectionPrice;
01138     }
01139 
01148     public function setCost( $sCostName, $oPrice = null )
01149     {
01150         $this->_aCosts[$sCostName] = $oPrice;
01151     }
01152 
01161     public function calculateBasket( $blForceUpdate = false )
01162     {
01163         if ( !$this->isEnabled() ) {
01164             return;
01165         }
01166 
01167         if ( !$this->_blUpdateNeeded && !$blForceUpdate ) {
01168             return;
01169         }
01170 
01171         $this->_aCosts = array();
01172 
01173         $this->_oPrice = oxNew( 'oxprice' );
01174         $this->_oPrice->setBruttoPriceMode();
01175 
01176         //  1. saving basket to the database
01177         $this->_save();
01178 
01179         //  2. remove all bundles
01180         $this->_clearBundles();
01181 
01182         //  3. generate bundle items
01183         $this->_addBundles();
01184 
01185         // reserve active basket
01186         if ($this->getConfig()->getConfigParam( 'blPsBasketReservationEnabled' )) {
01187             $this->getSession()->getBasketReservations()->reserveBasket($this);
01188         }
01189 
01190         //  4. calculating item prices
01191         $this->_calcItemsPrice();
01192 
01193         //  5. calculating/applying discounts
01194         $this->_calcBasketDiscount();
01195 
01196         //  6. calculating basket total discount
01197         $this->_calcBasketTotalDiscount();
01198 
01199         //  7. check for vouchers
01200         $this->_calcVoucherDiscount();
01201 
01202         //  8. applies all discounts to pricelist
01203         $this->_applyDiscounts();
01204 
01205         //  9. calculating additional costs:
01206         //  9.1: delivery
01207         $this->setCost( 'oxdelivery', $this->_calcDeliveryCost() );
01208 
01209         //  9.2: adding wrapping costs
01210         $this->setCost( 'oxwrapping', $this->_calcBasketWrapping() );
01211 
01212         //  9.3: adding payment cost
01213         $this->setCost( 'oxpayment', $this->_calcPaymentCost() );
01214 
01215         //  9.4: adding TS protection cost
01216         $this->setCost( 'oxtsprotection', $this->_calcTsProtectionCost() );
01217 
01218         //  10. calculate total price
01219         $this->_calcTotalPrice();
01220 
01221         //  11. setting deprecated values
01222         $this->_setDeprecatedValues();
01223 
01224         //  12.setting to up-to-date status
01225         $this->afterUpdate();
01226     }
01227 
01233     public function onUpdate()
01234     {
01235         $this->_blUpdateNeeded = true;
01236     }
01237 
01243     public function afterUpdate()
01244     {
01245         $this->_blUpdateNeeded = false;
01246     }
01247 
01255     public function getBasketSummary()
01256     {
01257         if ( $this->_blUpdateNeeded || $this->_aBasketSummary === null ) {
01258             $this->_aBasketSummary = new Oxstdclass();
01259             $this->_aBasketSummary->aArticles = array();
01260             $this->_aBasketSummary->aCategories = array();
01261             $this->_aBasketSummary->iArticleCount = 0;
01262             $this->_aBasketSummary->dArticlePrice = 0;
01263             $this->_aBasketSummary->dArticleDiscountablePrice = 0;
01264         }
01265 
01266         if ( !$this->isEnabled() ) {
01267             return $this->_aBasketSummary;
01268         }
01269 
01270         $myConfig = $this->getConfig();
01271         foreach ( $this->_aBasketContents as $oBasketItem ) {
01272             if ( !$oBasketItem->isBundle() && $oArticle = $oBasketItem->getArticle(false) ) {
01273                 $aCatIds = $oArticle->getCategoryIds();
01274                 //#M530 if price is not loaded for articles
01275                 $dPrice = 0;
01276                 $dDiscountablePrice = 0;
01277                 if ( ( $oPrice = $oArticle->getPrice( $oBasketItem->getAmount() ) ) ) {
01278                     $dPrice = $oPrice->getBruttoPrice();
01279                     if ( !$oArticle->skipDiscounts() ) {
01280                         $dDiscountablePrice = $dPrice;
01281                     }
01282                 }
01283 
01284                 foreach ( $aCatIds as $sCatId ) {
01285                     if ( !isset( $this->_aBasketSummary->aCategories[$sCatId] ) ) {
01286                         $this->_aBasketSummary->aCategories[$sCatId] = new Oxstdclass();
01287                     }
01288 
01289                     $this->_aBasketSummary->aCategories[$sCatId]->dPrice  += $dPrice * $oBasketItem->getAmount();
01290                     $this->_aBasketSummary->aCategories[$sCatId]->dDiscountablePrice += $dDiscountablePrice * $oBasketItem->getAmount();
01291                     $this->_aBasketSummary->aCategories[$sCatId]->dAmount += $oBasketItem->getAmount();
01292                     $this->_aBasketSummary->aCategories[$sCatId]->iCount++;
01293                 }
01294 
01295                 // variant handling
01296                 if ( ($sParentId = $oArticle->getProductParentId()) && $myConfig->getConfigParam( 'blVariantParentBuyable' ) ) {
01297                     if ( !isset( $this->_aBasketSummary->aArticles[$sParentId] ) ) {
01298                         $this->_aBasketSummary->aArticles[$sParentId] = 0;
01299                     }
01300                     $this->_aBasketSummary->aArticles[$sParentId] += $oBasketItem->getAmount();
01301                 }
01302 
01303                 if ( !isset( $this->_aBasketSummary->aArticles[$oBasketItem->getProductId()] ) ) {
01304                     $this->_aBasketSummary->aArticles[$oBasketItem->getProductId()] = 0;
01305                 }
01306 
01307                 $this->_aBasketSummary->aArticles[$oBasketItem->getProductId()] += $oBasketItem->getAmount();
01308                 $this->_aBasketSummary->iArticleCount += $oBasketItem->getAmount();
01309                 $this->_aBasketSummary->dArticlePrice += $dPrice * $oBasketItem->getAmount();
01310                 $this->_aBasketSummary->dArticleDiscountablePrice += $dDiscountablePrice * $oBasketItem->getAmount();
01311             }
01312         }
01313         return $this->_aBasketSummary;
01314     }
01315 
01327     public function addVoucher( $sVoucherId )
01328     {
01329         // calculating price to check
01330         // P using prices sum which has discount, not sum of skipped discounts
01331         $dPrice = 0;
01332         if ( $this->_oDiscountProductsPriceList ) {
01333             $dPrice = $this->_oDiscountProductsPriceList->getBruttoSum();
01334         }
01335 
01336         try { // trying to load voucher and apply it
01337 
01338             $oVoucher = oxNew( 'oxvoucher' );
01339 
01340             if ( !$this->_blSkipVouchersAvailabilityChecking ) {
01341                 $oVoucher->getVoucherByNr( $sVoucherId, $this->_aVouchers, true );
01342                 $oVoucher->checkVoucherAvailability( $this->_aVouchers, $dPrice );
01343                 $oVoucher->checkUserAvailability( $this->getBasketUser() );
01344                 $oVoucher->markAsReserved();
01345             } else {
01346                 $oVoucher->load( $sVoucherId );
01347             }
01348 
01349             // saving voucher info
01350             $this->_aVouchers[$oVoucher->oxvouchers__oxid->value] = $oVoucher->getSimpleVoucher();
01351         } catch ( oxVoucherException $oEx ) {
01352 
01353             // problems adding voucher
01354             oxUtilsView::getInstance()->addErrorToDisplay( $oEx, false, true );
01355         }
01356 
01357         $this->onUpdate();
01358     }
01359 
01367     public function removeVoucher( $sVoucherId )
01368     {
01369         // removing if it exists
01370         if ( isset( $this->_aVouchers[$sVoucherId] ) ) {
01371 
01372             $oVoucher = oxNew( 'oxvoucher' );
01373             $oVoucher->load( $sVoucherId );
01374 
01375             $oVoucher->unMarkAsReserved();
01376 
01377             // unsetting it if exists this voucher in DB or not
01378             unset( $this->_aVouchers[$sVoucherId] );
01379             $this->onUpdate();
01380         }
01381 
01382     }
01383 
01389     public function resetUserInfo()
01390     {
01391         $this->setPayment( null );
01392         $this->setShipping( null );
01393     }
01394 
01402     protected function _setDeprecatedValues()
01403     {
01404         // discount information
01405         // formating discount value
01406         $this->aDiscounts = $this->getDiscounts();
01407         if ( count($this->aDiscounts) > 0 ) {
01408             $oLang = oxLang::getInstance();
01409             foreach ($this->aDiscounts as $oDiscount) {
01410                 $oDiscount->fDiscount = $oLang->formatCurrency( $oDiscount->dDiscount, $this->getBasketCurrency() );
01411             }
01412         }
01413     }
01414 
01415 
01421     protected function _canSaveBasket()
01422     {
01423         $blCanSave = !$this->getConfig()->getConfigParam( 'blPerfNoBasketSaving' );
01424         return $blCanSave;
01425     }
01426 
01432     public function load()
01433     {
01434         $oUser = $this->getBasketUser();
01435         if ( !$oUser ) {
01436             return;
01437         }
01438 
01439         $oBasket = $oUser->getBasket( 'savedbasket' );
01440 
01441         // restoring from saved history
01442         $aSavedItems = $oBasket->getItems();
01443         foreach ( $aSavedItems as $oItem ) {
01444             try {
01445                 $oSelList = $oItem->getSelList();
01446 
01447                 $this->addToBasket( $oItem->oxuserbasketitems__oxartid->value, $oItem->oxuserbasketitems__oxamount->value, $oSelList, $oItem->getPersParams(), true );
01448             } catch( oxArticleException $oEx ) {
01449                 // caught and ignored
01450             }
01451         }
01452     }
01453 
01459     protected function _save()
01460     {
01461         if ( $this->_canSaveBasket() ) {
01462 
01463             if ( $oUser = $this->getBasketUser() ) {
01464                 //first delete all contents
01465                 //#2039
01466                 $oSavedBasket = $oUser->getBasket( 'savedbasket' );
01467                 $oSavedBasket->delete();
01468 
01469                 //then save
01470                 foreach ( $this->_aBasketContents as $oBasketItem ) {
01471                     $oSavedBasket->addItemToBasket( $oBasketItem->getProductId(), $oBasketItem->getAmount(), $oBasketItem->getSelList(), true, $oBasketItem->getPersParams() );
01472                 }
01473             }
01474         }
01475     }
01476 
01488     /*
01489     protected function _addItemToSavedBasket( $sProductId , $dAmount, $aSel, $blOverride = false, $aPersParam = null )
01490     {
01491         // updating basket history
01492         if ( $oUser = $this->getBasketUser() ) {
01493             $oUser->getBasket( 'savedbasket' )->addItemToBasket( $sProductId, $dAmount, $aSel, $blOverride, $aPersParam );
01494         }
01495     }*/
01496 
01504     protected function _deleteSavedBasket()
01505     {
01506         // deleting basket if session user available
01507         if ( $oUser = $this->getBasketUser() ) {
01508             $oUser->getBasket( 'savedbasket' )->delete();
01509         }
01510 
01511         // basket exclude
01512         if ( $this->getConfig()->getConfigParam( 'blBasketExcludeEnabled' )) {
01513             $this->setBasketRootCatId(null);
01514         }
01515     }
01516 
01522     protected function _findDelivCountry()
01523     {
01524         $myConfig = $this->getConfig();
01525         $oUser    = $this->getBasketUser();
01526 
01527         $sDelivCountry = null;
01528 
01529         if ( !$oUser ) {
01530             // don't calculate if not logged in unless specified otherwise
01531             $aHomeCountry = $myConfig->getConfigParam( 'aHomeCountry' );
01532             if ( $myConfig->getConfigParam( 'blCalculateDelCostIfNotLoggedIn' ) && is_array( $aHomeCountry ) ) {
01533                 $sDelivCountry = current( $aHomeCountry );
01534             }
01535         } else {
01536 
01537             // ok, logged in
01538             if ( $sCountryId = $myConfig->getGlobalParameter( 'delcountryid' ) ) {
01539                 $sDelivCountry = $sCountryId;
01540             } elseif ( $sAddressId = oxSession::getVar( 'deladrid' ) ) {
01541 
01542                 $oDelAdress = oxNew( 'oxaddress' );
01543                 if ( $oDelAdress->load( $sAddressId ) ) {
01544                     $sDelivCountry = $oDelAdress->oxaddress__oxcountryid->value;
01545                 }
01546             }
01547 
01548             // still not found ?
01549             if ( !$sDelivCountry ) {
01550                 $sDelivCountry = $oUser->oxuser__oxcountryid->value;
01551             }
01552         }
01553 
01554         return $sDelivCountry;
01555     }
01556 
01562     public function deleteBasket()
01563     {
01564         $this->_aBasketContents = array();
01565         $this->getSession()->delBasket();
01566 
01567         if ($this->getConfig()->getConfigParam( 'blPsBasketReservationEnabled' )) {
01568             $this->getSession()->getBasketReservations()->discardReservations();
01569         }
01570 
01571         // merging basket history
01572         if ( !$this->getConfig()->getConfigParam( 'blPerfNoBasketSaving' ) ) {
01573             $this->_deleteSavedBasket();
01574         }
01575     }
01576 
01584     public function setPayment( $sPaymentId = null )
01585     {
01586         $this->_sPaymentId = $sPaymentId;
01587     }
01588 
01594     public function getPaymentId()
01595     {
01596         if ( !$this->_sPaymentId ) {
01597              $this->_sPaymentId = oxSession::getVar( 'paymentid' );
01598         }
01599         return $this->_sPaymentId;
01600     }
01601 
01609     public function setShipping( $sShippingSetId = null )
01610     {
01611         $this->_sShippingSetId = $sShippingSetId;
01612         oxSession::setVar( 'sShipSet', $sShippingSetId );
01613     }
01614 
01622     public function setDeliveryPrice( $oShippingPrice = null )
01623     {
01624         $this->_oDeliveryPrice = $oShippingPrice;
01625     }
01626 
01632     public function getShippingId()
01633     {
01634         if ( !$this->_sShippingSetId ) {
01635              $this->_sShippingSetId = oxSession::getVar( 'sShipSet' );
01636         }
01637 
01638         $sActPaymentId = $this->getPaymentId();
01639         // setting default if none is set
01640         if ( !$this->_sShippingSetId && $sActPaymentId != 'oxempty' ) {
01641             $oUser = $this->getUser();
01642 
01643             // choosing first preferred delivery set
01644             list( , $sActShipSet ) = oxDeliverySetList::getInstance()->getDeliverySetData( null, $oUser, $this );
01645             // in case nothing was found and no user set - choosing default
01646             $this->_sShippingSetId = $sActShipSet ? $sActShipSet : ( $oUser ? null : 'oxidstandard' );
01647         } elseif ( !$this->isAdmin() && $sActPaymentId == 'oxempty' ) {
01648             // in case 'oxempty' is payment id - delivery set must be reset
01649             $this->_sShippingSetId = null;
01650         }
01651 
01652         return $this->_sShippingSetId;
01653     }
01654 
01660     public function getBasketArticles()
01661     {
01662         $aBasketArticles = array();
01663 
01664         foreach ( $this->_aBasketContents as $sItemKey => $oBasketItem ) {
01665             try {
01666                 $oProduct = $oBasketItem->getArticle();
01667 
01668                 if ( $this->getConfig()->getConfigParam( 'bl_perfLoadSelectLists' ) ) {
01669                     // marking chosen select list
01670                     $aSelList = $oBasketItem->getSelList();
01671                     if ( is_array( $aSelList ) && ( $aSelectlist = $oProduct->getSelectLists( $sItemKey ) ) ) {
01672                         reset( $aSelList );
01673                         while ( list( $conkey, $iSel ) = each( $aSelList ) ) {
01674                             $aSelectlist[$conkey][$iSel] = clone $aSelectlist[$conkey][$iSel];
01675                             $aSelectlist[$conkey][$iSel]->selected = 1;
01676                         }
01677                         $oProduct->setSelectlist( $aSelectlist );
01678                     }
01679                 }
01680             } catch ( oxNoArticleException $oEx ) {
01681                 oxUtilsView::getInstance()->addErrorToDisplay( $oEx );
01682                 $this->removeItem( $sItemKey );
01683                 $this->calculateBasket( true );
01684                 continue;
01685             } catch ( oxArticleInputException $oEx ) {
01686                 oxUtilsView::getInstance()->addErrorToDisplay( $oEx );
01687                 $this->removeItem( $sItemKey );
01688                 $this->calculateBasket( true );
01689                 continue;
01690             }
01691 
01692             $aBasketArticles[$sItemKey] = $oProduct;
01693         }
01694         return $aBasketArticles;
01695     }
01696 
01702     public function getDiscountProductsPrice()
01703     {
01704         return $this->_oDiscountProductsPriceList;
01705     }
01706 
01712     public function getProductsPrice()
01713     {
01714         if ( is_null($this->_oProductsPriceList) ) {
01715             $this->_oProductsPriceList = oxNew( 'oxPriceList' );
01716         }
01717 
01718         return $this->_oProductsPriceList;
01719     }
01720 
01726     public function getPrice()
01727     {
01728         if ( is_null($this->_oPrice) ) {
01729             $this->_oPrice = oxNew( 'oxprice' );
01730         }
01731 
01732         return $this->_oPrice;
01733     }
01734 
01741     public function getOrderId()
01742     {
01743         return $this->_sOrderId;
01744     }
01745 
01753     public function setOrderId( $sId )
01754     {
01755         $this->_sOrderId = $sId;
01756     }
01757 
01766     public function getCosts( $sId = null )
01767     {
01768         // if user want some specific cost - return it
01769         if ( $sId ) {
01770             return isset( $this->_aCosts[$sId] )?$this->_aCosts[$sId]:null;
01771         }
01772         return $this->_aCosts;
01773     }
01774 
01780     public function getVouchers()
01781     {
01782         return $this->_aVouchers;
01783     }
01784 
01790     public function getProductsCount()
01791     {
01792         return $this->_iProductsCnt;
01793     }
01794 
01800     public function getItemsCount()
01801     {
01802         return $this->_dItemsCnt;
01803     }
01804 
01810     public function getWeight()
01811     {
01812         return $this->_dWeight;
01813     }
01814 
01820     public function getContents()
01821     {
01822         return $this->_aBasketContents;
01823     }
01824 
01832     public function getProductVats( $blFormatCurrency = true)
01833     {
01834         if ( !$this->_oNotDiscountedProductsPriceList ) {
01835             return array();
01836         }
01837 
01838         $aVats = $this->_oNotDiscountedProductsPriceList->getVatInfo();
01839 
01840         $oUtils = oxUtils::getInstance();
01841         foreach ( $this->_aDiscountedVats as $sKey => $dVat ) {
01842             // add prices of the same discounts
01843             $aVats[$sKey] += $oUtils->fRound( $dVat, $this->_oCurrency);
01844         }
01845 
01846         if ( $blFormatCurrency ) {
01847             $oLang = oxLang::getInstance();
01848             foreach ( $aVats as $sKey => $dVat ) {
01849                 $aVats[$sKey] = $oLang->formatCurrency( $dVat, $this->getBasketCurrency() );
01850             }
01851         }
01852 
01853         return $aVats;
01854     }
01855 
01861     public function getDiscountedNettoPrice()
01862     {
01863         if ( $this->_oNotDiscountedProductsPriceList ) {
01864             return $this->_dDiscountedProductNettoPrice + $this->_oNotDiscountedProductsPriceList->getNettoSum();
01865         }
01866         return false;
01867     }
01868 
01876     public function setCardMessage( $sMessage )
01877     {
01878         $this->_sCardMessage = $sMessage;
01879     }
01880 
01886     public function getCardMessage()
01887     {
01888         return $this->_sCardMessage;
01889     }
01890 
01898     public function setCardId( $sCardId )
01899     {
01900         $this->_sCardId = $sCardId;
01901     }
01902 
01908     public function getCardId()
01909     {
01910         return $this->_sCardId;
01911     }
01912 
01918     public function getCard()
01919     {
01920         $oCard = null;
01921         if ( $sCardId = $this->getCardId() ) {
01922             $oCard = oxNew( 'oxwrapping' );
01923             $oCard->load( $sCardId );
01924         }
01925         return $oCard;
01926     }
01927 
01933     public function getTotalDiscount()
01934     {
01935         return $this->_oTotalDiscount;
01936     }
01937 
01943     public function getDiscounts()
01944     {
01945         if ( $this->getTotalDiscount() && $this->getTotalDiscount()->getBruttoPrice() == 0 && count($this->_aItemDiscounts) == 0) {
01946             return null;
01947         }
01948 
01949         return array_merge($this->_aItemDiscounts, $this->_aDiscounts);
01950     }
01951 
01957     public function getVoucherDiscount()
01958     {
01959         if ($this->getConfig()->getConfigParam( 'bl_showVouchers' )) {
01960             return $this->_oVoucherDiscount;
01961         }
01962         return null;
01963     }
01964 
01972     public function setBasketCurrency( $oCurrency )
01973     {
01974         $this->_oCurrency = $oCurrency;
01975     }
01976 
01982     public function getBasketCurrency()
01983     {
01984         if ( $this->_oCurrency === null ) {
01985             $this->_oCurrency = $this->getConfig()->getActShopCurrencyObject();
01986         }
01987 
01988         return $this->_oCurrency;
01989     }
01990 
01998     public function setSkipVouchersChecking( $blSkipChecking = null )
01999     {
02000         $this->_blSkipVouchersAvailabilityChecking = $blSkipChecking;
02001     }
02002 
02008     public function hasSkipedDiscount()
02009     {
02010         return $this->_blSkipDiscounts;
02011     }
02012 
02020     public function setSkipDiscounts( $blSkip )
02021     {
02022         $this->_blSkipDiscounts = $blSkip;
02023     }
02024 
02030     public function getProductsNetPrice()
02031     {
02032         return oxLang::getInstance()->formatCurrency( $this->getDiscountedNettoPrice(), $this->getBasketCurrency() );
02033     }
02034 
02040     public function getFProductsPrice()
02041     {
02042         if ( $this->_oProductsPriceList ) {
02043             return oxLang::getInstance()->formatCurrency( $this->_oProductsPriceList->getBruttoSum(), $this->getBasketCurrency() );
02044         }
02045         return null;
02046     }
02047 
02053     public function getDelCostVatPercent()
02054     {
02055         return $this->getCosts( 'oxdelivery' )->getVat();
02056     }
02057 
02063     public function getDelCostVat()
02064     {
02065         $dDelVAT = $this->getCosts( 'oxdelivery' )->getVatValue();
02066 
02067         if ( $dDelVAT > 0 ) {
02068             return oxLang::getInstance()->formatCurrency( $dDelVAT, $this->getBasketCurrency() );
02069         }
02070         return false;
02071     }
02072 
02078     public function getDelCostNet()
02079     {
02080         if ( $this->getBasketUser() || $this->getConfig()->getConfigParam( 'blCalculateDelCostIfNotLoggedIn' ) ) {
02081             return oxLang::getInstance()->formatCurrency( $this->getCosts( 'oxdelivery' )->getNettoPrice(), $this->getBasketCurrency() );
02082         }
02083         return false;
02084     }
02085 
02091     public function getPayCostVatPercent()
02092     {
02093         return $this->getCosts( 'oxpayment' )->getVat();
02094     }
02095 
02101     public function getPayCostVat()
02102     {
02103         $dPayVAT = $this->getCosts( 'oxpayment' )->getVatValue();
02104         if ( $dPayVAT > 0 ) {
02105             return oxLang::getInstance()->formatCurrency( $dPayVAT, $this->getBasketCurrency() );
02106         }
02107         return false;
02108     }
02109 
02115     public function getPayCostNet()
02116     {
02117         return oxLang::getInstance()->formatCurrency( $this->getCosts( 'oxpayment' )->getNettoPrice(), $this->getBasketCurrency() );
02118     }
02119 
02125     public function getPaymentCosts()
02126     {
02127         return $this->getCosts( 'oxpayment' )->getBruttoPrice();
02128     }
02129 
02135     public function getFPaymentCosts()
02136     {
02137         $oPaymentCost = $this->getCosts( 'oxpayment' );
02138 
02139         if ( $oPaymentCost && $oPaymentCost->getBruttoPrice() ) {
02140             return oxLang::getInstance()->formatCurrency( $oPaymentCost->getBruttoPrice(), $this->getBasketCurrency() );
02141         }
02142         return false;
02143     }
02144 
02150     public function getVoucherDiscValue()
02151     {
02152         if ( $this->getVoucherDiscount() ) {
02153             return $this->getVoucherDiscount()->getBruttoPrice();
02154         }
02155         return false;
02156     }
02157 
02163     public function getFVoucherDiscountValue()
02164     {
02165         if ( $oVoucherDiscount = $this->getVoucherDiscount() ) {
02166             if ( $oVoucherDiscount->getBruttoPrice() ) {
02167                 return oxLang::getInstance()->formatCurrency( $oVoucherDiscount->getBruttoPrice(), $this->getBasketCurrency() );
02168             }
02169         }
02170         return false;
02171     }
02172 
02173 
02179     public function getWrappCostVatPercent()
02180     {
02181         return $this->getCosts( 'oxwrapping' )->getVat();
02182     }
02183 
02189     public function getWrappCostVat()
02190     {
02191         $dWrappVAT = $this->getCosts( 'oxwrapping' )->getVatValue();
02192         if ( $dWrappVAT > 0 ) {
02193             return oxLang::getInstance()->formatCurrency( $dWrappVAT, $this->getBasketCurrency() );
02194         }
02195         return false;
02196 
02197     }
02198 
02204     public function getWrappCostNet()
02205     {
02206         $dWrappNet = $this->getCosts( 'oxwrapping' )->getNettoPrice();
02207         if ( $dWrappNet > 0 ) {
02208             return  oxLang::getInstance()->formatCurrency( $dWrappNet, $this->getBasketCurrency() );
02209         }
02210         return false;
02211     }
02212 
02218     public function getFWrappingCosts()
02219     {
02220         $oWrappingCost = $this->getCosts( 'oxwrapping' );
02221         if ( $oWrappingCost && $oWrappingCost->getBruttoPrice() ) {
02222             return oxLang::getInstance()->formatCurrency( $oWrappingCost->getBruttoPrice(), $this->getBasketCurrency() );
02223         }
02224         return false;
02225     }
02226 
02232     public function getFPrice()
02233     {
02234         return oxLang::getInstance()->formatCurrency( $this->getPrice()->getBruttoPrice(), $this->getBasketCurrency() );
02235     }
02236 
02242     public function getFDeliveryCosts()
02243     {
02244         $oDeliveryCost = $this->getCosts( 'oxdelivery' );
02245         if ( $oDeliveryCost && $oDeliveryCost->getBruttoPrice()) {
02246             return oxLang::getInstance()->formatCurrency( $oDeliveryCost->getBruttoPrice(), $this->getBasketCurrency() );
02247         }
02248         return false;
02249     }
02250 
02256     public function getDeliveryCosts()
02257     {
02258         if ( $oDeliveryCost = $this->getCosts( 'oxdelivery' ) ) {
02259             return $oDeliveryCost->getBruttoPrice();
02260         }
02261         return false;
02262     }
02263 
02271     public function setTotalDiscount( $dDiscount )
02272     {
02273         $this->_oTotalDiscount = oxNew( 'oxPrice' );
02274         $this->_oTotalDiscount->setBruttoPriceMode();
02275         $this->_oTotalDiscount->add( $dDiscount );
02276     }
02277 
02284     public function getPriceForPayment()
02285     {
02286         $dPrice = $this->getDiscountedProductsBruttoPrice();
02287         //#1905 not discounted products should be included in payment amount calculation
02288         if ( $oPriceList = $this->getNotDiscountProductsPrice() ) {
02289             $dPrice += $oPriceList->getBruttoSum();
02290         }
02291 
02292         // adding delivery price to final price
02293         if ( $oDeliveryPrice = $this->_aCosts['oxdelivery'] ) {
02294             $dPrice += $oDeliveryPrice->getBruttoPrice();
02295         }
02296 
02297         return $dPrice;
02298     }
02299 
02305     public function getDiscountedProductsBruttoPrice()
02306     {
02307         if ( $oProductsPrice = $this->getDiscountProductsPrice() ) {
02308             $dPrice = $oProductsPrice->getBruttoSum();
02309         }
02310 
02311         // substracting total discount
02312         if ( $oPrice = $this->getTotalDiscount() ) {
02313             $dPrice -= $oPrice->getBruttoPrice();
02314         }
02315 
02316         if ( $oVoucherPrice = $this->getVoucherDiscount() ) {
02317             $dPrice -= $oVoucherPrice->getBruttoPrice();
02318         }
02319 
02320         return $dPrice;
02321     }
02322 
02328     public function isBelowMinOrderPrice()
02329     {
02330         $blIsBelowMinOrderPrice = false;
02331         $sConfValue = $this->getConfig()->getConfigParam( 'iMinOrderPrice' );
02332         if ( is_numeric($sConfValue) && $this->getProductsCount() ) {
02333             $dMinOrderPrice = oxPrice::getPriceInActCurrency( ( int ) $sConfValue );
02334             $blIsBelowMinOrderPrice = ($dMinOrderPrice > $this->getDiscountedProductsBruttoPrice());
02335         }
02336 
02337         return $blIsBelowMinOrderPrice;
02338 
02339     }
02340 
02349     public function getArtStockInBasket( $sArtId, $sExpiredArtId = null )
02350     {
02351         $dArtStock = 0;
02352         foreach ( $this->_aBasketContents as $sItemKey => $oOrderArticle ) {
02353             if ( $oOrderArticle && ( $sExpiredArtId == null || $sExpiredArtId != $sItemKey ) ) {
02354                 if ( $oOrderArticle->getArticle()->getId() == $sArtId ) {
02355                     $dArtStock += $oOrderArticle->getAmount();
02356                 }
02357             }
02358         }
02359 
02360         return $dArtStock;
02361     }
02362 
02370     public function canAddProductToBasket( $sProductId )
02371     {
02372         $blCanAdd = null;
02373 
02374         // if basket category is not set..
02375         if ( $this->_sBasketCategoryId === null ) {
02376             $oCat = null;
02377 
02378             // request category
02379             if ( $oView = $this->getConfig()->getActiveView() ) {
02380                 if ( $oCat = $oView->getActCategory() ) {
02381                     if ( !$this->_isProductInRootCategory( $sProductId, $oCat->oxcategories__oxrootid->value ) ) {
02382                         $oCat = null;
02383                     } else {
02384                         $blCanAdd = true;
02385                     }
02386                 }
02387             }
02388 
02389             // product main category
02390             if ( !$oCat ) {
02391                 $oProduct = oxNew( "oxarticle" );
02392                 if ( $oProduct->load( $sProductId ) ) {
02393                     $oCat = $oProduct->getCategory();
02394                 }
02395             }
02396 
02397             // root category id
02398             if ( $oCat ) {
02399                 $this->setBasketRootCatId($oCat->oxcategories__oxrootid->value);
02400             }
02401         }
02402 
02403         // avoiding double check..
02404         if ( $blCanAdd === null ) {
02405             $blCanAdd = $this->_sBasketCategoryId ? $this->_isProductInRootCategory( $sProductId, $this->getBasketRootCatId() ) : true;
02406         }
02407 
02408         return $blCanAdd;
02409     }
02410 
02419     protected function _isProductInRootCategory( $sProductId, $sRootCatId )
02420     {
02421         $sO2CTable = getViewName( 'oxobject2category' );
02422         $sCatTable = getViewName( 'oxcategories' );
02423 
02424         $oDb = oxDb::getDb();
02425         $sParentId  = $oDb->getOne( "select oxparentid from oxarticles where oxid = ".$oDb->quote( $sProductId ) );
02426         $sProductId = $sParentId ? $sParentId : $sProductId;
02427 
02428         $sQ = "select 1 from {$sO2CTable}
02429                  left join {$sCatTable} on {$sCatTable}.oxid = {$sO2CTable}.oxcatnid
02430                  where {$sO2CTable}.oxobjectid = ".$oDb->quote( $sProductId )." and
02431                        {$sCatTable}.oxrootid = ".$oDb->quote( $sRootCatId );
02432 
02433         return (bool) $oDb->getOne( $sQ );
02434     }
02435 
02443     public function setBasketRootCatId($sRoot)
02444     {
02445         $this->_sBasketCategoryId = $sRoot;
02446     }
02447 
02453     public function getBasketRootCatId()
02454     {
02455         return $this->_sBasketCategoryId;
02456     }
02457 
02465     public function setCatChangeWarningState( $blShow )
02466     {
02467         $this->_blShowCatChangeWarning = $blShow;
02468     }
02469 
02475     public function showCatChangeWarning()
02476     {
02477         return $this->_blShowCatChangeWarning;
02478     }
02479 
02487     public function setTsProductId( $sProductId )
02488     {
02489         $this->_sTsProductId = $sProductId;
02490     }
02491 
02497     public function getTsProductId()
02498     {
02499         return $this->_sTsProductId;
02500     }
02501 
02507     public function getFTsProtectionCosts()
02508     {
02509         $oProtectionCost = $this->getCosts( 'oxtsprotection' );
02510         if ( $oProtectionCost && $oProtectionCost->getBruttoPrice() ) {
02511             return oxLang::getInstance()->formatCurrency( $oProtectionCost->getBruttoPrice(), $this->getBasketCurrency() );
02512         }
02513         return false;
02514     }
02515 
02521     public function getTsProtectionVatPercent()
02522     {
02523         return $this->getCosts( 'oxtsprotection' )->getVat();
02524     }
02525 
02531     public function getTsProtectionVat()
02532     {
02533         $dProtectionVAT = $this->getCosts( 'oxtsprotection' )->getVatValue();
02534         if ( $dProtectionVAT > 0 ) {
02535             return oxLang::getInstance()->formatCurrency( $dProtectionVAT, $this->getBasketCurrency() );
02536         }
02537         return false;
02538     }
02539 
02545     public function getTsProtectionNet()
02546     {
02547         return oxLang::getInstance()->formatCurrency( $this->getCosts( 'oxtsprotection' )->getNettoPrice(), $this->getBasketCurrency() );
02548     }
02549 
02555     public function getTsProtectionCosts()
02556     {
02557         $oProtection = $this->getCosts( 'oxtsprotection' );
02558         if ( $oProtection ) {
02559             return $oProtection->getBruttoPrice();
02560         }
02561         return false;
02562     }
02563 
02569     public function getNotDiscountProductsPrice()
02570     {
02571         return $this->_oNotDiscountedProductsPriceList;
02572     }
02573 
02574 }