oxarticle.php

Go to the documentation of this file.
00001 <?php
00002 
00003 // defining supported link types
00004 define( 'OXARTICLE_LINKTYPE_CATEGORY', 0 );
00005 define( 'OXARTICLE_LINKTYPE_VENDOR', 1 );
00006 define( 'OXARTICLE_LINKTYPE_MANUFACTURER', 2 );
00007 define( 'OXARTICLE_LINKTYPE_PRICECATEGORY', 3 );
00008 define( 'OXARTICLE_LINKTYPE_TAG', 4 );
00009 define( 'OXARTICLE_LINKTYPE_RECOMM', 5 );
00010 
00017 class oxArticle extends oxI18n implements oxIArticle, oxIUrl
00018 {
00024     protected $_sCoreTbl = 'oxarticles';
00025 
00031     protected $_sClassName = 'oxarticle';
00032 
00038     protected $_blUseLazyLoading = true;
00039 
00045     protected $_sItemKey;
00046 
00052     protected $_blCalcPrice    = true;
00053 
00058     protected $_oPrice      = null;
00059 
00065     protected $_dArticleVat = null;
00066 
00072     protected $_aPersistParam  = null;
00073 
00079     protected $_blNotBuyable   = false;
00080 
00087     protected $_blLoadVariants = true;
00088 
00094     protected $_aVariants = null;
00095 
00101     protected $_aVariantsWithNotOrderables = null;
00102 
00111     protected $_blNotBuyableParent  = false;
00112 
00116     protected $_blHasVariants = false;
00117 
00121     protected $_blHasMdVariants = false;
00122 
00127     protected $_blIsOnComparisonList = false;
00128 
00133     protected $_oUser = null;
00134 
00140     protected $_blLoadPrice = true;
00141 
00145     protected $_blSkipAbPrice = false;
00146 
00153     protected $_fPricePerUnit = null;
00154 
00158     protected $_blLoadParentData = false;
00159 
00163     protected $_blSkipAssign = false;
00164 
00170     protected $_blSkipDiscounts = null;
00171 
00176     protected $_oAttributeList = null;
00177 
00178 
00184     protected $_blIsRangePrice = false;
00185 
00191     protected $_aMediaUrls = null;
00192 
00198     static protected $_aLoadedParents;
00199 
00205     static protected $_aSelList;
00206 
00212     protected $_aDispSelList;
00213 
00219     protected $_blIsSeoObject = true;
00220 
00226     protected $_oAmountPriceList = null;
00227 
00236     protected $_iLinkType = 0;
00237 
00243     protected $_aStdUrls = array();
00244 
00250     protected $_aSeoUrls = array();
00251 
00257     protected $_aSeoAddParams = array();
00258 
00264     protected $_aStdAddParams = array();
00265 
00271     protected $_sDynImageDir = null;
00272 
00278     protected $_sMoreDetailLink = null;
00279 
00285     protected $_sToBasketLink = null;
00286 
00292     protected $_iStockStatus = null;
00293 
00299     protected $_oTPrice = null;
00300 
00306     protected $_oAmountPriceInfo = null;
00307 
00313     protected $_dAmountPrice = null;
00314 
00320     protected static $_aArticleManufacturers = array();
00321 
00327     protected static $_aArticleVendors = array();
00328 
00334     protected static $_aArticleCats = array();
00335 
00341     protected $_aNonCopyParentFields = array('oxarticles__oxinsert',
00342                                              'oxarticles__oxtimestamp',
00343                                              'oxarticles__oxnid',
00344                                              'oxarticles__oxid',
00345                                              'oxarticles__oxparentid');
00346 
00352     protected $_aCopyParentField = array('oxarticles__oxnonmaterial',
00353                                          'oxarticles__oxfreeshipping',
00354                                          'oxarticles__oxremindactive');
00355 
00361     protected $_oMdVariants = null;
00362 
00368     protected $_oLongDesc = null;
00369 
00377     protected $_aVariantSelections = array();
00378 
00383     protected static $_aSelections = array();
00384 
00389     protected static $_aCategoryCache = null;
00394     protected static $_blHasAmountPrice = null;
00395 
00396 
00405     public function __construct($aParams = null)
00406     {
00407         if ( $aParams && is_array($aParams)) {
00408             foreach ( $aParams as $sParam => $mValue) {
00409                 $this->$sParam = $mValue;
00410             }
00411         }
00412         parent::__construct();
00413         $this->init( 'oxarticles' );
00414 
00415         $this->_blIsRangePrice = false;
00416     }
00417 
00426     public function __get($sName)
00427     {
00428         $myUtils = oxUtils::getInstance();
00429         // deprecated since 2011.03.10, should be used getArticleLongDesc() / getLongDesc()
00430         if ( strpos( $sName, 'oxarticles__oxlongdesc' ) === 0 ) {
00431             return $this->getArticleLongDesc();
00432         }
00433 
00434         $this->$sName = parent::__get($sName);
00435         if ( $this->$sName ) {
00436             // since the field could have been loaded via lazyloading
00437             $this->_assignParentFieldValue($sName);
00438         }
00439 
00440         return $this->$sName;
00441     }
00442 
00451     public function __set( $sName, $sValue )
00452     {
00453         // deprecated since 2011.03.14, should be used setArticleLongDesc()
00454         if ( strpos( $sName, 'oxarticles__oxlongdesc' ) === 0 ) {
00455             if ($this->_blEmployMultilanguage) {
00456                 $sValue = ( $sValue instanceof oxField ) ? $sValue->getRawValue() : $sValue;
00457                 $this->setArticleLongDesc( $sValue );
00458             } else {
00459                 $this->$sName = $sValue;
00460             }
00461         } else {
00462             parent::__set( $sName, $sValue );
00463         }
00464     }
00465 
00473     public function setId( $sId = null )
00474     {
00475         $sId = parent::setId( $sId );
00476 
00477         // TODO: in oxbase::setId make it to check if exists and update, not recreate, then delete this overload
00478         $this->oxarticles__oxnid = $this->oxarticles__oxid;
00479 
00480         return $sId;
00481     }
00482 
00492     public function getActiveCheckQuery( $blForceCoreTable = null )
00493     {
00494         $sTable = $this->getViewName( $blForceCoreTable );
00495 
00496         // check if article is still active
00497         $sQ = " $sTable.oxactive = 1 ";
00498 
00499         // enabled time range check ?
00500         if ( $this->getConfig()->getConfigParam( 'blUseTimeCheck' ) ) {
00501             $sDate = date( 'Y-m-d H:i:s', oxUtilsDate::getInstance()->getTime() );
00502             $sQ = "( $sQ or ( $sTable.oxactivefrom < '$sDate' and $sTable.oxactiveto > '$sDate' ) ) ";
00503         }
00504 
00505         return $sQ;
00506     }
00507 
00521     public function getStockCheckQuery( $blForceCoreTable = null )
00522     {
00523         $myConfig = $this->getConfig();
00524         $sTable = $this->getViewName( $blForceCoreTable );
00525 
00526         $sQ = "";
00527 
00528         //do not check for variants
00529         if ( $myConfig->getConfigParam( 'blUseStock' ) ) {
00530             $sQ = " and ( $sTable.oxstockflag != 2 or ( $sTable.oxstock + $sTable.oxvarstock ) > 0  ) ";
00531             //V #M513: When Parent article is not purchaseble, it's visibility should be displayed in shop only if any of Variants is available.
00532             if ( !$myConfig->getConfigParam( 'blVariantParentBuyable' ) ) {
00533                 $sTimeCheckQ = '';
00534                 if ( $myConfig->getConfigParam( 'blUseTimeCheck' ) ) {
00535                      $sDate = date( 'Y-m-d H:i:s', oxUtilsDate::getInstance()->getTime() );
00536                      $sTimeCheckQ = " or ( art.oxactivefrom < '$sDate' and art.oxactiveto > '$sDate' )";
00537                 }
00538                 $sQ = " $sQ and IF( $sTable.oxvarcount = 0, 1, ( select 1 from $sTable as art where art.oxparentid=$sTable.oxid and ( art.oxactive = 1 $sTimeCheckQ ) and ( art.oxstockflag != 2 or art.oxstock > 0 ) limit 1 ) ) ";
00539             }
00540         }
00541 
00542         return $sQ;
00543     }
00544 
00556     public function getVariantsQuery( $blRemoveNotOrderables, $blForceCoreTable = null  )
00557     {
00558         $sTable = $this->getViewName( $blForceCoreTable );
00559         $sQ = " and $sTable.oxparentid = '".$this->getId()."' ";
00560 
00561         //checking if variant is active and stock status
00562         if ( $this->getConfig()->getConfigParam( 'blUseStock' ) ) {
00563             $sQ .= " and ( $sTable.oxstock > 0 or ( $sTable.oxstock <= 0 and $sTable.oxstockflag != 2 ";
00564             if ( $blRemoveNotOrderables ) {
00565                 $sQ .= " and $sTable.oxstockflag != 3 ";
00566             }
00567             $sQ .= " ) ) ";
00568         }
00569 
00570         return $sQ;
00571     }
00572 
00580     public function getSqlActiveSnippet( $blForceCoreTable = null )
00581     {
00582         $myConfig = $this->getConfig();
00583 
00584         // check if article is still active
00585         $sQ = $this->getActiveCheckQuery( $blForceCoreTable );
00586 
00587         // stock and variants check
00588         $sQ .= $this->getStockCheckQuery( $blForceCoreTable );
00589 
00590 
00591         return "( $sQ ) ";
00592     }
00593 
00601     public function setSkipAssign($blSkipAssign)
00602     {
00603         $this->_blSkipAssign = $blSkipAssign;
00604     }
00605 
00611     public function disablePriceLoad()
00612     {
00613         $this->_blLoadPrice = false;
00614     }
00615 
00621     public function getItemKey()
00622     {
00623         return $this->_sItemKey;
00624     }
00625 
00633     public function setItemKey($sItemKey)
00634     {
00635         $this->_sItemKey = $sItemKey;
00636     }
00637 
00645     public function setNoVariantLoading( $blLoadVariants )
00646     {
00647         $this->_blLoadVariants = !$blLoadVariants;
00648     }
00649 
00655     public function isBuyable()
00656     {
00657         if ($this->_blNotBuyableParent) {
00658             return false;
00659         }
00660 
00661         return !$this->_blNotBuyable;
00662     }
00663 
00669     public function getPersParams()
00670     {
00671         return $this->_aPersistParam;
00672     }
00673 
00679     public function isOnComparisonList()
00680     {
00681         return $this->_blIsOnComparisonList;
00682     }
00683 
00691     public function setOnComparisonList( $blOnList )
00692     {
00693         $this->_blIsOnComparisonList = $blOnList;
00694     }
00695 
00703     public function setLoadParentData($blLoadParentData)
00704     {
00705         $this->_blLoadParentData = $blLoadParentData;
00706     }
00707 
00715     public function setSkipAbPrice( $blSkipAbPrice = null )
00716     {
00717         $this->_blSkipAbPrice = $blSkipAbPrice;
00718     }
00719 
00727     public function getSearchableFields()
00728     {
00729         $aSkipFields = array("oxblfixedprice", "oxicon", "oxvarselect", "oxamitemid", "oxamtaskid", "oxpixiexport", "oxpixiexported") ;
00730         $aFields = array_diff( array_keys($this->_aFieldNames), $aSkipFields );
00731 
00732         return $aFields;
00733     }
00734 
00735 
00743     public function isMultilingualField($sFieldName)
00744     {
00745         switch ($sFieldName) {
00746             case "oxlongdesc":
00747             case "oxtags":
00748                 return true;
00749         }
00750 
00751         return parent::isMultilingualField($sFieldName);
00752     }
00753 
00759     public function isVisible()
00760     {
00761 
00762         // admin preview mode
00763         if ( ( $blCanPreview = oxUtils::getInstance()->canPreview() ) !== null ) {
00764             return $blCanPreview;
00765         }
00766 
00767         // active ?
00768         $sNow = date('Y-m-d H:i:s');
00769         if ( !$this->oxarticles__oxactive->value &&
00770              (  $this->oxarticles__oxactivefrom->value > $sNow ||
00771                 $this->oxarticles__oxactiveto->value < $sNow
00772              )) {
00773             return false;
00774         }
00775 
00776         // stock flags
00777         if ( $this->getConfig()->getConfigParam( 'blUseStock' ) && $this->oxarticles__oxstockflag->value == 2) {
00778             $iOnStock = $this->oxarticles__oxstock->value + $this->oxarticles__oxvarstock->value;
00779             if ($this->getConfig()->getConfigParam( 'blPsBasketReservationEnabled' )) {
00780                 $iOnStock += $this->getSession()->getBasketReservations()->getReservedAmount($this->getId());
00781             }
00782             if ( $iOnStock <= 0 ) {
00783                 return false;
00784             }
00785         }
00786 
00787         return true;
00788     }
00789 
00798     public function assign( $aRecord)
00799     {
00800         startProfile('articleAssign');
00801 
00802 
00803         // load object from database
00804         parent::assign( $aRecord);
00805 
00806         $this->oxarticles__oxnid = $this->oxarticles__oxid;
00807 
00808         // check for simple article.
00809         if ($this->_blSkipAssign) {
00810             return;
00811         }
00812 
00813         $this->_assignParentFieldValues();
00814         $this->_assignNotBuyableParent();
00815 
00816         $this->_assignStock();
00817         startProfile('articleAssignPrices');
00818         $this->_assignPrices();
00819         stopProfile('articleAssignPrices');
00820         $this->_assignPersistentParam();
00821         $this->_assignDynImageDir();
00822         $this->_assignComparisonListFlag();
00823         $this->_assignAttributes();
00824 
00825 
00826         //$this->_seoAssign();
00827 
00828         stopProfile('articleAssign');
00829     }
00830 
00841     public function load( $oxID)
00842     {
00843         // A. #1325 resetting to avoid problems when reloading (details etc)
00844         $this->_blNotBuyableParent = false;
00845 
00846         $blRet = parent::load( $oxID);
00847 
00848         // convert date's to international format
00849         $this->oxarticles__oxinsert    = new oxField(oxUtilsDate::getInstance()->formatDBDate( $this->oxarticles__oxinsert->value));
00850         $this->oxarticles__oxtimestamp = new oxField(oxUtilsDate::getInstance()->formatDBDate( $this->oxarticles__oxtimestamp->value));
00851 
00852         return $blRet;
00853     }
00854 
00862     public function addToRatingAverage( $iRating)
00863     {
00864         $dOldRating = $this->oxarticles__oxrating->value;
00865         $dOldCnt    = $this->oxarticles__oxratingcnt->value;
00866         $this->oxarticles__oxrating->setValue(( $dOldRating * $dOldCnt + $iRating ) / ($dOldCnt + 1));
00867         $this->oxarticles__oxratingcnt->setValue($dOldCnt + 1);
00868         $dRating = ( $dOldRating * $dOldCnt + $iRating ) / ($dOldCnt + 1);
00869         $dRatingCnt = (int) ($dOldCnt + 1);
00870         // oxarticles.oxtimestamp = oxarticles.oxtimestamp to keep old timestamp value
00871         $oDb = oxDb::getDb();
00872         $oDb->execute( 'update oxarticles set oxarticles.oxrating = '.$dRating.',oxarticles.oxratingcnt = '.$dRatingCnt.', oxarticles.oxtimestamp = oxarticles.oxtimestamp where oxarticles.oxid = '.$oDb->quote( $this->getId() ) );
00873     }
00874 
00880     public function getArticleRatingAverage()
00881     {
00882         return round( $this->oxarticles__oxrating->value, 1);
00883     }
00884 
00890     public function getReviews()
00891     {
00892         $aIds = array($this->getId());
00893 
00894         if ( $this->oxarticles__oxparentid->value ) {
00895             $aIds[] = $this->oxarticles__oxparentid->value;
00896         }
00897 
00898         // showing variant reviews ..
00899         if ( $this->getConfig()->getConfigParam( 'blShowVariantReviews' ) ) {
00900             $aAdd = $this->_getVariantsIds();
00901             if (is_array($aAdd)) {
00902                 $aIds = array_merge($aIds, $aAdd);
00903             }
00904         }
00905 
00906         $oReview = oxNew('oxreview');
00907         $oRevs = $oReview->loadList('oxarticle', $aIds);
00908 
00909         //if no review found, return null
00910         if ( $oRevs->count() < 1 ) {
00911             return null;
00912         }
00913 
00914         return $oRevs;
00915     }
00916 
00922     public function getCrossSelling()
00923     {
00924         $oCrosslist = oxNew( "oxarticlelist");
00925         $oCrosslist->loadArticleCrossSell($this->oxarticles__oxid->value);
00926         if ( $oCrosslist->count() ) {
00927             return $oCrosslist;
00928         }
00929     }
00930 
00936     public function getAccessoires()
00937     {
00938         $myConfig = $this->getConfig();
00939 
00940         // Performance
00941         if ( !$myConfig->getConfigParam( 'bl_perfLoadAccessoires' ) ) {
00942             return;
00943         }
00944 
00945         $oAcclist = oxNew( "oxarticlelist");
00946         $oAcclist->setSqlLimit( 0, $myConfig->getConfigParam( 'iNrofCrossellArticles' ));
00947         $oAcclist->loadArticleAccessoires($this->oxarticles__oxid->value);
00948 
00949         if ( $oAcclist->count()) {
00950             return $oAcclist;
00951         }
00952     }
00953 
00959     public function getSimilarProducts()
00960     {
00961         // Performance
00962         $myConfig = $this->getConfig();
00963         if ( !$myConfig->getConfigParam( 'bl_perfLoadSimilar' ) ) {
00964             return;
00965         }
00966 
00967         $sArticleTable = $this->getViewName();
00968 
00969         $sAttribs = '';
00970         $iCnt = 0;
00971         $this->_getAttribsString($sAttribs, $iCnt);
00972 
00973         if ( !$sAttribs) {
00974             return null;
00975         }
00976 
00977         $aList = $this->_getSimList($sAttribs, $iCnt);
00978 
00979         if ( count( $aList ) ) {
00980             uasort( $aList, 'cmpart');
00981 
00982             $sSearch = $this->_generateSimListSearchStr($sArticleTable, $aList);
00983 
00984             $oSimilarlist = oxNew( 'oxarticlelist' );
00985             $oSimilarlist->setSqlLimit( 0, $myConfig->getConfigParam( 'iNrofSimilarArticles' ));
00986             $oSimilarlist->selectString( $sSearch);
00987 
00988             return $oSimilarlist;
00989         }
00990     }
00991 
00997     public function getCustomerAlsoBoughtThisProducts()
00998     {
00999         // Performance
01000         $myConfig = $this->getConfig();
01001         if ( !$myConfig->getConfigParam( 'bl_perfLoadCustomerWhoBoughtThis' ) ) {
01002             return;
01003         }
01004 
01005         // selecting products that fits
01006         $sQ = $this->_generateSearchStrForCustomerBought();
01007 
01008         $oArticles = oxNew( 'oxarticlelist' );
01009         $oArticles->setSqlLimit( 0, $myConfig->getConfigParam( 'iNrofCustomerWhoArticles' ));
01010         $oArticles->selectString( $sQ );
01011         if ( $oArticles->count() ) {
01012             return $oArticles;
01013         }
01014     }
01015 
01022     public function loadAmountPriceInfo()
01023     {
01024         $myConfig = $this->getConfig();
01025         if ( !$myConfig->getConfigParam( 'bl_perfLoadPrice' ) || !$this->_blLoadPrice || !$this->_blCalcPrice || !$this->hasAmountPrice() ) {
01026             return array();
01027         }
01028 
01029         if ( $this->_oAmountPriceInfo === null ) {
01030             $this->_oAmountPriceInfo = array();
01031             if ( count( ( $oAmPriceList = $this->_getAmountPriceList() ) ) ) {
01032                 $this->_oAmountPriceInfo = $this->_fillAmountPriceList( $oAmPriceList );
01033             }
01034         }
01035         return $this->_oAmountPriceInfo;
01036     }
01037 
01045     public function getSelectLists($sKeyPrefix = null)
01046     {
01047         //#1468C - more then one article in basket with different selectlist...
01048         //optionall function parameter $sKeyPrefix added, used only in basket.php
01049         $sKey = $this->getId();
01050         if ( isset( $sKeyPrefix ) ) {
01051             $sKey = $sKeyPrefix.'__'.$this->getId();
01052         }
01053 
01054         if ( !isset( self::$_aSelList[$sKey] ) ) {
01055             $oDb = oxDb::getDb();
01056             $sSLViewName = getViewName( 'oxselectlist' );
01057 
01058             $sQ = "select {$sSLViewName}.* from oxobject2selectlist join {$sSLViewName} on $sSLViewName.oxid=oxobject2selectlist.oxselnid
01059                    where oxobject2selectlist.oxobjectid=%s order by oxobject2selectlist.oxsort";
01060 
01061             // all selectlists this article has
01062             $oLists = oxNew( 'oxlist' );
01063             $oLists->init( 'oxselectlist' );
01064             $oLists->selectString( sprintf( $sQ, $oDb->quote( $this->getId() ) ) );
01065 
01066             //#1104S if this is variant ant it has no selectlists, trying with parent
01067             if ( $oLists->count() == 0 && $this->oxarticles__oxparentid->value ) {
01068                 $oLists->selectString( sprintf( $sQ, $oDb->quote( $this->oxarticles__oxparentid->value ) ) );
01069             }
01070 
01071             $dVat = 0;
01072             if ( $this->getPrice() != null ) {
01073                 $dVat = $this->getPrice()->getVat();
01074             }
01075 
01076             $iCnt = 0;
01077             self::$_aSelList[$sKey] = array();
01078             foreach ( $oLists as $oSelectlist ) {
01079                 self::$_aSelList[$sKey][$iCnt] = $oSelectlist->getFieldList( $dVat );
01080                 self::$_aSelList[$sKey][$iCnt]['name'] = $oSelectlist->oxselectlist__oxtitle->value;
01081                 $iCnt++;
01082             }
01083         }
01084         return self::$_aSelList[$sKey];
01085     }
01086 
01094     protected function _hasAnyVariant( $blForceCoreTable = null )
01095     {
01096         $blHas = false;
01097         if ( ( $sId = $this->getId() ) ) {
01098             if ( $this->oxarticles__oxshopid->value == $this->getConfig()->getShopId() ) {
01099                 $blHas = (bool) $this->oxarticles__oxvarcount->value;
01100             } else {
01101                 $sArticleTable = $this->getViewName( $blForceCoreTable );
01102                 $blHas = (bool) oxDb::getDb()->getOne( "select 1 from $sArticleTable where oxparentid='{$sId}'" );
01103             }
01104 
01105         }
01106         return $blHas;
01107     }
01108 
01114     public function hasMdVariants()
01115     {
01116         return $this->_blHasMdVariants;
01117     }
01118 
01128     public function getVariantSelections( $aFilterIds = null, $sActVariantId = null, $iLimit = 0 )
01129     {
01130         $iLimit = (int) $iLimit;
01131         if ( !isset( $this->_aVariantSelections[$iLimit] ) ) {
01132             $this->_aVariantSelections[$iLimit] = false;
01133             if ( $this->oxarticles__oxvarcount->value ) {
01134                 $this->_aVariantSelections[$iLimit] = oxNew( "oxVariantHandler" )->buildVariantSelections( $this->oxarticles__oxvarname->getRawValue(), $this->getVariants(), $aFilterIds, $sActVariantId, $iLimit );
01135             }
01136         }
01137         return $this->_aVariantSelections[$iLimit];
01138     }
01139 
01148     public function getSelections( $iLimit = null, $aFilter = null )
01149     {
01150         $sId = $this->getId() . ( (int) $iLimit );
01151         if ( !array_key_exists( $sId, self::$_aSelections ) ) {
01152 
01153             $oDb = oxDb::getDb();
01154             $sSLViewName = getViewName( 'oxselectlist' );
01155 
01156             $sQ = "select {$sSLViewName}.* from oxobject2selectlist join {$sSLViewName} on $sSLViewName.oxid=oxobject2selectlist.oxselnid
01157                    where oxobject2selectlist.oxobjectid=%s order by oxobject2selectlist.oxsort";
01158 
01159             if ( ( $iLimit = (int) $iLimit ) ) {
01160                 $sQ .= " limit $iLimit ";
01161             }
01162 
01163             // vat value for price
01164             $dVat = 0;
01165             if ( ( $oPrice = $this->getPrice() ) != null ) {
01166                 $dVat = $oPrice->getVat();
01167             }
01168 
01169             // all selectlists this article has
01170             $oList = oxNew( 'oxlist' );
01171             $oList->init( 'oxselectlist' );
01172             $oList->getBaseObject()->setVat( $dVat );
01173             $oList->selectString( sprintf( $sQ, $oDb->quote( $this->getId() ) ) );
01174 
01175             //#1104S if this is variant and it has no selectlists, trying with parent
01176             if ( $oList->count() == 0 && $this->oxarticles__oxparentid->value ) {
01177                 $oList->selectString( sprintf( $sQ, $oDb->quote( $this->oxarticles__oxparentid->value ) ) );
01178             }
01179 
01180             self::$_aSelections[$sId] = $oList->count() ? $oList : false;
01181         }
01182 
01183         if ( self::$_aSelections[$sId] ) {
01184             // marking active from filter
01185             $aFilter = ( $aFilter === null ) ? oxConfig::getParameter( "sel" ) : $aFilter;
01186             if ( $aFilter ) {
01187                 $iSelIdx = 0;
01188                 foreach ( self::$_aSelections[$sId] as $oSelection ) {
01189                     if ( isset( $aFilter[$iSelIdx] ) ) {
01190                         $oSelection->setActiveSelectionByIndex( $aFilter[$iSelIdx] );
01191                     }
01192                     $iSelIdx++;
01193                 }
01194             }
01195         }
01196 
01197         return self::$_aSelections[$sId];
01198     }
01199 
01209     protected function _loadVariantList( $blSimple, $blRemoveNotOrderables = true, $blForceCoreTable = null )
01210     {
01211         $oVariants = array();
01212         if ( ( $sId = $this->getId() ) ) {
01213             //do not load me as a parent later
01214             self::$_aLoadedParents[$sId] = $this;
01215 
01216             $myConfig = $this->getConfig();
01217 
01218             if ( !$this->_blLoadVariants ||
01219                 ( !$this->isAdmin() && !$myConfig->getConfigParam( 'blLoadVariants') ) ||
01220                 ( !$this->isAdmin() && !$this->oxarticles__oxvarcount->value ) ) {
01221                 return $oVariants;
01222             }
01223 
01224             // cache
01225             $sCacheKey = $blSimple ? "simple" : "full";
01226             if ( $blRemoveNotOrderables ) {
01227                 if ( isset( $this->_aVariants[$sCacheKey] ) ) {
01228                    return $this->_aVariants[$sCacheKey];
01229                 } else {
01230                     $this->_aVariants[$sCacheKey] = & $oVariants;
01231                 }
01232             } elseif ( !$blRemoveNotOrderables ) {
01233                 if ( isset( $this->_aVariantsWithNotOrderables[$sCacheKey] ) ) {
01234                     return $this->_aVariantsWithNotOrderables[$sCacheKey];
01235                 } else {
01236                     $this->_aVariantsWithNotOrderables[$sCacheKey] = & $oVariants;
01237                 }
01238             }
01239 
01240             if ( ( $this->_blHasVariants = $this->_hasAnyVariant( $blForceCoreTable ) ) ) {
01241 
01242                 //load simple variants for lists
01243                 if ( $blSimple ) {
01244                     $oVariants = oxNew( 'oxsimplevariantlist' );
01245                     $oVariants->setParent( $this );
01246                 } else {
01247                     //loading variants
01248                     $oVariants = oxNew( 'oxarticlelist' );
01249                     $oVariants->getBaseObject()->modifyCacheKey( '_variants' );
01250                 }
01251 
01252                 startProfile("selectVariants");
01253                 $blUseCoreTable = (bool) $blForceCoreTable;
01254                 $oBaseObject = $oVariants->getBaseObject();
01255                 $oBaseObject->setLanguage( $this->getLanguage() );
01256 
01257 
01258                 $sArticleTable = $this->getViewName( $blUseCoreTable );
01259 
01260                 $sSelect = "select ".$oBaseObject->getSelectFields()." from $sArticleTable where " .
01261                            $this->getActiveCheckQuery( $blUseCoreTable ) .
01262                            $this->getVariantsQuery( $blRemoveNotOrderables, $blUseCoreTable ) .
01263                            " order by $sArticleTable.oxsort";
01264 
01265                 $oVariants->selectString( $sSelect );
01266 
01267                 //if this is multidimensional variants, make additional processing
01268                 if ( $myConfig->getConfigParam( 'blUseMultidimensionVariants' ) ) {
01269                     $oMdVariants = oxNew( "oxVariantHandler" );
01270                     $this->_blHasMdVariants = $oMdVariants->isMdVariant( $oVariants->current() );
01271                 }
01272                 stopProfile("selectVariants");
01273             }
01274 
01275             //if we have variants then depending on config option the parent may be non buyable
01276             if ( !$myConfig->getConfigParam( 'blVariantParentBuyable' ) && $this->_blHasVariants ) {
01277                 $this->_blNotBuyableParent = true;
01278             }
01279 
01280             //if we have variants, but all variants are incative means article may be non buyable (depends on config option)
01281             if ( !$myConfig->getConfigParam( 'blVariantParentBuyable' ) && count( $oVariants ) == 0 && $this->_blHasVariants ) {
01282                 $this->_blNotBuyable = true;
01283             }
01284         }
01285         return $oVariants;
01286     }
01287 
01296     public function getFullVariants( $blRemoveNotOrderables = true, $blForceCoreTable = null )
01297     {
01298         return $this->_loadVariantList( false, $blRemoveNotOrderables, $blForceCoreTable );
01299     }
01300 
01309     public function getVariants( $blRemoveNotOrderables = true, $blForceCoreTable = null  )
01310     {
01311         return $this->_loadVariantList( $this->_isInList(), $blRemoveNotOrderables, $blForceCoreTable );
01312     }
01313 
01319     public function getSimpleVariants()
01320     {
01321         if ( $this->oxarticles__oxvarcount->value) {
01322             return $this->getVariants();
01323         }
01324     }
01325 
01334     public function getAdminVariants( $sLanguage = null )
01335     {
01336         $oVariants = oxNew( 'oxarticlelist');
01337         if ( ( $sId = $this->getId() ) ) {
01338 
01339             $oBaseObj = $oVariants->getBaseObject();
01340 
01341             if ( is_null( $sLanguage ) ) {
01342                 $oBaseObj->setLanguage( oxLang::getInstance()->getBaseLanguage() );
01343             } else {
01344                 $oBaseObj->setLanguage( $sLanguage );
01345             }
01346 
01347             $sSql = "select * from ".$oBaseObj->getViewName()." where oxparentid = '{$sId}' order by oxsort ";
01348             $oVariants->selectString( $sSql );
01349 
01350             //if we have variants then depending on config option the parent may be non buyable
01351             if ( !$this->getConfig()->getConfigParam( 'blVariantParentBuyable' ) && ( $oVariants->count() > 0 ) ) {
01352                 //$this->blNotBuyable = true;
01353                 $this->_blNotBuyableParent = true;
01354             }
01355         }
01356 
01357         return $oVariants;
01358     }
01359 
01367     public function getCategory()
01368     {
01369         $oCategory = oxNew( 'oxcategory' );
01370         $oCategory->setLanguage( $this->getLanguage() );
01371 
01372         // variant handling
01373         $sOXID = $this->getId();
01374         if ( isset( $this->oxarticles__oxparentid->value ) && $this->oxarticles__oxparentid->value ) {
01375             $sOXID = $this->oxarticles__oxparentid->value;
01376         }
01377 
01378         if ( $sOXID ) {
01379             // if the oxcategory instance of this article is not cached
01380             if ( !isset( $this->_aCategoryCache[ $sOXID ] ) ) {
01381                 startPRofile( 'getCategory' );
01382                 $oStr = getStr();
01383                 $sWhere   = $oCategory->getSqlActiveSnippet();
01384                 $sSelect  = $this->_generateSearchStr( $sOXID );
01385                 $sSelect .= ( $oStr->strstr( $sSelect, 'where' )?' and ':' where ') . $sWhere . " order by oxobject2category.oxtime limit 1";
01386 
01387                 // category not found ?
01388                 if ( !$oCategory->assignRecord( $sSelect ) ) {
01389 
01390                     $sSelect  = $this->_generateSearchStr( $sOXID, true );
01391                     $sSelect .= ( $oStr->strstr( $sSelect, 'where' )?' and ':' where ') . $sWhere . " limit 1";
01392 
01393                     // looking for price category
01394                     if ( !$oCategory->assignRecord( $sSelect ) ) {
01395                         $oCategory = null;
01396                     }
01397                 }
01398                 // add the category instance to cache
01399                 $this->_aCategoryCache[ $sOXID ] = $oCategory;
01400                 stopPRofile( 'getCategory' );
01401             } else {
01402                // if the oxcategory instance is cached
01403                $oCategory = $this->_aCategoryCache[ $sOXID ];
01404             }
01405         }
01406 
01407         return $oCategory;
01408     }
01409 
01418     public function getCategoryIds( $blActCats = false, $blSkipCache = false )
01419     {
01420         $myConfig = $this->getConfig();
01421         if ( isset( self::$_aArticleCats[$this->getId()] ) && !$blSkipCache ) {
01422             return self::$_aArticleCats[$this->getId()];
01423         }
01424 
01425         // variant handling
01426         $sOXID = $this->getId();
01427         if (isset( $this->oxarticles__oxparentid->value) && $this->oxarticles__oxparentid->value) {
01428             $sOXID = $this->oxarticles__oxparentid->value;
01429         }
01430 
01431         // we do not use lists here as we dont need this overhead right now
01432         $sSql = $this->_getSelectCatIds( $sOXID, $blActCats );
01433         $oDB = oxDb::getDb(true);
01434         $rs = $oDB->execute( $sSql );
01435 
01436 
01437         $aRet = array();
01438 
01439         if ($rs != false && $rs->recordCount() > 0) {
01440             while (!$rs->EOF) {
01441                 $aRet[] = $rs->fields['oxcatnid'];
01442                 $rs->moveNext();
01443             }
01444         }
01445 
01446         // adding price categories if such exists
01447         $sSql = $this->getSqlForPriceCategories();
01448 
01449         $oDB = oxDb::getDb( true );
01450         $rs = $oDB->execute( $sSql );
01451 
01452         if ($rs != false && $rs->recordCount() > 0) {
01453             while (!$rs->EOF) {
01454 
01455                 if ( is_array( $rs->fields ) ) {
01456                    $rs->fields = array_change_key_case( $rs->fields, CASE_LOWER );
01457                 }
01458 
01459 
01460                 if ( !$aRet[$rs->fields['oxid']] ) {
01461                     $aRet[] = $rs->fields['oxid'];
01462                 }
01463                 $rs->moveNext();
01464             }
01465         }
01466 
01467         return self::$_aArticleCats[$this->getId()] = $aRet;
01468     }
01469 
01478     protected function _getSelectCatIds( $sOXID, $blActCats = false )
01479     {
01480         $sO2CView = $this->_getObjectViewName('oxobject2category');
01481         $sCatView = $this->_getObjectViewName('oxcategories');
01482         $sSelect =  "select oxobject2category.oxcatnid as oxcatnid from $sO2CView as oxobject2category left join $sCatView as oxcategories on oxcategories.oxid = oxobject2category.oxcatnid ";
01483         $sSelect .= 'where oxobject2category.oxobjectid='.oxDb::getDb()->quote($sOXID).' and oxcategories.oxid is not null and oxcategories.oxactive = 1 ';
01484         if ( $blActCats ) {
01485             $sSelect .= "and oxcategories.oxhidden = 0 and (select count(cats.oxid) from $sCatView as cats where cats.oxrootid = oxcategories.oxrootid and cats.oxleft < oxcategories.oxleft and cats.oxright > oxcategories.oxright and ( cats.oxhidden = 1 or cats.oxactive = 0 ) ) = 0 ";
01486         }
01487         $sSelect .= 'order by oxobject2category.oxtime ';
01488         return $sSelect;
01489     }
01490 
01500     public function getVendor( $blShopCheck = true )
01501     {
01502         if ( ( $sVendorId = $this->getVendorId() ) ) {
01503             $oVendor = oxNew( 'oxvendor' );
01504         } elseif ( !$blShopCheck && $this->oxarticles__oxvendorid->value ) {
01505                 $oVendor = oxNew( 'oxi18n' );
01506                 $oVendor->init('oxvendor');
01507                 $oVendor->setReadOnly( true );
01508             $sVendorId = $this->oxarticles__oxvendorid->value;
01509         }
01510         if ( $sVendorId && $oVendor->load( $sVendorId ) && $oVendor->oxvendor__oxactive->value ) {
01511             if ( !$this->getConfig()->getConfigParam( 'bl_perfLoadVendorTree' ) ) {
01512                 $oVendor->setReadOnly( true );
01513             }
01514             return $oVendor;
01515         }
01516         return null;
01517     }
01518 
01526     public function getVendorId( $blForceReload = false )
01527     {
01528         $sVendorId = false;
01529         if ( $this->oxarticles__oxvendorid->value ) {
01530                 $sVendorId = $this->oxarticles__oxvendorid->value;
01531 
01532         }
01533         return $sVendorId;
01534     }
01535 
01543     public function getManufacturerId( $blForceReload = false )
01544     {
01545         $sManufacturerId = false;
01546         if ( $this->oxarticles__oxmanufacturerid->value ) {
01547 
01548                 $sManufacturerId = $this->oxarticles__oxmanufacturerid->value;
01549 
01550         }
01551         return $sManufacturerId;
01552     }
01553 
01563     public function getManufacturer( $blShopCheck = true )
01564     {
01565             $oManufacturer = oxNew( 'oxmanufacturer' );;
01566         if ( !( $sManufacturerId = $this->getManufacturerId() ) &&
01567              !$blShopCheck && $this->oxarticles__oxmanufacturerid->value ) {
01568             $oManufacturer->setReadOnly( true );
01569             $sManufacturerId = $this->oxarticles__oxmanufacturerid->value;
01570         }
01571 
01572         if ( $sManufacturerId && $oManufacturer->load( $sManufacturerId ) ) {
01573             if ( !$this->getConfig()->getConfigParam( 'bl_perfLoadManufacturerTree' ) ) {
01574                 $oManufacturer->setReadOnly( true );
01575             }
01576             $oManufacturer = $oManufacturer->oxmanufacturers__oxactive->value ? $oManufacturer : null;
01577         } else {
01578             $oManufacturer = null;
01579         }
01580 
01581         return $oManufacturer;
01582     }
01583 
01591     public function inCategory( $sCatNid)
01592     {
01593         return in_array( $sCatNid, $this->getCategoryIds());
01594     }
01595 
01604     public function isAssignedToCategory( $sCatId )
01605     {
01606         // variant handling
01607         $sOXID = $this->getId();
01608         if ( isset( $this->oxarticles__oxparentid->value) && $this->oxarticles__oxparentid->value) {
01609             $sOXID = $this->oxarticles__oxparentid->value;
01610         }
01611 
01612         $oDB = oxDb::getDb();
01613         $sSelect = $this->_generateSelectCatStr( $sOXID, $sCatId);
01614         $sOXID = $oDB->getOne( $sSelect);
01615         // article is assigned to passed category!
01616         if ( isset( $sOXID) && $sOXID) {
01617             return true;
01618         }
01619 
01620         // maybe this category is price category ?
01621         if ( $this->getConfig()->getConfigParam( 'bl_perfLoadPrice' ) && $this->_blLoadPrice ) {
01622             $dPriceFromTo = $this->getPrice()->getBruttoPrice();
01623             if ( $dPriceFromTo > 0) {
01624                 $sSelect = $this->_generateSelectCatStr( $sOXID, $sCatId, $dPriceFromTo);
01625                 $sOXID = $oDB->getOne( $sSelect);
01626                 // article is assigned to passed category!
01627                 if ( isset( $sOXID) && $sOXID) {
01628                     return true;
01629                 }
01630             }
01631         }
01632         return false;
01633     }
01634 
01640     public function getTPrice()
01641     {
01642         if ( !$this->getConfig()->getConfigParam( 'bl_perfLoadPrice' ) || !$this->_blLoadPrice ) {
01643             return;
01644         }
01645         // return cached result, since oPrice is created ONLY in this function [or function of EQUAL level]
01646         if ( $this->_oTPrice !== null ) {
01647             return $this->_oTPrice;
01648         }
01649 
01650         $this->_oTPrice = oxNew( 'oxPrice' );
01651         $this->_oTPrice->setPrice( $this->oxarticles__oxtprice->value );
01652 
01653         $this->_applyVat( $this->_oTPrice, $this->getArticleVat() );
01654         $this->_applyCurrency( $this->_oTPrice );
01655 
01656         return $this->_oTPrice;
01657     }
01658 
01664     public function skipDiscounts()
01665     {
01666         // allready loaded skip discounts config
01667         if ( $this->_blSkipDiscounts !== null ) {
01668             return $this->_blSkipDiscounts;
01669         }
01670 
01671         if ( $this->oxarticles__oxskipdiscounts->value ) {
01672             return true;
01673         }
01674 
01675 
01676         $this->_blSkipDiscounts = false;
01677         if ( oxDiscountList::getInstance()->hasSkipDiscountCategories() ) {
01678 
01679             $oDb = oxDb::getDb();
01680             $sO2CView  = getViewName( 'oxobject2category', $this->getLanguage() );
01681             $sViewName = getViewName( 'oxcategories', $this->getLanguage() );
01682             $sSelect =  "select 1 from $sO2CView as $sO2CView left join {$sViewName} on {$sViewName}.oxid = $sO2CView.oxcatnid
01683                          where $sO2CView.oxobjectid=".$oDb->quote( $this->getId() )." and {$sViewName}.oxactive = 1 and {$sViewName}.oxskipdiscounts = '1' ";
01684             $this->_blSkipDiscounts = ( $oDb->getOne($sSelect) == 1 );
01685         }
01686         return $this->_blSkipDiscounts;
01687     }
01688 
01696     public function setPrice(oxPrice $oPrice)
01697     {
01698         $this->_oPrice = $oPrice;
01699     }
01700 
01709     public function getBasePrice( $dAmount = 1 )
01710     {
01711         // override this function if you want e.g. different prices
01712         // for diff. usergroups.
01713 
01714         // Performance
01715         $myConfig = $this->getConfig();
01716         if( !$myConfig->getConfigParam( 'bl_perfLoadPrice' ) || !$this->_blLoadPrice )
01717             return;
01718 
01719         // GroupPrice or DB price ajusted by AmountPrice
01720         $dPrice = $this->_getAmountPrice( $dAmount );
01721 
01722 
01723         return $dPrice;
01724     }
01725 
01733     public function getPrice( $dAmount = 1 )
01734     {
01735         $myConfig = $this->getConfig();
01736         // Performance
01737         if ( !$myConfig->getConfigParam( 'bl_perfLoadPrice' ) || !$this->_blLoadPrice ) {
01738             return;
01739         }
01740 
01741         // return cached result, since oPrice is created ONLY in this function [or function of EQUAL level]
01742         if ( $dAmount != 1 || $this->_oPrice === null ) {
01743             $oPrice = oxNew( 'oxPrice' );
01744 
01745             // get base
01746             $oPrice->setPrice( $this->getBasePrice( $dAmount ) );
01747 
01748             // price handling
01749             if ( !$this->_blCalcPrice && $dAmount == 1 ) {
01750                 return $this->_oPrice = $oPrice;
01751             }
01752 
01753             $this->_calculatePrice( $oPrice );
01754             if ( $dAmount != 1 ) {
01755                 return $oPrice;
01756             }
01757 
01758             $this->_oPrice = $oPrice;
01759         }
01760         return $this->_oPrice;
01761     }
01762 
01771     protected function _calculatePrice( $oPrice, $dVat = null )
01772     {
01773         // apply VAT only if configuration requires it
01774         if ( isset( $dVat ) || !$this->getConfig()->getConfigParam( 'bl_perfCalcVatOnlyForBasketOrder' ) ) {
01775             $this->_applyVAT( $oPrice, isset( $dVat ) ? $dVat : $this->getArticleVat() );
01776         }
01777 
01778         // apply currency
01779         $this->_applyCurrency( $oPrice );
01780         // apply discounts
01781         if ( !$this->skipDiscounts() ) {
01782             $oDiscountList = oxDiscountList::getInstance();
01783             $oDiscountList->applyDiscounts( $oPrice, $oDiscountList->getArticleDiscounts( $this, $this->getArticleUser() ) );
01784         }
01785 
01786         return $oPrice;
01787     }
01788 
01796     public function setArticleUser($oUser)
01797     {
01798         $this->_oUser = $oUser;
01799     }
01800 
01806     public function getArticleUser()
01807     {
01808         if ($this->_oUser) {
01809             return $this->_oUser;
01810         }
01811         return $this->getUser();
01812     }
01813 
01823     public function getBasketPrice( $dAmount, $aSelList, $oBasket )
01824     {
01825         $oUser = $oBasket->getBasketUser();
01826         $this->setArticleUser( $oUser );
01827 
01828         $oBasketPrice = oxNew( 'oxPrice' );
01829 
01830         // get base price
01831         $dBasePrice = $this->getBasePrice( $dAmount );
01832 
01833         // applying select list price
01834         $dBasePrice = $this->_modifySelectListPrice( $dBasePrice, $aSelList );
01835 
01836         // setting price
01837         $oBasketPrice->setPrice( $dBasePrice );
01838 
01839         $dVat = oxVatSelector::getInstance()->getBasketItemVat( $this, $oBasket );
01840         $this->_calculatePrice( $oBasketPrice, $dVat );
01841 
01842         // returning final price object
01843         return $oBasketPrice;
01844     }
01845 
01858     public function applyBasketDiscounts(oxPrice $oPrice, $aDiscounts, $dAmount = 1)
01859     {
01860         $oDiscountList = oxDiscountList::getInstance();
01861         return $oDiscountList->applyBasketDiscounts( $oPrice, $aDiscounts, $dAmount );
01862     }
01863 
01872     public function delete( $sOXID = null )
01873     {
01874         if ( !$sOXID ) {
01875             $sOXID = $this->getId();
01876         }
01877         if ( !$sOXID ) {
01878             return false;
01879         }
01880 
01881 
01882         // #2339 delete first variants before deleting parent product
01883         $this->_deleteVariantRecords( $sOXID );
01884         $this->load( $sOXID );
01885         $this->_deletePics();
01886         $this->_onChangeResetCounts( $sOXID, $this->oxarticles__oxvendorid->value, $this->oxarticles__oxmanufacturerid->value );
01887 
01888         // delete self
01889         parent::delete( $sOXID );
01890 
01891         $rs = $this->_deleteRecords( $sOXID );
01892 
01893         oxSeoEncoderArticle::getInstance()->onDeleteArticle($this);
01894 
01895         $this->onChange( ACTION_DELETE, $sOXID, $this->oxarticles__oxparentid->value );
01896 
01897         return $rs->EOF;
01898     }
01899 
01908     public function reduceStock($dAmount, $blAllowNegativeStock = false)
01909     {
01910         $this->beforeUpdate();
01911 
01912         $iStockCount = $this->oxarticles__oxstock->value - $dAmount;
01913         if (!$blAllowNegativeStock && ($iStockCount < 0)) {
01914             $dAmount += $iStockCount;
01915             $iStockCount = 0;
01916         }
01917         $this->oxarticles__oxstock = new oxField($iStockCount);
01918 
01919         $oDb = oxDb::getDb();
01920         $oDb->execute( 'update oxarticles set oxarticles.oxstock = '.$oDb->quote( $iStockCount ).' where oxarticles.oxid = '.$oDb->quote( $this->getId() ) );
01921         $this->onChange( ACTION_UPDATE_STOCK );
01922         return $dAmount;
01923     }
01924 
01933     public function updateSoldAmount( $dAmount = 0 )
01934     {
01935         if ( !$dAmount ) {
01936             return;
01937         }
01938 
01939         $this->beforeUpdate();
01940 
01941         // article is not variant - should be updated current amount
01942         if ( !$this->oxarticles__oxparentid->value ) {
01943             //updating by SQL query, due to wrong behaviour if saving article using not admin mode
01944             $dAmount = (double) $dAmount;
01945             $oDb = oxDb::getDb();
01946             $rs = $oDb->execute( "update oxarticles set oxarticles.oxsoldamount = oxarticles.oxsoldamount + $dAmount where oxarticles.oxid = ".$oDb->quote($this->oxarticles__oxid->value));
01947         } elseif ( $this->oxarticles__oxparentid->value) {
01948             // article is variant - should be updated this article parent amount
01949             $oUpdateArticle = oxNewArticle( $this->oxarticles__oxparentid->value );
01950             $oUpdateArticle->updateSoldAmount( $dAmount );
01951         }
01952 
01953         $this->onChange( ACTION_UPDATE );
01954 
01955         return $rs;
01956     }
01957 
01963     public function disableReminder()
01964     {
01965         $oDB = oxDb::getDb(true);
01966         return $oDB->execute( "update oxarticles set oxarticles.oxremindactive = 2 where oxarticles.oxid = ".$oDB->quote($this->oxarticles__oxid->value));
01967     }
01968 
01976     public function save()
01977     {
01978         // @deprecated since 20110821. folders are no more written, getters must be user for urls
01979         $this->oxarticles__oxthumb = new oxField( basename( $this->oxarticles__oxthumb->value ), oxField::T_RAW );
01980         $this->oxarticles__oxicon  = new oxField( basename( $this->oxarticles__oxicon->value ), oxField::T_RAW );
01981         $iPicCount = $this->getConfig()->getConfigParam( 'iPicCount' );
01982         for ( $i = 1; $i <= $iPicCount; $i++ ) {
01983             $sFieldName = 'oxarticles__oxpic' . $i;
01984             if ( isset( $this->$sFieldName ) ) {
01985                 $this->_setFieldData( $sFieldName, basename( $this->$sFieldName->value ), oxField::T_RAW );
01986             }
01987         }
01988         // @end deprecated
01989 
01990         if ( ( $blRet = parent::save() ) ) {
01991             // saving long descrition
01992             $this->_saveArtLongDesc();
01993         }
01994 
01995         return $blRet;
01996     }
01997 
01998 
02005     public function getPictureGallery()
02006     {
02007         $myConfig = $this->getConfig();
02008 
02009         //initialize
02010         $blMorePic = false;
02011         $aArtPics  = array();
02012         $aArtIcons = array();
02013         $iActPicId = 1;
02014         $sActPic = $this->getPictureUrl( $iActPicId );
02015 
02016         if ( oxConfig::getParameter( 'actpicid' ) ) {
02017             $iActPicId = oxConfig::getParameter('actpicid');
02018         }
02019 
02020         $oStr = getStr();
02021         $iCntr = 0;
02022         $iPicCount = $myConfig->getConfigParam( 'iPicCount' );
02023         $blCheckActivePicId = true;
02024 
02025         for ( $i = 1; $i <= $iPicCount; $i++) {
02026             $sPicVal = $this->getPictureUrl( $i );
02027             $sIcoVal = $this->getIconUrl( $i );
02028             if ( !$oStr->strstr($sIcoVal, 'nopic_ico.jpg') && !$oStr->strstr($sIcoVal, 'nopic.jpg') &&
02029                  !$oStr->strstr($sPicVal, 'nopic_ico.jpg') && !$oStr->strstr($sPicVal, 'nopic.jpg') ) {
02030                 if ($iCntr) {
02031                     $blMorePic = true;
02032                 }
02033                 $aArtIcons[$i]= $sIcoVal;
02034                 $aArtPics[$i]= $sPicVal;
02035                 $iCntr++;
02036 
02037                 if ($iActPicId == $i) {
02038                     $sActPic = $sPicVal;
02039                     $blCheckActivePicId = false;
02040                 }
02041 
02042             } else if ( $blCheckActivePicId && $iActPicId <= $i) {
02043                 // if picture is empty, setting active pic id to next
02044                 // picture
02045                 $iActPicId++;
02046             }
02047         }
02048 
02049         $blZoomPic  = false;
02050         $aZoomPics = array();
02051         $iZoomPicCount = $myConfig->getConfigParam( 'iPicCount' );
02052 
02053         for ( $j = 1,$c = 1; $j <= $iZoomPicCount; $j++) {
02054             $sVal = $this->getZoomPictureUrl($j);
02055 
02056             if ( $sVal && !$oStr->strstr($sVal, 'nopic.jpg')) {
02057                 $blZoomPic = true;
02058                 $aZoomPics[$c]['id'] = $c;
02059                 $aZoomPics[$c]['file'] = $sVal;
02060                 //anything is better than empty name, because <img src=""> calls shop once more = x2 SLOW.
02061                 if (!$sVal) {
02062                     $aZoomPics[$c]['file'] = "nopic.jpg";
02063                 }
02064                 $c++;
02065             }
02066         }
02067 
02068         $aPicGallery = array('ActPicID' => $iActPicId,
02069                              'ActPic' => $sActPic,
02070                              'MorePics' => $blMorePic,
02071                              'Pics' => $aArtPics,
02072                              'Icons' => $aArtIcons,
02073                              'ZoomPic' => $blZoomPic,
02074                              'ZoomPics' => $aZoomPics);
02075 
02076         return $aPicGallery;
02077     }
02078 
02092     public function onChange($sAction = null, $sOXID = null, $sParentID = null)
02093     {
02094         $myConfig = $this->getConfig();
02095 
02096         if (!isset($sOXID)) {
02097             if ( $this->getId()) {
02098                 $sOXID = $this->getId();
02099             }
02100             if (!isset ($sOXID)) {
02101                 $sOXID = $this->oxarticles__oxid->value;
02102             }
02103             if ($this->oxarticles__oxparentid->value) {
02104                 $sParentID = $this->oxarticles__oxparentid->value;
02105             }
02106         }
02107         if (!isset($sOXID)) {
02108             return;
02109         }
02110 
02111         //if (isset($sOXID) && !$myConfig->blVariantParentBuyable && $myConfig->blUseStock)
02112         if ( $myConfig->getConfigParam( 'blUseStock' ) ) {
02113             //if article has variants then updating oxvarstock field
02114             //getting parent id
02115             if (!isset($sParentID)) {
02116                 $oDb = oxDb::getDb();
02117                 $sQ = 'select oxparentid from oxarticles where oxid = '.$oDb->quote($sOXID);
02118                 $sParentID = $oDb->getOne($sQ);
02119             }
02120             //if we have parent id then update stock
02121             if ($sParentID) {
02122                 $this->_onChangeUpdateStock($sParentID);
02123             }
02124         }
02125         //if we have parent id then update count
02126         //update count even if blUseStock is not active
02127         if ($sParentID) {
02128             $this->_onChangeUpdateVarCount($sParentID);
02129         }
02130 
02131         $sId = ( $sParentID ) ? $sParentID : $sOXID;
02132         $this->_onChangeUpdateMinVarPrice( $sId );
02133 
02134             // reseting articles count cache if stock has changed and some
02135             // articles goes offline (M:1448)
02136             if ( $sAction === ACTION_UPDATE_STOCK ) {
02137                 $this->_onChangeStockResetCount( $sOXID );
02138             }
02139 
02140     }
02141 
02148     public function getCustomVAT()
02149     {
02150         if ( isset($this->oxarticles__oxvat->value) ) {
02151             return $this->oxarticles__oxvat->value;
02152         }
02153     }
02154 
02163     public function checkForStock( $dAmount, $dArtStockAmount = 0 )
02164     {
02165         $myConfig = $this->getConfig();
02166         if ( !$myConfig->getConfigParam( 'blUseStock' ) ) {
02167             return true;
02168         }
02169 
02170         $oDb = oxDb::getDb(true);
02171         // fetching DB info as its up-to-date
02172         $sQ = 'select oxstock, oxstockflag from oxarticles where oxid = '.oxDb::getDb(true)->quote( $this->getId() );
02173         $rs = oxDb::getDb(true)->execute( $sQ );
02174 
02175         $iOnStock   = 0;
02176         $iStockFlag = 0;
02177         if ( $rs !== false && $rs->recordCount() > 0 ) {
02178             $iOnStock   = $rs->fields['oxstock'] - $dArtStockAmount;
02179             $iStockFlag = $rs->fields['oxstockflag'];
02180 
02181             // dodger : fremdlager is also always considered as on stock
02182             if ( $iStockFlag == 1 || $iStockFlag == 4) {
02183                 return true;
02184             }
02185             if ( !$myConfig->getConfigParam( 'blAllowUnevenAmounts' ) ) {
02186                 $iOnStock = floor( $iOnStock );
02187             }
02188         }
02189         if ($this->getConfig()->getConfigParam( 'blPsBasketReservationEnabled' )) {
02190             $iOnStock += $this->getSession()->getBasketReservations()->getReservedAmount($this->getId());
02191         }
02192         if ( $iOnStock >= $dAmount ) {
02193             return true;
02194         } else {
02195             if ( $iOnStock > 0 ) {
02196                 return $iOnStock;
02197             } else {
02198                 $oEx = oxNew( 'oxArticleInputException' );
02199                 $oEx->setMessage( 'EXCEPTION_ARTICLE_ARTICELNOTBUYABLE' );
02200                 oxUtilsView::getInstance()->addErrorToDisplay( $oEx );
02201                 return false;
02202             }
02203         }
02204     }
02205 
02206 
02214     public function getArticleLongDesc( $sOxid = null )
02215     {
02216         if ( $this->_oLongDesc === null ) {
02217             // initializing
02218             $this->_oLongDesc = new oxField();
02219 
02220 
02221             // choosing which to get..
02222             $sOxid = $sOxid === null ? $this->getId() : $sOxid;
02223             $sViewName = getViewName( 'oxartextends', $this->getLanguage() );
02224 
02225             $sDbValue = oxDb::getDb()->getOne( "select oxlongdesc from {$sViewName} where oxid = ?", array( $sOxid ) );
02226             if ( $sDbValue !== false ) {
02227                 $this->_oLongDesc->setValue( $sDbValue, oxField::T_RAW );
02228             } elseif ( $this->oxarticles__oxparentid->value ) {
02229                 $this->_oLongDesc->setValue( $this->getParentArticle()->getArticleLongDesc()->getRawValue(), oxField::T_RAW );
02230             }
02231         }
02232         return $this->_oLongDesc;
02233     }
02234 
02244     protected function _setLongDesc( $sDbValue )
02245     {
02246         $this->setArticleLongDesc( $sDbValue );
02247     }
02248 
02255     public function getLongDesc()
02256     {
02257         return oxUtilsView::getInstance()->parseThroughSmarty( $this->getArticleLongDesc()->getRawValue(), $this->getId().$this->getLanguage() );
02258     }
02259 
02268     public function setArticleLongDesc( $sDesc, $sOrigValue = null )
02269     {
02270 
02271         // setting current value
02272         $this->_oLongDesc = new oxField( $sDesc, oxField::T_RAW );
02273 
02274         // setting original value?
02275         if ( $sOrigValue ) {
02276             $this->_oLongDesc->orignalValue = $sOrigValue;
02277         }
02278     }
02279 
02285     public function getAttributes()
02286     {
02287         if ( $this->_oAttributeList === null ) {
02288             $this->_oAttributeList = oxNew( 'oxattributelist' );
02289             $this->_oAttributeList->loadAttributes( $this->getId() );
02290         }
02291 
02292         return $this->_oAttributeList;
02293     }
02294 
02303     public function appendLink( $sAddParams, $iLang = null )
02304     {
02305         if ( $sAddParams ) {
02306             if ( $iLang === null ) {
02307                 $iLang = $this->getLanguage();
02308             }
02309 
02310             $this->_aSeoAddParams[$iLang]  = isset( $this->_aSeoAddParams[$iLang] ) ? $this->_aSeoAddParams[$iLang] . "&amp;" : "";
02311             $this->_aSeoAddParams[$iLang] .= $sAddParams;
02312         }
02313     }
02314 
02323     public function getBaseSeoLink( $iLang, $blMain = false )
02324     {
02325         $oEncoder = oxSeoEncoderArticle::getInstance();
02326         if ( !$blMain ) {
02327             return $oEncoder->getArticleUrl( $this, $iLang, $this->getLinkType() );
02328         }
02329         return $oEncoder->getArticleMainUrl( $this, $iLang );
02330     }
02331 
02340     public function getLink( $iLang = null, $blMain = false  )
02341     {
02342         if ( !oxUtils::getInstance()->seoIsActive() ) {
02343             return $this->getStdLink( $iLang );
02344         }
02345 
02346         if ( $iLang === null ) {
02347             $iLang = $this->getLanguage();
02348         }
02349 
02350         $iLinkType = $this->getLinkType();
02351         if ( !isset( $this->_aSeoUrls[$iLang][$iLinkType] ) ) {
02352             $this->_aSeoUrls[$iLang][$iLinkType] = $this->getBaseSeoLink( $iLang, $blMain );
02353         }
02354 
02355         $sUrl = $this->_aSeoUrls[$iLang][$iLinkType];
02356         if ( isset($this->_aSeoAddParams[$iLang])) {
02357             $sUrl .= ( ( strpos( $sUrl.$this->_aSeoAddParams[$iLang], '?' ) === false ) ? '?' : '&amp;' ).$this->_aSeoAddParams[$iLang];
02358         }
02359 
02360         return $sUrl;
02361     }
02362 
02371     public function getMainLink( $iLang = null )
02372     {
02373         return $this->getLink( $iLang, true );
02374     }
02375 
02383     public function setLinkType( $iType )
02384     {
02385         // resetting detaisl link, to force new
02386         $this->_sDetailLink = null;
02387 
02388         // setting link type
02389         $this->_iLinkType = (int) $iType;
02390     }
02391 
02397     public function getLinkType()
02398     {
02399         return $this->_iLinkType;
02400     }
02401 
02410     public function appendStdLink( $sAddParams, $iLang = null )
02411     {
02412         if ( $sAddParams ) {
02413             if ( $iLang === null ) {
02414                 $iLang = $this->getLanguage();
02415             }
02416 
02417             $this->_aStdAddParams[$iLang]  = isset( $this->_aStdAddParams[$iLang] ) ? $this->_aStdAddParams[$iLang] . "&amp;" : "";
02418             $this->_aStdAddParams[$iLang] .= $sAddParams;
02419         }
02420     }
02421 
02431     public function getBaseStdLink( $iLang, $blAddId = true, $blFull = true )
02432     {
02433         $sUrl = '';
02434         if ( $blFull ) {
02435             //always returns shop url, not admin
02436             $sUrl = $this->getConfig()->getShopUrl( $iLang, false );
02437         }
02438 
02439         $sUrl .= "index.php?cl=details" . ( $blAddId ? "&amp;anid=".$this->getId() : "" );
02440         return $sUrl . ( isset( $this->_aStdAddParams[$iLang] ) ? "&amp;". $this->_aStdAddParams[$iLang] : "" );
02441     }
02442 
02451     public function getStdLink( $iLang = null, $aParams = array() )
02452     {
02453         if ( $iLang === null ) {
02454             $iLang = $this->getLanguage();
02455         }
02456 
02457         if ( !isset( $this->_aStdUrls[$iLang] ) ) {
02458             $this->_aStdUrls[$iLang] = $this->getBaseStdLink( $iLang );
02459         }
02460 
02461         return oxUtilsUrl::getInstance()->processUrl( $this->_aStdUrls[$iLang], true, $aParams, $iLang );
02462     }
02463 
02471     public function getStdTagLink( $sTag )
02472     {
02473         $sStdTagLink = $this->getConfig()->getShopHomeURL( $this->getLanguage(), false );
02474         return $sStdTagLink . "cl=details&amp;anid=".$this->getId()."&amp;listtype=tag&amp;searchtag=".rawurlencode( $sTag );
02475     }
02476 
02482     public function getTags()
02483     {
02484         $oDb = oxDb::getDb();
02485         $sViewName = getViewName( "oxartextends", $this->getLanguage() );
02486         $sQ = "select oxtags from {$sViewName} where oxid = ".$oDb->quote( $this->getId() );
02487         $oTagCloud = oxNew('oxtagcloud');
02488         return $oTagCloud->trimTags( $oDb->getOne( $sQ ) );
02489     }
02490 
02498     public function saveTags($sTags)
02499     {
02500         //do not allow derived update
02501         if ( !$this->allowDerivedUpdate() ) {
02502             return false;
02503         }
02504 
02505 
02506         $oTagCloud = oxNew( 'oxtagcloud' );
02507         $oTagCloud->resetTagCache();
02508         $sTags = mysql_real_escape_string( $oTagCloud->prepareTags( $sTags ) );
02509         $oDb = oxDb::getDb();
02510 
02511         $sTable = getLangTableName( 'oxartextends', $this->getLanguage() );
02512         $sLangSuffix = oxLang::getInstance()->getLanguageTag($this->getLanguage());
02513         $sQ = "insert into {$sTable} (oxid, oxtags$sLangSuffix) value (".$oDb->quote( $this->getId() ).", '{$sTags}')
02514                on duplicate key update oxtags$sLangSuffix = '{$sTags}'";
02515         return $oDb->execute( $sQ );
02516     }
02517 
02525     public function addTag($sTag)
02526     {
02527         $oDb = oxDb::getDb();
02528 
02529         $oTagCloud = oxNew('oxtagcloud');
02530         $oTagCloud->resetTagCache();
02531         $sTag = $oTagCloud->prepareTags($sTag);
02532         $sTagSeparator = $this->getConfig()->getConfigParam('sTagSeparator');
02533 
02534         $sTable = getLangTableName( 'oxartextends', $this->getLanguage() );
02535         $sLangSuffix = oxLang::getInstance()->getLanguageTag($this->getLanguage());
02536         if ( $oDb->getOne( "select {$sTable}.OXTAGS$sLangSuffix from {$sTable} where {$sTable}.OXID = ".$oDb->quote( $this->getId() ) ) ) {
02537             $sTailTag = $sTagSeparator . $sTag;
02538         } else {
02539             $sTailTag = $sTag;
02540         }
02541 
02542         $sTag = mysql_real_escape_string($sTag);
02543         $sTailTag = mysql_real_escape_string($sTailTag);
02544 
02545         $sTag = mysql_real_escape_string($sTag);
02546         $sTailTag = mysql_real_escape_string($sTailTag);
02547 
02548         $sQ = "insert into {$sTable} ( {$sTable}.OXID, {$sTable}.OXTAGS$sLangSuffix) values (".$oDb->quote( $this->getId() ).", '{$sTag}')
02549                        ON DUPLICATE KEY update {$sTable}.OXTAGS$sLangSuffix = CONCAT(TRIM({$sTable}.OXTAGS$sLangSuffix), '$sTailTag') ";
02550 
02551         return $oDb->execute( $sQ );
02552     }
02553 
02559     public function getMediaUrls()
02560     {
02561         if ( $this->_aMediaUrls === null ) {
02562             $this->_aMediaUrls = oxNew("oxlist");
02563             $this->_aMediaUrls->init("oxmediaurl");
02564             $this->_aMediaUrls->getBaseObject()->setLanguage( $this->getLanguage() );
02565 
02566             $sViewName = getViewName( "oxmediaurls", $this->getLanguage() );
02567             $sQ = "select * from {$sViewName} where oxobjectid = '".$this->getId()."'";
02568             $this->_aMediaUrls->selectString($sQ);
02569         }
02570         return $this->_aMediaUrls;
02571     }
02572 
02578     public function getDynImageDir()
02579     {
02580         return $this->_sDynImageDir;
02581     }
02582 
02588     public function getDispSelList()
02589     {
02590         if ($this->_aDispSelList === null) {
02591             if ( $this->getConfig()->getConfigParam( 'bl_perfLoadSelectLists' ) && $this->getConfig()->getConfigParam( 'bl_perfLoadSelectListsInAList' ) ) {
02592                 $this->_aDispSelList = $this->getSelectLists();
02593             }
02594         }
02595         return $this->_aDispSelList;
02596     }
02597 
02603     public function getMoreDetailLink()
02604     {
02605         if ( $this->_sMoreDetailLink == null ) {
02606 
02607             // and assign special article values
02608             $this->_sMoreDetailLink = $this->getConfig()->getShopHomeURL() . 'cl=moredetails';
02609 
02610             // not always it is okey, as not all the time active category is the same as primary article cat.
02611             if ( $sActCat = oxConfig::getParameter( 'cnid' ) ) {
02612                 $this->_sMoreDetailLink .= '&amp;cnid='.$sActCat;
02613             }
02614             $this->_sMoreDetailLink .= '&amp;anid='.$this->getId();
02615             $this->_sMoreDetailLink = $this->_sMoreDetailLink;
02616         }
02617 
02618         return $this->_sMoreDetailLink;
02619     }
02620 
02626     public function getToBasketLink()
02627     {
02628         if ( $this->_sToBasketLink == null ) {
02629             $myConfig = $this->getConfig();
02630 
02631             if ( oxUtils::getInstance()->isSearchEngine() ) {
02632                 $this->_sToBasketLink = $this->getLink();
02633             } else {
02634                 // and assign special article values
02635                 $this->_sToBasketLink = $myConfig->getShopHomeURL();
02636 
02637                 // override some classes as these should never showup
02638                 $sActClass = oxConfig::getParameter( 'cl' );
02639                 if ( $sActClass == 'thankyou') {
02640                     $sActClass = 'basket';
02641                 }
02642                 $this->_sToBasketLink .= 'cl='.$sActClass;
02643 
02644                 // this is not very correct
02645                 if ( $sActCat = oxConfig::getParameter( 'cnid' ) ) {
02646                     $this->_sToBasketLink .= '&amp;cnid='.$sActCat;
02647                 }
02648 
02649                 $this->_sToBasketLink .= '&amp;fnc=tobasket&amp;aid='.$this->getId().'&amp;anid='.$this->getId();
02650 
02651                 if ( $sTpl = basename( oxConfig::getParameter( 'tpl' ) ) ) {
02652                     $this->_sToBasketLink .= '&amp;tpl='.$sTpl;
02653                 }
02654             }
02655         }
02656 
02657         return $this->_sToBasketLink;
02658     }
02659 
02665     public function getStockStatus()
02666     {
02667         return $this->_iStockStatus;
02668     }
02669 
02675     public function getDeliveryDate()
02676     {
02677         if ( $this->oxarticles__oxdelivery->value != '0000-00-00') {
02678             return oxUtilsDate::getInstance()->formatDBDate( $this->oxarticles__oxdelivery->value);
02679         }
02680         return false;
02681     }
02682 
02688     public function getFTPrice()
02689     {
02690         if ( $oPrice = $this->getTPrice() ) {
02691             if ( $oPrice->getBruttoPrice() ) {
02692                 return oxLang::getInstance()->formatCurrency( oxUtils::getInstance()->fRound($oPrice->getBruttoPrice()));
02693             }
02694         }
02695     }
02696 
02702     public function getFPrice()
02703     {
02704         if ( $oPrice = $this->getPrice() ) {
02705             return $this->getPriceFromPrefix().oxLang::getInstance()->formatCurrency( $oPrice->getBruttoPrice() );
02706         }
02707     }
02708 
02714     public function getFNetPrice()
02715     {
02716         if ( $oPrice = $this->getPrice() ) {
02717             return oxLang::getInstance()->formatCurrency( $oPrice->getNettoPrice() );
02718         }
02719     }
02720 
02726     public function getPricePerUnit()
02727     {
02728         return $this->_fPricePerUnit;
02729     }
02730 
02736     public function isParentNotBuyable()
02737     {
02738         return $this->_blNotBuyableParent;
02739     }
02740 
02746     public function isNotBuyable()
02747     {
02748         return $this->_blNotBuyable;
02749     }
02750 
02758     public function setBuyableState( $blBuyable = false )
02759     {
02760         $this->_blNotBuyable = !$blBuyable;
02761     }
02762 
02771     public function getVariantList()
02772     {
02773         return $this->getVariants();
02774     }
02775 
02783     public function setSelectlist( $aSelList )
02784     {
02785         $this->_aDispSelList = $aSelList;
02786     }
02787 
02795     public function getPictureUrl( $iIndex = 1 )
02796     {
02797         if ( $iIndex ) {
02798             $sImgName = false;
02799             if ( !$this->_isFieldEmpty( "oxarticles__oxpic".$iIndex ) ) {
02800                 $sImgName = basename( $this->{"oxarticles__oxpic$iIndex"}->value );
02801             }
02802 
02803             $sSize = $this->getConfig()->getConfigParam( 'aDetailImageSizes' );
02804             return oxPictureHandler::getInstance()->getProductPicUrl( "product/{$iIndex}/", $sImgName, $sSize, 'oxpic'.$iIndex );
02805         }
02806     }
02807 
02816     public function getIconUrl( $iIndex = 0 )
02817     {
02818         $sImgName = false;
02819         $sDirname = "product/1/";
02820         if ( $iIndex && !$this->_isFieldEmpty( "oxarticles__oxpic{$iIndex}" ) ) {
02821             $sImgName = basename( $this->{"oxarticles__oxpic$iIndex"}->value );
02822             $sDirname = "product/{$iIndex}/";
02823         } elseif ( !$this->_isFieldEmpty( "oxarticles__oxicon" ) ) {
02824             $sImgName = basename( $this->oxarticles__oxicon->value );
02825             $sDirname = "product/icon/";
02826         } elseif ( !$this->_isFieldEmpty( "oxarticles__oxpic1" ) ) {
02827             $sImgName = basename( $this->oxarticles__oxpic1->value );
02828         }
02829 
02830         $sSize = $this->getConfig()->getConfigParam( 'sIconsize' );
02831         return oxPictureHandler::getInstance()->getProductPicUrl( $sDirname, $sImgName, $sSize, $iIndex );
02832     }
02833 
02839     public function getThumbnailUrl()
02840     {
02841         $sImgName = false;
02842         $sDirname = "product/1/";
02843         if ( !$this->_isFieldEmpty( "oxarticles__oxthumb" ) ) {
02844             $sImgName = basename( $this->oxarticles__oxthumb->value );
02845             $sDirname = "product/thumb/";
02846         } elseif ( !$this->_isFieldEmpty( "oxarticles__oxpic1" ) ) {
02847             $sImgName = basename( $this->oxarticles__oxpic1->value );
02848         }
02849 
02850         $sSize = $this->getConfig()->getConfigParam( 'sThumbnailsize' );
02851         return oxPictureHandler::getInstance()->getProductPicUrl( $sDirname, $sImgName, $sSize, 0 );
02852     }
02853 
02861     public function getZoomPictureUrl( $iIndex = '' )
02862     {
02863         $iIndex = (int) $iIndex;
02864         if ( $iIndex > 0 && !$this->_isFieldEmpty( "oxarticles__oxpic".$iIndex ) ) {
02865             $sImgName = basename( $this->{"oxarticles__oxpic".$iIndex}->value );
02866             $sSize = $this->getConfig()->getConfigParam( "sZoomImageSize" );
02867             return oxPictureHandler::getInstance()->getProductPicUrl( "product/{$iIndex}/", $sImgName, $sSize, 'oxpic'.$iIndex );
02868         }
02869     }
02870 
02876     public function getFileUrl()
02877     {
02878         return $this->getConfig()->getPictureUrl( 'media/' );
02879     }
02880 
02886     public function getPriceFromPrefix()
02887     {
02888         $sPricePrefix = '';
02889         if ( $this->_blIsRangePrice) {
02890             $sPricePrefix = oxLang::getInstance()->translateString('priceFrom').' ';
02891         }
02892 
02893         return $sPricePrefix;
02894     }
02895 
02901     protected function _saveArtLongDesc()
02902     {
02903         $myConfig = $this->getConfig();
02904         $sShopId = $myConfig->getShopID();
02905         if (in_array("oxlongdesc", $this->_aSkipSaveFields)) {
02906             return;
02907         }
02908 
02909         if ($this->_blEmployMultilanguage) {
02910             $sValue = $this->getArticleLongDesc()->getRawValue();
02911             if ( $sValue !== null ) {
02912                 $oArtExt = oxNew('oxI18n');
02913                 $oArtExt->init('oxartextends');
02914                 $oArtExt->setLanguage((int) $this->getLanguage());
02915                 if (!$oArtExt->load($this->getId())) {
02916                     $oArtExt->setId($this->getId());
02917                 }
02918                 $oArtExt->oxartextends__oxlongdesc = new oxField($sValue, oxField::T_RAW);
02919                 $oArtExt->save();
02920             }
02921         } else {
02922             $oArtExt = oxNew('oxI18n');
02923             $oArtExt->setEnableMultilang(false);
02924             $oArtExt->init('oxartextends');
02925             $aObjFields = $oArtExt->_getAllFields(true);
02926             if (!$oArtExt->load($this->getId())) {
02927                 $oArtExt->setId($this->getId());
02928             }
02929 
02930             foreach ($aObjFields as $sKey => $sValue ) {
02931                 if ( preg_match('/^oxlongdesc(_(\d{1,2}))?$/', $sKey) ) {
02932                     $sField = $this->_getFieldLongName($sKey);
02933 
02934                     if (isset($this->$sField)) {
02935                         $sLongDesc = null;
02936                         if ($this->$sField instanceof oxField) {
02937                             $sLongDesc = $this->$sField->getRawValue();
02938                         } elseif (is_object($this->$sField)) {
02939                             $sLongDesc = $this->$sField->value;
02940                         }
02941                         if (isset($sLongDesc)) {
02942                             $sAEField = $oArtExt->_getFieldLongName($sKey);
02943                             $oArtExt->$sAEField = new oxField($sLongDesc, oxField::T_RAW);
02944                         }
02945                     }
02946                 }
02947             }
02948             $oArtExt->save();
02949         }
02950     }
02951 
02957     protected function _skipSaveFields()
02958     {
02959         $myConfig = $this->getConfig();
02960 
02961         $this->_aSkipSaveFields = array();
02962 
02963         $this->_aSkipSaveFields[] = 'oxtimestamp';
02964        // $this->_aSkipSaveFields[] = 'oxlongdesc';
02965         $this->_aSkipSaveFields[] = 'oxinsert';
02966 
02967         if ( !isset( $this->oxarticles__oxparentid->value) || $this->oxarticles__oxparentid->value == '') {
02968             $this->_aSkipSaveFields[] = 'oxparentid';
02969         }
02970 
02971     }
02972 
02982     protected function _mergeDiscounts( $aDiscounts, $aItemDiscounts)
02983     {
02984         foreach ( $aItemDiscounts as $sKey => $oDiscount ) {
02985             // add prices of the same discounts
02986             if ( array_key_exists ($sKey, $aDiscounts) ) {
02987                 $aDiscounts[$sKey]->dDiscount += $oDiscount->dDiscount;
02988             } else {
02989                 $aDiscounts[$sKey] = $oDiscount;
02990             }
02991         }
02992         return $aDiscounts;
02993     }
02994 
03000     protected function _getGroupPrice()
03001     {
03002         $dPrice = $this->oxarticles__oxprice->value;
03003 
03004         $oUser = $this->getArticleUser();
03005         if ( $oUser ) {
03006             if ( $oUser->inGroup( 'oxidpricea' ) ) {
03007                 $dPrice = $this->oxarticles__oxpricea->value;
03008             } elseif ( $oUser->inGroup( 'oxidpriceb' ) ) {
03009                 $dPrice = $this->oxarticles__oxpriceb->value;
03010             } elseif ( $oUser->inGroup( 'oxidpricec' ) ) {
03011                 $dPrice = $this->oxarticles__oxpricec->value;
03012             }
03013         }
03014 
03015         // #1437/1436C - added config option, and check for zero A,B,C price values
03016         if ( $this->getConfig()->getConfigParam( 'blOverrideZeroABCPrices' ) && (double) $dPrice == 0 ) {
03017             $dPrice = $this->oxarticles__oxprice->value;
03018         }
03019 
03020         return $dPrice;
03021     }
03022 
03031     protected function _getAmountPrice($dAmount = 1)
03032     {
03033         $myConfig = $this->getConfig();
03034 
03035         startProfile( "_getAmountPrice" );
03036 
03037         $dPrice = $this->_getGroupPrice();
03038         $oAmtPrices = $this->_getAmountPriceList();
03039         foreach ($oAmtPrices as $oAmPrice) {
03040             if ($oAmPrice->oxprice2article__oxamount->value <= $dAmount
03041                     && $dAmount <= $oAmPrice->oxprice2article__oxamountto->value
03042                     && $dPrice > $oAmPrice->oxprice2article__oxaddabs->value ) {
03043                 $dPrice = $oAmPrice->oxprice2article__oxaddabs->value;
03044             }
03045         }
03046 
03047         stopProfile( "_getAmountPrice" );
03048         return $dPrice;
03049     }
03050 
03059     protected function _modifySelectListPrice( $dPrice, $aChosenList = null )
03060     {
03061         $myConfig = $this->getConfig();
03062         // #690
03063         if ( $myConfig->getConfigParam( 'bl_perfLoadSelectLists' ) && $myConfig->getConfigParam( 'bl_perfUseSelectlistPrice' ) ) {
03064 
03065             $aSelLists = $this->getSelectLists();
03066 
03067             foreach ( $aSelLists as $key => $aSel) {
03068                 if ( isset( $aChosenList[$key]) && isset($aSel[$aChosenList[$key]] ) ) {
03069                     $oSel = $aSel[$aChosenList[$key]];
03070                     if ( $oSel->priceUnit =='abs' ) {
03071                         $dPrice += $oSel->price;
03072                     } elseif ( $oSel->priceUnit =='%' ) {
03073                         $dPrice += oxPrice::percent( $dPrice, $oSel->price );
03074                     }
03075                 }
03076             }
03077         }
03078         return $dPrice;
03079     }
03080 
03081 
03089     protected function _fillAmountPriceList($oAmPriceList)
03090     {
03091         $myConfig = $this->getConfig();
03092         $myUtils  = oxUtils::getInstance();
03093 
03094         //modifying price
03095         $oCur = $myConfig->getActShopCurrencyObject();
03096 
03097         $oUser = $this->getArticleUser();
03098 
03099         $oDiscountList = oxDiscountList::getInstance();
03100         $aDiscountList = $oDiscountList->getArticleDiscounts( $this, $oUser );
03101 
03102         $oLowestPrice = null;
03103 
03104         $dBasePrice = $this->_getGroupPrice();
03105         $oLang = oxLang::getInstance();
03106 
03107         $dArticleVat = null;
03108         if ( !$myConfig->getConfigParam( 'bl_perfCalcVatOnlyForBasketOrder' ) ) {
03109             $dArticleVat = $this->getArticleVat();
03110         }
03111 
03112         // trying to find lowest price value
03113         foreach ($oAmPriceList as $sId => $oItem) {
03114             $oItemPrice = oxNew( 'oxprice' );
03115             if ( $oItem->oxprice2article__oxaddabs->value) {
03116                 $oItemPrice->setPrice( $oItem->oxprice2article__oxaddabs->value );
03117                 $oDiscountList->applyDiscounts( $oItemPrice, $aDiscountList );
03118                 $this->_applyCurrency( $oItemPrice, $oCur );
03119             } else {
03120                 $oItemPrice->setPrice( $dBasePrice );
03121                 $oItemPrice->subtractPercent( $oItem->oxprice2article__oxaddperc->value );
03122             }
03123 
03124             if (isset($dArticleVat)) {
03125                 $this->_applyVAT($oItemPrice, $dArticleVat);
03126             }
03127 
03128             if (!$oLowestPrice) {
03129                 $oLowestPrice = $oItemPrice;
03130             } elseif ($oLowestPrice->getBruttoPrice() > $oItemPrice->getBruttoPrice()) {
03131                 $oLowestPrice = $oItemPrice;
03132             }
03133 
03134             $oAmPriceList[$sId]->oxprice2article__oxaddabs = new oxField( $oLang->formatCurrency( $myUtils->fRound( $oItemPrice->getBruttoPrice(), $oCur ) ) );
03135             $oAmPriceList[$sId]->fnetprice  = $oLang->formatCurrency( $myUtils->fRound($oItemPrice->getNettoPrice(), $oCur ) );
03136             $oAmPriceList[$sId]->fbrutprice = $oLang->formatCurrency( $myUtils->fRound($oItemPrice->getBruttoPrice(), $oCur ) );
03137         }
03138 
03139         $this->_dAmountPrice = $myUtils->fRound( $oLowestPrice->getBruttoPrice() );
03140         return $oAmPriceList;
03141     }
03142 
03148     protected function _getVariantsIds()
03149     {
03150         $aSelect = array();
03151         if ( ( $sId = $this->getId() ) ) {
03152             $oDb = oxDb::getDb(true);
03153             $sQ = "select oxid from " . $this->getViewName( true ) . " where oxparentid = ".$oDb->quote( $sId )." and " .
03154                    $this->getSqlActiveSnippet( true );
03155 
03156             $oRs = $oDb->execute( $sQ );
03157             if ( $oRs != false && $oRs->recordCount() > 0 ) {
03158                 while (!$oRs->EOF) {
03159                     $aSelect[] = reset( $oRs->fields );
03160                     $oRs->moveNext();
03161                 }
03162             }
03163         }
03164         return $aSelect;
03165     }
03166 
03172     public function getArticleVat()
03173     {
03174         if (!isset($this->_dArticleVat)) {
03175             $this->_dArticleVat = oxVatSelector::getInstance()->getArticleVat( $this );
03176         }
03177         return $this->_dArticleVat;
03178     }
03179 
03188     protected function _applyVAT( oxPrice $oPrice, $dVat )
03189     {
03190         startProfile(__FUNCTION__);
03191         $oPrice->setVAT( $dVat );
03192         if ( ($dVat = oxVatSelector::getInstance()->getArticleUserVat($this)) !== false ) {
03193             $oPrice->setUserVat( $dVat );
03194         }
03195         stopProfile(__FUNCTION__);
03196     }
03197 
03205     public function applyVats( oxPrice $oPrice )
03206     {
03207         $this->_applyVAT($oPrice, $this->getArticleVat() );
03208     }
03209 
03220     protected function _applyDiscounts( $oPrice, $aDiscounts )
03221     {
03222         $oDiscountList = oxDiscountList::getInstance();
03223         $oDiscountList->applyDiscounts( $oPrice, $aDiscounts );
03224     }
03225 
03233     public function applyDiscountsForVariant( $oPrice )
03234     {
03235         // apply discounts
03236         if ( !$this->skipDiscounts() ) {
03237             $oDiscountList = oxDiscountList::getInstance();
03238             $oDiscountList->applyDiscounts( $oPrice, $oDiscountList->getArticleDiscounts( $this, $this->getArticleUser() ) );
03239         }
03240     }
03241 
03250     protected function _applyCurrency(oxPrice $oPrice, $oCur = null )
03251     {
03252         if ( !$oCur ) {
03253             $oCur = $this->getConfig()->getActShopCurrencyObject();
03254         }
03255 
03256         $oPrice->multiply($oCur->rate);
03257     }
03258 
03259 
03268     protected function _getAttribsString(&$sAttribs, &$iCnt)
03269     {
03270         // we do not use lists here as we dont need this overhead right now
03271         $oDB = oxDb::getDb(true);
03272         $sSelect =  'select oxattrid from oxobject2attribute where oxobject2attribute.oxobjectid='.$oDB->quote( $this->getId() );
03273         $sAttribs = '';
03274         $blSep = false;
03275         $rs = $oDB->execute( $sSelect);
03276         $iCnt = 0;
03277         if ($rs != false && $rs->recordCount() > 0) {
03278             while (!$rs->EOF) {
03279                 if ( $blSep) {
03280                     $sAttribs .= ' or ';
03281                 }
03282                 $sAttribs .= 't1.oxattrid = '.$oDB->quote($rs->fields['oxattrid']).' ';
03283                 $blSep = true;
03284                 $iCnt++;
03285                 $rs->moveNext();
03286             }
03287         }
03288     }
03289 
03298     protected function _getSimList($sAttribs, $iCnt)
03299     {
03300         $myConfig = $this->getConfig();
03301         $oDB      = oxDb::getDb(true);
03302 
03303         // #523A
03304         $iAttrPercent = $myConfig->getConfigParam( 'iAttributesPercent' )/100;
03305         // 70% same attributes
03306         if ( !$iAttrPercent || $iAttrPercent < 0 || $iAttrPercent > 1) {
03307             $iAttrPercent = 0.70;
03308         }
03309         // #1137V iAttributesPercent = 100 doesnt work
03310         $iHitMin = ceil( $iCnt * $iAttrPercent );
03311 
03312         // we do not use lists here as we dont need this overhead right now
03313         $aList= array();
03314         $sSelect =  "select oxobjectid, count(*) as cnt from oxobject2attribute as t1 where
03315                     ( $sAttribs )
03316                     and t1.oxobjectid != ".$oDB->quote( $this->oxarticles__oxid->value )."
03317                     group by t1.oxobjectid having count(*) >= $iHitMin ";
03318 
03319         $rs = $oDB->selectLimit( $sSelect, 20, 0);
03320         if ($rs != false && $rs->recordCount() > 0) {
03321             while (!$rs->EOF) {
03322                 $oTemp = new stdClass();    // #663
03323                 $oTemp->cnt = $rs->fields['cnt'];
03324                 $oTemp->id  = $rs->fields['oxobjectid'];
03325                 $aList[] = $oTemp;
03326                 $rs->moveNext();
03327             }
03328         }
03329         return $aList;
03330     }
03331 
03340     protected function _generateSimListSearchStr($sArticleTable, $aList)
03341     {
03342         $myConfig = $this->getConfig();
03343         $sFieldList = $this->getSelectFields();
03344         $sSearch = "select $sFieldList from $sArticleTable where ".$this->getSqlActiveSnippet()."  and $sArticleTable.oxissearch = 1 and $sArticleTable.oxid in ( ";
03345         $blSep = false;
03346         $iCnt = 0;
03347         $oDb = oxDb::getDb();
03348         foreach ( $aList as $oTemp) {
03349             if ( $blSep) {
03350                 $sSearch .= ',';
03351             }
03352             $sSearch .= $oDb->quote($oTemp->id);
03353             $blSep = true;
03354             if ( $iCnt >= $myConfig->getConfigParam( 'iNrofSimilarArticles' ) ) {
03355                 break;
03356             }
03357             $iCnt++;
03358         }
03359 
03360         //#1741T
03361         //$sSearch .= ") and $sArticleTable.oxparentid = '' ";
03362         $sSearch .= ') ';
03363 
03364         // #524A -- randomizing articles in attribute list
03365         $sSearch .= ' order by rand() ';
03366 
03367         return $sSearch;
03368     }
03369 
03378     protected function _generateSearchStr($sOXID, $blSearchPriceCat = false )
03379     {
03380 
03381         $sCatView = getViewName( 'oxcategories', $this->getLanguage() );
03382         $sO2CView = getViewName( 'oxobject2category' );
03383 
03384         // we do not use lists here as we dont need this overhead right now
03385         if ( !$blSearchPriceCat ) {
03386             $sSelect  = "select {$sCatView}.* from {$sO2CView} as oxobject2category left join {$sCatView} on
03387                          {$sCatView}.oxid = oxobject2category.oxcatnid
03388                          where oxobject2category.oxobjectid=".oxDb::getDb()->quote($sOXID)." and {$sCatView}.oxid is not null ";
03389         } else {
03390             $sSelect  = "select {$sCatView}.* from {$sCatView} where
03391                          '{$this->oxarticles__oxprice->value}' >= {$sCatView}.oxpricefrom and
03392                          '{$this->oxarticles__oxprice->value}' <= {$sCatView}.oxpriceto ";
03393         }
03394         return $sSelect;
03395     }
03396 
03402     protected function _generateSearchStrForCustomerBought()
03403     {
03404         $sArtTable = $this->getViewName();
03405         $sOrderArtTable = getViewName( 'oxorderarticles' );
03406 
03407         // fetching filter params
03408         $sIn = " '{$this->oxarticles__oxid->value}' ";
03409         if ( $this->oxarticles__oxparentid->value ) {
03410 
03411             // adding article parent
03412             $sIn .= ", '{$this->oxarticles__oxparentid->value}' ";
03413             $sParentIdForVariants = $this->oxarticles__oxparentid->value;
03414 
03415         } else {
03416             $sParentIdForVariants = $this->getId();
03417         }
03418 
03419         // adding variants
03420         $oDb = oxDb::getDb(true);
03421         $oRs = $oDb->execute( "select oxid from {$sArtTable} where oxparentid = ".$oDb->quote($sParentIdForVariants)." and oxid != ".$oDb->quote($this->oxarticles__oxid->value) );
03422         if ( $oRs != false && $oRs->recordCount() > 0) {
03423             while ( !$oRs->EOF ) {
03424                 $sIn .= ", ".$oDb->quote(current( $oRs->fields ))." ";
03425                 $oRs->moveNext();
03426             }
03427         }
03428 
03429         $iLimit = (int) $this->getConfig()->getConfigParam( 'iNrofCustomerWhoArticles' );
03430         $iLimit = $iLimit?( $iLimit * 10 ): 50;
03431 
03432         // building sql (optimized)
03433         $sQ = "select distinct {$sArtTable}.* from (
03434                    select d.oxorderid as suborderid from {$sOrderArtTable} as d use index ( oxartid ) where d.oxartid in ( {$sIn} ) limit {$iLimit}
03435                ) as suborder
03436                left join {$sOrderArtTable} force index ( oxorderid ) on suborder.suborderid = {$sOrderArtTable}.oxorderid
03437                left join {$sArtTable} on {$sArtTable}.oxid = {$sOrderArtTable}.oxartid
03438                where {$sArtTable}.oxid not in ( {$sIn} )
03439                and ( {$sArtTable}.oxissearch = 1 or {$sArtTable}.oxparentid <> '' ) and ".$this->getSqlActiveSnippet();
03440 
03441         /* non optimized, but could be used if index forcing is not supported
03442         // building sql
03443         $sQ = "select distinct {$sArtTable}.* from {$sOrderArtTable}, {$sArtTable} where {$sOrderArtTable}.oxorderid in (
03444                    select {$sOrderArtTable}.oxorderid from {$sOrderArtTable} where {$sOrderArtTable}.oxartid in ( {$sIn} )
03445                ) and {$sArtTable}.oxid = {$sOrderArtTable}.oxartid and {$sArtTable}.oxid not in ( {$sIn} )
03446                and ( {$sArtTable}.oxissearch = 1 or {$sArtTable}.oxparentid <> '' )
03447                and ".$this->getSqlActiveSnippet();
03448         */
03449 
03450         return $sQ;
03451     }
03452 
03462     protected function _generateSelectCatStr($sOXID, $sCatId, $dPriceFromTo = false)
03463     {
03464         $sCategoryView = getViewName('oxcategories');
03465         $sO2CView = getViewName('oxobject2category');
03466 
03467         $oDb    = oxDb::getDb();
03468         $sOXID  = $oDb->quote($sOXID);
03469         $sCatId = $oDb->quote($sCatId);
03470 
03471         if (!$dPriceFromTo) {
03472             $sSelect  = "select oxobject2category.oxcatnid from $sO2CView as oxobject2category ";
03473             $sSelect .= "left join $sCategoryView as oxcategories on oxcategories.oxid = oxobject2category.oxcatnid ";
03474             $sSelect .= "where oxobject2category.oxcatnid=$sCatId and oxobject2category.oxobjectid=$sOXID ";
03475             $sSelect .= "and oxcategories.oxactive = 1 order by oxobject2category.oxtime ";
03476         } else {
03477             $dPriceFromTo = $oDb->quote($dPriceFromTo);
03478             $sSelect  = "select oxcategories.oxid from $sCategoryView as oxcategories where ";
03479             $sSelect .= "oxcategories.oxid=$sCatId and $dPriceFromTo >= oxcategories.oxpricefrom and ";
03480             $sSelect .= "$dPriceFromTo <= oxcategories.oxpriceto ";
03481         }
03482         return $sSelect;
03483     }
03484 
03490     protected function _getAmountPriceList()
03491     {
03492         if ( $this->_oAmountPriceList === null ) {
03493             $this->_oAmountPriceList = array();
03494             if ( !$this->skipDiscounts() ) {
03495                 $myConfig = $this->getConfig();
03496                 $sArtId   = $this->getId();
03497 
03498                 // #1690C - Scale prices and variants
03499                 if ( !$this->isAdmin() && $myConfig->getConfigParam( 'blVariantInheritAmountPrice' ) && $this->oxarticles__oxparentid->value ) {
03500                     $sArtId = $this->oxarticles__oxparentid->value;
03501                 }
03502 
03503                 //collecting assigned to article amount-price list
03504                 $oAmPriceList = oxNew( 'oxlist' );
03505                 $oAmPriceList->init( 'oxbase', 'oxprice2article' );
03506 
03507                 $sShopID = $myConfig->getShopID();
03508                 if ( $myConfig->getConfigParam( 'blMallInterchangeArticles' ) ) {
03509                     $sShopSelect = '1';
03510                 } else {
03511                     $sShopSelect = " oxshopid =  '$sShopID' ";
03512                 }
03513 
03514                 $oAmPriceList->selectString( "select * from oxprice2article where oxartid = " . oxDb::getDb()->quote( $sArtId ) . " and $sShopSelect order by oxamount ");
03515 
03516                 // prepare abs prices if currently having percentages
03517                 $oBasePrice = $this->_getGroupPrice();
03518                 foreach ( $oAmPriceList as $oAmPrice ) {
03519                     if ( $oAmPrice->oxprice2article__oxaddperc->value ) {
03520                         $oAmPrice->oxprice2article__oxaddabs = new oxField(oxPrice::percent( $oBasePrice, 100 - $oAmPrice->oxprice2article__oxaddperc->value ), oxField::T_RAW );
03521                     }
03522                 }
03523 
03524                 $this->_oAmountPriceList = $oAmPriceList;
03525             }
03526         }
03527 
03528         return $this->_oAmountPriceList;
03529     }
03530 
03538     protected function _isFieldEmpty( $sFieldName )
03539     {
03540         $mValue = $this->$sFieldName->value;
03541 
03542         if ( is_null( $mValue ) ) {
03543             return true;
03544         }
03545 
03546         if ( $mValue === '' ) {
03547             return true;
03548         }
03549 
03550         $aDoubleCopyFields = array('oxarticles__oxprice', 'oxarticles__oxvat');
03551 
03552         if (!$mValue && in_array( $sFieldName, $aDoubleCopyFields ) ) {
03553             return true;
03554         }
03555 
03556 
03557         if (!strcmp($mValue, '0000-00-00 00:00:00') || !strcmp($mValue, '0000-00-00')) {
03558             return true;
03559         }
03560 
03561         $sFieldName = strtolower($sFieldName);
03562 
03563         if ( $sFieldName == 'oxarticles__oxicon' && ( strpos($mValue, "nopic_ico.jpg") !== false || strpos($mValue, "nopic.jpg") !== false ) ) {
03564             return true;
03565         }
03566 
03567         if ( strpos($mValue, "nopic.jpg") !== false && ($sFieldName == 'oxarticles__oxthumb' || substr($sFieldName, 0, 17) == 'oxarticles__oxpic' || substr($sFieldName, 0, 18) == 'oxarticles__oxzoom') ) {
03568             return true;
03569         }
03570 
03571         return false;
03572     }
03573 
03581     protected function _assignParentFieldValue($sFieldName)
03582     {
03583         if (!($oParentArticle = $this->getParentArticle())) {
03584             return;
03585         }
03586 
03587         $sCopyFieldName = $this->_getFieldLongName($sFieldName);
03588 
03589         // assigning only theese which parent article has
03590         if ( $oParentArticle->$sCopyFieldName != null ) {
03591 
03592             // only overwrite database values
03593             if ( substr( $sCopyFieldName, 0, 12) != 'oxarticles__') {
03594                 return;
03595             }
03596 
03597             //do not copy certain fields
03598             if (in_array($sCopyFieldName, $this->_aNonCopyParentFields)) {
03599                 return;
03600             }
03601 
03602             //COPY THE VALUE
03603             // assigning images from parent only if variant has no master image (#1807)
03604             if ( stristr($sCopyFieldName, '_oxthumb') || stristr($sCopyFieldName, '_oxicon') ) {
03605                 if ( $this->_isFieldEmpty( $sCopyFieldName ) && !$this->_hasMasterImage( 1 ) ) {
03606                     $this->$sCopyFieldName = clone $oParentArticle->$sCopyFieldName;
03607                 }
03608             } elseif ( stristr($sCopyFieldName, '_oxzoom') ) {
03609                 // for zoom images checking master image with specified index
03610                 // assign from parent only if no pictures to variant are added
03611                 $iIndex = (int) str_ireplace( "oxarticles__oxzoom", "", $sFieldName );
03612                 if ( $this->_isFieldEmpty( $sCopyFieldName ) && !$this->_hasMasterImage( $iIndex ) && !$this->_hasMasterImage( 1 ) ) {
03613                     $this->$sCopyFieldName = clone $oParentArticle->$sCopyFieldName;
03614                 }
03615             } elseif ( stristr($sCopyFieldName, '_oxpicsgenerated') && $this->{$sCopyFieldName}->value == 0 ) {
03616                 // if no pics generated for variants, load all from
03617                 $this->$sCopyFieldName = clone $oParentArticle->$sCopyFieldName;
03618             } elseif ($this->_isFieldEmpty($sCopyFieldName) || in_array( $sCopyFieldName, $this->_aCopyParentField ) ) {
03619                 $this->$sCopyFieldName = clone $oParentArticle->$sCopyFieldName;
03620             }
03621         }
03622     }
03623 
03629     public function getParentArticle()
03630     {
03631         if ( ( $sParentId = $this->oxarticles__oxparentid->value ) ) {
03632             $sIndex = $sParentId . "_" . $this->getLanguage();
03633             if ( !isset( self::$_aLoadedParents[$sIndex] ) ) {
03634                 self::$_aLoadedParents[$sIndex] = oxNew( 'oxarticle' );
03635                 self::$_aLoadedParents[$sIndex]->_blSkipAbPrice  = true;
03636                 self::$_aLoadedParents[$sIndex]->_blLoadPrice    = false;
03637                 self::$_aLoadedParents[$sIndex]->_blLoadVariants = false;
03638                 self::$_aLoadedParents[$sIndex]->loadInLang( $this->getLanguage(), $sParentId );
03639             }
03640             return self::$_aLoadedParents[$sIndex];
03641         }
03642     }
03643 
03651     protected function _getParentAricle()
03652     {
03653         return $this->getParentArticle();
03654     }
03655 
03661     protected function _assignParentFieldValues()
03662     {
03663         startProfile('articleAssignParentInternal');
03664         if ( $this->oxarticles__oxparentid->value ) {
03665             // yes, we are in fact a variant
03666             if ( !$this->isAdmin() || ( $this->_blLoadParentData && $this->isAdmin() ) ) {
03667                 foreach ( $this->_aFieldNames as $sFieldName => $sVal ) {
03668                     $this->_assignParentFieldValue( $sFieldName );
03669                 }
03670             }
03671         }
03672         stopProfile('articleAssignParentInternal');
03673     }
03674 
03680     protected function _assignNotBuyableParent()
03681     {
03682         if ( !$this->getConfig()->getConfigParam( 'blVariantParentBuyable' ) &&
03683              ($this->_blHasVariants || $this->oxarticles__oxvarstock->value || $this->oxarticles__oxvarcount->value )) {
03684             $this->_blNotBuyableParent = true;
03685 
03686         }
03687     }
03688 
03694     protected function _assignStock()
03695     {
03696         $myConfig = $this->getConfig();
03697         // -----------------------------------
03698         // stock
03699         // -----------------------------------
03700 
03701         // #1125 A. must round (using floor()) value taken from database and cast to int
03702         if (!$myConfig->getConfigParam( 'blAllowUnevenAmounts' ) && !$this->isAdmin() ) {
03703             $this->oxarticles__oxstock = new oxField((int) floor($this->oxarticles__oxstock->value));
03704         }
03705         //GREEN light
03706         $this->_iStockStatus = 0;
03707 
03708         // if we have flag /*1 or*/ 4 - we show always green light
03709         if ( $myConfig->getConfigParam( 'blUseStock' ) && /*$this->oxarticles__oxstockflag->value != 1 && */ $this->oxarticles__oxstockflag->value != 4) {
03710             //ORANGE light
03711             $iStock = $this->oxarticles__oxstock->value;
03712 
03713             if ($this->_blNotBuyableParent) {
03714                 $iStock = $this->oxarticles__oxvarstock->value;
03715             }
03716 
03717 
03718             if ( $iStock <= $myConfig->getConfigParam( 'sStockWarningLimit' ) && $iStock > 0) {
03719                 $this->_iStockStatus = 1;
03720             }
03721 
03722             //RED light
03723             if ($iStock <= 0) {
03724                 $this->_iStockStatus = -1;
03725             }
03726         }
03727 
03728 
03729         // stock
03730         if ( $myConfig->getConfigParam( 'blUseStock' ) && ($this->oxarticles__oxstockflag->value == 3 || $this->oxarticles__oxstockflag->value == 2)) {
03731             $iOnStock = $this->oxarticles__oxstock->value;
03732             if ($this->getConfig()->getConfigParam( 'blPsBasketReservationEnabled' )) {
03733                 $iOnStock += $this->getSession()->getBasketReservations()->getReservedAmount($this->getId());
03734             }
03735             if ($iOnStock <= 0) {
03736                 $this->_blNotBuyable = true;
03737             }
03738         }
03739 
03740         //exceptional handling for variant parent stock:
03741         if ($this->_blNotBuyable && $this->oxarticles__oxvarstock->value ) {
03742             $this->_blNotBuyable = false;
03743             //but then at least setting notBuaybleParent to true
03744             $this->_blNotBuyableParent = true;
03745         }
03746 
03747         //special treatment for lists when blVariantParentBuyable config option is set to false
03748         //then we just hide "to basket" button.
03749         //if variants are not loaded in the list and this article has variants and parent is not buyable then this article is not buyable
03750         if ( !$myConfig->getConfigParam( 'blVariantParentBuyable' ) && !$myConfig->getConfigParam( 'blLoadVariants' ) && $this->oxarticles__oxvarstock->value) {
03751             $this->_blNotBuyable = true;
03752         }
03753 
03754         //setting to non buyable when variant list is empty (for example not loaded or inactive) and $this is non buyable parent
03755         if (!$this->_blNotBuyable && $this->_blNotBuyableParent && $this->oxarticles__oxvarcount->value == 0) {
03756             $this->_blNotBuyable = true;
03757         }
03758     }
03759 
03765     protected function _assignPrices()
03766     {
03767         $myConfig = $this->getConfig();
03768 
03769         // Performance
03770         if ( !$myConfig->getConfigParam( 'bl_perfLoadPrice' ) || !$this->_blLoadPrice ) {
03771             return;
03772         }
03773 
03774         // compute price
03775         $dPrice = $this->getPrice()->getBruttoPrice();
03776 
03777         $oCur = $myConfig->getActShopCurrencyObject();
03778         //price per unit handling
03779         if ((double) $this->oxarticles__oxunitquantity->value && $this->oxarticles__oxunitname->value) {
03780             $this->_fPricePerUnit = oxLang::getInstance()->formatCurrency($dPrice / (double) $this->oxarticles__oxunitquantity->value, $oCur);
03781         }
03782 
03783         //getting min and max prices of variants
03784         if ( $this->_hasAnyVariant() ) {
03785             $this->_applyRangePrice();
03786         }
03787     }
03788 
03794     protected function _assignPersistentParam()
03795     {
03796         // Persistent Parameter Handling
03797         $aPersParam     = oxSession::getVar( 'persparam');
03798         if ( isset( $aPersParam) && isset( $aPersParam[$this->getId()])) {
03799             $this->_aPersistParam = $aPersParam[$this->getId()];
03800         }
03801     }
03802 
03808     protected function _assignDynImageDir()
03809     {
03810         $myConfig = $this->getConfig();
03811 
03812         $sThisShop = $this->oxarticles__oxshopid->value;
03813 
03814         $this->_sDynImageDir   = $myConfig->getPictureUrl( null, false );
03815         $this->dabsimagedir    = $myConfig->getPictureDir( false ); //$sThisShop
03816         $this->nossl_dimagedir = $myConfig->getPictureUrl( null, false, false, null, $sThisShop ); //$sThisShop
03817         $this->ssl_dimagedir   = $myConfig->getPictureUrl( null, false, true, null, $sThisShop ); //$sThisShop
03818     }
03819 
03825     protected function _assignComparisonListFlag()
03826     {
03827         // #657 add a flag if article is on comparisonlist
03828 
03829         $aItems = oxSession::getVar('aFiltcompproducts');
03830         if ( isset( $aItems[$this->getId()])) {
03831             $this->_blIsOnComparisonList = true;
03832         }
03833     }
03834 
03840     protected function _assignAttributes()
03841     {
03842         //#1029T load attributes
03843         //#1078S removed check for module "Produktvergleich"
03844         if ( $this->getConfig()->getConfigParam( 'bl_perfLoadAttributes' ) ) {
03845             $this->getAttributes();
03846         }
03847     }
03848 
03849 
03857     protected function _insert()
03858     {
03859         // set oxinsert
03860         $iInsertTime = time();
03861         $now = date('Y-m-d H:i:s', $iInsertTime);
03862         $this->oxarticles__oxinsert    = new oxField( $now );
03863         $this->oxarticles__oxtimestamp = new oxField( $now );
03864         if ( !is_object($this->oxarticles__oxsubclass) || $this->oxarticles__oxsubclass->value == '') {
03865             $this->oxarticles__oxsubclass = new oxField('oxarticle');
03866         }
03867 
03868         return parent::_insert();
03869     }
03870 
03876     protected function _update()
03877     {
03878 
03879         $this->_skipSaveFields();
03880 
03881         $myConfig = $this->getConfig();
03882 
03883 
03884         return parent::_update();
03885     }
03886 
03894     protected function _deleteRecords($sOXID)
03895     {
03896         $oDB = oxDb::getDb();
03897 
03898         $sOXID = $oDB->quote($sOXID);
03899 
03900         //remove other records
03901         $sDelete = 'delete from oxobject2article where oxarticlenid = '.$sOXID.' or oxobjectid = '.$sOXID.' ';
03902         $oDB->execute( $sDelete);
03903 
03904         $sDelete = 'delete from oxobject2attribute where oxobjectid = '.$sOXID.' ';
03905         $oDB->execute( $sDelete);
03906 
03907         $sDelete = 'delete from oxobject2category where oxobjectid = '.$sOXID.' ';
03908         $oDB->execute( $sDelete);
03909 
03910         $sDelete = 'delete from oxobject2selectlist where oxobjectid = '.$sOXID.' ';
03911         $oDB->execute( $sDelete);
03912 
03913         $sDelete = 'delete from oxprice2article where oxartid = '.$sOXID.' ';
03914         $oDB->execute( $sDelete);
03915 
03916         $sDelete = 'delete from oxreviews where oxtype="oxarticle" and oxobjectid = '.$sOXID.' ';
03917         $oDB->execute( $sDelete);
03918 
03919         $sDelete = 'delete from oxaccessoire2article where oxobjectid = '.$sOXID.' or oxarticlenid = '.$sOXID.' ';
03920         $oDB->execute( $sDelete);
03921 
03922         //#1508C - deleting oxobject2delivery entries added
03923         $sDelete = 'delete from oxobject2delivery where oxobjectid = '.$sOXID.' and oxtype=\'oxarticles\' ';
03924         $oDB->execute( $sDelete);
03925 
03926         $sDelete = 'delete from oxartextends where oxid = '.$sOXID.' ';
03927         $oDB->execute( $sDelete);
03928 
03929         //delete the record
03930         foreach ( $this->_getLanguageSetTables( "oxartextends" ) as $sSetTbl ) {
03931             $oDB->execute( "delete from $sSetTbl where oxid = {$sOXID}" );
03932         }
03933 
03934         $sDelete = 'delete from oxactions2article where oxartid = '.$sOXID.' ';
03935         $rs = $oDB->execute( $sDelete );
03936 
03937         $sDelete = 'delete from oxobject2list where oxobjectid = '.$sOXID.' ';
03938         $rs = $oDB->execute( $sDelete );
03939 
03940 
03941         return $rs;
03942     }
03943 
03951     protected function _deleteVariantRecords( $sOXID )
03952     {
03953         if ( $sOXID ) {
03954             $oDb = oxDb::getDb();
03955             //collect variants to remove recursively
03956             $sQ = 'select oxid from '.$this->getViewName().' where oxparentid = '.$oDb->quote( $sOXID );
03957             $rs = $oDb->execute( $sQ );
03958             if ($rs != false && $rs->recordCount() > 0) {
03959                 while (!$rs->EOF) {
03960                     $this->delete( $rs->fields[0] );
03961                     $rs->moveNext();
03962                 }
03963             }
03964         }
03965     }
03966 
03976     protected function _resetCacheAndArticleCount( $sOxid )
03977     {
03978         $this->_onChangeResetCounts( $sOxid, $this->oxarticles__oxvendorid->value, $this->oxarticles__oxmanufacturerid->value );
03979     }
03980 
03986     protected function _deletePics()
03987     {
03988         $myUtilsPic = oxUtilsPic::getInstance();
03989         $myConfig   = $this->getConfig();
03990         $oPictureHandler = oxPictureHandler::getInstance();
03991 
03992         //deleting custom main icon
03993         $oPictureHandler->deleteMainIcon( $this );
03994 
03995         //deleting custom thumbnail
03996         $oPictureHandler->deleteThumbnail( $this );
03997 
03998         $sAbsDynImageDir = $myConfig->getPictureDir(false);
03999 
04000         // deleting master image and all generated images
04001         $iPicCount = $myConfig->getConfigParam( 'iPicCount' );
04002         for ( $i = 1; $i <= $iPicCount; $i++ ) {
04003             $oPictureHandler->deleteArticleMasterPicture( $this, $i );
04004         }
04005     }
04006 
04016     protected function _onChangeResetCounts( $sOxid, $sVendorId = null, $sManufacturerId = null )
04017     {
04018 
04019         $myUtilsCount = oxUtilsCount::getInstance();
04020 
04021         if ( $sVendorId ) {
04022             $myUtilsCount->resetVendorArticleCount( $sVendorId );
04023         }
04024 
04025         if ( $sManufacturerId ) {
04026             $myUtilsCount->resetManufacturerArticleCount( $sManufacturerId );
04027         }
04028 
04029         //also reseting category counts
04030         $oDb = oxDb::getDb();
04031         $sQ = "select oxcatnid from oxobject2category where oxobjectid = ".$oDb->quote($sOxid);
04032         $oRs = $oDb->execute( $sQ );
04033         if ( $oRs !== false && $oRs->recordCount() > 0) {
04034             while ( !$oRs->EOF ) {
04035                 $myUtilsCount->resetCatArticleCount( $oRs->fields[0] );
04036                 $oRs->moveNext();
04037             }
04038         }
04039     }
04040 
04048     protected function _onChangeUpdateStock( $sParentID )
04049     {
04050         if ( $sParentID ) {
04051             $oDb = oxDb::getDb();
04052             $sParentIdQuoted = $oDb->quote($sParentID);
04053             $sQ = 'select oxstock, oxvendorid, oxmanufacturerid from oxarticles where oxid = '.$sParentIdQuoted;
04054             $rs = $oDb->execute($sQ);
04055             $iOldStock = $rs->fields[0];
04056             $iVendorID = $rs->fields[1];
04057             $iManufacturerID = $rs->fields[2];
04058 
04059             $sQ = 'select sum(oxstock) from '.$this->getViewName(true).' where oxparentid = '.$sParentIdQuoted.' and '. $this->getSqlActiveSnippet( true ).' and oxstock > 0 ';
04060             $iStock = (float) $oDb->getOne( $sQ );
04061 
04062             $sQ = 'update oxarticles set oxvarstock = '.$iStock.' where oxid = '.$sParentIdQuoted;
04063             $oDb->execute( $sQ );
04064 
04065                 //now lets update category counts
04066                 //first detect stock status change for this article (to or from 0)
04067                 if ( $iStock < 0 ) {
04068                     $iStock = 0;
04069                 }
04070                 if ( $iOldStock < 0 ) {
04071                     $iOldStock = 0;
04072                 }
04073                 if ( $this->oxarticles__oxstockflag->value == 2 && $iOldStock xor $iStock ) {
04074                     //means the stock status could be changed (oxstock turns from 0 to 1 or from 1 to 0)
04075                     // so far we leave it like this but later we could move all count resets to one or two functions
04076                     $this->_onChangeResetCounts( $sParentID, $iVendorID, $iManufacturerID );
04077                 }
04078         }
04079     }
04080 
04088     protected function _onChangeStockResetCount( $sOxid )
04089     {
04090         $myConfig = $this->getConfig();
04091 
04092         if ( $myConfig->getConfigParam( 'blUseStock' ) && $this->oxarticles__oxstockflag->value == 2 &&
04093            ( $this->oxarticles__oxstock->value + $this->oxarticles__oxvarstock->value ) <= 0 ) {
04094 
04095                $this->_onChangeResetCounts( $sOxid, $this->oxarticles__oxvendorid->value, $this->oxarticles__oxmanufacturerid->value );
04096         }
04097     }
04098 
04106     protected function _onChangeUpdateVarCount( $sParentID )
04107     {
04108         if ( $sParentID ) {
04109             $oDb = oxDb::getDb();
04110             $sParentIdQuoted = $oDb->quote( $sParentID );
04111             $sQ = "select count(*) as varcount from oxarticles where oxparentid = {$sParentIdQuoted}";
04112             $iVarCount = (int) $oDb->getOne( $sQ );
04113 
04114             $sQ = "update oxarticles set oxvarcount = {$iVarCount} where oxid = {$sParentIdQuoted}";
04115             $oDb->execute( $sQ );
04116         }
04117     }
04118 
04126     protected function _onChangeUpdateMinVarPrice( $sParentID )
04127     {
04128         if ( $sParentID ) {
04129             $oDb = oxDb::getDb();
04130             $sParentIdQuoted = $oDb->quote($sParentID);
04131             //#M0000883 (Sarunas)
04132             $sQ = 'select min(oxprice) as varminprice from '.$this->getViewName(true).' where '.$this->getSqlActiveSnippet(true).' and (oxparentid = '.$sParentIdQuoted.')';
04133             $dVarMinPrice = $oDb->getOne($sQ);
04134 
04135             $dParentPrice = $oDb->getOne("select oxprice from oxarticles where oxid = $sParentIdQuoted ");
04136 
04137             $blParentBuyable =  $this->getConfig()->getConfigParam( 'blVariantParentBuyable' );
04138 
04139             if ($dVarMinPrice) {
04140                 if ($blParentBuyable) {
04141                     $dVarMinPrice = min($dVarMinPrice, $dParentPrice);
04142                 }
04143 
04144             } else {
04145                 $dVarMinPrice = $dParentPrice;
04146             }
04147 
04148             if ( $dVarMinPrice ) {
04149                 $sQ = 'update oxarticles set oxvarminprice = '.$dVarMinPrice.' where oxid = '.$sParentIdQuoted;
04150                 $oDb->execute($sQ);
04151             }
04152         }
04153     }
04154 
04155 
04161     protected function _applyRangePrice()
04162     {
04163         //#buglist_413 if bl_perfLoadPriceForAddList variant price shouldn't be loaded too
04164         if ( !$this->getConfig()->getConfigParam( 'bl_perfLoadPrice' ) || !$this->_blLoadPrice ) {
04165             return;
04166         }
04167 
04168         $this->_blIsRangePrice = false;
04169 
04170         // if parent is buyable - do not apply range price calcculations
04171         if ($this->_blSkipAbPrice || !$this->_blNotBuyableParent) {
04172             return;
04173         }
04174 
04175         if ( $this->isParentNotBuyable() && !$this->getConfig()->getConfigParam( 'blLoadVariants' )) {
04176             //#2509 we cannot force brutto price here, as netto price can be added to DB
04177             // $this->getPrice()->setBruttoPriceMode();
04178             $this->getPrice()->setPrice($this->oxarticles__oxvarminprice->value);
04179             $this->_blIsRangePrice = true;
04180             $this->_calculatePrice( $this->getPrice() );
04181             return;
04182         }
04183 
04184         $aPrices = array();
04185 
04186         if (!$this->_blNotBuyableParent) {
04187             $aPrices[] = $this->getPrice()->getBruttoPrice();
04188         }
04189 
04190         $aVariants = $this->getVariants(false);
04191 
04192         if (count($aVariants)) {
04193             foreach ($aVariants as $sKey => $oVariant) {
04194                 $aPrices[] = $oVariant->getPrice()->getBruttoPrice();
04195             }
04196         }
04197 
04198         if ( count( $aPrices ) ) {
04199             $dMinPrice = min( $aPrices );
04200             $dMaxPrice = max( $aPrices );
04201         }
04202 
04203         if ($this->_blNotBuyableParent && isset($dMinPrice) && $dMinPrice == $dMaxPrice) {
04204             $this->getPrice()->setBruttoPriceMode();
04205             $this->getPrice()->setPrice($dMinPrice);
04206         }
04207 
04208         if (isset($dMinPrice) && $dMinPrice != $dMaxPrice) {
04209             $this->getPrice()->setBruttoPriceMode();
04210             $this->getPrice()->setPrice($dMinPrice);
04211             $this->_blIsRangePrice = true;
04212         }
04213     }
04214 
04221     public function getProductId()
04222     {
04223         return $this->getId();
04224     }
04225 
04231     public function getProductParentId()
04232     {
04233         return $this->oxarticles__oxparentid->value;
04234     }
04235 
04241     public function isOrderArticle()
04242     {
04243         return false;
04244     }
04245 
04251     public function isVariant()
04252     {
04253         return (bool) ( isset( $this->oxarticles__oxparentid ) ? $this->oxarticles__oxparentid->value : false );
04254     }
04255 
04261     public function isMdVariant()
04262     {
04263         $oMdVariant = oxNew( "oxVariantHandler" );
04264 
04265         return $oMdVariant->isMdVariant($this);
04266     }
04267 
04275     public function getSqlForPriceCategories($sFields = '')
04276     {
04277         if (!$sFields) {
04278             $sFields = 'oxid';
04279         }
04280         $sSelectWhere = "select $sFields from ".$this->_getObjectViewName('oxcategories')." where";
04281         $sQuotedPrice = oxDb::getDb()->quote( $this->oxarticles__oxprice->value );
04282         return  "$sSelectWhere oxpricefrom != 0 and oxpriceto != 0 and oxpricefrom <= $sQuotedPrice and oxpriceto >= $sQuotedPrice"
04283                ." union $sSelectWhere oxpricefrom != 0 and oxpriceto = 0 and oxpricefrom <= $sQuotedPrice"
04284                ." union $sSelectWhere oxpricefrom = 0 and oxpriceto != 0 and oxpriceto >= $sQuotedPrice";
04285     }
04286 
04294     public function inPriceCategory( $sCatNid )
04295     {
04296         $oDb = oxDb::getDb();
04297 
04298         $sQuotedPrice = $oDb->quote( $this->oxarticles__oxprice->value );
04299         $sQuotedCnid = $oDb->quote( $sCatNid );
04300         return (bool) $oDb->getOne(
04301             "select 1 from ".$this->_getObjectViewName('oxcategories')." where oxid=$sQuotedCnid and"
04302            ."(   (oxpricefrom != 0 and oxpriceto != 0 and oxpricefrom <= $sQuotedPrice and oxpriceto >= $sQuotedPrice)"
04303            ." or (oxpricefrom != 0 and oxpriceto = 0 and oxpricefrom <= $sQuotedPrice)"
04304            ." or (oxpricefrom = 0 and oxpriceto != 0 and oxpriceto >= $sQuotedPrice)"
04305            .")"
04306         );
04307     }
04308 
04314     public function getMdVariants()
04315     {
04316         if ( $this->_oMdVariants ) {
04317             return $this->_oMdVariants;
04318         }
04319 
04320         $oParentArticle = $this->getParentArticle();
04321         if ( $oParentArticle ) {
04322             $oVariants = $oParentArticle->getVariants();
04323         } else {
04324             $oVariants = $this->getVariants();
04325         }
04326 
04327         $oVariantHandler = oxNew( "oxVariantHandler" );
04328         $this->_oMdVariants = $oVariantHandler->buildMdVariants( $oVariants, $this->getId() );
04329 
04330         return $this->_oMdVariants;
04331     }
04332 
04338     public function getMdSubvariants()
04339     {
04340         return $this->getMdVariants()->getMdSubvariants();
04341     }
04342 
04350     protected function _hasMasterImage( $iIndex )
04351     {
04352         $sPicName = basename($this->{"oxarticles__oxpic" . $iIndex}->value);
04353 
04354         if ( $sPicName == "nopic.jpg" || $sPicName == "" ) {
04355             return false;
04356         }
04357         if ( $this->isVariant() && $this->getParentArticle()->{"oxarticles__oxpic".$iIndex}->value == $this->{"oxarticles__oxpic".$iIndex}->value ) {
04358             return false;
04359         }
04360 
04361         $sMasterPic = 'product/'.$iIndex . "/" . $sPicName;
04362 
04363         if ( $this->getConfig()->getMasterPicturePath( $sMasterPic ) ) {
04364             return true;
04365         }
04366 
04367         return false;
04368     }
04369 
04378     public function getPictureFieldValue( $sFieldName, $iIndex = null )
04379     {
04380         if ( $sFieldName ) {
04381             $sFieldName = "oxarticles__" . $sFieldName . $iIndex;
04382             return $this->$sFieldName->value;
04383         }
04384     }
04385 
04393     public function getMasterZoomPictureUrl( $iIndex )
04394     {
04395         $sPicUrl  = false;
04396         $sPicName = basename( $this->{"oxarticles__oxpic" . $iIndex}->value );
04397 
04398         if ( $sPicName && $sPicName != "nopic.jpg" ) {
04399             $sPicUrl = $this->getConfig()->getPictureUrl( "master/product/" . $iIndex . "/" . $sPicName );
04400             if ( !$sPicUrl || basename( $sPicUrl ) == "nopic.jpg" ) {
04401                 $sPicUrl = false;
04402             }
04403         }
04404 
04405         return $sPicUrl;
04406     }
04407 
04413     public function hasAmountPrice()
04414     {
04415         if ( self::$_blHasAmountPrice === null ) {
04416 
04417             self::$_blHasAmountPrice = false;
04418 
04419             $oDb = oxDb::getDb();
04420             $sQ = "SELECT 1 FROM `oxprice2article` LIMIT 1";
04421 
04422             if ( $oDb->getOne( $sQ ) ) {
04423                 self::$_blHasAmountPrice = true;
04424             }
04425         }
04426 
04427         return self::$_blHasAmountPrice;
04428     }
04429 }