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 
00014 class oxArticle extends oxI18n
00015 {
00021     protected $_sCoreTbl = 'oxarticles';
00022 
00028     protected $_sClassName = 'oxarticle';
00029 
00035     protected $_blUseLazyLoading = true;
00036 
00042     protected $_sItemKey;
00043 
00049     protected $_blCalcPrice    = true;
00050 
00055     protected $_oPrice      = null;
00056 
00062     protected $_dArticleVat = null;
00063 
00068     protected $_aPersistParam  = null;
00069 
00074     protected $_blNotBuyable   = false;
00075 
00081     protected $_blLoadVariants = true;
00082 
00088     protected $_aVariants = null;
00089 
00098     protected $_blNotBuyableParent  = false;
00099 
00104     protected $_blHasVariants = false;
00105 
00109     protected $_iVarStock = 0;
00110 
00115     protected $_oVariantList   = array();
00116 
00121     protected $_blIsOnComparisonList = false;
00122 
00127     protected $_oUser = null;
00128 
00134     protected $_blLoadPrice = true;
00135 
00139     protected $_blSkipAbPrice = false;
00140 
00147     protected $_fPricePerUnit = null;
00148 
00152     protected $_blLoadParentData = false;
00153 
00157     protected $_blSkipAssign = false;
00158 
00164     protected $_blSkipDiscounts = null;
00165 
00170     protected $_oAttributeList = null;
00171 
00172 
00178     protected $_blIsRangePrice = false;
00179 
00185     protected $_aMediaUrls = null;
00186 
00192     static protected $_aLoadedParents;
00193 
00199     static protected $_aSelList;
00200 
00206     protected $_aDispSelList;
00207 
00213     protected $_blIsSeoObject = true;
00214 
00220     protected $_oAmountPriceList = null;
00221 
00230     protected $_iLinkType = 0;
00231 
00237     protected $_sStdLink = null;
00238 
00244     protected $_sDynImageDir = null;
00245 
00251     protected $_sMoreDetailLink = null;
00252 
00258     protected $_sToBasketLink = null;
00259 
00265     protected $_iStockStatus = null;
00266 
00272     protected $_oTPrice = null;
00273 
00279     protected $_oAmountPriceInfo = null;
00280 
00286     protected $_dAmountPrice = null;
00287 
00293     protected $_sDetailLink = null;
00294 
00300     protected static $_aArticleManufacturers = array();
00301 
00307     protected static $_aArticleVendors = array();
00308 
00314     protected static $_aArticleCats = array();
00315 
00324     public function __construct($aParams = null)
00325     {
00326         if ( $aParams && is_array($aParams)) {
00327             foreach ( $aParams as $sParam => $mValue) {
00328                 $this->$sParam = $mValue;
00329             }
00330         }
00331         parent::__construct();
00332         $this->init( 'oxarticles' );
00333 
00334         $this->_blIsRangePrice = false;
00335     }
00336 
00344     public function __isset( $sName )
00345     {
00346         if ( $sName == 'oxarticles__oxlongdesc' ) {
00347             //get empty oxlongdesc field
00348             $this->getArticleLongDesc();
00349             return true;
00350         }
00351         return isset( $this->$sName );
00352     }
00353 
00362     public function __set( $sName, $sValue)
00363     {
00364         if ($sName == 'oxarticles__oxlongdesc') {
00365             $this->$sName = $sValue;
00366             return;
00367         }
00368         return parent::__set($sName, $sValue);
00369     }
00370 
00379     public function __get($sName)
00380     {
00381         $myUtils = oxUtils::getInstance();
00382         switch ($sName) {
00383             // NOT using caching here, because of these params should be used in templates ONLY
00384             // and in template files they are used not very much [once most of the time]
00385 
00386             // price related
00387             case 'netprice':
00388             case 'netPrice':
00389                 $mVal = $myUtils->fRound($this->getPrice()->getNettoPrice());
00390                 break;
00391             case 'brutPrice':
00392                 return $myUtils->fRound($this->getPrice()->getBruttoPrice());
00393                 break;
00394             case 'vatPercent':
00395                 return $this->getPrice()->getVAT();
00396                 break;
00397             case 'vat':
00398                 return $this->getPrice()->getVATValue();
00399                 break;
00400             case 'fnetprice':
00401                 return oxLang::getInstance()->formatCurrency( $myUtils->fRound($this->getPrice()->getNettoPrice()));
00402                 break;
00403             case 'fprice':
00404                 return $this->getFPrice();
00405                 break;
00406 
00407             // t price related
00408             case 'dtprice':
00409                 if ( $oPrice = $this->getTPrice() ) {
00410                     return $myUtils->fRound($oPrice->getBruttoPrice());
00411                     break;
00412                 } else {
00413                     return null;
00414                     break;
00415                 }
00416             case 'tvat':
00417                 if ( $oPrice = $this->getTPrice() ) {
00418                     return $oPrice->getVATValue();
00419                     break;
00420                 } else {
00421                     return null;
00422                     break;
00423                 }
00424             case 'ftprice':
00425                 if ( $oPrice = $this->getTPrice() ) {
00426                     return oxLang::getInstance()->formatCurrency( $myUtils->fRound($oPrice->getBruttoPrice()) );
00427                     break;
00428                 } else {
00429                     return null;
00430                     break;
00431                 }
00432             case 'oxarticles__oxlongdesc':
00433                 return $this->getArticleLongDesc($this->getId());
00434                 break;
00435             case 'foxdelivery':
00436                 return $this->getDeliveryDate();
00437                 break;
00438             case 'sItemKey':
00439                 return $this->getItemKey();
00440                 break;
00441             case 'selectlist':
00442                 return $this->_aDispSelList = $this->getDispSelList();
00443                 break;
00444             case 'blNotBuyable':
00445                 return $this->isNotBuyable();
00446                 break;
00447             case 'blNotBuyableParent':
00448                 return $this->isParentNotBuyable();
00449                 break;
00450             case 'blIsOnComparisonList':
00451                 return $this->isOnComparisonList();
00452                 break;
00453             case 'oVariantlist' :
00454                 return $this->_oVariantList;
00455                 break;
00456             case 'fPricePerUnit' :
00457                 return $this->getPricePerUnit();
00458                 break;
00459             case 'dimagedir' :
00460                 return $this->_sDynImageDir = $this->getDynImageDir();
00461                 break;
00462             case 'oxmoredetaillink' :
00463                 return $this->_sMoreDetailLink = $this->getMoreDetailLink();
00464                 break;
00465             case 'amountpricelist' :
00466                 return $this->loadAmountPriceInfo();
00467                 break;
00468             case 'stockstatus' :
00469                 return $this->getStockStatus();
00470                 break;
00471             case 'tobasketlink' :
00472                 return $this->getToBasketLink();
00473                 break;
00474             case 'oxdetaillink' :
00475                 return $this->getLink();
00476                 break;
00477             /*case 'oxarticles__oxnid':
00478                 return $this->getId();*/
00479         }
00480 
00481         $sRet = parent::__get($sName);
00482         if ( $this->$sName ) {
00483             $this->_assignParentFieldValue($sName);
00484         }
00485         //checking for picture information
00486         if ($sName == "oxarticles__oxthumb" || $sName == "oxarticles__oxicon" || strpos($sName, "oxarticles__oxpic") === 0 || strpos($sName, "oxarticles__oxzoom") === 0) {
00487             $this->_assignPictureValues();
00488             return $this->$sName;
00489         }
00490 
00491         return $sRet;
00492     }
00493 
00501     public function setId( $sId = null )
00502     {
00503         $sId = parent::setId( $sId );
00504 
00505         // TODO: in oxbase::setId make it to check if exists and update, not recreate, then delete this overload
00506         $this->oxarticles__oxnid = $this->oxarticles__oxid;
00507 
00508         return $sId;
00509     }
00510 
00518     public function getSqlActiveSnippet( $blForceCoreTable = false )
00519     {
00520         $myConfig = $this->getConfig();
00521             $sTable = $this->getCoreTableName();
00522 
00523         // check if article is still active
00524         $sQ = " $sTable.oxactive = 1 ";
00525 
00526         // enabled time range check ?
00527         if ( $myConfig->getConfigParam( 'blUseTimeCheck' ) ) {
00528             $sDate = date( 'Y-m-d H:i:s', oxUtilsDate::getInstance()->getTime() );
00529             $sQ = "( $sQ or ( $sTable.oxactivefrom < '$sDate' and $sTable.oxactiveto > '$sDate' ) ) ";
00530         }
00531 
00532         //do not check for variants
00533         if ( $myConfig->getConfigParam( 'blUseStock' ) ) {
00534             $sQ = " $sQ and ( $sTable.oxstockflag != 2 or ( $sTable.oxstock + $sTable.oxvarstock ) > 0  ) ";
00535             //V #M513: When Parent article is not purchaseble, it's visibility should be displayed in shop only if any of Variants is available.
00536             if ( !$myConfig->getConfigParam( 'blVariantParentBuyable' ) ) {
00537                 $sQ = " $sQ and ( $sTable.oxvarcount=0 or ( select count(art.oxid) from $sTable as art where art.oxstockflag=2 and art.oxparentid=$sTable.oxid and art.oxstock=0 ) < $sTable.oxvarcount ) ";
00538             }
00539         }
00540 
00541 
00542         return "( $sQ ) ";
00543     }
00544 
00552     public function setSkipAssign($blSkipAssign)
00553     {
00554         $this->_blSkipAssign = $blSkipAssign;
00555     }
00556 
00564     public function disablePriceLoad( $oArticle )
00565     {
00566         $oArticle->_blLoadPrice = false;
00567     }
00568 
00574     public function getItemKey()
00575     {
00576         return $this->_sItemKey;
00577     }
00578 
00586     public function setItemKey($sItemKey)
00587     {
00588         $this->_sItemKey = $sItemKey;
00589     }
00590 
00598     public function setNoVariantLoading( $blLoadVariants )
00599     {
00600         $this->_blLoadVariants = !$blLoadVariants;
00601     }
00602 
00608     public function isBuyable()
00609     {
00610         if ($this->_blNotBuyableParent) {
00611             return false;
00612         }
00613 
00614         return !$this->_blNotBuyable;
00615     }
00616 
00622     public function getPersParams()
00623     {
00624         return $this->_aPersistParam;
00625     }
00626 
00632     public function isOnComparisonList()
00633     {
00634         return $this->_blIsOnComparisonList;
00635     }
00636 
00644     public function setOnComparisonList( $blOnList )
00645     {
00646         $this->_blIsOnComparisonList = $blOnList;
00647     }
00648 
00656     public function setLoadParentData($blLoadParentData)
00657     {
00658         $this->_blLoadParentData = $blLoadParentData;
00659     }
00660 
00668     public function setSkipAbPrice( $blSkipAbPrice = null )
00669     {
00670         $this->_blSkipAbPrice = $blSkipAbPrice;
00671     }
00672 
00678     public function getSearchableFields()
00679     {
00680         $aSkipFields = array("oxblfixedprice", "oxicon", "oxvarselect", "oxamitemid", "oxamtaskid", "oxpixiexport", "oxpixiexported") ;
00681         $aFields = array_diff( array_keys($this->_aFieldNames), $aSkipFields );
00682 
00683         return $aFields;
00684     }
00685 
00686 
00694     public function isMultilingualField($sFieldName)
00695     {
00696         if ($sFieldName == "oxlongdesc") {
00697             return true;
00698         }
00699 
00700         return parent::isMultilingualField($sFieldName);
00701     }
00702 
00708     public function isVisible()
00709     {
00710 
00711         // admin preview mode
00712         $myConfig  = $this->getConfig();
00713         if ( ( $sPrevId = oxConfig::getParameter( 'preview' ) ) &&
00714              ( $sAdminSid = oxUtilsServer::getInstance()->getOxCookie( 'admin_sid' ) ) ) {
00715 
00716             $oDb = oxDb::getDb();
00717             $sPrevId   = $oDb->quote( $sPrevId );
00718             $sAdminSid = $oDb->quote( $sAdminSid );
00719             $sTable    = getViewName( 'oxuser' );
00720 
00721             return (bool) $oDb->getOne( "select 1 from $sTable where MD5( CONCAT( {$sAdminSid}, {$sTable}.oxid, {$sTable}.oxpassword, {$sTable}.oxrights ) ) = $sPrevId" );
00722         }
00723 
00724         // active ?
00725         $sNow = date('Y-m-d H:i:s');
00726         if ( !$this->oxarticles__oxactive->value &&
00727              (  $this->oxarticles__oxactivefrom->value > $sNow ||
00728                 $this->oxarticles__oxactiveto->value < $sNow
00729              )) {
00730             return false;
00731         }
00732 
00733         // stock flags
00734         if ( $myConfig->getConfigParam( 'blUseStock' ) && $this->oxarticles__oxstockflag->value == 2 &&
00735            ( $this->oxarticles__oxstock->value + $this->oxarticles__oxvarstock->value ) <= 0 ) {
00736             return false;
00737         }
00738 
00739         return true;
00740     }
00741 
00750     public function assign( $aRecord)
00751     {
00752         startProfile('articleAssign');
00753 
00754 
00755         // load object from database
00756         parent::assign( $aRecord);
00757 
00758         $this->oxarticles__oxnid = $this->oxarticles__oxid;
00759 
00760         // check for simple article.
00761         if ($this->_blSkipAssign) {
00762             return;
00763         }
00764 
00765         $this->_assignLinks();
00766         $this->_assignParentFieldValues();
00767         $this->_assignNotBuyableParent();
00768         $this->_assignPictureValues();
00769         $this->_assignStock();
00770         startProfile('articleAssignPrices');
00771         $this->_assignPrices();
00772         stopProfile('articleAssignPrices');
00773         $this->_assignPersistentParam();
00774         $this->_assignDynImageDir();
00775         $this->_assignComparisonListFlag();
00776         $this->_assignAttributes();
00777 
00778 
00779         //$this->_seoAssign();
00780 
00781         stopProfile('articleAssign');
00782     }
00783 
00793     protected function _setFieldData( $sFieldName, $sValue, $iDataType = oxField::T_TEXT)
00794     {
00795         parent::_setFieldData( $sFieldName, $sValue, $iDataType);
00796     }
00797 
00808     public function load( $oxID)
00809     {
00810         // A. #1325 resetting to avoid problems when reloading (details etc)
00811         $this->_blNotBuyableParent = false;
00812 
00813         $blRet = parent::load( $oxID);
00814 
00815         // convert date's to international format
00816         $this->oxarticles__oxinsert    = new oxField(oxUtilsDate::getInstance()->formatDBDate( $this->oxarticles__oxinsert->value));
00817         $this->oxarticles__oxtimestamp = new oxField(oxUtilsDate::getInstance()->formatDBDate( $this->oxarticles__oxtimestamp->value));
00818 
00819         return $blRet;
00820     }
00821 
00829     public function addToRatingAverage( $iRating)
00830     {
00831         $dOldRating = $this->oxarticles__oxrating->value;
00832         $dOldCnt    = $this->oxarticles__oxratingcnt->value;
00833         $this->oxarticles__oxrating->setValue(( $dOldRating * $dOldCnt + $iRating ) / ($dOldCnt + 1));
00834         $this->oxarticles__oxratingcnt->setValue($dOldCnt + 1);
00835         $dRating = ( $dOldRating * $dOldCnt + $iRating ) / ($dOldCnt + 1);
00836         $dRatingCnt = $dOldCnt + 1;
00837         // oxarticles.oxtimestamp = oxarticles.oxtimestamp to keep old timestamp value
00838         oxDb::getDb()->execute( 'update oxarticles set oxarticles.oxrating = '.$dRating.',oxarticles.oxratingcnt = '.$dRatingCnt.', oxarticles.oxtimestamp = oxarticles.oxtimestamp where oxarticles.oxid = "'.$this->getId().'" ' );
00839     }
00840 
00846     public function getArticleRatingAverage()
00847     {
00848         return round( $this->oxarticles__oxrating->value, 1);
00849     }
00850 
00856     public function getReviews()
00857     {
00858         $myConfig  = $this->getConfig();
00859 
00860         $aIds = array($this->getId());
00861 
00862         if ( $this->oxarticles__oxparentid->value ) {
00863                 $aIds[] = $this->oxarticles__oxparentid->value;
00864         }
00865 
00866         // showing variant reviews ..
00867         if ( $myConfig->getConfigParam( 'blShowVariantReviews' ) ) {
00868             $aAdd = $this->_getVariantsIds();
00869             if (is_array($aAdd)) {
00870                 $aIds = array_merge($aIds, $aAdd);
00871             }
00872         }
00873 
00874         $oReview = oxNew('oxreview');
00875         $oRevs = $oReview->loadList('oxarticle', $aIds);
00876 
00877         //if no review found, return null
00878         if ( $oRevs->count() < 1 ) {
00879             return null;
00880         }
00881 
00882         return $oRevs;
00883     }
00884 
00890     public function getCrossSelling()
00891     {
00892         $oCrosslist = oxNew( "oxarticlelist");
00893         $oCrosslist->loadArticleCrossSell($this->oxarticles__oxid->value);
00894         if ( $oCrosslist->count() ) {
00895             return $oCrosslist;
00896         }
00897     }
00898 
00904     public function getAccessoires()
00905     {
00906         $myConfig = $this->getConfig();
00907 
00908         // Performance
00909         if ( !$myConfig->getConfigParam( 'bl_perfLoadAccessoires' ) ) {
00910             return;
00911         }
00912 
00913         $oAcclist = oxNew( "oxarticlelist");
00914         $oAcclist->setSqlLimit( 0, $myConfig->getConfigParam( 'iNrofCrossellArticles' ));
00915         $oAcclist->loadArticleAccessoires($this->oxarticles__oxid->value);
00916 
00917         if ( $oAcclist->count()) {
00918             return $oAcclist;
00919         }
00920     }
00921 
00927     public function getSimilarProducts()
00928     {
00929         // Performance
00930         $myConfig = $this->getConfig();
00931         if ( !$myConfig->getConfigParam( 'bl_perfLoadSimilar' ) ) {
00932             return;
00933         }
00934 
00935         $sArticleTable = $this->_getObjectViewName('oxarticles');
00936 
00937         $sAttribs = '';
00938         $iCnt = 0;
00939         $this->_getAttribsString($sAttribs, $iCnt);
00940 
00941         if ( !$sAttribs) {
00942             return null;
00943         }
00944 
00945         // DODGER : Actually to optimize this function we only take the similar products from the first 100 hits
00946         // I think that this is possible as this function anyway never worked like it should
00947         // Calculation of iHitMin was ALWAYS == 1
00948         // Still it's not so fast like I would like to have it, but I don't have any idea how to improve it more
00949 
00950         $aList = $this->_getSimList($sAttribs, $iCnt);
00951 
00952         if ( count( $aList ) ) {
00953             uasort( $aList, 'cmpart');
00954 
00955             $sSearch = $this->_generateSimListSearchStr($sArticleTable, $aList);
00956 
00957             $oSimilarlist = oxNew( 'oxarticlelist' );
00958             $oSimilarlist->setSqlLimit( 0, $myConfig->getConfigParam( 'iNrofSimilarArticles' ));
00959             $oSimilarlist->selectString( $sSearch);
00960 
00961             return $oSimilarlist;
00962         }
00963     }
00964 
00970     public function getCustomerAlsoBoughtThisProducts()
00971     {
00972         // Performance
00973         $myConfig = $this->getConfig();
00974         if ( !$myConfig->getConfigParam( 'bl_perfLoadCustomerWhoBoughtThis' ) ) {
00975             return;
00976         }
00977 
00978         // selecting products that fits
00979         $sQ = $this->_generateSearchStrForCustomerBought();
00980 
00981         $oArticles = oxNew( 'oxarticlelist' );
00982         $oArticles->setSqlLimit( 0, $myConfig->getConfigParam( 'iNrofCustomerWhoArticles' ));
00983         $oArticles->selectString( $sQ );
00984         if ( $oArticles->count() ) {
00985             return $oArticles;
00986         }
00987     }
00988 
00995     public function loadAmountPriceInfo()
00996     {
00997         $myConfig = $this->getConfig();
00998         if ( !$myConfig->getConfigParam( 'bl_perfLoadPrice' ) || !$this->_blLoadPrice || !$this->_blCalcPrice) {
00999             return array();
01000         }
01001 
01002         if ( $this->_oAmountPriceInfo !== null ) {
01003             return $this->_oAmountPriceInfo;
01004         }
01005 
01006         $oAmPriceList = $this->_getAmountPriceList();
01007 
01008         if ( count( $oAmPriceList ) ) {
01009             $this->_oAmountPriceInfo = $this->_fillAmountPriceList( $oAmPriceList );
01010             return $this->_oAmountPriceInfo;
01011         }
01012 
01013         return array();
01014     }
01015 
01023     public function getSelectLists($sKeyPrefix = null)
01024     {
01025         //#1468C - more then one article in basket with different selectlist...
01026         //optionall function parameter $sKeyPrefix added, used only in basket.php
01027         $sKey = $this->getId();
01028         if ( isset( $sKeyPrefix ) ) {
01029             $sKey = $sKeyPrefix.'__'.$this->getId();
01030         }
01031 
01032         if ( self::$_aSelList[$sKey]) {
01033             return self::$_aSelList[$sKey];
01034         }
01035 
01036         // all selectlists this article has
01037         $oLists = oxNew( 'oxlist' );
01038         $oLists->init('oxselectlist');
01039         $sSLViewName = getViewName('oxselectlist');
01040         $sSelect  = "select $sSLViewName.* from oxobject2selectlist left join $sSLViewName on $sSLViewName.oxid=oxobject2selectlist.oxselnid ";
01041         $sSelect .= 'where oxobject2selectlist.oxobjectid=\''.$this->getId().'\' ';
01042         //sorting
01043         $sSelect .= ' order by oxobject2selectlist.oxsort';
01044 
01045         $oLists->selectString( $sSelect );
01046 
01047         //#1104S if this is variant ant it has no selectlists, trying with parent
01048         if ( $this->oxarticles__oxparentid->value && $oLists->count() == 0 ) {
01049             //#1496C - select fixed ( * => $sSLViewName.*)
01050             $sSelect  = "select $sSLViewName.* from oxobject2selectlist left join $sSLViewName on $sSLViewName.oxid=oxobject2selectlist.oxselnid ";
01051             $sSelect .= "where oxobject2selectlist.oxobjectid='{$this->oxarticles__oxparentid->value}' ";
01052             //sorting
01053             $sSelect .= ' order by oxobject2selectlist.oxsort';
01054             $oLists->selectString( $sSelect);
01055         }
01056 
01057         $dVat = 0;
01058         if ( $this->getPrice() != null ) {
01059             $dVat = $this->getPrice()->getVat();
01060         }
01061 
01062         $iCnt = 0;
01063         self::$_aSelList[$sKey] = array();
01064         foreach ( $oLists as $oSelectlist ) {
01065             self::$_aSelList[$sKey][$iCnt] = $oSelectlist->getFieldList( $dVat );
01066             self::$_aSelList[$sKey][$iCnt]['name'] = $oSelectlist->oxselectlist__oxtitle->value;
01067             $iCnt++;
01068         }
01069         return self::$_aSelList[$sKey];
01070     }
01071 
01079     public function getVariants( $blRemoveNotOrderables = true )
01080     {
01081         if ($this->_aVariants) {
01082             return $this->_aVariants;
01083         }
01084 
01085         //return ;
01086         if (!$this->_blLoadVariants) {
01087             return array();
01088         }
01089 
01090         $myConfig = $this->getConfig();
01091 
01092         // Performance
01093         if ( !$this->isAdmin() && !$myConfig->getConfigParam( 'blLoadVariants')) {
01094             return array();
01095         }
01096 
01097         //do not load variants where variant oxvarcount is 0
01098         //hint: if variantas are not loaded you should check your data integrity oxvarcount should always be equal to variant count
01099         if (!$this->isAdmin() && !$this->oxarticles__oxvarcount->value) {
01100             return array();
01101         }
01102 
01103         //do not load me as a parent later
01104         self::$_aLoadedParents[$this->getId()] = $this;
01105 
01106         //load simple variants for lists
01107         if ($this->_isInList()) {
01108             $oVariants = oxNew( 'oxsimplevariantlist' );
01109             $oVariants->setParent($this);
01110         } else {
01111             //loading variants
01112             $oVariants = oxNew( 'oxarticlelist' );
01113         }
01114 
01115         startProfile("selectVariants");
01116         $sSelectFields = $oVariants->getBaseObject()->getSelectFields();
01117         $sArticleTable = $this->getViewName();
01118         $sSelect =  "select $sSelectFields from $sArticleTable where ";
01119         $sSelect .= " $sArticleTable.oxparentid ='".$this->getId()."' ";
01120         $sSelect .= " order by $sArticleTable.oxsort";
01121         $oVariants->selectString( $sSelect);
01122         stopProfile("selectVariants");
01123 
01124         if (!$oVariants->count()) {
01125             return array();
01126         }
01127         $oVariants = $this->_removeInactiveVariants( $oVariants, $blRemoveNotOrderables );
01128         //$this->calculateMinVarPrice($oVariants);
01129         //#1104S Load selectlists
01130         if ( $myConfig->getConfigParam( 'bl_perfLoadSelectLists' ) ) {
01131             foreach ($oVariants as $key => $oVariant) {
01132                 $oVariants[$key]->aSelectlist = $oVariant->getSelectLists();
01133             }
01134         }
01135         $this->_aVariants = $oVariants;
01136         return $oVariants;
01137     }
01138 
01144     public function getSimpleVariants()
01145     {
01146         if ( $this->oxarticles__oxvarcount->value) {
01147             return $this->getVariants();
01148         }
01149     }
01150 
01159     public function getAdminVariants( $sLanguage = null )
01160     {
01161         $myConfig = $this->getConfig();
01162 
01163         $oVariants = oxNew( 'oxarticlelist');
01164 
01165         if ( is_null($sLanguage) ) {
01166             $oVariants->getBaseObject()->setLanguage(oxLang::getInstance()->getBaseLanguage());
01167         } else {
01168             $oVariants->getBaseObject()->setLanguage($sLanguage);
01169         }
01170 
01171         $sSql = 'select * from oxarticles where oxparentid = "'.$this->getId().'" order by oxsort ';
01172 
01173         $oVariants->selectString( $sSql);
01174 
01175         //if we have variants then depending on config option the parent may be non buyable
01176         if (!$myConfig->getConfigParam( 'blVariantParentBuyable' ) && ($oVariants->count() > 0)) {
01177             //$this->blNotBuyable = true;
01178             $this->_blNotBuyableParent = true;
01179         }
01180 
01181         return $oVariants;
01182     }
01183 
01191     public function getCategory()
01192     {
01193         startPRofile( 'getCategory' );
01194 
01195         $oCategory = oxNew( 'oxcategory' );
01196         $oCategory->setLanguage( $this->getLanguage() );
01197 
01198         // variant handling
01199         $sOXID = $this->getId();
01200         if ( isset( $this->oxarticles__oxparentid->value ) && $this->oxarticles__oxparentid->value ) {
01201             $sOXID = $this->oxarticles__oxparentid->value;
01202         }
01203 
01204         $oStr = getStr();
01205         $sWhere   = $oCategory->getSqlActiveSnippet();
01206         $sSelect  = $this->_generateSearchStr( $sOXID );
01207         $sSelect .= ( $oStr->strstr( $sSelect, 'where' )?' and ':' where ') . $sWhere . " order by oxobject2category.oxtime ";
01208 
01209         // category not found ?
01210         if ( !$oCategory->assignRecord( $sSelect ) ) {
01211 
01212             $sSelect  = $this->_generateSearchStr( $sOXID, true );
01213             $sSelect .= ( $oStr->strstr( $sSelect, 'where' )?' and ':' where ') . $sWhere ;
01214 
01215             // looking for price category
01216             if ( !$oCategory->assignRecord( $sSelect ) ) {
01217                 $oCategory = null;
01218             }
01219         }
01220 
01221         stopPRofile( 'getCategory' );
01222         return $oCategory;
01223     }
01224 
01232     public function getCategoryIds( $blSkipCache = false )
01233     {
01234         $myConfig = $this->getConfig();
01235         if ( isset( self::$_aArticleCats[$this->getId()] ) && !$blSkipCache ) {
01236             return self::$_aArticleCats[$this->getId()];
01237         }
01238 
01239         // variant handling
01240         $sOXID = $this->getId();
01241         if (isset( $this->oxarticles__oxparentid->value) && $this->oxarticles__oxparentid->value) {
01242             $sOXID = $this->oxarticles__oxparentid->value;
01243         }
01244 
01245         $sO2CView = $this->_getObjectViewName('oxobject2category');
01246         $sCatView = $this->_getObjectViewName('oxcategories');
01247 
01248         // we do not use lists here as we dont need this overhead right now
01249         $oDB = oxDb::getDb(true);
01250         $sSelect =  "select oxobject2category.oxcatnid as oxcatnid from $sO2CView as oxobject2category left join $sCatView as oxcategories on oxcategories.oxid = oxobject2category.oxcatnid ";
01251         $sSelect .= 'where oxobject2category.oxobjectid=\''.$sOXID.'\' and oxcategories.oxid is not null and oxcategories.oxactive'.(($this->getLanguage())?'_'.$this->getLanguage():'').' = 1 order by oxobject2category.oxtime ';
01252         $rs = $oDB->execute( $sSelect);
01253 
01254 
01255         $aRet = array();
01256         $iHitMax = 0;
01257         if ($rs != false && $rs->recordCount() > 0) {
01258             while (!$rs->EOF) {
01259                 $aRet[] = $rs->fields['oxcatnid'];
01260                 $rs->moveNext();
01261             }
01262         }
01263 
01264         return self::$_aArticleCats[$this->getId()] = $aRet;
01265     }
01266 
01276     public function getVendor( $blShopCheck = true )
01277     {
01278         if ( ( $sVendorId = $this->getVendorId() ) ) {
01279             $oVendor = oxNew( 'oxvendor' );
01280         } elseif ( !$blShopCheck && $this->oxarticles__oxvendorid->value ) {
01281             $oVendor = oxNew( 'oxi18n' );
01282             $oVendor->init('oxvendor');
01283             $oVendor->setReadOnly( true );
01284             $sVendorId = $this->oxarticles__oxvendorid->value;
01285         }
01286         if ( $sVendorId && $oVendor->load( $sVendorId ) && $oVendor->oxvendor__oxactive->value ) {
01287             if ( !$this->getConfig()->getConfigParam( 'bl_perfLoadVendorTree' ) ) {
01288                 $oVendor->setReadOnly( true );
01289             }
01290             return $oVendor;
01291         }
01292         return null;
01293     }
01294 
01302     public function getVendorId( $blForceReload = false )
01303     {
01304         $sVendorId = false;
01305         if ( $this->oxarticles__oxvendorid->value ) {
01306             if ( !$blForceReload && isset( self::$_aArticleVendors[$this->getId()] ) ) {
01307                 return self::$_aArticleVendors[$this->getId()];
01308             }
01309             $sQ = "select oxid from ".getViewName('oxvendor')." where oxid='{$this->oxarticles__oxvendorid->value}'";
01310             self::$_aArticleVendors[$this->getId()] = $sVendorId = oxDb::getDb()->getOne( $sQ );
01311         }
01312         return $sVendorId;
01313     }
01314 
01322     public function getManufacturerId( $blForceReload = false )
01323     {
01324         $sManufacturerId = false;
01325         if ( $this->oxarticles__oxmanufacturerid->value ) {
01326             if ( !$blForceReload && isset( self::$_aArticleManufacturers[$this->getId()])) {
01327                 return self::$_aArticleManufacturers[$this->getId()];
01328             }
01329             $sQ = "select oxid from ".getViewName('oxmanufacturers')." where oxid='{$this->oxarticles__oxmanufacturerid->value}'";
01330             self::$_aArticleManufacturers[$this->getId()] = $sManufacturerId = oxDb::getDb()->getOne( $sQ );
01331         }
01332         return $sManufacturerId;
01333     }
01334 
01344     public function getManufacturer( $blShopCheck = true )
01345     {
01346         $oManufacturer = null;
01347         if ( ( $sManufacturerId = $this->getManufacturerId() ) ) {
01348             $oManufacturer = oxNew( 'oxmanufacturer' );
01349         } elseif ( !$blShopCheck && $this->oxarticles__oxmanufacturerid->value ) {
01350             $oManufacturer = oxNew( 'oxI18n' );
01351             $oManufacturer->init('oxmanufacturers');
01352             $oManufacturer->setReadOnly( true );
01353             $sManufacturerId = $this->oxarticles__oxmanufacturerid->value;
01354         }
01355 
01356         if ( $sManufacturerId && $oManufacturer->load( $sManufacturerId ) ) {
01357             if ( !$this->getConfig()->getConfigParam( 'bl_perfLoadManufacturerTree' ) ) {
01358                 $oManufacturer->setReadOnly( true );
01359             }
01360             $oManufacturer = $oManufacturer->oxmanufacturers__oxactive->value ? $oManufacturer : null;
01361         } else {
01362             $oManufacturer = null;
01363         }
01364 
01365         return $oManufacturer;
01366     }
01367 
01376     public function inCategory( $sCatNid)
01377     {
01378         return in_array( $sCatNid, $this->getCategoryIds());
01379     }
01380 
01389     public function isAssignedToCategory( $sCatId )
01390     {
01391         // variant handling
01392         $sOXID = $this->getId();
01393         if ( isset( $this->oxarticles__oxparentid->value) && $this->oxarticles__oxparentid->value) {
01394             $sOXID = $this->oxarticles__oxparentid->value;
01395         }
01396 
01397         $oDB = oxDb::getDb();
01398         $sSelect = $this->_generateSelectCatStr( $sOXID, $sCatId);
01399         $sOXID = $oDB->getOne( $sSelect);
01400         // article is assigned to passed category!
01401         if ( isset( $sOXID) && $sOXID) {
01402             return true;
01403         }
01404 
01405         // maybe this category is price category ?
01406         if ( $this->getConfig()->getConfigParam( 'bl_perfLoadPrice' ) && $this->_blLoadPrice ) {
01407             $dPriceFromTo = $this->getPrice()->getBruttoPrice();
01408             if ( $dPriceFromTo > 0) {
01409                 $sSelect = $this->_generateSelectCatStr( $sOXID, $sCatId, $dPriceFromTo);
01410                 $sOXID = $oDB->getOne( $sSelect);
01411                 // article is assigned to passed category!
01412                 if ( isset( $sOXID) && $sOXID) {
01413                     return true;
01414                 }
01415             }
01416         }
01417         return false;
01418     }
01419 
01425     public function getTPrice()
01426     {
01427         if ( !$this->getConfig()->getConfigParam( 'bl_perfLoadPrice' ) || !$this->_blLoadPrice ) {
01428             return;
01429         }
01430         // return cached result, since oPrice is created ONLY in this function [or function of EQUAL level]
01431         if ( $this->_oTPrice !== null ) {
01432             return $this->_oTPrice;
01433         }
01434 
01435         $this->_oTPrice = oxNew( 'oxPrice' );
01436         $this->_oTPrice->setPrice( $this->oxarticles__oxtprice->value );
01437 
01438         $this->_applyVat( $this->_oTPrice, $this->getArticleVat() );
01439         $this->_applyCurrency( $this->_oTPrice );
01440 
01441         return $this->_oTPrice;
01442     }
01443 
01449     public function skipDiscounts()
01450     {
01451         // allready loaded skip discounts config
01452         if ( $this->_blSkipDiscounts !== null )
01453             return $this->_blSkipDiscounts;
01454 
01455         if ( $this->oxarticles__oxskipdiscounts->value )
01456             return true;
01457 
01458         $sO2CView = getViewName('oxobject2category');
01459         $sSelect =  "select 1 from $sO2CView as oxobject2category left join oxcategories on oxcategories.oxid = oxobject2category.oxcatnid ";
01460         $sSelect .= 'where oxobject2category.oxobjectid="'.$this->getId().'" and oxcategories.oxactive'.(($this->getLanguage())?'_'.$this->getLanguage():'').' = 1 and oxcategories.oxskipdiscounts = "1" ';
01461 
01462         return $this->_blSkipDiscounts = ( oxDb::getDb()->getOne($sSelect) == 1 );
01463     }
01464 
01472     public function setPrice(oxPrice $oPrice)
01473     {
01474         $this->_oPrice = $oPrice;
01475     }
01476 
01485     public function getBasePrice( $dAmount = 1 )
01486     {
01487         // override this function if you want e.g. different prices
01488         // for diff. usergroups.
01489 
01490         // Performance
01491         $myConfig = $this->getConfig();
01492         if( !$myConfig->getConfigParam( 'bl_perfLoadPrice' ) || !$this->_blLoadPrice )
01493             return;
01494 
01495         // GroupPrice or DB price ajusted by AmountPrice
01496         $dPrice = $this->_getAmountPrice( $dAmount );
01497 
01498 
01499         return $dPrice;
01500     }
01501 
01507     public function getPrice()
01508     {
01509         $myConfig = $this->getConfig();
01510         // Performance
01511         if ( !$myConfig->getConfigParam( 'bl_perfLoadPrice' ) || !$this->_blLoadPrice ) {
01512             return;
01513         }
01514         // return cached result, since oPrice is created ONLY in this function [or function of EQUAL level]
01515         if ( $this->_oPrice ) {
01516             return $this->_oPrice;
01517         }
01518 
01519         $this->_oPrice = oxNew( 'oxPrice' );
01520 
01521         // get base
01522         $this->_oPrice->setPrice( $this->getBasePrice() );
01523 
01524         // price handling
01525         if ( !$this->_blCalcPrice ) {
01526             return $this->_oPrice;
01527         }
01528 
01529         // apply VAT only if configuration requires it
01530         if ( !$myConfig->getConfigParam( 'bl_perfCalcVatOnlyForBasketOrder' ) ) {
01531             $this->_applyVAT( $this->_oPrice, $this->getArticleVat() );
01532         }
01533 
01534         // apply currency
01535         $this->_applyCurrency( $this->_oPrice );
01536 
01537         // apply discounts
01538         if ( !$this->skipDiscounts() ) {
01539             $this->_applyDiscounts($this->_oPrice, oxDiscountList::getInstance()->getArticleDiscounts($this, $this->getArticleUser()));
01540         }
01541 
01542         return $this->_oPrice;
01543     }
01544 
01552     public function setArticleUser($oUser)
01553     {
01554         $this->_oUser = $oUser;
01555     }
01556 
01562     public function getArticleUser()
01563     {
01564         if ($this->_oUser) {
01565             return $this->_oUser;
01566         }
01567         return $this->getUser();
01568     }
01569 
01579     public function getBasketPrice( $dAmount, $aSelList, $oBasket )
01580     {
01581         $oUser = $oBasket->getBasketUser();
01582         $this->setArticleUser($oUser);
01583 
01584         $oBasketPrice = oxNew( 'oxPrice' );
01585 
01586         // get base price
01587         $dBasePrice = $this->getBasePrice( $dAmount );
01588 
01589         // applying select list price
01590         $this->_modifySelectListPrice( $dBasePrice, $aSelList );
01591 
01592         // setting price
01593         $oBasketPrice->setPrice( $dBasePrice );
01594 
01595         // apply VAT
01596         $this->_applyVat( $oBasketPrice, oxVatSelector::getInstance()->getBasketItemVat( $this, $oBasket ) );
01597 
01598         // apply currency
01599         $this->_applyCurrency( $oBasketPrice );
01600 
01601         // apply discounts
01602         if ( !$this->skipDiscounts() ) {
01603             // apply general discounts
01604             $this->_applyDiscounts( $oBasketPrice, oxDiscountList::getInstance()->getArticleDiscounts( $this, $oUser ) );
01605         }
01606 
01607         // returning final price object
01608         return $oBasketPrice;
01609     }
01610 
01621     public function applyBasketDiscounts(oxPrice $oPrice, $aDiscounts, $dAmount = 1)
01622     {
01623         $aDiscLog = array();
01624         reset( $aDiscounts );
01625 
01626         // price object to correctly perform calculations
01627         $dOldPrice = $oPrice->getBruttoPrice();
01628 
01629         while (list( , $oDiscount) = each($aDiscounts)) {
01630             $oDiscount->applyDiscount( $oPrice );
01631             $dNewPrice = $oPrice->getBruttoPrice();
01632 
01633             if (!isset($aDiscLog[$oDiscount->getId()])) {
01634                 $aDiscLog[$oDiscount->getId()] = $oDiscount->getSimpleDiscount();
01635             }
01636 
01637             $aDiscLog[$oDiscount->getId()]->dDiscount += $dOldPrice - $dNewPrice;
01638             $aDiscLog[$oDiscount->getId()]->dDiscount *= $dAmount;
01639             $dOldPrice = $dNewPrice;
01640         }
01641         return $aDiscLog;
01642     }
01643 
01652     public function delete( $sOXID = null )
01653     {
01654         if ( !$sOXID ) {
01655             $sOXID = $this->getId();
01656         }
01657         if ( !$sOXID ) {
01658             return false;
01659         }
01660 
01661 
01662         $this->load( $sOXID );
01663         $this->_deletePics();
01664         $this->_onChangeResetCounts( $sOXID, $this->oxarticles__oxvendorid->value, $this->oxarticles__oxmanufacturerid->value );
01665         $this->_deleteVariantRecords( $sOXID );
01666         $rs = $this->_deleteRecords( $sOXID );
01667 
01668         oxSeoEncoderArticle::getInstance()->onDeleteArticle($this);
01669 
01670         $this->onChange( ACTION_DELETE, $sOXID, $this->oxarticles__oxparentid->value );
01671 
01672         return $rs->EOF;
01673     }
01674 
01683     public function updateSoldAmount( $iAmount = 0 )
01684     {
01685         if ( !$iAmount ) {
01686             return;
01687         }
01688 
01689         $this->beforeUpdate();
01690 
01691         // article is not variant - should be updated current amount
01692         if ( !$this->oxarticles__oxparentid->value ) {
01693             //updating by SQL query, due to wrong behaviour if saving article using not admin mode
01694             $rs = oxDb::getDb()->execute( "update oxarticles set oxarticles.oxsoldamount = oxarticles.oxsoldamount + $iAmount, oxarticles.oxtimestamp = oxarticles.oxtimestamp where oxarticles.oxid = '".$this->oxarticles__oxid->value."'");
01695         } elseif ( $this->oxarticles__oxparentid->value) {
01696             // article is variant - should be updated this article parent amount
01697             $oUpdateArticle = oxNewArticle( $this->oxarticles__oxparentid->value );
01698             $oUpdateArticle->updateSoldAmount( $iAmount );
01699         }
01700 
01701         $this->onChange( ACTION_UPDATE );
01702 
01703         return $rs;
01704     }
01705 
01711     public function disableReminder()
01712     {
01713         $oDB = oxDb::getDb(true);
01714         return $oDB->execute( "update oxarticles set oxarticles.oxremindactive = 2 where oxarticles.oxid = '".$this->oxarticles__oxid->value."'");
01715     }
01716 
01723     public function save()
01724     {
01725         $myConfig = $this->getConfig();
01726 
01727         $this->oxarticles__oxthumb = new oxField(basename($this->oxarticles__oxthumb->value), oxField::T_RAW);
01728         $this->oxarticles__oxicon  = new oxField(basename($this->oxarticles__oxicon->value), oxField::T_RAW);
01729         $iPicCount = $myConfig->getConfigParam( 'iPicCount');
01730         for ($i=1; $i <= $iPicCount; $i++) {
01731             if ( isset($this->{'oxarticles__oxpic'.$i}) ) {
01732                 $this->{'oxarticles__oxpic'.$i}->setValue(basename($this->{'oxarticles__oxpic'.$i}->value));
01733             }
01734         }
01735         $iZoomPicCount = $myConfig->getConfigParam( 'iZoomPicCount' );
01736         for ($i=1; $i <= $iZoomPicCount; $i++) {
01737             if ( isset($this->{'oxarticles__oxzoom'.$i}) ) {
01738                 $this->{'oxarticles__oxzoom'.$i}->setValue(basename($this->{'oxarticles__oxzoom'.$i}->value));
01739             }
01740         }
01741 
01742 
01743             $blRet = parent::save();
01744 
01745         // save article long description
01746         $this->setArticleLongDesc();
01747         // load article images after save
01748         $this->_assignPictureValues();
01749 
01750         return $blRet;
01751     }
01752 
01759     public function getPictureGallery()
01760     {
01761         $myConfig = $this->getConfig();
01762 
01763         //initialize
01764         $blMorePic = false;
01765         $aArtPics  = array();
01766         $aArtIcons = array();
01767         $iActPicId = 1;
01768         $sActPic = $this->getPictureUrl( $iActPicId );
01769 
01770         if ( oxConfig::getParameter( 'actpicid' ) ) {
01771             $iActPicId = oxConfig::getParameter('actpicid');
01772         }
01773 
01774         $oStr = getStr();
01775         $iCntr = 0;
01776         $iPicCount = $myConfig->getConfigParam( 'iPicCount' );
01777         for ( $i = 1; $i <= $iPicCount; $i++) {
01778             $sPicVal = $this->getPictureUrl( $i );
01779             $sIcoVal = $this->getIconUrl( $i );
01780             if ( !$oStr->strstr($sIcoVal, 'nopic_ico.jpg')) {
01781                 if ($iCntr) {
01782                     $blMorePic = true;
01783                 }
01784                 $aArtIcons[$i]= $sIcoVal;
01785                 $aArtPics[$i]= $sPicVal;
01786                 $iCntr++;
01787             }
01788             if ($iActPicId == $i) {
01789                 $sActPic = $sPicVal;
01790             }
01791         }
01792 
01793         $blZoomPic  = false;
01794         $aZoomPics = array();
01795         $iZoomPicCount = $myConfig->getConfigParam( 'iZoomPicCount' );
01796         for ( $j = 1,$c = 1; $j <= $iZoomPicCount; $j++) {
01797             $sVal = $this->getZoomPictureUrl($j);
01798             if ( !$oStr->strstr($sVal, 'nopic.jpg')) {
01799                 if ($this->getConfig()->getConfigParam('blFormerTplSupport')) {
01800                     $sVal = $this->_sDynImageDir."/".$sVal;
01801                 }
01802                 $blZoomPic = true;
01803                 $aZoomPics[$c]['id'] = $c;
01804                 $aZoomPics[$c]['file'] = $sVal;
01805                 //anything is better than empty name, because <img src=""> calls shop once more = x2 SLOW.
01806                 if (!$sVal) {
01807                     $aZoomPics[$c]['file'] = "nopic.jpg";
01808                 }
01809                 $c++;
01810             }
01811         }
01812 
01813         $aPicGallery = array('ActPicID' => $iActPicId,
01814                              'ActPic' => $sActPic,
01815                              'MorePics' => $blMorePic,
01816                              'Pics' => $aArtPics,
01817                              'Icons' => $aArtIcons,
01818                              'ZoomPic' => $blZoomPic,
01819                              'ZoomPics' => $aZoomPics);
01820 
01821         return $aPicGallery;
01822     }
01823 
01837     public function onChange($sAction = null, $sOXID = null, $sParentID = null)
01838     {
01839         $myConfig = $this->getConfig();
01840 
01841         if (!isset($sOXID)) {
01842             if ( $this->getId()) {
01843                 $sOXID = $this->getId();
01844             }
01845             if (!isset ($sOXID)) {
01846                 $sOXID = $this->oxarticles__oxid->value;
01847             }
01848             if ($this->oxarticles__oxparentid->value) {
01849                 $sParentID = $this->oxarticles__oxparentid->value;
01850             }
01851         }
01852         if (!isset($sOXID)) {
01853             return;
01854         }
01855 
01856         //if (isset($sOXID) && !$myConfig->blVariantParentBuyable && $myConfig->blUseStock)
01857         if ( $myConfig->getConfigParam( 'blUseStock' ) ) {
01858             //if article has variants then updating oxvarstock field
01859             //getting parent id
01860             if (!isset($sParentID)) {
01861                 $sQ = 'select oxparentid from oxarticles where oxid = \''.$sOXID.'\'';
01862                 $sParentID = oxDb::getDb()->getOne($sQ);
01863             }
01864             //if we have parent id then update stock
01865             if ($sParentID) {
01866                 $this->_onChangeUpdateStock($sParentID);
01867             }
01868         }
01869         //if we have parent id then update count
01870         //update count even if blUseStock is not active
01871         if ($sParentID) {
01872             $this->_onChangeUpdateVarCount($sParentID);
01873         }
01874 
01875         $sId = ( $sParentID ) ? $sParentID : $sOXID;
01876         $this->_onChangeUpdateMinVarPrice( $sId );
01877 
01878     }
01879 
01886     public function getCustomVAT()
01887     {
01888         if ( isset($this->oxarticles__oxvat->value) ) {
01889             return $this->oxarticles__oxvat->value;
01890         }
01891     }
01892 
01900     public function checkForStock( $dAmount )
01901     {
01902         $myConfig = $this->getConfig();
01903         if ( !$myConfig->getConfigParam( 'blUseStock' ) ) {
01904             return true;
01905         }
01906 
01907         // fetching DB info as its up-to-date
01908         $sQ = 'select oxstock, oxstockflag from oxarticles where oxid = "'.$this->getId().'" ';
01909         $rs = oxDb::getDb(true)->Execute( $sQ );
01910 
01911         $iOnStock   = 0;
01912         $iStockFlag = 0;
01913         if ( $rs !== false && $rs->recordCount() > 0 ) {
01914             $iOnStock   = $rs->fields['oxstock'];
01915             $iStockFlag = $rs->fields['oxstockflag'];
01916 
01917             // dodger : fremdlager is also always considered as on stock
01918             if ( $iStockFlag == 1 || $iStockFlag == 4) {
01919                 return true;
01920             }
01921             if ( !$myConfig->getConfigParam( 'blAllowUnevenAmounts' ) ) {
01922                 //2007-09-04 MK this if is NEVER true, because upper return in if $iStockFlag == 1 or $iStockFlag == 4
01923                 /* if ( $iStockFlag == 1 || $iStockFlag == 4 ) {
01924                     $iOnStock = ceil( $iOnStock );
01925                  } else {*/
01926                     $iOnStock = floor( $iOnStock );
01927                 //}
01928             }
01929         }
01930 
01931         if ( $iOnStock >= $dAmount ) {
01932             return true;
01933         } else {
01934             if ( $iOnStock > 0 ) {
01935                 return $iOnStock;
01936             } else {
01937                 return false;
01938             }
01939         }
01940     }
01941 
01942 
01950     public function getArticleLongDesc($sOXID = null)
01951     {
01952 
01953         if ( !$sOXID ) {
01954             $sOXID = $this->oxarticles__oxid->value;
01955         }
01956 
01957         if ($sOXID == $this->oxarticles__oxid->value) {
01958             if (isset($this->oxarticles__oxlongdesc) && ($this->oxarticles__oxlongdesc instanceof oxField) && $this->oxarticles__oxlongdesc->value) {
01959                 return $this->oxarticles__oxlongdesc;
01960             }
01961         }
01962 
01963         $myConfig = $this->getConfig();
01964 
01965         // TODO: check if keeping fldname is needed in non-admin mode
01966         $this->oxarticles__oxlongdesc = new oxField();
01967         $this->oxarticles__oxlongdesc->fldname = 'oxlongdesc';
01968         $this->oxarticles__oxlongdesc->table   = 'oxarticles';
01969         $this->oxarticles__oxlongdesc->fldtype = 'text';
01970 
01971         if ( $sOXID ) {
01972             $sLangField = oxLang::getInstance()->getLanguageTag($this->getLanguage());
01973             $this->oxarticles__oxlongdesc->setValue(oxDb::getDb()->getOne( "select oxlongdesc{$sLangField} from oxartextends where oxid = '$sOXID'" ), oxField::T_RAW);
01974 
01975             // TODO: eliminate code below
01976             // hack, if editor screws up text, htmledit tends to do so
01977             $this->oxarticles__oxlongdesc->setValue(str_replace( '&amp;nbsp;', '&nbsp;', $this->oxarticles__oxlongdesc->value ), oxField::T_RAW);
01978             $this->oxarticles__oxlongdesc->setValue(str_replace( '&amp;', '&', $this->oxarticles__oxlongdesc->value ), oxField::T_RAW);
01979             $this->oxarticles__oxlongdesc->setValue(str_replace( '&quot;', '"', $this->oxarticles__oxlongdesc->value ), oxField::T_RAW);
01980             $oStr = getStr();
01981             $blHasSmarty = $oStr->strstr( $this->oxarticles__oxlongdesc->value, '[{' );
01982             $blHasPhp = $oStr->strstr( $this->oxarticles__oxlongdesc->value, '<?' );
01983             if ( ( $blHasSmarty || $blHasPhp ) && ($myConfig->getConfigParam( 'blExport' ) || !$this->isAdmin() ) && $myConfig->getConfigParam( 'bl_perfParseLongDescinSmarty' ) ) {
01984                 $this->oxarticles__oxlongdesc->setValue(oxUtilsView::getInstance()->parseThroughSmarty( $this->oxarticles__oxlongdesc->value, $this->getId() ), oxField::T_RAW);
01985             }
01986         }
01987 
01988         return $this->oxarticles__oxlongdesc;
01989     }
01990 
01996     public function setArticleLongDesc()
01997     {
01998 
01999         if ($this->_blEmployMultilanguage) {
02000             // update or insert article long description
02001             if ($this->oxarticles__oxlongdesc instanceof oxField) {
02002                 $sLongDesc = $this->oxarticles__oxlongdesc->getRawValue();
02003             } else {
02004                 $sLongDesc = $this->oxarticles__oxlongdesc->value;
02005             }
02006             $this->_saveArtLongDesc($this->getLanguage(), $sLongDesc);
02007         } else {
02008             $oArtExt = oxNew('oxi18n');
02009             $oArtExt->init('oxartextends');
02010             $aObjFields = $oArtExt->_getAllFields(true);
02011             foreach ($aObjFields as $sKey => $sValue ) {
02012                 if ( preg_match('/^oxlongdesc(_(\d{1,2}))?$/', $sKey) ) {
02013                     $iLang = $oArtExt->_getFieldLang($sKey);
02014                     $sField = $this->_getFieldLongName($sKey);
02015                     $sLongDesc = null;
02016                     if ($this->$sField instanceof oxField) {
02017                         $sLongDesc = $this->$sField->getRawValue();
02018                     } elseif (is_object($this->$sField)) {
02019                         $sLongDesc = $this->$sField->value;
02020                     }
02021                     if (isset($sLongDesc)) {
02022                         $this->_saveArtLongDesc($iLang, $sLongDesc);
02023                     }
02024                 }
02025             }
02026         }
02027     }
02028 
02034     public function getAttributes()
02035     {
02036 
02037         if ($this->_oAttributeList) {
02038             return $this->_oAttributeList;
02039         }
02040 
02041         $oAttributeList = oxNew( 'oxattributelist' );
02042         $oAttributeList->loadAttributes( $this->getId());
02043         //if config option is set then the value for this object is also set
02044         //2007-02-09T
02045         $this->_oAttributeList = $oAttributeList;
02046 
02047         return $oAttributeList;
02048     }
02049 
02057     public function appendLink( $sAddParams )
02058     {
02059         if ( $this->_sDetailLink === null ) {
02060             $this->_sDetailLink = $this->getLink();
02061         }
02062         $this->_sDetailLink .= (( strpos( $this->_sDetailLink, '?' ) !== false ) ? '&amp;' : '?' ) . $sAddParams;
02063     }
02064 
02072     public function getLink($iLang = null)
02073     {
02074         if (isset($iLang)) {
02075             $iLang = (int) $iLang;
02076             if ($iLang == (int) $this->getLanguage()) {
02077                 $iLang = null;
02078             }
02079         }
02080         if ( $this->_sDetailLink === null || isset($iLang) ) {
02081 
02082             if ( oxUtils::getInstance()->seoIsActive() ) {
02083                 $oxdetaillink = oxSeoEncoderArticle::getInstance()->getArticleUrl( $this, $iLang, $this->_iLinkType);
02084             } else {
02085                 $oxdetaillink = $this->getStdLink($iLang);
02086             }
02087 
02088             if (isset($iLang)) {
02089                 return $oxdetaillink;
02090             } else {
02091                 $this->_sDetailLink = $oxdetaillink;
02092             }
02093         }
02094 
02095         return $this->_sDetailLink;
02096     }
02097 
02105     public function setLinkType( $iType )
02106     {
02107         // resetting detaisl link, to force new
02108         $this->_sDetailLink = null;
02109 
02110         // setting link type
02111         $this->_iLinkType = (int) $iType;
02112     }
02113 
02121     public function getStdLink($iLang = null)
02122     {
02123         //always returns shop url, not admin
02124         $sUrl  = $this->getConfig()->getShopHomeURL( $iLang, false );
02125         $sUrl .= "cl=details&amp;anid=".$this->getId();
02126 
02127         $blSeo = oxUtils::getInstance()->seoIsActive();
02128         if ( !$blSeo || $this->_iLinkType != 0 ) {
02129 
02130             if ( !$blSeo ) {
02131                 $iPgNr = (int) oxConfig::getParameter( 'pgNr' );
02132                 if ( $iPgNr > 0 ) {
02133                     $sUrl .= "&amp;pgNr={$iPgNr}";
02134                 }
02135             }
02136 
02137             if ( ( $sCat = oxConfig::getParameter( 'cnid' ) ) ) {
02138                 $sUrl .= "&amp;cnid={$sCat}";
02139             }
02140 
02141             if ( ( $sCat = oxConfig::getParameter( 'mnid' ) ) ) {
02142                 $sUrl .= "&amp;mnid={$sCat}";
02143             }
02144 
02145             $sListType = oxConfig::getParameter( 'listtype' );
02146             if ( !isset( $sListType ) ) {
02147                 // view defined list type
02148                 $sListType = $this->getConfig()->getGlobalParameter( 'listtype' );
02149             }
02150 
02151             // list type
02152             if ( $sListType ) {
02153                 $sUrl .= "&amp;listtype={$sListType}";
02154             }
02155 
02156             if (!$blSeo && isset($iLang)) {
02157                 $iLang = (int) $iLang;
02158                 if ($iLang != (int) $this->getLanguage()) {
02159                     $sUrl .= "&amp;lang={$iLang}";
02160                 }
02161             }
02162         }
02163 
02164         return $sUrl;
02165     }
02166 
02172     public function getTags()
02173     {
02174         $sTagField = "oxtags".oxLang::getInstance()->getLanguageTag($this->getLanguage());
02175         $sQ = "select $sTagField from oxartextends where oxid = '".$this->getId()."'";
02176         $sTags = oxDb::getDb(true)->getOne($sQ);
02177         $oTagCloud = oxNew('oxtagcloud');
02178         $sTags = $oTagCloud->trimTags($sTags);
02179         return $sTags;
02180     }
02181 
02189     public function saveTags($sTags)
02190     {
02191         $sTags = mysql_real_escape_string($sTags);
02192         $oTagCloud = oxNew('oxtagcloud');
02193         $oTagCloud->resetTagCache();
02194         $sTags = $oTagCloud->prepareTags($sTags);
02195         $sTagField = "oxtags".oxLang::getInstance()->getLanguageTag($this->getLanguage());
02196         $sQ = "update oxartextends set $sTagField = '$sTags'  where oxid = '".$this->getId()."'";
02197         return oxDb::getDb()->execute($sQ);
02198 
02199     }
02200 
02208     public function addTag($sTag)
02209     {
02210         $sTag = mysql_real_escape_string($sTag);
02211 
02212         $oTagCloud = oxNew('oxtagcloud');
02213         $oTagCloud->resetTagCache();
02214         $sTag = $oTagCloud->prepareTags($sTag);
02215 
02216         $sField = "oxartextends.OXTAGS".oxLang::getInstance()->getLanguageTag();
02217         $sQ = "insert into oxartextends (oxartextends.OXID, $sField) values ('".$this->getId()."', '{$sTag}')
02218                        ON DUPLICATE KEY update $sField = CONCAT(TRIM($sField), ' $sTag') ";
02219 
02220         return oxDb::getDb()->Execute($sQ);
02221     }
02222 
02228     public function getMediaUrls()
02229     {
02230         if ($this->_aMediaUrls) {
02231             return $this->_aMediaUrls;
02232         }
02233 
02234         $this->_aMediaUrls = oxNew("oxlist");
02235         $this->_aMediaUrls->init("oxmediaurl");
02236         $this->_aMediaUrls->getBaseObject()->setLanguage( $this->getLanguage() );
02237 
02238         $sQ = "select * from oxmediaurls where oxobjectid = '".$this->getId()."'";
02239         $this->_aMediaUrls->selectString($sQ);
02240 
02241         return $this->_aMediaUrls;
02242     }
02243 
02249     public function getDynImageDir()
02250     {
02251         return $this->_sDynImageDir;
02252     }
02253 
02259     public function getDispSelList()
02260     {
02261         if ($this->_aDispSelList === null) {
02262             if ( $this->getConfig()->getConfigParam( 'bl_perfLoadSelectLists' ) && $this->getConfig()->getConfigParam( 'bl_perfLoadSelectListsInAList' ) ) {
02263                 $this->_aDispSelList = $this->getSelectLists();
02264             }
02265         }
02266         return $this->_aDispSelList;
02267     }
02268 
02274     public function getMoreDetailLink()
02275     {
02276         return $this->_sMoreDetailLink;
02277     }
02278 
02284     public function getToBasketLink()
02285     {
02286         return $this->_sToBasketLink;
02287     }
02288 
02294     public function getStockStatus()
02295     {
02296         return $this->_iStockStatus;
02297     }
02298 
02304     public function getDeliveryDate()
02305     {
02306         if ( $this->oxarticles__oxdelivery->value != '0000-00-00') {
02307             return oxUtilsDate::getInstance()->formatDBDate( $this->oxarticles__oxdelivery->value);
02308         } else {
02309             return false;
02310         }
02311     }
02312 
02318     public function getFTPrice()
02319     {
02320         if ( $oPrice = $this->getTPrice() ) {
02321             if ( $oPrice->getBruttoPrice() ) {
02322                 return oxLang::getInstance()->formatCurrency( oxUtils::getInstance()->fRound($oPrice->getBruttoPrice()));
02323             }
02324         } else {
02325             return null;
02326         }
02327     }
02328 
02334     public function getFPrice()
02335     {
02336         if ( $oPrice = $this->getPrice() ) {
02337             return $this->getPriceFromPrefix().oxLang::getInstance()->formatCurrency( $oPrice->getBruttoPrice() );
02338         } else {
02339             return null;
02340         }
02341     }
02342 
02348     public function getPricePerUnit()
02349     {
02350         return $this->_fPricePerUnit;
02351     }
02352 
02358     public function isParentNotBuyable()
02359     {
02360         return $this->_blNotBuyableParent;
02361     }
02362 
02368     public function isNotBuyable()
02369     {
02370         return $this->_blNotBuyable;
02371     }
02372 
02378     public function getVariantList()
02379     {
02380         return $this->_oVariantList;
02381     }
02382 
02390     public function setSelectlist( $aSelList )
02391     {
02392         $this->_aDispSelList = $aSelList;
02393     }
02394 
02402     public function getPictureUrl( $iIndex )
02403     {
02404         return $this->getConfig()->getPictureUrl( $this->{"oxarticles__oxpic".$iIndex}->value );
02405     }
02406 
02414     public function getIconUrl( $iIndex = '')
02415     {
02416         if (!$iIndex) {
02417             $sFile = $this->oxarticles__oxicon->value;
02418         } else {
02419             $sFile = $this->{'oxarticles__oxpic' . $iIndex . '_ico'}->value;
02420         }
02421 
02422         $sFile = str_replace('nopic.jpg', 'nopic_ico.jpg', $sFile);
02423 
02424         //$sFile = $this->getConfig()->getPictureUrl( 'icon/' ). basename($sFile);
02425         $sFile = $this->getConfig()->getPictureUrl( $sFile );
02426 
02427         return $sFile;
02428     }
02429 
02435     public function getThumbnailUrl()
02436     {
02437         //return $this->getConfig()->getPictureUrl( $this->oxarticles__oxthumb->value );
02438         return $this->getConfig()->getPictureUrl( '0/' ) . basename($this->oxarticles__oxthumb->value);
02439     }
02440 
02448     public function getZoomPictureUrl($iIndex)
02449     {
02450         return $this->getConfig()->getPictureUrl( $this->{'oxarticles__oxzoom'.$iIndex}->value );
02451     }
02452 
02458     public function getFileUrl()
02459     {
02460         return $this->getConfig()->getPictureUrl( '0/' );
02461     }
02462 
02468     public function getPriceFromPrefix()
02469     {
02470         $sPricePrefics = '';
02471         if ( $this->_blIsRangePrice) {
02472             $sPricePrefics = oxLang::getInstance()->translateString('priceFrom').' ';
02473         }
02474 
02475         return $sPricePrefics;
02476     }
02477 
02486     protected function _saveArtLongDesc($iLang, $sValue)
02487     {
02488         $oDB = oxDb::getDb();
02489         $iLang = (int) $iLang;
02490         $sLangField = ($iLang > '0') ? '_'.$iLang : '';
02491         $sLongDesc = $oDB->quote($sValue);
02492         $sLongDescSQL = "insert into oxartextends (oxartextends.OXID, oxartextends.OXLONGDESC{$sLangField})
02493                        VALUES ('".$this->getId()."', {$sLongDesc})
02494                        ON DUPLICATE KEY update oxartextends.OXLONGDESC{$sLangField} = {$sLongDesc} ";
02495 
02496         $oDB->execute($sLongDescSQL);
02497     }
02498 
02514     protected function _removeInactiveVariants( $oVariants, $blStrict = false )
02515     {
02516         $myConfig = $this->getConfig();
02517         $this->_iVarStock = 0;
02518         $this->_blHasVariants = false;
02519         $now = time();
02520         $sSearchdate = date('Y-m-d H:i:s', $now);
02521         $this->_iVarStock = $this->oxarticles__oxvarstock->value;
02522 
02523         //checking if variant is active and stock status
02524         foreach (array_keys($oVariants->getArray()) as $key ) {
02525 
02526             $oVariant = $oVariants[$key];
02527             $this->_blHasVariants = true;
02528             //removing variants not in stock
02529             if ( $myConfig->getConfigParam( 'blUseStock' ) &&
02530                 $oVariant->oxarticles__oxstockflag->value != 1 && $oVariant->oxarticles__oxstockflag->value != 4 &&
02531                 ($oVariant->oxarticles__oxstockflag->value != 3 || $blStrict) && $oVariant->oxarticles__oxstock->value <= 0) {
02532                     unset($oVariants[$key]);
02533                     continue;
02534             }
02535 
02536             //removing non active variants
02537             if (!$oVariant->oxarticles__oxactive->value &&
02538                 !($oVariant->oxarticles__oxactivefrom->value < $sSearchdate &&
02539                 $oVariant->oxarticles__oxactiveto->value > $sSearchdate) ) {
02540                     unset($oVariants[$key]);
02541                     continue;
02542             }
02543         }
02544 
02545         //if we have variants then depending on config option the parent may be non buyable
02546         if (!$myConfig->getConfigParam( 'blVariantParentBuyable' ) && $this->_blHasVariants ) {
02547             $this->_blNotBuyableParent = true;
02548         }
02549 
02550         //if we have variants, but all variants are incative means article may be non buyable (depends on config option)
02551         if (!$myConfig->getConfigParam( 'blVariantParentBuyable' ) && $oVariants->count() == 0 && $this->_blHasVariants) {
02552             $this->_blNotBuyable = true;
02553         }
02554 
02555         return $oVariants;
02556     }
02557 
02561     protected function _skipSaveFields()
02562     {
02563         $myConfig = $this->getConfig();
02564 
02565         $this->_aSkipSaveFields = array();
02566 
02567         $this->_aSkipSaveFields[] = 'oxtimestamp';
02568         $this->_aSkipSaveFields[] = 'oxlongdesc';
02569         $this->_aSkipSaveFields[] = 'oxinsert';
02570 
02571         if ( !isset( $this->oxarticles__oxparentid->value) || $this->oxarticles__oxparentid->value == '') {
02572             $this->_aSkipSaveFields[] = 'oxparentid';
02573         }
02574 
02575     }
02576 
02586     protected function _mergeDiscounts( $aDiscounts, $aItemDiscounts)
02587     {
02588         foreach ( $aItemDiscounts as $sKey => $oDiscount ) {
02589             // add prices of the same discounts
02590             if ( array_key_exists ($sKey, $aDiscounts) ) {
02591                 $aDiscounts[$sKey]->dDiscount += $oDiscount->dDiscount;
02592             } else {
02593                 $aDiscounts[$sKey] = $oDiscount;
02594             }
02595         }
02596         return $aDiscounts;
02597     }
02598 
02604     protected function _getGroupPrice()
02605     {
02606         $dPrice = $this->oxarticles__oxprice->value;
02607 
02608         $oUser = $this->getArticleUser();
02609         if ( $oUser ) {
02610             if ( $oUser->inGroup( 'oxidpricea' ) ) {
02611                 $dPrice = $this->oxarticles__oxpricea->value;
02612             } elseif ( $oUser->inGroup( 'oxidpriceb' ) ) {
02613                 $dPrice = $this->oxarticles__oxpriceb->value;
02614             } elseif ( $oUser->inGroup( 'oxidpricec' ) ) {
02615                 $dPrice = $this->oxarticles__oxpricec->value;
02616             }
02617         }
02618 
02619         // #1437/1436C - added config option, and check for zero A,B,C price values
02620         if ( $this->getConfig()->getConfigParam( 'blOverrideZeroABCPrices' ) && (double) $dPrice == 0 ) {
02621             $dPrice = $this->oxarticles__oxprice->value;
02622         }
02623 
02624         return $dPrice;
02625     }
02626 
02635     protected function _getAmountPrice($dAmount = 1)
02636     {
02637         $myConfig = $this->getConfig();
02638 
02639         startProfile( "_getAmountPrice" );
02640 
02641         $dPrice = $this->_getGroupPrice();
02642         $oAmtPrices = $this->_getAmountPriceList();
02643         foreach ($oAmtPrices as $oAmPrice) {
02644             if ($oAmPrice->oxprice2article__oxamount->value <= $dAmount
02645                     && $dAmount <= $oAmPrice->oxprice2article__oxamountto->value
02646                     && $dPrice > $oAmPrice->oxprice2article__oxaddabs->value ) {
02647                 $dPrice = $oAmPrice->oxprice2article__oxaddabs->value;
02648             }
02649         }
02650 
02651         stopProfile( "_getAmountPrice" );
02652         return $dPrice;
02653     }
02654 
02663     protected function _modifySelectListPrice( &$dPrice, $aChosenList = null )
02664     {
02665         $myConfig = $this->getConfig();
02666         // #690
02667         if ( $myConfig->getConfigParam( 'bl_perfLoadSelectLists' ) && $myConfig->getConfigParam( 'bl_perfUseSelectlistPrice' ) ) {
02668 
02669             $aSelLists = $this->getSelectLists();
02670             foreach ( $aSelLists as $key => $aSel) {
02671                 if ( isset( $aChosenList[$key]) && isset($aSel[$aChosenList[$key]] ) ) {
02672                     $oSel = $aSel[$aChosenList[$key]];
02673                     if ( $oSel->priceUnit =='abs' ) {
02674                         $dPrice += $oSel->price;
02675                     } elseif ( $oSel->priceUnit =='%' ) {
02676                         $dPrice += oxPrice::percent( $dPrice, $oSel->price );
02677                     }
02678                 }
02679             }
02680         }
02681         return $dPrice;
02682     }
02683 
02684 
02692     protected function _fillAmountPriceList($oAmPriceList)
02693     {
02694         $myConfig = $this->getConfig();
02695         $myUtils  = oxUtils::getInstance();
02696 
02697         //modifying price
02698         $oCur = $myConfig->getActShopCurrencyObject();
02699 
02700         $oUser = $this->getArticleUser();
02701 
02702         $aDiscountList = oxDiscountList::getInstance()->getArticleDiscounts($this, $oUser );
02703 
02704         $oLowestPrice = null;
02705 
02706         $dBasePrice = $this->_getGroupPrice();
02707         $oLang = oxLang::getInstance();
02708 
02709         $dArticleVat = null;
02710         if ( !$myConfig->getConfigParam( 'bl_perfCalcVatOnlyForBasketOrder' ) ) {
02711             $dArticleVat = $this->getArticleVat();
02712         }
02713 
02714         // trying to find lowest price value
02715         foreach ($oAmPriceList as $sId => $oItem) {
02716             $oItemPrice = oxNew( 'oxprice' );
02717             if ( $oItem->oxprice2article__oxaddabs->value) {
02718                 $oItemPrice->setPrice( $oItem->oxprice2article__oxaddabs->value );
02719                 $this->_applyDiscounts( $oItemPrice, $aDiscountList );
02720                 $this->_applyCurrency( $oItemPrice, $oCur );
02721             } else {
02722                 $oItemPrice->setPrice( $dBasePrice );
02723                 $oItemPrice->subtractPercent( $oItem->oxprice2article__oxaddperc->value );
02724             }
02725 
02726             if (isset($dArticleVat)) {
02727                 $this->_applyVAT($oItemPrice, $dArticleVat);
02728             }
02729 
02730             if (!$oLowestPrice) {
02731                 $oLowestPrice = $oItemPrice;
02732             } elseif ($oLowestPrice->getBruttoPrice() > $oItemPrice->getBruttoPrice()) {
02733                 $oLowestPrice = $oItemPrice;
02734             }
02735 
02736             $oAmPriceList[$sId]->oxprice2article__oxaddabs = new oxField( $oLang->formatCurrency( $myUtils->fRound( $oItemPrice->getBruttoPrice(), $oCur ) ) );
02737             $oAmPriceList[$sId]->fnetprice  = $oLang->formatCurrency( $myUtils->fRound($oItemPrice->getNettoPrice(), $oCur ) );
02738             $oAmPriceList[$sId]->fbrutprice = $oLang->formatCurrency( $myUtils->fRound($oItemPrice->getBruttoPrice(), $oCur ) );
02739         }
02740 
02741         $this->_dAmountPrice = $myUtils->fRound( $oLowestPrice->getBruttoPrice() );
02742         return $oAmPriceList;
02743     }
02744 
02750     protected function _getVariantsIds()
02751     {
02752         $aSelect = array();
02753         $oRs = oxDb::getDb(true)->execute( "select oxid from oxarticles where oxparentid = '".$this->oxarticles__oxid->value."' " );
02754         if ( $oRs != false && $oRs->recordCount() > 0 ) {
02755             while (!$oRs->EOF) {
02756                 $aSelect[] = $oRs->fields['oxid'];
02757                 $oRs->moveNext();
02758             }
02759         }
02760         return $aSelect;
02761     }
02762 
02768     public function getArticleVat()
02769     {
02770         if (!isset($this->_dArticleVat)) {
02771             $this->_dArticleVat = oxVatSelector::getInstance()->getArticleVat( $this );
02772         }
02773         return $this->_dArticleVat;
02774     }
02775 
02784     protected function _applyVAT( oxPrice $oPrice, $dVat )
02785     {
02786         startProfile(__FUNCTION__);
02787         $oPrice->setVAT( $dVat );
02788         if ( ($dVat = oxVatSelector::getInstance()->getArticleUserVat($this)) !== false ) {
02789             $oPrice->setUserVat( $dVat );
02790         }
02791         stopProfile(__FUNCTION__);
02792     }
02793 
02799     public function applyVats( oxPrice $oPrice )
02800     {
02801         $this->_applyVAT($oPrice, 
02802                          $this->getArticleVat()
02803                         );
02804     }
02805 
02814     protected function _applyDiscounts( $oPrice, $aDiscounts )
02815     {
02816         reset( $aDiscounts );
02817         while ( list( , $oDiscount ) = each( $aDiscounts ) ) {
02818             $oDiscount->applyDiscount( $oPrice );
02819         }
02820     }
02821 
02830     protected function _applyCurrency(oxPrice $oPrice, $oCur = null )
02831     {
02832         if ( !$oCur ) {
02833             $oCur = $this->getConfig()->getActShopCurrencyObject();
02834         }
02835 
02836         $oPrice->multiply($oCur->rate);
02837     }
02838 
02847     protected function _getIcon()
02848     {
02849         // #1479/1179M - Article icon automatic generation
02850         //if set to do not generate.
02851         $myConfig = $this->getConfig();
02852 
02853         if (!$myConfig->getConfigParam( 'blAutoIcons' ) ) {
02854             if ($this->oxarticles__oxicon->value) {
02855                 return basename($this->oxarticles__oxicon->value);
02856             } else {
02857                 $sQ = "UPDATE oxarticles SET oxicon = 'nopic_ico.jpg' WHERE oxid = '".$this->getId()."'";
02858                 oxDb::getDb()->execute($sQ);
02859                 return 'nopic_ico.jpg';
02860             }
02861         }
02862 
02863         // if set to generate and icon already exist
02864         if ( $this->oxarticles__oxicon->value && strpos( $this->oxarticles__oxicon->value, 'nopic_ico.jpg') === false ) {
02865             return basename($this->oxarticles__oxicon->value);
02866         }
02867 
02868         //we don't have an icon yet so lets make one
02869         if ($this->oxarticles__oxthumb->value && strpos( $this->oxarticles__oxthumb->value, 'nopic.jpg') === false &&  function_exists('gd_info')) {
02870 
02871             $sSourceFile = $this->oxarticles__oxthumb->value;
02872             $sTargetFile = str_replace('_th', '_ico', $sSourceFile);
02873 
02874             if ($sSourceFile == $sTargetFile) {
02875                 $sPattern = '(\.[a-z0-9]*$)';
02876                 $sTargetFile = eregi_replace($sPattern, '_ico\\1', $sTargetFile);
02877             }
02878 
02879             $sTarget = $myConfig->getAbsDynImageDir().'/icon/'. basename($sTargetFile);
02880             $sSource = $myConfig->getAbsDynImageDir().'/0/'. basename($sSourceFile);
02881 
02882             if (!$myConfig->getConfigParam( 'sIconsize' ) ) {
02883                 $myConfig->setConfigParam( 'sIconsize', '56*42' );
02884             }
02885 
02886             $aSize = explode('*', $myConfig->getConfigParam( 'sIconsize' ) );
02887             $iX = $aSize[0];
02888             $iY = $aSize[1];
02889 
02890             oxUtilspic::getInstance()->resizeImage( $sSource, $sTarget, $iX, $iY );
02891 
02892             $sResult = $sTargetFile;
02893         } else {
02894             $sResult = 'nopic_ico.jpg';
02895         }
02896 
02897         //saving new icon
02898         $sIconFile = basename($sResult);
02899 
02900         $sQ = "UPDATE oxarticles SET oxicon = '$sIconFile' WHERE oxid = '".$this->getId()."'";
02901 
02902         oxDb::getDb()->execute($sQ);
02903 
02904         return $sIconFile;
02905     }
02906 
02907 
02916     protected function _getAttribsString(&$sAttribs, &$iCnt)
02917     {
02918         // we do not use lists here as we dont need this overhead right now
02919         $oDB = oxDb::getDb(true);
02920         $sSelect =  'select oxattrid from oxobject2attribute where oxobject2attribute.oxobjectid="'.$this->oxarticles__oxid->value.'" ';
02921         $sAttribs = '';
02922         $blSep = false;
02923         $rs = $oDB->execute( $sSelect);
02924         $iCnt = 0;
02925         if ($rs != false && $rs->recordCount() > 0) {
02926             while (!$rs->EOF) {
02927                 if ( $blSep) {
02928                     $sAttribs .= ' or ';
02929                 }
02930                 $sAttribs .= 't1.oxattrid = "'.$rs->fields['oxattrid'].'" ';
02931                 $blSep = true;
02932                 $iCnt++;
02933                 $rs->moveNext();
02934             }
02935         }
02936     }
02937 
02946     protected function _getSimList($sAttribs, $iCnt)
02947     {
02948         $myConfig = $this->getConfig();
02949         $oDB      = oxDb::getDb(true);
02950 
02951         // #523A
02952         $iAttrPercent = $myConfig->getConfigParam( 'iAttributesPercent' )/100;
02953         // 70% same attributes
02954         if ( !$iAttrPercent || $iAttrPercent < 0 || $iAttrPercent > 1) {
02955             $iAttrPercent = 0.70;
02956         }
02957         $iHitMin = round( $iCnt * $iAttrPercent + 0.5);
02958 
02959         // we do not use lists here as we dont need this overhead right now
02960         $aList= array();
02961         $sSelect =  "select oxobjectid, count(*) as cnt from oxobject2attribute as t1 where
02962                     ( $sAttribs )
02963                     and t1.oxobjectid != '".$this->oxarticles__oxid->value."'
02964                     group by t1.oxobjectid having count(*) >= $iHitMin ";
02965 
02966         $rs = $oDB->selectLimit( $sSelect, 20, 0);
02967         if ($rs != false && $rs->recordCount() > 0) {
02968             while (!$rs->EOF) {
02969                 $oTemp = new stdClass();    // #663
02970                 $oTemp->cnt = $rs->fields['cnt'];
02971                 $oTemp->id  = $rs->fields['oxobjectid'];
02972                 $aList[] = $oTemp;
02973                 $rs->moveNext();
02974             }
02975         }
02976         return $aList;
02977     }
02978 
02987     protected function _generateSimListSearchStr($sArticleTable, $aList)
02988     {
02989         $myConfig = $this->getConfig();
02990         $sFieldList = $this->getSelectFields();
02991         $sSearch = "select $sFieldList from $sArticleTable where ".$this->getSqlActiveSnippet()."  and $sArticleTable.oxissearch = 1 and $sArticleTable.oxid in ( ";
02992         $blSep = false;
02993         $iCnt = 0;
02994         foreach ( $aList as $oTemp) {
02995             if ( $blSep) {
02996                 $sSearch .= ',';
02997             }
02998             $sSearch .= "'".$oTemp->id."'";
02999             $blSep = true;
03000             if ( $iCnt >= $myConfig->getConfigParam( 'iNrofSimilarArticles' ) ) {
03001                 break;
03002             }
03003             $iCnt++;
03004         }
03005 
03006         //#1741T
03007         //$sSearch .= ") and $sArticleTable.oxparentid = '' ";
03008         $sSearch .= ') ';
03009 
03010         // #524A -- randomizing articles in attribute list
03011         $sSearch .= ' order by rand() ';
03012 
03013         return $sSearch;
03014     }
03015 
03024     protected function _generateSearchStr($sOXID, $blSearchPriceCat = false )
03025     {
03026         $sCatView = getViewName( 'oxcategories' );
03027         $sO2CView = getViewName( 'oxobject2category' );
03028 
03029         // we do not use lists here as we dont need this overhead right now
03030         if ( !$blSearchPriceCat ) {
03031             $sSelect  = "select {$sCatView}.* from {$sO2CView} as oxobject2category left join {$sCatView} on
03032                          {$sCatView}.oxid = oxobject2category.oxcatnid
03033                          where oxobject2category.oxobjectid='{$sOXID}' and {$sCatView}.oxid is not null ";
03034         } else {
03035             $sSelect  = "select {$sCatView}.* from {$sCatView} where
03036                          '{$this->oxarticles__oxprice->value}' >= {$sCatView}.oxpricefrom and
03037                          '{$this->oxarticles__oxprice->value}' <= {$sCatView}.oxpriceto ";
03038         }
03039         return $sSelect;
03040     }
03041 
03047     protected function _generateSearchStrForCustomerBought()
03048     {
03049         $sArtTable = $this->_getObjectViewName( 'oxarticles' );
03050         $sOrderArtTable = getViewName( 'oxorderarticles' );
03051 
03052         // fetching filter params
03053         $sIn = " '{$this->oxarticles__oxid->value}' ";
03054         if ( $this->oxarticles__oxparentid->value ) {
03055 
03056             // adding article parent
03057             $sIn .= ", '{$this->oxarticles__oxparentid->value}' ";
03058             $sParentIdForVariants = $this->oxarticles__oxparentid->value;
03059 
03060         } else {
03061             $sParentIdForVariants = $this->getId();
03062         }
03063 
03064         // adding variants
03065         $oRs = oxDb::getDb(true)->execute( "select oxid from {$sArtTable} where oxparentid = '{$sParentIdForVariants}' and oxid != '{$this->oxarticles__oxid->value}' " );
03066         if ( $oRs != false && $oRs->recordCount() > 0) {
03067             while ( !$oRs->EOF ) {
03068                 $sIn .= ", '".current( $oRs->fields )."' ";
03069                 $oRs->moveNext();
03070             }
03071         }
03072 
03073         $iLimit = (int) $this->getConfig()->getConfigParam( 'iNrofCustomerWhoArticles' );
03074         $iLimit = $iLimit?( $iLimit * 10 ): 50;
03075 
03076         // building sql (optimized)
03077         $sQ = "select distinct {$sArtTable}.* from (
03078                    select d.oxorderid as suborderid from {$sOrderArtTable} as d use index ( oxartid ) where d.oxartid in ( {$sIn} ) limit {$iLimit}
03079                ) as suborder
03080                left join {$sOrderArtTable} force index ( oxorderid ) on suborder.suborderid = {$sOrderArtTable}.oxorderid
03081                left join {$sArtTable} on {$sArtTable}.oxid = {$sOrderArtTable}.oxartid
03082                where {$sArtTable}.oxid not in ( {$sIn} )
03083                and ( {$sArtTable}.oxissearch = 1 or {$sArtTable}.oxparentid <> '' ) and ".$this->getSqlActiveSnippet();
03084 
03085         /* non optimized, but could be used if index forcing is not supported
03086         // building sql
03087         $sQ = "select distinct {$sArtTable}.* from {$sOrderArtTable}, {$sArtTable} where {$sOrderArtTable}.oxorderid in (
03088                    select {$sOrderArtTable}.oxorderid from {$sOrderArtTable} where {$sOrderArtTable}.oxartid in ( {$sIn} )
03089                ) and {$sArtTable}.oxid = {$sOrderArtTable}.oxartid and {$sArtTable}.oxid not in ( {$sIn} )
03090                and ( {$sArtTable}.oxissearch = 1 or {$sArtTable}.oxparentid <> '' )
03091                and ".$this->getSqlActiveSnippet();
03092         */
03093 
03094         return $sQ;
03095     }
03096 
03106     protected function _generateSelectCatStr($sOXID, $sCatId, $dPriceFromTo = false)
03107     {
03108         $sCategoryView = getViewName('oxcategories');
03109         $sO2CView = getViewName('oxobject2category');
03110         $sLangPrefix = (($this->getLanguage())?'_'.$this->getLanguage():'');
03111         if (!$dPriceFromTo) {
03112             $sSelect  = "select oxobject2category.oxcatnid from $sO2CView as oxobject2category ";
03113             $sSelect .= "left join $sCategoryView as oxcategories on oxcategories.oxid = oxobject2category.oxcatnid ";
03114             $sSelect .= "where oxobject2category.oxcatnid='$sCatId' and oxobject2category.oxobjectid='$sOXID' ";
03115             $sSelect .= "and oxcategories.oxactive$sLangPrefix = 1 order by oxobject2category.oxtime ";
03116         } else {
03117             $sSelect  = "select oxcategories.oxid from $sCategoryView as oxcategories where ";
03118             $sSelect .= "oxcategories.oxid='$sCatId' and '$dPriceFromTo' >= oxcategories.oxpricefrom and ";
03119             $sSelect .= "'$dPriceFromTo' <= oxcategories.oxpriceto ";
03120         }
03121         return $sSelect;
03122     }
03123 
03129     protected function _getAmountPriceList()
03130     {
03131         if ($this->_oAmountPriceList) {
03132             return $this->_oAmountPriceList;
03133         }
03134 
03135         $myConfig = $this->getConfig();
03136 
03137         $sArtID  = $this->getId();
03138 
03139         // #1690C - Scale prices and variants
03140         if ( !$this->isAdmin() && $myConfig->getConfigParam( 'blVariantInheritAmountPrice' ) && $this->oxarticles__oxparentid->value ) {
03141             $sArtID = $this->oxarticles__oxparentid->value;
03142         }
03143 
03144         // echo( "TODO replace oxlist usage here _collectAmPriceList".PHP_EOL);
03145         $sArtID = mysql_real_escape_string($sArtID);
03146 
03147         //collecting assigned to article amount-price list
03148         $oAmPriceList = oxNew( 'oxlist');
03149         $oAmPriceList->init('oxbase', 'oxprice2article');
03150 
03151         $sShopID = $myConfig->getShopID();
03152         if ( $myConfig->getConfigParam( 'blMallInterchangeArticles' ) ) {
03153             $sShopSelect = '1';
03154         } else {
03155             $sShopSelect = " oxshopid =  '$sShopID' ";
03156         }
03157 
03158         $oAmPriceList->selectString( "select * from oxprice2article where oxartid = '$sArtID' and $sShopSelect order by oxamount ");
03159 
03160         // prepare abs prices if currently having percentages
03161         $oBasePrice = $this->_getGroupPrice();
03162         foreach ($oAmPriceList as $oAmPrice) {
03163             if ($oAmPrice->oxprice2article__oxaddperc->value) {
03164                 $oAmPrice->oxprice2article__oxaddabs = new oxField(oxPrice::percent( $oBasePrice, 100 - $oAmPrice->oxprice2article__oxaddperc->value ), oxField::T_RAW);
03165             }
03166         }
03167 
03168         $this->_oAmountPriceList = $oAmPriceList;
03169         return $oAmPriceList;
03170     }
03171 
03179     protected function _isFieldEmpty($sFieldName)
03180     {
03181         $mValue = $this->$sFieldName->value;
03182 
03183         if (is_null($mValue)) {
03184             return true;
03185         }
03186 
03187         if ($mValue === '') {
03188             return true;
03189         }
03190 
03191         $aDoubleCopyFields = array('oxarticles__oxprice',
03192                                        'oxarticles__oxvat');
03193 
03194         if (!$mValue && in_array($sFieldName, $aDoubleCopyFields))
03195             return true;
03196 
03197 
03198         if (!strcmp($mValue, '0000-00-00 00:00:00') || !strcmp($mValue, '0000-00-00')) {
03199             return true;
03200         }
03201 
03202         $sFieldName = strtolower($sFieldName);
03203 
03204         if ($mValue == "nopic_ico.jpg" && $sFieldName == 'oxarticles__oxicon') {
03205             return true;
03206         }
03207 
03208         if ($mValue == "nopic.jpg" && ($sFieldName == 'oxarticles__oxthumb' || substr($sFieldName, 0, 17) == 'oxarticles__oxpic' || substr($sFieldName, 0, 18) == 'oxarticles__oxzoom')) {
03209             return true;
03210         }
03211 
03212         return false;
03213     }
03214 
03222     protected function _assignParentFieldValue($sFieldName)
03223     {
03224         if (!($oParentArticle = $this->_getParentAricle())) {
03225             return;
03226         }
03227 
03228         $sCopyFieldName = $this->_getFieldLongName($sFieldName);
03229 
03230         // assigning only theese which parent article has
03231         if ( $oParentArticle->$sCopyFieldName != null ) {
03232 
03233             // only overwrite database values
03234             if ( substr( $sCopyFieldName, 0, 12) != 'oxarticles__') {
03235                 continue;
03236             }
03237 
03238             //do not copy certain fields
03239             $aNonCopyFields = array('oxarticles__oxinsert',
03240                                     'oxarticles__oxtimestamp',
03241                                     'oxarticles__oxnid',
03242                                     'oxarticles__oxid',
03243                                     'oxarticles__oxparentid');
03244 
03245             $aCopyParentField = array('oxarticles__oxnonmaterial',
03246                                       'oxarticles__oxfreeshipping',
03247                                       'oxarticles__oxremindactive');
03248 
03249             if (in_array($sCopyFieldName, $aNonCopyFields)) {
03250                 return;
03251             }
03252 
03253 
03254 
03255             //do not copy parent data for icons in case we have (need) own variant icon (in case variant thumbnail exists)
03256             if ($sFieldName == "oxicon" && !$this->_isFieldEmpty("oxarticles__oxthumb") && $this->oxarticles__oxthumb->value != $oParentArticle->oxarticles__oxthumb->value && $this->getConfig()->getConfigParam( 'blAutoIcons' ) ) {
03257                 return ;
03258             }
03259 
03260             //COPY THE VALUE
03261             //replaced the code bellow with this two liner
03262             //T2009-01-12
03263             if ($this->_isFieldEmpty($sCopyFieldName) || in_array($sCopyFieldName, $aCopyParentField)) {
03264                 $this->$sCopyFieldName = clone $oParentArticle->$sCopyFieldName;
03265             }
03266 
03267 
03268             /*
03269             //#1101S empty image fields (without nopic.jpg, nopic_ico.jpg) should be copied from parent too
03270             if ( $this->$sCopyFieldName->value == 'nopic.jpg' || $this->$sCopyFieldName->value == 'nopic_ico.jpg' || ((stristr($sCopyFieldName, '_oxthumb') || stristr($sCopyFieldName, '_oxicon') || stristr($sCopyFieldName, '_oxpic') || stristr($sCopyFieldName, '_oxzoom') ) && $this->$sCopyFieldName->value == '')) {
03271                 // pictures
03272                 if ( $this->_blLoadParentData && $this->isAdmin() ) {
03273                     $this->$sCopyFieldName = clone $oParentArticle->$sCopyFieldName;
03274                 } else {
03275                     $aFile = explode( '/', $oParentArticle->$sCopyFieldName->value);
03276                     $this->$sCopyFieldName->setValue(basename);
03277                 }
03278             } elseif ( $this->$sCopyFieldName->value == '' ||
03279                     $this->$sCopyFieldName->value == '0000-00-00 00:00:00' ||
03280                     $this->$sCopyFieldName->value == '0000-00-00' ||
03281                     ( in_array($sCopyFieldName, $aDoubleCopyFields) && $this->$sCopyFieldName->value == 0)
03282                    ) {
03283                 $this->$sCopyFieldName = clone $oParentArticle->$sCopyFieldName;
03284             }
03285 
03286             //another fields which should be copied from parent if empty and not covered by above condition
03287             $aCopyParentField = array('oxarticles__oxnonmaterial',
03288                                       'oxarticles__oxfreeshipping',
03289                                       'oxarticles__oxremindactive');
03290             if (!$this->$sCopyFieldName->value && in_array($sCopyFieldName, $aCopyParentField)) {
03291                 $this->$sCopyFieldName = clone $oParentArticle->$sCopyFieldName;
03292             }*/
03293         }
03294     }
03295 
03301     protected function _getParentAricle()
03302     {
03303         $sParentId = $this->oxarticles__oxparentid->value;
03304         if (!$sParentId) {
03305             return null;
03306         }
03307         if (isset(self::$_aLoadedParents[$sParentId])) {
03308             return self::$_aLoadedParents[$sParentId];
03309         } else {
03310             $oParentArticle = oxNew( 'oxarticle' );
03311             $oParentArticle->_blSkipAbPrice = true;
03312             $oParentArticle->_blLoadPrice = false;
03313             $oParentArticle->_blLoadVariants = false;
03314             $oParentArticle->load( $sParentId);
03315             self::$_aLoadedParents[$sParentId] = $oParentArticle;
03316             return $oParentArticle;
03317         }
03318     }
03319 
03325     protected function _assignParentFieldValues()
03326     {   startProfile('articleAssignParentInternal');
03327         if ( $this->oxarticles__oxparentid->value) {
03328             // yes, we are in fact a variant
03329             if ( !$this->isAdmin() || ($this->_blLoadParentData && $this->isAdmin() ) ) {
03330                 foreach ($this->_aFieldNames as $sFieldName => $sVal) {
03331                     $this->_assignParentFieldValue($sFieldName);
03332                 }
03333 
03334                 //assing long description
03335                 $oParentArticle = $this->_getParentAricle();
03336                 if ( !$this->oxarticles__oxlongdesc->value ) {
03337                     $this->oxarticles__oxlongdesc = $oParentArticle->oxarticles__oxlongdesc;
03338                 }
03339             }
03340         } elseif ( $this->oxarticles__oxid->value ) {
03341             // I am not a variant but I might have some
03342             //$this->_oVariantList = $this->getSimpleVariants();
03343             startProfile("loadVariants");
03344             $this->_oVariantList = $this->getVariants();
03345             stopProfile("loadVariants");
03346             // #1650M - article title with <br> tag
03347             // htmlspecialchars parses only 5 characters, so i have stiped out '<' and '>'
03348             /*
03349             if ( !$this->isAdmin() ) {
03350                 $this->oxarticles__oxtitle->setValue(str_replace(array('&', "'", '"'), array('&amp;', '&#039;', '&quot;'), $this->oxarticles__oxtitle->value));
03351             }*/
03352         }
03353         stopProfile('articleAssignParentInternal');
03354 
03355     }
03356 
03362     protected function _assignNotBuyableParent()
03363     {
03364         if ( !$this->getConfig()->getConfigParam( 'blVariantParentBuyable' ) &&
03365              ($this->_blHasVariants || $this->oxarticles__oxvarstock->value || $this->oxarticles__oxvarcount->value )) {
03366             $this->_blNotBuyableParent = true;
03367 
03368         }
03369     }
03370 
03376     protected function _assignPictureValues()
03377     {
03378         $myConfig = $this->getConfig();
03379         $this->oxarticles__oxicon = new oxField($this->_getIcon());
03380 
03381         // picture isset($this->_aFieldNames["thumb"]) && re handling
03382         $sNoPic     = 'nopic.jpg';
03383         $sNoPicIcon = 'nopic_ico.jpg';
03384 
03385         if ( isset($this->_aFieldNames["oxthumb"]) && !$this->oxarticles__oxthumb->value) {
03386             $this->oxarticles__oxthumb = new oxField($sNoPic);
03387         }
03388         /*
03389         if( isset($this->_aFieldNames["oxicon"]) && !isset($this->oxarticles__oxicon->value))
03390             $this->oxarticles__oxicon  = new oxField($sNoPicIcon);
03391         */
03392 
03393         $iPicCount = $myConfig->getConfigParam( 'iPicCount' );
03394         for ( $i=1; $i<= $iPicCount; $i++ ) {
03395             if ( isset($this->_aFieldNames["oxpic".$i]) &&  !$this->{'oxarticles__oxpic'.$i}->value ) {
03396                 $this->{'oxarticles__oxpic'.$i} = new oxField($sNoPic);
03397             }
03398         }
03399 
03400         $iZoomPicCount = $myConfig->getConfigParam( 'iZoomPicCount' );
03401         for ( $i=1; $i<= $iZoomPicCount; $i++ ) {
03402             if ( isset($this->_aFieldNames["oxzoom".$i]) &&  !$this->{'oxarticles__oxzoom'.$i}->value) {
03403                 $this->{'oxarticles__oxzoom'.$i} = new oxField($sNoPic);
03404             }
03405         }
03406 
03407         if ( !$this->isAdmin() ) {
03408             // add directories
03409             if ( isset($this->_aFieldNames["oxthumb"])) {
03410                 $this->oxarticles__oxthumb->setValue('0/'.basename($this->oxarticles__oxthumb->value));
03411             }
03412             if ( isset($this->_aFieldNames["oxicon"])) {
03413                 $this->oxarticles__oxicon = new oxField('icon/'.basename($this->oxarticles__oxicon->value));
03414             }
03415 
03416             $myUtilsPic = oxUtilsPic::getInstance();
03417             for ( $i=1; $i<= $iPicCount; $i++ ) {
03418                 $sFieldName = 'oxarticles__oxpic'.$i;
03419                 if ( isset($this->_aFieldNames["oxpic".$i])) {
03420                     $sIconFieldName = 'oxarticles__oxpic'.$i.'_ico';
03421                     $this->$sIconFieldName = new oxField($i.'/'.basename($myUtilsPic->iconName($this->$sFieldName->value)));
03422                     $this->$sFieldName     = new oxField($i.'/'.basename($this->$sFieldName->value));
03423                 }
03424             }
03425             for ( $i=1; $i<= $iZoomPicCount; $i++ ) {
03426                 if ( isset($this->_aFieldNames["oxzoom".$i])) {
03427                     $this->{'oxarticles__oxzoom'.$i} = new oxField('z'.$i.'/'.basename($this->{'oxarticles__oxzoom'.$i}->value));
03428                 }
03429             }
03430         }
03431 
03432     }
03433 
03439     protected function _assignStock()
03440     {
03441         $myConfig = $this->getConfig();
03442         // -----------------------------------
03443         // stock
03444         // -----------------------------------
03445 
03446         // #1125 A. must round (using floor()) value taken from database and cast to int
03447         if (!$myConfig->getConfigParam( 'blAllowUnevenAmounts' ) && !$this->isAdmin() ) {
03448             $this->oxarticles__oxstock = new oxField((int) floor($this->oxarticles__oxstock->value));
03449         }
03450         //GREEN light
03451         $this->_iStockStatus = 0;
03452 
03453         // if we have flag /*1 or*/ 4 - we show always green light
03454         if ( $myConfig->getConfigParam( 'blUseStock' ) && /*$this->oxarticles__oxstockflag->value != 1 && */ $this->oxarticles__oxstockflag->value != 4) {
03455             //ORANGE light
03456             $iStock = $this->oxarticles__oxstock->value;
03457 
03458             if ($this->_blNotBuyableParent) {
03459                 $iStock = $this->oxarticles__oxvarstock->value;
03460             }
03461 
03462 
03463             if ( $iStock <= $myConfig->getConfigParam( 'sStockWarningLimit' ) && $iStock > 0) {
03464                 $this->_iStockStatus = 1;
03465             }
03466 
03467             //RED light
03468             if ($iStock <= 0) {
03469                 $this->_iStockStatus = -1;
03470             }
03471         }
03472 
03473 
03474         // stock
03475         if ( $myConfig->getConfigParam( 'blUseStock' ) && $this->oxarticles__oxstock->value <= 0 && ($this->oxarticles__oxstockflag->value == 3 || $this->oxarticles__oxstockflag->value == 2)) {
03476             $this->_blNotBuyable = true;
03477         }
03478 
03479         //exceptional handling for variant parent stock:
03480         if ($this->_blNotBuyable && $this->_iVarStock) {
03481             $this->_blNotBuyable = false;
03482             //but then at least setting notBuaybleParent to true
03483             $this->_blNotBuyableParent = true;
03484         }
03485 
03486         //special treatment for lists when blVariantParentBuyable config option is set to false
03487         //then we just hide "to basket" button.
03488         //if variants are not loaded in the list and this article has variants and parent is not buyable then this article is not buyable
03489         if ( !$myConfig->getConfigParam( 'blVariantParentBuyable' ) && !$myConfig->getConfigParam( 'blLoadVariants' ) && $this->oxarticles__oxvarstock->value) {
03490             $this->_blNotBuyable = true;
03491         }
03492 
03493         //setting to non buyable when variant list is empty (for example not loaded or inactive) and $this is non buyable parent
03494         if ($this->_blNotBuyableParent && count($this->_oVariantList) == 0) {
03495             $this->_blNotBuyable = true;
03496         }
03497     }
03498 
03504     protected function _assignPrices()
03505     {
03506         $myConfig = $this->getConfig();
03507 
03508         // Performance
03509         if ( !$myConfig->getConfigParam( 'bl_perfLoadPrice' ) || !$this->_blLoadPrice ) {
03510             return;
03511         }
03512 
03513 
03514         // compute price
03515         $dPrice = $this->getPrice()->getBruttoPrice();
03516 
03517         $oCur = $myConfig->getActShopCurrencyObject();
03518         //price per unit handling
03519         if ((double) $this->oxarticles__oxunitquantity->value && $this->oxarticles__oxunitname->value) {
03520             $this->_fPricePerUnit = oxLang::getInstance()->formatCurrency($dPrice / (double) $this->oxarticles__oxunitquantity->value, $oCur);
03521         }
03522 
03523 
03524         //getting min and max prices of variants
03525         $this->_applyRangePrice();
03526     }
03527 
03533     protected function _assignPersistentParam()
03534     {
03535         // Persistent Parameter Handling
03536         $aPersParam     = oxSession::getVar( 'persparam');
03537         if ( isset( $aPersParam) && isset( $aPersParam[$this->getId()])) {
03538             $this->_aPersistParam = $aPersParam[$this->getId()];
03539         }
03540     }
03541 
03547     protected function _assignDynImageDir()
03548     {
03549         $myConfig = $this->getConfig();
03550 
03551         $sThisShop = $this->oxarticles__oxshopid->value;
03552 
03553         $this->_sDynImageDir   = $myConfig->getPictureUrl( null, false );
03554         $this->dabsimagedir    = $myConfig->getPictureDir( false ); //$sThisShop
03555         $this->nossl_dimagedir = $myConfig->getPictureUrl( null, false, false, null, $sThisShop ); //$sThisShop
03556         $this->ssl_dimagedir   = $myConfig->getPictureUrl( null, false, true, null, $sThisShop ); //$sThisShop
03557     }
03558 
03564     protected function _assignComparisonListFlag()
03565     {
03566         // #657 add a flag if article is on comparisonlist
03567 
03568         $aItems = oxConfig::getParameter('aFiltcompproducts');
03569         if ( isset( $aItems[$this->getId()])) {
03570             $this->_blIsOnComparisonList = true;
03571         }
03572     }
03573 
03579     protected function _assignAttributes()
03580     {
03581         //#1029T load attributes
03582         //#1078S removed check for module "Produktvergleich"
03583         if ( $this->getConfig()->getConfigParam( 'bl_perfLoadAttributes' ) ) {
03584             $this->getAttributes();
03585         }
03586     }
03587 
03588 
03594     protected function _assignLinks()
03595     {
03596         $myConfig = $this->getConfig();
03597 
03598         // and assign special article values
03599         $sURL       = $myConfig->getShopHomeURL();
03600         $sActCat    = oxConfig::getParameter( 'cnid' );
03601         $sActClass  = oxConfig::getParameter( 'cl' );
03602         $sTPL       = basename( oxConfig::getParameter( 'tpl' ) );
03603 
03604         // override some classes as these should never showup
03605         if ( $sActClass == 'thankyou') {
03606             $sActClass = 'basket';
03607         }
03608 
03609         $sCnid = '';
03610 
03611         // this is not very correct
03612         if ($sActCat) {
03613             $sCnid = '&amp;cnid='.$sActCat;
03614         }
03615 
03616         $this->_sDetailLink     = $this->getLink();
03617 
03618         // mallchange to make sure
03619         // MALL OFF
03620         /*if( $myConfig->isMall() && !$this->InShop())
03621             $this->oxdetaillink .= "&amp;cshp=".$this->oxarticles__oxshopid->value;*/
03622 
03623         $this->_sMoreDetailLink = $sURL. 'cl=moredetails&amp;cnid='.$sActCat.'&amp;anid='.$this->getId();
03624 
03625         if ( oxUtils::getInstance()->isSearchEngine() ) {
03626             $this->_sToBasketLink = $this->_sDetailLink;
03627         } else {
03628             $this->_sToBasketLink = $sURL. 'cl='.$sActClass.'&amp;fnc=tobasket'.$sCnid.'&amp;aid='.$this->getId().'&amp;anid='.$this->getId();
03629         }
03630 
03631 
03632         if ( isset( $sTPL) && $sTPL) {
03633             $this->_sToBasketLink .=  '&amp;tpl='.$sTPL;
03634         }
03635     }
03636 
03644     protected function _insert()
03645     {
03646         // set oxinsert
03647         $iInsertTime = time();
03648         $now = date('Y-m-d H:i:s', $iInsertTime);
03649         $this->oxarticles__oxinsert    = new oxField( $now );
03650         $this->oxarticles__oxtimestamp = new oxField( $now );
03651         if ( !is_object($this->oxarticles__oxsubclass) || $this->oxarticles__oxsubclass->value == '') {
03652             $this->oxarticles__oxsubclass = new oxField('oxarticle');
03653         }
03654 
03655         return parent::_insert();
03656     }
03657 
03663     protected function _update()
03664     {
03665 
03666         $myConfig = $this->getConfig();
03667 
03668 
03669         $this->_skipSaveFields();
03670 
03671         return parent::_update();
03672     }
03673 
03681     protected function _deleteRecords($sOXID)
03682     {
03683 
03684         //delete the record
03685         $oDB = oxDb::getDb();
03686         $sDelete = 'delete from '.$this->_sCoreTbl.' where oxid = \''.$sOXID.'\' ';
03687         $oDB->execute( $sDelete);
03688 
03689         //remove other records
03690         $sDelete = 'delete from oxobject2article where oxarticlenid = \''.$sOXID.'\' or oxobjectid = \''.$sOXID.'\' ';
03691         $oDB->execute( $sDelete);
03692 
03693         $sDelete = 'delete from oxobject2attribute where oxobjectid = \''.$sOXID.'\' ';
03694         $oDB->execute( $sDelete);
03695 
03696         $sDelete = 'delete from oxobject2category where oxobjectid = \''.$sOXID.'\' ';
03697         $oDB->execute( $sDelete);
03698 
03699         $sDelete = 'delete from oxobject2selectlist where oxobjectid = \''.$sOXID.'\' ';
03700         $oDB->execute( $sDelete);
03701 
03702         $sDelete = 'delete from oxprice2article where oxartid = \''.$sOXID.'\' ';
03703         $oDB->execute( $sDelete);
03704 
03705         $sDelete = 'delete from oxreviews where oxtype="oxarticle" and oxobjectid = \''.$sOXID.'\' ';
03706         $oDB->execute( $sDelete);
03707 
03708         $sDelete = 'delete from oxaccessoire2article where oxobjectid = "'.$sOXID.'" or oxarticlenid = "'.$sOXID.'" ';
03709         $oDB->execute( $sDelete);
03710 
03711         //#1508C - deleting oxobject2delivery entries added
03712         $sDelete = 'delete from oxobject2delivery where oxobjectid = \''.$sOXID.'\' and oxtype=\'oxarticles\' ';
03713         $oDB->execute( $sDelete);
03714 
03715         $sDelete = 'delete from oxartextends where oxid = \''.$sOXID.'\' ';
03716         $oDB->execute( $sDelete);
03717 
03718         $sDelete = 'delete from oxactions2article where oxartid = \''.$sOXID.'\' ';
03719         $rs = $oDB->execute( $sDelete );
03720 
03721 
03722         return $rs;
03723     }
03724 
03732     protected function _deleteVariantRecords($sOXID)
03733     {
03734         $oDB = oxDb::getDb();
03735         //collect variants to remove recursively
03736         $sVariants = 'select oxid from '.$this->getViewName().' where oxparentid = \''.$sOXID.'\'';
03737         $rs = $oDB->execute( $sVariants);
03738         if ($rs != false && $rs->recordCount() > 0) {
03739             while (!$rs->EOF) {
03740                 $this->delete( $rs->fields[0]);
03741                 $rs->moveNext();
03742             }
03743         }
03744     }
03745 
03755     protected function _resetCacheAndArticleCount( $sOxid )
03756     {
03757         $this->_onChangeResetCounts( $sOxid, $this->oxarticles__oxvendorid->value, $this->oxarticles__oxmanufacturerid->value );
03758     }
03759 
03765     protected function _deletePics()
03766     {
03767         $myUtilsPic = oxUtilsPic::getInstance();
03768         $myConfig   = $this->getConfig();
03769 
03770         // #1173M - not all pic are deleted, after article is removed
03771         $blThumbDeleted = $myUtilsPic->safePictureDelete( $this->oxarticles__oxthumb->value, $myConfig->getAbsDynImageDir().'/0', 'oxarticles', 'oxthumb' );
03772 
03773         if ( $blThumbDeleted ) {
03774             $myUtilsPic->safePictureDelete('icon/'.$this->oxarticles__oxicon->value, $myConfig->getAbsDynImageDir(), 'oxarticles', 'oxicon' );
03775         }
03776         //removed and replaced with savePcitureDelete MAFI
03777         //if( $blThumbDeleted && $myUtilsPic->isPicDeletable( $this->oxarticles__oxthumb->value, 'oxarticles', 'oxicon' )) {
03778             //TODO: is it correct that oxarticles__oxthumb is checked and oxarticles__oxicon deleted? if not replace this with safePictureDelete MAFI
03779          //   $myUtilsPic->deletePicture( 'icon/'.$this->oxarticles__oxicon->value, $myConfig->getAbsDynImageDir(), '' $myConfig->getConfigParam( 'blIsOXDemoShop' ));
03780         //}
03781 
03782         $iPicCount = $myConfig->getConfigParam( 'iPicCount' );
03783         $sAbsDynImageDir = $myConfig->getAbsDynImageDir();
03784         for ( $i = 1; $i <= $iPicCount; $i++ ) {
03785             // Getting coresponding pic's filename value
03786             $sPicFName = $this->{'oxarticles__oxpic'.$i}->value;
03787             $myUtilsPic->safePictureDelete($sPicFName, $sAbsDynImageDir.'/'.$i, 'oxarticles', 'oxpic'.$i );
03788         }
03789         // deleting zoom images
03790         $iZoomPicCount = $myConfig->getConfigParam( 'iZoomPicCount' );
03791         for ( $i = 1; $i <= $iZoomPicCount; $i++ ) {
03792             if ( isset($this->{'oxarticles__oxzoom'.$i}) ) {
03793                 $myUtilsPic->safePictureDelete($this->{'oxarticles__oxzoom'.$i}->value, $sAbsDynImageDir.'/z'.$i, 'oxarticles', 'oxzoom'.$i );
03794             }
03795         }
03796 
03797     }
03798 
03808     protected function _onChangeResetCounts( $sOxid, $sVendorId = null, $sManufacturerId = null )
03809     {
03810 
03811         $myUtilsCount = oxUtilsCount::getInstance();
03812 
03813         if ( $sVendorId ) {
03814             $myUtilsCount->resetVendorArticleCount( $sVendorId );
03815         }
03816 
03817         if ( $sManufacturerId ) {
03818             $myUtilsCount->resetManufacturerArticleCount( $sManufacturerId );
03819         }
03820 
03821         //also reseting category counts
03822         $sQ = "select oxcatnid from oxobject2category where oxobjectid = '{$sOxid}'";
03823         $oRs = oxDb::getDb()->execute( $sQ );
03824         if ( $oRs !== false && $oRs->recordCount() > 0) {
03825             while ( !$oRs->EOF ) {
03826                 $myUtilsCount->resetCatArticleCount( $oRs->fields[0] );
03827                 $oRs->moveNext();
03828             }
03829         }
03830     }
03831 
03839     protected function _onChangeUpdateStock( $sParentID )
03840     {
03841         $oDb = oxDb::getDb();
03842         $sQ = 'select oxstock, oxvendorid, oxmanufacturerid from oxarticles where oxid = \''.$sParentID.'\' ';
03843         $rs = $oDb->execute($sQ);
03844         $iOldStock = $rs->fields[0];
03845         $iVendorID = $rs->fields[1];
03846         $iManufacturerID = $rs->fields[2];
03847 
03848         $sQ = 'select sum(oxstock) from oxarticles where oxparentid = \''.$sParentID.'\' and '. $this->getSqlActiveSnippet( true ).' and oxstock > 0 ';
03849         $iStock = (float) $oDb->getOne( $sQ );
03850 
03851         $sQ = 'update oxarticles set oxvarstock = '.$iStock.' where oxid = \''.$sParentID.'\'';
03852         $oDb->execute( $sQ );
03853 
03854             //now lets update category counts
03855             //first detect stock status change for this article (to or from 0)
03856             if ( $iStock < 0 ) {
03857                 $iStock = 0;
03858             }
03859             if ( $iOldStock < 0 ) {
03860                 $iOldStock = 0;
03861             }
03862             if ( $this->oxarticles__oxstockflag->value == 2 && $iOldStock xor $iStock ) {
03863                 //means the stock status could be changed (oxstock turns from 0 to 1 or from 1 to 0)
03864                 // so far we leave it like this but later we could move all count resets to one or two functions
03865                 $this->_onChangeResetCounts( $sParentID, $iVendorID, $iManufacturerID );
03866             }
03867     }
03868 
03876     protected function _onChangeUpdateVarCount( $sParentID )
03877     {
03878         $oDb = oxDb::getDb();
03879         $sQ = 'select count(*) as varcount from oxarticles where oxparentid = \''.$sParentID.'\' ';
03880         $iVarCount = (int) $oDb->getOne($sQ);
03881 
03882         $sQ = 'update oxarticles set oxvarcount = '.$iVarCount.' where oxid = \''.$sParentID.'\'';
03883         $oDb->execute($sQ);
03884     }
03885 
03893     protected function _onChangeUpdateMinVarPrice( $sParentID )
03894     {
03895         //#M0000883 (Sarunas)
03896         $sQ = 'select min(oxprice) as varminprice from oxarticles where '.$this->getSqlActiveSnippet(true).' and (oxparentid = "'.$sParentID.'"';
03897         //#M0000886 (Sarunas)
03898         if ( $this->getConfig()->getConfigParam( 'blVariantParentBuyable' ) ) {
03899             $sQ .= ' or oxid = "'.$sParentID.'"';
03900         } else {
03901             $sQ .= ' or (oxid = "'.$sParentID.'" and oxvarcount=0)';
03902         }
03903         $sQ .= ')';
03904         $oDb = oxDb::getDb();
03905         $dVarMinPrice = $oDb->getOne($sQ);
03906         if ( $dVarMinPrice ) {
03907             $sQ = 'update oxarticles set oxvarminprice = '.$dVarMinPrice.' where oxid = "'.$sParentID.'"';
03908             $oDb->execute($sQ);
03909         }
03910     }
03911 
03912 
03918     protected function _applyRangePrice()
03919     {
03920         //#buglist_413 if bl_perfLoadPriceForAddList variant price shouldn't be loaded too
03921         if ( !$this->getConfig()->getConfigParam( 'bl_perfLoadPrice' ) || !$this->_blLoadPrice ) {
03922             return;
03923         }
03924 
03925         $this->_blIsRangePrice = false;
03926 
03927         if ($this->_blSkipAbPrice && !$this->_blNotBuyableParent) {
03928             return;
03929         }
03930 
03931         $aPrices = array();
03932 
03933         if (!$this->_blNotBuyableParent) {
03934             $aPrices[] = $this->getPrice()->getBruttoPrice();
03935         }
03936 
03937         if (count($this->_oVariantList)) {
03938             foreach ($this->_oVariantList as $sKey => $oVariant) {
03939                 $aPrices[] = $oVariant->getPrice()->getBruttoPrice();
03940             }
03941         }
03942 
03943         /*  $oAmPrices = $this->loadAmountPriceInfo();
03944         foreach ($oAmPrices as $oAmPrice) {
03945             $aPrices[] = $oAmPrice->oxprice2article__oxaddabs->value;
03946         }*/
03947 
03948         if (count($aPrices)) {
03949             $dMinPrice = $aPrices[0];
03950             $dMaxPrice = $aPrices[0];
03951             foreach ($aPrices as $dPrice) {
03952                 if ($dMinPrice > $dPrice) {
03953                     $dMinPrice = $dPrice;
03954                 }
03955 
03956                 if ($dMaxPrice < $dPrice) {
03957                     $dMaxPrice = $dPrice;
03958                 }
03959             }
03960         }
03961 
03962         if ($this->_blNotBuyableParent && isset($dMinPrice) && $dMinPrice == $dMaxPrice) {
03963             $this->getPrice()->setBruttoPriceMode();
03964             $this->getPrice()->setPrice($dMinPrice);
03965         }
03966 
03967         if (isset($dMinPrice) && $dMinPrice != $dMaxPrice) {
03968             $this->getPrice()->setBruttoPriceMode();
03969             $this->getPrice()->setPrice($dMinPrice);
03970             $this->_blIsRangePrice = true;
03971         }
03972 
03973         if ( $this->isParentNotBuyable() && !$this->getConfig()->getConfigParam( 'blLoadVariants' )) {
03974             $this->getPrice()->setBruttoPriceMode();
03975             $this->getPrice()->setPrice($this->oxarticles__oxvarminprice->value);
03976             $this->_blIsRangePrice = true;
03977         }
03978     }
03979 }

Generated on Wed May 13 13:25:51 2009 for OXID eShop CE by  doxygen 1.5.5