oxbasket.php

Go to the documentation of this file.
00001 <?php
00002 
00005 class oxBasket extends oxSuperCfg
00006 {
00012     protected $_aBasketContents = array();
00013 
00019     protected $_iProductsCnt = 0;
00020 
00026     protected $_dItemsCnt = 0.0;
00027 
00033     protected $_dWeight = 0.0;
00034 
00040     protected $_oPrice = null;
00041 
00047     protected $_oProductsPriceList = null;
00048 
00054     protected $_aDiscounts = array();
00055 
00061     protected $_aItemDiscounts = array();
00062 
00068     protected $_sOrderId = null;
00069 
00075     protected $_aVouchers = array();
00076 
00082     protected $_aCosts = array();
00083 
00089     protected $_oDiscountProductsPriceList = null;
00090 
00096     protected $_oNotDiscountedProductsPriceList = null;
00097 
00103     protected $_blUpdateNeeded = true;
00104 
00110     protected $_aBasketSummary = null;
00111 
00117     protected $_sPaymentId = null;
00118 
00124     protected $_sShippingSetId = null;
00125 
00131     protected $_oUser = null;
00132 
00138     protected $_oTotalDiscount = null;
00139 
00145     protected $_oVoucherDiscount = null;
00146 
00152     protected $_oCurrency = null;
00153 
00159     protected $_blSkipVouchersAvailabilityChecking = null;
00160 
00166     protected $_dDiscountedProductNettoPrice = null;
00167 
00173     protected $_aDiscountedVats = null;
00174 
00180     protected $_blSkipDiscounts = false;
00181 
00187     protected $_oDeliveryPrice = null;
00188 
00194      protected $_blCheckStock = true;
00195 
00201     protected $_blCalcDiscounts = true;
00202 
00208     protected $_sBasketCategoryId = null;
00209 
00215     protected $_blShowCatChangeWarning = false;
00216 
00222     protected $_sTsProductId = null;
00223 
00228     protected $_blNewITemAdded = null;
00229 
00235     public function isEnabled()
00236     {
00237         return !oxUtils::getInstance()->isSearchEngine();
00238     }
00239 
00249     protected function _changeBasketItemKey($sOldKey, $sNewKey, $value = null)
00250     {
00251         reset($this->_aBasketContents);
00252         $iOldKeyPlace = 0;
00253         while (key($this->_aBasketContents) != $sOldKey && next($this->_aBasketContents)) {
00254             ++$iOldKeyPlace;
00255         }
00256         $aNewCopy = array_merge(
00257             array_slice($this->_aBasketContents, 0, $iOldKeyPlace, true),
00258             array($sNewKey => $value),
00259             array_slice($this->_aBasketContents, $iOldKeyPlace+1, count($this->_aBasketContents)-$iOldKeyPlace, true)
00260         );
00261         $this->_aBasketContents = $aNewCopy;
00262     }
00263 
00279     public function addToBasket( $sProductID, $dAmount, $aSel = null, $aPersParam = null, $blOverride = false, $blBundle = false, $sOldBasketItemId = null )
00280     {
00281         // enabled ?
00282         if ( !$this->isEnabled() )
00283             return null;
00284 
00285         // basket exclude
00286         if ( $this->getConfig()->getConfigParam( 'blBasketExcludeEnabled' ) ) {
00287             if ( !$this->canAddProductToBasket( $sProductID ) ) {
00288                 $this->setCatChangeWarningState( true );
00289                 return null;
00290             } else {
00291                 $this->setCatChangeWarningState( false );
00292             }
00293         }
00294 
00295         $sItemId = $this->getItemKey( $sProductID, $aSel, $aPersParam, $blBundle );
00296         if ( $sOldBasketItemId && ( strcmp( $sOldBasketItemId, $sItemId ) != 0 ) ) {
00297             if ( isset( $this->_aBasketContents[$sItemId] ) ) {
00298                 // we are merging, so params will just go to the new key
00299                 unset( $this->_aBasketContents[$sOldBasketItemId] );
00300                 // do not override stock
00301                 $blOverride = false;
00302             } else {
00303                 // value is null - means isset will fail and real values will be filled
00304                 $this->_changeBasketItemKey( $sOldBasketItemId, $sItemId );
00305             }
00306         }
00307 
00308         // after some checks item must be removed from basket
00309         $blRemoveItem = false;
00310 
00311         // initialting exception storage
00312         $oEx = null;
00313 
00314         if ( isset( $this->_aBasketContents[$sItemId] ) ) {
00315 
00316             //updating existing
00317             try {
00318                 // setting stock check status
00319                 $this->_aBasketContents[$sItemId]->setStockCheckStatus( $this->getStockCheckMode() );
00320                 //validate amount
00321                 //possibly throws exception
00322                 $this->_aBasketContents[$sItemId]->setAmount( $dAmount, $blOverride, $sItemId );
00323             } catch( oxOutOfStockException $oEx ) {
00324                 // rethrow later
00325             }
00326 
00327         } else {
00328             //inserting new
00329             $oBasketItem = oxNew( 'oxbasketitem' );
00330             try {
00331                 $oBasketItem->setStockCheckStatus( $this->getStockCheckMode() );
00332                 $oBasketItem->init( $sProductID, $dAmount, $aSel, $aPersParam, $blBundle );
00333             } catch( oxNoArticleException $oEx ) {
00334                 // in this case that the article does not exist remove the item from the basket by setting its amount to 0
00335                 //$oBasketItem->dAmount = 0;
00336                 $blRemoveItem = true;
00337 
00338             } catch( oxOutOfStockException $oEx ) {
00339                 // rethrow later
00340             } catch ( oxArticleInputException $oEx ) {
00341                 // rethrow later
00342                 $blRemoveItem = true;
00343             }
00344 
00345             $this->_aBasketContents[$sItemId] = $oBasketItem;
00346         }
00347 
00348         //in case amount is 0 removing item
00349         if ( $this->_aBasketContents[$sItemId]->getAmount() == 0 || $blRemoveItem ) {
00350             $this->removeItem( $sItemId );
00351         } elseif ( $blBundle ) {
00352             //marking bundles
00353             $this->_aBasketContents[$sItemId]->setBundle( true );
00354         }
00355 
00356         //calling update method
00357         $this->onUpdate();
00358 
00359         if ( $oEx ) {
00360             throw $oEx;
00361         }
00362 
00363         // notifying that new basket item was added
00364         $this->_addedNewItem( $sProductID, $dAmount, $aSel, $aPersParam, $blOverride, $blBundle, $sOldBasketItemId );
00365 
00366         // returning basket item object
00367         return $this->_aBasketContents[$sItemId];
00368     }
00369 
00377     public function addOrderArticleToBasket( $oOrderArticle )
00378     {
00379         // adding only if amount > 0
00380         if ( $oOrderArticle->oxorderarticles__oxamount->value > 0 && !$oOrderArticle->isBundle() ) {
00381             $sItemId = $oOrderArticle->getId();
00382 
00383             //inserting new
00384             $this->_aBasketContents[$sItemId] = oxNew( 'oxbasketitem' );
00385             $this->_aBasketContents[$sItemId]->initFromOrderArticle( $oOrderArticle );
00386             $this->_aBasketContents[$sItemId]->setWrapping( $oOrderArticle->oxorderarticles__oxwrapid->value );
00387             $this->_aBasketContents[$sItemId]->setBundle( $oOrderArticle->isBundle() );
00388 
00389             //calling update method
00390             $this->onUpdate();
00391 
00392             return $this->_aBasketContents[$sItemId];
00393         } elseif ( $oOrderArticle->isBundle() ) {
00394             // deleting bundles, they are handled automatically
00395             $oOrderArticle->delete();
00396         }
00397     }
00398 
00406     public function setStockCheckMode( $blCheck )
00407     {
00408         $this->_blCheckStock = $blCheck;
00409     }
00410 
00416     public function getStockCheckMode()
00417     {
00418         return $this->_blCheckStock;
00419     }
00420 
00433     public function getItemKey( $sProductId, $aSel = null, $aPersParam = null, $blBundle = false, $sAdditionalParam = '' )
00434     {
00435         $aSel = ( $aSel != null) ? $aSel : array (0=>'0');
00436 
00437         $sItemKey = md5( $sProductId.'|'.serialize( $aSel ).'|'.serialize( $aPersParam ).'|'.( int ) $blBundle . '|' . serialize( $sAdditionalParam ) );
00438 
00439         return $sItemKey;
00440     }
00441 
00442 
00450     public function removeItem( $sItemKey )
00451     {
00452         if ($this->getConfig()->getConfigParam( 'blPsBasketReservationEnabled' )) {
00453             if (isset($this->_aBasketContents[$sItemKey])) {
00454                 $sArticleId = $this->_aBasketContents[$sItemKey]->getProductId();
00455                 if ($sArticleId) {
00456                     $this->getSession()
00457                             ->getBasketReservations()
00458                             ->discardArticleReservation($sArticleId);
00459                 }
00460             }
00461         }
00462         unset( $this->_aBasketContents[$sItemKey] );
00463 
00464         // basket exclude
00465         if ( !count($this->_aBasketContents) && $this->getConfig()->getConfigParam( 'blBasketExcludeEnabled' ) ) {
00466             $this->setBasketRootCatId(null);
00467         }
00468     }
00469 
00475     protected function _clearBundles()
00476     {
00477         reset( $this->_aBasketContents );
00478         while ( list( $sItemKey, $oBasketItem ) = each( $this->_aBasketContents ) ) {
00479             if ( $oBasketItem->isBundle() ) {
00480                 $this->removeItem( $sItemKey );
00481             }
00482         }
00483     }
00484 
00492     protected function _getArticleBundles( $oBasketItem )
00493     {
00494         $aBundles = array();
00495 
00496         if ( $oBasketItem->isBundle() ) {
00497             return $aBundles;
00498         }
00499 
00500         $oArticle = $oBasketItem->getArticle();
00501         if ( $oArticle && $oArticle->oxarticles__oxbundleid->value ) {
00502             $aBundles[$oArticle->oxarticles__oxbundleid->value] = 1;
00503         }
00504 
00505         return $aBundles;
00506     }
00507 
00515     protected function _getItemBundles( $oBasketItem )
00516     {
00517         if ( $oBasketItem->isBundle() ) {
00518             return array();
00519         }
00520 
00521         $aBundles = array();
00522 
00523         // does this object still exists ?
00524         if ( $oArticle = $oBasketItem->getArticle() ) {
00525             $aDiscounts = oxDiscountList::getInstance()->getBasketItemBundleDiscounts( $oArticle, $this, $this->getBasketUser() );
00526 
00527             foreach ( $aDiscounts as $oDiscount ) {
00528 
00529                 $iAmnt = $oDiscount->getBundleAmount( $oBasketItem->getAmount() );
00530                 if ( $iAmnt ) {
00531                     //init array element
00532                     if ( !isset( $aBundles[$oDiscount->oxdiscount__oxitmartid->value] ) ) {
00533                         $aBundles[$oDiscount->oxdiscount__oxitmartid->value] = 0;
00534                     }
00535 
00536                     $aBundles[$oDiscount->oxdiscount__oxitmartid->value] += $iAmnt;
00537                 }
00538             }
00539         }
00540 
00541         return $aBundles;
00542     }
00543 
00549     protected function _getBasketBundles()
00550     {
00551         $aBundles = array();
00552         $aDiscounts = oxDiscountList::getInstance()->getBasketBundleDiscounts( $this, $this->getBasketUser() );
00553 
00554         // calculating amount of non bundled/discount items
00555         $dAmount = 0;
00556         foreach ( $this->_aBasketContents as $oBasketItem ) {
00557             if ( !( $oBasketItem->isBundle() || $oBasketItem->isDiscountArticle() ) ) {
00558                 $dAmount += $oBasketItem->getAmount();
00559             }
00560         }
00561 
00562         foreach ( $aDiscounts as $oDiscount ) {
00563             if ($oDiscount->oxdiscount__oxitmartid->value) {
00564                 if ( !isset( $aBundles[$oDiscount->oxdiscount__oxitmartid->value] ) ) {
00565                     $aBundles[$oDiscount->oxdiscount__oxitmartid->value] = 0;
00566                 }
00567 
00568                 $aBundles[$oDiscount->oxdiscount__oxitmartid->value] += $oDiscount->getBundleAmount( $dAmount );
00569             }
00570         }
00571 
00572         return $aBundles;
00573     }
00574 
00581     protected function _addBundles()
00582     {
00583         // iterating through articles and binding bundles
00584         foreach ( $this->_aBasketContents as $key => $oBasketItem ) {
00585             try {
00586                 // adding discount type bundles
00587                 if ( !$oBasketItem->isDiscountArticle() && !$oBasketItem->isBundle() ) {
00588                     $aBundles = $this->_getItemBundles( $oBasketItem );
00589                 } else {
00590                     continue;
00591                 }
00592 
00593                 $this->_addBundlesToBasket( $aBundles );
00594 
00595                     // adding item type bundles
00596                     $aBundles = $this->_getArticleBundles( $oBasketItem );
00597 
00598                     // adding bundles to basket
00599                     $this->_addBundlesToBasket( $aBundles );
00600             } catch ( oxNoArticleException $oEx ) {
00601                 $this->removeItem( $key );
00602                 oxUtilsView::getInstance()->addErrorToDisplay( $oEx );
00603             } catch( oxArticleInputException $oEx ) {
00604                 $this->removeItem( $key );
00605                 oxUtilsView::getInstance()->addErrorToDisplay( $oEx );
00606             }
00607         }
00608 
00609         // adding global basket bundles
00610         if ( $aBundles = $this->_getBasketBundles() ) {
00611             $this->_addBundlesToBasket( $aBundles );
00612         }
00613 
00614     }
00615 
00623     protected function _addBundlesToBasket( $aBundles )
00624     {
00625         foreach ( $aBundles as $sBundleId => $dAmount ) {
00626             if ( $dAmount ) {
00627                 try {
00628                     if ( $oBundleItem = $this->addToBasket( $sBundleId, $dAmount, null, null, false, true ) ) {
00629                         $oBundleItem->setAsDiscountArticle( true );
00630                     }
00631                 } catch(oxArticleException $oEx) {
00632                     // caught and ignored
00633                 }
00634             }
00635         }
00636 
00637     }
00638 
00644     protected function _calcItemsPrice()
00645     {
00646         // resetting
00647         $this->setSkipDiscounts( false );
00648         $this->_iProductsCnt = 0; // count different types
00649         $this->_dItemsCnt    = 0; // count of item units
00650         $this->_dWeight      = 0; // basket weight
00651 
00652         // resetting
00653         $this->_aItemDiscounts = array();
00654 
00655         $this->_oProductsPriceList = oxNew( 'oxpricelist' );
00656         $this->_oDiscountProductsPriceList = oxNew( 'oxpricelist' );
00657         $this->_oNotDiscountedProductsPriceList = oxNew( 'oxpricelist' );
00658 
00659         $oDiscountList = oxDiscountList::getInstance();
00660 
00661         foreach ( $this->_aBasketContents as $oBasketItem ) {
00662             $this->_iProductsCnt++;
00663             $this->_dItemsCnt += $oBasketItem->getAmount();
00664             $this->_dWeight   += $oBasketItem->getWeight();
00665 
00666             if ( !$oBasketItem->isDiscountArticle() && ( $oArticle = $oBasketItem->getArticle() ) ) {
00667                 $oBasketPrice = $oArticle->getBasketPrice( $oBasketItem->getAmount(), $oBasketItem->getSelList(), $this );
00668                 $oBasketItem->setPrice( $oBasketPrice );
00669                 //P adding product price
00670                 $this->_oProductsPriceList->addToPriceList( $oBasketItem->getPrice() );
00671 
00672                 $oBasketPrice->setBruttoPriceMode();
00673                 if ( !$oArticle->skipDiscounts() && $this->canCalcDiscounts() ) {
00674                     // apply basket type discounts
00675                     $aItemDiscounts = $oDiscountList->applyBasketDiscounts( $oBasketPrice, $oDiscountList->getBasketItemDiscounts( $oArticle, $this, $this->getBasketUser() ), $oBasketItem->getAmount() );
00676                     if ( is_array($this->_aItemDiscounts) && is_array($aItemDiscounts) ) {
00677                         $this->_aItemDiscounts = $this->_mergeDiscounts( $this->_aItemDiscounts, $aItemDiscounts);
00678                     }
00679                 } else {
00680                     $oBasketItem->setSkipDiscounts( true );
00681                     $this->setSkipDiscounts( true );
00682                 }
00683                 $oBasketPrice->multiply( $oBasketItem->getAmount() );
00684 
00685                 //P collect discount values for basket items which are discountable
00686                 if ( !$oArticle->skipDiscounts() ) {
00687                     $this->_oDiscountProductsPriceList->addToPriceList( $oBasketPrice );
00688                 } else {
00689                     $this->_oNotDiscountedProductsPriceList->addToPriceList( $oBasketPrice );
00690                     $oBasketItem->setSkipDiscounts( true );
00691                     $this->setSkipDiscounts( true );
00692                 }
00693             } elseif ( $oBasketItem->isBundle() ) {
00694                 // if bundles price is set to zero
00695                 $oPrice = oxNew( "oxprice");
00696                 $oBasketItem->setPrice( $oPrice );
00697             }
00698         }
00699     }
00700 
00708     public function setDiscountCalcMode( $blCalcDiscounts )
00709     {
00710         $this->_blCalcDiscounts = $blCalcDiscounts;
00711     }
00712 
00718     public function canCalcDiscounts()
00719     {
00720         return $this->_blCalcDiscounts;
00721     }
00722 
00732     protected function _mergeDiscounts( $aDiscounts, $aItemDiscounts)
00733     {
00734         foreach ( $aItemDiscounts as $sKey => $oDiscount ) {
00735             // add prices of the same discounts
00736             if ( array_key_exists ($sKey, $aDiscounts) ) {
00737                 $aDiscounts[$sKey]->dDiscount += $oDiscount->dDiscount;
00738             } else {
00739                 $aDiscounts[$sKey] = $oDiscount;
00740             }
00741         }
00742         return $aDiscounts;
00743     }
00744 
00750     protected function _calcDeliveryCost()
00751     {
00752         if ( $this->_oDeliveryPrice !== null ) {
00753             return $this->_oDeliveryPrice;
00754         }
00755         $myConfig  = $this->getConfig();
00756         $oDeliveryPrice = oxNew( 'oxprice' );
00757         $oDeliveryPrice->setBruttoPriceMode();
00758 
00759         // don't calculate if not logged in
00760         $oUser = $this->getBasketUser();
00761 
00762         if ( !$oUser && !$myConfig->getConfigParam( 'blCalculateDelCostIfNotLoggedIn' ) ) {
00763             return $oDeliveryPrice;
00764         }
00765 
00766         // VAT for delivery ?
00767         $fDelVATPercent = 0;
00768         if ( $myConfig->getConfigParam( 'blCalcVATForDelivery' ) ) {
00769             $fDelVATPercent = $this->getMostUsedVatPercent();
00770             $oDeliveryPrice->setVat( $fDelVATPercent );
00771         }
00772 
00773         // list of active delivery costs
00774         if ( $myConfig->getConfigParam('bl_perfLoadDelivery') ) {
00775             $aDeliveryList = oxDeliveryList::getInstance()->getDeliveryList( $this,
00776                                         $oUser,
00777                                         $this->_findDelivCountry(),
00778                                         $this->getShippingId()
00779                                     );
00780 
00781             if ( count( $aDeliveryList ) > 0 ) {
00782                 foreach ( $aDeliveryList as $oDelivery ) {
00783                     //debug trace
00784                     if ( $myConfig->getConfigParam( 'iDebug' ) == 5 ) {
00785                         echo( "DelCost : ".$oDelivery->oxdelivery__oxtitle->value."<br>" );
00786                     }
00787                     $oDeliveryPrice->addPrice( $oDelivery->getDeliveryPrice( $fDelVATPercent ) );
00788                 }
00789             }
00790         }
00791 
00792         return $oDeliveryPrice;
00793     }
00794 
00800     public function getBasketUser()
00801     {
00802         if ( $this->_oUser == null ) {
00803             return $this->getUser();
00804         }
00805 
00806         return $this->_oUser;
00807     }
00808 
00816     public function setBasketUser( $oUser )
00817     {
00818         $this->_oUser = $oUser;
00819     }
00820 
00821     //P
00827     public function getMostUsedVatPercent()
00828     {
00829         return $this->_oProductsPriceList->getMostUsedVatPercent();
00830     }
00831 
00832     //P
00839     protected function _calcTotalPrice()
00840     {
00841         // 1. add products price
00842         $dprice = $this->_oProductsPriceList->getBruttoSum();
00843         $this->_oPrice->setPrice( $dprice );
00844 
00845         // 2. substract discounts
00846         if ( $dprice ) {
00847 
00848             // 2.1 applying basket item discounts
00849             foreach ( $this->_aItemDiscounts as $oDiscount ) {
00850 
00851                 // skipping bundle discounts
00852                 if ( $oDiscount->sType == 'itm' ) {
00853                     continue;
00854                 }
00855                 $this->_oPrice->subtract( $oDiscount->dDiscount );
00856             }
00857 
00858             // 2.2 applying basket discounts
00859             $this->_oPrice->subtract( $this->_oTotalDiscount->getBruttoPrice() );
00860 
00861             // 2.3 applying voucher discounts
00862             if ($oVoucherDisc = $this->getVoucherDiscount()) {
00863                 $this->_oPrice->subtract( $oVoucherDisc->getBruttoPrice() );
00864             }
00865         }
00866 
00867         // 2.3 add delivery cost
00868         if ( isset( $this->_aCosts['oxdelivery'] ) ) {
00869             $this->_oPrice->add( $this->_aCosts['oxdelivery']->getBruttoPrice() );
00870         }
00871 
00872         // 2.4 add wrapping price
00873         if ( isset( $this->_aCosts['oxwrapping'] ) ) {
00874             $this->_oPrice->add( $this->_aCosts['oxwrapping']->getBruttoPrice() );
00875         }
00876 
00877         // 2.5 add payment price
00878         if ( isset( $this->_aCosts['oxpayment'] ) ) {
00879             $this->_oPrice->add( $this->_aCosts['oxpayment']->getBruttoPrice() );
00880         }
00881 
00882         // 2.6 add TS protection price
00883         if ( isset( $this->_aCosts['oxtsprotection'] ) ) {
00884             $this->_oPrice->add( $this->_aCosts['oxtsprotection']->getBruttoPrice() );
00885         }
00886 
00887     }
00888 
00896     public function setVoucherDiscount( $dDiscount )
00897     {
00898         $this->_oVoucherDiscount = oxNew( 'oxPrice' );
00899         $this->_oVoucherDiscount->setBruttoPriceMode();
00900         $this->_oVoucherDiscount->add( $dDiscount );
00901     }
00902 
00908     protected function _calcVoucherDiscount()
00909     {
00910         if ( $this->getConfig()->getConfigParam( 'bl_showVouchers' ) && ($this->_oVoucherDiscount === null || ( $this->_blUpdateNeeded && !$this->isAdmin() ) ) ) {
00911 
00912             $this->_oVoucherDiscount = oxNew( 'oxPrice' );
00913             $this->_oVoucherDiscount->setBruttoPriceMode();
00914 
00915 
00916             // calculating price to apply discount
00917             $dPrice = $this->_oDiscountProductsPriceList->getBruttoSum() - $this->_oTotalDiscount->getBruttoPrice();
00918 
00919             // recalculating
00920             if ( count( $this->_aVouchers ) ) {
00921                 $oLang = oxLang::getInstance();
00922                 foreach ( $this->_aVouchers as $sVoucherId => $oStdVoucher ) {
00923                     $oVoucher = oxNew( 'oxvoucher' );
00924                     try { // checking
00925                         $oVoucher->load( $oStdVoucher->sVoucherId );
00926 
00927                         if ( !$this->_blSkipVouchersAvailabilityChecking ) {
00928                             $oVoucher->checkBasketVoucherAvailability( $this->_aVouchers, $dPrice );
00929                             $oVoucher->checkUserAvailability( $this->getBasketUser() );
00930                         }
00931 
00932                         // assigning real voucher discount value as this is the only place where real value is calculated
00933                         $dVoucherdiscount = $oVoucher->getDiscountValue( $dPrice );
00934 
00935                         // acumulating discount value
00936                         $this->_oVoucherDiscount->add( $dVoucherdiscount );
00937 
00938                         // collecting formatted for preview
00939                         $oStdVoucher->fVoucherdiscount = $oLang->formatCurrency( $dVoucherdiscount, $this->getBasketCurrency() );
00940                         $oStdVoucher->dVoucherdiscount = $dVoucherdiscount;
00941 
00942                         // substracting voucher discount
00943                         $dPrice -= $dVoucherdiscount;
00944                     } catch ( oxVoucherException $oEx ) {
00945 
00946                         // removing voucher on error
00947                         $oVoucher->unMarkAsReserved();
00948                         unset( $this->_aVouchers[$sVoucherId] );
00949 
00950                         // storing voucher error info
00951                         oxUtilsView::getInstance()->addErrorToDisplay($oEx, false, true);
00952                     }
00953                 }
00954             }
00955         }
00956     }
00957 
00958     //V
00965     protected function _applyDiscounts()
00966     {
00967         $dBruttoPrice = 0;
00968         $this->_aDiscountedVats = array();
00969         if ( $oPriceList = $this->getDiscountProductsPrice() ) {
00970             $dBruttoPrice = $oPriceList->getBruttoSum();
00971             $this->_aDiscountedVats = $oPriceList->getVatInfo();
00972         }
00973 
00974         //apply discounts for brutto price
00975         $dDiscountedBruttoPrice = $this->getDiscountedProductsBruttoPrice();
00976         $oTotalDiscount   = $this->getTotalDiscount();
00977         $oVoucherDiscount = $this->getVoucherDiscount();
00978 
00979         //apply discount for VATs
00980         if ( $dBruttoPrice &&
00981              ( ( $oTotalDiscount && $oTotalDiscount->getBruttoPrice() ) ||
00982                ( $oVoucherDiscount && $oVoucherDiscount->getBruttoPrice() )
00983              )
00984            ) {
00985             $dPercent = ( $dDiscountedBruttoPrice / $dBruttoPrice) * 100;
00986             foreach ( $this->_aDiscountedVats as $sKey => $dVat ) {
00987                 $this->_aDiscountedVats[$sKey] = oxPrice::percent( $dVat, $dPercent);
00988             }
00989         }
00990 
00991         $oUtils = oxUtils::getInstance();
00992         $dDiscVatSum = 0;
00993         foreach ( $this->_aDiscountedVats as $dVat ) {
00994             $dDiscVatSum += $oUtils->fRound( -$dVat, $this->_oCurrency);
00995         }
00996         //calculate netto price with discounts
00997         $this->_dDiscountedProductNettoPrice = $dDiscountedBruttoPrice + $dDiscVatSum;
00998     }
00999 
01005     protected function _calcBasketDiscount()
01006     {
01007         // resetting
01008         $this->_aDiscounts = array();
01009 
01010         // P using prices sum which has discount, not sum of skipped discounts
01011         $dOldprice = $this->_oDiscountProductsPriceList->getBruttoSum();
01012 
01013         // add basket discounts
01014         $aDiscounts = oxDiscountList::getInstance()->getBasketDiscounts( $this, $this->getBasketUser() );
01015 
01016         foreach ( $aDiscounts as $oDiscount ) {
01017 
01018             // storing applied discounts
01019             $oStdDiscount = $oDiscount->getSimpleDiscount();
01020 
01021             // skipping bundle discounts
01022             if ( $oDiscount->oxdiscount__oxaddsumtype->value == 'itm' ) {
01023                 continue;
01024             }
01025 
01026             // saving discount info
01027             $oStdDiscount->dDiscount = $oDiscount->getAbsValue( $dOldprice );
01028             if ($dOldprice < $oStdDiscount->dDiscount) {
01029                 $oStdDiscount->dDiscount = $dOldprice;
01030             }
01031 
01032             if ($oStdDiscount->dDiscount != 0) {
01033                 $this->_aDiscounts[$oDiscount->getId()] = $oStdDiscount;
01034                 // substracting product price after discount
01035                 $dOldprice = $dOldprice - $oStdDiscount->dDiscount;
01036             }
01037         }
01038     }
01039 
01045     protected function _calcBasketTotalDiscount()
01046     {
01047         if ( $this->_oTotalDiscount === null || ( $this->_blUpdateNeeded && !$this->isAdmin() ) ) {
01048             $this->_oTotalDiscount = oxNew( 'oxPrice' );
01049             $this->_oTotalDiscount->setBruttoPriceMode();
01050 
01051             if ( is_array($this->_aDiscounts) ) {
01052                 foreach ( $this->_aDiscounts as $oDiscount ) {
01053 
01054                     // skipping bundle discounts
01055                     if ( $oDiscount->sType == 'itm' ) {
01056                         continue;
01057                     }
01058 
01059                     // add discount value to total basket discount
01060                     $this->_oTotalDiscount->add( $oDiscount->dDiscount );
01061                 }
01062             }
01063         }
01064     }
01065 
01075     protected function _calcBasketWrapping()
01076     {
01077         $myConfig = $this->getConfig();
01078         $oWrappingPrice = oxNew( 'oxPrice' );
01079         $oWrappingPrice->setBruttoPriceMode();
01080 
01081         // wrapping VAT
01082         if ( $myConfig->getConfigParam( 'blCalcVatForWrapping' ) ) {
01083             $oWrappingPrice->setVat( $this->getMostUsedVatPercent() );
01084         }
01085 
01086         // calculating basket items wrapping
01087         foreach ( $this->_aBasketContents as $oBasketItem ) {
01088 
01089             if ( ( $oWrapping = $oBasketItem->getWrapping() ) ) {
01090                 $oWrapPrice = $oWrapping->getWrappingPrice( $oBasketItem->getAmount() );
01091                 $oWrappingPrice->add( $oWrapPrice->getBruttoPrice() );
01092             }
01093         }
01094 
01095         // gift card price calculation
01096         if ( ( $oCard = $this->getCard() ) ) {
01097             $oCardPrice = $oCard->getWrappingPrice();
01098             $oWrappingPrice->add( $oCardPrice->getBruttoPrice() );
01099         }
01100 
01101         return $oWrappingPrice;
01102     }
01103 
01110     protected function _calcPaymentCost()
01111     {
01112         // resetting values
01113         $oPaymentPrice = oxNew( 'oxPrice' );
01114         $oPaymentPrice->setBruttoPriceMode();
01115 
01116         // payment
01117         if ( ( $this->_sPaymentId = $this->getPaymentId() ) ) {
01118 
01119             $oPayment = oxNew( 'oxpayment' );
01120             $oPayment->load( $this->_sPaymentId );
01121 
01122             $oPaymentPrice = $oPayment->getPaymentPrice( $this );
01123         }
01124 
01125         return $oPaymentPrice;
01126     }
01127 
01134     protected function _calcTsProtectionCost()
01135     {
01136         // resetting values
01137         $oProtectionPrice = oxNew( 'oxPrice' );
01138         $oProtectionPrice->setBruttoPriceMode();
01139 
01140         // payment
01141         if ( ( $this->_sTsProductId = $this->getTsProductId() ) ) {
01142 
01143             $oTsProtection = oxNew('oxtsprotection');
01144             $oTsProduct = $oTsProtection->getTsProduct( $this->_sTsProductId );
01145 
01146             $oProtectionPrice = $oTsProduct->getPrice();
01147         }
01148         return $oProtectionPrice;
01149     }
01150 
01159     public function setCost( $sCostName, $oPrice = null )
01160     {
01161         $this->_aCosts[$sCostName] = $oPrice;
01162     }
01163 
01172     public function calculateBasket( $blForceUpdate = false )
01173     {
01174         if ( !$this->isEnabled() ) {
01175             return;
01176         }
01177 
01178         if ( !$this->_blUpdateNeeded && !$blForceUpdate ) {
01179             return;
01180         }
01181 
01182         $this->_aCosts = array();
01183 
01184         $this->_oPrice = oxNew( 'oxprice' );
01185         $this->_oPrice->setBruttoPriceMode();
01186 
01187         //  1. saving basket to the database
01188         $this->_save();
01189 
01190         //  2. remove all bundles
01191         $this->_clearBundles();
01192 
01193         //  3. generate bundle items
01194         $this->_addBundles();
01195 
01196         // reserve active basket
01197         if ($this->getConfig()->getConfigParam( 'blPsBasketReservationEnabled' )) {
01198             $this->getSession()->getBasketReservations()->reserveBasket($this);
01199         }
01200 
01201         //  4. calculating item prices
01202         $this->_calcItemsPrice();
01203 
01204         //  5. calculating/applying discounts
01205         $this->_calcBasketDiscount();
01206 
01207         //  6. calculating basket total discount
01208         $this->_calcBasketTotalDiscount();
01209 
01210         //  7. check for vouchers
01211         $this->_calcVoucherDiscount();
01212 
01213         //  8. applies all discounts to pricelist
01214         $this->_applyDiscounts();
01215 
01216         //  9. calculating additional costs:
01217         //  9.1: delivery
01218         $this->setCost( 'oxdelivery', $this->_calcDeliveryCost() );
01219 
01220         //  9.2: adding wrapping costs
01221         $this->setCost( 'oxwrapping', $this->_calcBasketWrapping() );
01222 
01223         //  9.3: adding payment cost
01224         $this->setCost( 'oxpayment', $this->_calcPaymentCost() );
01225 
01226         //  9.4: adding TS protection cost
01227         $this->setCost( 'oxtsprotection', $this->_calcTsProtectionCost() );
01228 
01229         //  10. calculate total price
01230         $this->_calcTotalPrice();
01231 
01232         //  11. setting deprecated values
01233         $this->_setDeprecatedValues();
01234 
01235         //  12.setting to up-to-date status
01236         $this->afterUpdate();
01237     }
01238 
01244     public function onUpdate()
01245     {
01246         $this->_blUpdateNeeded = true;
01247     }
01248 
01254     public function afterUpdate()
01255     {
01256         $this->_blUpdateNeeded = false;
01257     }
01258 
01266     public function getBasketSummary()
01267     {
01268         if ( $this->_blUpdateNeeded || $this->_aBasketSummary === null ) {
01269             $this->_aBasketSummary = new Oxstdclass();
01270             $this->_aBasketSummary->aArticles = array();
01271             $this->_aBasketSummary->aCategories = array();
01272             $this->_aBasketSummary->iArticleCount = 0;
01273             $this->_aBasketSummary->dArticlePrice = 0;
01274             $this->_aBasketSummary->dArticleDiscountablePrice = 0;
01275         }
01276 
01277         if ( !$this->isEnabled() ) {
01278             return $this->_aBasketSummary;
01279         }
01280 
01281         $myConfig = $this->getConfig();
01282         foreach ( $this->_aBasketContents as $oBasketItem ) {
01283             if ( !$oBasketItem->isBundle() && $oArticle = $oBasketItem->getArticle(false) ) {
01284                 $aCatIds = $oArticle->getCategoryIds();
01285                 //#M530 if price is not loaded for articles
01286                 $dPrice = 0;
01287                 $dDiscountablePrice = 0;
01288                 if ( ( $oPrice = $oArticle->getPrice( $oBasketItem->getAmount() ) ) ) {
01289                     $dPrice = $oPrice->getBruttoPrice();
01290                     if ( !$oArticle->skipDiscounts() ) {
01291                         $dDiscountablePrice = $dPrice;
01292                     }
01293                 }
01294 
01295                 foreach ( $aCatIds as $sCatId ) {
01296                     if ( !isset( $this->_aBasketSummary->aCategories[$sCatId] ) ) {
01297                         $this->_aBasketSummary->aCategories[$sCatId] = new Oxstdclass();
01298                     }
01299 
01300                     $this->_aBasketSummary->aCategories[$sCatId]->dPrice  += $dPrice * $oBasketItem->getAmount();
01301                     $this->_aBasketSummary->aCategories[$sCatId]->dDiscountablePrice += $dDiscountablePrice * $oBasketItem->getAmount();
01302                     $this->_aBasketSummary->aCategories[$sCatId]->dAmount += $oBasketItem->getAmount();
01303                     $this->_aBasketSummary->aCategories[$sCatId]->iCount++;
01304                 }
01305 
01306                 // variant handling
01307                 if ( ($sParentId = $oArticle->getProductParentId()) && $myConfig->getConfigParam( 'blVariantParentBuyable' ) ) {
01308                     if ( !isset( $this->_aBasketSummary->aArticles[$sParentId] ) ) {
01309                         $this->_aBasketSummary->aArticles[$sParentId] = 0;
01310                     }
01311                     $this->_aBasketSummary->aArticles[$sParentId] += $oBasketItem->getAmount();
01312                 }
01313 
01314                 if ( !isset( $this->_aBasketSummary->aArticles[$oBasketItem->getProductId()] ) ) {
01315                     $this->_aBasketSummary->aArticles[$oBasketItem->getProductId()] = 0;
01316                 }
01317 
01318                 $this->_aBasketSummary->aArticles[$oBasketItem->getProductId()] += $oBasketItem->getAmount();
01319                 $this->_aBasketSummary->iArticleCount += $oBasketItem->getAmount();
01320                 $this->_aBasketSummary->dArticlePrice += $dPrice * $oBasketItem->getAmount();
01321                 $this->_aBasketSummary->dArticleDiscountablePrice += $dDiscountablePrice * $oBasketItem->getAmount();
01322             }
01323         }
01324         return $this->_aBasketSummary;
01325     }
01326 
01338     public function addVoucher( $sVoucherId )
01339     {
01340         // calculating price to check
01341         // P using prices sum which has discount, not sum of skipped discounts
01342         $dPrice = 0;
01343         if ( $this->_oDiscountProductsPriceList ) {
01344             $dPrice = $this->_oDiscountProductsPriceList->getBruttoSum();
01345         }
01346 
01347         try { // trying to load voucher and apply it
01348 
01349             $oVoucher = oxNew( 'oxvoucher' );
01350 
01351             if ( !$this->_blSkipVouchersAvailabilityChecking ) {
01352                 $oVoucher->getVoucherByNr( $sVoucherId, $this->_aVouchers, true );
01353                 $oVoucher->checkVoucherAvailability( $this->_aVouchers, $dPrice );
01354                 $oVoucher->checkUserAvailability( $this->getBasketUser() );
01355                 $oVoucher->markAsReserved();
01356             } else {
01357                 $oVoucher->load( $sVoucherId );
01358             }
01359 
01360             // saving voucher info
01361             $this->_aVouchers[$oVoucher->oxvouchers__oxid->value] = $oVoucher->getSimpleVoucher();
01362         } catch ( oxVoucherException $oEx ) {
01363 
01364             // problems adding voucher
01365             oxUtilsView::getInstance()->addErrorToDisplay( $oEx, false, true );
01366         }
01367 
01368         $this->onUpdate();
01369     }
01370 
01378     public function removeVoucher( $sVoucherId )
01379     {
01380         // removing if it exists
01381         if ( isset( $this->_aVouchers[$sVoucherId] ) ) {
01382 
01383             $oVoucher = oxNew( 'oxvoucher' );
01384             $oVoucher->load( $sVoucherId );
01385 
01386             $oVoucher->unMarkAsReserved();
01387 
01388             // unsetting it if exists this voucher in DB or not
01389             unset( $this->_aVouchers[$sVoucherId] );
01390             $this->onUpdate();
01391         }
01392 
01393     }
01394 
01400     public function resetUserInfo()
01401     {
01402         $this->setPayment( null );
01403         $this->setShipping( null );
01404     }
01405 
01413     protected function _setDeprecatedValues()
01414     {
01415         // discount information
01416         // formating discount value
01417         $this->aDiscounts = $this->getDiscounts();
01418         if ( count($this->aDiscounts) > 0 ) {
01419             $oLang = oxLang::getInstance();
01420             foreach ($this->aDiscounts as $oDiscount) {
01421                 $oDiscount->fDiscount = $oLang->formatCurrency( $oDiscount->dDiscount, $this->getBasketCurrency() );
01422             }
01423         }
01424     }
01425 
01426 
01432     protected function _canSaveBasket()
01433     {
01434         $blCanSave = !$this->getConfig()->getConfigParam( 'blPerfNoBasketSaving' );
01435         return $blCanSave;
01436     }
01437 
01443     public function load()
01444     {
01445         $oUser = $this->getBasketUser();
01446         if ( !$oUser ) {
01447             return;
01448         }
01449 
01450         $oBasket = $oUser->getBasket( 'savedbasket' );
01451 
01452         // restoring from saved history
01453         $aSavedItems = $oBasket->getItems();
01454         foreach ( $aSavedItems as $oItem ) {
01455             try {
01456                 $oSelList = $oItem->getSelList();
01457 
01458                 $this->addToBasket( $oItem->oxuserbasketitems__oxartid->value, $oItem->oxuserbasketitems__oxamount->value, $oSelList, $oItem->getPersParams(), true );
01459             } catch( oxArticleException $oEx ) {
01460                 // caught and ignored
01461             }
01462         }
01463     }
01464 
01470     protected function _save()
01471     {
01472         if ( $this->_canSaveBasket() ) {
01473 
01474             if ( $oUser = $this->getBasketUser() ) {
01475                 //first delete all contents
01476                 //#2039
01477                 $oSavedBasket = $oUser->getBasket( 'savedbasket' );
01478                 $oSavedBasket->delete();
01479 
01480                 //then save
01481                 foreach ( $this->_aBasketContents as $oBasketItem ) {
01482                     // discount or bundled products will be added automatically if available
01483                     if ( !$oBasketItem->isBundle() && !$oBasketItem->isDiscountArticle() ) {
01484                        $oSavedBasket->addItemToBasket( $oBasketItem->getProductId(), $oBasketItem->getAmount(), $oBasketItem->getSelList(), true, $oBasketItem->getPersParams() );
01485                     }
01486                 }
01487             }
01488         }
01489     }
01490 
01502     /*
01503     protected function _addItemToSavedBasket( $sProductId , $dAmount, $aSel, $blOverride = false, $aPersParam = null )
01504     {
01505         // updating basket history
01506         if ( $oUser = $this->getBasketUser() ) {
01507             $oUser->getBasket( 'savedbasket' )->addItemToBasket( $sProductId, $dAmount, $aSel, $blOverride, $aPersParam );
01508         }
01509     }*/
01510 
01518     protected function _deleteSavedBasket()
01519     {
01520         // deleting basket if session user available
01521         if ( $oUser = $this->getBasketUser() ) {
01522             $oUser->getBasket( 'savedbasket' )->delete();
01523         }
01524 
01525         // basket exclude
01526         if ( $this->getConfig()->getConfigParam( 'blBasketExcludeEnabled' )) {
01527             $this->setBasketRootCatId(null);
01528         }
01529     }
01530 
01536     protected function _findDelivCountry()
01537     {
01538         $myConfig = $this->getConfig();
01539         $oUser    = $this->getBasketUser();
01540 
01541         $sDelivCountry = null;
01542 
01543         if ( !$oUser ) {
01544             // don't calculate if not logged in unless specified otherwise
01545             $aHomeCountry = $myConfig->getConfigParam( 'aHomeCountry' );
01546             if ( $myConfig->getConfigParam( 'blCalculateDelCostIfNotLoggedIn' ) && is_array( $aHomeCountry ) ) {
01547                 $sDelivCountry = current( $aHomeCountry );
01548             }
01549         } else {
01550 
01551             // ok, logged in
01552             if ( $sCountryId = $myConfig->getGlobalParameter( 'delcountryid' ) ) {
01553                 $sDelivCountry = $sCountryId;
01554             } elseif ( $sAddressId = oxSession::getVar( 'deladrid' ) ) {
01555 
01556                 $oDelAdress = oxNew( 'oxaddress' );
01557                 if ( $oDelAdress->load( $sAddressId ) ) {
01558                     $sDelivCountry = $oDelAdress->oxaddress__oxcountryid->value;
01559                 }
01560             }
01561 
01562             // still not found ?
01563             if ( !$sDelivCountry ) {
01564                 $sDelivCountry = $oUser->oxuser__oxcountryid->value;
01565             }
01566         }
01567 
01568         return $sDelivCountry;
01569     }
01570 
01576     public function deleteBasket()
01577     {
01578         $this->_aBasketContents = array();
01579         $this->getSession()->delBasket();
01580 
01581         if ($this->getConfig()->getConfigParam( 'blPsBasketReservationEnabled' )) {
01582             $this->getSession()->getBasketReservations()->discardReservations();
01583         }
01584 
01585         // merging basket history
01586         if ( !$this->getConfig()->getConfigParam( 'blPerfNoBasketSaving' ) ) {
01587             $this->_deleteSavedBasket();
01588         }
01589     }
01590 
01598     public function setPayment( $sPaymentId = null )
01599     {
01600         $this->_sPaymentId = $sPaymentId;
01601     }
01602 
01608     public function getPaymentId()
01609     {
01610         if ( !$this->_sPaymentId ) {
01611              $this->_sPaymentId = oxSession::getVar( 'paymentid' );
01612         }
01613         return $this->_sPaymentId;
01614     }
01615 
01623     public function setShipping( $sShippingSetId = null )
01624     {
01625         $this->_sShippingSetId = $sShippingSetId;
01626         oxSession::setVar( 'sShipSet', $sShippingSetId );
01627     }
01628 
01636     public function setDeliveryPrice( $oShippingPrice = null )
01637     {
01638         $this->_oDeliveryPrice = $oShippingPrice;
01639     }
01640 
01646     public function getShippingId()
01647     {
01648         if ( !$this->_sShippingSetId ) {
01649              $this->_sShippingSetId = oxSession::getVar( 'sShipSet' );
01650         }
01651 
01652         $sActPaymentId = $this->getPaymentId();
01653         // setting default if none is set
01654         if ( !$this->_sShippingSetId && $sActPaymentId != 'oxempty' ) {
01655             $oUser = $this->getUser();
01656 
01657             // choosing first preferred delivery set
01658             list( , $sActShipSet ) = oxDeliverySetList::getInstance()->getDeliverySetData( null, $oUser, $this );
01659             // in case nothing was found and no user set - choosing default
01660             $this->_sShippingSetId = $sActShipSet ? $sActShipSet : ( $oUser ? null : 'oxidstandard' );
01661         } elseif ( !$this->isAdmin() && $sActPaymentId == 'oxempty' ) {
01662             // in case 'oxempty' is payment id - delivery set must be reset
01663             $this->_sShippingSetId = null;
01664         }
01665 
01666         return $this->_sShippingSetId;
01667     }
01668 
01674     public function getBasketArticles()
01675     {
01676         $aBasketArticles = array();
01677 
01678         foreach ( $this->_aBasketContents as $sItemKey => $oBasketItem ) {
01679             try {
01680                 $oProduct = $oBasketItem->getArticle();
01681 
01682                 if ( $this->getConfig()->getConfigParam( 'bl_perfLoadSelectLists' ) ) {
01683                     // marking chosen select list
01684                     $aSelList = $oBasketItem->getSelList();
01685                     if ( is_array( $aSelList ) && ( $aSelectlist = $oProduct->getSelectLists( $sItemKey ) ) ) {
01686                         reset( $aSelList );
01687                         while ( list( $conkey, $iSel ) = each( $aSelList ) ) {
01688                             $aSelectlist[$conkey][$iSel] = $aSelectlist[$conkey][$iSel];
01689                             $aSelectlist[$conkey][$iSel]->selected = 1;
01690                         }
01691                         $oProduct->setSelectlist( $aSelectlist );
01692                     }
01693                 }
01694             } catch ( oxNoArticleException $oEx ) {
01695                 oxUtilsView::getInstance()->addErrorToDisplay( $oEx );
01696                 $this->removeItem( $sItemKey );
01697                 $this->calculateBasket( true );
01698                 continue;
01699             } catch ( oxArticleInputException $oEx ) {
01700                 oxUtilsView::getInstance()->addErrorToDisplay( $oEx );
01701                 $this->removeItem( $sItemKey );
01702                 $this->calculateBasket( true );
01703                 continue;
01704             }
01705 
01706             $aBasketArticles[$sItemKey] = $oProduct;
01707         }
01708         return $aBasketArticles;
01709     }
01710 
01716     public function getDiscountProductsPrice()
01717     {
01718         return $this->_oDiscountProductsPriceList;
01719     }
01720 
01726     public function getProductsPrice()
01727     {
01728         if ( is_null($this->_oProductsPriceList) ) {
01729             $this->_oProductsPriceList = oxNew( 'oxPriceList' );
01730         }
01731 
01732         return $this->_oProductsPriceList;
01733     }
01734 
01740     public function getPrice()
01741     {
01742         if ( is_null($this->_oPrice) ) {
01743             $this->_oPrice = oxNew( 'oxprice' );
01744         }
01745 
01746         return $this->_oPrice;
01747     }
01748 
01755     public function getOrderId()
01756     {
01757         return $this->_sOrderId;
01758     }
01759 
01767     public function setOrderId( $sId )
01768     {
01769         $this->_sOrderId = $sId;
01770     }
01771 
01780     public function getCosts( $sId = null )
01781     {
01782         // if user want some specific cost - return it
01783         if ( $sId ) {
01784             return isset( $this->_aCosts[$sId] )?$this->_aCosts[$sId]:null;
01785         }
01786         return $this->_aCosts;
01787     }
01788 
01794     public function getVouchers()
01795     {
01796         return $this->_aVouchers;
01797     }
01798 
01804     public function getProductsCount()
01805     {
01806         return $this->_iProductsCnt;
01807     }
01808 
01814     public function getItemsCount()
01815     {
01816         return $this->_dItemsCnt;
01817     }
01818 
01824     public function getWeight()
01825     {
01826         return $this->_dWeight;
01827     }
01828 
01834     public function getContents()
01835     {
01836         return $this->_aBasketContents;
01837     }
01838 
01846     public function getProductVats( $blFormatCurrency = true)
01847     {
01848         if ( !$this->_oNotDiscountedProductsPriceList ) {
01849             return array();
01850         }
01851 
01852         $aVats = $this->_oNotDiscountedProductsPriceList->getVatInfo();
01853 
01854         $oUtils = oxUtils::getInstance();
01855         foreach ( $this->_aDiscountedVats as $sKey => $dVat ) {
01856             if ( !isset( $aVats[$sKey] ) ) {
01857                 $aVats[$sKey] = 0;
01858             }
01859             // add prices of the same discounts
01860             $aVats[$sKey] += $oUtils->fRound( $dVat, $this->_oCurrency );
01861         }
01862 
01863         if ( $blFormatCurrency ) {
01864             $oLang = oxLang::getInstance();
01865             foreach ( $aVats as $sKey => $dVat ) {
01866                 $aVats[$sKey] = $oLang->formatCurrency( $dVat, $this->getBasketCurrency() );
01867             }
01868         }
01869 
01870         return $aVats;
01871     }
01872 
01878     public function getDiscountedNettoPrice()
01879     {
01880         if ( $this->_oNotDiscountedProductsPriceList ) {
01881             return $this->_dDiscountedProductNettoPrice + $this->_oNotDiscountedProductsPriceList->getNettoSum();
01882         }
01883         return false;
01884     }
01885 
01893     public function setCardMessage( $sMessage )
01894     {
01895         $this->_sCardMessage = $sMessage;
01896     }
01897 
01903     public function getCardMessage()
01904     {
01905         return $this->_sCardMessage;
01906     }
01907 
01915     public function setCardId( $sCardId )
01916     {
01917         $this->_sCardId = $sCardId;
01918     }
01919 
01925     public function getCardId()
01926     {
01927         return $this->_sCardId;
01928     }
01929 
01935     public function getCard()
01936     {
01937         $oCard = null;
01938         if ( $sCardId = $this->getCardId() ) {
01939             $oCard = oxNew( 'oxwrapping' );
01940             $oCard->load( $sCardId );
01941         }
01942         return $oCard;
01943     }
01944 
01950     public function getTotalDiscount()
01951     {
01952         return $this->_oTotalDiscount;
01953     }
01954 
01960     public function getDiscounts()
01961     {
01962         if ( $this->getTotalDiscount() && $this->getTotalDiscount()->getBruttoPrice() == 0 && count($this->_aItemDiscounts) == 0) {
01963             return null;
01964         }
01965 
01966         return array_merge($this->_aItemDiscounts, $this->_aDiscounts);
01967     }
01968 
01974     public function getVoucherDiscount()
01975     {
01976         if ($this->getConfig()->getConfigParam( 'bl_showVouchers' )) {
01977             return $this->_oVoucherDiscount;
01978         }
01979         return null;
01980     }
01981 
01989     public function setBasketCurrency( $oCurrency )
01990     {
01991         $this->_oCurrency = $oCurrency;
01992     }
01993 
01999     public function getBasketCurrency()
02000     {
02001         if ( $this->_oCurrency === null ) {
02002             $this->_oCurrency = $this->getConfig()->getActShopCurrencyObject();
02003         }
02004 
02005         return $this->_oCurrency;
02006     }
02007 
02015     public function setSkipVouchersChecking( $blSkipChecking = null )
02016     {
02017         $this->_blSkipVouchersAvailabilityChecking = $blSkipChecking;
02018     }
02019 
02025     public function hasSkipedDiscount()
02026     {
02027         return $this->_blSkipDiscounts;
02028     }
02029 
02037     public function setSkipDiscounts( $blSkip )
02038     {
02039         $this->_blSkipDiscounts = $blSkip;
02040     }
02041 
02047     public function getProductsNetPrice()
02048     {
02049         return oxLang::getInstance()->formatCurrency( $this->getDiscountedNettoPrice(), $this->getBasketCurrency() );
02050     }
02051 
02057     public function getFProductsPrice()
02058     {
02059         if ( $this->_oProductsPriceList ) {
02060             return oxLang::getInstance()->formatCurrency( $this->_oProductsPriceList->getBruttoSum(), $this->getBasketCurrency() );
02061         }
02062         return null;
02063     }
02064 
02070     public function getDelCostVatPercent()
02071     {
02072         return $this->getCosts( 'oxdelivery' )->getVat();
02073     }
02074 
02080     public function getDelCostVat()
02081     {
02082         $dDelVAT = $this->getCosts( 'oxdelivery' )->getVatValue();
02083 
02084         if ( $dDelVAT > 0 ) {
02085             return oxLang::getInstance()->formatCurrency( $dDelVAT, $this->getBasketCurrency() );
02086         }
02087         return false;
02088     }
02089 
02095     public function getDelCostNet()
02096     {
02097         if ( $this->getBasketUser() || $this->getConfig()->getConfigParam( 'blCalculateDelCostIfNotLoggedIn' ) ) {
02098             return oxLang::getInstance()->formatCurrency( $this->getCosts( 'oxdelivery' )->getNettoPrice(), $this->getBasketCurrency() );
02099         }
02100         return false;
02101     }
02102 
02108     public function getPayCostVatPercent()
02109     {
02110         return $this->getCosts( 'oxpayment' )->getVat();
02111     }
02112 
02118     public function getPayCostVat()
02119     {
02120         $dPayVAT = $this->getCosts( 'oxpayment' )->getVatValue();
02121         if ( $dPayVAT > 0 ) {
02122             return oxLang::getInstance()->formatCurrency( $dPayVAT, $this->getBasketCurrency() );
02123         }
02124         return false;
02125     }
02126 
02132     public function getPayCostNet()
02133     {
02134         return oxLang::getInstance()->formatCurrency( $this->getCosts( 'oxpayment' )->getNettoPrice(), $this->getBasketCurrency() );
02135     }
02136 
02142     public function getPaymentCosts()
02143     {
02144         return $this->getCosts( 'oxpayment' )->getBruttoPrice();
02145     }
02146 
02152     public function getFPaymentCosts()
02153     {
02154         $oPaymentCost = $this->getCosts( 'oxpayment' );
02155 
02156         if ( $oPaymentCost && $oPaymentCost->getBruttoPrice() ) {
02157             return oxLang::getInstance()->formatCurrency( $oPaymentCost->getBruttoPrice(), $this->getBasketCurrency() );
02158         }
02159         return false;
02160     }
02161 
02167     public function getVoucherDiscValue()
02168     {
02169         if ( $this->getVoucherDiscount() ) {
02170             return $this->getVoucherDiscount()->getBruttoPrice();
02171         }
02172         return false;
02173     }
02174 
02180     public function getFVoucherDiscountValue()
02181     {
02182         if ( $oVoucherDiscount = $this->getVoucherDiscount() ) {
02183             if ( $oVoucherDiscount->getBruttoPrice() ) {
02184                 return oxLang::getInstance()->formatCurrency( $oVoucherDiscount->getBruttoPrice(), $this->getBasketCurrency() );
02185             }
02186         }
02187         return false;
02188     }
02189 
02190 
02196     public function getWrappCostVatPercent()
02197     {
02198         return $this->getCosts( 'oxwrapping' )->getVat();
02199     }
02200 
02206     public function getWrappCostVat()
02207     {
02208         $dWrappVAT = $this->getCosts( 'oxwrapping' )->getVatValue();
02209         if ( $dWrappVAT > 0 ) {
02210             return oxLang::getInstance()->formatCurrency( $dWrappVAT, $this->getBasketCurrency() );
02211         }
02212         return false;
02213 
02214     }
02215 
02221     public function getWrappCostNet()
02222     {
02223         $dWrappNet = $this->getCosts( 'oxwrapping' )->getNettoPrice();
02224         if ( $dWrappNet > 0 ) {
02225             return  oxLang::getInstance()->formatCurrency( $dWrappNet, $this->getBasketCurrency() );
02226         }
02227         return false;
02228     }
02229 
02235     public function getFWrappingCosts()
02236     {
02237         $oWrappingCost = $this->getCosts( 'oxwrapping' );
02238         if ( $oWrappingCost && $oWrappingCost->getBruttoPrice() ) {
02239             return oxLang::getInstance()->formatCurrency( $oWrappingCost->getBruttoPrice(), $this->getBasketCurrency() );
02240         }
02241         return false;
02242     }
02243 
02249     public function getFPrice()
02250     {
02251         return oxLang::getInstance()->formatCurrency( $this->getPrice()->getBruttoPrice(), $this->getBasketCurrency() );
02252     }
02253 
02259     public function getFDeliveryCosts()
02260     {
02261         $oDeliveryCost = $this->getCosts( 'oxdelivery' );
02262         if ( $oDeliveryCost ) {
02263             return oxLang::getInstance()->formatCurrency( $oDeliveryCost->getBruttoPrice(), $this->getBasketCurrency() );
02264         }
02265         return false;
02266     }
02267 
02273     public function getDeliveryCosts()
02274     {
02275         if ( $oDeliveryCost = $this->getCosts( 'oxdelivery' ) ) {
02276             return $oDeliveryCost->getBruttoPrice();
02277         }
02278         return false;
02279     }
02280 
02288     public function setTotalDiscount( $dDiscount )
02289     {
02290         $this->_oTotalDiscount = oxNew( 'oxPrice' );
02291         $this->_oTotalDiscount->setBruttoPriceMode();
02292         $this->_oTotalDiscount->add( $dDiscount );
02293     }
02294 
02301     public function getPriceForPayment()
02302     {
02303         $dPrice = $this->getDiscountedProductsBruttoPrice();
02304         //#1905 not discounted products should be included in payment amount calculation
02305         if ( $oPriceList = $this->getNotDiscountProductsPrice() ) {
02306             $dPrice += $oPriceList->getBruttoSum();
02307         }
02308 
02309         // adding delivery price to final price
02310         if ( $oDeliveryPrice = $this->_aCosts['oxdelivery'] ) {
02311             $dPrice += $oDeliveryPrice->getBruttoPrice();
02312         }
02313 
02314         return $dPrice;
02315     }
02316 
02322     public function getDiscountedProductsBruttoPrice()
02323     {
02324         if ( $oProductsPrice = $this->getDiscountProductsPrice() ) {
02325             $dPrice = $oProductsPrice->getBruttoSum();
02326         }
02327 
02328         // substracting total discount
02329         if ( $oPrice = $this->getTotalDiscount() ) {
02330             $dPrice -= $oPrice->getBruttoPrice();
02331         }
02332 
02333         if ( $oVoucherPrice = $this->getVoucherDiscount() ) {
02334             $dPrice -= $oVoucherPrice->getBruttoPrice();
02335         }
02336 
02337         return $dPrice;
02338     }
02339 
02345     public function isBelowMinOrderPrice()
02346     {
02347         $blIsBelowMinOrderPrice = false;
02348         $sConfValue = $this->getConfig()->getConfigParam( 'iMinOrderPrice' );
02349         if ( is_numeric($sConfValue) && $this->getProductsCount() ) {
02350             $dMinOrderPrice = oxPrice::getPriceInActCurrency( ( int ) $sConfValue );
02351             $dNotDiscountedProductPrice = 0;
02352             if ( $oPrice = $this->getNotDiscountProductsPrice() ) {
02353                 $dNotDiscountedProductPrice = $oPrice->getBruttoSum();
02354             }
02355             $blIsBelowMinOrderPrice = ($dMinOrderPrice > ($this->getDiscountedProductsBruttoPrice() + $dNotDiscountedProductPrice));
02356         }
02357 
02358         return $blIsBelowMinOrderPrice;
02359 
02360     }
02361 
02370     public function getArtStockInBasket( $sArtId, $sExpiredArtId = null )
02371     {
02372         $dArtStock = 0;
02373         foreach ( $this->_aBasketContents as $sItemKey => $oOrderArticle ) {
02374             if ( $oOrderArticle && ( $sExpiredArtId == null || $sExpiredArtId != $sItemKey ) ) {
02375                 if ( $oOrderArticle->getArticle()->getId() == $sArtId ) {
02376                     $dArtStock += $oOrderArticle->getAmount();
02377                 }
02378             }
02379         }
02380 
02381         return $dArtStock;
02382     }
02383 
02391     public function canAddProductToBasket( $sProductId )
02392     {
02393         $blCanAdd = null;
02394 
02395         // if basket category is not set..
02396         if ( $this->_sBasketCategoryId === null ) {
02397             $oCat = null;
02398 
02399             // request category
02400             if ( $oView = $this->getConfig()->getActiveView() ) {
02401                 if ( $oCat = $oView->getActCategory() ) {
02402                     if ( !$this->_isProductInRootCategory( $sProductId, $oCat->oxcategories__oxrootid->value ) ) {
02403                         $oCat = null;
02404                     } else {
02405                         $blCanAdd = true;
02406                     }
02407                 }
02408             }
02409 
02410             // product main category
02411             if ( !$oCat ) {
02412                 $oProduct = oxNew( "oxarticle" );
02413                 if ( $oProduct->load( $sProductId ) ) {
02414                     $oCat = $oProduct->getCategory();
02415                 }
02416             }
02417 
02418             // root category id
02419             if ( $oCat ) {
02420                 $this->setBasketRootCatId($oCat->oxcategories__oxrootid->value);
02421             }
02422         }
02423 
02424         // avoiding double check..
02425         if ( $blCanAdd === null ) {
02426             $blCanAdd = $this->_sBasketCategoryId ? $this->_isProductInRootCategory( $sProductId, $this->getBasketRootCatId() ) : true;
02427         }
02428 
02429         return $blCanAdd;
02430     }
02431 
02440     protected function _isProductInRootCategory( $sProductId, $sRootCatId )
02441     {
02442         $sO2CTable = getViewName( 'oxobject2category' );
02443         $sCatTable = getViewName( 'oxcategories' );
02444 
02445         $oDb = oxDb::getDb();
02446         $sParentId  = $oDb->getOne( "select oxparentid from oxarticles where oxid = ".$oDb->quote( $sProductId ) );
02447         $sProductId = $sParentId ? $sParentId : $sProductId;
02448 
02449         $sQ = "select 1 from {$sO2CTable}
02450                  left join {$sCatTable} on {$sCatTable}.oxid = {$sO2CTable}.oxcatnid
02451                  where {$sO2CTable}.oxobjectid = ".$oDb->quote( $sProductId )." and
02452                        {$sCatTable}.oxrootid = ".$oDb->quote( $sRootCatId );
02453 
02454         return (bool) $oDb->getOne( $sQ );
02455     }
02456 
02464     public function setBasketRootCatId($sRoot)
02465     {
02466         $this->_sBasketCategoryId = $sRoot;
02467     }
02468 
02474     public function getBasketRootCatId()
02475     {
02476         return $this->_sBasketCategoryId;
02477     }
02478 
02486     public function setCatChangeWarningState( $blShow )
02487     {
02488         $this->_blShowCatChangeWarning = $blShow;
02489     }
02490 
02496     public function showCatChangeWarning()
02497     {
02498         return $this->_blShowCatChangeWarning;
02499     }
02500 
02508     public function setTsProductId( $sProductId )
02509     {
02510         $this->_sTsProductId = $sProductId;
02511     }
02512 
02518     public function getTsProductId()
02519     {
02520         return $this->_sTsProductId;
02521     }
02522 
02528     public function getFTsProtectionCosts()
02529     {
02530         $oProtectionCost = $this->getCosts( 'oxtsprotection' );
02531         if ( $oProtectionCost && $oProtectionCost->getBruttoPrice() ) {
02532             return oxLang::getInstance()->formatCurrency( $oProtectionCost->getBruttoPrice(), $this->getBasketCurrency() );
02533         }
02534         return false;
02535     }
02536 
02542     public function getTsProtectionVatPercent()
02543     {
02544         return $this->getCosts( 'oxtsprotection' )->getVat();
02545     }
02546 
02552     public function getTsProtectionVat()
02553     {
02554         $dProtectionVAT = $this->getCosts( 'oxtsprotection' )->getVatValue();
02555         if ( $dProtectionVAT > 0 ) {
02556             return oxLang::getInstance()->formatCurrency( $dProtectionVAT, $this->getBasketCurrency() );
02557         }
02558         return false;
02559     }
02560 
02566     public function getTsProtectionNet()
02567     {
02568         return oxLang::getInstance()->formatCurrency( $this->getCosts( 'oxtsprotection' )->getNettoPrice(), $this->getBasketCurrency() );
02569     }
02570 
02576     public function getTsProtectionCosts()
02577     {
02578         $oProtection = $this->getCosts( 'oxtsprotection' );
02579         if ( $oProtection ) {
02580             return $oProtection->getBruttoPrice();
02581         }
02582         return false;
02583     }
02584 
02590     public function getNotDiscountProductsPrice()
02591     {
02592         return $this->_oNotDiscountedProductsPriceList;
02593     }
02594 
02608     protected function _addedNewItem( $sProductID, $dAmount, $aSel, $aPersParam, $blOverride, $blBundle, $sOldBasketItemId )
02609     {
02610         if ( !$blOverride ) {
02611             $this->_blNewITemAdded = null;
02612             oxSession::setVar( "blAddedNewItem", true );
02613         }
02614     }
02615 
02621     public function __wakeUp()
02622     {
02623         $this->_blNewITemAdded = null;
02624     }
02625 
02631     public function isNewItemAdded()
02632     {
02633         if ( $this->_blNewITemAdded == null ) {
02634             $this->_blNewITemAdded = (bool) oxSession::getVar( "blAddedNewItem" );
02635             oxSession::deleteVar( "blAddedNewItem" );
02636         }
02637         return $this->_blNewITemAdded;
02638     }
02639 }